@energy8platform/game-engine 0.7.1 → 0.8.0
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/core.cjs.js +19 -6
- package/dist/core.cjs.js.map +1 -1
- package/dist/core.d.ts +2 -1
- package/dist/core.esm.js +19 -6
- package/dist/core.esm.js.map +1 -1
- package/dist/index.cjs.js +27 -14
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.esm.js +27 -14
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/core/SceneManager.ts +20 -6
- package/src/state/StateMachine.ts +11 -8
package/package.json
CHANGED
package/src/core/SceneManager.ts
CHANGED
|
@@ -25,12 +25,14 @@ interface SceneManagerEvents {
|
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
27
|
export class SceneManager extends EventEmitter<SceneManagerEvents> {
|
|
28
|
+
private static MAX_TRANSITION_DEPTH = 10;
|
|
29
|
+
|
|
28
30
|
/** Root container that scenes are added to */
|
|
29
31
|
public root!: Container;
|
|
30
32
|
|
|
31
33
|
private registry = new Map<string, SceneConstructor>();
|
|
32
34
|
private stack: SceneEntry[] = [];
|
|
33
|
-
private
|
|
35
|
+
private _transitionDepth = 0;
|
|
34
36
|
|
|
35
37
|
/** Current viewport dimensions — set by ViewportManager */
|
|
36
38
|
private _width = 0;
|
|
@@ -64,7 +66,7 @@ export class SceneManager extends EventEmitter<SceneManagerEvents> {
|
|
|
64
66
|
|
|
65
67
|
/** Whether a scene transition is in progress */
|
|
66
68
|
get isTransitioning(): boolean {
|
|
67
|
-
return this.
|
|
69
|
+
return this._transitionDepth > 0;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
/**
|
|
@@ -75,6 +77,9 @@ export class SceneManager extends EventEmitter<SceneManagerEvents> {
|
|
|
75
77
|
data?: unknown,
|
|
76
78
|
transition?: TransitionConfig,
|
|
77
79
|
): Promise<void> {
|
|
80
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
81
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
82
|
+
}
|
|
78
83
|
const prevKey = this.currentKey;
|
|
79
84
|
|
|
80
85
|
// Exit all current scenes
|
|
@@ -96,6 +101,9 @@ export class SceneManager extends EventEmitter<SceneManagerEvents> {
|
|
|
96
101
|
data?: unknown,
|
|
97
102
|
transition?: TransitionConfig,
|
|
98
103
|
): Promise<void> {
|
|
104
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
105
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
106
|
+
}
|
|
99
107
|
const prevKey = this.currentKey;
|
|
100
108
|
await this.pushInternal(key, data, transition);
|
|
101
109
|
this.emit('change', { from: prevKey, to: key });
|
|
@@ -109,6 +117,9 @@ export class SceneManager extends EventEmitter<SceneManagerEvents> {
|
|
|
109
117
|
console.warn('[SceneManager] Cannot pop the last scene');
|
|
110
118
|
return;
|
|
111
119
|
}
|
|
120
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
121
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
122
|
+
}
|
|
112
123
|
const prevKey = this.currentKey;
|
|
113
124
|
await this.popInternal(true, transition);
|
|
114
125
|
this.emit('change', { from: prevKey, to: this.currentKey! });
|
|
@@ -122,6 +133,9 @@ export class SceneManager extends EventEmitter<SceneManagerEvents> {
|
|
|
122
133
|
data?: unknown,
|
|
123
134
|
transition?: TransitionConfig,
|
|
124
135
|
): Promise<void> {
|
|
136
|
+
if (this._transitionDepth >= SceneManager.MAX_TRANSITION_DEPTH) {
|
|
137
|
+
throw new Error('[SceneManager] Max transition depth exceeded — possible infinite loop');
|
|
138
|
+
}
|
|
125
139
|
const prevKey = this.currentKey;
|
|
126
140
|
await this.popInternal(false);
|
|
127
141
|
await this.pushInternal(key, data, transition);
|
|
@@ -177,7 +191,7 @@ export class SceneManager extends EventEmitter<SceneManagerEvents> {
|
|
|
177
191
|
data?: unknown,
|
|
178
192
|
transition?: TransitionConfig,
|
|
179
193
|
): Promise<void> {
|
|
180
|
-
this.
|
|
194
|
+
this._transitionDepth++;
|
|
181
195
|
|
|
182
196
|
const scene = this.createScene(key);
|
|
183
197
|
this.root.addChild(scene.container);
|
|
@@ -195,7 +209,7 @@ export class SceneManager extends EventEmitter<SceneManagerEvents> {
|
|
|
195
209
|
|
|
196
210
|
await scene.onEnter?.(data);
|
|
197
211
|
|
|
198
|
-
this.
|
|
212
|
+
this._transitionDepth--;
|
|
199
213
|
}
|
|
200
214
|
|
|
201
215
|
private async popInternal(
|
|
@@ -205,7 +219,7 @@ export class SceneManager extends EventEmitter<SceneManagerEvents> {
|
|
|
205
219
|
const entry = this.stack.pop();
|
|
206
220
|
if (!entry) return;
|
|
207
221
|
|
|
208
|
-
this.
|
|
222
|
+
this._transitionDepth++;
|
|
209
223
|
|
|
210
224
|
await entry.scene.onExit?.();
|
|
211
225
|
|
|
@@ -216,7 +230,7 @@ export class SceneManager extends EventEmitter<SceneManagerEvents> {
|
|
|
216
230
|
entry.scene.onDestroy?.();
|
|
217
231
|
entry.scene.container.destroy({ children: true });
|
|
218
232
|
|
|
219
|
-
this.
|
|
233
|
+
this._transitionDepth--;
|
|
220
234
|
}
|
|
221
235
|
|
|
222
236
|
private async transitionIn(
|
|
@@ -58,10 +58,12 @@ interface StateMachineEvents {
|
|
|
58
58
|
* ```
|
|
59
59
|
*/
|
|
60
60
|
export class StateMachine<TContext = Record<string, unknown>> extends EventEmitter<StateMachineEvents> {
|
|
61
|
+
private static MAX_TRANSITION_DEPTH = 10;
|
|
62
|
+
|
|
61
63
|
private _states = new Map<string, StateConfig<TContext>>();
|
|
62
64
|
private _guards = new Map<string, (ctx: TContext) => boolean>();
|
|
63
65
|
private _current: string | null = null;
|
|
64
|
-
private
|
|
66
|
+
private _transitionDepth = 0;
|
|
65
67
|
private _context: TContext;
|
|
66
68
|
|
|
67
69
|
constructor(context: TContext) {
|
|
@@ -76,7 +78,7 @@ export class StateMachine<TContext = Record<string, unknown>> extends EventEmitt
|
|
|
76
78
|
|
|
77
79
|
/** Whether a transition is in progress */
|
|
78
80
|
get isTransitioning(): boolean {
|
|
79
|
-
return this.
|
|
81
|
+
return this._transitionDepth > 0;
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
/** State machine context (shared data) */
|
|
@@ -131,9 +133,10 @@ export class StateMachine<TContext = Record<string, unknown>> extends EventEmitt
|
|
|
131
133
|
* @returns true if the transition succeeded, false if blocked by a guard
|
|
132
134
|
*/
|
|
133
135
|
async transition(to: string, data?: unknown): Promise<boolean> {
|
|
134
|
-
if (this.
|
|
135
|
-
|
|
136
|
-
|
|
136
|
+
if (this._transitionDepth >= StateMachine.MAX_TRANSITION_DEPTH) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
'[StateMachine] Max transition depth exceeded — possible infinite loop',
|
|
139
|
+
);
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
const from = this._current;
|
|
@@ -152,7 +155,7 @@ export class StateMachine<TContext = Record<string, unknown>> extends EventEmitt
|
|
|
152
155
|
throw new Error(`[StateMachine] State "${to}" not registered.`);
|
|
153
156
|
}
|
|
154
157
|
|
|
155
|
-
this.
|
|
158
|
+
this._transitionDepth++;
|
|
156
159
|
|
|
157
160
|
try {
|
|
158
161
|
// Exit current state
|
|
@@ -170,7 +173,7 @@ export class StateMachine<TContext = Record<string, unknown>> extends EventEmitt
|
|
|
170
173
|
this.emit('error', err instanceof Error ? err : new Error(String(err)));
|
|
171
174
|
throw err;
|
|
172
175
|
} finally {
|
|
173
|
-
this.
|
|
176
|
+
this._transitionDepth--;
|
|
174
177
|
}
|
|
175
178
|
|
|
176
179
|
return true;
|
|
@@ -213,7 +216,7 @@ export class StateMachine<TContext = Record<string, unknown>> extends EventEmitt
|
|
|
213
216
|
await state?.exit?.(this._context);
|
|
214
217
|
}
|
|
215
218
|
this._current = null;
|
|
216
|
-
this.
|
|
219
|
+
this._transitionDepth = 0;
|
|
217
220
|
}
|
|
218
221
|
|
|
219
222
|
/**
|