import { lua, lauxlib, lualib, to_luastring } from "fengari"; import { ScriptSchedulerService } from "./ScriptSchedulerService.js"; import { Instance } from "./Instance.js"; // your engine's instance class // Import interop from fengari-interop import { push, luaopen_js } from "fengari-interop"; export class Script extends Instance { constructor(sourceCode) { super("Script"); this.Source = sourceCode; this.LuaState = null; } Run() { const L = lauxlib.luaL_newstate(); luaopen_js(L); lualib.luaL_openlibs(L); // Bridge all engine APIs this._registerGlobals(L); // Compile the source const status = lauxlib.luaL_loadstring(L, to_luastring(this.Source)); if (status !== lua.LUA_OK) { const err = lua.lua_tojsstring(L, -1); throw new Error("Lua load error: " + err); } // Create a coroutine thread const thread = lua.lua_newthread(L); // Schedule with scheduler this._getScheduler().scheduleFengariCoroutine(thread, L); this.LuaState = L; } _registerGlobals(L) { // game global push(L, globalThis.game); lua.lua_setglobal(L, to_luastring("game")); // task + wait bridge lua.lua_pushjsfunction(L, () => { const secs = lua.lua_isnumber(L, 1) ? lua.lua_tonumber(L, 1) : 0; const yieldVal = JSON.stringify({ wait: secs }); lua.lua_pushstring(L, to_luastring(yieldVal)); return lua.lua_yield(L, 1); }); lua.lua_setglobal(L, to_luastring("task_wait")); // Lua API helpers lua.lua_pushjsfunction(L, () => { const inst = new Instance("Part"); // example return inst.LuaBridge(); // converts to Lua table/proxy }); lua.lua_setglobal(L, to_luastring("Instance_new")); } _getScheduler() { return game.GetService("ScriptSchedulerService"); } }