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

@@ -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<UniqueInvocation> DrivenEngine::get_queued_invocations() {
eng::vector<UniqueInvocation> 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;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//

View File

@@ -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<UniqueInvocation> 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<util::SharedStdString> anim_queues_;
eng::string lua_source_pack_;
eng::vector<UniqueInvocation> queued_invocations_;
bool rescan_lua_source_;
double clock_;
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.
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<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");
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<SharedChannel> keep;
@@ -60,13 +62,13 @@ public:
class DriverDNSFailTest : public DrivenEngine {
public:
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");
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<SharedChannel> 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);

View File

@@ -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<Invocation>;
class InvocationQueue : public eng::deque<Invocation> {
};

View File

@@ -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<UniqueInvocation> invocations = get_queued_invocations();
for (const UniqueInvocation &inv : invocations) {
send_invocation(*inv);
}
// Check for keyboard input on stdin.

View File

@@ -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<UniqueInvocation> invocations = get_queued_invocations();
for (const UniqueInvocation &inv : invocations) {
master_->invoke(*inv);
}
// Check for keyboard input on stdin.
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