Add invocation queue to DrivenEngine, use it for lua source

This commit is contained in:
2023-10-23 20:57:47 -04:00
parent c4bb4bfb9d
commit 600ae7cef9
9 changed files with 50 additions and 188 deletions

View File

@@ -90,7 +90,6 @@ OBJ_CORE=\
build/$(OS)/core/world-diffxmit.obj\ build/$(OS)/core/world-diffxmit.obj\
build/$(OS)/core/world-pairtab.obj\ build/$(OS)/core/world-pairtab.obj\
build/$(OS)/core/world-testing.obj\ build/$(OS)/core/world-testing.obj\
build/$(OS)/core/textgame.obj\
build/$(OS)/core/lpxserver.obj\ build/$(OS)/core/lpxserver.obj\
build/$(OS)/core/lpxclient.obj\ build/$(OS)/core/lpxclient.obj\
build/$(OS)/core/eng-tests.obj\ build/$(OS)/core/eng-tests.obj\

View File

@@ -165,9 +165,9 @@ void DrivenEngine::set_console_prompt(const eng::string &prompt) {
console_prompt_ = prompt; console_prompt_ = prompt;
} }
eng::string DrivenEngine::get_lua_source_pack() { eng::vector<UniqueInvocation> DrivenEngine::get_queued_invocations() {
eng::string result = std::move(lua_source_pack_); eng::vector<UniqueInvocation> result = std::move(queued_invocations_);
lua_source_pack_.clear(); queued_invocations_.clear();
return result; return result;
} }
@@ -392,11 +392,11 @@ bool DrivenEngine::drv_get_stop_driver() const {
return stop_driver_; return stop_driver_;
} }
uint64_t DrivenEngine::drv_get_actor_id() const { int64_t DrivenEngine::drv_get_actor_id() const {
return visible_actor_id_; 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(); uint32_t hash1 = eng::memhash();
scan_result_.clear(); scan_result_.clear();
if ((visible_world_ != 0) && (tanid != 0)) { 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) { 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; rescan_lua_source_ = false;
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //

View File

@@ -53,6 +53,7 @@
#include "streambuffer.hpp" #include "streambuffer.hpp"
#include "enginewrapper.hpp" #include "enginewrapper.hpp"
#include "planemap.hpp" #include "planemap.hpp"
#include "invocation.hpp"
class DrivenEngine; class DrivenEngine;
class World; class World;
@@ -144,12 +145,12 @@ public:
// The init callback. You may override this in a subclass. // The init callback. You may override this in a subclass.
// This will be called once at program initialization. // 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. // The update callback. You may override this in a subclass.
// This will be called whenever anything changes. // This will be called whenever anything changes.
// //
virtual void event_update() {} virtual void event_update() = 0;
// Specify the set of listening ports. // Specify the set of listening ports.
// This can only be used during the init routine. // This can only be used during the init routine.
@@ -210,13 +211,11 @@ public:
// //
void set_console_prompt(const eng::string &prompt); void set_console_prompt(const eng::string &prompt);
// Fetches the lua 'sourcepack'. The sourcepack is a packaged collection // Fetches the invocation queue.
// 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.
// //
eng::string get_lua_source_pack(); // This also clears the stored queue.
//
eng::vector<UniqueInvocation> get_queued_invocations();
// 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,
@@ -283,8 +282,8 @@ public:
double drv_get_clock() const; double drv_get_clock() const;
bool drv_get_rescan_lua_source() const; bool drv_get_rescan_lua_source() const;
bool drv_get_stop_driver() const; bool drv_get_stop_driver() const;
uint64_t drv_get_actor_id() const; int64_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); 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_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); void drv_initialize(uint32_t srcpklen, const char *srcpk, int argc, char **argv);
@@ -316,7 +315,7 @@ private:
int64_t visible_actor_id_; int64_t visible_actor_id_;
util::IdVector scan_result_; util::IdVector scan_result_;
std::vector<util::SharedStdString> anim_queues_; std::vector<util::SharedStdString> anim_queues_;
eng::string lua_source_pack_; eng::vector<UniqueInvocation> queued_invocations_;
bool rescan_lua_source_; bool rescan_lua_source_;
double clock_; double clock_;
bool stop_driver_; bool stop_driver_;

View File

@@ -24,9 +24,11 @@ static void dump_lines(StreamBuffer *in, StreamBuffer *out, int chid) {
// This test is the minimal possible DrivenEngine. // This test is the minimal possible DrivenEngine.
class DriverStubTest : public 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(); stop_driver();
} }
virtual void event_update() override {
}
}; };
// This test connects to a public webserver and prints // This test connects to a public webserver and prints
@@ -34,13 +36,13 @@ class DriverStubTest : public DrivenEngine {
class DriverWebServerTest : public DrivenEngine { class DriverWebServerTest : public DrivenEngine {
public: public:
eng::vector<SharedChannel> channels_; eng::vector<SharedChannel> 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"); SharedChannel ch = new_outgoing_channel("cert:stanford.edu:443");
ch->out()->write_bytes("GET https://stanford.edu/xbanankjdsh.html HTTP/1.1\n\n"); ch->out()->write_bytes("GET https://stanford.edu/xbanankjdsh.html HTTP/1.1\n\n");
channels_.emplace_back(std::move(ch)); channels_.emplace_back(std::move(ch));
} }
virtual void event_update() { virtual void event_update() override {
SharedChannel stdioch = get_stdio_channel(); SharedChannel stdioch = get_stdio_channel();
dump_lines(stdioch->in(), stdioch->out(), 0); dump_lines(stdioch->in(), stdioch->out(), 0);
eng::vector<SharedChannel> keep; eng::vector<SharedChannel> keep;
@@ -60,13 +62,13 @@ public:
class DriverDNSFailTest : public DrivenEngine { class DriverDNSFailTest : public DrivenEngine {
public: public:
eng::vector<SharedChannel> channels_; eng::vector<SharedChannel> 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"); SharedChannel ch = new_outgoing_channel("akjsdkajshdakjshd.alk:80");
ch->out()->write_bytes("GET http://stanford.edu/index.html HTTP/1.1\n\n"); ch->out()->write_bytes("GET http://stanford.edu/index.html HTTP/1.1\n\n");
channels_.emplace_back(std::move(ch)); channels_.emplace_back(std::move(ch));
} }
virtual void event_update() { virtual void event_update() override {
SharedChannel stdioch = get_stdio_channel(); SharedChannel stdioch = get_stdio_channel();
dump_lines(stdioch->in(), stdioch->out(), 0); dump_lines(stdioch->in(), stdioch->out(), 0);
eng::vector<SharedChannel> keep; eng::vector<SharedChannel> keep;
@@ -87,12 +89,12 @@ class DriverPrintClockTest : public DrivenEngine {
public: public:
int count_; int count_;
double last_clock_; 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; count_ = 0;
last_clock_ = 0.0; last_clock_ = 0.0;
} }
virtual void event_update() { virtual void event_update() override {
double clock = get_clock(); double clock = get_clock();
if (clock > last_clock_ + 0.5) { if (clock > last_clock_ + 0.5) {
int ms = eng::memhash(); int ms = eng::memhash();
@@ -112,13 +114,15 @@ class RunUnitTests : public DrivenEngine {
private: private:
UniqueWorld world_; 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_.reset(new World(WORLD_TYPE_MASTER));
world_->update_source(get_lua_source_pack()); world_->update_source(srcpk);
world_->run_unittests(); world_->run_unittests();
stop_driver(); stop_driver();
} }
void event_update() override {}
}; };
DrivenEngineDefine("driverstubtest", DriverStubTest); DrivenEngineDefine("driverstubtest", DriverStubTest);

View File

@@ -40,11 +40,10 @@
#include "wrap-string.hpp" #include "wrap-string.hpp"
#include "wrap-map.hpp" #include "wrap-map.hpp"
#include "wrap-deque.hpp" #include "wrap-deque.hpp"
#include "streambuffer.hpp" #include "streambuffer.hpp"
class Invocation : public eng::nevernew { class Invocation : public eng::opnew {
public: public:
enum Kind { enum Kind {
KIND_INVALID, KIND_INVALID,
@@ -76,6 +75,8 @@ public:
eng::string debug_string() const; eng::string debug_string() const;
}; };
using UniqueInvocation = std::unique_ptr<Invocation>;
class InvocationQueue : public eng::deque<Invocation> { class InvocationQueue : public eng::deque<Invocation> {
}; };

View File

@@ -35,6 +35,9 @@ public:
// Clear the unack command queue. // Clear the unack command queue.
unack_.clear(); 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); 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) { void do_luainvoke_command(const StringVec &words) {
send_invocation(Invocation(Invocation::KIND_LUA, actor_id_, actor_id_, words[1])); 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; stdostream() << "Actor ID changing: " << actor_id << std::endl;
print_channeler_.reset(); print_channeler_.reset();
actor_id_ = actor_id; actor_id_ = actor_id;
set_visible_world_and_actor(world_.get(), actor_id_);
} }
void receive_ack_from_server(StreamBuffer *sb) { void receive_ack_from_server(StreamBuffer *sb) {
@@ -230,12 +229,10 @@ public:
} }
virtual void event_update() { virtual void event_update() {
// Check for lua source code. If this returns non-null, // Send invocations. We execute these using predictive execution.
// it is because somebody typed CPL. eng::vector<UniqueInvocation> invocations = get_queued_invocations();
eng::string lua_source_pack = get_lua_source_pack(); for (const UniqueInvocation &inv : invocations) {
if (!lua_source_pack.empty()) { send_invocation(*inv);
send_lua_source(lua_source_pack);
lua_source_pack.clear();
} }
// Check for keyboard input on stdin. // Check for keyboard input on stdin.

View File

@@ -31,7 +31,7 @@ public:
Gui gui_; Gui gui_;
public: 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. // Create the master world model.
master_.reset(new World(WORLD_TYPE_MASTER)); master_.reset(new World(WORLD_TYPE_MASTER));
@@ -166,9 +166,13 @@ public:
return true; return true;
} }
virtual void event_update() { virtual void event_update() override {
// If the driver has reloaded the source, put it into master model. // Execute any queued invocations.
master_->update_source(get_lua_source_pack()); // We just feed these directly into the master model.
eng::vector<UniqueInvocation> invocations = get_queued_invocations();
for (const UniqueInvocation &inv : invocations) {
master_->invoke(*inv);
}
// Check for keyboard input on stdin. // Check for keyboard input on stdin.
while (true) { while (true) {

View File

@@ -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 <memory>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <csignal>
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);

View File

@@ -1,9 +0,0 @@
#ifndef TEXTGAME_HPP
#define TEXTGAME_HPP
#include "drivenengine.hpp"
UniqueDrivenEngine make_TextGame();
#endif // TEXTGAME_HPP