@umicat/phaser-sdk 1.0.7 → 1.0.8
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/index.d.ts +1 -1
- package/dist/scene/SceneLoader.js +10 -2
- package/dist/scene/spawnEntity.js +70 -0
- package/dist/scene/types.d.ts +18 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -39,5 +39,5 @@ export { setupEditorBridge } from './editor/EditorBridge.js';
|
|
|
39
39
|
export { EditorOverlayScene, EDITOR_OVERLAY_KEY } from './editor/EditorOverlayScene.js';
|
|
40
40
|
export type { EditorEntityPatch, EditorEnterMessage, EditorExitMessage, EditorGetSceneMessage, EditorApplyEditMessage, EditorSetSelectionMessage, EditorPanZoomMessage, EditorHostToSdkMessage, EditorSceneLoadedMessage, EditorSelectionPickedMessage, EditorDragEndMessage, EditorShortcutMessage, EditorCreateEntityMessage, EditorDeleteEntityMessage, EditorSetEditModeMessage, EditorSelectionRectMessage, EditorSdkToHostMessage, } from './protocol.js';
|
|
41
41
|
export { SCHEMA_VERSION, isPerFrameNinePatch, isPerFrameHitbox, } from './scene/types.js';
|
|
42
|
-
export type { Manifest, ManifestGroup, SceneRef, HudRef, AssetRecord, AssetKind, SceneType, SceneFile, WorldScene, HudScene, WorldSceneConfig, CameraConfig, WorldEntity, WorldEntityKind, NonGroupWorldEntity, RenderableEntity, SpriteEntity, RectEntity, CircleEntity, CodeRenderedEntity, GroupEntity, TilemapEntity, TilemapLayer, TilesetMetadata, TileMetadata, TilesetAutotile, TilesetAnimation, WangTerrain, TriggerEntity, TriggerShape, HudEntity, HudEntityKind, HudEntityBase, HudTextEntity, HudImageEntity, HudIconButtonEntity, HudProgressBarEntity, HudPanelEntity, HudTextSource, HudNumberSource, HudLayer, Transform, Anchor, AnchorSide, NinePatchConfig, NinePatchPerFrame, HitboxRect, HitboxPerFrame, DepthAnchor, } from './scene/types.js';
|
|
42
|
+
export type { Manifest, ManifestGroup, SceneRef, HudRef, AssetRecord, AssetKind, SceneType, SceneFile, WorldScene, HudScene, WorldSceneConfig, CameraConfig, WorldEntity, WorldEntityKind, NonGroupWorldEntity, RenderableEntity, SpriteEntity, RectEntity, CircleEntity, CodeRenderedEntity, GroupEntity, TilemapEntity, TilemapLayer, TilesetMetadata, TileMetadata, TilesetAutotile, TilesetAnimation, WangTerrain, TriggerEntity, PrefabRefEntity, TriggerShape, HudEntity, HudEntityKind, HudEntityBase, HudTextEntity, HudImageEntity, HudIconButtonEntity, HudProgressBarEntity, HudPanelEntity, HudTextSource, HudNumberSource, HudLayer, Transform, Anchor, AnchorSide, NinePatchConfig, NinePatchPerFrame, HitboxRect, HitboxPerFrame, DepthAnchor, } from './scene/types.js';
|
|
43
43
|
export { PROTOCOL_VERSION, type HelloMessage, type InitMessage, type RpcRequestMessage, type RpcResultOk, type RpcResultError, type HostToSdkMessage, type SdkToHostMessage, type RpcErrorPayload, type RpcMethod, type SavesGetParams, type SavesGetResult, type SavesSetParams, type SavesSetResult, type SavesDeleteParams, type SavesDeleteResult, type SavesListResult, type GameDataGetParams, type GameDataGetResult, type GameDataSetParams, type GameDataSetResult, type GameDataDeleteParams, type GameDataDeleteResult, type GameDataListResult, type RealtimeGetTokenParams, type RealtimeGetTokenResult, } from './protocol.js';
|
|
@@ -78,7 +78,7 @@ export function preloadSceneAssets(scene, sceneFile, manifest) {
|
|
|
78
78
|
if (sceneFile.type !== 'world')
|
|
79
79
|
return; // HUD slice will add its own walker
|
|
80
80
|
const state = getOrInitState(scene, manifest);
|
|
81
|
-
const ids = collectAssetIds(sceneFile.entities);
|
|
81
|
+
const ids = collectAssetIds(sceneFile.entities, manifest);
|
|
82
82
|
for (const id of ids) {
|
|
83
83
|
if (state.requestedAssetIds.has(id))
|
|
84
84
|
continue;
|
|
@@ -98,7 +98,7 @@ export function preloadSceneAssets(scene, sceneFile, manifest) {
|
|
|
98
98
|
state.requestedAssetIds.add(id);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
-
function collectAssetIds(entities) {
|
|
101
|
+
function collectAssetIds(entities, manifest) {
|
|
102
102
|
const ids = new Set();
|
|
103
103
|
function walk(e) {
|
|
104
104
|
if (e.kind === 'sprite') {
|
|
@@ -119,6 +119,14 @@ function collectAssetIds(entities) {
|
|
|
119
119
|
ids.add(id);
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
+
else if (e.kind === 'prefab-ref') {
|
|
123
|
+
// Authored prefab instance — preload whatever the prefab's visual
|
|
124
|
+
// references (sprite prefabs carry an assetId at the record root).
|
|
125
|
+
const prefab = manifest?.prefabs?.find((p) => p.id === e.prefabId);
|
|
126
|
+
const assetId = prefab?.assetId;
|
|
127
|
+
if (typeof assetId === 'string')
|
|
128
|
+
ids.add(assetId);
|
|
129
|
+
}
|
|
122
130
|
// rect / circle / code-rendered / trigger don't reference assets.
|
|
123
131
|
}
|
|
124
132
|
for (const e of entities)
|
|
@@ -30,6 +30,14 @@ export function spawnEntity(ctx, entity) {
|
|
|
30
30
|
case 'trigger':
|
|
31
31
|
go = createTriggerStub(ctx, entity);
|
|
32
32
|
break;
|
|
33
|
+
case 'prefab-ref':
|
|
34
|
+
// Authored prefab INSTANCE (editor "Convert to Type" / drag-from-Types,
|
|
35
|
+
// 2026-06-12). Resolve the prefab record, build a synthetic entity at
|
|
36
|
+
// this instance's transform, and recurse — the inner call creates the
|
|
37
|
+
// GameObject, applies the prefab's physics, tags, and registers under
|
|
38
|
+
// THIS entity's id. We then re-tag kind + prefabId below.
|
|
39
|
+
go = createPrefabRefInstance(ctx, entity);
|
|
40
|
+
break;
|
|
33
41
|
default: {
|
|
34
42
|
const exhaustive = entity;
|
|
35
43
|
throw new Error(`[umicat/scene] unknown entity kind: ${JSON.stringify(exhaustive)}`);
|
|
@@ -38,9 +46,71 @@ export function spawnEntity(ctx, entity) {
|
|
|
38
46
|
applyTransform(go, entity.transform);
|
|
39
47
|
tagGameObject(go, entity);
|
|
40
48
|
applyEntityPhysicsIfDeclared(ctx.scene, go, entity);
|
|
49
|
+
if (entity.kind === 'prefab-ref') {
|
|
50
|
+
// Tag for editor live-edit: `umicat:editor:editPrefab` walks instances
|
|
51
|
+
// via this data key, and canvas clicks route to the Prefab inspector
|
|
52
|
+
// (editing one instance = editing the type). Registry re-registers with
|
|
53
|
+
// the prefabId so byPrefabId() finds authored instances too.
|
|
54
|
+
go.setData('entityPrefabId', entity.prefabId);
|
|
55
|
+
ctx.registry.unregister(entity.id);
|
|
56
|
+
ctx.registry.register(entity.id, entity.role ?? prefabRoleOf(ctx.scene, entity.prefabId), go, entity.prefabId);
|
|
57
|
+
return go;
|
|
58
|
+
}
|
|
41
59
|
ctx.registry.register(entity.id, entity.role, go);
|
|
42
60
|
return go;
|
|
43
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Read a prefab record straight from the cached manifest. Deliberately NOT
|
|
64
|
+
* importing SceneLoader's getManifest — that module imports this one, and
|
|
65
|
+
* keeping the read inline avoids the import cycle.
|
|
66
|
+
*/
|
|
67
|
+
function lookupPrefab(scene, prefabId) {
|
|
68
|
+
const manifest = scene.cache.json.get('umicat:manifest');
|
|
69
|
+
const prefab = manifest?.prefabs?.find((p) => p.id === prefabId);
|
|
70
|
+
return prefab ?? null;
|
|
71
|
+
}
|
|
72
|
+
function prefabRoleOf(scene, prefabId) {
|
|
73
|
+
const prefab = lookupPrefab(scene, prefabId);
|
|
74
|
+
return prefab?.role ?? undefined;
|
|
75
|
+
}
|
|
76
|
+
function createPrefabRefInstance(ctx, entity) {
|
|
77
|
+
const prefab = lookupPrefab(ctx.scene, entity.prefabId);
|
|
78
|
+
if (!prefab) {
|
|
79
|
+
console.warn(`[umicat/scene] prefab-ref '${entity.id}' references prefab '${entity.prefabId}' but the manifest has no such prefab; rendering placeholder`);
|
|
80
|
+
return createMissingPlaceholder(ctx.scene, `prefab: ${entity.prefabId}?`);
|
|
81
|
+
}
|
|
82
|
+
// Synthetic entity = prefab fields + this instance's id/transform. Instance
|
|
83
|
+
// role/properties override the prefab's when set (per-instance variance
|
|
84
|
+
// without breaking the type link).
|
|
85
|
+
const synthetic = {
|
|
86
|
+
...prefab,
|
|
87
|
+
id: entity.id,
|
|
88
|
+
transform: entity.transform,
|
|
89
|
+
...(entity.role !== undefined ? { role: entity.role } : {}),
|
|
90
|
+
...(entity.properties !== undefined
|
|
91
|
+
? { properties: { ...(prefab.properties ?? {}), ...entity.properties } }
|
|
92
|
+
: {}),
|
|
93
|
+
};
|
|
94
|
+
if (synthetic.kind === 'prefab-ref') {
|
|
95
|
+
// A prefab record can never be kind prefab-ref, but guard against a
|
|
96
|
+
// hand-edited manifest producing infinite recursion.
|
|
97
|
+
console.warn(`[umicat/scene] prefab '${entity.prefabId}' has invalid kind 'prefab-ref'`);
|
|
98
|
+
return createMissingPlaceholder(ctx.scene, `prefab: ${entity.prefabId}?`);
|
|
99
|
+
}
|
|
100
|
+
return spawnEntity(ctx, synthetic);
|
|
101
|
+
}
|
|
102
|
+
/** Magenta-bordered "?" placeholder — same soft-fail pattern as missing assets. */
|
|
103
|
+
function createMissingPlaceholder(scene, label) {
|
|
104
|
+
const g = scene.add.graphics();
|
|
105
|
+
g.lineStyle(2, 0xff00ff, 1);
|
|
106
|
+
g.strokeRect(-32, -32, 64, 64);
|
|
107
|
+
g.lineBetween(-32, -32, 32, 32);
|
|
108
|
+
g.lineBetween(-32, 32, 32, -32);
|
|
109
|
+
g.setData('editorHitWidth', 64);
|
|
110
|
+
g.setData('editorHitHeight', 64);
|
|
111
|
+
void label;
|
|
112
|
+
return g;
|
|
113
|
+
}
|
|
44
114
|
/**
|
|
45
115
|
* Apply a scene entity's optional `physics` block. Only renderable entity
|
|
46
116
|
* kinds (sprite / rect / circle / code-rendered) carry a body — they mirror
|
package/dist/scene/types.d.ts
CHANGED
|
@@ -753,7 +753,7 @@ export interface Anchor {
|
|
|
753
753
|
offsetX?: number;
|
|
754
754
|
offsetY?: number;
|
|
755
755
|
}
|
|
756
|
-
export type WorldEntityKind = 'sprite' | 'rect' | 'circle' | 'code-rendered' | 'group' | 'tilemap' | 'trigger';
|
|
756
|
+
export type WorldEntityKind = 'sprite' | 'rect' | 'circle' | 'code-rendered' | 'group' | 'tilemap' | 'trigger' | 'prefab-ref';
|
|
757
757
|
export interface WorldEntityBase {
|
|
758
758
|
id: string;
|
|
759
759
|
/** Optional semantic tag. Behavior code keys off this. */
|
|
@@ -913,7 +913,23 @@ export interface TriggerEntity extends WorldEntityBase {
|
|
|
913
913
|
/** Optional preset name (open-door / damage-zone / scene-transition / spawner / heal). */
|
|
914
914
|
preset?: string;
|
|
915
915
|
}
|
|
916
|
-
|
|
916
|
+
/**
|
|
917
|
+
* Authored INSTANCE of a prefab — the Figma component/instance model
|
|
918
|
+
* brought to scene data (editor "Convert to Type" + drag-from-Types,
|
|
919
|
+
* 2026-06-12). The scene stores only "which type + where"; every render /
|
|
920
|
+
* physics / properties field comes from the prefab record at spawn time,
|
|
921
|
+
* so editing the prefab updates every placed instance across all scenes.
|
|
922
|
+
*
|
|
923
|
+
* Unlike `spawnPrefab` runtime instances (`<prefabId>#<n>` ids, created by
|
|
924
|
+
* behavior code), prefab-refs are scene-file entities: they appear in the
|
|
925
|
+
* editor Hierarchy, are draggable (transform lives here), and persist.
|
|
926
|
+
* `role` defaults to the prefab's role; an explicit role here overrides.
|
|
927
|
+
*/
|
|
928
|
+
export interface PrefabRefEntity extends WorldEntityBase {
|
|
929
|
+
kind: 'prefab-ref';
|
|
930
|
+
prefabId: string;
|
|
931
|
+
}
|
|
932
|
+
export type NonGroupWorldEntity = SpriteEntity | RectEntity | CircleEntity | CodeRenderedEntity | TilemapEntity | TriggerEntity | PrefabRefEntity;
|
|
917
933
|
export type WorldEntity = NonGroupWorldEntity | GroupEntity;
|
|
918
934
|
/**
|
|
919
935
|
* Renderable entity kinds — those that produce a single GameObject with
|