From bce756d1fd2cc68d19634db285dd8f10196fe892 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Tue, 5 Oct 2021 12:54:37 -0400 Subject: [PATCH] Event driven engine, further work. --- luprex/core/cpp/drivenengine.cpp | 22 ++++++------- luprex/core/cpp/drivenengine.hpp | 55 ++++++++------------------------ luprex/core/cpp/driver.cpp | 5 ++- luprex/core/cpp/source.cpp | 30 +---------------- luprex/core/cpp/source.hpp | 2 +- luprex/core/cpp/textgame.cpp | 33 ++++++++----------- luprex/core/cpp/textgame.hpp | 4 +-- luprex/core/cpp/util.cpp | 8 ++--- luprex/core/cpp/util.hpp | 6 ++-- luprex/core/cpp/world-core.cpp | 7 ++++ luprex/core/cpp/world.hpp | 4 ++- 11 files changed, 61 insertions(+), 115 deletions(-) diff --git a/luprex/core/cpp/drivenengine.cpp b/luprex/core/cpp/drivenengine.cpp index deebcd66..b6701c66 100644 --- a/luprex/core/cpp/drivenengine.cpp +++ b/luprex/core/cpp/drivenengine.cpp @@ -43,7 +43,7 @@ Channel *DrivenEngine::get_stdio_channel() { return stdio_channel_.get(); } -std::unique_ptr DrivenEngine::get_lua_source() { +util::LuaSourcePtr DrivenEngine::get_lua_source() { return std::move(lua_source_); } @@ -68,14 +68,6 @@ void DrivenEngine::drv_logmode_none() { // NOT IMPLEMENTED YET, but it's okay as a stub. } -void DrivenEngine::drv_invoke_engine_init() { - init(); -} - -void DrivenEngine::drv_invoke_engine_update() { - update(); -} - Channel *DrivenEngine::get_chid(int chid) { // We cache the most recently used channel. if (recent_channel_->chid_ != chid) { @@ -110,7 +102,9 @@ void DrivenEngine::drv_sent_outgoing(int chid, int nbytes) { } void DrivenEngine::drv_recv_incoming(int chid, int nbytes, char *bytes) { - get_chid(chid)->sb_in_->write_bytes(bytes, nbytes); + if (nbytes > 0) { + get_chid(chid)->sb_in_->write_bytes(bytes, nbytes); + } } void DrivenEngine::drv_notify_close(int chid) { @@ -127,11 +121,15 @@ void DrivenEngine::drv_set_clock(double t) { clock_ = t; } -void DrivenEngine::drv_set_lua_source(const util::LuaSource &source) { - lua_source_.reset(new util::LuaSource(source)); +void DrivenEngine::drv_set_lua_source(util::LuaSourcePtr source) { + lua_source_ = std::move(source); rescan_lua_source_ = false; } +void DrivenEngine::drv_invoke_event_update() { + event_update(); +} + bool DrivenEngine::drv_get_rescan_lua_source() { return rescan_lua_source_; } diff --git a/luprex/core/cpp/drivenengine.hpp b/luprex/core/cpp/drivenengine.hpp index 89146f9b..c7033851 100644 --- a/luprex/core/cpp/drivenengine.hpp +++ b/luprex/core/cpp/drivenengine.hpp @@ -64,11 +64,6 @@ // * If 'logmode_write' or 'logmode_none' is selected, the driver must proceed // to drive the application. Follow the remainder of these steps. // -// * Read the lua source from disk, and call 'drv_set_lua_source'. -// -// * Invoke the DrivenEngine's init callback by calling -// 'drv_invoke_engine_init'. -// // * Open a hardwired list of ports for listening. // // * Repeat the following steps over and over: @@ -104,7 +99,7 @@ // drv_peek_outgoing, drv_sent_outgoing, and drv_recv_incoming in the // same manner as you would for a socket. // -// - Use 'drv_invoke_engine_update' to invoke the engine's update callback. +// - Use 'drv_invoke_event_update' to invoke the engine's update callback. // ////////////////////////////////////////////////////////////// @@ -168,16 +163,10 @@ public: // ////////////////////////////////////////////////////////////// - // The initialization function. You should override this in a subclass. - // This will be called to initialize the logic engine, shortly after the lua - // source is loaded. + // The update callback. You may override this in a subclass. + // This will be called whenever anything changes. // - virtual void init() {} - - // The update function. You should override this in a subclass. This will - // be called to give the engine a chance to respond to new data. - // - virtual void update() {} + virtual void event_update() {} // Get the current time. // @@ -218,21 +207,10 @@ public: // Channel *get_stdio_channel(); - // Fetches the entire contents of the lua source directory. The keys in the - // map are filenames, and the values in the map are file contents. By - // default, the lua source is actually read from disk just once. If you call - // get_lua_source a second time, it will return a nullptr. The nullptr - // indicates that the source has not been refreshed recently. If you want - // to reread the source code, you must trigger the process by calling - // 'refresh_lua_source'. After some delay, it will again be possible to - // get_lua_source. + // Fetches the lua source, and takes ownership of it. The DrivenEngine + // no longer contains the source after calling this. // - // DRIVER: the driver is responsible for storing the lua source into the - // DrivenEngine, once, at startup, using drv_set_source. The driver will - // periodically poll to see if the engine has called rescan_lua_source, - // using drv_get_rescan - // - std::unique_ptr get_lua_source(); + util::LuaSourcePtr get_lua_source(); // Rescan the lua source directory. The lua source directory is read once, // automatically, at engine creation time. If you want to read it again, @@ -272,17 +250,6 @@ public: // void drv_logmode_none(); - // Invoke the engine's init function. The driver must call drv_set_lua_source - // before calling this. - // - void drv_invoke_engine_init(); - - // Invoke the engine's update function. This typically causes the engine - // to check the I/O buffers, and respond to I/O, if any. It also typically - // causes the engine to check the clock, and do any scheduled calculation. - // - void drv_invoke_engine_update(); - // Get a list of all non-closed existing channels. This may include new // channels that were created using 'new_outgoing_channel'. It may also be // missing channels that were deleted. It is up to the driver to update its @@ -341,7 +308,11 @@ public: // Set the lua source code. The driver is expected to read the lua source // code and store it (using this function) once before invoking // - void drv_set_lua_source(const util::LuaSource &source); + void drv_set_lua_source(util::LuaSourcePtr source); + + // Invoke the update event. + // + void drv_invoke_event_update(); // Check the 'rescan_lua_source' flag. If this flag is set, it means // that the engine wants the driver to rescan the lua source code. @@ -398,8 +369,8 @@ private: std::map channels_; Channel *recent_channel_; std::vector> accepted_channels_; + util::LuaSourcePtr lua_source_; bool rescan_lua_source_; - std::unique_ptr lua_source_; double clock_; bool stop_driver_; friend class Channel; diff --git a/luprex/core/cpp/driver.cpp b/luprex/core/cpp/driver.cpp index 1e7e46ad..2a567034 100644 --- a/luprex/core/cpp/driver.cpp +++ b/luprex/core/cpp/driver.cpp @@ -12,11 +12,10 @@ void driver_drive(DrivenEngine *de) { int nbytes; const char *bytes; DrivenEngine::set(de); de->drv_logmode_none(); - de->drv_set_lua_source(util::read_lua_source("lua")); - de->drv_invoke_engine_init(); while (!de->drv_get_stop_driver()) { if (de->drv_get_rescan_lua_source()) { de->drv_set_lua_source(util::read_lua_source("lua")); + de->drv_invoke_event_update(); } de->drv_peek_outgoing(0, &nbytes, &bytes); if (nbytes > 0) { @@ -24,8 +23,8 @@ void driver_drive(DrivenEngine *de) { } if (fgets(buf, MAXINPUT, stdin)) { de->drv_recv_incoming(0, strlen(buf), buf); + de->drv_invoke_event_update(); } - de->drv_invoke_engine_update(); } DrivenEngine::set(nullptr); } diff --git a/luprex/core/cpp/source.cpp b/luprex/core/cpp/source.cpp index d9e6e0a7..3d6ee224 100644 --- a/luprex/core/cpp/source.cpp +++ b/luprex/core/cpp/source.cpp @@ -112,34 +112,6 @@ static void calculate_loadresult(LuaStack &LS0, LuaSlot info, const std::string } } -static void source_updatefile(LuaStack &LS0, LuaSlot source, LuaSlot fn, LuaSlot info) { - lua_State *L = LS0.state(); - LuaVar fingerprint; - LuaStack LS(L, fingerprint); - - // Get the existing info table from the source DB. - if (LS.istable(source)) { - LS.rawget(info, source, fn); - if (!LS.istable(info)) { - LS.newtable(info); - } - } else { - LS.newtable(info); - } - - // If the file modification is wrong, update - // these fields: code, hash, fingerprint, closure, error - // Otherwise, update nothing. - std::string cfn = LS.ckstring(fn); - LS.rawget(fingerprint, info, "fingerprint"); - std::string old_fingerprint; - if (LS.isstring(fingerprint)) { - old_fingerprint = LS.ckstring(fingerprint); - } - // std::cerr << "Probing " << cfn << std::endl; - - LS.result(); -} void SourceDB::diff(const SourceDB &auth, StreamBuffer *sb) { LuaVar sdb, sfn, sinfo, shash, sseq; @@ -267,7 +239,7 @@ std::string SourceDB::get(const std::string &fn) { return oss.str(); } -void SourceDB::update(const util::LuaSource &source) { +void SourceDB::update(const util::LuaSourceVec &source) { lua_State *L = lua_state_; LuaVar sourcedb, info; LuaStack LS(L, sourcedb, info); diff --git a/luprex/core/cpp/source.hpp b/luprex/core/cpp/source.hpp index d6bbb9f5..e6b8dfea 100644 --- a/luprex/core/cpp/source.hpp +++ b/luprex/core/cpp/source.hpp @@ -135,7 +135,7 @@ public: // Update the database using the specified lua source code. // Compiles these files using lua's "load" function. // - void update(const util::LuaSource &source); + void update(const util::LuaSourceVec &source); // Rebuild // diff --git a/luprex/core/cpp/textgame.cpp b/luprex/core/cpp/textgame.cpp index bd9c0d32..af01e778 100644 --- a/luprex/core/cpp/textgame.cpp +++ b/luprex/core/cpp/textgame.cpp @@ -170,24 +170,17 @@ void TextGame::check_redirects() { } } -void TextGame::init() +void TextGame::event_update() { - world_.reset(new World(util::WORLD_TYPE_STANDALONE)); - std::unique_ptr lsource = get_lua_source(); - world_->update_source(*lsource); - world_->run_unittests(); - actor_id_ = world_->create_login_actor(); - std::cerr << "Login actor ID: " << actor_id_ << std::endl; - console_.clear(); -} - -void TextGame::update() { - check_redirects(); - if (actor_id_ == 0) { - stop_driver(); - return; + if (world_ == nullptr) { + world_.reset(new World(util::WORLD_TYPE_STANDALONE)); + world_->update_source(get_lua_source()); + world_->run_unittests(); + actor_id_ = world_->create_login_actor(); + std::cerr << "Login actor ID: " << actor_id_ << std::endl; } - // Process lines from stdin. + world_->update_source(get_lua_source()); + while (true) { std::string line = get_stdio_channel()->in()->readline(); if (line == "") break; @@ -200,9 +193,11 @@ void TextGame::update() { } else if (action == LuaConsole::DO_SYNTAX) { std::cerr << console_.syntax() << std::endl; } + check_redirects(); + if (actor_id_ == 0) { + stop_driver(); + return; + } } - // Process lua source if available. - std::unique_ptr source = get_lua_source(); - if (source != nullptr) world_->update_source(*source); } diff --git a/luprex/core/cpp/textgame.hpp b/luprex/core/cpp/textgame.hpp index 3b4ff258..f89bde85 100644 --- a/luprex/core/cpp/textgame.hpp +++ b/luprex/core/cpp/textgame.hpp @@ -27,9 +27,9 @@ private: void do_command(const StringVec &exp); void check_redirects(); + public: - virtual void init(); - virtual void update(); + virtual void event_update(); }; #endif // TEXTGAME_HPP diff --git a/luprex/core/cpp/util.cpp b/luprex/core/cpp/util.cpp index 4e6a35bd..c729e985 100644 --- a/luprex/core/cpp/util.cpp +++ b/luprex/core/cpp/util.cpp @@ -226,15 +226,15 @@ static StringVec read_control_lst(const std::string &path) { return result; } -LuaSource read_lua_source(const std::string &dir) { +LuaSourcePtr read_lua_source(const std::string &dir) { StringVec files = read_control_lst(dir + "/control.lst"); assert (!files.empty()); - LuaSource result; + LuaSourcePtr result(new LuaSourceVec); for (const std::string &file : files) { std::string data = get_file_contents(dir + "/" + file); - result.emplace_back(file, data); + result->emplace_back(file, data); } - return result; + return std::move(result); } std::string XYZ::debug_string() const { diff --git a/luprex/core/cpp/util.hpp b/luprex/core/cpp/util.hpp index 4a69f3e1..cfb02962 100644 --- a/luprex/core/cpp/util.hpp +++ b/luprex/core/cpp/util.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include "luastack.hpp" @@ -23,7 +24,8 @@ enum WorldType { using StringVec = std::vector; using StringPair = std::pair; -using LuaSource = std::vector; +using LuaSourceVec = std::vector; +using LuaSourcePtr = std::unique_ptr; using HashValue = std::pair; using IdVector = std::vector; @@ -76,7 +78,7 @@ std::string trim(std::string s); double distance_squared(double x1, double y1, double x2, double y2); // Read the lua source code from the specified directory. -LuaSource read_lua_source(const std::string &directory); +LuaSourcePtr read_lua_source(const std::string &directory); // An XYZ coordinate, general purpose. struct XYZ { diff --git a/luprex/core/cpp/world-core.cpp b/luprex/core/cpp/world-core.cpp index c6bb1835..9d03eeee 100644 --- a/luprex/core/cpp/world-core.cpp +++ b/luprex/core/cpp/world-core.cpp @@ -331,6 +331,13 @@ void World::invoke(const Invocation &inv) { } } +void World::update_source(util::LuaSourcePtr source) { + if (source != nullptr) { + source_db_.update(*source); + source_db_.rebuild(true); + } +} + void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &idata) { assert(stack_is_clear()); diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index 03a1bd7c..b8812dd9 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -174,7 +174,9 @@ public: // Update the source database from disk. // - void update_source(const util::LuaSource &source) { source_db_.update(source); source_db_.rebuild(true); } + // Special case: if the source pointer is nullptr, does not update. + // + void update_source(util::LuaSourcePtr source); // Run all unit tests. //