From 2b426eefeb727fedc88c545259e6e7dd44ee30e1 Mon Sep 17 00:00:00 2001 From: jyelon Date: Tue, 27 Feb 2024 17:01:26 -0500 Subject: [PATCH] Refactor code in world-core that spawns threads --- luprex/cpp/core/lpxserver.cpp | 1 + luprex/cpp/core/luaconsole.cpp | 3 +- luprex/cpp/core/luastack.hpp | 2 + luprex/cpp/core/world-core.cpp | 205 +++++++++++++++------------------ luprex/cpp/core/world.hpp | 6 +- luprex/lua/login.lua | 6 + 6 files changed, 112 insertions(+), 111 deletions(-) diff --git a/luprex/cpp/core/lpxserver.cpp b/luprex/cpp/core/lpxserver.cpp index ff2b6906..c2875ea6 100644 --- a/luprex/cpp/core/lpxserver.cpp +++ b/luprex/cpp/core/lpxserver.cpp @@ -87,6 +87,7 @@ public: } void do_choose_command(const StringVec &cmd) { + stdostream() << "Chose menu item: " << cmd[1] << std::endl; eng::string action = gui_.get_action(sv::to_int64(cmd[1])); if (action == "") { stdostream() << "Invalid menu item #" << std::endl; diff --git a/luprex/cpp/core/luaconsole.cpp b/luprex/cpp/core/luaconsole.cpp index 2c200e4f..3e6d6f92 100644 --- a/luprex/cpp/core/luaconsole.cpp +++ b/luprex/cpp/core/luaconsole.cpp @@ -54,9 +54,10 @@ void LuaConsole::simplify(const StringVec &words) { return; } else if (sv::valid_int64(words[0])) { if (words.size() == 1) { + eng::string num = words[0]; words_.clear(); words_.push_back("choose"); - words_.push_back(words[0]); + words_.push_back(num); } else { synerr("/choose command takes no arguments"); } diff --git a/luprex/cpp/core/luastack.hpp b/luprex/cpp/core/luastack.hpp index d2368bfa..89fe48b9 100644 --- a/luprex/cpp/core/luastack.hpp +++ b/luprex/cpp/core/luastack.hpp @@ -664,6 +664,8 @@ public: template LuaExtStack(const LuaCoreStack &LS0, SS & ... stackslots) : LuaCoreStack(LS0.state(), stackslots...) {} + int oldtop() const { return oldtop_; } + ~LuaExtStack() { if (!lua_isthrowing(L_)) { lua_settop(L_, oldtop_); diff --git a/luprex/cpp/core/world-core.cpp b/luprex/cpp/core/world-core.cpp index e3c99697..1a667ec0 100644 --- a/luprex/cpp/core/world-core.cpp +++ b/luprex/cpp/core/world-core.cpp @@ -594,6 +594,90 @@ void World::invoke(const Invocation &inv) { } } +bool World::spawn(LuaCoreStack &LS0, int64_t actor_id, int64_t place_id, LuaSlot func, + bool passactorplace, int nargs, bool print) { + lua_State *L = LS0.state(); + LuaVar actor, place, mt, index, tangibles, thread, threads, thinfo; + LuaExtStack LS(L, actor, place, mt, index, tangibles, thread, threads, thinfo); + + // Get the actor and place, C++ version. Make sure both exist. + Tangible *tactor = tangible_get(actor_id); + Tangible *tplace = tangible_get(place_id); + if ((tactor == nullptr) || (tplace == nullptr)) { + return false; + } + + // Get the actor and place, lua version. Make sure both exist. + LS.rawget(tangibles, LuaRegistry, "tangibles"); + LS.rawget(actor, tangibles, actor_id); + LS.rawget(place, tangibles, place_id); + if (!LS.istable(actor) || !LS.istable(place)) { + return false; + } + + // Get an ID for the thread. + // We currently always use the actor pool. We may extend + // this to allow the use of the place pool. + int64_t tid = tactor->id_player_pool_.get_one(); + + // Get the place's metatable. + LS.getmetatable(mt, place); + if (!LS.istable(mt)) { + return false; + } + + // If the function is a string, look it up in the place's class. + if (LS.isstring(func)) { + LS.rawget(index, mt, "__index"); + if (!LS.istable(index)) { + return false; + } + LS.rawget(func, index, func); + } + + // Make sure the function is a function. + if (!LS.isfunction(func)) { + return false; + } + + // Create a new thread. Push function, and maybe actor and place. + lua_State *CO = LS.newthread(thread); + lua_pushvalue(L, func.index()); + if (passactorplace) { + lua_pushvalue(L, actor.index()); + lua_pushvalue(L, place.index()); + } + lua_xmove(L, CO, passactorplace ? 3:1); + + // Push any extra arguments. Extra arguments were pushed onto + // the lua stack before calling spawn, so they are located at oldtop. + if (nargs > 0) { + int base = LS.oldtop() - nargs + 1; + for (int i = 0; i < nargs; i++) { + lua_pushvalue(L, base + i); + } + lua_xmove(L, CO, nargs); + } + + // Create the thread info table. + LS.newtable(thinfo); + LS.rawset(thinfo, "thread", thread); + LS.rawset(thinfo, "actorid", actor_id); + LS.rawset(thinfo, "isnew", true); + LS.rawset(thinfo, "useppool", true); + LS.rawset(thinfo, "print", print); + + // Store the thread into place's thread table. + LS.rawget(threads, mt, "threads"); + if (!LS.istable(threads)) { + return false; + } + LS.rawset(threads, tid, thinfo); + + schedule(0, tid, place_id); + return true; +} + void World::invoke_flush_prints(int64_t actor_id, int64_t place_id, std::string_view datapack) { assert(stack_is_clear()); // Check argument sanity. @@ -614,22 +698,10 @@ void World::invoke_flush_prints(int64_t actor_id, int64_t place_id, std::string_ void World::invoke_lua(int64_t actor_id, int64_t place_id, std::string_view datapack) { assert(stack_is_clear()); - - // Make sure that actor and place exist and are not stubs. - Tangible *tactor = tangible_get(actor_id); - Tangible *tplace = tangible_get(place_id); - if ((tactor == nullptr) || (tplace == nullptr)) { - return; - } - - // Get a thread ID for the new thread. - int64_t tid = tplace->id_player_pool_.get_one(); - - // Set up for lua manipulation. { lua_State *L = state(); - LuaVar func, tangibles, place, mt, thread, thinfo, threads; - LuaExtStack LS(L, func, tangibles, place, mt, thread, thinfo, threads); + LuaVar func; + LuaExtStack LS(L, func); // create the compiled closure. int status = luaL_loadbuffer(L, datapack.data(), datapack.size(), "=invoke"); @@ -641,41 +713,10 @@ void World::invoke_lua(int64_t actor_id, int64_t place_id, std::string_view data return; } - // Get the place. - LS.rawget(tangibles, LuaRegistry, "tangibles"); - LS.rawget(place, tangibles, place_id); - if (!LS.istable(place)) { - return; - } - - // Get the place's metatable. - LS.getmetatable(mt, place); - if (!LS.istable(mt)) { - return; - } - - // Create a new thread, set up function and parameters. - lua_State *CO = LS.newthread(thread); - lua_pushvalue(L, func.index()); - lua_xmove(L, CO, 1); - - // Create the thread info table. - LS.newtable(thinfo); - LS.rawset(thinfo, "thread", thread); - LS.rawset(thinfo, "actorid", actor_id); - LS.rawset(thinfo, "isnew", true); - LS.rawset(thinfo, "useppool", true); - LS.rawset(thinfo, "print", true); - - // Store the thread into place's thread table. - LS.rawget(threads, mt, "threads"); - if (!LS.istable(threads)) { - return; - } - LS.rawset(threads, tid, thinfo); + // Spawn the thread and run it. + int nargs = 0; + spawn(LS, actor_id, place_id, func, false, nargs, true); } - - schedule(0, tid, place_id); run_scheduled_threads(); assert(stack_is_clear()); } @@ -694,77 +735,23 @@ void World::invoke_choose(int64_t actor_id, int64_t place_id, std::string_view d if (!sv::has_prefix(datapack, "cb_")) { return; } - - // Get the actor and place. Make sure both exist. - Tangible *tactor = tangible_get(actor_id); - Tangible *tplace = tangible_get(place_id); - if ((tactor == nullptr) || (tplace == nullptr)) { - return; - } - - // Get an ID for the thread. We always use the player - // pool in this case. - int64_t tid = tactor->id_player_pool_.get_one(); - { - // Set up for Lua manipulation. lua_State *L = state(); - LuaVar actor, place, func, tangibles, mt, index, thread, threads, thinfo, message, invdata; - LuaExtStack LS(L, actor, place, func, tangibles, mt, index, thread, threads, thinfo, message, invdata); + LuaVar func, invdata; + LuaExtStack LS(L, func, invdata); - // Get the actor and place. - LS.rawget(tangibles, LuaRegistry, "tangibles"); - LS.rawget(actor, tangibles, actor_id); - LS.rawget(place, tangibles, place_id); - if (!LS.istable(actor) || !LS.istable(place)) { - return; - } - // Get the action closure. - LS.getmetatable(mt, place); - if (!LS.istable(mt)) { - return; - } - LS.rawget(index, mt, "__index"); - if (!LS.istable(index)) { - return; - } - LS.rawget(func, index, datapack); - if (!LS.isfunction(func)) { - return; - } + LS.set(func, datapack); - // TODO: maybe add the ability to pass data in as a table? + // We're planning to add the ability to pass data in as a table. // For now the table is always empty. LS.newtable(invdata); - // Create a new thread, set up function and parameters. - lua_State *CO = LS.newthread(thread); - lua_pushvalue(L, func.index()); - lua_pushvalue(L, actor.index()); - lua_pushvalue(L, place.index()); + // Spawn the thread and run it. + int nargs = 1; lua_pushvalue(L, invdata.index()); - lua_xmove(L, CO, 4); - - // Create the thread info table. - LS.newtable(thinfo); - LS.rawset(thinfo, "thread", thread); - LS.rawset(thinfo, "actorid", actor_id); - LS.rawset(thinfo, "isnew", true); - LS.rawset(thinfo, "useppool", true); - LS.rawset(thinfo, "print", false); - - // Store the thread into place's thread table. - LS.rawget(threads, mt, "threads"); - if (!LS.istable(threads)) { - return; - } - LS.rawset(threads, tid, thinfo); + spawn(LS, actor_id, place_id, func, true, nargs, false); } - - // Push the thread's ID into the runnable thread queue, - // then run the thread queue. - schedule(0, tid, place_id); run_scheduled_threads(); assert(stack_is_clear()); } diff --git a/luprex/cpp/core/world.hpp b/luprex/cpp/core/world.hpp index 3f5d8030..b3fc1c26 100644 --- a/luprex/cpp/core/world.hpp +++ b/luprex/cpp/core/world.hpp @@ -372,7 +372,11 @@ private: // Invoke the lua_source operation. // void invoke_lua_source(int64_t actor_id, int64_t place_id, std::string_view datapack); - + + // Low level spawn thread function. + // + bool spawn(LuaCoreStack &LS0, int64_t actor_id, int64_t place_id, LuaSlot func, bool passactorplace, int nargs, bool print); + public: //////////////////////////////////////////////////////////////////////////// // diff --git a/luprex/lua/login.lua b/luprex/lua/login.lua index f94c21a0..89afce5f 100644 --- a/luprex/lua/login.lua +++ b/luprex/lua/login.lua @@ -25,6 +25,12 @@ function login.cb_becomeplayer(actor, place, dialog) tangible.animate(actor,{action="warp",plane="main",x=0,y=0,z=0}) end +function login.cb_p123(actor, place, dialog) + print("CB_P123 actor=", actor, " place=", place, " dialog=", dialog); + print(1); + print(2); + print(3); + end function bechar() local a = tangible.actor()