feat(lua): added delay global + fixed issues with waiting

This commit is contained in:
maelstrom 2025-05-07 01:46:19 +02:00
parent 13cad8e01a
commit 626be7107f
3 changed files with 43 additions and 24 deletions

View file

@ -8,11 +8,11 @@
#include "objects/datamodel.h" #include "objects/datamodel.h"
#include "datatypes/ref.h" #include "datatypes/ref.h"
#include "lua.h" #include "lua.h"
#include <luajit-2.1/lauxlib.h> #include <algorithm>
#include <luajit-2.1/lua.h>
#include <memory> #include <memory>
int script_wait(lua_State*); int script_wait(lua_State*);
int script_delay(lua_State*);
Script::Script(): Instance(&TYPE) { Script::Script(): Instance(&TYPE) {
source = "print \"Hello, world!\"\nwait(1)print \"Wait success! :D\""; source = "print \"Hello, world!\"\nwait(1)print \"Wait success! :D\"";
@ -33,18 +33,19 @@ void Script::Run() {
// Initialize script globals // Initialize script globals
lua_getglobal(Lt, "_G"); lua_getglobal(Lt, "_G");
lua_pushstring(Lt, "game");
Data::InstanceRef(dataModel().value()).PushLuaValue(Lt); Data::InstanceRef(dataModel().value()).PushLuaValue(Lt);
lua_rawset(Lt, -3); lua_setfield(Lt, -2, "game");
lua_pushstring(Lt, "workspace");
Data::InstanceRef(dataModel().value()->GetService<Workspace>()).PushLuaValue(Lt); Data::InstanceRef(dataModel().value()->GetService<Workspace>()).PushLuaValue(Lt);
lua_rawset(Lt, -3); lua_setfield(Lt, -2, "workspace");
lua_pushstring(Lt, "wait");
lua_pushlightuserdata(Lt, scriptContext.get()); lua_pushlightuserdata(Lt, scriptContext.get());
lua_pushcclosure(Lt, script_wait, 1); lua_pushcclosure(Lt, script_wait, 1);
lua_rawset(Lt, -3); lua_setfield(Lt, -2, "wait");
lua_pushlightuserdata(Lt, scriptContext.get());
lua_pushcclosure(Lt, script_delay, 1);
lua_setfield(Lt, -2, "delay");
lua_pop(Lt, 1); // _G lua_pop(Lt, 1); // _G
@ -66,10 +67,27 @@ void Script::Stop() {
int script_wait(lua_State* L) { int script_wait(lua_State* L) {
ScriptContext* scriptContext = (ScriptContext*)lua_touserdata(L, lua_upvalueindex(1)); ScriptContext* scriptContext = (ScriptContext*)lua_touserdata(L, lua_upvalueindex(1));
float secs = luaL_checknumber(L, 1); float secs = lua_gettop(L) == 0 ? 0.03 : std::max(luaL_checknumber(L, 1), 0.03);
scriptContext->PushThreadSleep(L, secs); scriptContext->PushThreadSleep(L, secs);
lua_pop(L, 1); // pop secs
// Yield // Yield
return lua_yield(L, 0); return lua_yield(L, 0);
}
int script_delay(lua_State* L) {
ScriptContext* scriptContext = (ScriptContext*)lua_touserdata(L, lua_upvalueindex(1));
float secs = std::max(luaL_checknumber(L, 1), 0.03);
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_State* Lt = lua_newthread(L); // Create a new thread
lua_pop(L, 1); // pop the newly created thread so that xmove moves func instead of it into itself
lua_xmove(L, Lt, 1); // move func
lua_pop(L, 1); // pop secs
// Schedule next run
scriptContext->PushThreadSleep(Lt, secs);
return 0;
} }

View file

@ -7,7 +7,6 @@
#include <cstdint> #include <cstdint>
#include <ctime> #include <ctime>
#include <chrono> #include <chrono>
#include <luajit-2.1/lua.h>
#include "lua.h" #include "lua.h"
static int g_print(lua_State*); static int g_print(lua_State*);
@ -66,13 +65,9 @@ void ScriptContext::InitService() {
lua_pop(state, 1); // _G lua_pop(state, 1); // _G
lua_getregistry(state); lua_pushlightuserdata(state, &sleepingThreads);
lua_pushstring(state, "__sleepingThreads");
lua_newtable(state); lua_newtable(state);
lua_rawset(state, -3); lua_settable(state, LUA_REGISTRYINDEX);
lua_pop(state, -1); // registry
} }
void ScriptContext::PushThreadSleep(lua_State* thread, float delay) { void ScriptContext::PushThreadSleep(lua_State* thread, float delay) {
@ -88,16 +83,15 @@ void ScriptContext::PushThreadSleep(lua_State* thread, float delay) {
// Add to registry so it doesn't get GC'd // Add to registry so it doesn't get GC'd
// https://stackoverflow.com/a/17138663/16255372 // https://stackoverflow.com/a/17138663/16255372
lua_getregistry(state); // registry lua_pushlightuserdata(state, &sleepingThreads);
lua_pushstring(state, "__sleepingThreads"); lua_gettable(state, LUA_REGISTRYINDEX);
lua_rawget(state, -2); // table
lua_pushthread(thread); // key lua_pushthread(thread); // key
lua_xmove(thread, state, 1); lua_xmove(thread, state, 1);
lua_pushboolean(state, true); // value lua_pushboolean(state, true); // value
lua_rawset(state, -3); // set lua_rawset(state, -3); // set
lua_pop(state, 2); // pop table and registry lua_pop(state, 1); // pop sleepingThreads
} }
void ScriptContext::RunSleepingThreads() { void ScriptContext::RunSleepingThreads() {
@ -109,20 +103,26 @@ void ScriptContext::RunSleepingThreads() {
// Time args // Time args
lua_pushnumber(sleep.thread, float(tu_clock_micros() - sleep.timeYieldedWhen) / 1'000'000); lua_pushnumber(sleep.thread, float(tu_clock_micros() - sleep.timeYieldedWhen) / 1'000'000);
lua_pushnumber(sleep.thread, float(tu_clock_micros()) / 1'000'000); lua_pushnumber(sleep.thread, float(tu_clock_micros()) / 1'000'000);
lua_resume(sleep.thread, 2); int status = lua_resume(sleep.thread, 2);
if (status > LUA_YIELD) {
Logger::error(lua_tostring(sleep.thread, -1));
lua_pop(sleep.thread, 1); // Pop return value
}
// Remove thread // Remove thread
deleted = true;
sleepingThreads.erase(sleepingThreads.begin() + i); sleepingThreads.erase(sleepingThreads.begin() + i);
// Erase from registry // Erase from registry
lua_getregistry(state); // registry lua_pushlightuserdata(state, &sleepingThreads);
lua_pushstring(state, "__sleepingThreads"); lua_gettable(state, LUA_REGISTRYINDEX);
lua_rawget(state, -2); // table
lua_pushthread(sleep.thread); // key lua_pushthread(sleep.thread); // key
lua_xmove(sleep.thread, state, 1); lua_xmove(sleep.thread, state, 1);
lua_pushnil(state); lua_pushnil(state);
lua_rawset(state, -3); // set lua_rawset(state, -3); // set
lua_pop(state, 1); // sleepingThreads
} }
if (!deleted) if (!deleted)

View file

@ -58,6 +58,7 @@ ScriptDocument::ScriptDocument(std::shared_ptr<Script> script, QWidget* parent):
scintilla->setMarginsBackgroundColor(palette().window().color()); scintilla->setMarginsBackgroundColor(palette().window().color());
scintilla->setCaretForegroundColor(palette().text().color()); scintilla->setCaretForegroundColor(palette().text().color());
scintilla->setFont(font); scintilla->setFont(font);
scintilla->setTabWidth(4);
scintilla->setText(QString::fromStdString(script->source)); scintilla->setText(QString::fromStdString(script->source));