@skewedaspect/sage 0.9.4 → 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.
- package/dist/classes/gameLevel.d.ts +0 -17
- package/dist/classes/input/mouse.d.ts +10 -1
- package/dist/classes/level.d.ts +39 -2
- package/dist/managers/entity.d.ts +17 -0
- package/dist/managers/level.d.ts +10 -0
- package/dist/sage.es.js +134 -93
- package/dist/sage.es.js.map +1 -1
- package/dist/sage.umd.js +1 -1
- package/dist/sage.umd.js.map +1 -1
- package/package.json +1 -1
|
@@ -103,7 +103,6 @@ export declare class GameLevel extends Level {
|
|
|
103
103
|
* and fix PBR material falloff for compatibility.
|
|
104
104
|
*/
|
|
105
105
|
private _setupClustering;
|
|
106
|
-
private _toColor3;
|
|
107
106
|
/**
|
|
108
107
|
* Configure and enable the Havok physics plugin with the level's gravity settings.
|
|
109
108
|
*/
|
|
@@ -112,21 +111,10 @@ export declare class GameLevel extends Level {
|
|
|
112
111
|
* Walk all transform nodes and meshes, normalizing glTF metadata and dispatching to property handlers.
|
|
113
112
|
*/
|
|
114
113
|
private _processNodeProperties;
|
|
115
|
-
/**
|
|
116
|
-
* Get normalized metadata from a node, handling glTF extras.
|
|
117
|
-
*
|
|
118
|
-
* Babylon.js stores glTF custom properties in node.metadata.gltf.extras,
|
|
119
|
-
* so we need to extract them for easier access.
|
|
120
|
-
*/
|
|
121
|
-
private _getNormalizedMetadata;
|
|
122
114
|
/**
|
|
123
115
|
* Check a node's metadata for spawn/entity markers and run any registered property handlers.
|
|
124
116
|
*/
|
|
125
117
|
private _processNodeMetadata;
|
|
126
|
-
/**
|
|
127
|
-
* Run registered property handlers on a node.
|
|
128
|
-
*/
|
|
129
|
-
private _runPropertyHandlers;
|
|
130
118
|
/**
|
|
131
119
|
* Match collected spawn points against the level config's spawn definitions and instantiate entities.
|
|
132
120
|
*/
|
|
@@ -144,11 +132,6 @@ export declare class GameLevel extends Level {
|
|
|
144
132
|
* Create an entity from a spawn definition, inheriting position/rotation/scaling from the spawn point.
|
|
145
133
|
*/
|
|
146
134
|
private _spawnEntity;
|
|
147
|
-
/**
|
|
148
|
-
* Build or import a mesh from the entity definition and attach it to the entity.
|
|
149
|
-
* Supports primitive shapes (box/sphere/capsule/cylinder) and GLB/GLTF file paths.
|
|
150
|
-
*/
|
|
151
|
-
private _createEntityMesh;
|
|
152
135
|
/**
|
|
153
136
|
* Create game entities for all nodes marked with the 'entity' metadata property.
|
|
154
137
|
*/
|
|
@@ -68,9 +68,18 @@ export declare class MouseInputPlugin {
|
|
|
68
68
|
*/
|
|
69
69
|
private _handlePointerMove;
|
|
70
70
|
/**
|
|
71
|
-
* Handle mouse wheel events
|
|
71
|
+
* Handle mouse wheel events.
|
|
72
|
+
*
|
|
73
|
+
* The wheel is a pulse, not a level: the browser reports a delta per notch and never reports "stopped scrolling".
|
|
74
|
+
* So each event notifies twice — once carrying the deltas, once carrying zeros. Without that trailing zero,
|
|
75
|
+
* `emitOnChange` value bindings swallow every notch after the first (consecutive notches report identical deltas),
|
|
76
|
+
* trigger bindings never see a falling edge to re-arm on, and `getState()` latches the last scroll forever.
|
|
72
77
|
*/
|
|
73
78
|
private _handleMouseWheel;
|
|
79
|
+
/**
|
|
80
|
+
* Notify subscribers of the current wheel state, attributed to the wheel event that produced it
|
|
81
|
+
*/
|
|
82
|
+
private _notifyWheelState;
|
|
74
83
|
/**
|
|
75
84
|
* Notify subscribers of device connected event
|
|
76
85
|
*/
|
package/dist/classes/level.d.ts
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
import { Scene } from '@babylonjs/core';
|
|
1
|
+
import { Color3, Quaternion, Scene, TransformNode, Vector3 } from '@babylonjs/core';
|
|
2
2
|
import { ClusteredLightContainer } from '@babylonjs/core/Lights/Clustered/clusteredLightContainer';
|
|
3
3
|
import { LoggerInterface } from "../interfaces/logger.d.ts";
|
|
4
|
-
import { LevelConfig, LevelContext, LevelInstance, PropertyHandler } from "../interfaces/level.d.ts";
|
|
4
|
+
import { ColorConfig, LevelConfig, LevelContext, LevelInstance, PropertyHandler } from "../interfaces/level.d.ts";
|
|
5
|
+
import { GameEntity } from "./entity.d.ts";
|
|
5
6
|
import { GameEngine } from "./gameEngine.d.ts";
|
|
6
7
|
import { OutlineManager } from "../managers/outline.d.ts";
|
|
8
|
+
/**
|
|
9
|
+
* Transform and visibility overrides applied to a mesh built by `Level.createEntityMesh()`.
|
|
10
|
+
*/
|
|
11
|
+
export interface CreateEntityMeshOptions {
|
|
12
|
+
/** World position for the entity's root node. Left at the node default when omitted. */
|
|
13
|
+
position?: Vector3;
|
|
14
|
+
/** World rotation for the entity's root node. Left at the node default when omitted. */
|
|
15
|
+
rotation?: Quaternion;
|
|
16
|
+
/** Scaling for the entity's root node. Left at the node default when omitted. */
|
|
17
|
+
scaling?: Vector3;
|
|
18
|
+
/** When false, the node is disabled immediately on creation so nothing ever renders. Default true. */
|
|
19
|
+
enabled?: boolean;
|
|
20
|
+
}
|
|
7
21
|
/**
|
|
8
22
|
* Abstract base class for game levels.
|
|
9
23
|
*
|
|
@@ -47,11 +61,34 @@ export declare abstract class Level implements LevelInstance {
|
|
|
47
61
|
* @param message
|
|
48
62
|
*/
|
|
49
63
|
protected $emitProgress(progress: number, message: string): void;
|
|
64
|
+
protected _toColor3(color: ColorConfig): Color3;
|
|
65
|
+
/**
|
|
66
|
+
* Get normalized metadata from a node, handling glTF extras.
|
|
67
|
+
*
|
|
68
|
+
* Babylon.js stores glTF custom properties in node.metadata.gltf.extras,
|
|
69
|
+
* so we need to extract them for easier access.
|
|
70
|
+
*/
|
|
71
|
+
protected _getNormalizedMetadata(node: TransformNode): Record<string, unknown> | null;
|
|
72
|
+
/**
|
|
73
|
+
* Run registered property handlers on a node.
|
|
74
|
+
*/
|
|
75
|
+
protected _runPropertyHandlers(node: TransformNode): Promise<void>;
|
|
50
76
|
/**
|
|
51
77
|
* Load and create the scene for this level.
|
|
52
78
|
* Progress events will be emitted during loading.
|
|
53
79
|
*/
|
|
54
80
|
load(): Promise<Scene>;
|
|
81
|
+
/**
|
|
82
|
+
* Build or import a mesh from the entity definition and attach it to the entity.
|
|
83
|
+
* Supports primitive shapes (box/sphere/capsule/cylinder) and GLB/GLTF file paths.
|
|
84
|
+
*
|
|
85
|
+
* @param entity - The entity whose definition supplies the mesh spec
|
|
86
|
+
* @param options - Transform overrides and initial enabled state
|
|
87
|
+
*
|
|
88
|
+
* @returns The root node the mesh was built under, or null if the level has no scene, the definition has no
|
|
89
|
+
* mesh spec, or the GLB import produced no meshes.
|
|
90
|
+
*/
|
|
91
|
+
createEntityMesh(entity: GameEntity, options?: CreateEntityMeshOptions): Promise<TransformNode | null>;
|
|
55
92
|
/**
|
|
56
93
|
* Abstract method for building the scene content.
|
|
57
94
|
* Concrete levels must implement this to create their specific content.
|
|
@@ -18,6 +18,11 @@ export interface CreateEntityOptions<State extends object = object> {
|
|
|
18
18
|
tags?: string[];
|
|
19
19
|
/** Scene node to attach the entity to. */
|
|
20
20
|
node?: TransformNode;
|
|
21
|
+
/**
|
|
22
|
+
* Build the definition's mesh via the current level ('disabled' loads it setEnabled(false)).
|
|
23
|
+
* Mutually exclusive with `node`.
|
|
24
|
+
*/
|
|
25
|
+
mesh?: 'enabled' | 'disabled';
|
|
21
26
|
}
|
|
22
27
|
export declare class GameEntityManager implements Disposable {
|
|
23
28
|
/** The event bus for the entity manager. */
|
|
@@ -85,6 +90,18 @@ export declare class GameEntityManager implements Disposable {
|
|
|
85
90
|
*/
|
|
86
91
|
private _registerEntityActions;
|
|
87
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;
|
|
101
|
+
/**
|
|
102
|
+
* Honor the `mesh` create option by building the definition's mesh on the current level.
|
|
103
|
+
*/
|
|
104
|
+
private _buildDefinitionMesh;
|
|
88
105
|
/**
|
|
89
106
|
* Registers a new entity definition.
|
|
90
107
|
* Also registers any actions declared in the definition with the binding manager.
|
package/dist/managers/level.d.ts
CHANGED
|
@@ -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.
|
|
62
|
+
}, k = "0.9.6", A = class {
|
|
63
63
|
canvas;
|
|
64
64
|
renderEngine;
|
|
65
65
|
physics;
|
|
@@ -1606,6 +1606,26 @@ 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
|
+
}
|
|
1616
|
+
async _buildDefinitionMesh(e, t) {
|
|
1617
|
+
if (!t.mesh) return;
|
|
1618
|
+
if (t.node) {
|
|
1619
|
+
this._log.warn(`Ignoring 'mesh' option for entity ${e.id}: 'node' was supplied, and the two are exclusive.`);
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
let { levelManager: n } = this._engine.managers, r = n.loadingLevel ?? n.currentLevel;
|
|
1623
|
+
if (!r?.isLoaded) {
|
|
1624
|
+
this._log.warn(`Cannot build a mesh for entity ${e.id}: no level is loaded.`);
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
await r.createEntityMesh(e, { enabled: t.mesh === "enabled" });
|
|
1628
|
+
}
|
|
1609
1629
|
registerEntityDefinition(e) {
|
|
1610
1630
|
this._log.debug(`Registering entity definition: ${e.type}`);
|
|
1611
1631
|
let t = e.extends ? this._resolveInheritance(e) : e;
|
|
@@ -1626,16 +1646,16 @@ var Ae = ke(16), G = class {
|
|
|
1626
1646
|
if (r && r.length > 0) {
|
|
1627
1647
|
this._log.trace(`Recycling entity from pool for type: ${e}`);
|
|
1628
1648
|
let i = r.pop();
|
|
1629
|
-
if (i.$reset(n
|
|
1649
|
+
if (i.$reset(this._cloneDefaultState(n), n.tags ?? []), i.$setEntityManager(this), t.initialState && (i.state = {
|
|
1630
1650
|
...i.state,
|
|
1631
1651
|
...t.initialState
|
|
1632
1652
|
}), t.tags) for (let e of t.tags) i.$addTag(e);
|
|
1633
|
-
return t.node && i.$attachToNode(t.node, this._engine), this.entities.set(i.id, i), this._indexEntity(i), this._log.debug(`Recycled entity ${i.id} from pool`), i;
|
|
1653
|
+
return t.node && i.$attachToNode(t.node, this._engine), this.entities.set(i.id, i), this._indexEntity(i), await this._buildDefinitionMesh(i, t), this._log.debug(`Recycled entity ${i.id} from pool`), i;
|
|
1634
1654
|
}
|
|
1635
1655
|
}
|
|
1636
1656
|
this._log.trace(`Using entity definition with ${n.behaviors?.length || 0} behaviors`);
|
|
1637
1657
|
let r = {
|
|
1638
|
-
...n
|
|
1658
|
+
...this._cloneDefaultState(n),
|
|
1639
1659
|
...t.initialState
|
|
1640
1660
|
};
|
|
1641
1661
|
if (n.onBeforeCreate) {
|
|
@@ -1660,7 +1680,7 @@ var Ae = ke(16), G = class {
|
|
|
1660
1680
|
});
|
|
1661
1681
|
a.$addChild(n);
|
|
1662
1682
|
}
|
|
1663
|
-
return a;
|
|
1683
|
+
return await this._buildDefinitionMesh(a, t), a;
|
|
1664
1684
|
}
|
|
1665
1685
|
async destroyEntity(e) {
|
|
1666
1686
|
this._log.debug(`Destroying entity: ${e}`);
|
|
@@ -1670,7 +1690,7 @@ var Ae = ke(16), G = class {
|
|
|
1670
1690
|
if (n?.poolable) {
|
|
1671
1691
|
this._log.trace(`Pooling entity ${e} instead of destroying`);
|
|
1672
1692
|
for (let e of [...t.children]) await this.destroyEntity(e.id);
|
|
1673
|
-
t.parent && t.parent.$removeChild(t), this._unindexEntity(t), t.$reset(n
|
|
1693
|
+
t.parent && t.parent.$removeChild(t), this._unindexEntity(t), t.$reset(this._cloneDefaultState(n), n.tags ?? []);
|
|
1674
1694
|
let r = this._pools.get(t.type);
|
|
1675
1695
|
r || (r = [], this._pools.set(t.type, r)), r.push(t), this.entities.delete(e), this._log.debug(`Entity ${e} pooled`);
|
|
1676
1696
|
return;
|
|
@@ -1912,6 +1932,21 @@ var ze = class {
|
|
|
1912
1932
|
}
|
|
1913
1933
|
});
|
|
1914
1934
|
}
|
|
1935
|
+
_toColor3(e) {
|
|
1936
|
+
return new r(e.r, e.g, e.b);
|
|
1937
|
+
}
|
|
1938
|
+
_getNormalizedMetadata(e) {
|
|
1939
|
+
if (!e.metadata) return null;
|
|
1940
|
+
let t = e.metadata?.gltf?.extras;
|
|
1941
|
+
return t ? { ...t } : e.metadata;
|
|
1942
|
+
}
|
|
1943
|
+
async _runPropertyHandlers(e) {
|
|
1944
|
+
for (let [t, n] of this.propertyHandlers) if (t in e.metadata) try {
|
|
1945
|
+
await n(e, e.metadata[t], this, this.gameEngine);
|
|
1946
|
+
} catch (n) {
|
|
1947
|
+
this._log.error(`Error in property handler '${t}' for node '${e.name}':`, n);
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1915
1950
|
async load() {
|
|
1916
1951
|
if (this._scene) return this._log.warn(`Level ${this.name} is already loaded`), this._scene;
|
|
1917
1952
|
this._log.info(`Loading level: ${this.name}`), this._log.time(`level-${this.name}-load`);
|
|
@@ -1935,6 +1970,74 @@ var ze = class {
|
|
|
1935
1970
|
}), e;
|
|
1936
1971
|
}
|
|
1937
1972
|
}
|
|
1973
|
+
async createEntityMesh(e, t = {}) {
|
|
1974
|
+
if (!this._scene) return null;
|
|
1975
|
+
let n = this.gameEngine.managers.entityManager.getDefinition(e.type);
|
|
1976
|
+
if (!n?.mesh) return null;
|
|
1977
|
+
let r = n.mesh, i = this._scene, a = new D(`entity-${e.id}`, i);
|
|
1978
|
+
t.enabled === !1 && a.setEnabled(!1);
|
|
1979
|
+
let o;
|
|
1980
|
+
switch (r.source) {
|
|
1981
|
+
case "box":
|
|
1982
|
+
o = [b.CreateBox(`${e.type}-mesh`, {
|
|
1983
|
+
size: r.params?.size ?? 1,
|
|
1984
|
+
width: r.params?.width,
|
|
1985
|
+
height: r.params?.height,
|
|
1986
|
+
depth: r.params?.depth
|
|
1987
|
+
}, i)];
|
|
1988
|
+
break;
|
|
1989
|
+
case "sphere":
|
|
1990
|
+
o = [b.CreateSphere(`${e.type}-mesh`, {
|
|
1991
|
+
diameter: r.params?.diameter ?? 1,
|
|
1992
|
+
segments: r.params?.segments ?? 16
|
|
1993
|
+
}, i)];
|
|
1994
|
+
break;
|
|
1995
|
+
case "capsule":
|
|
1996
|
+
o = [b.CreateCapsule(`${e.type}-mesh`, {
|
|
1997
|
+
height: r.params?.height ?? 1.8,
|
|
1998
|
+
radius: r.params?.radius ?? .4
|
|
1999
|
+
}, i)];
|
|
2000
|
+
break;
|
|
2001
|
+
case "cylinder":
|
|
2002
|
+
o = [b.CreateCylinder(`${e.type}-mesh`, {
|
|
2003
|
+
height: r.params?.height ?? 1,
|
|
2004
|
+
diameter: r.params?.diameter ?? 1
|
|
2005
|
+
}, i)];
|
|
2006
|
+
break;
|
|
2007
|
+
default: {
|
|
2008
|
+
let e = await this.gameEngine.engines.sceneEngine.importMeshes([], r.source, i);
|
|
2009
|
+
if (e.meshes.length === 0) return this._log.warn(`No meshes loaded from: ${r.source}`), a.dispose(), null;
|
|
2010
|
+
o = e.meshes;
|
|
2011
|
+
for (let t of e.transformNodes) t.parent ||= a;
|
|
2012
|
+
break;
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
for (let e of o) e.parent ||= a;
|
|
2016
|
+
t.position && a.position.copyFrom(t.position), t.rotation && (a.rotationQuaternion = t.rotation.clone()), t.scaling && a.scaling.copyFrom(t.scaling), r.scale && (typeof r.scale == "number" ? a.scaling.setAll(r.scale) : a.scaling.set(r.scale.x, r.scale.y, r.scale.z));
|
|
2017
|
+
let s = r.material;
|
|
2018
|
+
if (s?.color) {
|
|
2019
|
+
let t = s.color;
|
|
2020
|
+
if (s.type === "pbr") {
|
|
2021
|
+
let n = new S(`${e.type}-material`, i);
|
|
2022
|
+
n.albedoColor = this._toColor3(t), s.emissive && (n.emissiveColor = this._toColor3(s.emissive)), n.metallic = s.metallic ?? 0, n.roughness = s.roughness ?? 1;
|
|
2023
|
+
for (let e of o) e.material = n;
|
|
2024
|
+
} else {
|
|
2025
|
+
let n = new E(`${e.type}-material`, i);
|
|
2026
|
+
n.diffuseColor = this._toColor3(t), s.emissive && (n.emissiveColor = this._toColor3(s.emissive));
|
|
2027
|
+
for (let e of o) e.material = n;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
if (r.visible === !1) for (let e of o) e.isVisible = !1;
|
|
2031
|
+
let c = a.getDescendants(!1).filter((e) => e instanceof D);
|
|
2032
|
+
for (let e of c) {
|
|
2033
|
+
let t = this._getNormalizedMetadata(e);
|
|
2034
|
+
t && Object.keys(t).length > 0 && (e.metadata = {
|
|
2035
|
+
...e.metadata,
|
|
2036
|
+
...t
|
|
2037
|
+
}, await this._runPropertyHandlers(e));
|
|
2038
|
+
}
|
|
2039
|
+
return this.gameEngine.managers.entityManager.attachToNode(e, a), a;
|
|
2040
|
+
}
|
|
1938
2041
|
async $dispose() {
|
|
1939
2042
|
if (this._scene) {
|
|
1940
2043
|
this._log.info(`Disposing level: ${this.name}`);
|
|
@@ -2163,9 +2266,6 @@ var ze = class {
|
|
|
2163
2266
|
t.horizontalTiles !== void 0 && (r.horizontalTiles = t.horizontalTiles), t.verticalTiles !== void 0 && (r.verticalTiles = t.verticalTiles), t.depthSlices !== void 0 && (r.depthSlices = t.depthSlices), t.maxRange !== void 0 && (r.maxRange = t.maxRange), this.clusteredLights = r, this._log.debug(`Clustered lighting enabled: ${n.length} lights, ${r.horizontalTiles}x${r.verticalTiles} tiles, ${r.depthSlices} depth slices`);
|
|
2164
2267
|
for (let t of e.materials) t instanceof S && (t.useGLTFLightFalloff = !0);
|
|
2165
2268
|
}
|
|
2166
|
-
_toColor3(e) {
|
|
2167
|
-
return new r(e.r, e.g, e.b);
|
|
2168
|
-
}
|
|
2169
2269
|
async _enablePhysics(e) {
|
|
2170
2270
|
let t = this._config.physics, n = new O(0, -9.81, 0);
|
|
2171
2271
|
typeof t == "object" && t.gravity && (n = new O(t.gravity.x, t.gravity.y, t.gravity.z));
|
|
@@ -2183,11 +2283,6 @@ var ze = class {
|
|
|
2183
2283
|
}
|
|
2184
2284
|
this._log.debug(`Processed ${t.length} nodes, found ${this._spawnPoints.length} spawn points and ${this._entityNodes.length} entity nodes`);
|
|
2185
2285
|
}
|
|
2186
|
-
_getNormalizedMetadata(e) {
|
|
2187
|
-
if (!e.metadata) return null;
|
|
2188
|
-
let t = e.metadata?.gltf?.extras;
|
|
2189
|
-
return t ? { ...t } : e.metadata;
|
|
2190
|
-
}
|
|
2191
2286
|
async _processNodeMetadata(e) {
|
|
2192
2287
|
if ("spawn" in e.metadata) {
|
|
2193
2288
|
let { position: t, rotation: n, scaling: r } = Re(e);
|
|
@@ -2204,13 +2299,6 @@ var ze = class {
|
|
|
2204
2299
|
node: e
|
|
2205
2300
|
}), await this._runPropertyHandlers(e);
|
|
2206
2301
|
}
|
|
2207
|
-
async _runPropertyHandlers(e) {
|
|
2208
|
-
for (let [t, n] of this.propertyHandlers) if (t in e.metadata) try {
|
|
2209
|
-
await n(e, e.metadata[t], this, this.gameEngine);
|
|
2210
|
-
} catch (n) {
|
|
2211
|
-
this._log.error(`Error in property handler '${t}' for node '${e.name}':`, n);
|
|
2212
|
-
}
|
|
2213
|
-
}
|
|
2214
2302
|
async _processSpawnPoints() {
|
|
2215
2303
|
for (let e of this._spawnPoints) {
|
|
2216
2304
|
let t = this._config.spawns?.[e.name];
|
|
@@ -2240,76 +2328,11 @@ var ze = class {
|
|
|
2240
2328
|
tags: e.tags,
|
|
2241
2329
|
initialState: n
|
|
2242
2330
|
});
|
|
2243
|
-
return await this.
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
if (!n?.mesh) return;
|
|
2249
|
-
let r = n.mesh, i = this._scene, a = new D(`entity-${e.id}`, i), o;
|
|
2250
|
-
switch (r.source) {
|
|
2251
|
-
case "box":
|
|
2252
|
-
o = [b.CreateBox(`${e.type}-mesh`, {
|
|
2253
|
-
size: r.params?.size ?? 1,
|
|
2254
|
-
width: r.params?.width,
|
|
2255
|
-
height: r.params?.height,
|
|
2256
|
-
depth: r.params?.depth
|
|
2257
|
-
}, i)];
|
|
2258
|
-
break;
|
|
2259
|
-
case "sphere":
|
|
2260
|
-
o = [b.CreateSphere(`${e.type}-mesh`, {
|
|
2261
|
-
diameter: r.params?.diameter ?? 1,
|
|
2262
|
-
segments: r.params?.segments ?? 16
|
|
2263
|
-
}, i)];
|
|
2264
|
-
break;
|
|
2265
|
-
case "capsule":
|
|
2266
|
-
o = [b.CreateCapsule(`${e.type}-mesh`, {
|
|
2267
|
-
height: r.params?.height ?? 1.8,
|
|
2268
|
-
radius: r.params?.radius ?? .4
|
|
2269
|
-
}, i)];
|
|
2270
|
-
break;
|
|
2271
|
-
case "cylinder":
|
|
2272
|
-
o = [b.CreateCylinder(`${e.type}-mesh`, {
|
|
2273
|
-
height: r.params?.height ?? 1,
|
|
2274
|
-
diameter: r.params?.diameter ?? 1
|
|
2275
|
-
}, i)];
|
|
2276
|
-
break;
|
|
2277
|
-
default: {
|
|
2278
|
-
let e = await this.gameEngine.engines.sceneEngine.importMeshes([], r.source, i);
|
|
2279
|
-
if (e.meshes.length === 0) {
|
|
2280
|
-
this._log.warn(`No meshes loaded from: ${r.source}`), a.dispose();
|
|
2281
|
-
return;
|
|
2282
|
-
}
|
|
2283
|
-
o = e.meshes;
|
|
2284
|
-
for (let t of e.transformNodes) t.parent ||= a;
|
|
2285
|
-
break;
|
|
2286
|
-
}
|
|
2287
|
-
}
|
|
2288
|
-
for (let e of o) e.parent ||= a;
|
|
2289
|
-
a.position.copyFrom(t.position), a.rotationQuaternion = t.rotation.clone(), a.scaling.copyFrom(t.scaling), r.scale && (typeof r.scale == "number" ? a.scaling.setAll(r.scale) : a.scaling.set(r.scale.x, r.scale.y, r.scale.z));
|
|
2290
|
-
let s = r.material;
|
|
2291
|
-
if (s?.color) {
|
|
2292
|
-
let t = s.color;
|
|
2293
|
-
if (s.type === "pbr") {
|
|
2294
|
-
let n = new S(`${e.type}-material`, i);
|
|
2295
|
-
n.albedoColor = this._toColor3(t), s.emissive && (n.emissiveColor = this._toColor3(s.emissive)), n.metallic = s.metallic ?? 0, n.roughness = s.roughness ?? 1;
|
|
2296
|
-
for (let e of o) e.material = n;
|
|
2297
|
-
} else {
|
|
2298
|
-
let n = new E(`${e.type}-material`, i);
|
|
2299
|
-
n.diffuseColor = this._toColor3(t), s.emissive && (n.emissiveColor = this._toColor3(s.emissive));
|
|
2300
|
-
for (let e of o) e.material = n;
|
|
2301
|
-
}
|
|
2302
|
-
}
|
|
2303
|
-
if (r.visible === !1) for (let e of o) e.isVisible = !1;
|
|
2304
|
-
let c = a.getDescendants(!1).filter((e) => e instanceof D);
|
|
2305
|
-
for (let e of c) {
|
|
2306
|
-
let t = this._getNormalizedMetadata(e);
|
|
2307
|
-
t && Object.keys(t).length > 0 && (e.metadata = {
|
|
2308
|
-
...e.metadata,
|
|
2309
|
-
...t
|
|
2310
|
-
}, await this._runPropertyHandlers(e));
|
|
2311
|
-
}
|
|
2312
|
-
this.gameEngine.managers.entityManager.attachToNode(e, a);
|
|
2331
|
+
return await this.createEntityMesh(r, {
|
|
2332
|
+
position: t.position,
|
|
2333
|
+
rotation: t.rotation,
|
|
2334
|
+
scaling: t.scaling
|
|
2335
|
+
}), r;
|
|
2313
2336
|
}
|
|
2314
2337
|
async _processEntityNodes() {
|
|
2315
2338
|
for (let e of this._entityNodes) await this._processEntityNode(e);
|
|
@@ -2381,10 +2404,14 @@ var ze = class {
|
|
|
2381
2404
|
_loadedLevels = /* @__PURE__ */ new Map();
|
|
2382
2405
|
_propertyHandlers = /* @__PURE__ */ new Map();
|
|
2383
2406
|
_currentLevel = null;
|
|
2407
|
+
_loadingLevel = null;
|
|
2384
2408
|
_eventUnsubscribers = [];
|
|
2385
2409
|
get currentLevel() {
|
|
2386
2410
|
return this._currentLevel;
|
|
2387
2411
|
}
|
|
2412
|
+
get loadingLevel() {
|
|
2413
|
+
return this._loadingLevel;
|
|
2414
|
+
}
|
|
2388
2415
|
get propertyHandlers() {
|
|
2389
2416
|
return this._propertyHandlers;
|
|
2390
2417
|
}
|
|
@@ -2458,7 +2485,13 @@ var ze = class {
|
|
|
2458
2485
|
if (n) return this._log.warn(`Level '${t.name}' is already loaded`), n;
|
|
2459
2486
|
this._log.debug(`Loading level: ${t.name}`);
|
|
2460
2487
|
let r = this._createLevelInstance(t);
|
|
2461
|
-
|
|
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;
|
|
2462
2495
|
}
|
|
2463
2496
|
async activateLevel(e) {
|
|
2464
2497
|
let t = await this.loadLevel(e);
|
|
@@ -2879,7 +2912,15 @@ var ze = class {
|
|
|
2879
2912
|
deltaY: e.deltaY,
|
|
2880
2913
|
deltaZ: e.deltaZ,
|
|
2881
2914
|
deltaMode: e.deltaMode
|
|
2882
|
-
}, this.
|
|
2915
|
+
}, this._notifyWheelState(e), this._wheelState = {
|
|
2916
|
+
deltaX: 0,
|
|
2917
|
+
deltaY: 0,
|
|
2918
|
+
deltaZ: 0,
|
|
2919
|
+
deltaMode: 0
|
|
2920
|
+
}, this._notifyWheelState(e);
|
|
2921
|
+
}
|
|
2922
|
+
_notifyWheelState(e) {
|
|
2923
|
+
this._notifyInputChanged({
|
|
2883
2924
|
type: "mouse",
|
|
2884
2925
|
event: e,
|
|
2885
2926
|
buttons: { ...this._buttonState },
|