@combos-fun/plugin-development-tool 0.0.13 → 0.0.15
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/dist/plugin-development-tool.cjs.js +454 -40
- package/dist/plugin-development-tool.cjs.js.map +1 -1
- package/dist/plugin-development-tool.cjs.prod.js +1 -1
- package/dist/plugin-development-tool.d.ts +49 -4
- package/dist/plugin-development-tool.esm.js +444 -37
- package/dist/plugin-development-tool.esm.js.map +1 -1
- package/package.json +5 -4
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Component, System, OBSERVER_TYPE, GameObject, decorators } from '@combos-fun/engine';
|
|
2
1
|
import { __decorate } from 'tslib';
|
|
2
|
+
import { Component, System, OBSERVER_TYPE, GameObject, decorators } from '@combos-fun/engine';
|
|
3
|
+
import { RendererSystem } from '@combos-fun/plugin-renderer';
|
|
3
4
|
import { Graphics } from '@combos-fun/plugin-renderer-graphics';
|
|
4
5
|
import { Event, HIT_AREA_TYPE } from '@combos-fun/plugin-renderer-event';
|
|
5
6
|
|
|
@@ -9,6 +10,10 @@ const COMBOS_DEVELOPMENT_TOOL_SET = 'combos-development-tool:set';
|
|
|
9
10
|
const COMBOS_DEVELOPMENT_TOOL_REFRESH = 'combos-development-tool:refresh';
|
|
10
11
|
/** Emitted to `window.parent` when an object is selected while the tool is on. */
|
|
11
12
|
const COMBOS_DEVELOPMENT_TOOL_GAMEOBJECT_SELECTED = 'combos-development-tool:gameobject-selected';
|
|
13
|
+
/** Parent → iframe: apply a value to a component field (live preview). */
|
|
14
|
+
const COMBOS_DEVELOPMENT_TOOL_APPLY_PROPERTY = 'combos-development-tool:apply-property';
|
|
15
|
+
/** iframe → parent: game scene bootstrap finished; parent may enable pick mode. */
|
|
16
|
+
const COMBOS_DEVELOPMENT_TOOL_READY = 'combos-development-tool:ready';
|
|
12
17
|
|
|
13
18
|
/**
|
|
14
19
|
* Optional marker when using `CombosDevelopmentToolSystem` with `scope: 'tagged'`, or to attach
|
|
@@ -25,6 +30,243 @@ class CombosDevelopmentToolTarget extends Component {
|
|
|
25
30
|
}
|
|
26
31
|
}
|
|
27
32
|
|
|
33
|
+
function isSceneSourceAnchor(v) {
|
|
34
|
+
return (!!v &&
|
|
35
|
+
typeof v === 'object' &&
|
|
36
|
+
typeof v.file === 'string');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const SKIP_KEYS = new Set([
|
|
40
|
+
'gameObject',
|
|
41
|
+
'name',
|
|
42
|
+
'started',
|
|
43
|
+
'__componentDefaultParams',
|
|
44
|
+
'destroyed',
|
|
45
|
+
'inScene',
|
|
46
|
+
'worldTransform',
|
|
47
|
+
'children',
|
|
48
|
+
'_parent',
|
|
49
|
+
]);
|
|
50
|
+
const COMPONENT_SKIP_KEYS = {
|
|
51
|
+
Physics: new Set([
|
|
52
|
+
'body',
|
|
53
|
+
'Body',
|
|
54
|
+
'PhysicsEngine',
|
|
55
|
+
'World',
|
|
56
|
+
'Constraint',
|
|
57
|
+
'mouseConstraint',
|
|
58
|
+
'bodyParams',
|
|
59
|
+
]),
|
|
60
|
+
Event: new Set(['hitArea']),
|
|
61
|
+
};
|
|
62
|
+
function cloneJsonSafe(value, depth = 0) {
|
|
63
|
+
if (value === null || value === undefined)
|
|
64
|
+
return value;
|
|
65
|
+
if (typeof value === 'number' || typeof value === 'string' || typeof value === 'boolean') {
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
if (depth > 6)
|
|
69
|
+
return undefined;
|
|
70
|
+
if (Array.isArray(value)) {
|
|
71
|
+
return value.map(item => cloneJsonSafe(item, depth + 1));
|
|
72
|
+
}
|
|
73
|
+
if (typeof value === 'object') {
|
|
74
|
+
const out = {};
|
|
75
|
+
for (const [k, v] of Object.entries(value)) {
|
|
76
|
+
if (typeof v === 'function')
|
|
77
|
+
continue;
|
|
78
|
+
const cloned = cloneJsonSafe(v, depth + 1);
|
|
79
|
+
if (cloned !== undefined)
|
|
80
|
+
out[k] = cloned;
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
function serializeComponent(comp) {
|
|
87
|
+
const out = {};
|
|
88
|
+
const componentSkips = COMPONENT_SKIP_KEYS[comp.name];
|
|
89
|
+
for (const key of Object.keys(comp)) {
|
|
90
|
+
if (SKIP_KEYS.has(key) || key.startsWith('_'))
|
|
91
|
+
continue;
|
|
92
|
+
if (componentSkips?.has(key))
|
|
93
|
+
continue;
|
|
94
|
+
const value = comp[key];
|
|
95
|
+
if (typeof value === 'function')
|
|
96
|
+
continue;
|
|
97
|
+
const cloned = cloneJsonSafe(value);
|
|
98
|
+
if (cloned !== undefined)
|
|
99
|
+
out[key] = cloned;
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
function readSourceAnchor(go) {
|
|
104
|
+
const tag = go.getComponent(CombosDevelopmentToolTarget);
|
|
105
|
+
const raw = tag?.payload?.source;
|
|
106
|
+
if (!isSceneSourceAnchor(raw))
|
|
107
|
+
return undefined;
|
|
108
|
+
return {
|
|
109
|
+
file: raw.file,
|
|
110
|
+
anchor: raw.anchor ?? go.name,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function buildGameObjectSnapshot(go) {
|
|
114
|
+
const components = go.components
|
|
115
|
+
.filter(c => c.name !== 'CombosDevelopmentToolTarget')
|
|
116
|
+
.map(c => ({
|
|
117
|
+
componentName: c.name,
|
|
118
|
+
fields: serializeComponent(c),
|
|
119
|
+
}));
|
|
120
|
+
return {
|
|
121
|
+
id: go.id,
|
|
122
|
+
name: go.name,
|
|
123
|
+
components,
|
|
124
|
+
source: readSourceAnchor(go),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function applyPropertyValue(go, componentName, path, value) {
|
|
128
|
+
const comp = go.getComponent(componentName);
|
|
129
|
+
if (!comp || !path.length)
|
|
130
|
+
return false;
|
|
131
|
+
let target = comp;
|
|
132
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
133
|
+
const key = path[i];
|
|
134
|
+
if (target[key] === undefined || target[key] === null) {
|
|
135
|
+
target[key] = {};
|
|
136
|
+
}
|
|
137
|
+
target = target[key];
|
|
138
|
+
}
|
|
139
|
+
target[path[path.length - 1]] = value;
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
function readPropertyValue(go, componentName, path) {
|
|
143
|
+
const comp = go.getComponent(componentName);
|
|
144
|
+
if (!comp || !path.length)
|
|
145
|
+
return undefined;
|
|
146
|
+
let target = comp;
|
|
147
|
+
for (const key of path) {
|
|
148
|
+
if (target === null || target === undefined || typeof target !== 'object') {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
target = target[key];
|
|
152
|
+
}
|
|
153
|
+
return target;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const TRANSFORM_VECTOR_KEYS = new Set([
|
|
157
|
+
'position',
|
|
158
|
+
'size',
|
|
159
|
+
'origin',
|
|
160
|
+
'anchor',
|
|
161
|
+
'scale',
|
|
162
|
+
'skew',
|
|
163
|
+
]);
|
|
164
|
+
function asNumber(value) {
|
|
165
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
169
|
+
const next = Number(value);
|
|
170
|
+
return Number.isFinite(next) ? next : undefined;
|
|
171
|
+
}
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
function syncPhysicsBodyFromTransform(go) {
|
|
175
|
+
const physics = go.getComponent('Physics');
|
|
176
|
+
if (!physics?.body) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const { x, y } = go.transform.position;
|
|
180
|
+
if (physics.Body?.setPosition) {
|
|
181
|
+
physics.Body.setPosition(physics.body, { x, y });
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
physics.body.position.x = x;
|
|
185
|
+
physics.body.position.y = y;
|
|
186
|
+
}
|
|
187
|
+
function syncMoverOriginFromTransform(go) {
|
|
188
|
+
const mover = go.getComponent('PlatformerMover');
|
|
189
|
+
if (!mover) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
mover.originX = go.transform.position.x;
|
|
193
|
+
mover.originY = go.transform.position.y;
|
|
194
|
+
}
|
|
195
|
+
function applyTransformProperty(go, comp, path, value) {
|
|
196
|
+
const transform = go.transform ?? comp;
|
|
197
|
+
const transformRecord = transform;
|
|
198
|
+
if (path.length === 1 && path[0] === 'rotation') {
|
|
199
|
+
const next = asNumber(value);
|
|
200
|
+
if (next === undefined) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
transform.rotation = next;
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
if (path.length === 2 && TRANSFORM_VECTOR_KEYS.has(path[0])) {
|
|
207
|
+
const groupKey = path[0];
|
|
208
|
+
const leafKey = path[1];
|
|
209
|
+
const next = asNumber(value);
|
|
210
|
+
if (next === undefined) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
const group = transformRecord[groupKey];
|
|
214
|
+
if (!group || typeof group !== 'object') {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
group[leafKey] = next;
|
|
218
|
+
if (groupKey === 'position') {
|
|
219
|
+
syncPhysicsBodyFromTransform(go);
|
|
220
|
+
syncMoverOriginFromTransform(go);
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
function applyTextProperty(_go, comp, path, value) {
|
|
227
|
+
const textComp = comp;
|
|
228
|
+
if (path.length === 1 && path[0] === 'text') {
|
|
229
|
+
textComp.text = String(value ?? '');
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
if (path.length === 2 && path[0] === 'style') {
|
|
233
|
+
const styleKey = path[1];
|
|
234
|
+
const nextStyle = { ...(textComp.style ?? {}), [styleKey]: value };
|
|
235
|
+
textComp.style = nextStyle;
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
function applySoundProperty(_go, comp, path, value) {
|
|
241
|
+
const soundComp = comp;
|
|
242
|
+
if ((path.length === 1 && path[0] === 'volume') ||
|
|
243
|
+
(path.length === 2 && path[0] === 'config' && path[1] === 'volume')) {
|
|
244
|
+
const next = asNumber(value);
|
|
245
|
+
if (next === undefined) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
soundComp.volume = next;
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
const APPLY_HOOKS = {
|
|
254
|
+
Transform: applyTransformProperty,
|
|
255
|
+
Text: applyTextProperty,
|
|
256
|
+
Sound: applySoundProperty,
|
|
257
|
+
};
|
|
258
|
+
function applyPropertyWithHooks(go, componentName, path, value) {
|
|
259
|
+
const comp = go.getComponent(componentName);
|
|
260
|
+
if (!comp || !path.length) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
const hook = APPLY_HOOKS[componentName];
|
|
264
|
+
if (hook?.(go, comp, path, value)) {
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
return applyPropertyValue(go, componentName, path, value);
|
|
268
|
+
}
|
|
269
|
+
|
|
28
270
|
const OUTLINE_GO_NAME = '__combosDevelopmentToolOutline';
|
|
29
271
|
/**
|
|
30
272
|
* **Defaults:** `scope: 'scene'`, **off** at start (no tap hijack until enabled).
|
|
@@ -48,6 +290,7 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
|
|
|
48
290
|
/** We added `Event` for hit-testing; remove on teardown when disabling / releaseTap. */
|
|
49
291
|
this.injectedEvents = new Set();
|
|
50
292
|
this.needsSceneRescan = false;
|
|
293
|
+
this.needsTaggedRescan = false;
|
|
51
294
|
this.onWindowSet = (e) => {
|
|
52
295
|
const d = e.detail;
|
|
53
296
|
if (d && typeof d.enabled === 'boolean') {
|
|
@@ -64,6 +307,9 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
|
|
|
64
307
|
else if (d.type === COMBOS_DEVELOPMENT_TOOL_REFRESH) {
|
|
65
308
|
this.requestSceneRescan();
|
|
66
309
|
}
|
|
310
|
+
else if (d.type === COMBOS_DEVELOPMENT_TOOL_APPLY_PROPERTY) {
|
|
311
|
+
this.handleApplyProperty(d);
|
|
312
|
+
}
|
|
67
313
|
};
|
|
68
314
|
this.onGameSet = (payload) => {
|
|
69
315
|
if (payload && typeof payload.enabled === 'boolean') {
|
|
@@ -91,6 +337,9 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
|
|
|
91
337
|
if (this.enabled && this.scope === 'scene') {
|
|
92
338
|
this.needsSceneRescan = true;
|
|
93
339
|
}
|
|
340
|
+
else if (this.enabled && this.scope === 'tagged') {
|
|
341
|
+
this.needsTaggedRescan = true;
|
|
342
|
+
}
|
|
94
343
|
}
|
|
95
344
|
onDestroy() {
|
|
96
345
|
if (typeof window !== 'undefined') {
|
|
@@ -110,22 +359,27 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
|
|
|
110
359
|
this.enabled = on;
|
|
111
360
|
if (!on) {
|
|
112
361
|
this.clearSelection();
|
|
113
|
-
|
|
114
|
-
this.detachAllTaps();
|
|
115
|
-
}
|
|
362
|
+
this.detachAllTaps();
|
|
116
363
|
}
|
|
117
364
|
else if (this.scope === 'scene') {
|
|
118
365
|
this.needsSceneRescan = true;
|
|
119
366
|
}
|
|
367
|
+
else {
|
|
368
|
+
this.needsTaggedRescan = true;
|
|
369
|
+
}
|
|
120
370
|
}
|
|
121
371
|
get isEnabled() {
|
|
122
372
|
return this.enabled;
|
|
123
373
|
}
|
|
124
374
|
update(e) {
|
|
125
|
-
if (this.
|
|
375
|
+
if (this.enabled && this.needsSceneRescan && this.scope === 'scene') {
|
|
126
376
|
this.needsSceneRescan = false;
|
|
127
377
|
this.attachSceneTree();
|
|
128
378
|
}
|
|
379
|
+
if (this.enabled && this.needsTaggedRescan && this.scope === 'tagged') {
|
|
380
|
+
this.needsTaggedRescan = false;
|
|
381
|
+
this.attachTaggedObjects();
|
|
382
|
+
}
|
|
129
383
|
for (const go of [...this.tapOwners.values()]) {
|
|
130
384
|
if (go.destroyed) {
|
|
131
385
|
this.releaseTap(go);
|
|
@@ -136,12 +390,12 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
|
|
|
136
390
|
const gfxComp = this.outlineGo.getComponent(Graphics);
|
|
137
391
|
if (!gfxComp?.graphics)
|
|
138
392
|
return;
|
|
139
|
-
const
|
|
393
|
+
const bounds = this.resolvePickBounds(this.selected);
|
|
140
394
|
const g = gfxComp.graphics;
|
|
141
395
|
g.clear();
|
|
142
396
|
const t = typeof performance !== 'undefined' ? performance.now() : e.time;
|
|
143
397
|
const pulse = 0.35 + 0.65 * (0.5 + 0.5 * Math.sin(t * 0.012));
|
|
144
|
-
g.rect(
|
|
398
|
+
g.rect(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
145
399
|
g.stroke({ width: 4, color: 0x55ffaa, alpha: pulse });
|
|
146
400
|
}
|
|
147
401
|
componentChanged(changed) {
|
|
@@ -162,9 +416,29 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
|
|
|
162
416
|
}
|
|
163
417
|
/** Re-bind scene taps when `scope === 'scene'` (e.g. after dynamic spawn). */
|
|
164
418
|
requestSceneRescan() {
|
|
165
|
-
if (
|
|
419
|
+
if (!this.enabled)
|
|
166
420
|
return;
|
|
167
|
-
this.
|
|
421
|
+
if (this.scope === 'scene') {
|
|
422
|
+
this.needsSceneRescan = true;
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
this.needsTaggedRescan = true;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
attachTaggedObjects() {
|
|
429
|
+
const list = [];
|
|
430
|
+
for (const tr of this.game.scene.transform.children) {
|
|
431
|
+
this.collectGameObjects(tr.gameObject, list);
|
|
432
|
+
}
|
|
433
|
+
for (const go of list) {
|
|
434
|
+
if (go.name === OUTLINE_GO_NAME)
|
|
435
|
+
continue;
|
|
436
|
+
if (go === this.outlineGo)
|
|
437
|
+
continue;
|
|
438
|
+
if (!go.getComponent(CombosDevelopmentToolTarget))
|
|
439
|
+
continue;
|
|
440
|
+
this.ensureTap(go);
|
|
441
|
+
}
|
|
168
442
|
}
|
|
169
443
|
attachSceneTree() {
|
|
170
444
|
this.detachAllTaps();
|
|
@@ -194,22 +468,85 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
|
|
|
194
468
|
ensureTap(go) {
|
|
195
469
|
let ev = go.getComponent(Event);
|
|
196
470
|
if (!ev) {
|
|
197
|
-
|
|
198
|
-
ev = go.addComponent(new Event({
|
|
199
|
-
hitArea: {
|
|
200
|
-
type: HIT_AREA_TYPE.Rect,
|
|
201
|
-
style: { x: 0, y: 0, width: width || 1, height: height || 1 },
|
|
202
|
-
},
|
|
203
|
-
}));
|
|
471
|
+
ev = go.addComponent(this.createInjectedEvent(go));
|
|
204
472
|
this.injectedEvents.add(go.id);
|
|
205
473
|
}
|
|
206
474
|
if (this.tapHandlers.has(go.id))
|
|
207
475
|
return;
|
|
208
|
-
const handler = () => this.onSelect(go);
|
|
476
|
+
const handler = (payload) => this.onSelect(go, payload);
|
|
209
477
|
this.tapHandlers.set(go.id, handler);
|
|
210
478
|
this.tapOwners.set(go.id, go);
|
|
211
479
|
ev.on('tap', handler);
|
|
212
480
|
}
|
|
481
|
+
createInjectedEvent(go) {
|
|
482
|
+
const { width, height } = go.transform.size;
|
|
483
|
+
if (width > 0 && height > 0) {
|
|
484
|
+
return new Event({
|
|
485
|
+
hitArea: {
|
|
486
|
+
type: HIT_AREA_TYPE.Rect,
|
|
487
|
+
style: { x: 0, y: 0, width, height },
|
|
488
|
+
},
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
const bounds = this.resolveContainerLocalBounds(go);
|
|
492
|
+
if (bounds) {
|
|
493
|
+
return new Event({
|
|
494
|
+
hitArea: {
|
|
495
|
+
type: HIT_AREA_TYPE.Rect,
|
|
496
|
+
style: {
|
|
497
|
+
x: bounds.x,
|
|
498
|
+
y: bounds.y,
|
|
499
|
+
width: bounds.width,
|
|
500
|
+
height: bounds.height,
|
|
501
|
+
},
|
|
502
|
+
},
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
// Let Pixi use natural rendered bounds instead of forcing a 1×1 hit area.
|
|
506
|
+
return new Event();
|
|
507
|
+
}
|
|
508
|
+
resolvePickBounds(go) {
|
|
509
|
+
const { width, height } = go.transform.size;
|
|
510
|
+
if (width > 0 && height > 0) {
|
|
511
|
+
return { x: 0, y: 0, width, height };
|
|
512
|
+
}
|
|
513
|
+
const fromContainer = this.resolveContainerLocalBounds(go);
|
|
514
|
+
if (fromContainer) {
|
|
515
|
+
return fromContainer;
|
|
516
|
+
}
|
|
517
|
+
return { x: 0, y: 0, width: 1, height: 1 };
|
|
518
|
+
}
|
|
519
|
+
resolveContainerLocalBounds(go) {
|
|
520
|
+
const container = this.getRendererContainer(go);
|
|
521
|
+
if (!container)
|
|
522
|
+
return null;
|
|
523
|
+
try {
|
|
524
|
+
const bounds = container.getLocalBounds();
|
|
525
|
+
if (bounds.width > 0 && bounds.height > 0) {
|
|
526
|
+
return {
|
|
527
|
+
x: bounds.x,
|
|
528
|
+
y: bounds.y,
|
|
529
|
+
width: bounds.width,
|
|
530
|
+
height: bounds.height,
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
catch {
|
|
535
|
+
/* ignore */
|
|
536
|
+
}
|
|
537
|
+
return null;
|
|
538
|
+
}
|
|
539
|
+
getRendererContainer(go) {
|
|
540
|
+
const rendererSystem = this.game.getSystem(RendererSystem);
|
|
541
|
+
if (!rendererSystem?.containerManager)
|
|
542
|
+
return null;
|
|
543
|
+
try {
|
|
544
|
+
return rendererSystem.containerManager.getContainer(go.id);
|
|
545
|
+
}
|
|
546
|
+
catch {
|
|
547
|
+
return null;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
213
550
|
releaseTap(go) {
|
|
214
551
|
const handler = this.tapHandlers.get(go.id);
|
|
215
552
|
if (!handler)
|
|
@@ -239,7 +576,7 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
|
|
|
239
576
|
go.addComponent(new Graphics());
|
|
240
577
|
this.outlineGo = go;
|
|
241
578
|
}
|
|
242
|
-
onSelect(go) {
|
|
579
|
+
onSelect(go, tap) {
|
|
243
580
|
if (!this.enabled)
|
|
244
581
|
return;
|
|
245
582
|
this.ensureOutline();
|
|
@@ -250,11 +587,91 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
|
|
|
250
587
|
this.outlineGo.remove();
|
|
251
588
|
}
|
|
252
589
|
go.addChild(this.outlineGo);
|
|
253
|
-
const
|
|
590
|
+
const snapshot = buildGameObjectSnapshot(go);
|
|
591
|
+
const payload = {
|
|
592
|
+
type: COMBOS_DEVELOPMENT_TOOL_GAMEOBJECT_SELECTED,
|
|
593
|
+
snapshot,
|
|
594
|
+
pointer: tap?.data?.position ?? null,
|
|
595
|
+
};
|
|
254
596
|
if (typeof window !== 'undefined' && window.parent && window.parent !== window) {
|
|
255
597
|
window.parent.postMessage(payload, this.postMessageOrigin);
|
|
256
598
|
}
|
|
257
599
|
}
|
|
600
|
+
findGameObjectById(id) {
|
|
601
|
+
const stack = [];
|
|
602
|
+
for (const tr of this.game.scene.transform.children) {
|
|
603
|
+
this.collectGameObjects(tr.gameObject, stack);
|
|
604
|
+
}
|
|
605
|
+
return stack.find(go => go.id === id) ?? null;
|
|
606
|
+
}
|
|
607
|
+
findGameObjectBySource(source) {
|
|
608
|
+
const stack = [];
|
|
609
|
+
for (const tr of this.game.scene.transform.children) {
|
|
610
|
+
this.collectGameObjects(tr.gameObject, stack);
|
|
611
|
+
}
|
|
612
|
+
const wantFile = source.file.trim();
|
|
613
|
+
const wantAnchor = (source.anchor ?? '').trim();
|
|
614
|
+
if (!wantAnchor) {
|
|
615
|
+
return null;
|
|
616
|
+
}
|
|
617
|
+
for (const go of stack) {
|
|
618
|
+
const anchor = readSourceAnchor(go);
|
|
619
|
+
if (!anchor || anchor.file !== wantFile) {
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
const resolvedAnchor = anchor.anchor ?? go.name;
|
|
623
|
+
if (resolvedAnchor === wantAnchor) {
|
|
624
|
+
return go;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return null;
|
|
628
|
+
}
|
|
629
|
+
resolveApplyTarget(payload) {
|
|
630
|
+
if (typeof payload.gameObjectId === 'number') {
|
|
631
|
+
const byId = this.findGameObjectById(payload.gameObjectId);
|
|
632
|
+
if (byId) {
|
|
633
|
+
return byId;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
const file = payload.source?.file?.trim();
|
|
637
|
+
const anchor = payload.source?.anchor?.trim();
|
|
638
|
+
if (!file || !anchor) {
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
641
|
+
return this.findGameObjectBySource({ file, anchor });
|
|
642
|
+
}
|
|
643
|
+
handleApplyProperty(payload) {
|
|
644
|
+
const componentName = payload.componentName;
|
|
645
|
+
const path = payload.path;
|
|
646
|
+
const hasId = typeof payload.gameObjectId === 'number';
|
|
647
|
+
const hasSource = Boolean(payload.source?.file?.trim()) && Boolean(payload.source?.anchor?.trim());
|
|
648
|
+
if ((!hasId && !hasSource) ||
|
|
649
|
+
typeof componentName !== 'string' ||
|
|
650
|
+
!Array.isArray(path) ||
|
|
651
|
+
path.length === 0) {
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
const go = this.resolveApplyTarget(payload);
|
|
655
|
+
if (!go)
|
|
656
|
+
return;
|
|
657
|
+
const applied = applyPropertyWithHooks(go, componentName, path, payload.value);
|
|
658
|
+
if (!applied)
|
|
659
|
+
return;
|
|
660
|
+
if (this.selected?.id === go.id) {
|
|
661
|
+
this.postSnapshotUpdate(go);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
postSnapshotUpdate(go) {
|
|
665
|
+
const snapshot = buildGameObjectSnapshot(go);
|
|
666
|
+
if (typeof window !== 'undefined' && window.parent && window.parent !== window) {
|
|
667
|
+
window.parent.postMessage({
|
|
668
|
+
type: COMBOS_DEVELOPMENT_TOOL_GAMEOBJECT_SELECTED,
|
|
669
|
+
snapshot,
|
|
670
|
+
pointer: null,
|
|
671
|
+
source: 'property-applied',
|
|
672
|
+
}, this.postMessageOrigin);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
258
675
|
clearSelection() {
|
|
259
676
|
this.selected = null;
|
|
260
677
|
if (this.outlineGo?.parent) {
|
|
@@ -265,29 +682,19 @@ let CombosDevelopmentToolSystem = class CombosDevelopmentToolSystem extends Syst
|
|
|
265
682
|
gfx.graphics.clear();
|
|
266
683
|
}
|
|
267
684
|
}
|
|
268
|
-
serializeGameObject(go) {
|
|
269
|
-
const tag = go.getComponent(CombosDevelopmentToolTarget);
|
|
270
|
-
const pos = go.transform.position;
|
|
271
|
-
const size = go.transform.size;
|
|
272
|
-
return {
|
|
273
|
-
type: COMBOS_DEVELOPMENT_TOOL_GAMEOBJECT_SELECTED,
|
|
274
|
-
gameObject: {
|
|
275
|
-
name: go.name,
|
|
276
|
-
id: go.id,
|
|
277
|
-
position: { x: pos.x, y: pos.y },
|
|
278
|
-
size: { width: size.width, height: size.height },
|
|
279
|
-
rotation: go.transform.rotation,
|
|
280
|
-
payload: tag?.payload ?? {},
|
|
281
|
-
},
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
685
|
};
|
|
285
686
|
CombosDevelopmentToolSystem = __decorate([
|
|
286
687
|
decorators.componentObserver({
|
|
287
688
|
CombosDevelopmentToolTarget: [],
|
|
288
689
|
})
|
|
289
690
|
], CombosDevelopmentToolSystem);
|
|
290
|
-
var
|
|
691
|
+
var CombosDevelopmentToolSystem$1 = CombosDevelopmentToolSystem;
|
|
692
|
+
|
|
693
|
+
/** Auto-generated by scripts/build-package.mjs — do not edit. */
|
|
694
|
+
Object.assign(CombosDevelopmentToolSystem$1, {
|
|
695
|
+
packageName: "@combos-fun/plugin-development-tool",
|
|
696
|
+
packageVersion: "0.0.15",
|
|
697
|
+
});
|
|
291
698
|
|
|
292
|
-
export { COMBOS_DEVELOPMENT_TOOL_GAMEOBJECT_SELECTED, COMBOS_DEVELOPMENT_TOOL_REFRESH, COMBOS_DEVELOPMENT_TOOL_SET,
|
|
699
|
+
export { COMBOS_DEVELOPMENT_TOOL_APPLY_PROPERTY, COMBOS_DEVELOPMENT_TOOL_GAMEOBJECT_SELECTED, COMBOS_DEVELOPMENT_TOOL_READY, COMBOS_DEVELOPMENT_TOOL_REFRESH, COMBOS_DEVELOPMENT_TOOL_SET, CombosDevelopmentToolSystem$1 as CombosDevelopmentToolSystem, CombosDevelopmentToolTarget, applyPropertyValue, applyPropertyWithHooks, buildGameObjectSnapshot, readPropertyValue, readSourceAnchor };
|
|
293
700
|
//# sourceMappingURL=plugin-development-tool.esm.js.map
|