diff --git a/luprex/cpp/core/lpxclient.cpp b/luprex/cpp/core/lpxclient.cpp index e0b7744d..d0f47445 100644 --- a/luprex/cpp/core/lpxclient.cpp +++ b/luprex/cpp/core/lpxclient.cpp @@ -34,7 +34,7 @@ public: // the invariant that there's always an actor. When the first difference // transmission arrives, this actor may be deleted, or it may just be // ignored, at the server's discretion. - actor_id_ = world_->create_login_actor(); + actor_id_ = world_->create_login_actor(false); // Clear the unack command queue. unack_.clear(); @@ -57,7 +57,7 @@ public: channel_.reset(); // Create the standalone actor. - actor_id_ = world_->create_login_actor(); + actor_id_ = world_->create_login_actor(true); // TODO: initialize the standalone actor. diff --git a/luprex/cpp/core/lpxserver.cpp b/luprex/cpp/core/lpxserver.cpp index c2875ea6..fa19f5cd 100644 --- a/luprex/cpp/core/lpxserver.cpp +++ b/luprex/cpp/core/lpxserver.cpp @@ -43,7 +43,7 @@ public: master_->update_source(srcpk); // Create an actor for administrative commands. - admin_id_ = master_->create_login_actor(); + admin_id_ = master_->create_login_actor(true); // TODO: initialize the admin actor. @@ -208,7 +208,7 @@ public: if (chan == nullptr) break; if (chan->port() == 8085) { Client *client = new Client; - client->actor_id_ = master_->create_login_actor(); + client->actor_id_ = master_->create_login_actor(true); // TODO: initialize the login actor on the master. client->channel_ = std::move(chan); client->async_diff_ = true; @@ -216,7 +216,7 @@ public: client->sync_.reset(new World(WORLD_TYPE_PREDICTIVE)); // This login actor is never used, it is just to preserve the invariant that // the client model and the server synchronous model are identical. - client->sync_->create_login_actor(); + client->sync_->create_login_actor(false); clients_.emplace_back(client); stdostream() << "New client: actor id=" << client->actor_id_ << std::endl; } else if (chan->port() == 8080) { diff --git a/luprex/cpp/core/world-core.cpp b/luprex/cpp/core/world-core.cpp index 1a667ec0..50960a71 100644 --- a/luprex/cpp/core/world-core.cpp +++ b/luprex/cpp/core/world-core.cpp @@ -246,18 +246,26 @@ World::Redirects World::fetch_redirects() { return result; } -int64_t World::create_login_actor() { +int64_t World::create_login_actor(bool initialize) { assert(stack_is_clear()); int64_t id = id_global_pool_.get_one(); - LuaVar database, classtab, mt; - LuaExtStack LS(state(), database, classtab, mt); - Tangible *tan = tangible_make(LS, database, id); - LS.makeclass(classtab, "login"); - LS.getmetatable(mt, database); - LS.rawset(mt, "__index", classtab); - tan->configure_id_pool_for_actor(); - tan->print_buffer_.clear(); - return tan->id(); + { + LuaVar database, classtab, mt, func; + LuaExtStack LS(state(), database, classtab, mt, func); + Tangible *tan = tangible_make(LS, database, id); + LS.makeclass(classtab, "login"); + LS.getmetatable(mt, database); + LS.rawset(mt, "__index", classtab); + tan->configure_id_pool_for_actor(); + tan->print_buffer_.clear(); + + if (initialize) { + LS.rawget(func, classtab, "initialize"); + spawn(LS, id, id, func, true, 0, false); + } + } + run_scheduled_threads(); + return id; } eng::string World::probe_lua(int64_t actor_id, const eng::string &lua) { @@ -794,17 +802,6 @@ void push_simple_dynamic(lua_State *L, StreamBuffer *sb) { void World::invoke_engio(int64_t actor_id, int64_t place_id, std::string_view datapack) { assert(stack_is_clear()); - // 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(); - // Use a streambuffer to parse the datapack. StreamBuffer datasb(datapack); @@ -820,37 +817,19 @@ void World::invoke_engio(int64_t actor_id, int64_t place_id, std::string_view da } { - // Set up for Lua manipulation. lua_State *L = state(); - LuaVar actor, place, func, mt, tangibles, playercb, thread, threads, thinfo, message; - LuaExtStack LS(L, actor, place, func, mt, tangibles, playercb, thread, threads, thinfo, message); + LuaVar engio, func; + LuaExtStack LS(L, engio, func); - // 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 closure (playerinvoke.funcname). - eng::string err = LS.getclass(playercb, "engio"); - if ((!err.empty()) || (!LS.istable(playercb))) { - return; - } - LS.rawget(func, playercb, funcname); - if (!LS.isfunction(func)) { + // Get the closure (engio.funcname). + eng::string err = LS.getclass(engio, "engio"); + if ((!err.empty()) || (!LS.istable(engio))) { return; } + LS.rawget(func, engio, funcname); - // Create a new thread, push func, actor, place. - int nargs = 3; - lua_State *CO = LS.newthread(thread); - lua_pushvalue(L, func.index()); - lua_pushvalue(L, actor.index()); - lua_pushvalue(L, place.index()); - - // Push any additional args from the datapack. + // Spawn a thread, pushing extra arguments from the datapack. + int nargs = 0; try { while (!datasb.empty()) { push_simple_dynamic(L, &datasb); @@ -859,33 +838,8 @@ void World::invoke_engio(int64_t actor_id, int64_t place_id, std::string_view da } catch (const StreamException &exc) { return; } - - // Transfer all arguments to the new thread. - 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", false); - - // Store the thread into place's thread table. - LS.getmetatable(mt, place); - if (!LS.istable(mt)) { - return; - } - 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 b3fc1c26..b0dc99a2 100644 --- a/luprex/cpp/core/world.hpp +++ b/luprex/cpp/core/world.hpp @@ -184,7 +184,10 @@ public: // This is used to create a temporary actor which is used during // the login process. // - int64_t create_login_actor(); + // If initialize is true, then the function 'login.initialize' + // will be executed. + // + int64_t create_login_actor(bool initialize); // Fetch all redirects and clear the redirects table. // diff --git a/luprex/lua/login.lua b/luprex/lua/login.lua index 89afce5f..3917627c 100644 --- a/luprex/lua/login.lua +++ b/luprex/lua/login.lua @@ -1,5 +1,9 @@ makeclass('login') +function login.initialize(actor, place) + dprint("login.initialize:", actor) + end + function login.interface(actor, place) gui.menu_item("cb_becomeplayer", "Become a Player") gui.menu_item("cb_p123", "Print 1, 2, 3")