@fenglimg/cocos-state-controller 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +287 -0
- package/assets/script/controller/Capability.ts +100 -0
- package/assets/script/controller/Capability.ts.meta +10 -0
- package/assets/script/controller/CapabilityRegistry.ts +116 -0
- package/assets/script/controller/CapabilityRegistry.ts.meta +10 -0
- package/assets/script/controller/EnumPropRefMap.ts +232 -0
- package/assets/script/controller/EnumPropRefMap.ts.meta +10 -0
- package/assets/script/controller/NestedCtrlData.ts +199 -0
- package/assets/script/controller/NestedCtrlData.ts.meta +10 -0
- package/assets/script/controller/PrefabIntrospection.ts +151 -0
- package/assets/script/controller/PrefabIntrospection.ts.meta +10 -0
- package/assets/script/controller/Props.meta +13 -0
- package/assets/script/controller/StateControllerV2.ts +1957 -0
- package/assets/script/controller/StateControllerV2.ts.meta +10 -0
- package/assets/script/controller/StateEnumV2.ts +165 -0
- package/assets/script/controller/StateEnumV2.ts.meta +10 -0
- package/assets/script/controller/StateErrorManagerV2.ts +217 -0
- package/assets/script/controller/StateErrorManagerV2.ts.meta +10 -0
- package/assets/script/controller/StatePropHandlerV2.ts +316 -0
- package/assets/script/controller/StatePropHandlerV2.ts.meta +10 -0
- package/assets/script/controller/StatePropertyControlService.ts +148 -0
- package/assets/script/controller/StatePropertyControlService.ts.meta +10 -0
- package/assets/script/controller/StateSelectV2.ts +4542 -0
- package/assets/script/controller/StateSelectV2.ts.meta +10 -0
- package/assets/script/controller/capabilities/AutoSyncCapability.ts +30 -0
- package/assets/script/controller/capabilities/AutoSyncCapability.ts.meta +10 -0
- package/assets/script/controller/capabilities/EventCapability.ts +144 -0
- package/assets/script/controller/capabilities/EventCapability.ts.meta +10 -0
- package/assets/script/controller/capabilities/MigrationCapability.ts +94 -0
- package/assets/script/controller/capabilities/MigrationCapability.ts.meta +10 -0
- package/assets/script/controller/capabilities/MultiCtrlBindingCapability.ts +157 -0
- package/assets/script/controller/capabilities/MultiCtrlBindingCapability.ts.meta +10 -0
- package/assets/script/controller/capabilities/PropertyControlCapability.ts +124 -0
- package/assets/script/controller/capabilities/PropertyControlCapability.ts.meta +10 -0
- package/assets/script/controller/capabilities/RecordingCapability.ts +69 -0
- package/assets/script/controller/capabilities/RecordingCapability.ts.meta +10 -0
- package/assets/script/controller/capabilities/SelectedPageIdCapability.ts +88 -0
- package/assets/script/controller/capabilities/SelectedPageIdCapability.ts.meta +10 -0
- package/assets/script/controller/capabilities.meta +13 -0
- package/assets/script/controller/props/CtrlInspectorGroups.ts +138 -0
- package/assets/script/controller/props/CtrlInspectorGroups.ts.meta +10 -0
- package/assets/script/controller/props/SelectInspectorGroups.ts +104 -0
- package/assets/script/controller/props/SelectInspectorGroups.ts.meta +10 -0
- package/bin/csc.js +286 -0
- package/package.json +60 -0
- package/packages/state-controller-v2-panel/README.md +80 -0
- package/packages/state-controller-v2-panel/inspector-inject.js +917 -0
- package/packages/state-controller-v2-panel/inspector-probe.json +3767 -0
- package/packages/state-controller-v2-panel/lib/handlers.js +534 -0
- package/packages/state-controller-v2-panel/main.js +149 -0
- package/packages/state-controller-v2-panel/package.json +32 -0
- package/packages/state-controller-v2-panel/panel/build.js +23 -0
- package/packages/state-controller-v2-panel/panel/logic.js +1207 -0
- package/packages/state-controller-v2-panel/panel/styles.css +454 -0
- package/packages/state-controller-v2-panel/panel/template.html +296 -0
- package/packages/state-controller-v2-panel/scene-accessor.js +657 -0
- package/skills/cocos-state-controller/SKILL.md +28 -0
- package/skills/cocos-state-controller/refs/cli-usage.md +78 -0
- package/skills/cocos-state-controller/refs/editor-guide.md +127 -0
- package/skills/cocos-state-controller/refs/migrate.md +106 -0
- package/skills/cocos-state-controller/refs/upstream-pr.md +66 -0
- package/tools/migration/migrate-prefab-v1-to-v2.js +608 -0
- package/tools/state-controller-sync-manifest.json +33 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RecordingCapability (Wave 2 T25).
|
|
3
|
+
*
|
|
4
|
+
* Topic 3 录制路径 (T03-T17) 已实装在 StateControllerV2 / StateSelectV2 内部.
|
|
5
|
+
* 本 capability 不重复录制逻辑, 仅作为"录制能力的对外接口":
|
|
6
|
+
* - 暴露 isRecording(ctrl) 静态查询
|
|
7
|
+
* - 提供 onRecordingStart/Stop hook (默认空实现, 其它 capability 可监听录制态)
|
|
8
|
+
* - 注册到 CapabilityRegistry, 让 dispatch 走 capability 路径时, 录制态能广播给监听者
|
|
9
|
+
*
|
|
10
|
+
* 命名空间: Topic 3 数据 (snapshot, ctrlData diff) 都不写 namespace, 直接复用 ctrlData[state][prop].
|
|
11
|
+
* - snapshot 是 StateSelectV2 实例字段, 不需要 namespace
|
|
12
|
+
* - diff commit 写 propData[propType], 与 PropertyControl 同一份数据 (录制是"写入工具", 不是"独立存储")
|
|
13
|
+
*
|
|
14
|
+
* 后续扩展位 (Wave 3+):
|
|
15
|
+
* - 录制历史 (回放) - 需要 $$recording$$ namespace 存 timeline
|
|
16
|
+
* - 多片段录制 - 同上
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { CapabilityRegistry } from "../CapabilityRegistry";
|
|
20
|
+
import { CapabilityContext, ICapability } from "../Capability";
|
|
21
|
+
import { StateErrorManager } from "../StateErrorManagerV2";
|
|
22
|
+
|
|
23
|
+
export const RecordingCapability: ICapability & {
|
|
24
|
+
isRecording: (ctrl: any) => boolean
|
|
25
|
+
} = {
|
|
26
|
+
name: "recording",
|
|
27
|
+
|
|
28
|
+
isRecording: (ctrl: any) => !!(ctrl && ctrl.isRecording),
|
|
29
|
+
|
|
30
|
+
onRecordingStart(ctx: CapabilityContext): void {
|
|
31
|
+
StateErrorManager.debug("RecordingCapability.onRecordingStart", {
|
|
32
|
+
component: "RecordingCapability",
|
|
33
|
+
method: "onRecordingStart",
|
|
34
|
+
params: { ctrlName: ctx.ctrl?.ctrlName },
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
onRecordingStop(ctx: CapabilityContext): void {
|
|
39
|
+
StateErrorManager.debug("RecordingCapability.onRecordingStop", {
|
|
40
|
+
component: "RecordingCapability",
|
|
41
|
+
method: "onRecordingStop",
|
|
42
|
+
params: { ctrlName: ctx.ctrl?.ctrlName },
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
onStateWillChange(ctx: CapabilityContext): void {
|
|
47
|
+
// 录制中切 state, Topic 3 的 StateSelectV2.onStateWillChange 已直接处理 diff commit,
|
|
48
|
+
// 这里仅作 capability 路径上的 log, 让其它监听者 (如 timeline / undo) 知道发生.
|
|
49
|
+
if (ctx.ctrl?.isRecording) {
|
|
50
|
+
StateErrorManager.debug("RecordingCapability.onStateWillChange (recording)", {
|
|
51
|
+
component: "RecordingCapability",
|
|
52
|
+
method: "onStateWillChange",
|
|
53
|
+
params: { fromState: ctx.fromState },
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
onStateChanged(ctx: CapabilityContext): void {
|
|
59
|
+
if (ctx.ctrl?.isRecording) {
|
|
60
|
+
StateErrorManager.debug("RecordingCapability.onStateChanged (recording)", {
|
|
61
|
+
component: "RecordingCapability",
|
|
62
|
+
method: "onStateChanged",
|
|
63
|
+
params: { toState: ctx.ctrl.selectedIndex },
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
CapabilityRegistry.register(RecordingCapability);
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SelectedPageIdCapability (Wave 3 T06).
|
|
3
|
+
*
|
|
4
|
+
* 用稳定的 stateId 切换 controller, 解决 ctrl.selectedIndex 在 reorder/delete 后下标飘移的问题.
|
|
5
|
+
*
|
|
6
|
+
* SelectedPageIdCapability.setStateById(ctrl, stateId) → boolean
|
|
7
|
+
* SelectedPageIdCapability.getSelectedStateId(ctrl) → 当前 state 的 stateId, 无效 -1
|
|
8
|
+
* SelectedPageIdCapability.getStateIdByName(ctrl, name) → stateId | -1
|
|
9
|
+
* SelectedPageIdCapability.listAllStates(ctrl) → [{stateId, name, index}]
|
|
10
|
+
*
|
|
11
|
+
* 不引入新的持久化字段; 全部从 _states[].stateId 派生.
|
|
12
|
+
* 切换走标准 selectedIndex setter, 自动联动 EventCapability / RecordingCapability 等.
|
|
13
|
+
*
|
|
14
|
+
* 用途:
|
|
15
|
+
* - Panel 用 listAllStates 渲染 state 列表 + setStateById 切换
|
|
16
|
+
* - 业务代码用 setStateById("home") 等稳定 API, 不依赖临时 index
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { CapabilityRegistry } from "../CapabilityRegistry";
|
|
20
|
+
import { ICapability } from "../Capability";
|
|
21
|
+
|
|
22
|
+
export interface StateInfo {
|
|
23
|
+
index: number
|
|
24
|
+
stateId: number
|
|
25
|
+
name: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function findIndexByStateId(ctrl: any, stateId: number): number {
|
|
29
|
+
const states = ctrl && ctrl._states;
|
|
30
|
+
if (!states) return -1;
|
|
31
|
+
for (let i = 0; i < states.length; i++) {
|
|
32
|
+
const s = states[i];
|
|
33
|
+
if (s && s.stateId === stateId) return i;
|
|
34
|
+
}
|
|
35
|
+
return -1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const SelectedPageIdCapability: ICapability & {
|
|
39
|
+
setStateById: (ctrl: any, stateId: number) => boolean
|
|
40
|
+
getSelectedStateId: (ctrl: any) => number
|
|
41
|
+
getStateIdByName: (ctrl: any, name: string) => number
|
|
42
|
+
listAllStates: (ctrl: any) => StateInfo[]
|
|
43
|
+
} = {
|
|
44
|
+
name: "selectedPageId",
|
|
45
|
+
|
|
46
|
+
setStateById(ctrl: any, stateId: number): boolean {
|
|
47
|
+
if (!ctrl) return false;
|
|
48
|
+
const idx = findIndexByStateId(ctrl, stateId);
|
|
49
|
+
if (idx < 0) return false;
|
|
50
|
+
ctrl.selectedIndex = idx;
|
|
51
|
+
return true;
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
getSelectedStateId(ctrl: any): number {
|
|
55
|
+
if (!ctrl) return -1;
|
|
56
|
+
const idx = ctrl.selectedIndex;
|
|
57
|
+
const states = ctrl._states;
|
|
58
|
+
if (!states || idx < 0 || idx >= states.length) return -1;
|
|
59
|
+
const s = states[idx];
|
|
60
|
+
return (s && typeof s.stateId === "number") ? s.stateId : -1;
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
getStateIdByName(ctrl: any, name: string): number {
|
|
64
|
+
if (!ctrl) return -1;
|
|
65
|
+
const states = ctrl._states;
|
|
66
|
+
if (!states) return -1;
|
|
67
|
+
for (let i = 0; i < states.length; i++) {
|
|
68
|
+
const s = states[i];
|
|
69
|
+
if (s && s.name === name) return s.stateId;
|
|
70
|
+
}
|
|
71
|
+
return -1;
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
listAllStates(ctrl: any): StateInfo[] {
|
|
75
|
+
const out: StateInfo[] = [];
|
|
76
|
+
if (!ctrl) return out;
|
|
77
|
+
const states = ctrl._states;
|
|
78
|
+
if (!states) return out;
|
|
79
|
+
for (let i = 0; i < states.length; i++) {
|
|
80
|
+
const s = states[i];
|
|
81
|
+
if (!s) continue;
|
|
82
|
+
out.push({ index: i, stateId: s.stateId, name: s.name });
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
CapabilityRegistry.register(SelectedPageIdCapability);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ver": "1.1.3",
|
|
3
|
+
"uuid": "c56c1d4e-382e-4e33-9862-90c97b5d3b94",
|
|
4
|
+
"importer": "folder",
|
|
5
|
+
"isBundle": false,
|
|
6
|
+
"bundleName": "",
|
|
7
|
+
"priority": 1,
|
|
8
|
+
"compressionType": {},
|
|
9
|
+
"optimizeHotUpdate": {},
|
|
10
|
+
"inlineSpriteFrames": {},
|
|
11
|
+
"isRemoteBundle": {},
|
|
12
|
+
"subMetas": {}
|
|
13
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { EnumStateName } from "../StateEnumV2";
|
|
2
|
+
import type { StateControllerV2 } from "../StateControllerV2";
|
|
3
|
+
|
|
4
|
+
const { ccclass, property } = cc._decorator;
|
|
5
|
+
|
|
6
|
+
// 本文件早于 StateControllerV2 内的 cc.Enum(EnumStateName) 被 import,
|
|
7
|
+
// 这里先注册一次 (idempotent), 保证回收站下拉的 @property type 能解析到枚举。
|
|
8
|
+
cc.Enum(EnumStateName);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* StateControllerV2「状态操作」分组 — inspector 可折叠区域.
|
|
12
|
+
*
|
|
13
|
+
* 设计同 StateNodeProps: 自身不持状态, 仅作 inspector 视图 facade, getter/setter
|
|
14
|
+
* 全部代理到 owner (StateControllerV2) 的同名访问器 (真实逻辑仍在 controller 上,
|
|
15
|
+
* 测试 / 代码可继续走 ctrl.moveStateUp 老路径). owner 在 __preload 中注入.
|
|
16
|
+
*/
|
|
17
|
+
@ccclass("CtrlStateOpsGroup")
|
|
18
|
+
export class CtrlStateOpsGroup {
|
|
19
|
+
public owner: StateControllerV2 = null;
|
|
20
|
+
|
|
21
|
+
@property({ displayName: "状态上移", tooltip: "将当前选中的状态上移一位" })
|
|
22
|
+
public get moveStateUp() {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public set moveStateUp(v: boolean) {
|
|
27
|
+
if (this.owner) this.owner.moveStateUp = v;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@property({ displayName: "状态下移", tooltip: "将当前选中的状态下移一位" })
|
|
31
|
+
public get moveStateDown() {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public set moveStateDown(v: boolean) {
|
|
36
|
+
if (this.owner) this.owner.moveStateDown = v;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@property({ displayName: "复制当前状态", tooltip: "以当前状态为模板复制并插入到下一位" })
|
|
40
|
+
public get duplicateCurrentState() {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public set duplicateCurrentState(v: boolean) {
|
|
45
|
+
if (this.owner) this.owner.duplicateCurrentState = v;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@property({ displayName: "删除当前状态", tooltip: "删除当前选中的状态并自动选择相邻状态" })
|
|
49
|
+
public get deleteCurrentState() {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public set deleteCurrentState(v: boolean) {
|
|
54
|
+
if (this.owner) this.owner.deleteCurrentState = v;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* StateControllerV2「回收站」分组 — inspector 可折叠区域.
|
|
60
|
+
*
|
|
61
|
+
* 让"软删 → 恢复 / 彻底删除"在 inspector 内闭环 (无需插件面板). facade 同 SelectExcludeGroup:
|
|
62
|
+
* - deletedList 只读展示回收站内容 (name + id)。
|
|
63
|
+
* - restoreTarget / purgeTarget 下拉的动态 enumList 由 owner.refreshRecycleBinEnums 注入到本组类上;
|
|
64
|
+
* getter 恒返 0 (sentinel "选一个…"), 选项 value 从 1 起, 选中即触发动作并自动回到 sentinel。
|
|
65
|
+
* - purgeTarget / purgeAll 是硬删 (不可恢复), 经 owner.showDialog 弹窗二次确认。
|
|
66
|
+
*/
|
|
67
|
+
@ccclass("CtrlRecycleBinGroup")
|
|
68
|
+
export class CtrlRecycleBinGroup {
|
|
69
|
+
public owner: StateControllerV2 = null;
|
|
70
|
+
|
|
71
|
+
@property({ type: [cc.String], readonly: true, displayName: "回收站内容", tooltip: "已移除的状态 (软删, 数据保留)。下方可恢复或彻底删除" })
|
|
72
|
+
public get deletedList(): string[] {
|
|
73
|
+
return this.owner ? this.owner.getDeletedStatesDisplay() : [];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@property({ type: EnumStateName, displayName: "↩ 恢复状态", tooltip: "选择要恢复的状态, 追加到状态列表尾部 (具体数据自动接回)" })
|
|
77
|
+
public get restoreTarget(): number {
|
|
78
|
+
return 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public set restoreTarget(v: number) {
|
|
82
|
+
if (this.owner) this.owner.recycleRestorePick(v);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@property({ type: EnumStateName, displayName: "🗑 彻底删除", tooltip: "选择要彻底删除的状态 (清空其数据, 不可恢复)" })
|
|
86
|
+
public get purgeTarget(): number {
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public set purgeTarget(v: number) {
|
|
91
|
+
if (this.owner) this.owner.recyclePurgePick(v);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@property({ type: EnumStateName, displayName: "👁 预览", tooltip: "选择一个回收态只读预览 (叠加到节点, 不改当前选中)。改选中/录制会自动退出预览" })
|
|
95
|
+
public get previewTarget(): number {
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public set previewTarget(v: number) {
|
|
100
|
+
if (this.owner) this.owner.recyclePreviewPick(v);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@property({ displayName: "⏹ 退出预览", tooltip: "退出回收态预览, 按快照把节点精确还原到预览前" })
|
|
104
|
+
public get exitPreviewTrigger(): boolean {
|
|
105
|
+
return this.owner ? this.owner.isPreviewing : false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public set exitPreviewTrigger(_v: boolean) {
|
|
109
|
+
if (this.owner) this.owner.recycleExitPreview();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@property({ displayName: "清空回收站", tooltip: "彻底删除回收站内全部状态数据, 不可恢复" })
|
|
113
|
+
public get purgeAll(): boolean {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public set purgeAll(v: boolean) {
|
|
118
|
+
if (this.owner && v) this.owner.recyclePurgeAll();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* StateControllerV2「录制」分组 — inspector 可折叠区域.
|
|
124
|
+
* recordTrigger 镜像 owner.isRecording (经 owner.recordTrigger getter), 点击 toggle 起停.
|
|
125
|
+
*/
|
|
126
|
+
@ccclass("CtrlRecordGroup")
|
|
127
|
+
export class CtrlRecordGroup {
|
|
128
|
+
public owner: StateControllerV2 = null;
|
|
129
|
+
|
|
130
|
+
@property({ displayName: "🔴 录制", tooltip: "进入/退出录制模式. 录制中, 节点改动自动写入当前 state. 要回退整次录制用编辑器 Ctrl+Z" })
|
|
131
|
+
public get recordTrigger() {
|
|
132
|
+
return this.owner ? this.owner.recordTrigger : false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public set recordTrigger(v: boolean) {
|
|
136
|
+
if (this.owner) this.owner.recordTrigger = v;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { EnumExcludeSlot } from "../StateEnumV2";
|
|
2
|
+
import type { StateSelectV2 } from "../StateSelectV2";
|
|
3
|
+
|
|
4
|
+
const { ccclass, property } = cc._decorator;
|
|
5
|
+
|
|
6
|
+
// 本文件被 StateSelectV2 import 的时机早于 StateSelectV2 内的 cc.Enum(EnumExcludeSlot),
|
|
7
|
+
// 这里先注册一次 (idempotent), 保证 addExcludeTrigger 的 @property type 能解析到枚举.
|
|
8
|
+
cc.Enum(EnumExcludeSlot);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* StateSelectV2「排除管理」分组 — inspector 可折叠区域.
|
|
12
|
+
*
|
|
13
|
+
* facade 同 StateNodeProps: getter/setter 代理到 owner. 注意:
|
|
14
|
+
* - excludedPropsDisplay getter 内含 reconcile 副作用 (owner 侧), inspector 渲染时触发.
|
|
15
|
+
* - userExcludedProps 代理同一份 owner._userExcludedProps 数组引用 (序列化字段仍在 owner 上,
|
|
16
|
+
* 不挪路径), cocos 数组 +/- 走 setter 回写 owner.
|
|
17
|
+
* - addExcludeTrigger 的动态 enumList 由 owner.refreshExcludeEnumLists 注入到本组类上.
|
|
18
|
+
*/
|
|
19
|
+
@ccclass("SelectExcludeGroup")
|
|
20
|
+
export class SelectExcludeGroup {
|
|
21
|
+
public owner: StateSelectV2 = null;
|
|
22
|
+
|
|
23
|
+
@property({ displayName: "排除跟随", tooltip: "当前被排除的 prop 列表 (系统 + 用户). 系统部分不可恢复.", readonly: true })
|
|
24
|
+
public get excludedPropsDisplay(): string[] {
|
|
25
|
+
return this.owner ? this.owner.excludedPropsDisplay : [];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@property({ type: EnumExcludeSlot, displayName: "+ 添加排除", tooltip: "从当前跟随中选一个 prop 加入排除清单" })
|
|
29
|
+
public get addExcludeTrigger(): number {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public set addExcludeTrigger(v: number) {
|
|
34
|
+
if (this.owner) this.owner.addExcludeTrigger = v;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@property({ type: EnumExcludeSlot, displayName: "- 恢复跟随", tooltip: "从用户排除清单选一个 prop 恢复跟随 (含 [失效] 项可在此清理)" })
|
|
38
|
+
public get removeExcludeTrigger(): number {
|
|
39
|
+
return this.owner ? this.owner.removeExcludeTrigger : 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public set removeExcludeTrigger(v: number) {
|
|
43
|
+
if (this.owner) this.owner.removeExcludeTrigger = v;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@property({
|
|
47
|
+
type: [cc.String],
|
|
48
|
+
displayName: "用户排除清单",
|
|
49
|
+
tooltip: "用户手动排除的 prop 列表 (除 SYSTEM_EXCLUDE 外). 用 +/- 按钮增删数组项 (不要直接编辑文本: 加项请走 '+ 添加排除' 下拉). 删项 = 重新跟随.",
|
|
50
|
+
readonly: true,
|
|
51
|
+
})
|
|
52
|
+
public get userExcludedProps(): string[] {
|
|
53
|
+
return this.owner ? this.owner._userExcludedProps : [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public set userExcludedProps(v: string[]) {
|
|
57
|
+
if (this.owner) this.owner._userExcludedProps = v;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* StateSelectV2「录制」分组 — inspector 可折叠区域.
|
|
63
|
+
* 镜像 currCtrl.isRecording, 与 StateControllerV2 录制态共享 (经 owner.recordTrigger getter/setter).
|
|
64
|
+
*/
|
|
65
|
+
@ccclass("SelectRecordGroup")
|
|
66
|
+
export class SelectRecordGroup {
|
|
67
|
+
public owner: StateSelectV2 = null;
|
|
68
|
+
|
|
69
|
+
@property({ displayName: "🔴 录制", tooltip: "进入/退出录制模式. 录制中, 节点改动自动写入当前 state. 要回退整次录制用编辑器 Ctrl+Z" })
|
|
70
|
+
public get recordTrigger() {
|
|
71
|
+
return this.owner ? this.owner.recordTrigger : false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public set recordTrigger(v: boolean) {
|
|
75
|
+
if (this.owner) this.owner.recordTrigger = v;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* StateSelectV2「值搬运」分组 — inspector 可折叠区域.
|
|
81
|
+
* 节点级局部操作: 当前 state ↔ 下一 state 的值数据 (不改 state 数量 / 选中).
|
|
82
|
+
*/
|
|
83
|
+
@ccclass("SelectValueOpsGroup")
|
|
84
|
+
export class SelectValueOpsGroup {
|
|
85
|
+
public owner: StateSelectV2 = null;
|
|
86
|
+
|
|
87
|
+
@property({ displayName: "⇄ 与下一 state 交换值", tooltip: "把本节点当前 state 的值数据与下一 state 互换 (仅本节点, 不改 state 数量/选中)" })
|
|
88
|
+
public get swapValueWithNext(): boolean {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public set swapValueWithNext(v: boolean) {
|
|
93
|
+
if (this.owner) this.owner.swapValueWithNext = v;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@property({ displayName: "⎘ 复制值到下一 state", tooltip: "把本节点当前 state 的值数据深拷到下一 state (仅本节点, 不改 state 数量/选中)" })
|
|
97
|
+
public get copyValueToNext(): boolean {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public set copyValueToNext(v: boolean) {
|
|
102
|
+
if (this.owner) this.owner.copyValueToNext = v;
|
|
103
|
+
}
|
|
104
|
+
}
|