From 600ae7cef96e4ef6947c25fb96c8dbb85eb2261d Mon Sep 17 00:00:00 2001 From: jyelon Date: Mon, 23 Oct 2023 20:57:47 -0400 Subject: [PATCH] Add invocation queue to DrivenEngine, use it for lua source --- luprex/Makefile | 1 - luprex/cpp/core/drivenengine.cpp | 14 ++-- luprex/cpp/core/drivenengine.hpp | 23 +++--- luprex/cpp/core/eng-tests.cpp | 22 ++--- luprex/cpp/core/invocation.hpp | 5 +- luprex/cpp/core/lpxclient.cpp | 19 ++--- luprex/cpp/core/lpxserver.cpp | 12 ++- luprex/cpp/core/textgame.cpp | 133 ------------------------------- luprex/cpp/core/textgame.hpp | 9 --- 9 files changed, 50 insertions(+), 188 deletions(-) delete mode 100644 luprex/cpp/core/textgame.cpp delete mode 100644 luprex/cpp/core/textgame.hpp diff --git a/luprex/Makefile b/luprex/Makefile index 8deead6f..e8b0857e 100644 --- a/luprex/Makefile +++ b/luprex/Makefile @@ -90,7 +90,6 @@ OBJ_CORE=\ build/$(OS)/core/world-diffxmit.obj\ build/$(OS)/core/world-pairtab.obj\ build/$(OS)/core/world-testing.obj\ - build/$(OS)/core/textgame.obj\ build/$(OS)/core/lpxserver.obj\ build/$(OS)/core/lpxclient.obj\ build/$(OS)/core/eng-tests.obj\ diff --git a/luprex/cpp/core/drivenengine.cpp b/luprex/cpp/core/drivenengine.cpp index fea88b8f..f54a085e 100644 --- a/luprex/cpp/core/drivenengine.cpp +++ b/luprex/cpp/core/drivenengine.cpp @@ -165,9 +165,9 @@ void DrivenEngine::set_console_prompt(const eng::string &prompt) { console_prompt_ = prompt; } -eng::string DrivenEngine::get_lua_source_pack() { - eng::string result = std::move(lua_source_pack_); - lua_source_pack_.clear(); +eng::vector DrivenEngine::get_queued_invocations() { + eng::vector result = std::move(queued_invocations_); + queued_invocations_.clear(); return result; } @@ -392,11 +392,11 @@ bool DrivenEngine::drv_get_stop_driver() const { return stop_driver_; } -uint64_t DrivenEngine::drv_get_actor_id() const { +int64_t DrivenEngine::drv_get_actor_id() const { return visible_actor_id_; } -void DrivenEngine::drv_get_tangibles_near(uint64_t tanid, double rx, double ry, double rz, uint32_t *count, int64_t **ids) { +void DrivenEngine::drv_get_tangibles_near(int64_t tanid, double rx, double ry, double rz, uint32_t *count, int64_t **ids) { uint32_t hash1 = eng::memhash(); scan_result_.clear(); if ((visible_world_ != 0) && (tanid != 0)) { @@ -483,11 +483,11 @@ void DrivenEngine::drv_invoke_event_update(double clock) { } void DrivenEngine::drv_set_lua_source_pack(uint32_t srcpklen, const char *srcpk) { - lua_source_pack_ = std::string_view(srcpk, srcpklen); + Invocation *inv = new Invocation(Invocation::KIND_LUA_SOURCE, visible_actor_id_, visible_actor_id_, std::string_view(srcpk, srcpklen)); + queued_invocations_.emplace_back(inv); rescan_lua_source_ = false; } - ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // diff --git a/luprex/cpp/core/drivenengine.hpp b/luprex/cpp/core/drivenengine.hpp index 0c43b222..63c0dfac 100644 --- a/luprex/cpp/core/drivenengine.hpp +++ b/luprex/cpp/core/drivenengine.hpp @@ -53,6 +53,7 @@ #include "streambuffer.hpp" #include "enginewrapper.hpp" #include "planemap.hpp" +#include "invocation.hpp" class DrivenEngine; class World; @@ -144,12 +145,12 @@ public: // The init callback. You may override this in a subclass. // This will be called once at program initialization. // - virtual void event_init(std::string_view srcpk, int argc, char *argv[]) {} + virtual void event_init(std::string_view srcpk, int argc, char *argv[]) = 0; // The update callback. You may override this in a subclass. // This will be called whenever anything changes. // - virtual void event_update() {} + virtual void event_update() = 0; // Specify the set of listening ports. // This can only be used during the init routine. @@ -210,14 +211,12 @@ public: // void set_console_prompt(const eng::string &prompt); - // Fetches the lua 'sourcepack'. The sourcepack is a packaged collection - // of all the lua sourcefiles, see drvutil::package_lua_source for - // documentation of the format. This also clears the sourcepack stored - // in the DrivenEngine. Returns empty string if there is no sourcepack - // in the DrivenEngine. + // Fetches the invocation queue. // - eng::string get_lua_source_pack(); - + // This also clears the stored queue. + // + eng::vector get_queued_invocations(); + // Rescan the lua source directory. The lua source directory is read once, // automatically, at engine creation time. If you want to read it again, // you must trigger a rescan. The rescan is not instantaneous. @@ -283,8 +282,8 @@ public: double drv_get_clock() const; bool drv_get_rescan_lua_source() const; bool drv_get_stop_driver() const; - uint64_t drv_get_actor_id() const; - void drv_get_tangibles_near(uint64_t tanid, double rx, double ry, double rz, uint32_t *count, int64_t **ids); + int64_t drv_get_actor_id() const; + void drv_get_tangibles_near(int64_t tanid, double rx, double ry, double rz, uint32_t *count, int64_t **ids); void drv_get_animation_queues(uint32_t count, const int64_t *ids, uint32_t *lengths, const char **strings); void drv_initialize(uint32_t srcpklen, const char *srcpk, int argc, char **argv); @@ -316,7 +315,7 @@ private: int64_t visible_actor_id_; util::IdVector scan_result_; std::vector anim_queues_; - eng::string lua_source_pack_; + eng::vector queued_invocations_; bool rescan_lua_source_; double clock_; bool stop_driver_; diff --git a/luprex/cpp/core/eng-tests.cpp b/luprex/cpp/core/eng-tests.cpp index 61037b76..e99b3c6f 100644 --- a/luprex/cpp/core/eng-tests.cpp +++ b/luprex/cpp/core/eng-tests.cpp @@ -24,9 +24,11 @@ static void dump_lines(StreamBuffer *in, StreamBuffer *out, int chid) { // This test is the minimal possible DrivenEngine. class DriverStubTest : public DrivenEngine { - virtual void event_init(int argc, char *argv[]) { + virtual void event_init(std::string_view srcpk, int argc, char *argv[]) override { stop_driver(); } + virtual void event_update() override { + } }; // This test connects to a public webserver and prints @@ -34,13 +36,13 @@ class DriverStubTest : public DrivenEngine { class DriverWebServerTest : public DrivenEngine { public: eng::vector channels_; - virtual void event_init(int argc, char *argv[]) { + virtual void event_init(std::string_view srcpk, int argc, char *argv[]) override { SharedChannel ch = new_outgoing_channel("cert:stanford.edu:443"); ch->out()->write_bytes("GET https://stanford.edu/xbanankjdsh.html HTTP/1.1\n\n"); channels_.emplace_back(std::move(ch)); } - virtual void event_update() { + virtual void event_update() override { SharedChannel stdioch = get_stdio_channel(); dump_lines(stdioch->in(), stdioch->out(), 0); eng::vector keep; @@ -60,13 +62,13 @@ public: class DriverDNSFailTest : public DrivenEngine { public: eng::vector channels_; - virtual void event_init(int argc, char *argv[]) { + virtual void event_init(std::string_view srcpk, int argc, char *argv[]) override { SharedChannel ch = new_outgoing_channel("akjsdkajshdakjshd.alk:80"); ch->out()->write_bytes("GET http://stanford.edu/index.html HTTP/1.1\n\n"); channels_.emplace_back(std::move(ch)); } - virtual void event_update() { + virtual void event_update() override { SharedChannel stdioch = get_stdio_channel(); dump_lines(stdioch->in(), stdioch->out(), 0); eng::vector keep; @@ -87,12 +89,12 @@ class DriverPrintClockTest : public DrivenEngine { public: int count_; double last_clock_; - virtual void event_init(int argc, char *argv[]) { + virtual void event_init(std::string_view srcpk, int argc, char *argv[]) override { count_ = 0; last_clock_ = 0.0; } - virtual void event_update() { + virtual void event_update() override { double clock = get_clock(); if (clock > last_clock_ + 0.5) { int ms = eng::memhash(); @@ -112,13 +114,15 @@ class RunUnitTests : public DrivenEngine { private: UniqueWorld world_; - void event_init(int argc, char *argv[]) + void event_init(std::string_view srcpk, int argc, char *argv[]) override { world_.reset(new World(WORLD_TYPE_MASTER)); - world_->update_source(get_lua_source_pack()); + world_->update_source(srcpk); world_->run_unittests(); stop_driver(); } + + void event_update() override {} }; DrivenEngineDefine("driverstubtest", DriverStubTest); diff --git a/luprex/cpp/core/invocation.hpp b/luprex/cpp/core/invocation.hpp index 4a2a6fc9..b7dff90b 100644 --- a/luprex/cpp/core/invocation.hpp +++ b/luprex/cpp/core/invocation.hpp @@ -40,11 +40,10 @@ #include "wrap-string.hpp" #include "wrap-map.hpp" #include "wrap-deque.hpp" - #include "streambuffer.hpp" -class Invocation : public eng::nevernew { +class Invocation : public eng::opnew { public: enum Kind { KIND_INVALID, @@ -76,6 +75,8 @@ public: eng::string debug_string() const; }; +using UniqueInvocation = std::unique_ptr; + class InvocationQueue : public eng::deque { }; diff --git a/luprex/cpp/core/lpxclient.cpp b/luprex/cpp/core/lpxclient.cpp index 5463dd7c..106a7668 100644 --- a/luprex/cpp/core/lpxclient.cpp +++ b/luprex/cpp/core/lpxclient.cpp @@ -35,6 +35,9 @@ public: // Clear the unack command queue. unack_.clear(); + + // Export stuff to the graphics engine. + set_visible_world_and_actor(world_.get(), actor_id_); } @@ -93,11 +96,6 @@ public: inv.serialize(sb); } - void send_lua_source(std::string_view sourcepack) { - Invocation inv(Invocation::KIND_LUA_SOURCE, actor_id_, actor_id_, sourcepack); - send_invocation(inv); - } - void do_luainvoke_command(const StringVec &words) { send_invocation(Invocation(Invocation::KIND_LUA, actor_id_, actor_id_, words[1])); } @@ -176,6 +174,7 @@ public: stdostream() << "Actor ID changing: " << actor_id << std::endl; print_channeler_.reset(); actor_id_ = actor_id; + set_visible_world_and_actor(world_.get(), actor_id_); } void receive_ack_from_server(StreamBuffer *sb) { @@ -230,12 +229,10 @@ public: } virtual void event_update() { - // Check for lua source code. If this returns non-null, - // it is because somebody typed CPL. - eng::string lua_source_pack = get_lua_source_pack(); - if (!lua_source_pack.empty()) { - send_lua_source(lua_source_pack); - lua_source_pack.clear(); + // Send invocations. We execute these using predictive execution. + eng::vector invocations = get_queued_invocations(); + for (const UniqueInvocation &inv : invocations) { + send_invocation(*inv); } // Check for keyboard input on stdin. diff --git a/luprex/cpp/core/lpxserver.cpp b/luprex/cpp/core/lpxserver.cpp index 729fa063..18796623 100644 --- a/luprex/cpp/core/lpxserver.cpp +++ b/luprex/cpp/core/lpxserver.cpp @@ -31,7 +31,7 @@ public: Gui gui_; public: - virtual void event_init(std::string_view srcpk, int argc, char *argv[]) { + virtual void event_init(std::string_view srcpk, int argc, char *argv[]) override { // Create the master world model. master_.reset(new World(WORLD_TYPE_MASTER)); @@ -166,9 +166,13 @@ public: return true; } - virtual void event_update() { - // If the driver has reloaded the source, put it into master model. - master_->update_source(get_lua_source_pack()); + virtual void event_update() override { + // Execute any queued invocations. + // We just feed these directly into the master model. + eng::vector invocations = get_queued_invocations(); + for (const UniqueInvocation &inv : invocations) { + master_->invoke(*inv); + } // Check for keyboard input on stdin. while (true) { diff --git a/luprex/cpp/core/textgame.cpp b/luprex/cpp/core/textgame.cpp deleted file mode 100644 index e004a98f..00000000 --- a/luprex/cpp/core/textgame.cpp +++ /dev/null @@ -1,133 +0,0 @@ - -#include "wrap-vector.hpp" -#include "wrap-string.hpp" -#include "luastack.hpp" -#include "util.hpp" -#include "gui.hpp" -#include "invocation.hpp" -#include "world.hpp" -#include "traceback.hpp" -#include "luaconsole.hpp" -#include "pprint.hpp" -#include "printbuffer.hpp" -#include "drivenengine.hpp" - -#include -#include -#include -#include -#include - -class TextGame : public DrivenEngine { -private: - using StringVec = LuaConsole::StringVec; - UniqueWorld world_; - LuaConsole console_; - PrintChanneler print_channeler_; - Gui gui_; - int64_t actor_id_; - - void do_luainvoke_command(const StringVec &words) { - world_->invoke(Invocation(Invocation::KIND_LUA, actor_id_, actor_id_, words[1])); - } - - void do_luaprobe_command(const StringVec &words) { - world_->snapshot(); - stdostream() << world_->probe_lua(actor_id_, words[1]); - world_->rollback(); - } - - void do_syntax_command(const StringVec &words) { - stdostream() << "Syntax Error: " << words[1] << std::endl; - } - - void do_view_command(const StringVec &cmd) { - stdostream() << world_->tangibles_near_debug_string(actor_id_, 100); - } - - void do_menu_command(const StringVec &cmd) { - int64_t place = sv::to_int64(cmd[1], actor_id_); - world_->update_gui(actor_id_, place, &gui_); - stdostream() << gui_.menu_debug_string(); - } - - void do_choose_command(const StringVec &cmd) { - eng::string action = gui_.get_action(sv::to_int64(cmd[1])); - if (action == "") { - stdostream() << "Invalid menu item #" << std::endl; - return; - } - Invocation inv(Invocation::KIND_PLAN, actor_id_, gui_.place(), action); - stdostream() << "Invoking: " << inv.debug_string() << std::endl; - world_->invoke(inv); - } - - void do_tick_command(const StringVec &cmd) { - world_->invoke(Invocation(Invocation::KIND_TICK, actor_id_, actor_id_, "")); - } - - void do_quit_command(const StringVec &cmd) { - actor_id_ = 0; - } - - void do_command(const StringVec &words) { - if (words.empty()) return; - else if (words[0] == "luainvoke") do_luainvoke_command(words); - else if (words[0] == "luaprobe") do_luaprobe_command(words); - else if (words[0] == "syntax") do_syntax_command(words); - else if (words[0] == "view") do_view_command(words); - else if (words[0] == "menu") do_menu_command(words); - else if (words[0] == "quit") do_quit_command(words); - else if (words[0] == "tick") do_tick_command(words); - else if (words[0] == "choose") do_choose_command(words); - else { - stdostream() << "Unsupported command: " << words[0] << std::endl; - } - } - - void check_redirects() { - World::Redirects redir = world_->fetch_redirects(); - for (const auto &p : redir) { - if (p.first == actor_id_) { - actor_id_ = p.second; - stdostream() << "Login actor ID: " << actor_id_ << std::endl; - gui_.clear(0); - } - } - } - - void event_init(int argc, char *argv[]) - { - world_.reset(new World(WORLD_TYPE_MASTER)); - world_->update_source(get_lua_source_pack()); - world_->run_unittests(); - actor_id_ = world_->create_login_actor(); - stdostream() << "Login actor ID: " << actor_id_ << std::endl; - set_console_prompt(console_.get_prompt()); - } - - void event_update() - { - world_->update_source(get_lua_source_pack()); - while (true) { - eng::string line = get_stdio_channel()->in()->readline(); - if (line == "") break; - console_.add(line); - set_console_prompt(console_.get_prompt()); - do_command(console_.get_command()); - if (print_channeler_.channel(world_->get_printbuffer(actor_id_), stdostream())) { - world_->invoke(print_channeler_.invocation(actor_id_)); - } - check_redirects(); - if (actor_id_ == 0) { - stop_driver(); - break; - } - } - } -}; - -UniqueDrivenEngine make_TextGame() { - return UniqueDrivenEngine(new TextGame); -} -static DrivenEngineReg reg_TextGame("textgame", make_TextGame); diff --git a/luprex/cpp/core/textgame.hpp b/luprex/cpp/core/textgame.hpp deleted file mode 100644 index 4fa33481..00000000 --- a/luprex/cpp/core/textgame.hpp +++ /dev/null @@ -1,9 +0,0 @@ - -#ifndef TEXTGAME_HPP -#define TEXTGAME_HPP - -#include "drivenengine.hpp" - -UniqueDrivenEngine make_TextGame(); - -#endif // TEXTGAME_HPP