Can now use /CPL to reload lua source
This commit is contained in:
@@ -64,11 +64,14 @@ std::string Invocation::debug_string() {
|
||||
case KIND_LUA: oss << "lua"; break;
|
||||
case KIND_FLUSH_PRINTS: oss << "flush_prints"; break;
|
||||
case KIND_TICK: oss << "tick"; break;
|
||||
case KIND_LUA_SOURCE: oss << "lua_source"; break;
|
||||
default: oss << "UNKNOWN"; break;
|
||||
}
|
||||
oss << " a=" << actor_;
|
||||
oss << " p=" << place_;
|
||||
oss << " " << action_;
|
||||
if (kind_ != KIND_LUA_SOURCE) {
|
||||
oss << " " << action_;
|
||||
}
|
||||
for (const auto &pair : data_) {
|
||||
oss << " " << pair.first << "=" << pair.second;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
KIND_LUA,
|
||||
KIND_FLUSH_PRINTS,
|
||||
KIND_TICK,
|
||||
KIND_LUA_SOURCE,
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
@@ -79,6 +79,10 @@ public:
|
||||
|
||||
// Set the console prompt
|
||||
get_stdio_channel()->set_prompt(console_.get_prompt());
|
||||
|
||||
// The driver loads the lua source automatically.
|
||||
// However, we don't need it. Throw it out.
|
||||
get_lua_source();
|
||||
}
|
||||
|
||||
void send_invocation(const Invocation &inv) {
|
||||
@@ -94,6 +98,14 @@ public:
|
||||
inv.serialize(sb);
|
||||
}
|
||||
|
||||
void send_lua_source(const util::LuaSourceVec &sv) {
|
||||
StreamBuffer serial;
|
||||
SourceDB::serialize_source(sv, &serial);
|
||||
std::string sstr = serial.read_entire_contents();
|
||||
Invocation inv(Invocation::KIND_LUA_SOURCE, actor_id_, actor_id_, sstr);
|
||||
send_invocation(inv);
|
||||
}
|
||||
|
||||
void do_luainvoke_command(const StringVec &words) {
|
||||
send_invocation(Invocation(Invocation::KIND_LUA, actor_id_, actor_id_, words[1]));
|
||||
}
|
||||
@@ -134,6 +146,10 @@ public:
|
||||
send_invocation(Invocation(Invocation::KIND_TICK, actor_id_, actor_id_, ""));
|
||||
}
|
||||
|
||||
void do_cpl_command(const util::StringVec &words) {
|
||||
rescan_lua_source();
|
||||
}
|
||||
|
||||
void do_quit_command(const util::StringVec &words) {
|
||||
abandon_server();
|
||||
stop_driver();
|
||||
@@ -148,6 +164,7 @@ public:
|
||||
else if (words[0] == "menu") do_menu_command(words);
|
||||
else if (words[0] == "choose") do_choose_command(words);
|
||||
else if (words[0] == "tick") do_tick_command(words);
|
||||
else if (words[0] == "cpl") do_cpl_command(words);
|
||||
else if (words[0] == "quit") do_quit_command(words);
|
||||
else {
|
||||
stdostream() << "Unsupported command: " << words[0] << std::endl;
|
||||
@@ -214,6 +231,14 @@ public:
|
||||
}
|
||||
|
||||
virtual void event_update() {
|
||||
// Check for lua source code. If this returns non-null,
|
||||
// it is because somebody typed CPL.
|
||||
util::LuaSourcePtr lua_source = get_lua_source();
|
||||
if (lua_source != nullptr) {
|
||||
send_lua_source(*lua_source);
|
||||
lua_source.reset();
|
||||
}
|
||||
|
||||
// Check for keyboard input on stdin.
|
||||
while (true) {
|
||||
std::string line = get_stdio_channel()->in()->readline();
|
||||
|
||||
@@ -63,6 +63,10 @@ public:
|
||||
master_->invoke(Invocation(Invocation::KIND_TICK, admin_id_, admin_id_, ""));
|
||||
}
|
||||
|
||||
void do_cpl_command(const util::StringVec &words) {
|
||||
rescan_lua_source();
|
||||
}
|
||||
|
||||
void do_quit_command(const util::StringVec &words) {
|
||||
stop_driver();
|
||||
}
|
||||
@@ -73,6 +77,7 @@ public:
|
||||
else if (words[0] == "luaprobe") do_luaprobe_command(words);
|
||||
else if (words[0] == "syntax") do_syntax_command(words);
|
||||
else if (words[0] == "tick") do_tick_command(words);
|
||||
else if (words[0] == "cpl") do_cpl_command(words);
|
||||
else if (words[0] == "quit") do_quit_command(words);
|
||||
else {
|
||||
stdostream() << "Unsupported command: " << words[0] << std::endl;
|
||||
@@ -127,6 +132,9 @@ public:
|
||||
}
|
||||
|
||||
virtual void event_update() {
|
||||
// If the driver has reloaded the source, put it into master model.
|
||||
master_->update_source(get_lua_source());
|
||||
|
||||
// Check for keyboard input on stdin.
|
||||
while (true) {
|
||||
std::string line = get_stdio_channel()->in()->readline();
|
||||
|
||||
@@ -82,6 +82,10 @@ void LuaConsole::simplify(const StringVec &words) {
|
||||
if (words.size() != 1) {
|
||||
synerr("/tick takes no arguments");
|
||||
}
|
||||
} else if (words[0] == "cpl") {
|
||||
if (words.size() != 1) {
|
||||
synerr("/cpl takes no arguments");
|
||||
}
|
||||
} else {
|
||||
synerr("unrecognized command");
|
||||
}
|
||||
|
||||
@@ -446,6 +446,25 @@ void SourceDB::init(lua_State *L) {
|
||||
}
|
||||
}
|
||||
|
||||
void SourceDB::serialize_source(const util::LuaSourceVec &sv, StreamBuffer *sb) {
|
||||
sb->write_int32(sv.size());
|
||||
for (const auto &pair : sv) {
|
||||
sb->write_string(pair.first);
|
||||
sb->write_string(pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
void SourceDB::deserialize_source(util::LuaSourceVec *sv, StreamBuffer *sb) {
|
||||
sv->clear();
|
||||
int count = sb->read_int32();
|
||||
if ((count < 0) || (count > 10000)) throw StreamCorruption();
|
||||
for (int i = 0; i < count; i++) {
|
||||
std::string fn = sb->read_string();
|
||||
std::string code = sb->read_string();
|
||||
sv->emplace_back(fn, code);
|
||||
}
|
||||
}
|
||||
|
||||
// These should go away eventually. They're for debugging.
|
||||
LuaDefine(coroutine_setnextid, "c") {
|
||||
LuaArg co, lid;
|
||||
|
||||
@@ -172,6 +172,11 @@ public:
|
||||
//
|
||||
void set(const std::string &fn, const std::string &code, int sequence);
|
||||
std::string get(const std::string &fn);
|
||||
|
||||
// Serialize and unserialize a source vector.
|
||||
//
|
||||
static void serialize_source(const util::LuaSourceVec &sv, StreamBuffer *sb);
|
||||
static void deserialize_source(util::LuaSourceVec *sv, StreamBuffer *sb);
|
||||
};
|
||||
|
||||
#endif // SOURCE_HPP
|
||||
|
||||
@@ -30,6 +30,11 @@ StreamBuffer::StreamBuffer(const char *s, int64_t size) {
|
||||
write_cursor_ = buf_hi_;
|
||||
}
|
||||
|
||||
StreamBuffer::StreamBuffer(const std::string &src) {
|
||||
init(true, false, const_cast<char *>(src.c_str()), src.size());
|
||||
write_cursor_ = buf_hi_;
|
||||
}
|
||||
|
||||
StreamBuffer::~StreamBuffer() {
|
||||
if (owned_ && (buf_lo_ != 0)) free(buf_lo_);
|
||||
}
|
||||
|
||||
@@ -249,6 +249,9 @@ public:
|
||||
// Construct a streambuffer that reads from an external block of bytes.
|
||||
StreamBuffer(const char *s, int64_t len);
|
||||
|
||||
// Construct a streambuffer that reads from an external block of bytes.
|
||||
StreamBuffer(const std::string &data);
|
||||
|
||||
// Delete a StreamBuffer.
|
||||
~StreamBuffer();
|
||||
|
||||
|
||||
@@ -375,16 +375,20 @@ void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) {
|
||||
}
|
||||
|
||||
void World::update_source(const util::LuaSourcePtr &source) {
|
||||
assert(stack_is_clear());
|
||||
if (source != nullptr) {
|
||||
source_db_.update(*source);
|
||||
assert(stack_is_clear());
|
||||
std::string errs = source_db_.rebuild();
|
||||
// I don't have a good place to send the error messages right
|
||||
// now. The engine needs a catch-all place to send errors that
|
||||
// occur at unexpected times.
|
||||
std::cerr << errs;
|
||||
update_source(*source);
|
||||
}
|
||||
}
|
||||
|
||||
void World::update_source(const util::LuaSourceVec &source) {
|
||||
assert(stack_is_clear());
|
||||
source_db_.update(source);
|
||||
assert(stack_is_clear());
|
||||
std::string errs = source_db_.rebuild();
|
||||
// I don't have a good place to send the error messages right
|
||||
// now. The engine needs a catch-all place to send errors that
|
||||
// occur at unexpected times.
|
||||
std::cerr << errs;
|
||||
assert(stack_is_clear());
|
||||
}
|
||||
|
||||
@@ -407,6 +411,10 @@ void World::invoke(const Invocation &inv) {
|
||||
break;
|
||||
case Invocation::KIND_TICK:
|
||||
invoke_tick(inv.actor(), inv.place(), inv.action(), inv.data());
|
||||
break;
|
||||
case Invocation::KIND_LUA_SOURCE:
|
||||
invoke_lua_source(inv.actor(), inv.place(), inv.action(), inv.data());
|
||||
break;
|
||||
default:
|
||||
// Do nothing. Standard behavior for any invalid command is to
|
||||
// simply do nothing at all. Perhaps eventually we may add a flag
|
||||
@@ -604,9 +612,25 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a
|
||||
}
|
||||
|
||||
void World::invoke_tick(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &data) {
|
||||
if (util::world_type_authoritative(world_type_)) {
|
||||
clock_ += 1;
|
||||
run_scheduled_threads();
|
||||
if (!util::world_type_authoritative(world_type_)) {
|
||||
return;
|
||||
}
|
||||
clock_ += 1;
|
||||
run_scheduled_threads();
|
||||
}
|
||||
|
||||
void World::invoke_lua_source(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &data) {
|
||||
if (!util::world_type_authoritative(world_type_)) {
|
||||
return;
|
||||
}
|
||||
// We need some kind of authentication here.
|
||||
try {
|
||||
StreamBuffer sb(action);
|
||||
util::LuaSourceVec sv;
|
||||
SourceDB::deserialize_source(&sv, &sb);
|
||||
update_source(sv);
|
||||
} catch (const StreamException &ex) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -196,7 +196,8 @@ public:
|
||||
// Special case: if the source pointer is nullptr, does not update.
|
||||
//
|
||||
void update_source(const util::LuaSourcePtr &source);
|
||||
|
||||
void update_source(const util::LuaSourceVec &source);
|
||||
|
||||
// Run all unit tests.
|
||||
//
|
||||
void run_unittests();
|
||||
@@ -277,6 +278,10 @@ private:
|
||||
//
|
||||
void invoke_tick(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &data);
|
||||
|
||||
// Invoke the lua_source operation.
|
||||
//
|
||||
void invoke_lua_source(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &data);
|
||||
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user