新增阶段五文档:面板接真实数据(增删改查/属性读写/Inspector 真名翻译/滚动焦点/统计)+ 14 条踩坑点 + 未完成清单
This commit is contained in:
1 parent
bb817b85e5
commit
7f06c6744a
43 files changed
+2942
-79
No files matched your search
@@ -636,45 +636,53 @@ public final class ObjectPanel {
|
||||
* 建用编辑器自己的 New Bone(带撤销),建完立刻改该骨骼的 x/y 与 color 字段。
|
||||
*/
|
||||
private static void createTenRedBones(final State state) {
|
||||
// 用已验证可行的做法:编辑器自己的 New Bone(一根一次)+ 每根之间等一帧;最后刷新一次。
|
||||
// (此前试过"直接调模型 API 连建 10 根",会把编辑器卡死,已放弃那条路。)
|
||||
// 编辑器自己的 API 路径(不经 UI、不依赖下一帧):一次建 10 根 → 一次刷新 → 一次撤销
|
||||
final Object parent = currentTarget(state);
|
||||
if (parent == null) {
|
||||
setStatus(state, "+10 Red Bones: select a parent bone first.");
|
||||
return;
|
||||
}
|
||||
final int[] made = new int[1];
|
||||
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);
|
||||
final Object skeleton = SceneActions.skeletonOf(parent);
|
||||
if (skeleton == null) {
|
||||
setStatus(state, "+10 Red Bones: 找不到所属骨架");
|
||||
return;
|
||||
}
|
||||
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 java.util.List<Object> 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);
|
||||
made[0]++;
|
||||
final int[] made = new int[1];
|
||||
SceneActions.onEditorThread(state.loader, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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));
|
||||
Class<?> undo = Class.forName("un", true, state.loader);
|
||||
java.lang.reflect.Method begin = null;
|
||||
java.lang.reflect.Method commit = null;
|
||||
for (Method m : undo.getDeclaredMethods()) {
|
||||
if (m.getParameterTypes().length != 0 || m.getReturnType() != void.class) continue;
|
||||
if (m.getName().equals("D")) begin = m;
|
||||
if (m.getName().equals("B")) commit = m;
|
||||
}
|
||||
if (begin != null) {
|
||||
begin.setAccessible(true);
|
||||
begin.invoke(null);
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Object bone = SceneActions.createBone(state.loader, skeleton, parent, "red_" + (i + 1),
|
||||
(float) (Math.random() * 400.0 - 200.0), (float) (Math.random() * 400.0 - 200.0),
|
||||
red);
|
||||
if (bone != null) made[0]++;
|
||||
}
|
||||
if (commit != null) {
|
||||
commit.setAccessible(true);
|
||||
commit.invoke(null);
|
||||
}
|
||||
SceneActions.refresh(state.loader, skeleton);
|
||||
} catch (Throwable error) {
|
||||
System.err.println("[panel] +10 Red Bones(API) 失败: " + error);
|
||||
}
|
||||
});
|
||||
try {
|
||||
Thread.sleep(180); // 等编辑器过一帧,下一根才会真的建出来
|
||||
} catch (InterruptedException ignored) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
setStatus(state, "made " + made[0] + " red bones under " + SceneObjects.nameOf(parent));
|
||||
refreshList(state);
|
||||
}
|
||||
|
||||
@@ -909,67 +909,74 @@ public final class SceneActions {
|
||||
// → 骨架.StackMapTable() ← 重建索引 → Editor.D(骨骼, true) → VZ.D(骨架, true, true) 重建树
|
||||
// 一次调用可以连建 N 根,最后只刷新一次;外层包 un.D()/un.B() 就是"一次撤销"。
|
||||
|
||||
/** 直接建一根骨骼(返回新骨骼对象;失败返回 null)。 */
|
||||
/**
|
||||
* 直接建一根骨骼(编辑器自己的序列,全部有字节码依据,见 `javap -c UH` 的 D(Gp,Gp,Z,gR,fI)):
|
||||
* new Gp(模板, 父.skeleton, 父) ← 构造器 (Gp, GP, Gp)
|
||||
* name = OG.D(父名字, skeleton.骨骼数组, null) ← 编辑器自己的不重名生成器
|
||||
* skeleton.addBone(bone) ← GP.D(Gp)(字节码:bone.B = size; array.add(bone))
|
||||
* 之后由调用方设 x/y/color 并统一刷新一次。
|
||||
*/
|
||||
public static Object createBone(ClassLoader loader, Object skeleton, Object parent, String name,
|
||||
float x, float y, Object color) {
|
||||
try {
|
||||
System.err.println("[crud] createBone step1 new Gp " + skeleton + " parent=" + parent);
|
||||
Class<?> boneClass = Class.forName("Gp", true, loader);
|
||||
Object bone = boneClass.getConstructor().newInstance();
|
||||
setByType(bone, "GP", skeleton);
|
||||
if (parent != null) setByType(bone, "Gp", parent);
|
||||
setByNameType(bone, "D", String.class, name);
|
||||
setByNameType(bone, "Z", float.class, Float.valueOf(x));
|
||||
setByNameType(bone, "V", float.class, Float.valueOf(y));
|
||||
if (color != null) setByNameType(bone, "B",
|
||||
Class.forName("com.badlogic.gdx.graphics.Color", true, loader), color);
|
||||
System.err.println("[crud] createBone step2 fields ok");
|
||||
Class<?> skeletonClass = Class.forName("GP", true, loader);
|
||||
Object bone = boneClass.getConstructor(boneClass, skeletonClass, boneClass)
|
||||
.newInstance(parent, skeleton, parent);
|
||||
|
||||
// 骨架.D(骨骼):GP 上的 (LGp;)V
|
||||
Method addBone = findMethod(skeleton.getClass(), "D", new Class<?>[] {boneClass}, void.class);
|
||||
if (addBone == null) throw new NoSuchMethodException("GP.D(LGp;)V addBone");
|
||||
addBone.setAccessible(true);
|
||||
System.err.println("[crud] createBone step3 " + addBone.getDeclaringClass().getName() + "."
|
||||
+ addBone.getName() + "(Gp) 调用中");
|
||||
addBone.invoke(skeleton, bone);
|
||||
System.err.println("[crud] createBone step3 ok");
|
||||
|
||||
// 骨架.StackMapTable():重建索引
|
||||
Method rebuild = null;
|
||||
for (Method m : skeleton.getClass().getMethods()) {
|
||||
if (m.getName().equals("StackMapTable") && m.getParameterTypes().length == 0
|
||||
&& m.getReturnType() == void.class) {
|
||||
rebuild = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rebuild != null) {
|
||||
rebuild.setAccessible(true);
|
||||
rebuild.invoke(skeleton);
|
||||
}
|
||||
|
||||
// Editor.D(骨骼, true):通知编辑器(找不到就跳过,不影响模型)
|
||||
// 名字:优先用编辑器自己的生成器(找不到就用调用方给的名字)
|
||||
String finalName = name;
|
||||
try {
|
||||
Class<?> editorClass = Class.forName("com.esotericsoftware.spine.editor.Editor", true, loader);
|
||||
Method notify = findMethod(editorClass, "D", new Class<?>[] {boneClass, boolean.class},
|
||||
void.class);
|
||||
Object editor = SceneObjects.global(loader, "com.esotericsoftware.spine.editor.Editor");
|
||||
if (notify != null && editor != null) {
|
||||
notify.setAccessible(true);
|
||||
notify.invoke(editor, bone, Boolean.TRUE);
|
||||
Class<?> og = Class.forName("OG", true, loader);
|
||||
Class<?> arrayClass = Class.forName("fI", true, loader);
|
||||
Class<?> slotClass = Class.forName("GU", true, loader);
|
||||
Method gen = findMethod(og, "D",
|
||||
new Class<?>[] {String.class, arrayClass, slotClass}, String.class);
|
||||
Object bones = null;
|
||||
for (Field field : skeletonClass.getDeclaredFields()) {
|
||||
if (field.getType() == arrayClass) {
|
||||
field.setAccessible(true);
|
||||
bones = field.get(skeleton);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Object parentName = null;
|
||||
for (Field field : boneClass.getDeclaredFields()) {
|
||||
if (field.getType() == String.class) {
|
||||
field.setAccessible(true);
|
||||
parentName = field.get(parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (gen != null && bones != null) {
|
||||
gen.setAccessible(true);
|
||||
Object generated = gen.invoke(null, "bone", bones, null);
|
||||
if (generated instanceof String && !((String) generated).isEmpty()) {
|
||||
finalName = (String) generated;
|
||||
}
|
||||
}
|
||||
} catch (Throwable error) {
|
||||
System.err.println("[crud] Editor.D(bone,true) 跳过: " + error);
|
||||
System.err.println("[crud] 名字生成器跳过: " + error);
|
||||
}
|
||||
|
||||
Method addBone = findMethod(skeletonClass, "D", new Class<?>[] {boneClass}, void.class);
|
||||
if (addBone == null) throw new NoSuchMethodException("GP.D(Gp) addBone");
|
||||
addBone.setAccessible(true);
|
||||
addBone.invoke(skeleton, bone);
|
||||
|
||||
setByNameType(bone, "D", String.class, finalName);
|
||||
setByNameType(bone, "Z", float.class, Float.valueOf(x));
|
||||
setByNameType(bone, "V", float.class, Float.valueOf(y));
|
||||
if (color != null) {
|
||||
setByNameType(bone, "B", Class.forName("com.badlogic.gdx.graphics.Color", true, loader),
|
||||
color);
|
||||
}
|
||||
System.err.println("[crud] createBone ok name=" + finalName);
|
||||
return bone;
|
||||
} catch (Throwable error) {
|
||||
System.err.println("[crud] createBone 失败: " + error);
|
||||
Throwable cause = error;
|
||||
while (cause != null) {
|
||||
System.err.println("[crud] cause: " + cause);
|
||||
cause.printStackTrace(System.err);
|
||||
cause = cause.getCause();
|
||||
}
|
||||
Throwable cause = error.getCause();
|
||||
if (cause != null) System.err.println("[crud] cause: " + cause);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user