From aa7de03c5789f08a08dd86b68a3791c3cdc46381 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Tue, 30 Mar 2021 18:35:08 -0400 Subject: [PATCH] Implement the core of the login system --- luprex/core/cpp/textgame.cpp | 24 ++++++++-- luprex/core/cpp/textgame.hpp | 3 ++ luprex/core/cpp/world.cpp | 93 ++++++++++++++++++++++++++---------- luprex/core/cpp/world.hpp | 25 +++++++++- 4 files changed, 113 insertions(+), 32 deletions(-) diff --git a/luprex/core/cpp/textgame.cpp b/luprex/core/cpp/textgame.cpp index c6c1cf08..f4d81513 100644 --- a/luprex/core/cpp/textgame.cpp +++ b/luprex/core/cpp/textgame.cpp @@ -81,7 +81,7 @@ void TextGame::do_view_command(const StringVec &cmd) { std::cerr << "v command (view) takes no arguments" << std::endl; return; } - for (int64_t id : world_->get_near(1, 100, true)) { + for (int64_t id : world_->get_near(actor_id_, 100, true)) { const Tangible *tan = world_->tangible_get(id); const AnimStep &aqback = tan->anim_queue_.back(); std::cerr << id << ": " << aqback.graphic() << " " << aqback.plane() << " " << aqback.xyz() << std::endl; @@ -91,15 +91,15 @@ void TextGame::do_view_command(const StringVec &cmd) { void TextGame::do_menu_command(const StringVec &cmd) { int64_t id; if (cmd.size() == 1) { - id = 1; + id = actor_id_; } else if (cmd.size() == 2) { id = util::strtoint(cmd[1], -1); } else { - std::cerr << "m command (menu) expects a tangible ID or defaults to 1" << std::endl; + std::cerr << "m command (menu) expects a tangible ID or defaults to actor_id" << std::endl; return; } gui_place_ = id; - world_->update_gui(1, id, &gui_); + world_->update_gui(actor_id_, id, &gui_); int index = 0; for (const GuiElt &elt : gui_.elts()) { std::cerr << index << " " << elt.label() << std::endl; @@ -125,7 +125,7 @@ void TextGame::do_choose_command(const StringVec &cmd) { GuiResult dummyresult; dummyresult["flavor"] = "chocolate"; dummyresult["color"] = "blue"; - world_->invoke_plan(1, gui_place_, action, dummyresult); + world_->invoke_plan(actor_id_, gui_place_, action, dummyresult); } void TextGame::do_snapshot_command(const StringVec &cmd) { @@ -164,12 +164,26 @@ void TextGame::do_command(const StringVec &words) { } } +void TextGame::check_redirects() { + World::Redirects redir = world_->fetch_redirects(); + for (const auto &p : redir) { + if (p.first == actor_id_) { + actor_id_ = p.second; + std::cerr << "Login actor ID: " << actor_id_ << std::endl; + gui_.clear(); + } + } +} + void TextGame::run() { world_.reset(new World); world_->init_standalone(); + actor_id_ = world_->create_login_actor(); + std::cerr << "Login actor ID: " << actor_id_ << std::endl; console_.clear(); while (true) { + check_redirects(); console_.add_stdin(); int action = console_.action(); if (action == LuaConsole::DO_LUA) { diff --git a/luprex/core/cpp/textgame.hpp b/luprex/core/cpp/textgame.hpp index bca24258..7cd2baa3 100644 --- a/luprex/core/cpp/textgame.hpp +++ b/luprex/core/cpp/textgame.hpp @@ -13,6 +13,7 @@ private: LuaConsole console_; Gui gui_; int64_t gui_place_; + int64_t actor_id_; void do_view_command(const StringVec &cmd); void do_menu_command(const StringVec &cmd); @@ -23,6 +24,8 @@ private: void do_lua(const std::string &exp); void do_command(const StringVec &exp); + + void check_redirects(); public: void run(); }; diff --git a/luprex/core/cpp/world.cpp b/luprex/core/cpp/world.cpp index d3cc182a..5039cb50 100644 --- a/luprex/core/cpp/world.cpp +++ b/luprex/core/cpp/world.cpp @@ -72,29 +72,9 @@ void Tangible::deserialize(StreamBuffer *sb) { update_plane_item(); } -void Tangible::be_a_player() { - if (!id_player_pool_.fifo_enabled()) { - id_player_pool_.enable_fifo(); - - AnimStep asinit; - asinit.set_graphic("player"); - anim_queue_.add(world_->id_global_pool_.get_one(), asinit); - anim_queue_.keep_only(1); - update_plane_item(); - - LuaVar classtab, mt, place, tangibles; - LuaStack LS(world_->state(), classtab, mt, place, tangibles); - - LS.makeclass(classtab, "player"); - LS.rawget(tangibles, LuaRegistry, "tangibles"); - LS.rawget(place, tangibles, id()); - LS.getmetatable(mt, place); - LS.rawset(mt, "__index", classtab); - LS.result(); - } -} - void World::init_standalone() { + assert(stack_is_clear()); + // Load the lua source from disk then rebuild the environment. source_db_.update(); source_db_.rebuild(); @@ -102,9 +82,7 @@ void World::init_standalone() { // Run unit tests. source_db_.run_unittests(); - // Create the player tangible. - Tangible *player = tangible_make(state(), 1, false); - player->be_a_player(); + assert(stack_is_clear()); } Tangible *World::tangible_get(int64_t id) { @@ -207,7 +185,50 @@ Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) { return t.get(); } +World::Redirects World::fetch_redirects() { + World::Redirects result = std::move(redirects_); + redirects_.clear(); + return std::move(result); +} + +// void Tangible::be_a_player() { +// if (!id_player_pool_.fifo_enabled()) { +// id_player_pool_.enable_fifo(); + +// AnimStep asinit; +// asinit.set_graphic("player"); +// anim_queue_.add(world_->id_global_pool_.get_one(), asinit); +// anim_queue_.keep_only(1); +// update_plane_item(); + +// LuaVar classtab, mt, place, tangibles; +// LuaStack LS(world_->state(), classtab, mt, place, tangibles); + +// LS.makeclass(classtab, "player"); +// LS.rawget(tangibles, LuaRegistry, "tangibles"); +// LS.rawget(place, tangibles, id()); +// LS.getmetatable(mt, place); +// LS.rawset(mt, "__index", classtab); +// LS.result(); +// } +// } + +int64_t World::create_login_actor() { + Tangible *tan = tangible_make(state(), 0, true); + LuaArg database; + LuaVar classtab, mt; + LuaStack LS(state(), database, classtab, mt); + LS.makeclass(classtab, "login"); + LS.getmetatable(mt, database); + LS.rawset(mt, "__index", classtab); + LS.result(); + tan->id_player_pool_.enable_fifo(); + assert(stack_is_clear()); + return tan->id(); +} + void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) { + assert(stack_is_clear()); gui->clear(); lua_State *L = state(); @@ -256,9 +277,12 @@ void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) { // And we're done. LS.result(); + assert(stack_is_clear()); } void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const GuiResult &gres) { + assert(stack_is_clear()); + // Validate that the action is legal. Gui validation_gui; update_gui(actor_id, place_id, &validation_gui); @@ -334,9 +358,11 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a // then run the thread queue. thread_sched_.add(0, tid, place_id); run_scheduled_threads(0); + assert(stack_is_clear()); } void World::run_scheduled_threads(int64_t clk) { + assert(stack_is_clear()); lua_State *L = state(); LuaVar tangibles, place, mt, threads, thread; LuaStack LS(L, tangibles, place, mt, threads, thread); @@ -391,9 +417,12 @@ void World::run_scheduled_threads(int64_t clk) { } } LS.result(); + assert(stack_is_clear()); } void World::serialize(StreamBuffer *sb) { + assert(stack_is_clear()); + assert(redirects_.empty()); int64_t wc0 = sb->write_count(); lua_snap_.serialize(sb); id_global_pool_.serialize(sb); @@ -405,9 +434,12 @@ void World::serialize(StreamBuffer *sb) { } int64_t wc1 = sb->write_count(); std::cerr << "World serialized to " << wc1-wc0 << " bytes." << std::endl; + assert(stack_is_clear()); } void World::deserialize(StreamBuffer *sb) { + assert(stack_is_clear()); + redirects_.clear(); lua_snap_.deserialize(sb); id_global_pool_.deserialize(sb); thread_sched_.deserialize(sb); @@ -435,6 +467,7 @@ void World::deserialize(StreamBuffer *sb) { ++iter; } } + assert(stack_is_clear()); } void World::snapshot() { @@ -561,6 +594,16 @@ LuaDefine(tangible_get, "c") { return LS.result(); } +LuaDefine(tangible_redirect, "c") { + LuaArg actor1, actor2; + LuaStack LS(L, actor1, actor2); + World *w = World::fetch_global_pointer(L); + Tangible *tan1 = w->tangible_get(L, actor1.index()); + Tangible *tan2 = w->tangible_get(L, actor2.index()); + w->redirects_[tan1->id()] = tan2->id(); + return LS.result(); +} + LuaDefine(world_wait, "f") { if ((lua_gettop(L) != 1) || (lua_type(L, -1) != LUA_TNUMBER)) { luaL_error(L, "Argument to wait must be a number."); diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index 1a37d383..b4735bd1 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -68,12 +68,13 @@ public: // int64_t id() { return plane_item_.id(); } - void be_a_player(); + // void be_a_player(); void update_plane_item(); }; class World { public: + // A lua intepreter with snapshot function. // LuaSnap lua_snap_; @@ -99,8 +100,16 @@ public: // Serialized snapshot of world model. StreamBuffer snapshot_; + // Redirects. + // + using Redirects = std::map; + Redirects redirects_; + void run_scheduled_threads(int64_t clk); static void store_global_pointer(lua_State *L, World *w); + + // Check if main thread has nothing on the stack + bool stack_is_clear() const { return lua_gettop(state()) == 0; } public: // Constructor. // @@ -125,7 +134,7 @@ public: // // Get the lua interpreter associated with this world model. // - lua_State *state() { return lua_snap_.state(); } + lua_State *state() const { return lua_snap_.state(); } // get_near // @@ -157,6 +166,18 @@ public: // void tangible_delete(lua_State *L, int64_t id); + // Create a login actor. + // + // Creates a tangible of class 'login' and returns its ID. + // This is used to create a temporary actor which is used during + // the login process. + // + int64_t create_login_actor(); + + // Fetch all redirects and clear the redirects table. + // + Redirects fetch_redirects(); + // Probe the 'interface' function of the specified sprite. // void update_gui(int64_t actor_id, int64_t place_id, Gui *gui);