diff --git a/luprex/cpp/core/invocation.cpp b/luprex/cpp/core/invocation.cpp index 20d753b5..4a480372 100644 --- a/luprex/cpp/core/invocation.cpp +++ b/luprex/cpp/core/invocation.cpp @@ -31,6 +31,8 @@ eng::string Invocation::debug_string() const { oss << "inv["; switch (kind_) { case KIND_INVALID: oss << "invalid"; break; + case KIND_ENGIO: oss << "engio"; break; + case KIND_LUA_CALL: oss << "lua_call"; break; case KIND_LUA: oss << "lua"; break; case KIND_FLUSH_PRINTS: oss << "flush_prints"; break; case KIND_TICK: oss << "tick"; break; diff --git a/luprex/cpp/core/invocation.hpp b/luprex/cpp/core/invocation.hpp index 91b7cdd7..d7a3d1e9 100644 --- a/luprex/cpp/core/invocation.hpp +++ b/luprex/cpp/core/invocation.hpp @@ -51,6 +51,7 @@ public: enum Kind { KIND_INVALID, KIND_ENGIO, + KIND_LUA_CALL, KIND_LUA, KIND_FLUSH_PRINTS, KIND_TICK, diff --git a/luprex/cpp/core/world-core.cpp b/luprex/cpp/core/world-core.cpp index 3a3e5705..638ecb32 100644 --- a/luprex/cpp/core/world-core.cpp +++ b/luprex/cpp/core/world-core.cpp @@ -554,6 +554,9 @@ void World::invoke(const Invocation &inv) { case Invocation::KIND_ENGIO: invoke_engio(inv.actor(), inv.place(), inv.datapack()); break; + case Invocation::KIND_LUA_CALL: + invoke_lua_call(inv.actor(), inv.place(), inv.datapack()); + break; case Invocation::KIND_LUA: invoke_lua(inv.actor(), inv.place(), inv.datapack()); break; @@ -784,6 +787,57 @@ void World::invoke_engio(int64_t actor_id, int64_t place_id, std::string_view da assert(stack_is_clear()); } +void World::invoke_lua_call(int64_t actor_id, int64_t place_id, std::string_view datapack) { + assert(stack_is_clear()); + + // Use a streambuffer to parse the datapack. + StreamBuffer datasb(datapack); + + // Extract the class and function name from the datapack. + eng::string classname; + eng::string funcname; + try { + classname = datasb.read_string_limit(100); + funcname = datasb.read_string_limit(100); + } catch (const StreamException &ex) { + return; + } + if ((!sv::is_lua_id(classname)) || (!sv::is_lua_id(funcname))) { + return; + } + // TODO: Add check for permit_invoke(classname, funcname) + + { + lua_State *L = state(); + LuaVar lclass, lfunc; + LuaExtStack LS(L, lclass, lfunc); + + // Get the class table and closure + eng::string err = LS.getclass(lclass, classname); + if ((!err.empty()) || (!LS.istable(lclass))) { + return; + } + LS.rawget(lfunc, lclass, funcname); + if (!LS.isfunction(lfunc)) { + return; + } + + // Spawn a thread, pushing extra arguments from the datapack. + int nargs = 0; + try { + while (!datasb.empty()) { + push_simple_dynamic(L, &datasb); + nargs++; + } + } catch (const StreamException &exc) { + return; + } + spawn(LS, actor_id, place_id, lfunc, true, nargs, false); + } + run_scheduled_threads(); + assert(stack_is_clear()); +} + void World::invoke_tick(int64_t actor_id, int64_t place_id, std::string_view datapack) { if (!is_authoritative()) { return; diff --git a/luprex/cpp/core/world.hpp b/luprex/cpp/core/world.hpp index b24a9b19..30bc4d92 100644 --- a/luprex/cpp/core/world.hpp +++ b/luprex/cpp/core/world.hpp @@ -394,6 +394,10 @@ private: // void invoke_engio(int64_t actor_id, int64_t place_id, std::string_view datapack); + // Invoke the lua_call operation. + // + void invoke_lua_call(int64_t actor_id, int64_t place_id, std::string_view datapack); + // Invoke a lua string. // void invoke_lua(int64_t actor_id, int64_t place_id, std::string_view datapack);