Event driven engine, further work.
This commit is contained in:
@@ -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_;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user