From 4000a06d613658930f2cd3018f7420c71f42995c Mon Sep 17 00:00:00 2001 From: tianmo Date: Fri, 16 Oct 2026 17:57:06 +0800 Subject: [PATCH] =?UTF-8?q?=EF=BC=8B10=20Red=20Bones=20=E4=BF=AE=E4=B8=A4?= =?UTF-8?q?=E5=A4=84=EF=BC=9A=E2=91=A0=E6=AF=8F=E5=BB=BA=E4=B8=80=E6=A0=B9?= =?UTF-8?q?=E7=AD=89=E4=B8=80=E5=B8=A7=EF=BC=88=E7=BC=96=E8=BE=91=E5=99=A8?= =?UTF-8?q?=E4=B8=8B=E4=B8=80=E5=B8=A7=E6=89=8D=E7=9C=9F=E5=BB=BA=EF=BC=8C?= =?UTF-8?q?=E5=90=8C=E5=B8=A7=E8=BF=9E=E8=B0=83=E5=8F=AA=E7=94=9F=E6=95=88?= =?UTF-8?q?=E4=B8=80=E6=AC=A1=EF=BC=89=E2=91=A1=E9=A2=9C=E8=89=B2=E6=8C=89?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E8=A1=A8=E5=86=99=20Gp=20=E7=9A=84=20color?= =?UTF-8?q?=20=E5=AD=97=E6=AE=B5=EF=BC=88=E6=B7=B7=E6=B7=86=E5=90=8D=20B?= =?UTF-8?q?=EF=BC=89=EF=BC=8C=E4=B8=8D=E5=86=8D=E5=8F=96'=E7=AC=AC?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=20Color=20=E5=AD=97=E6=AE=B5'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- viewpanel/src/com/spineview/ObjectPanel.java | 98 ++++++++++++-------- 1 file changed, 60 insertions(+), 38 deletions(-) diff --git a/viewpanel/src/com/spineview/ObjectPanel.java b/viewpanel/src/com/spineview/ObjectPanel.java index 3017241..df18353 100644 --- a/viewpanel/src/com/spineview/ObjectPanel.java +++ b/viewpanel/src/com/spineview/ObjectPanel.java @@ -636,41 +636,57 @@ public final class ObjectPanel { * 建用编辑器自己的 New Bone(带撤销),建完立刻改该骨骼的 x/y 与 color 字段。 */ private static void createTenRedBones(final State state) { - SceneActions.onEditorThread(state.loader, new Runnable() { - @Override - public void run() { - // 父级取"编辑器里的当前选择"(用户是在层级面板里选的,不是点我们列表行) - Object parent = currentTarget(state); - if (parent == null) { - setStatus(state, "+10 Red Bones: select a parent bone first."); - return; + // ⚠️ 不能整段放在 render 线程里连着调:编辑器是"下一帧"才真正建骨骼的, + // 同一帧连续调 10 次只会生效一次。所以每建一根 -> 回到本线程等一帧 -> 再建下一根。 + final Object parent = currentTarget(state); + if (parent == null) { + setStatus(state, "+10 Red Bones: select a parent bone first."); + return; + } + final Object red; + try { + Class colorClass = Class.forName("com.badlogic.gdx.graphics.Color", true, state.loader); + red = colorClass.getConstructor(float.class, float.class, float.class, float.class) + .newInstance(Float.valueOf(1f), Float.valueOf(0f), Float.valueOf(0f), Float.valueOf(1f)); + } catch (Throwable error) { + setStatus(state, "+10 Red Bones: 造红色失败 " + error); + return; + } + int made = 0; + for (int i = 0; i < 10; i++) { + final float x = (float) (Math.random() * 400.0 - 200.0); + final float y = (float) (Math.random() * 400.0 - 200.0); + final int[] ok = new int[1]; + final java.util.List before = listQuietly(state); + SceneActions.onEditorThread(state.loader, new Runnable() { + @Override + public void run() { + SceneActions.create(state.loader, parent, "Bone"); + Object fresh = firstNew(before, listQuietly(state)); + if (fresh == null) return; + setBoneNumber(fresh, "x", x); + setBoneNumber(fresh, "y", y); + setBoneColor(fresh, red); + ok[0] = 1; } - try { - Class colorClass = Class.forName("com.badlogic.gdx.graphics.Color", true, state.loader); - Object red = colorClass.getConstructor(float.class, float.class, float.class, - float.class).newInstance(Float.valueOf(1f), Float.valueOf(0f), Float.valueOf(0f), - Float.valueOf(1f)); - int made = 0; - for (int i = 0; i < 10; i++) { - java.util.List before = SceneObjects.listAllNodes(state.loader); - SceneActions.create(state.loader, parent, "Bone"); - Object fresh = firstNew(before, SceneObjects.listAllNodes(state.loader)); - if (fresh == null) continue; - float x = (float) (Math.random() * 400.0 - 200.0); - float y = (float) (Math.random() * 400.0 - 200.0); - setBoneNumber(fresh, "x", x); - setBoneNumber(fresh, "y", y); - setBoneColor(fresh, red); - made++; - } - setStatus(state, "made " + made + " red bones under " + SceneObjects.nameOf(parent)); - } catch (Throwable error) { - setStatus(state, "+10 Red Bones failed: " + error); - error.printStackTrace(System.err); - } - refreshList(state); + }); + made += ok[0]; + try { + Thread.sleep(180); // 等编辑器过一帧,下一根才会真的建出来 + } catch (InterruptedException ignored) { + return; } - }); + } + setStatus(state, "made " + made + " red bones under " + SceneObjects.nameOf(parent)); + refreshList(state); + } + + private static java.util.List listQuietly(State state) { + try { + return SceneObjects.listAllNodes(state.loader); + } catch (Throwable error) { + return new ArrayList(); + } } /** 前后列表对比,取第一个新出现的对象。 */ @@ -707,16 +723,22 @@ public final class ObjectPanel { } } - /** 骨骼颜色:找类型是 libGDX Color 的字段写进去。 */ + /** + * 骨骼颜色:按映射表写 `Gp` 的 color 字段(混淆名 B,描述符 Lcom/badlogic/gdx/graphics/Color;)。 + * 表里查不到时才退回"第一个 Color 类型字段"。 + */ private static void setBoneColor(Object bone, Object color) { try { + String obf = obfNameOf("Gp", "Lcom/badlogic/gdx/graphics/Color;", "color"); for (Class type = bone.getClass(); type != null && type != Object.class; type = type.getSuperclass()) { for (java.lang.reflect.Field field : type.getDeclaredFields()) { - if (!field.getType().getName().equals("com.badlogic.gdx.graphics.Color")) continue; - field.setAccessible(true); - field.set(bone, color); - return; + if (field.getType().getName().equals("com.badlogic.gdx.graphics.Color")) { + if (obf != null && !field.getName().equals(obf)) continue; + field.setAccessible(true); + field.set(bone, color); + return; + } } } } catch (Throwable error) {