@skewedaspect/sage 0.9.5 → 0.9.6

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.
@@ -90,6 +90,14 @@ export declare class GameEntityManager implements Disposable {
90
90
  */
91
91
  private _registerEntityActions;
92
92
  $frameUpdate(dt: number): void;
93
+ /**
94
+ * Deep-clone a definition's defaultState for a new instance.
95
+ *
96
+ * A shallow spread would hand every instance of a type the same nested arrays and objects — mutate one
97
+ * entity's inventory slots and you mutate its neighbor's. Definitions must keep defaultState as plain,
98
+ * structured-cloneable data.
99
+ */
100
+ private _cloneDefaultState;
93
101
  /**
94
102
  * Honor the `mesh` create option by building the definition's mesh on the current level.
95
103
  */
@@ -49,12 +49,22 @@ export declare class LevelManager implements Disposable {
49
49
  private _propertyHandlers;
50
50
  /** The currently active level */
51
51
  private _currentLevel;
52
+ /** The level currently inside load(), if any */
53
+ private _loadingLevel;
52
54
  /** Unsubscribe functions for event subscriptions */
53
55
  private _eventUnsubscribers;
54
56
  /**
55
57
  * Gets the currently active level
56
58
  */
57
59
  get currentLevel(): Level | null;
60
+ /**
61
+ * Gets the level currently being loaded, if any.
62
+ *
63
+ * During a transition, `currentLevel` still points at the outgoing level while the incoming one builds its
64
+ * scene — anything that needs "the level work is happening in right now" (dynamic entity mesh creation during
65
+ * spawn processing, for instance) must prefer this over `currentLevel`.
66
+ */
67
+ get loadingLevel(): Level | null;
58
68
  /**
59
69
  * Gets the registered property handlers
60
70
  */
package/dist/sage.es.js CHANGED
@@ -59,7 +59,7 @@ var he = class {
59
59
  configurable: !0
60
60
  });
61
61
  }
62
- }, k = "0.9.5", A = class {
62
+ }, k = "0.9.6", A = class {
63
63
  canvas;
64
64
  renderEngine;
65
65
  physics;
@@ -1606,18 +1606,25 @@ var Ae = ke(16), G = class {
1606
1606
  this._log.trace(`Updating ${this.entities.size} entities with dt=${e}`);
1607
1607
  for (let t of this.entities.values()) t.parent || t.$update(e);
1608
1608
  }
1609
+ _cloneDefaultState(e) {
1610
+ try {
1611
+ return structuredClone(e.defaultState);
1612
+ } catch (t) {
1613
+ throw Error(`Entity type '${e.type}' has a defaultState that cannot be structured-cloned. defaultState must be plain data (no functions, class instances, or DOM references).`, { cause: t });
1614
+ }
1615
+ }
1609
1616
  async _buildDefinitionMesh(e, t) {
1610
1617
  if (!t.mesh) return;
1611
1618
  if (t.node) {
1612
1619
  this._log.warn(`Ignoring 'mesh' option for entity ${e.id}: 'node' was supplied, and the two are exclusive.`);
1613
1620
  return;
1614
1621
  }
1615
- let n = this._engine.managers.levelManager.currentLevel;
1616
- if (!n?.isLoaded) {
1622
+ let { levelManager: n } = this._engine.managers, r = n.loadingLevel ?? n.currentLevel;
1623
+ if (!r?.isLoaded) {
1617
1624
  this._log.warn(`Cannot build a mesh for entity ${e.id}: no level is loaded.`);
1618
1625
  return;
1619
1626
  }
1620
- await n.createEntityMesh(e, { enabled: t.mesh === "enabled" });
1627
+ await r.createEntityMesh(e, { enabled: t.mesh === "enabled" });
1621
1628
  }
1622
1629
  registerEntityDefinition(e) {
1623
1630
  this._log.debug(`Registering entity definition: ${e.type}`);
@@ -1639,7 +1646,7 @@ var Ae = ke(16), G = class {
1639
1646
  if (r && r.length > 0) {
1640
1647
  this._log.trace(`Recycling entity from pool for type: ${e}`);
1641
1648
  let i = r.pop();
1642
- if (i.$reset(n.defaultState, n.tags ?? []), i.$setEntityManager(this), t.initialState && (i.state = {
1649
+ if (i.$reset(this._cloneDefaultState(n), n.tags ?? []), i.$setEntityManager(this), t.initialState && (i.state = {
1643
1650
  ...i.state,
1644
1651
  ...t.initialState
1645
1652
  }), t.tags) for (let e of t.tags) i.$addTag(e);
@@ -1648,7 +1655,7 @@ var Ae = ke(16), G = class {
1648
1655
  }
1649
1656
  this._log.trace(`Using entity definition with ${n.behaviors?.length || 0} behaviors`);
1650
1657
  let r = {
1651
- ...n.defaultState,
1658
+ ...this._cloneDefaultState(n),
1652
1659
  ...t.initialState
1653
1660
  };
1654
1661
  if (n.onBeforeCreate) {
@@ -1683,7 +1690,7 @@ var Ae = ke(16), G = class {
1683
1690
  if (n?.poolable) {
1684
1691
  this._log.trace(`Pooling entity ${e} instead of destroying`);
1685
1692
  for (let e of [...t.children]) await this.destroyEntity(e.id);
1686
- t.parent && t.parent.$removeChild(t), this._unindexEntity(t), t.$reset(n.defaultState, n.tags ?? []);
1693
+ t.parent && t.parent.$removeChild(t), this._unindexEntity(t), t.$reset(this._cloneDefaultState(n), n.tags ?? []);
1687
1694
  let r = this._pools.get(t.type);
1688
1695
  r || (r = [], this._pools.set(t.type, r)), r.push(t), this.entities.delete(e), this._log.debug(`Entity ${e} pooled`);
1689
1696
  return;
@@ -2397,10 +2404,14 @@ var ze = class {
2397
2404
  _loadedLevels = /* @__PURE__ */ new Map();
2398
2405
  _propertyHandlers = /* @__PURE__ */ new Map();
2399
2406
  _currentLevel = null;
2407
+ _loadingLevel = null;
2400
2408
  _eventUnsubscribers = [];
2401
2409
  get currentLevel() {
2402
2410
  return this._currentLevel;
2403
2411
  }
2412
+ get loadingLevel() {
2413
+ return this._loadingLevel;
2414
+ }
2404
2415
  get propertyHandlers() {
2405
2416
  return this._propertyHandlers;
2406
2417
  }
@@ -2474,7 +2485,13 @@ var ze = class {
2474
2485
  if (n) return this._log.warn(`Level '${t.name}' is already loaded`), n;
2475
2486
  this._log.debug(`Loading level: ${t.name}`);
2476
2487
  let r = this._createLevelInstance(t);
2477
- return await r.load(), this._loadedLevels.set(t.name, r), r;
2488
+ this._loadingLevel = r;
2489
+ try {
2490
+ await r.load();
2491
+ } finally {
2492
+ this._loadingLevel = null;
2493
+ }
2494
+ return this._loadedLevels.set(t.name, r), r;
2478
2495
  }
2479
2496
  async activateLevel(e) {
2480
2497
  let t = await this.loadLevel(e);