diff --git a/viewpanel/src/com/spineview/ViewInstaller.java b/viewpanel/src/com/spineview/ViewInstaller.java index b75b283..d8a3d85 100644 --- a/viewpanel/src/com/spineview/ViewInstaller.java +++ b/viewpanel/src/com/spineview/ViewInstaller.java @@ -70,19 +70,11 @@ public final class ViewInstaller { System.err.println("[view] 找不到 Skin"); return false; } - // 视图里挂的是**稳定容器**(由编辑器类加载器建),面板内容放在它里面: - // 这样热更时只要换容器里的内容,编辑器不用重启、场景与选择状态都保留。 - Class tableClass = Class.forName("et", true, loader); - Object holder = tableClass.getConstructor().newInstance(); - callStatic(tableClass, Obf.TABLE_SET_FILL_PARENT, new Class[] {boolean.class}, holder, - Boolean.TRUE); Object panel = buildPanel(loader, skin); - addChild(tableClass, holder, panel); - startHotReload(loader, skin, holder); for (Field field : viewEnum.getDeclaredFields()) { if (!field.getType().getName().equals(ACTOR)) continue; field.setAccessible(true); - field.set(view, holder); + field.set(view, panel); System.err.println("[view] 已把 Spine View 面板挂到视图 " + view); showView(loader, view); return true; @@ -121,91 +113,6 @@ public final class ViewInstaller { } } - /** 调一个"静态/实例"都行的方法:这里用来调 Table.setFillParent(实例方法)。 */ - private static void callStatic(Class owner, String name, Class[] parameterTypes, - Object receiver, Object... arguments) throws Exception { - for (Method method : owner.getMethods()) { - if (!method.getName().equals(name)) continue; - if (!java.util.Arrays.equals(method.getParameterTypes(), parameterTypes)) continue; - method.setAccessible(true); - method.invoke(receiver, arguments); - return; - } - throw new NoSuchMethodException(owner.getName() + "." + name); - } - - /** 往容器里加 Actor(Table.add(Actor))。 */ - private static void addChild(Class tableClass, Object table, Object actor) throws Exception { - for (Method method : tableClass.getMethods()) { - Class[] types = method.getParameterTypes(); - if (types.length != 1) continue; - if (!types[0].isAssignableFrom(actor.getClass())) continue; - if (method.getReturnType() == void.class) continue; - method.setAccessible(true); - method.invoke(table, actor); - return; - } - throw new NoSuchMethodException("找不到 add(Actor)"); - } - - /** 清空容器(Table.clearChildren())。 */ - private static void clearChildren(Class tableClass, Object table) throws Exception { - for (Method method : tableClass.getMethods()) { - if (!method.getName().equals(Obf.TABLE_CLEAR_CHILDREN)) continue; - if (method.getParameterTypes().length != 0) continue; - method.setAccessible(true); - method.invoke(table); - return; - } - throw new NoSuchMethodException("找不到 clearChildren()"); - } - - /** - * 热更:轮询 `viewpanel/build/classes/com/spineview/ObjectPanel.class` 的修改时间, - * 一变就用**新的子类加载器**(parent = 编辑器加载器)重建面板内容,换进稳定容器里。 - * 这样改完代码只要 `./viewpanel/build.sh`,编辑器不用重启。 - */ - private static void startHotReload(final ClassLoader loader, final Object skin, - final Object holder) { - final String classesDir = System.getProperty("spine.classes"); - if (classesDir == null) { - System.err.println("[view] 没有 -Dspine.classes,热更关闭"); - return; - } - final java.io.File marker = new java.io.File(classesDir, "com/spineview/ObjectPanel.class"); - final long[] lastSeen = new long[] {marker.lastModified()}; - Thread thread = new Thread(new Runnable() { - @Override - public void run() { - while (true) { - try { - Thread.sleep(1000); - long stamp = marker.lastModified(); - if (stamp == lastSeen[0] || stamp == 0) continue; - lastSeen[0] = stamp; - Thread.sleep(400); // 等编译落盘 - java.net.URL classesUrl = new java.io.File(classesDir).toURI().toURL(); - java.net.URLClassLoader child = new java.net.URLClassLoader( - new java.net.URL[] {classesUrl}, loader); - Class panelClass = Class.forName("com.spineview.ObjectPanel", true, child); - Object fresh = panelClass.getMethod("build", ClassLoader.class, Object.class) - .invoke(null, child, skin); - Class tableClass = Class.forName("et", true, loader); - clearChildren(tableClass, holder); - addChild(tableClass, holder, fresh); - System.err.println("[view] 热更完成:面板已用新的类加载器重建(未重启编辑器)"); - } catch (InterruptedException ignored) { - return; - } catch (Throwable error) { - System.err.println("[view] 热更失败: " + error); - } - } - } - }, "spineview-hot-reload"); - thread.setDaemon(true); - thread.start(); - } - /** Skin 挂在 OG 的静态字段上(字节码里 OG 有 LSkin;D)。 */ private static Object findSkin(ClassLoader loader) throws Exception { Class holder = Class.forName("OG", true, loader);