@energy8platform/game-engine 0.10.2 → 0.10.3
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/bin/simulate.ts +0 -0
- package/dist/debug.cjs.js +64 -882
- package/dist/debug.cjs.js.map +1 -1
- package/dist/debug.d.ts +7 -9
- package/dist/debug.esm.js +64 -882
- package/dist/debug.esm.js.map +1 -1
- package/dist/index.cjs.js +64 -889
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +8 -165
- package/dist/index.esm.js +65 -883
- package/dist/index.esm.js.map +1 -1
- package/dist/lua.cjs.js +4 -4
- package/dist/lua.cjs.js.map +1 -1
- package/dist/lua.esm.js +4 -4
- package/dist/lua.esm.js.map +1 -1
- package/dist/vite.cjs.js +79 -35
- package/dist/vite.cjs.js.map +1 -1
- package/dist/vite.esm.js +79 -35
- package/dist/vite.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/debug/DevBridge.ts +71 -54
- package/src/index.ts +3 -8
- package/src/lua/LuaEngine.ts +2 -3
- package/src/lua/LuaEngineAPI.ts +1 -4
- package/src/lua/fengari.d.ts +10 -0
- package/src/vite/index.ts +85 -37
package/dist/vite.esm.js
CHANGED
|
@@ -64,31 +64,84 @@ await import('${entrySrc}');
|
|
|
64
64
|
}
|
|
65
65
|
// ─── Lua Plugin ─────────────────────────────────────────
|
|
66
66
|
/**
|
|
67
|
-
* Vite plugin that
|
|
68
|
-
*
|
|
67
|
+
* Vite plugin that:
|
|
68
|
+
* 1. Enables importing `.lua` files as raw strings with HMR
|
|
69
|
+
* 2. Runs a LuaEngine on the Vite dev server (Node.js) via `POST /__lua-play`
|
|
69
70
|
*
|
|
70
|
-
*
|
|
71
|
-
* `fengari` references at the top level so the library can be pre-bundled
|
|
72
|
-
* by esbuild and run in the browser without errors.
|
|
71
|
+
* fengari runs server-side only — no browser shims needed.
|
|
73
72
|
*/
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
function luaPlugin(configPath) {
|
|
74
|
+
let luaEngine = null;
|
|
75
|
+
let viteServer = null;
|
|
76
|
+
async function initEngine() {
|
|
77
|
+
if (!viteServer)
|
|
78
|
+
return;
|
|
79
|
+
try {
|
|
80
|
+
// Use Vite's SSR module loader to handle .ts config files
|
|
81
|
+
const resolvedPath = configPath.startsWith('.')
|
|
82
|
+
? '/' + configPath.replace(/^\.\//, '')
|
|
83
|
+
: configPath;
|
|
84
|
+
// ssrLoadModule transpiles TS and resolves imports (including ?raw)
|
|
85
|
+
const mod = await viteServer.ssrLoadModule(resolvedPath);
|
|
86
|
+
const config = mod.default ?? mod.config ?? mod;
|
|
87
|
+
if (!config.luaScript || !config.gameDefinition) {
|
|
88
|
+
console.log('[LuaPlugin] No luaScript/gameDefinition in config — Lua server disabled');
|
|
89
|
+
luaEngine = null;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// Load LuaEngine via SSR too (handles the fengari CJS import in Node.js)
|
|
93
|
+
const luaMod = await viteServer.ssrLoadModule('@energy8platform/game-engine/lua');
|
|
94
|
+
const { LuaEngine } = luaMod;
|
|
95
|
+
if (luaEngine)
|
|
96
|
+
luaEngine.destroy();
|
|
97
|
+
luaEngine = new LuaEngine({
|
|
98
|
+
script: config.luaScript,
|
|
99
|
+
gameDefinition: config.gameDefinition,
|
|
100
|
+
seed: config.luaSeed,
|
|
101
|
+
});
|
|
102
|
+
console.log('[LuaPlugin] LuaEngine initialized (server-side)');
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
console.warn('[LuaPlugin] Failed to initialize LuaEngine:', e.message);
|
|
106
|
+
luaEngine = null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
80
109
|
return {
|
|
81
110
|
name: 'game-engine:lua',
|
|
82
111
|
apply: 'serve',
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
112
|
+
async configureServer(server) {
|
|
113
|
+
viteServer = server;
|
|
114
|
+
await initEngine();
|
|
115
|
+
// POST /__lua-play — execute Lua on the server
|
|
116
|
+
server.middlewares.use('/__lua-play', (req, res) => {
|
|
117
|
+
if (req.method !== 'POST') {
|
|
118
|
+
res.statusCode = 405;
|
|
119
|
+
res.end('Method Not Allowed');
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
let body = '';
|
|
123
|
+
req.on('data', (chunk) => { body += chunk; });
|
|
124
|
+
req.on('end', () => {
|
|
125
|
+
try {
|
|
126
|
+
if (!luaEngine) {
|
|
127
|
+
res.statusCode = 503;
|
|
128
|
+
res.setHeader('Content-Type', 'application/json');
|
|
129
|
+
res.end(JSON.stringify({ error: 'LuaEngine not initialized' }));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const params = JSON.parse(body);
|
|
133
|
+
const result = luaEngine.execute(params);
|
|
134
|
+
res.statusCode = 200;
|
|
135
|
+
res.setHeader('Content-Type', 'application/json');
|
|
136
|
+
res.end(JSON.stringify(result));
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
res.statusCode = 500;
|
|
140
|
+
res.setHeader('Content-Type', 'application/json');
|
|
141
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
});
|
|
92
145
|
},
|
|
93
146
|
transform(code, id) {
|
|
94
147
|
if (id.endsWith('.lua')) {
|
|
@@ -98,8 +151,10 @@ function luaPlugin() {
|
|
|
98
151
|
};
|
|
99
152
|
}
|
|
100
153
|
},
|
|
101
|
-
handleHotUpdate({ file, server }) {
|
|
102
|
-
if (file.endsWith('.lua')) {
|
|
154
|
+
async handleHotUpdate({ file, server }) {
|
|
155
|
+
if (file.endsWith('.lua') || file.includes('dev.config')) {
|
|
156
|
+
console.log('[LuaPlugin] Reloading LuaEngine...');
|
|
157
|
+
await initEngine();
|
|
103
158
|
server.ws.send({ type: 'full-reload' });
|
|
104
159
|
return [];
|
|
105
160
|
}
|
|
@@ -132,26 +187,15 @@ function defineGameConfig(config = {}) {
|
|
|
132
187
|
if (config.devBridge) {
|
|
133
188
|
const configPath = config.devBridgeConfig ?? './dev.config';
|
|
134
189
|
plugins.push(devBridgePlugin(configPath));
|
|
135
|
-
plugins.push(luaPlugin());
|
|
190
|
+
plugins.push(luaPlugin(configPath));
|
|
136
191
|
}
|
|
137
192
|
const userVite = config.vite ?? {};
|
|
138
|
-
// fengari (Lua 5.3 in JS) is a CJS Node.js package that references `process`
|
|
139
|
-
// and `require('os')` at module level. Provide shims so it works in the browser.
|
|
140
|
-
const fengariShims = config.devBridge ? {
|
|
141
|
-
'process.versions.node': 'undefined',
|
|
142
|
-
'process.env': '({})',
|
|
143
|
-
'process.platform': '"browser"',
|
|
144
|
-
} : {};
|
|
145
193
|
return {
|
|
146
194
|
base: config.base ?? '/',
|
|
147
195
|
plugins: [
|
|
148
196
|
...plugins,
|
|
149
197
|
...(userVite.plugins ?? []),
|
|
150
198
|
],
|
|
151
|
-
define: {
|
|
152
|
-
...fengariShims,
|
|
153
|
-
...userVite.define,
|
|
154
|
-
},
|
|
155
199
|
build: {
|
|
156
200
|
target: 'esnext',
|
|
157
201
|
assetsInlineLimit: 8192,
|
|
@@ -193,10 +237,10 @@ function defineGameConfig(config = {}) {
|
|
|
193
237
|
'yoga-layout/load',
|
|
194
238
|
'react',
|
|
195
239
|
'react-dom',
|
|
196
|
-
...(config.devBridge ? ['fengari'] : []),
|
|
197
240
|
],
|
|
198
241
|
exclude: [
|
|
199
242
|
'yoga-layout',
|
|
243
|
+
'fengari',
|
|
200
244
|
],
|
|
201
245
|
esbuildOptions: {
|
|
202
246
|
target: 'esnext',
|
package/dist/vite.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.esm.js","sources":["../src/vite/index.ts"],"sourcesContent":[null],"names":[],"mappings":"AAkBA;AAEA;;;;AAIG;AACH,MAAM,UAAU,GAAG,uBAAuB;AAE1C,SAAS,eAAe,CAAC,UAAkB,EAAA;IACzC,IAAI,QAAQ,GAAG,EAAE;IACjB,IAAI,QAAQ,GAAG,EAAE;IACjB,IAAI,kBAAkB,GAAG,UAAU;IAEnC,OAAO;AACL,QAAA,IAAI,EAAE,wBAAwB;QAC9B,KAAK,EAAE,OAAO;AACd,QAAA,OAAO,EAAE,KAAK;AAEd,QAAA,cAAc,CAAC,MAAM,EAAA;AACnB,YAAA,QAAQ,GAAG,MAAM,CAAC,IAAI;;;AAGtB,YAAA,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AAC9B,gBAAA,kBAAkB,GAAG,MAAM,CAAC,IAAI,GAAG,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC1E;QACF,CAAC;AAED,QAAA,SAAS,CAAC,EAAE,EAAA;YACV,IAAI,EAAE,KAAK,UAAU;AAAE,gBAAA,OAAO,EAAE;QAClC,CAAC;AAED,QAAA,IAAI,CAAC,EAAE,EAAA;AACL,YAAA,IAAI,EAAE,KAAK,UAAU,EAAE;;gBAErB,OAAO;;;;8BAIe,kBAAkB,CAAA;;;;;;;gBAOhC,QAAQ,CAAA;CACvB;YACK;QACF,CAAC;AAED,QAAA,kBAAkB,CAAC,IAAI,EAAA;;YAErB,MAAM,WAAW,GAAG,iEAAiE;YACrF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;YAErC,IAAI,CAAC,KAAK,EAAE;AACV,gBAAA,OAAO,CAAC,IAAI,CAAC,8DAA8D,CAAC;AAC5E,gBAAA,OAAO,IAAI;YACb;AAEA,YAAA,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC;AACnB,YAAA,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AAC5B,gBAAA,QAAQ,GAAG,QAAQ,GAAG,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC3D;AAAO,iBAAA,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AACnC,gBAAA,QAAQ,GAAG,QAAQ,GAAG,QAAQ;YAChC;AACA,YAAA,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA,2BAAA,EAA8B,UAAU,CAAA,WAAA,CAAa,CAAC;QACtF,CAAC;KACF;AACH;AAEA;AAEA
|
|
1
|
+
{"version":3,"file":"vite.esm.js","sources":["../src/vite/index.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/debug/DevBridge.ts
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
type PlayParams,
|
|
10
10
|
} from '@energy8platform/game-sdk';
|
|
11
11
|
import type { GameDefinition } from '../lua/types';
|
|
12
|
-
import { LuaEngine } from '../lua/LuaEngine';
|
|
13
12
|
|
|
14
13
|
export interface DevBridgeConfig {
|
|
15
14
|
/** Mock initial balance */
|
|
@@ -28,7 +27,7 @@ export interface DevBridgeConfig {
|
|
|
28
27
|
networkDelay?: number;
|
|
29
28
|
/** Enable debug logging */
|
|
30
29
|
debug?: boolean;
|
|
31
|
-
/** Lua script source code. When set,
|
|
30
|
+
/** Lua script source code. When set, play requests are routed to the Vite dev server's LuaEngine. */
|
|
32
31
|
luaScript?: string;
|
|
33
32
|
/** Game definition for Lua engine (actions, transitions, etc.) */
|
|
34
33
|
gameDefinition?: GameDefinition;
|
|
@@ -60,11 +59,11 @@ const DEFAULT_CONFIG: Omit<Required<DevBridgeConfig>, 'luaScript' | 'gameDefinit
|
|
|
60
59
|
* `CasinoGameSDK` via a shared in-memory `MemoryChannel`, removing
|
|
61
60
|
* the need for postMessage and iframes.
|
|
62
61
|
*
|
|
63
|
-
*
|
|
62
|
+
* When `luaScript` is set, play requests are sent to the Vite dev server
|
|
63
|
+
* which runs LuaEngine in Node.js — no fengari in the browser.
|
|
64
64
|
*
|
|
65
65
|
* @example
|
|
66
66
|
* ```ts
|
|
67
|
-
* // In your dev entry point or vite plugin
|
|
68
67
|
* import { DevBridge } from '@energy8platform/game-engine/debug';
|
|
69
68
|
*
|
|
70
69
|
* const devBridge = new DevBridge({
|
|
@@ -73,10 +72,7 @@ const DEFAULT_CONFIG: Omit<Required<DevBridgeConfig>, 'luaScript' | 'gameDefinit
|
|
|
73
72
|
* gameConfig: { id: 'my-slot', type: 'slot', betLevels: [0.2, 0.5, 1, 2] },
|
|
74
73
|
* onPlay: ({ action, bet }) => ({
|
|
75
74
|
* totalWin: Math.random() > 0.5 ? bet * (Math.random() * 20) : 0,
|
|
76
|
-
* data: {
|
|
77
|
-
* matrix: generateRandomMatrix(5, 3, 10),
|
|
78
|
-
* win_lines: [],
|
|
79
|
-
* },
|
|
75
|
+
* data: { matrix: [[1,2,3],[4,5,6],[7,8,9]] },
|
|
80
76
|
* }),
|
|
81
77
|
* });
|
|
82
78
|
* devBridge.start();
|
|
@@ -87,12 +83,12 @@ export class DevBridge {
|
|
|
87
83
|
private _balance: number;
|
|
88
84
|
private _roundCounter = 0;
|
|
89
85
|
private _bridge: Bridge | null = null;
|
|
90
|
-
private
|
|
86
|
+
private _useLuaServer: boolean;
|
|
91
87
|
|
|
92
88
|
constructor(config: DevBridgeConfig = {}) {
|
|
93
89
|
this._config = { ...DEFAULT_CONFIG, ...config };
|
|
94
90
|
this._balance = this._config.balance;
|
|
95
|
-
this.
|
|
91
|
+
this._useLuaServer = !!(this._config.luaScript && this._config.gameDefinition);
|
|
96
92
|
}
|
|
97
93
|
|
|
98
94
|
/** Current mock balance */
|
|
@@ -133,7 +129,8 @@ export class DevBridge {
|
|
|
133
129
|
});
|
|
134
130
|
|
|
135
131
|
if (this._config.debug) {
|
|
136
|
-
|
|
132
|
+
const mode = this._useLuaServer ? 'Lua (server-side)' : 'onPlay callback';
|
|
133
|
+
console.log(`[DevBridge] Started — mode: ${mode}`);
|
|
137
134
|
}
|
|
138
135
|
}
|
|
139
136
|
|
|
@@ -158,24 +155,6 @@ export class DevBridge {
|
|
|
158
155
|
/** Destroy the dev bridge */
|
|
159
156
|
destroy(): void {
|
|
160
157
|
this.stop();
|
|
161
|
-
if (this._luaEngine) {
|
|
162
|
-
this._luaEngine.destroy();
|
|
163
|
-
this._luaEngine = null;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
private initLuaEngine(): void {
|
|
168
|
-
if (!this._config.luaScript || !this._config.gameDefinition) return;
|
|
169
|
-
|
|
170
|
-
this._luaEngine = new LuaEngine({
|
|
171
|
-
script: this._config.luaScript,
|
|
172
|
-
gameDefinition: this._config.gameDefinition,
|
|
173
|
-
seed: this._config.luaSeed,
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
if (this._config.debug) {
|
|
177
|
-
console.log('[DevBridge] LuaEngine initialized');
|
|
178
|
-
}
|
|
179
158
|
}
|
|
180
159
|
|
|
181
160
|
// ─── Message Handling ──────────────────────────────────
|
|
@@ -202,28 +181,18 @@ export class DevBridge {
|
|
|
202
181
|
this._balance -= bet;
|
|
203
182
|
this._roundCounter++;
|
|
204
183
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
balanceAfter: this._balance,
|
|
218
|
-
totalWin: Math.round(luaResult.totalWin * 100) / 100,
|
|
219
|
-
data: luaResult.data,
|
|
220
|
-
nextActions: luaResult.nextActions,
|
|
221
|
-
session: luaResult.session,
|
|
222
|
-
creditPending: luaResult.creditDeferred,
|
|
223
|
-
bonusFreeSpin: null,
|
|
224
|
-
currency: this._config.currency,
|
|
225
|
-
gameId: this._config.gameConfig?.id ?? 'dev-game',
|
|
226
|
-
};
|
|
184
|
+
if (this._useLuaServer) {
|
|
185
|
+
// Send to Vite dev server for Lua execution
|
|
186
|
+
this.executeLuaOnServer({ action, bet, roundId, params })
|
|
187
|
+
.then((result) => {
|
|
188
|
+
this._bridge?.send('PLAY_RESULT', result, id);
|
|
189
|
+
})
|
|
190
|
+
.catch((err) => {
|
|
191
|
+
console.error('[DevBridge] Lua server error:', err);
|
|
192
|
+
// Refund bet on error
|
|
193
|
+
this._balance += bet;
|
|
194
|
+
this._bridge?.send('PLAY_RESULT', this.buildFallbackResult(action, bet, roundId), id);
|
|
195
|
+
});
|
|
227
196
|
} else {
|
|
228
197
|
// Fallback to onPlay callback
|
|
229
198
|
const customResult = this._config.onPlay({ action, bet, roundId, params });
|
|
@@ -231,7 +200,7 @@ export class DevBridge {
|
|
|
231
200
|
|
|
232
201
|
this._balance += totalWin;
|
|
233
202
|
|
|
234
|
-
result = {
|
|
203
|
+
const result: PlayResultData = {
|
|
235
204
|
roundId: roundId ?? `dev-round-${this._roundCounter}`,
|
|
236
205
|
action,
|
|
237
206
|
balanceAfter: this._balance,
|
|
@@ -244,9 +213,57 @@ export class DevBridge {
|
|
|
244
213
|
currency: this._config.currency,
|
|
245
214
|
gameId: this._config.gameConfig?.id ?? 'dev-game',
|
|
246
215
|
};
|
|
216
|
+
|
|
217
|
+
this.delayedSend('PLAY_RESULT', result, id);
|
|
247
218
|
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private async executeLuaOnServer(params: PlayParams): Promise<PlayResultData> {
|
|
222
|
+
const response = await fetch('/__lua-play', {
|
|
223
|
+
method: 'POST',
|
|
224
|
+
headers: { 'Content-Type': 'application/json' },
|
|
225
|
+
body: JSON.stringify(params),
|
|
226
|
+
});
|
|
248
227
|
|
|
249
|
-
|
|
228
|
+
if (!response.ok) {
|
|
229
|
+
const err = await response.json().catch(() => ({ error: 'Unknown error' }));
|
|
230
|
+
throw new Error(err.error ?? `HTTP ${response.status}`);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const luaResult = await response.json();
|
|
234
|
+
|
|
235
|
+
const totalWin = luaResult.creditDeferred ? 0 : luaResult.totalWin;
|
|
236
|
+
this._balance += totalWin;
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
roundId: params.roundId ?? `dev-round-${this._roundCounter}`,
|
|
240
|
+
action: params.action,
|
|
241
|
+
balanceAfter: this._balance,
|
|
242
|
+
totalWin: Math.round(luaResult.totalWin * 100) / 100,
|
|
243
|
+
data: luaResult.data,
|
|
244
|
+
nextActions: luaResult.nextActions,
|
|
245
|
+
session: luaResult.session,
|
|
246
|
+
creditPending: luaResult.creditDeferred,
|
|
247
|
+
bonusFreeSpin: null,
|
|
248
|
+
currency: this._config.currency,
|
|
249
|
+
gameId: this._config.gameConfig?.id ?? 'dev-game',
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private buildFallbackResult(action: string, bet: number, roundId?: string): PlayResultData {
|
|
254
|
+
return {
|
|
255
|
+
roundId: roundId ?? `dev-round-${this._roundCounter}`,
|
|
256
|
+
action,
|
|
257
|
+
balanceAfter: this._balance,
|
|
258
|
+
totalWin: 0,
|
|
259
|
+
data: { error: 'Lua execution failed' },
|
|
260
|
+
nextActions: ['spin'],
|
|
261
|
+
session: null,
|
|
262
|
+
creditPending: false,
|
|
263
|
+
bonusFreeSpin: null,
|
|
264
|
+
currency: this._config.currency,
|
|
265
|
+
gameId: this._config.gameConfig?.id ?? 'dev-game',
|
|
266
|
+
};
|
|
250
267
|
}
|
|
251
268
|
|
|
252
269
|
private handlePlayAck(_payload: PlayResultAckPayload): void {
|
|
@@ -265,7 +282,7 @@ export class DevBridge {
|
|
|
265
282
|
|
|
266
283
|
private handleOpenDeposit(): void {
|
|
267
284
|
if (this._config.debug) {
|
|
268
|
-
console.log('[DevBridge]
|
|
285
|
+
console.log('[DevBridge] Open deposit requested (mock: adding 1000)');
|
|
269
286
|
}
|
|
270
287
|
this._balance += 1000;
|
|
271
288
|
this._bridge?.send('BALANCE_UPDATE', { balance: this._balance });
|
package/src/index.ts
CHANGED
|
@@ -101,14 +101,9 @@ export type { DevBridgeConfig } from './debug/DevBridge';
|
|
|
101
101
|
export { FPSOverlay } from './debug/FPSOverlay';
|
|
102
102
|
|
|
103
103
|
// ─── Lua ────────────────────────────────────────────────
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
export { LuaEngine } from './lua/LuaEngine';
|
|
108
|
-
export { LuaEngineAPI, createSeededRng } from './lua/LuaEngineAPI';
|
|
109
|
-
export { ActionRouter, evaluateCondition } from './lua/ActionRouter';
|
|
110
|
-
export { SessionManager } from './lua/SessionManager';
|
|
111
|
-
export { PersistentState } from './lua/PersistentState';
|
|
104
|
+
// Lua module is Node.js only (fengari). Use the sub-path import:
|
|
105
|
+
// import { LuaEngine } from '@energy8platform/game-engine/lua'
|
|
106
|
+
// Re-export only types (zero runtime cost, no fengari in browser bundle).
|
|
112
107
|
export type {
|
|
113
108
|
GameDefinition,
|
|
114
109
|
ActionDefinition,
|
package/src/lua/LuaEngine.ts
CHANGED
|
@@ -6,9 +6,8 @@ import { SessionManager } from './SessionManager';
|
|
|
6
6
|
import { PersistentState } from './PersistentState';
|
|
7
7
|
|
|
8
8
|
// fengari — Lua 5.3 in pure JavaScript
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const fengari = require('fengari');
|
|
9
|
+
import fengari from 'fengari';
|
|
10
|
+
|
|
12
11
|
const { lua, lauxlib, lualib } = fengari;
|
|
13
12
|
const { to_luastring, to_jsstring } = fengari;
|
|
14
13
|
|
package/src/lua/LuaEngineAPI.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { GameDefinition } from './types';
|
|
2
|
+
import fengari from 'fengari';
|
|
2
3
|
|
|
3
|
-
// fengari is a CJS module — use dynamic import workaround for ESM compatibility
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
5
|
-
declare const require: (module: string) => any;
|
|
6
|
-
const fengari = require('fengari');
|
|
7
4
|
const { lua, lauxlib } = fengari;
|
|
8
5
|
const { to_luastring, to_jsstring } = fengari;
|
|
9
6
|
|
package/src/vite/index.ts
CHANGED
|
@@ -91,33 +91,92 @@ await import('${entrySrc}');
|
|
|
91
91
|
// ─── Lua Plugin ─────────────────────────────────────────
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* Vite plugin that
|
|
95
|
-
*
|
|
94
|
+
* Vite plugin that:
|
|
95
|
+
* 1. Enables importing `.lua` files as raw strings with HMR
|
|
96
|
+
* 2. Runs a LuaEngine on the Vite dev server (Node.js) via `POST /__lua-play`
|
|
96
97
|
*
|
|
97
|
-
*
|
|
98
|
-
* `fengari` references at the top level so the library can be pre-bundled
|
|
99
|
-
* by esbuild and run in the browser without errors.
|
|
98
|
+
* fengari runs server-side only — no browser shims needed.
|
|
100
99
|
*/
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
function luaPlugin(configPath: string): Plugin {
|
|
101
|
+
let luaEngine: any = null;
|
|
102
|
+
let viteServer: any = null;
|
|
103
|
+
|
|
104
|
+
async function initEngine() {
|
|
105
|
+
if (!viteServer) return;
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
// Use Vite's SSR module loader to handle .ts config files
|
|
109
|
+
const resolvedPath = configPath.startsWith('.')
|
|
110
|
+
? '/' + configPath.replace(/^\.\//, '')
|
|
111
|
+
: configPath;
|
|
112
|
+
|
|
113
|
+
// ssrLoadModule transpiles TS and resolves imports (including ?raw)
|
|
114
|
+
const mod = await viteServer.ssrLoadModule(resolvedPath);
|
|
115
|
+
const config = mod.default ?? mod.config ?? mod;
|
|
116
|
+
|
|
117
|
+
if (!config.luaScript || !config.gameDefinition) {
|
|
118
|
+
console.log('[LuaPlugin] No luaScript/gameDefinition in config — Lua server disabled');
|
|
119
|
+
luaEngine = null;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Load LuaEngine via SSR too (handles the fengari CJS import in Node.js)
|
|
124
|
+
const luaMod = await viteServer.ssrLoadModule('@energy8platform/game-engine/lua');
|
|
125
|
+
const { LuaEngine } = luaMod;
|
|
126
|
+
|
|
127
|
+
if (luaEngine) luaEngine.destroy();
|
|
128
|
+
luaEngine = new LuaEngine({
|
|
129
|
+
script: config.luaScript,
|
|
130
|
+
gameDefinition: config.gameDefinition,
|
|
131
|
+
seed: config.luaSeed,
|
|
132
|
+
});
|
|
133
|
+
console.log('[LuaPlugin] LuaEngine initialized (server-side)');
|
|
134
|
+
} catch (e: any) {
|
|
135
|
+
console.warn('[LuaPlugin] Failed to initialize LuaEngine:', e.message);
|
|
136
|
+
luaEngine = null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
106
139
|
|
|
107
|
-
function luaPlugin(): Plugin {
|
|
108
140
|
return {
|
|
109
141
|
name: 'game-engine:lua',
|
|
110
142
|
apply: 'serve',
|
|
111
143
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
144
|
+
async configureServer(server) {
|
|
145
|
+
viteServer = server;
|
|
146
|
+
await initEngine();
|
|
147
|
+
|
|
148
|
+
// POST /__lua-play — execute Lua on the server
|
|
149
|
+
server.middlewares.use('/__lua-play', (req: any, res: any) => {
|
|
150
|
+
if (req.method !== 'POST') {
|
|
151
|
+
res.statusCode = 405;
|
|
152
|
+
res.end('Method Not Allowed');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let body = '';
|
|
157
|
+
req.on('data', (chunk: string) => { body += chunk; });
|
|
158
|
+
req.on('end', () => {
|
|
159
|
+
try {
|
|
160
|
+
if (!luaEngine) {
|
|
161
|
+
res.statusCode = 503;
|
|
162
|
+
res.setHeader('Content-Type', 'application/json');
|
|
163
|
+
res.end(JSON.stringify({ error: 'LuaEngine not initialized' }));
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const params = JSON.parse(body);
|
|
168
|
+
const result = luaEngine.execute(params);
|
|
169
|
+
|
|
170
|
+
res.statusCode = 200;
|
|
171
|
+
res.setHeader('Content-Type', 'application/json');
|
|
172
|
+
res.end(JSON.stringify(result));
|
|
173
|
+
} catch (e: any) {
|
|
174
|
+
res.statusCode = 500;
|
|
175
|
+
res.setHeader('Content-Type', 'application/json');
|
|
176
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
});
|
|
121
180
|
},
|
|
122
181
|
|
|
123
182
|
transform(code: string, id: string) {
|
|
@@ -129,8 +188,10 @@ function luaPlugin(): Plugin {
|
|
|
129
188
|
}
|
|
130
189
|
},
|
|
131
190
|
|
|
132
|
-
handleHotUpdate({ file, server }: { file: string; server: any }) {
|
|
133
|
-
if (file.endsWith('.lua')) {
|
|
191
|
+
async handleHotUpdate({ file, server }: { file: string; server: any }) {
|
|
192
|
+
if (file.endsWith('.lua') || file.includes('dev.config')) {
|
|
193
|
+
console.log('[LuaPlugin] Reloading LuaEngine...');
|
|
194
|
+
await initEngine();
|
|
134
195
|
server.ws.send({ type: 'full-reload' });
|
|
135
196
|
return [];
|
|
136
197
|
}
|
|
@@ -166,19 +227,11 @@ export function defineGameConfig(config: GameConfig = {}): UserConfig {
|
|
|
166
227
|
if (config.devBridge) {
|
|
167
228
|
const configPath = config.devBridgeConfig ?? './dev.config';
|
|
168
229
|
plugins.push(devBridgePlugin(configPath));
|
|
169
|
-
plugins.push(luaPlugin());
|
|
230
|
+
plugins.push(luaPlugin(configPath));
|
|
170
231
|
}
|
|
171
232
|
|
|
172
233
|
const userVite = config.vite ?? {};
|
|
173
234
|
|
|
174
|
-
// fengari (Lua 5.3 in JS) is a CJS Node.js package that references `process`
|
|
175
|
-
// and `require('os')` at module level. Provide shims so it works in the browser.
|
|
176
|
-
const fengariShims: Record<string, string> = config.devBridge ? {
|
|
177
|
-
'process.versions.node': 'undefined',
|
|
178
|
-
'process.env': '({})',
|
|
179
|
-
'process.platform': '"browser"',
|
|
180
|
-
} : {};
|
|
181
|
-
|
|
182
235
|
return {
|
|
183
236
|
base: config.base ?? '/',
|
|
184
237
|
|
|
@@ -187,11 +240,6 @@ export function defineGameConfig(config: GameConfig = {}): UserConfig {
|
|
|
187
240
|
...((userVite.plugins as Plugin[]) ?? []),
|
|
188
241
|
],
|
|
189
242
|
|
|
190
|
-
define: {
|
|
191
|
-
...fengariShims,
|
|
192
|
-
...(userVite as Record<string, any>).define,
|
|
193
|
-
},
|
|
194
|
-
|
|
195
243
|
build: {
|
|
196
244
|
target: 'esnext',
|
|
197
245
|
assetsInlineLimit: 8192,
|
|
@@ -236,10 +284,10 @@ export function defineGameConfig(config: GameConfig = {}): UserConfig {
|
|
|
236
284
|
'yoga-layout/load',
|
|
237
285
|
'react',
|
|
238
286
|
'react-dom',
|
|
239
|
-
...(config.devBridge ? ['fengari'] : []),
|
|
240
287
|
],
|
|
241
288
|
exclude: [
|
|
242
289
|
'yoga-layout',
|
|
290
|
+
'fengari',
|
|
243
291
|
],
|
|
244
292
|
esbuildOptions: {
|
|
245
293
|
target: 'esnext',
|