Add launchable
This commit is contained in:
111
js/instances/ScriptSchedulerService.js
Normal file
111
js/instances/ScriptSchedulerService.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import { lua, lauxlib, lualib, to_luastring } from "fengari";
|
||||
const lua_resume = lua.lua_resume;
|
||||
const LUA_OK = lua.LUA_OK;
|
||||
const LUA_YIELD = lua.LUA_YIELD;
|
||||
import { BaseService } from "./BaseService.js";
|
||||
export class ScriptSchedulerService extends BaseService {
|
||||
constructor() {
|
||||
super("ScriptSchedulerService");
|
||||
this._scheduled = [];
|
||||
this._waiting = [];
|
||||
this._running = false;
|
||||
}
|
||||
|
||||
// Add a script (generator function) to the scheduler
|
||||
schedule(scriptGen) {
|
||||
if (typeof scriptGen === "function") {
|
||||
const gen = scriptGen();
|
||||
this._scheduled.push({ gen, wakeTime: 0 });
|
||||
} else if (scriptGen && typeof scriptGen.next === "function") {
|
||||
this._scheduled.push({ gen: scriptGen, wakeTime: 0 });
|
||||
} else {
|
||||
throw new Error("Script must be a generator or generator function");
|
||||
}
|
||||
}
|
||||
|
||||
// Add a Fengari coroutine (thread) to the scheduler
|
||||
scheduleFengariCoroutine(luaThread, luaState) {
|
||||
// luaThread: the coroutine (thread) object from Fengari
|
||||
// luaState: the Lua state (L) from Fengari
|
||||
console.debug("Scheduling Fengari coroutine");
|
||||
this._scheduled.push({ fengari: true, thread: luaThread, state: luaState, wakeTime: 0 });
|
||||
}
|
||||
|
||||
// Main update loop, call this every frame with dt (delta time in seconds)
|
||||
step(dt) {
|
||||
const now = Date.now();
|
||||
// Wake up any waiting scripts whose time has come
|
||||
for (let i = this._waiting.length - 1; i >= 0; i--) {
|
||||
const item = this._waiting[i];
|
||||
if (now >= item.wakeTime) {
|
||||
this._scheduled.push(item);
|
||||
this._waiting.splice(i, 1);
|
||||
console.log("Woke up routine",i,"from waiting.");
|
||||
}
|
||||
}
|
||||
// Run scheduled scripts
|
||||
for (let i = this._scheduled.length - 1; i >= 0; i--) {
|
||||
const item = this._scheduled[i];
|
||||
if (item.fengari) {
|
||||
// Fengari coroutine
|
||||
const L = item.state;
|
||||
const thread = item.thread;
|
||||
// Resume the coroutine
|
||||
const status = lua_resume(thread, L, 0);
|
||||
if (status === LUA_OK) {
|
||||
// Coroutine finished
|
||||
this._scheduled.splice(i, 1);
|
||||
console.log("Woke up routine",i,"from fengari, finished.");
|
||||
} else if (status === LUA_YIELD) {
|
||||
// Check for yield value (wait)
|
||||
// You must implement a way for Lua to yield with a wait time, e.g. coroutine.yield({wait=seconds})
|
||||
// For now, we assume the top of the stack is a table with a 'wait' field
|
||||
const luaTable = lua.lua_tojsstring(L, -1);
|
||||
let waitSeconds = 0;
|
||||
try {
|
||||
// Try to parse the yielded value as JSON (if you yield a JSON string)
|
||||
const val = JSON.parse(luaTable);
|
||||
if (val && val.wait) waitSeconds = val.wait;
|
||||
} catch (e) { }
|
||||
if (waitSeconds > 0) {
|
||||
this._waiting.push({ ...item, wakeTime: now + waitSeconds * 1000 });
|
||||
this._scheduled.splice(i, 1);
|
||||
}
|
||||
// Otherwise, just continue next frame
|
||||
} else {
|
||||
// Error or unknown status
|
||||
this._scheduled.splice(i, 1);
|
||||
}
|
||||
} else {
|
||||
// JavaScript generator
|
||||
const { value, done } = item.gen.next();
|
||||
if (done) {
|
||||
this._scheduled.splice(i, 1);
|
||||
console.log("Woke up routine",i,"from JS generator, finished.");
|
||||
} else if (value && value.wait) {
|
||||
// Script yielded with {wait: seconds}
|
||||
const ms = value.wait * 1000;
|
||||
this._waiting.push({ gen: item.gen, wakeTime: now + ms });
|
||||
this._scheduled.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Utility for scripts to yield for a certain time (in seconds)
|
||||
static wait(seconds) {
|
||||
return { wait: seconds };
|
||||
}
|
||||
}
|
||||
|
||||
// Example usage:
|
||||
// function* myScript() {
|
||||
// console.log("Script start");
|
||||
// yield ScriptSchedulerService.wait(1);
|
||||
// console.log("1 second later");
|
||||
// yield ScriptSchedulerService.wait(2);
|
||||
// console.log("2 more seconds later");
|
||||
// }
|
||||
// const scheduler = new ScriptSchedulerService();
|
||||
// scheduler.schedule(myScript);
|
||||
// setInterval(() => scheduler.step(1/60), 1000/60);
|
||||
Reference in New Issue
Block a user