pixospritz-core 0.10.1 → 1.0.1
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/README.md +36 -286
- package/dist/bundle.js +13 -3
- package/dist/bundle.js.map +1 -1
- package/dist/style.css +1 -0
- package/package.json +43 -44
- package/src/components/WebGLView.jsx +318 -0
- package/src/css/pixos.css +372 -0
- package/src/engine/actions/animate.js +41 -0
- package/src/engine/actions/changezone.js +135 -0
- package/src/engine/actions/chat.js +109 -0
- package/src/engine/actions/dialogue.js +90 -0
- package/src/engine/actions/face.js +22 -0
- package/src/engine/actions/greeting.js +28 -0
- package/src/engine/actions/interact.js +86 -0
- package/src/engine/actions/move.js +67 -0
- package/src/engine/actions/patrol.js +109 -0
- package/src/engine/actions/prompt.js +185 -0
- package/src/engine/actions/script.js +42 -0
- package/src/engine/core/audio/AudioSystem.js +543 -0
- package/src/engine/core/cutscene/PxcPlayer.js +956 -0
- package/src/engine/core/cutscene/manager.js +243 -0
- package/src/engine/core/database/index.js +75 -0
- package/src/engine/core/debug/index.js +371 -0
- package/src/engine/core/hud/index.js +765 -0
- package/src/engine/core/index.js +540 -0
- package/src/engine/core/input/gamepad/Controller.js +71 -0
- package/src/engine/core/input/gamepad/ControllerButtons.js +231 -0
- package/src/engine/core/input/gamepad/ControllerStick.js +173 -0
- package/src/engine/core/input/gamepad/index.js +592 -0
- package/src/engine/core/input/keyboard.js +196 -0
- package/src/engine/core/input/manager.js +485 -0
- package/src/engine/core/input/mouse.js +203 -0
- package/src/engine/core/input/touch.js +175 -0
- package/src/engine/core/mode/manager.js +199 -0
- package/src/engine/core/net/manager.js +535 -0
- package/src/engine/core/queue/action.js +83 -0
- package/src/engine/core/queue/event.js +82 -0
- package/src/engine/core/queue/index.js +44 -0
- package/src/engine/core/queue/loadable.js +33 -0
- package/src/engine/core/render/CameraEffects.js +494 -0
- package/src/engine/core/render/FrustumCuller.js +417 -0
- package/src/engine/core/render/LODManager.js +285 -0
- package/src/engine/core/render/ParticleManager.js +529 -0
- package/src/engine/core/render/TextureAtlas.js +465 -0
- package/src/engine/core/render/camera.js +338 -0
- package/src/engine/core/render/light.js +197 -0
- package/src/engine/core/render/manager.js +1079 -0
- package/src/engine/core/render/shaders.js +110 -0
- package/src/engine/core/render/skybox.js +342 -0
- package/src/engine/core/resource/manager.js +133 -0
- package/src/engine/core/resource/object.js +611 -0
- package/src/engine/core/resource/texture.js +103 -0
- package/src/engine/core/resource/tileset.js +177 -0
- package/src/engine/core/scene/avatar.js +215 -0
- package/src/engine/core/scene/speech.js +138 -0
- package/src/engine/core/scene/sprite.js +702 -0
- package/src/engine/core/scene/spritz.js +189 -0
- package/src/engine/core/scene/world.js +681 -0
- package/src/engine/core/scene/zone.js +1167 -0
- package/src/engine/core/store/index.js +110 -0
- package/src/engine/dynamic/animatedSprite.js +64 -0
- package/src/engine/dynamic/animatedTile.js +98 -0
- package/src/engine/dynamic/avatar.js +110 -0
- package/src/engine/dynamic/map.js +174 -0
- package/src/engine/dynamic/sprite.js +255 -0
- package/src/engine/dynamic/spritz.js +119 -0
- package/src/engine/events/EventSystem.js +609 -0
- package/src/engine/events/camera.js +142 -0
- package/src/engine/events/chat.js +75 -0
- package/src/engine/events/menu.js +186 -0
- package/src/engine/scripting/CallbackManager.js +514 -0
- package/src/engine/scripting/PixoScriptInterpreter.js +81 -0
- package/src/engine/scripting/PixoScriptLibrary.js +704 -0
- package/src/engine/shaders/effects/index.js +450 -0
- package/src/engine/shaders/fs.js +222 -0
- package/src/engine/shaders/particles/fs.js +41 -0
- package/src/engine/shaders/particles/vs.js +61 -0
- package/src/engine/shaders/picker/fs.js +34 -0
- package/src/engine/shaders/picker/init.js +62 -0
- package/src/engine/shaders/picker/vs.js +42 -0
- package/src/engine/shaders/pxsl/README.md +250 -0
- package/src/engine/shaders/pxsl/index.js +25 -0
- package/src/engine/shaders/pxsl/library.js +608 -0
- package/src/engine/shaders/pxsl/manager.js +338 -0
- package/src/engine/shaders/pxsl/specification.js +363 -0
- package/src/engine/shaders/pxsl/transpiler.js +753 -0
- package/src/engine/shaders/skybox/cosmic/fs.js +147 -0
- package/src/engine/shaders/skybox/cosmic/vs.js +23 -0
- package/src/engine/shaders/skybox/matrix/fs.js +127 -0
- package/src/engine/shaders/skybox/matrix/vs.js +23 -0
- package/src/engine/shaders/skybox/morning/fs.js +109 -0
- package/src/engine/shaders/skybox/morning/vs.js +23 -0
- package/src/engine/shaders/skybox/neon/fs.js +119 -0
- package/src/engine/shaders/skybox/neon/vs.js +23 -0
- package/src/engine/shaders/skybox/sky/fs.js +114 -0
- package/src/engine/shaders/skybox/sky/vs.js +23 -0
- package/src/engine/shaders/skybox/sunset/fs.js +101 -0
- package/src/engine/shaders/skybox/sunset/vs.js +23 -0
- package/src/engine/shaders/transition/blur/fs.js +42 -0
- package/src/engine/shaders/transition/blur/vs.js +26 -0
- package/src/engine/shaders/transition/cross/fs.js +36 -0
- package/src/engine/shaders/transition/cross/vs.js +26 -0
- package/src/engine/shaders/transition/crossBlur/fs.js +41 -0
- package/src/engine/shaders/transition/crossBlur/vs.js +25 -0
- package/src/engine/shaders/transition/dissolve/fs.js +78 -0
- package/src/engine/shaders/transition/dissolve/vs.js +24 -0
- package/src/engine/shaders/transition/fade/fs.js +31 -0
- package/src/engine/shaders/transition/fade/vs.js +27 -0
- package/src/engine/shaders/transition/iris/fs.js +52 -0
- package/src/engine/shaders/transition/iris/vs.js +24 -0
- package/src/engine/shaders/transition/pixelate/fs.js +44 -0
- package/src/engine/shaders/transition/pixelate/vs.js +24 -0
- package/src/engine/shaders/transition/slide/fs.js +53 -0
- package/src/engine/shaders/transition/slide/vs.js +24 -0
- package/src/engine/shaders/transition/swirl/fs.js +39 -0
- package/src/engine/shaders/transition/swirl/vs.js +26 -0
- package/src/engine/shaders/transition/wipe/fs.js +50 -0
- package/src/engine/shaders/transition/wipe/vs.js +24 -0
- package/src/engine/shaders/vs.js +60 -0
- package/src/engine/utils/CameraController.js +506 -0
- package/src/engine/utils/ObjHelper.js +551 -0
- package/src/engine/utils/debug-logger.js +110 -0
- package/src/engine/utils/enums.js +305 -0
- package/src/engine/utils/generator.js +156 -0
- package/src/engine/utils/index.js +21 -0
- package/src/engine/utils/loaders/ActionLoader.js +77 -0
- package/src/engine/utils/loaders/AudioLoader.js +157 -0
- package/src/engine/utils/loaders/EventLoader.js +66 -0
- package/src/engine/utils/loaders/ObjectLoader.js +67 -0
- package/src/engine/utils/loaders/SpriteLoader.js +77 -0
- package/src/engine/utils/loaders/TilesetLoader.js +103 -0
- package/src/engine/utils/loaders/index.js +21 -0
- package/src/engine/utils/math/matrix4.js +367 -0
- package/src/engine/utils/math/vector.js +458 -0
- package/src/engine/utils/obj/_old_js/index.js +46 -0
- package/src/engine/utils/obj/_old_js/layout.js +308 -0
- package/src/engine/utils/obj/_old_js/material.js +711 -0
- package/src/engine/utils/obj/_old_js/mesh.js +761 -0
- package/src/engine/utils/obj/_old_js/utils.js +647 -0
- package/src/engine/utils/obj/index.js +24 -0
- package/src/engine/utils/obj/js/index.js +277 -0
- package/src/engine/utils/obj/js/loader.js +232 -0
- package/src/engine/utils/obj/layout.js +246 -0
- package/src/engine/utils/obj/material.js +665 -0
- package/src/engine/utils/obj/mesh.js +657 -0
- package/src/engine/utils/obj/ts/index.ts +72 -0
- package/src/engine/utils/obj/ts/layout.ts +265 -0
- package/src/engine/utils/obj/ts/material.ts +760 -0
- package/src/engine/utils/obj/ts/mesh.ts +785 -0
- package/src/engine/utils/obj/ts/utils.ts +501 -0
- package/src/engine/utils/obj/utils.js +428 -0
- package/src/engine/utils/resources.js +18 -0
- package/src/index.jsx +55 -0
- package/src/spritz/player.js +18 -0
- package/src/spritz/readme.md +18 -0
- package/LICENSE +0 -437
- package/dist/bundle.js.LICENSE.txt +0 -31
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
/* *\
|
|
2
|
+
** ----------------------------------------------- **
|
|
3
|
+
** Calliope - Pixos Game Engine **
|
|
4
|
+
** ----------------------------------------------- **
|
|
5
|
+
** Copyright (c) 2020-2025 - Kyle Derby MacInnis **
|
|
6
|
+
** **
|
|
7
|
+
** Any unauthorized distribution or transfer **
|
|
8
|
+
** of this work is strictly prohibited. **
|
|
9
|
+
** **
|
|
10
|
+
** All Rights Reserved. **
|
|
11
|
+
** ----------------------------------------------- **
|
|
12
|
+
\* */
|
|
13
|
+
|
|
14
|
+
import { debug } from '../utils/debug-logger.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {object} CallbackRegistration
|
|
18
|
+
* @property {string} id - Unique callback ID.
|
|
19
|
+
* @property {string} event - Event name (supports wildcards).
|
|
20
|
+
* @property {Function} handler - Callback function.
|
|
21
|
+
* @property {object} [context] - 'this' context for handler.
|
|
22
|
+
* @property {number} [priority=0] - Execution priority (higher = earlier).
|
|
23
|
+
* @property {boolean} [once=false] - Remove after first invocation.
|
|
24
|
+
* @property {object} [filter] - Optional event data filter.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @typedef {object} CallbackEvent
|
|
29
|
+
* @property {string} type - Event type name.
|
|
30
|
+
* @property {object} data - Event payload.
|
|
31
|
+
* @property {number} timestamp - Event timestamp.
|
|
32
|
+
* @property {boolean} defaultPrevented - Whether default was prevented.
|
|
33
|
+
* @property {boolean} propagationStopped - Whether propagation was stopped.
|
|
34
|
+
* @property {string} [target] - Target entity ID.
|
|
35
|
+
* @property {string} [source] - Source entity ID.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* CallbackManager - Manages engine event callbacks for scripting integration.
|
|
40
|
+
* Supports zone/sprite/trigger events with priority and filtering.
|
|
41
|
+
*/
|
|
42
|
+
export default class CallbackManager {
|
|
43
|
+
/**
|
|
44
|
+
* Creates an instance of CallbackManager.
|
|
45
|
+
* @param {import('../core/index.js').default} engine - The engine instance.
|
|
46
|
+
*/
|
|
47
|
+
constructor(engine) {
|
|
48
|
+
/** @type {import('../core/index.js').default} */
|
|
49
|
+
this.engine = engine;
|
|
50
|
+
|
|
51
|
+
/** @type {Map<string, CallbackRegistration[]>} Event name -> registrations */
|
|
52
|
+
this.callbacks = new Map();
|
|
53
|
+
|
|
54
|
+
/** @type {Map<string, CallbackRegistration[]>} Wildcard patterns */
|
|
55
|
+
this.wildcardCallbacks = new Map();
|
|
56
|
+
|
|
57
|
+
/** @type {number} Unique ID counter */
|
|
58
|
+
this.idCounter = 0;
|
|
59
|
+
|
|
60
|
+
/** @type {Set<string>} IDs to remove after current emission */
|
|
61
|
+
this.pendingRemovals = new Set();
|
|
62
|
+
|
|
63
|
+
/** @type {boolean} Currently emitting an event */
|
|
64
|
+
this.isEmitting = false;
|
|
65
|
+
|
|
66
|
+
/** @type {CallbackEvent[]} Event queue for deferred processing */
|
|
67
|
+
this.eventQueue = [];
|
|
68
|
+
|
|
69
|
+
/** @type {boolean} Process events immediately or queue them */
|
|
70
|
+
this.deferredMode = false;
|
|
71
|
+
|
|
72
|
+
// Register built-in event types
|
|
73
|
+
this.builtInEvents = [
|
|
74
|
+
'zone:enter', 'zone:exit', 'zone:load', 'zone:unload',
|
|
75
|
+
'sprite:click', 'sprite:hover', 'sprite:collide', 'sprite:spawn', 'sprite:destroy',
|
|
76
|
+
'trigger:enter', 'trigger:exit', 'trigger:activate',
|
|
77
|
+
'action:start', 'action:complete', 'action:cancel',
|
|
78
|
+
'player:move', 'player:interact', 'player:damage', 'player:heal',
|
|
79
|
+
'game:start', 'game:pause', 'game:resume', 'game:stop',
|
|
80
|
+
'cutscene:start', 'cutscene:end', 'cutscene:skip',
|
|
81
|
+
'menu:open', 'menu:close', 'menu:select',
|
|
82
|
+
'input:key', 'input:gamepad', 'input:mouse',
|
|
83
|
+
'update', 'render', 'physics'
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Register a callback for an event.
|
|
89
|
+
* @param {string} event - Event name (supports wildcards like 'sprite:*').
|
|
90
|
+
* @param {Function} handler - Callback function.
|
|
91
|
+
* @param {object} [options={}] - Registration options.
|
|
92
|
+
* @returns {string} Registration ID for unregistering.
|
|
93
|
+
*/
|
|
94
|
+
on(event, handler, options = {}) {
|
|
95
|
+
const id = `cb_${++this.idCounter}`;
|
|
96
|
+
const registration = {
|
|
97
|
+
id,
|
|
98
|
+
event,
|
|
99
|
+
handler,
|
|
100
|
+
context: options.context || null,
|
|
101
|
+
priority: options.priority || 0,
|
|
102
|
+
once: options.once || false,
|
|
103
|
+
filter: options.filter || null
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
if (event.includes('*')) {
|
|
107
|
+
// Wildcard registration
|
|
108
|
+
if (!this.wildcardCallbacks.has(event)) {
|
|
109
|
+
this.wildcardCallbacks.set(event, []);
|
|
110
|
+
}
|
|
111
|
+
this.wildcardCallbacks.get(event).push(registration);
|
|
112
|
+
this.sortByPriority(this.wildcardCallbacks.get(event));
|
|
113
|
+
} else {
|
|
114
|
+
// Direct registration
|
|
115
|
+
if (!this.callbacks.has(event)) {
|
|
116
|
+
this.callbacks.set(event, []);
|
|
117
|
+
}
|
|
118
|
+
this.callbacks.get(event).push(registration);
|
|
119
|
+
this.sortByPriority(this.callbacks.get(event));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
debug('CallbackManager', `Registered callback ${id} for event: ${event}`);
|
|
123
|
+
return id;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Register a one-time callback.
|
|
128
|
+
* @param {string} event - Event name.
|
|
129
|
+
* @param {Function} handler - Callback function.
|
|
130
|
+
* @param {object} [options={}] - Registration options.
|
|
131
|
+
* @returns {string} Registration ID.
|
|
132
|
+
*/
|
|
133
|
+
once(event, handler, options = {}) {
|
|
134
|
+
return this.on(event, handler, { ...options, once: true });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Unregister a callback by ID.
|
|
139
|
+
* @param {string} id - Registration ID.
|
|
140
|
+
* @returns {boolean} Whether the callback was found and removed.
|
|
141
|
+
*/
|
|
142
|
+
off(id) {
|
|
143
|
+
if (this.isEmitting) {
|
|
144
|
+
// Defer removal until after emission
|
|
145
|
+
this.pendingRemovals.add(id);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return this.removeById(id);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Remove a callback by ID from all maps.
|
|
154
|
+
* @param {string} id - Registration ID.
|
|
155
|
+
* @returns {boolean} Whether found and removed.
|
|
156
|
+
*/
|
|
157
|
+
removeById(id) {
|
|
158
|
+
for (const [event, registrations] of this.callbacks) {
|
|
159
|
+
const idx = registrations.findIndex(r => r.id === id);
|
|
160
|
+
if (idx >= 0) {
|
|
161
|
+
registrations.splice(idx, 1);
|
|
162
|
+
if (registrations.length === 0) this.callbacks.delete(event);
|
|
163
|
+
debug('CallbackManager', `Removed callback ${id}`);
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
for (const [pattern, registrations] of this.wildcardCallbacks) {
|
|
169
|
+
const idx = registrations.findIndex(r => r.id === id);
|
|
170
|
+
if (idx >= 0) {
|
|
171
|
+
registrations.splice(idx, 1);
|
|
172
|
+
if (registrations.length === 0) this.wildcardCallbacks.delete(pattern);
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Remove all callbacks for an event.
|
|
182
|
+
* @param {string} event - Event name.
|
|
183
|
+
*/
|
|
184
|
+
offAll(event) {
|
|
185
|
+
this.callbacks.delete(event);
|
|
186
|
+
this.wildcardCallbacks.delete(event);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Emit an event to all registered callbacks.
|
|
191
|
+
* @param {string} event - Event name.
|
|
192
|
+
* @param {object} [data={}] - Event data payload.
|
|
193
|
+
* @returns {CallbackEvent} The event object (check defaultPrevented).
|
|
194
|
+
*/
|
|
195
|
+
emit(event, data = {}) {
|
|
196
|
+
const callbackEvent = {
|
|
197
|
+
type: event,
|
|
198
|
+
data,
|
|
199
|
+
timestamp: Date.now(),
|
|
200
|
+
defaultPrevented: false,
|
|
201
|
+
propagationStopped: false,
|
|
202
|
+
target: data.target || null,
|
|
203
|
+
source: data.source || null,
|
|
204
|
+
|
|
205
|
+
preventDefault() {
|
|
206
|
+
this.defaultPrevented = true;
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
stopPropagation() {
|
|
210
|
+
this.propagationStopped = true;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
if (this.deferredMode) {
|
|
215
|
+
this.eventQueue.push(callbackEvent);
|
|
216
|
+
return callbackEvent;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
this.processEvent(callbackEvent);
|
|
220
|
+
return callbackEvent;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Process a single event.
|
|
225
|
+
* @param {CallbackEvent} event - Event to process.
|
|
226
|
+
*/
|
|
227
|
+
processEvent(event) {
|
|
228
|
+
this.isEmitting = true;
|
|
229
|
+
const toRemove = [];
|
|
230
|
+
|
|
231
|
+
// Get direct callbacks
|
|
232
|
+
const directCallbacks = this.callbacks.get(event.type) || [];
|
|
233
|
+
|
|
234
|
+
// Get wildcard callbacks
|
|
235
|
+
const wildcardMatches = this.getWildcardMatches(event.type);
|
|
236
|
+
|
|
237
|
+
// Combine and sort by priority
|
|
238
|
+
const allCallbacks = [...directCallbacks, ...wildcardMatches];
|
|
239
|
+
this.sortByPriority(allCallbacks);
|
|
240
|
+
|
|
241
|
+
for (const registration of allCallbacks) {
|
|
242
|
+
if (event.propagationStopped) break;
|
|
243
|
+
|
|
244
|
+
// Check filter
|
|
245
|
+
if (registration.filter && !this.matchesFilter(event.data, registration.filter)) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
if (registration.context) {
|
|
251
|
+
registration.handler.call(registration.context, event);
|
|
252
|
+
} else {
|
|
253
|
+
registration.handler(event);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (registration.once) {
|
|
257
|
+
toRemove.push(registration.id);
|
|
258
|
+
}
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.error(`CallbackManager: Error in callback for ${event.type}:`, error);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
this.isEmitting = false;
|
|
265
|
+
|
|
266
|
+
// Clean up once callbacks and pending removals
|
|
267
|
+
for (const id of toRemove) {
|
|
268
|
+
this.removeById(id);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
for (const id of this.pendingRemovals) {
|
|
272
|
+
this.removeById(id);
|
|
273
|
+
}
|
|
274
|
+
this.pendingRemovals.clear();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get all wildcard registrations matching an event.
|
|
279
|
+
* @param {string} event - Event name.
|
|
280
|
+
* @returns {CallbackRegistration[]} Matching registrations.
|
|
281
|
+
*/
|
|
282
|
+
getWildcardMatches(event) {
|
|
283
|
+
const matches = [];
|
|
284
|
+
|
|
285
|
+
for (const [pattern, registrations] of this.wildcardCallbacks) {
|
|
286
|
+
if (this.matchesPattern(event, pattern)) {
|
|
287
|
+
matches.push(...registrations);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return matches;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Check if an event matches a wildcard pattern.
|
|
296
|
+
* @param {string} event - Event name.
|
|
297
|
+
* @param {string} pattern - Pattern with wildcards.
|
|
298
|
+
* @returns {boolean} Whether it matches.
|
|
299
|
+
*/
|
|
300
|
+
matchesPattern(event, pattern) {
|
|
301
|
+
// Convert pattern to regex
|
|
302
|
+
const regexStr = '^' + pattern
|
|
303
|
+
.replace(/[.+?^${}()|[\]\\]/g, '\\$&')
|
|
304
|
+
.replace(/\*/g, '.*')
|
|
305
|
+
.replace(/\?/g, '.') + '$';
|
|
306
|
+
|
|
307
|
+
return new RegExp(regexStr).test(event);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Check if event data matches a filter.
|
|
312
|
+
* @param {object} data - Event data.
|
|
313
|
+
* @param {object} filter - Filter criteria.
|
|
314
|
+
* @returns {boolean} Whether data matches filter.
|
|
315
|
+
*/
|
|
316
|
+
matchesFilter(data, filter) {
|
|
317
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
318
|
+
if (typeof value === 'function') {
|
|
319
|
+
if (!value(data[key])) return false;
|
|
320
|
+
} else if (data[key] !== value) {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Sort registrations by priority (descending).
|
|
329
|
+
* @param {CallbackRegistration[]} registrations - Array to sort.
|
|
330
|
+
*/
|
|
331
|
+
sortByPriority(registrations) {
|
|
332
|
+
registrations.sort((a, b) => b.priority - a.priority);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Process all queued events (when in deferred mode).
|
|
337
|
+
*/
|
|
338
|
+
processQueue() {
|
|
339
|
+
while (this.eventQueue.length > 0) {
|
|
340
|
+
const event = this.eventQueue.shift();
|
|
341
|
+
this.processEvent(event);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Enable or disable deferred event processing.
|
|
347
|
+
* @param {boolean} enabled - Whether to defer events.
|
|
348
|
+
*/
|
|
349
|
+
setDeferredMode(enabled) {
|
|
350
|
+
this.deferredMode = enabled;
|
|
351
|
+
if (!enabled) {
|
|
352
|
+
this.processQueue();
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Create callback hooks for zone events.
|
|
358
|
+
* @param {string} zoneId - Zone identifier.
|
|
359
|
+
* @param {object} callbacks - Callback definitions.
|
|
360
|
+
* @returns {string[]} Registration IDs.
|
|
361
|
+
*/
|
|
362
|
+
registerZoneCallbacks(zoneId, callbacks) {
|
|
363
|
+
const ids = [];
|
|
364
|
+
|
|
365
|
+
if (callbacks.onEnter) {
|
|
366
|
+
ids.push(this.on('zone:enter', callbacks.onEnter, {
|
|
367
|
+
filter: { zoneId }
|
|
368
|
+
}));
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (callbacks.onExit) {
|
|
372
|
+
ids.push(this.on('zone:exit', callbacks.onExit, {
|
|
373
|
+
filter: { zoneId }
|
|
374
|
+
}));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (callbacks.onLoad) {
|
|
378
|
+
ids.push(this.on('zone:load', callbacks.onLoad, {
|
|
379
|
+
filter: { zoneId }
|
|
380
|
+
}));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return ids;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Create callback hooks for sprite events.
|
|
388
|
+
* @param {string} spriteId - Sprite identifier.
|
|
389
|
+
* @param {object} callbacks - Callback definitions.
|
|
390
|
+
* @returns {string[]} Registration IDs.
|
|
391
|
+
*/
|
|
392
|
+
registerSpriteCallbacks(spriteId, callbacks) {
|
|
393
|
+
const ids = [];
|
|
394
|
+
|
|
395
|
+
if (callbacks.onClick) {
|
|
396
|
+
ids.push(this.on('sprite:click', callbacks.onClick, {
|
|
397
|
+
filter: { spriteId }
|
|
398
|
+
}));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (callbacks.onHover) {
|
|
402
|
+
ids.push(this.on('sprite:hover', callbacks.onHover, {
|
|
403
|
+
filter: { spriteId }
|
|
404
|
+
}));
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (callbacks.onCollide) {
|
|
408
|
+
ids.push(this.on('sprite:collide', callbacks.onCollide, {
|
|
409
|
+
filter: { spriteId }
|
|
410
|
+
}));
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return ids;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Create callback hooks for trigger events.
|
|
418
|
+
* @param {string} triggerId - Trigger identifier.
|
|
419
|
+
* @param {object} callbacks - Callback definitions.
|
|
420
|
+
* @returns {string[]} Registration IDs.
|
|
421
|
+
*/
|
|
422
|
+
registerTriggerCallbacks(triggerId, callbacks) {
|
|
423
|
+
const ids = [];
|
|
424
|
+
|
|
425
|
+
if (callbacks.onEnter) {
|
|
426
|
+
ids.push(this.on('trigger:enter', callbacks.onEnter, {
|
|
427
|
+
filter: { triggerId }
|
|
428
|
+
}));
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (callbacks.onExit) {
|
|
432
|
+
ids.push(this.on('trigger:exit', callbacks.onExit, {
|
|
433
|
+
filter: { triggerId }
|
|
434
|
+
}));
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (callbacks.onActivate) {
|
|
438
|
+
ids.push(this.on('trigger:activate', callbacks.onActivate, {
|
|
439
|
+
filter: { triggerId }
|
|
440
|
+
}));
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return ids;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Register an update callback (called every frame).
|
|
448
|
+
* @param {Function} handler - Update function receiving delta time.
|
|
449
|
+
* @param {number} [priority=0] - Priority.
|
|
450
|
+
* @returns {string} Registration ID.
|
|
451
|
+
*/
|
|
452
|
+
onUpdate(handler, priority = 0) {
|
|
453
|
+
return this.on('update', (event) => {
|
|
454
|
+
handler(event.data.dt, event.data.time);
|
|
455
|
+
}, { priority });
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Get all registered event names.
|
|
460
|
+
* @returns {string[]} List of event names.
|
|
461
|
+
*/
|
|
462
|
+
getRegisteredEvents() {
|
|
463
|
+
return [
|
|
464
|
+
...this.callbacks.keys(),
|
|
465
|
+
...this.wildcardCallbacks.keys()
|
|
466
|
+
];
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Get count of registrations for an event.
|
|
471
|
+
* @param {string} event - Event name.
|
|
472
|
+
* @returns {number} Count.
|
|
473
|
+
*/
|
|
474
|
+
getListenerCount(event) {
|
|
475
|
+
const direct = this.callbacks.get(event)?.length || 0;
|
|
476
|
+
const wildcard = this.getWildcardMatches(event).length;
|
|
477
|
+
return direct + wildcard;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Clear all callbacks.
|
|
482
|
+
*/
|
|
483
|
+
clear() {
|
|
484
|
+
this.callbacks.clear();
|
|
485
|
+
this.wildcardCallbacks.clear();
|
|
486
|
+
this.eventQueue.length = 0;
|
|
487
|
+
this.pendingRemovals.clear();
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Create a Lua-compatible callback table for PixoScript.
|
|
492
|
+
* @returns {object} Lua table with callback functions.
|
|
493
|
+
*/
|
|
494
|
+
getLuaBindings() {
|
|
495
|
+
const manager = this;
|
|
496
|
+
|
|
497
|
+
return {
|
|
498
|
+
on: (event, handler) => manager.on(event, handler),
|
|
499
|
+
once: (event, handler) => manager.once(event, handler),
|
|
500
|
+
off: (id) => manager.off(id),
|
|
501
|
+
emit: (event, data) => manager.emit(event, data?.toObject?.() || data),
|
|
502
|
+
|
|
503
|
+
// Convenience methods
|
|
504
|
+
on_zone_enter: (zoneId, handler) => manager.on('zone:enter', handler, { filter: { zoneId } }),
|
|
505
|
+
on_zone_exit: (zoneId, handler) => manager.on('zone:exit', handler, { filter: { zoneId } }),
|
|
506
|
+
on_sprite_click: (spriteId, handler) => manager.on('sprite:click', handler, { filter: { spriteId } }),
|
|
507
|
+
on_trigger_enter: (triggerId, handler) => manager.on('trigger:enter', handler, { filter: { triggerId } }),
|
|
508
|
+
on_action_start: (handler) => manager.on('action:start', handler),
|
|
509
|
+
on_action_complete: (handler) => manager.on('action:complete', handler),
|
|
510
|
+
on_update: (handler) => manager.onUpdate(handler),
|
|
511
|
+
on_event: (pattern, handler) => manager.on(pattern, handler)
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/* *\
|
|
2
|
+
** ----------------------------------------------- **
|
|
3
|
+
** Calliope - Pixos Game Engine **
|
|
4
|
+
** ----------------------------------------------- **
|
|
5
|
+
** Copyright (c) 2020-2025 - Kyle Derby MacInnis **
|
|
6
|
+
** **
|
|
7
|
+
** Any unauthorized distribution or transfer **
|
|
8
|
+
** of this work is strictly prohibited. **
|
|
9
|
+
** **
|
|
10
|
+
** All Rights Reserved. **
|
|
11
|
+
** ----------------------------------------------- **
|
|
12
|
+
\* */
|
|
13
|
+
|
|
14
|
+
import PixoScriptLibrary from '@Engine/scripting/PixoScriptLibrary.js';
|
|
15
|
+
import * as pixoscript from 'pixoscript';
|
|
16
|
+
|
|
17
|
+
export default class PixoScriptInterpreter {
|
|
18
|
+
constructor(engine) {
|
|
19
|
+
this.engine = engine;
|
|
20
|
+
this.pixoscript = pixoscript;
|
|
21
|
+
this.pixosLib = new PixoScriptLibrary(this.pixoscript);
|
|
22
|
+
this.scope = {};
|
|
23
|
+
this.env = null;
|
|
24
|
+
this.library = null;
|
|
25
|
+
// Cache for loaded scripts (simulated filesystem)
|
|
26
|
+
this._scriptCache = new Map();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
setScope = (scope) => {
|
|
30
|
+
this.scope = scope;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
getScope = () => {
|
|
34
|
+
return this.scope;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Register a script in the virtual filesystem for require() support
|
|
39
|
+
* @param {string} path - Virtual path like "mymodule" or "lib/utils"
|
|
40
|
+
* @param {string} content - The script content
|
|
41
|
+
*/
|
|
42
|
+
registerScript = (path, content) => {
|
|
43
|
+
this._scriptCache.set(path, content);
|
|
44
|
+
this._scriptCache.set(path + '.pxs', content);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
createEnv = () => {
|
|
48
|
+
// Create config with virtual filesystem handlers
|
|
49
|
+
const config = {
|
|
50
|
+
PIXOSCRIPT_PATH: './?.pxs;./?/init.pxs',
|
|
51
|
+
fileExists: (path) => {
|
|
52
|
+
// Check if path exists in our script cache
|
|
53
|
+
const normalizedPath = path.replace(/^\.\//, '');
|
|
54
|
+
return this._scriptCache.has(normalizedPath);
|
|
55
|
+
},
|
|
56
|
+
loadFile: (path) => {
|
|
57
|
+
const normalizedPath = path.replace(/^\.\//, '');
|
|
58
|
+
const content = this._scriptCache.get(normalizedPath);
|
|
59
|
+
if (!content) {
|
|
60
|
+
throw new Error(`Script not found: ${path}`);
|
|
61
|
+
}
|
|
62
|
+
return content;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
this.env = this.pixoscript.createEnv(config);
|
|
67
|
+
return this.env;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
initLibrary = () => {
|
|
71
|
+
if (!this.env) this.createEnv();
|
|
72
|
+
this.library = this.pixosLib.getLibrary(this.engine, this.scope);
|
|
73
|
+
this.env.loadLib('pixos', this.library);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
run = async (script) => {
|
|
77
|
+
if (!this.env) this.createEnv();
|
|
78
|
+
if (!this.library) this.initLibrary();
|
|
79
|
+
return this.env.parse(script).exec();
|
|
80
|
+
};
|
|
81
|
+
}
|