场景对象增删改查调研:命令系统入口 + 新建对象的真实落点

- Commands.java:Editor -> pE(命令系统) -> void D(String) 按名字执行命令
- Launcher:新增 -Dspine.runCommand="<命令名>" 便于验证
- SceneReader:Tree/选中项探针(actor 树按 SnapshotArray 结构遍历)
- 混淆名对照表.md:补命令系统一节、可执行命令名单、skeleton/root 删除边界、
  以及 New X 最终落到静态 KP.B(target, 类型名) 的结论与待办
This commit is contained in:
tianmo committed 2026-10-16 14:20:45 +08:00
1 parent 8f7b72271f
commit a0080428f9
4 files changed
+394 -7

No files matched your search

+84
View File
@@ -175,6 +175,87 @@ JVM 允许同一个类里存在"**名字相同、描述符不同**"的字段和
---
## 四之二、命令系统(增删改查的入口)
编辑器的所有菜单动作都走同一套命令系统。链路(反编译源码里读出来的):
```
OG.D → com.esotericsoftware.spine.editor.Editor 单例
└─ public pE D; → 命令 / 热键系统(Editor.<init> 里 new pe_0())
├─ void D(String) → 按名字执行(名字 = hotkeys.txt / 菜单项名)
├─ pC D(String) → 按名字取菜单项(不执行)
└─ private final ll D; → 菜单注册表:D(String,pC,String...) 注册、D(String) 查表
```
菜单项基类 `pC`(所有动作类都继承它,例如 `mn_1`=New Bone、`pb_0`=Delete):
| 成员 | 含义 |
| --- | --- |
| `boolean D()` | **执行并返回"是否处理了"**(`pC` 基类实现 = `og_1.D.S.a_(); return true;`) |
| `void D()` | 执行(无返回值);基类里是空实现,动作类各自覆盖 |
| `String D` | 名字(`toString()` 返回它) |
> 注意:`pE.D(String)` 只看"找得到找不到",**不看动作有没有真的生效**。
> 实测 `-Dspine.runCommand="New Bone"` 打印"执行完成"但骨骼树没变 —— 因为
> `mn_1.D()` 的源码是:
> ```java
> et_0 sel = og_1.D.D; // 当前选择
> if (sel instanceof xw_2) { KP.B(...D, "Bone"); return true; }
> if (sel instanceof acK) { KP.B(...D, "Bone"); return true; }
> return false; // 没选中 → 什么都不做,也不报错
> ```
> 也就是说 **这些动作全都作用在"当前选择"上**,要先能设置选择,才谈得上增删改。
可用的命令名(= `hotkeys.txt` 里的名字,`~/Library/Application Support/Spine/hotkeys.txt`):
| 类别 | 名字 |
| --- | --- |
| 删除/改名 | `Delete`、`Rename`、`Duplicate`、`Cut`、`Copy`、`Paste` |
| 新建 | `New Bone`、`New Slot`、`New Skin Placeholder`、`New Bounding Box`、`New Path`、`New Clipping`、`New IK Constraint`、`New Path Constraint`、`New Transform Constraint`、`New Skin`、`New Animation`、`New Event`、`New Folder`、`New Skeleton` |
| 层级/顺序 | `Set Parent`、`Parent`、`Child`、`Previous Sibling`、`Next Sibling`、`Previous Sibling Bone`、`Next Sibling Bone`、`Draw Order Up`、`Draw Order Down`、`Tree Up`、`Tree Down` |
| 显示 | `Visibility`、`Show All Bones/Slots`、`Expand`、`Collapse`、`Expand/Collapse`、`Tree Filter`、`Search` |
| 选择类 | `Select - Bones`、`Select - Child Bones`、`Select - Descendant Bones`、`Select - Attachments`、`Select - Visible Attachments`、`Select - Draw Order` |
| 其它 | `Undo`、`Redo`、`Rulers`、`Zoom To Fit`、`Setup/Animate Mode`、`Color`、`Replace` |
**面板里的接口**:[`viewpanel/src/com/spineview/Commands.java`](viewpanel/src/com/spineview/Commands.java)
(`Commands.run(loader, "New Bone")`),验证入口是启动参数 `-Dspine.runCommand="<命令名>"`。
### 真正"建出一个能显示的骨骼"落在哪
用户在编辑器里新建骨骼是**交互式**的:先选父级骨骼,再用 Create Tool 在视口里点一下/拖一下。
菜单里的 `New Bone` 只是同一条路的"用当前选择当父级"版本 —— 所以没选中时它直接 `return false`。
把所有 `New X` 菜单动作摊开看,它们最后都落到**同一个静态方法**上(反编译源码里的名字):
```java
KP.B(target, "Bone"); // 新建骨骼(target = 当前选择对象)
KP.B(target, "Slot");
KP.B(target, "Skin Placeholder");
KP.B(target, "Bounding Box");
KP.B(target, "Path");
KP.B(target, "Clipping");
KP.B(target, "IK Constraint");
KP.B(og_1.D.D.D.D, "Path Constraint");
KP.B(og_1.D.D.D.D, "Skin");
```
调用点(可读源码):`mn_1`(New Bone)、`mo`(New Slot)、`mp`、`mq`、`ms_1`、`mt`、`mu_1`、
`mv_0`、`mx_0`,以及树上的两个"选中类型分支" `acM.java:98` / `yi_0.java:28`。
> ⚠️ 待办:`KP` 这个名字是**可读源码树里**的名字。载荷里另有一个也叫 `KP` 的类
> (`KP extends eW`,是个 SelectBox 控件),那是 CFR 大小写冲突造成的重名。
> 真正要调的那个 `KP` 得先用 `tools/obfmap/MapMethods` 之类的办法重新定位一次,
> 才能从面板里反射调用 —— 这是下一步的第一步。
### 场景对象的删除边界(需求确认)
- `skeleton` 是**整个场景的根节点**:删掉它等于清空全部场景对象;
- `root` 是**所有对象的根骨骼**:只要 skeleton 在,root 就必然在,**不允许删除**。
所以面板做删除时,选择集里要拦住 `root`(skeleton 可以删)。
---
## 五、验证状态
| 结论 | 证据 |
@@ -184,7 +265,10 @@ JVM 允许同一个类里存在"**名字相同、描述符不同**"的字段和
| `et.Z(Z)V` = `setFillParent` | 换成它之后面板铺满停靠框(先前误调 `setDebug` 时只会描出彩色单元格边框) |
| `Button.String()Z` = `isChecked`、`I(Z)V` = `setChecked` | 点击能触发一次读取;用前缀自校准曾配错组合,导致反复触发 |
| `Label.D(CharSequence)V` = `setText` | 修掉 `textEquals` 之后面板文字才真正刷新 |
| 命令系统入口 `Editor.pE.D(String)` 可达 | 面板成功拿到命令系统并执行了 `New Bone` / `Rulers`(日志有 `[cmd] 执行命令`) |
未逐条验证的(结构成组、按声明顺序推定):`Cell` 的 max/pad 系列、`Button` 的 `isOver/isPressed`、
`Cell` 的 `growX/growY`。要用到时,先用 `MapMethods` 重跑一遍,再在编辑器里实测。
**已知未打通**:命令"执行了但没生效"(`New Bone` / `Rulers` 都没看到界面变化)。
下一步要确认执行路径究竟是 `pC.boolean D()` 还是 `pC.void D()`,以及**怎么设置当前选择**。