Event driven engine, further work.

This commit is contained in:
2021-10-05 12:54:37 -04:00
parent bc22dc89af
commit bce756d1fd
11 changed files with 61 additions and 115 deletions

View File

@@ -43,7 +43,7 @@ Channel *DrivenEngine::get_stdio_channel() {
return stdio_channel_.get(); return stdio_channel_.get();
} }
std::unique_ptr<util::LuaSource> DrivenEngine::get_lua_source() { util::LuaSourcePtr DrivenEngine::get_lua_source() {
return std::move(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. // 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) { Channel *DrivenEngine::get_chid(int chid) {
// We cache the most recently used channel. // We cache the most recently used channel.
if (recent_channel_->chid_ != chid) { 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) { 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) { void DrivenEngine::drv_notify_close(int chid) {
@@ -127,11 +121,15 @@ void DrivenEngine::drv_set_clock(double t) {
clock_ = t; clock_ = t;
} }
void DrivenEngine::drv_set_lua_source(const util::LuaSource &source) { void DrivenEngine::drv_set_lua_source(util::LuaSourcePtr source) {
lua_source_.reset(new util::LuaSource(source)); lua_source_ = std::move(source);
rescan_lua_source_ = false; rescan_lua_source_ = false;
} }
void DrivenEngine::drv_invoke_event_update() {
event_update();
}
bool DrivenEngine::drv_get_rescan_lua_source() { bool DrivenEngine::drv_get_rescan_lua_source() {
return rescan_lua_source_; return rescan_lua_source_;
} }

View File

@@ -64,11 +64,6 @@
// * If 'logmode_write' or 'logmode_none' is selected, the driver must proceed // * If 'logmode_write' or 'logmode_none' is selected, the driver must proceed
// to drive the application. Follow the remainder of these steps. // 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. // * Open a hardwired list of ports for listening.
// //
// * Repeat the following steps over and over: // * Repeat the following steps over and over:
@@ -104,7 +99,7 @@
// drv_peek_outgoing, drv_sent_outgoing, and drv_recv_incoming in the // drv_peek_outgoing, drv_sent_outgoing, and drv_recv_incoming in the
// same manner as you would for a socket. // 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. // The update callback. You may override this in a subclass.
// This will be called to initialize the logic engine, shortly after the lua // This will be called whenever anything changes.
// source is loaded.
// //
virtual void init() {} virtual void event_update() {}
// 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() {}
// Get the current time. // Get the current time.
// //
@@ -218,21 +207,10 @@ public:
// //
Channel *get_stdio_channel(); Channel *get_stdio_channel();
// Fetches the entire contents of the lua source directory. The keys in the // Fetches the lua source, and takes ownership of it. The DrivenEngine
// map are filenames, and the values in the map are file contents. By // no longer contains the source after calling this.
// 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.
// //
// DRIVER: the driver is responsible for storing the lua source into the util::LuaSourcePtr get_lua_source();
// 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<util::LuaSource> get_lua_source();
// Rescan the lua source directory. The lua source directory is read once, // Rescan the lua source directory. The lua source directory is read once,
// automatically, at engine creation time. If you want to read it again, // automatically, at engine creation time. If you want to read it again,
@@ -272,17 +250,6 @@ public:
// //
void drv_logmode_none(); 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 // 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 // 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 // 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 // Set the lua source code. The driver is expected to read the lua source
// code and store it (using this function) once before invoking // 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 // 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. // that the engine wants the driver to rescan the lua source code.
@@ -398,8 +369,8 @@ private:
std::map<int, Channel *> channels_; std::map<int, Channel *> channels_;
Channel *recent_channel_; Channel *recent_channel_;
std::vector<std::unique_ptr<Channel>> accepted_channels_; std::vector<std::unique_ptr<Channel>> accepted_channels_;
util::LuaSourcePtr lua_source_;
bool rescan_lua_source_; bool rescan_lua_source_;
std::unique_ptr<util::LuaSource> lua_source_;
double clock_; double clock_;
bool stop_driver_; bool stop_driver_;
friend class Channel; friend class Channel;

View File

@@ -12,11 +12,10 @@ void driver_drive(DrivenEngine *de) {
int nbytes; const char *bytes; int nbytes; const char *bytes;
DrivenEngine::set(de); DrivenEngine::set(de);
de->drv_logmode_none(); 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()) { while (!de->drv_get_stop_driver()) {
if (de->drv_get_rescan_lua_source()) { if (de->drv_get_rescan_lua_source()) {
de->drv_set_lua_source(util::read_lua_source("lua")); de->drv_set_lua_source(util::read_lua_source("lua"));
de->drv_invoke_event_update();
} }
de->drv_peek_outgoing(0, &nbytes, &bytes); de->drv_peek_outgoing(0, &nbytes, &bytes);
if (nbytes > 0) { if (nbytes > 0) {
@@ -24,8 +23,8 @@ void driver_drive(DrivenEngine *de) {
} }
if (fgets(buf, MAXINPUT, stdin)) { if (fgets(buf, MAXINPUT, stdin)) {
de->drv_recv_incoming(0, strlen(buf), buf); de->drv_recv_incoming(0, strlen(buf), buf);
de->drv_invoke_event_update();
} }
de->drv_invoke_engine_update();
} }
DrivenEngine::set(nullptr); DrivenEngine::set(nullptr);
} }

View File

@@ -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) { void SourceDB::diff(const SourceDB &auth, StreamBuffer *sb) {
LuaVar sdb, sfn, sinfo, shash, sseq; LuaVar sdb, sfn, sinfo, shash, sseq;
@@ -267,7 +239,7 @@ std::string SourceDB::get(const std::string &fn) {
return oss.str(); return oss.str();
} }
void SourceDB::update(const util::LuaSource &source) { void SourceDB::update(const util::LuaSourceVec &source) {
lua_State *L = lua_state_; lua_State *L = lua_state_;
LuaVar sourcedb, info; LuaVar sourcedb, info;
LuaStack LS(L, sourcedb, info); LuaStack LS(L, sourcedb, info);

View File

@@ -135,7 +135,7 @@ public:
// Update the database using the specified lua source code. // Update the database using the specified lua source code.
// Compiles these files using lua's "load" function. // Compiles these files using lua's "load" function.
// //
void update(const util::LuaSource &source); void update(const util::LuaSourceVec &source);
// Rebuild // Rebuild
// //

View File

@@ -170,24 +170,17 @@ void TextGame::check_redirects() {
} }
} }
void TextGame::init() void TextGame::event_update()
{ {
world_.reset(new World(util::WORLD_TYPE_STANDALONE)); if (world_ == nullptr) {
std::unique_ptr<util::LuaSource> lsource = get_lua_source(); world_.reset(new World(util::WORLD_TYPE_STANDALONE));
world_->update_source(*lsource); world_->update_source(get_lua_source());
world_->run_unittests(); world_->run_unittests();
actor_id_ = world_->create_login_actor(); actor_id_ = world_->create_login_actor();
std::cerr << "Login actor ID: " << actor_id_ << std::endl; std::cerr << "Login actor ID: " << actor_id_ << std::endl;
console_.clear();
}
void TextGame::update() {
check_redirects();
if (actor_id_ == 0) {
stop_driver();
return;
} }
// Process lines from stdin. world_->update_source(get_lua_source());
while (true) { while (true) {
std::string line = get_stdio_channel()->in()->readline(); std::string line = get_stdio_channel()->in()->readline();
if (line == "") break; if (line == "") break;
@@ -200,9 +193,11 @@ void TextGame::update() {
} else if (action == LuaConsole::DO_SYNTAX) { } else if (action == LuaConsole::DO_SYNTAX) {
std::cerr << console_.syntax() << std::endl; std::cerr << console_.syntax() << std::endl;
} }
check_redirects();
if (actor_id_ == 0) {
stop_driver();
return;
}
} }
// Process lua source if available.
std::unique_ptr<util::LuaSource> source = get_lua_source();
if (source != nullptr) world_->update_source(*source);
} }

View File

@@ -27,9 +27,9 @@ private:
void do_command(const StringVec &exp); void do_command(const StringVec &exp);
void check_redirects(); void check_redirects();
public: public:
virtual void init(); virtual void event_update();
virtual void update();
}; };
#endif // TEXTGAME_HPP #endif // TEXTGAME_HPP

