@unboxy/phaser-sdk 0.2.42 → 0.2.43

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.
@@ -49,7 +49,7 @@ function handleMessage(game, msg) {
49
49
  postSceneSnapshot(game);
50
50
  break;
51
51
  case 'unboxy:editor:applyEdit':
52
- applyEdit(game, msg.entityId, msg.patch);
52
+ void applyEdit(game, msg.entityId, msg.patch, msg.manifestAsset);
53
53
  break;
54
54
  case 'unboxy:editor:setSelection':
55
55
  setSelection(game, msg.entityIds[0] ?? null);
@@ -429,7 +429,30 @@ function findRegistry(game) {
429
429
  return undefined;
430
430
  }
431
431
  // --- applyEdit ------------------------------------------------------------
432
- function applyEdit(game, entityId, patch) {
432
+ async function applyEdit(game, entityId, patch, manifestAsset) {
433
+ // Lazy-load + manifest-upsert path. When the host's Inspector picks a Bg
434
+ // image asset that the iframe never preloaded (e.g. a per-game upload that
435
+ // was never dragged into the scene) OR an asset whose `kind` just flipped
436
+ // (e.g. region-atlas — slice 10 — flipping from 'image' to 'atlas'), the
437
+ // host pipelines the new manifest entry along with the patch so the
438
+ // resulting re-spawn sees a consistent runtime state. Without this, the
439
+ // re-spawn reads the stale cached manifest and falls back to the
440
+ // colored-rect placeholder.
441
+ if (manifestAsset) {
442
+ const targetScene = getEditorMode(game) === 'hud'
443
+ ? game.scene.getScene(UNBOXY_HUD_SCENE_KEY)
444
+ : findWorldScene(game);
445
+ if (targetScene) {
446
+ try {
447
+ upsertCachedManifestAsset(targetScene, manifestAsset);
448
+ await ensureAssetLoaded(targetScene, manifestAsset);
449
+ }
450
+ catch (e) {
451
+ console.warn('[unboxy/editor] applyEdit asset upsert/load failed:', e);
452
+ // Fall through — applyHudPatch will render its placeholder.
453
+ }
454
+ }
455
+ }
433
456
  // HUD mode — patches modify anchor / HUD-visual fields. World-style
434
457
  // transform / sprite-tint patches don't apply to HUD widgets, so we
435
458
  // dispatch through a HUD-specific helper that knows the widget kinds.
@@ -625,6 +648,51 @@ async function createEntity(game, entity, manifestAsset) {
625
648
  console.warn('[unboxy/editor] spawnEntity failed:', e);
626
649
  }
627
650
  }
651
+ /**
652
+ * Merge an asset record into the scene's cached manifest (the one
653
+ * {@code getManifest(scene)} returns). Used by applyEdit's pipelined-asset
654
+ * path so subsequent re-spawns see the updated entry (kind / atlasPath /
655
+ * atlasFormat / ninePatch / etc.) without a full scene reload.
656
+ *
657
+ * <p>The manifest object lives in `scene.cache.json` and is shared by
658
+ * reference — mutating its `assets[]` is sufficient. We replace in place
659
+ * when an entry with the same id exists (so a stale {@code kind: 'image'}
660
+ * gets fully overwritten by a fresh {@code kind: 'atlas'} record).
661
+ */
662
+ function upsertCachedManifestAsset(scene, asset) {
663
+ let manifest;
664
+ try {
665
+ manifest = getManifest(scene);
666
+ }
667
+ catch {
668
+ return; // manifest not in cache — nothing to merge against
669
+ }
670
+ if (!manifest.assets)
671
+ manifest.assets = [];
672
+ const idx = manifest.assets.findIndex((a) => a.id === asset.id);
673
+ if (idx >= 0)
674
+ manifest.assets[idx] = asset;
675
+ else
676
+ manifest.assets.push(asset);
677
+ }
678
+ /**
679
+ * Idempotent asset-loaded check: returns immediately if the texture is in
680
+ * the cache. For atlas-format assets, ALSO ensures the per-frame ninePatch
681
+ * sidecar JSON is loaded so the SDK's region-9-slice path can read it back.
682
+ */
683
+ function ensureAssetLoaded(scene, asset) {
684
+ if (asset.kind === 'audio')
685
+ return Promise.resolve();
686
+ const needsTexture = !scene.textures.exists(asset.textureKey);
687
+ const sidecarKey = `unboxy:atlas-ninepatch:${asset.textureKey}`;
688
+ const needsSidecar = asset.kind === 'atlas' &&
689
+ asset.atlasFormat === 'json' &&
690
+ !!asset.atlasPath &&
691
+ !scene.cache.json.exists(sidecarKey);
692
+ if (!needsTexture && !needsSidecar)
693
+ return Promise.resolve();
694
+ return loadAssetIntoScene(scene, asset);
695
+ }
628
696
  function loadAssetIntoScene(scene, asset) {
629
697
  return new Promise((resolve, reject) => {
630
698
  if (scene.textures.exists(asset.textureKey)) {
@@ -673,6 +741,13 @@ function loadAssetIntoScene(scene, asset) {
673
741
  }
674
742
  else if (asset.atlasPath) {
675
743
  scene.load.atlas(asset.textureKey, asset.path, asset.atlasPath);
744
+ // Also fetch the raw JSON into the side-cache for per-region
745
+ // ninePatch lookups (slice 10). Phaser's atlas parser drops
746
+ // unknown per-frame fields, so we keep the original JSON around.
747
+ const sidecarKey = `unboxy:atlas-ninepatch:${asset.textureKey}`;
748
+ if (!scene.cache.json.exists(sidecarKey)) {
749
+ scene.load.json(sidecarKey, asset.atlasPath);
750
+ }
676
751
  }
677
752
  break;
678
753
  case 'audio':
@@ -130,6 +130,21 @@ export interface EditorApplyEditMessage {
130
130
  type: 'unboxy:editor:applyEdit';
131
131
  entityId: string;
132
132
  patch: EditorEntityPatch;
133
+ /**
134
+ * Optional asset record to upsert into the iframe's manifest cache + lazy-
135
+ * load before the patch applies. Mirrors {@link EditorCreateEntityMessage}'s
136
+ * `manifestAsset` field. Used by the Inspector's Bg-image picker when the
137
+ * user picks an asset whose manifest entry needs flipping (e.g. region
138
+ * atlases — visual editor slice 10 — where the existing manifest entry
139
+ * was {@code kind: 'image'} but the asset is now atlas-format).
140
+ *
141
+ * <p>When present, the bridge:
142
+ * 1. Merges the asset into {@code scene.cache.json}'s manifest record
143
+ * 2. Lazy-loads the texture (and atlas-ninepatch sidecar JSON when
144
+ * {@code kind: 'atlas' + atlasFormat: 'json'})
145
+ * 3. Applies the entity patch
146
+ */
147
+ manifestAsset?: unknown;
133
148
  }
134
149
  export interface EditorSetSelectionMessage {
135
150
  type: 'unboxy:editor:setSelection';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboxy/phaser-sdk",
3
- "version": "0.2.42",
3
+ "version": "0.2.43",
4
4
  "description": "Unboxy Phaser 3 SDK — game infrastructure for the Unboxy platform",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",