Files
Spine_lab/编辑器交互与数据API.md
T
tianmo 2b23ce59db 新增《编辑器交互与数据API》调研文档
- 交互层:工具注册(Create Tool 等)与视口交互入口
- 层级树:VZ(视图) / uo_2(节点) / xw_2(骨架) / gp_2(骨) / acK(插槽) 包装模型
- 当前选择:og_1.D.D 的读取点与菜单动作的依赖关系
- 数据层:所有 New X 都落到 KP.B(父级, 类型名),以及 KP 真实类名待解
- 改删查命令清单、撤销注意点、skeleton/root 删除边界、下一步 5 条
2026-10-16 14:22:48 +08:00

124 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 编辑器交互逻辑 & 数据 API 调研
目标:在动手写"面板里对场景对象增删改查"之前,先把编辑器**用户交互链路**和**真正生成数据的代码**摸清楚。
本文只记录查到的事实 + 出处 + 还没弄清的地方。(混淆名 ⇒ 真实名见 [`混淆名对照表.md`](混淆名对照表.md)。)
---
## 一、交互层:工具(Tool)
所有工具都在菜单注册表 `ll` 的构造函数里注册(`~/Desktop/spine398/src-readable/ll.java`):
| 菜单名 | 动作类(CFR 名) | 备注 |
| --- | --- | --- |
| `Create Tool` | `oo` | 新建对象用(靠视口点拖) |
| `Scale/Rotate/Translate/Shear/Pose/Weights Tool` | `oi_1` / `oj_0` / `ok_1` / `om` / `on_0` / `op` | |
| `Last Tool` | `oq_1` | 切回上一个工具 |
`oo`(Create Tool)点下去做的事:
```java
og_1.D.D.D.I(true); // 打开"创建"交互(og_1.D = 编辑器上下文单例,后面是逐层嵌套的字段)
```
→ 新建对象本身是**交互式**的:工具打开后由视口里的按下/拖动事件驱动;菜单里的 `New Bone`
只是"用当前选择当父级"的等价入口(见下)。
## 二、层级树(Tree 视图)与节点模型
- Tree 视图 Actor = `VZ`(2819 行,`us.Tree` 面板的内容类)。
- 树节点 = `uo_2`(Node),每个节点包一个**包装对象**:
| 包装类 | 代表的场景对象(按用法推断) |
| --- | --- |
| `xw_2` | skeleton 节点(`xw_2.D` = 骨架数据) |
| `gp_2` | bone 节点(`xw_2.java:367` 有 `"Bone: " + ((gp_2)object).D`) |
| `acK` / `acW` | slot 节点(`acK.java` 里有 "Set Parent" / "Sets the slot's parent bone") |
| `GU` | Draw Order 里的对象 |
| `Yr` | `xw_2` 的父类(一批节点包装的基类) |
| `md_1` | 节点里保存的模型引用 |
树里的固定结构(见 `VZ.java` 建节点处):`skeleton → root → bone/slot…`,
另有 `Draw Order#startcaps`、`Skins`、`Events`、`Animations` 这些 `icon-*Root` 固定根。
### 当前选择放在哪
反编译源码里到处是这种读取:
```java
et_0 sel = og_1.D; // 编辑器上下文单例
sel = sel.D; // ← 当前选择对象(菜单动作都作用在它上面)
... og_1.D.D.D // 再深一层(视图/工具相关)
```
`mn_1`(New Bone)的判断就依赖它:
```java
if (sel instanceof xw_2) { KP.B(((xw_2)sel).D, "Bone"); return true; } // 选中 skeleton
if (sel instanceof acK) { KP.B(((acK)sel).D, "Bone"); return true; } // 选中 slot
return false; // 没选中/不支持 → 什么都不做
```
## 三、数据层:真正"建出对象"的 API
所有 `New X` 最后都落到**同一个方法**:
```java
KP.B(target, "Bone"); // mn_1 New Bone
KP.B(target, "Slot"); // mo New Slot
KP.B(target, "Skin Placeholder"); // mp
KP.B(target, "Bounding Box"); // mq
KP.B(target, "Path"); // ms_1
KP.B(target, "Clipping"); // mt
KP.B(target, "IK Constraint"); // mu_1
KP.B(og_1.D.D.D.D, "Path Constraint"); // mv_0
KP.B(og_1.D.D.D.D, "Skin"); // mx_0
```
另有树视图自己的分支:`acM.java:98`、`yi_0.java:28`。
**这就是"增"的直接入口**:第一个参数是**父级对象**(选中项),第二个参数是类型名。
也就是说编辑器内部不是"凭空建一根骨头",模型本身就是"挂在父对象下面的树"。
### ⚠️ 还没定死:`KP` 到底是哪个类
- 载荷里确实有个 `KP.class`,但它是 `KP extends eW` 的 **SelectBox 控件**,
只有 `public static fI D(fI)` 一个静态方法,**没有 `B`**,不是我们要的那个。
- 可读源码树里的 `KP` 来自**解码 invokedynamic 调用点**(编辑器把几乎所有调用都编译成
invokedynamic,所以 `javap` 里看不到 `invokestatic KP.B`)。调用映射在
`~/Desktop/spine398/obmap.tsv`,能看到几十条 `KP.B` / `KP.D` / `KP.L`(如 `RE mq KP.B`、`Yr gy KP.D`)。
→ 下一步:用 `tools/decrypt/` 把某个调用点(例如 `mn` 里那次)的**真实 owner 类**解出来,
或在运行时按"方法名 + 描述符(对象 + String 两参)"在类表 `LPt4.mc` 里搜候选类逐个验证。
## 四、改 / 删 / 查
| 操作 | 入口 | 说明 |
| --- | --- | --- |
| 删 | `Delete`(`pb_0`) | 作用在当前选择上 |
| 改名 | `Rename`(`lo`) | |
| 复制 | `Duplicate`(`lp_0`)、`Cut`/`Copy`/`Paste`(`pv`/`pw`/`px_2`) | |
| 层级 | `Set Parent`(`mm_1`)、`Parent`/`Child`/`Previous Sibling`/`Next Sibling` | |
| 顺序 | `Draw Order Up`/`Down`(`lu_1`/`ls_1` 等) | |
| 查 | 树节点本身就是查询结果;`Select - Bones`/`Select - Attachments` 负责筛选 | |
**撤销**:`Undo`/`Redo` 也在这套命令系统里(`lm_0`/`nw`)。菜单路径的动作会进撤销栈;
直接反射调 `KP.B` 很可能**绕过撤销** —— 真要写入时优先走菜单命令(`Commands.run`),
或先看清动作类自己有没有压栈。
## 五、删除边界(需求确认)
- `skeleton`:整个场景的根节点,**可以删**(删它等于清空所有场景对象);
- `root`:所有对象的根骨骼,只要 skeleton 在就必然存在,**不允许删除**。
面板做删除时要在选择集里拦住 `root`。
## 六、下一步(按顺序)
1. 解出 `KP` 的真实类名(indy 调用映射 / 运行时按签名搜 `LPt4.mc`),确认 `B(Object,String)` 的描述符。
2. 确认"父级对象"参数的确切类型:`xw_2.D`(skeleton 节点里的骨架数据)、`acK.D`(slot 节点里的数据)。
3. 搞清选择怎么设置(`og_1.D.D` 是可直接写的字段,还是只能由视图点击设置)——
否则"对着指定对象增删改"无从指定。
4. 确认新建/删除后**谁负责刷新界面**(`VZ` 重扫模型?动作里带 invalidate?)。
5. 最后才做面板 UI:对象树列表 + 新建/删除/改名按钮。