View File

@@ -226,15 +226,15 @@ static StringVec read_control_lst(const std::string &path) {
return result; 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"); StringVec files = read_control_lst(dir + "/control.lst");
assert (!files.empty()); assert (!files.empty());
LuaSource result; LuaSourcePtr result(new LuaSourceVec);
for (const std::string &file : files) { for (const std::string &file : files) {
std::string data = get_file_contents(dir + "/" + file); 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 { std::string XYZ::debug_string() const {

View File

@@ -7,6 +7,7 @@
#include <algorithm> #include <algorithm>
#include <sstream> #include <sstream>
#include <ostream> #include <ostream>
#include <memory>
#include <tuple> #include <tuple>
#include <utility> #include <utility>
#include "luastack.hpp" #include "luastack.hpp"
@@ -23,7 +24,8 @@ enum WorldType {
using StringVec = std::vector<std::string>; using StringVec = std::vector<std::string>;
using StringPair = std::pair<std::string, std::string>; using StringPair = std::pair<std::string, std::string>;
using LuaSource = std::vector<StringPair>; using LuaSourceVec = std::vector<StringPair>;
using LuaSourcePtr = std::unique_ptr<LuaSourceVec>;
using HashValue = std::pair<uint64_t, uint64_t>; using HashValue = std::pair<uint64_t, uint64_t>;
using IdVector = std::vector<int64_t>; using IdVector = std::vector<int64_t>;
@@ -76,7 +78,7 @@ std::string trim(std::string s);
double distance_squared(double x1, double y1, double x2, double y2); double distance_squared(double x1, double y1, double x2, double y2);
// Read the lua source code from the specified directory. // 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. // An XYZ coordinate, general purpose.
struct XYZ { struct XYZ {

View File

@@ -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) { void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &idata) {
assert(stack_is_clear()); assert(stack_is_clear());

View File

@@ -174,7 +174,9 @@ public:
// Update the source database from disk. // 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. // Run all unit tests.
// //