First attempt at error-resistant /cpl directive
This commit is contained in:
@@ -13,5 +13,5 @@ RestoreOpenAssetTabsOnRestart=AlwaysRestore
|
|||||||
AutoSaveWarningInSeconds=0
|
AutoSaveWarningInSeconds=0
|
||||||
|
|
||||||
[/Script/Integration.lxProjectSettings]
|
[/Script/Integration.lxProjectSettings]
|
||||||
ActiveServer=/Game/Luprex/KnownServers/SS_Localhost.SS_Localhost
|
ActiveServer=/Game/Luprex/KnownServers/SS_Standalone.SS_Standalone
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ lua_State *LuaCoreStack::newstate (lua_Alloc allocf) {
|
|||||||
LS.rawset(LuaRegistry, "persist", LuaNewTable);
|
LS.rawset(LuaRegistry, "persist", LuaNewTable);
|
||||||
LS.rawset(LuaRegistry, "unpersist", LuaNewTable);
|
LS.rawset(LuaRegistry, "unpersist", LuaNewTable);
|
||||||
LS.rawset(LuaRegistry, "funcnames", LuaNewTable);
|
LS.rawset(LuaRegistry, "funcnames", LuaNewTable);
|
||||||
|
LS.rawset(LuaRegistry, "sourcedb", LuaNewTable);
|
||||||
|
|
||||||
// Tag the registry and global environment with their tabletypes.
|
// Tag the registry and global environment with their tabletypes.
|
||||||
LS.settabletype(LuaRegistry, LUA_TT_REGISTRY);
|
LS.settabletype(LuaRegistry, LUA_TT_REGISTRY);
|
||||||
|
|||||||
@@ -132,16 +132,6 @@ static void get_info_table(LuaCoreStack &LS, LuaSlot db, LuaSlot info, const eng
|
|||||||
LS.rawset(info, "name", fn);
|
LS.rawset(info, "name", fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calculate_loadresult(LuaCoreStack &LS0, LuaSlot info, const eng::string &fn, const eng::string &code) {
|
|
||||||
LuaVar loadresult;
|
|
||||||
LuaExtStack LS(LS0.state(), loadresult);
|
|
||||||
if (code == "") {
|
|
||||||
LS.rawset(info, "loadresult", "missing or empty source file");
|
|
||||||
} else {
|
|
||||||
LS.load(loadresult, code, fn);
|
|
||||||
LS.rawset(info, "loadresult", loadresult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
@@ -202,8 +192,8 @@ void SourceDB::diff(const SourceDB &auth, StreamBuffer *sb) {
|
|||||||
|
|
||||||
bool SourceDB::patch(StreamBuffer *sb, DebugCollector *dbc) {
|
bool SourceDB::patch(StreamBuffer *sb, DebugCollector *dbc) {
|
||||||
lua_State *L = lua_state_;
|
lua_State *L = lua_state_;
|
||||||
LuaVar db, info;
|
LuaVar db, info, closure;
|
||||||
LuaExtStack LS(L, db, info);
|
LuaExtStack LS(L, db, info, closure);
|
||||||
LS.rawget(db, LuaRegistry, "sourcedb");
|
LS.rawget(db, LuaRegistry, "sourcedb");
|
||||||
int nupdates = sb->read_int32();
|
int nupdates = sb->read_int32();
|
||||||
for (int i = 0; i < nupdates; i++) {
|
for (int i = 0; i < nupdates; i++) {
|
||||||
@@ -219,24 +209,27 @@ bool SourceDB::patch(StreamBuffer *sb, DebugCollector *dbc) {
|
|||||||
if (code != "\001") {
|
if (code != "\001") {
|
||||||
LS.rawset(info, "code", code);
|
LS.rawset(info, "code", code);
|
||||||
LS.rawset(info, "hash", util::hash_to_hex(util::hash_string(code)));
|
LS.rawset(info, "hash", util::hash_to_hex(util::hash_string(code)));
|
||||||
calculate_loadresult(LS, info, fn, code);
|
LS.load(closure, code, fn);
|
||||||
|
LS.rawset(info, "loadresult", closure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (nupdates > 0) rebuild();
|
||||||
return (nupdates > 0);
|
return (nupdates > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourceDB::set(const eng::string &fn, const eng::string &code, int sequence) {
|
void SourceDB::set(const eng::string &fn, const eng::string &code, int sequence) {
|
||||||
lua_State *L = lua_state_;
|
lua_State *L = lua_state_;
|
||||||
LuaVar db, info;
|
LuaVar db, info, closure;
|
||||||
LuaExtStack LS(L, db, info);
|
LuaExtStack LS(L, db, info, closure);
|
||||||
LS.rawget(db, LuaRegistry, "sourcedb");
|
LS.rawget(db, LuaRegistry, "sourcedb");
|
||||||
get_info_table(LS, db, info, fn);
|
get_info_table(LS, db, info, fn);
|
||||||
LS.rawset(info, "sequence", sequence);
|
LS.rawset(info, "sequence", sequence);
|
||||||
LS.rawset(info, "code", code);
|
LS.rawset(info, "code", code);
|
||||||
LS.rawset(info, "fingerprint", "");
|
LS.rawset(info, "fingerprint", "");
|
||||||
LS.rawset(info, "hash", util::hash_to_hex(util::hash_string(code)));
|
LS.rawset(info, "hash", util::hash_to_hex(util::hash_string(code)));
|
||||||
calculate_loadresult(LS, info, fn, code);
|
LS.load(closure, code, fn);
|
||||||
|
LS.rawset(info, "loadresult", closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
eng::string SourceDB::get(const eng::string &fn) {
|
eng::string SourceDB::get(const eng::string &fn) {
|
||||||
@@ -262,19 +255,15 @@ eng::string SourceDB::get(const eng::string &fn) {
|
|||||||
return util::ss(seqno, ":", ccode, ":", cloadresult);
|
return util::ss(seqno, ":", ccode, ":", cloadresult);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourceDB::update(const util::LuaSourceVec &source) {
|
eng::string SourceDB::update(const util::LuaSourceVec &source) {
|
||||||
lua_State *L = lua_state_;
|
lua_State *L = lua_state_;
|
||||||
LuaVar sourcedb, info;
|
LuaVar newsourcedb, oldsourcedb, info, closure;
|
||||||
LuaExtStack LS(L, sourcedb, info);
|
LuaExtStack LS(L, newsourcedb, oldsourcedb, info, closure);
|
||||||
|
|
||||||
// Get and clear the source database.
|
eng::ostringstream errors;
|
||||||
LS.rawget(sourcedb, LuaRegistry, "sourcedb");
|
|
||||||
if (!LS.istable(sourcedb)) {
|
|
||||||
LS.newtable(sourcedb);
|
|
||||||
LS.rawset(LuaRegistry, "sourcedb", sourcedb);
|
|
||||||
}
|
|
||||||
LS.cleartable(sourcedb, true);
|
|
||||||
|
|
||||||
|
// Step one. Build the new sourcedb.
|
||||||
|
LS.newtable(newsourcedb);
|
||||||
for (int i = 0; i < int(source.size()); i++) {
|
for (int i = 0; i < int(source.size()); i++) {
|
||||||
const eng::string &file = source[i].first;
|
const eng::string &file = source[i].first;
|
||||||
const eng::string &code = source[i].second;
|
const eng::string &code = source[i].second;
|
||||||
@@ -283,9 +272,32 @@ void SourceDB::update(const util::LuaSourceVec &source) {
|
|||||||
LS.rawset(info, "code", code);
|
LS.rawset(info, "code", code);
|
||||||
LS.rawset(info, "hash", util::hash_to_hex(util::hash_string(code)));
|
LS.rawset(info, "hash", util::hash_to_hex(util::hash_string(code)));
|
||||||
LS.rawset(info, "sequence", i + 1);
|
LS.rawset(info, "sequence", i + 1);
|
||||||
calculate_loadresult(LS, info, file, code);
|
LS.load(closure, code, file);
|
||||||
LS.rawset(sourcedb, file, info);
|
LS.rawset(info, "loadresult", closure);
|
||||||
|
if (LS.isstring(closure)) {
|
||||||
|
errors << file << ":" << LS.ckstring(closure) << std::endl;
|
||||||
|
}
|
||||||
|
LS.rawset(newsourcedb, file, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there were compile errors, return the errors and don't update the env.
|
||||||
|
if (!errors.view().empty()) {
|
||||||
|
return errors.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache the old source database and store the new one.
|
||||||
|
LS.rawget(oldsourcedb, LuaRegistry, "sourcedb");
|
||||||
|
LS.rawset(LuaRegistry, "sourcedb", newsourcedb);
|
||||||
|
|
||||||
|
// Rebuild the source database.
|
||||||
|
eng::string rebuild_errors = rebuild();
|
||||||
|
|
||||||
|
// Restore the old state, if there were errors.
|
||||||
|
if (!rebuild_errors.empty()) {
|
||||||
|
LS.rawset(LuaRegistry, "sourcedb", oldsourcedb);
|
||||||
|
rebuild();
|
||||||
|
}
|
||||||
|
return rebuild_errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete everything from the global environment.
|
// Delete everything from the global environment.
|
||||||
@@ -411,14 +423,11 @@ eng::string SourceDB::get_source(const eng::string &fn)
|
|||||||
return LS.ckstring(code);
|
return LS.ckstring(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
eng::vector<eng::string> SourceDB::modules() {
|
eng::vector<eng::string> SourceDB::modules() {
|
||||||
eng::vector<eng::string> result;
|
eng::vector<eng::string> result;
|
||||||
LuaVar sourcedb, key, info, seq;
|
LuaVar sourcedb, key, info, seq;
|
||||||
LuaExtStack LS(lua_state_, sourcedb, key, info, seq);
|
LuaExtStack LS(lua_state_, sourcedb, key, info, seq);
|
||||||
|
|
||||||
result.push_back("CORE");
|
|
||||||
|
|
||||||
// Get the source database.
|
// Get the source database.
|
||||||
LS.rawget(sourcedb, LuaRegistry, "sourcedb");
|
LS.rawget(sourcedb, LuaRegistry, "sourcedb");
|
||||||
if (!LS.istable(sourcedb)) {
|
if (!LS.istable(sourcedb)) {
|
||||||
@@ -439,35 +448,38 @@ eng::vector<eng::string> SourceDB::modules() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourceDB::rebuild_core() {
|
eng::string SourceDB::rebuild_module(const eng::string &mod) {
|
||||||
|
LuaVar sourcedb, info, closure;
|
||||||
|
LuaExtStack LS(lua_state_, sourcedb, info, closure);
|
||||||
|
LS.rawget(sourcedb, LuaRegistry, "sourcedb");
|
||||||
|
LS.rawget(info, sourcedb, mod);
|
||||||
|
if (!LS.istable(info)) {
|
||||||
|
return util::ss("No such module: ", mod);
|
||||||
|
}
|
||||||
|
LS.rawget(closure, info, "loadresult");
|
||||||
|
if (!LS.isfunction(closure)) {
|
||||||
|
return util::ss(mod, ":", LS.ckstring(closure));
|
||||||
|
}
|
||||||
|
lua_pushvalue(lua_state_, closure.index());
|
||||||
|
return traceback_pcall(lua_state_, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
eng::string SourceDB::rebuild() {
|
||||||
source_clear_globals(lua_state_);
|
source_clear_globals(lua_state_);
|
||||||
source_load_cfunctions(lua_state_);
|
source_load_cfunctions(lua_state_);
|
||||||
source_load_cconstants(lua_state_);
|
source_load_cconstants(lua_state_);
|
||||||
|
|
||||||
|
eng::ostringstream errors;
|
||||||
|
|
||||||
|
for (const eng::string &mod: modules()) {
|
||||||
|
eng::string err = rebuild_module(mod);
|
||||||
|
if (!err.empty()) errors << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
rebuild_funcnames();
|
||||||
|
return errors.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
eng::string SourceDB::rebuild_module(const eng::string &mod) {
|
|
||||||
if (mod == "CORE") {
|
|
||||||
rebuild_core();
|
|
||||||
return "";
|
|
||||||
} else {
|
|
||||||
LuaVar sourcedb, info, closure;
|
|
||||||
LuaExtStack LS(lua_state_, sourcedb, info, closure);
|
|
||||||
LS.rawget(sourcedb, LuaRegistry, "sourcedb");
|
|
||||||
if (!LS.istable(sourcedb)) {
|
|
||||||
return "SourceDB not initialized";
|
|
||||||
}
|
|
||||||
LS.rawget(info, sourcedb, mod);
|
|
||||||
if (!LS.istable(info)) {
|
|
||||||
return util::ss("No such module: ", mod);
|
|
||||||
}
|
|
||||||
LS.rawget(closure, info, "loadresult");
|
|
||||||
if (!LS.isfunction(closure)) {
|
|
||||||
return util::ss(mod, ":", LS.ckstring(closure));
|
|
||||||
}
|
|
||||||
lua_pushvalue(lua_state_, closure.index());
|
|
||||||
return traceback_pcall(lua_state_, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SourceDB::init(lua_State *L) {
|
void SourceDB::init(lua_State *L) {
|
||||||
register_lua_builtins();
|
register_lua_builtins();
|
||||||
@@ -482,8 +494,7 @@ void SourceDB::init(lua_State *L) {
|
|||||||
LS.set(nullstring, "");
|
LS.set(nullstring, "");
|
||||||
LS.setmetatable(nullstring, classtab);
|
LS.setmetatable(nullstring, classtab);
|
||||||
|
|
||||||
// Rebuild the global environment.
|
rebuild();
|
||||||
rebuild_core();
|
|
||||||
|
|
||||||
// We need to register all C functions with the eris permanents tables.
|
// We need to register all C functions with the eris permanents tables.
|
||||||
LS.rawget(persist, LuaRegistry, "persist");
|
LS.rawget(persist, LuaRegistry, "persist");
|
||||||
@@ -516,15 +527,22 @@ void SourceDB::serialize_source(const util::LuaSourceVec &sv, StreamBuffer *sb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourceDB::deserialize_source(util::LuaSourceVec *sv, StreamBuffer *sb) {
|
util::LuaSourceVec SourceDB::deserialize_source(std::string_view datapack) {
|
||||||
sv->clear();
|
StreamBuffer sb(datapack);
|
||||||
int count = sb->read_int32();
|
util::LuaSourceVec sv;
|
||||||
if ((count < 0) || (count > 10000)) throw StreamCorruption();
|
try {
|
||||||
for (int i = 0; i < count; i++) {
|
sv.clear();
|
||||||
eng::string fn = sb->read_string();
|
int count = sb.read_int32();
|
||||||
eng::string code = sb->read_string();
|
if ((count < 0) || (count > 10000)) throw StreamCorruption();
|
||||||
sv->emplace_back(fn, code);
|
for (int i = 0; i < count; i++) {
|
||||||
|
eng::string fn = sb.read_string();
|
||||||
|
eng::string code = sb.read_string();
|
||||||
|
sv.emplace_back(fn, code);
|
||||||
|
}
|
||||||
|
} catch (const StreamException &ex) {
|
||||||
|
sv.clear();
|
||||||
}
|
}
|
||||||
|
return sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register lua builtins.
|
// Register lua builtins.
|
||||||
@@ -630,7 +648,6 @@ bool SourceDB::search_docs(const eng::string &substring, std::ostream &ostream)
|
|||||||
|
|
||||||
// Search the lua source code.
|
// Search the lua source code.
|
||||||
for (const eng::string &module : modules()) {
|
for (const eng::string &module : modules()) {
|
||||||
if (module == "CORE") continue;
|
|
||||||
eng::string code = get_source(module);
|
eng::string code = get_source(module);
|
||||||
if (code.empty()) continue;
|
if (code.empty()) continue;
|
||||||
util::StringVec lines = util::split_lines(code);
|
util::StringVec lines = util::split_lines(code);
|
||||||
|
|||||||
@@ -132,58 +132,31 @@ private:
|
|||||||
public:
|
public:
|
||||||
void init(lua_State *L);
|
void init(lua_State *L);
|
||||||
|
|
||||||
// Update
|
// modules()
|
||||||
//
|
//
|
||||||
// Update the database using the specified lua source code.
|
// Returns a list of all the lua modules, in the proper order.
|
||||||
// Compiles these files using lua's "load" function.
|
|
||||||
//
|
|
||||||
void update(const util::LuaSourceVec &source);
|
|
||||||
|
|
||||||
// modules
|
|
||||||
//
|
|
||||||
// Returns a list of all the modules. The first item in the list
|
|
||||||
// is always the string "CORE" which represents the lua core
|
|
||||||
// functionality with all the builtins. This is then followed by
|
|
||||||
// all the lua sourcefiles in the correct order.
|
|
||||||
//
|
//
|
||||||
eng::vector<eng::string> modules();
|
eng::vector<eng::string> modules();
|
||||||
|
// Update
|
||||||
// get_source
|
|
||||||
//
|
//
|
||||||
// Get the source code for a given module.
|
// Try to compile and load the specified source. Then, rebuild the
|
||||||
|
// global environment.
|
||||||
//
|
//
|
||||||
eng::string get_source(const eng::string &fn);
|
// If this generates any errors, puts back the old code, and rebuilds
|
||||||
|
// the global environment using the old code.
|
||||||
// rebuild_module
|
|
||||||
//
|
//
|
||||||
// To rebuild the lua environment, fetch the module list, then
|
// Returns any error messages. If this returns empty string, it means
|
||||||
// call rebuild_module on each module in turn. This will return
|
// there were no errors and the code was successfully update. If there
|
||||||
// an error message for the module, or empty string if no error.
|
// are any error messages, it means we restored the old code as best as
|
||||||
|
// possible.
|
||||||
//
|
//
|
||||||
// This is a thin wrapper around traceback_pcall. The return
|
eng::string update(const util::LuaSourceVec &source);
|
||||||
// value is the return value of traceback_pcall.
|
|
||||||
//
|
|
||||||
eng::string rebuild_module(const eng::string &mod);
|
|
||||||
|
|
||||||
// rebuild_core
|
|
||||||
//
|
|
||||||
// This is equivalent to rebuild_module("CORE"). Clears the environment
|
|
||||||
// and installs all the builtins. No error conditions.
|
|
||||||
//
|
|
||||||
void rebuild_core();
|
|
||||||
|
|
||||||
// rebuild_funcnames
|
|
||||||
//
|
|
||||||
// Traverses the global environment and populates the registry "funcnames"
|
|
||||||
// table, mapping each closure to its name.
|
|
||||||
//
|
|
||||||
void rebuild_funcnames();
|
|
||||||
|
|
||||||
// Difference transmission.
|
// Difference transmission.
|
||||||
//
|
//
|
||||||
// Note: The patch routine applies the differences to the source
|
// Note: The patch routine applies the differences to the source
|
||||||
// database, and if there are any changes, it does a source rebuild.
|
// database, and if there are any changes, it does a source rebuild.
|
||||||
// The patch routine returns true if anything was modified.
|
//
|
||||||
//
|
//
|
||||||
void diff(const SourceDB &auth, StreamBuffer *sb);
|
void diff(const SourceDB &auth, StreamBuffer *sb);
|
||||||
bool patch(StreamBuffer *sb, DebugCollector *dbc);
|
bool patch(StreamBuffer *sb, DebugCollector *dbc);
|
||||||
@@ -213,7 +186,54 @@ public:
|
|||||||
// Serialize and unserialize a source vector.
|
// Serialize and unserialize a source vector.
|
||||||
//
|
//
|
||||||
static void serialize_source(const util::LuaSourceVec &sv, StreamBuffer *sb);
|
static void serialize_source(const util::LuaSourceVec &sv, StreamBuffer *sb);
|
||||||
static void deserialize_source(util::LuaSourceVec *sv, StreamBuffer *sb);
|
static util::LuaSourceVec deserialize_source(std::string_view datapack);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Internal implementation stuff.
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// rebuild
|
||||||
|
//
|
||||||
|
// Rebuild the global environment from the sourcedb:
|
||||||
|
//
|
||||||
|
// * Clears the environment
|
||||||
|
// * Installs the builtins
|
||||||
|
// * Executes all the closures in the sourcedb.
|
||||||
|
// * Regenerates the function-names table.
|
||||||
|
//
|
||||||
|
// The closures may generate errors, if so, this returns the error
|
||||||
|
// messages. Note that if there are errors, there is no automatic cleanup.
|
||||||
|
//
|
||||||
|
eng::string rebuild();
|
||||||
|
|
||||||
|
// get_source
|
||||||
|
//
|
||||||
|
// Get the source code for a given module.
|
||||||
|
//
|
||||||
|
eng::string get_source(const eng::string &fn);
|
||||||
|
|
||||||
|
// rebuild_module
|
||||||
|
//
|
||||||
|
// To rebuild the lua environment, fetch the module list, then
|
||||||
|
// call rebuild_module on each module in turn. This will return
|
||||||
|
// an error message for the module, or empty string if no error.
|
||||||
|
//
|
||||||
|
// This is a thin wrapper around traceback_pcall. The return
|
||||||
|
// value is the return value of traceback_pcall.
|
||||||
|
//
|
||||||
|
eng::string rebuild_module(const eng::string &mod);
|
||||||
|
|
||||||
|
|
||||||
|
// rebuild_funcnames
|
||||||
|
//
|
||||||
|
// Traverses the global environment and populates the registry "funcnames"
|
||||||
|
// table, mapping each closure to its name.
|
||||||
|
//
|
||||||
|
void rebuild_funcnames();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ public:
|
|||||||
virtual void event_access(AccessKind kind, int64_t place_id, std::string_view datapk, StreamBuffer *retpk) override {
|
virtual void event_access(AccessKind kind, int64_t place_id, std::string_view datapk, StreamBuffer *retpk) override {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case AccessKind::INVOKE_LUA_SOURCE: {
|
case AccessKind::INVOKE_LUA_SOURCE: {
|
||||||
world_->update_source(datapk, 0);
|
Invocation inv(kind, place_id, place_id, datapk);
|
||||||
|
world_->invoke(0, inv);
|
||||||
run_unittests(world_->state());
|
run_unittests(world_->state());
|
||||||
stop_driver();
|
stop_driver();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -572,71 +572,6 @@ void World::probe_lua_call(int64_t actor_id, int64_t place_id, std::string_view
|
|||||||
clear_lthread_state();
|
clear_lthread_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This is called from World::update_source, and also
|
|
||||||
// from World::patch_source in the difference transmitter.
|
|
||||||
//
|
|
||||||
// When called from the difference transmitter, we suppress
|
|
||||||
// error messages.
|
|
||||||
//
|
|
||||||
// For the moment, errors are channeled to util::dprint,
|
|
||||||
// and 'print' statements just go to std::cerr. Neither
|
|
||||||
// of these is ideal. We need to get serious about setting
|
|
||||||
// up error handling.
|
|
||||||
//
|
|
||||||
// We also need to figure out a solution for what happens if
|
|
||||||
// some lua source file tries to modify, say, tangible state
|
|
||||||
// in top-level code.
|
|
||||||
//
|
|
||||||
bool World::rebuild_sourcedb(int64_t actor_id) {
|
|
||||||
int successes = 0;
|
|
||||||
int failures = 0;
|
|
||||||
for (const eng::string &mod: source_db_.modules()) {
|
|
||||||
open_lthread_state(0, 0, 0, false);
|
|
||||||
eng::string err = source_db_.rebuild_module(mod);
|
|
||||||
eng::string prints = lthread_prints_.str();
|
|
||||||
clear_lthread_state();
|
|
||||||
if (err.empty()) successes ++;
|
|
||||||
else failures ++;
|
|
||||||
if ((!err.empty()) || (!prints.empty())) {
|
|
||||||
lthread_prints_ << "Compiling " << mod << ":" << std::endl;
|
|
||||||
if (!err.empty()) lthread_prints_ << err << std::endl;
|
|
||||||
if (!prints.empty()) lthread_prints_ << prints;
|
|
||||||
util::dprintview(lthread_prints_.view());
|
|
||||||
if (actor_id != 0) lthread_prints_to_actor(actor_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
source_db_.rebuild_funcnames();
|
|
||||||
lthread_prints_ << "Compiled " << successes << " modules successfully." << std::endl;
|
|
||||||
if (failures > 0) {
|
|
||||||
lthread_prints_ << "Compiled " << failures << " modules with errors." << std::endl;
|
|
||||||
}
|
|
||||||
util::dprintview(lthread_prints_.view());
|
|
||||||
if (actor_id > 0) lthread_prints_to_actor(actor_id);
|
|
||||||
return (failures == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool World::update_source(const util::LuaSourceVec &source, int64_t actor_id) {
|
|
||||||
assert(stack_is_clear());
|
|
||||||
source_db_.update(source);
|
|
||||||
return rebuild_sourcedb(actor_id);
|
|
||||||
assert(stack_is_clear());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool World::update_source(std::string_view sourcepack, int64_t actor_id) {
|
|
||||||
if (sourcepack.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
StreamBuffer sb(sourcepack);
|
|
||||||
util::LuaSourceVec sv;
|
|
||||||
SourceDB::deserialize_source(&sv, &sb);
|
|
||||||
return update_source(sv, actor_id);
|
|
||||||
} catch (const StreamException &ex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::http_response(const HttpParser &response) {
|
void World::http_response(const HttpParser &response) {
|
||||||
// Find the request.
|
// Find the request.
|
||||||
auto iter = http_requests_.find(response.request_id());
|
auto iter = http_requests_.find(response.request_id());
|
||||||
@@ -1019,14 +954,27 @@ void World::invoke_lua_source(int64_t actor_id, int64_t place_id, std::string_vi
|
|||||||
if (actor_id != place_id) return;
|
if (actor_id != place_id) return;
|
||||||
|
|
||||||
// Check if this is the first time we're loading the source.
|
// Check if this is the first time we're loading the source.
|
||||||
bool brand_new = (source_db_.modules().size() == 1);
|
bool brand_new = (source_db_.modules().size() == 0);
|
||||||
|
|
||||||
// Compile and load the source.
|
// Deserialize the datapack.
|
||||||
bool success = update_source(datapack, actor_id);
|
util::LuaSourceVec sv = SourceDB::deserialize_source(datapack);
|
||||||
|
if (sv.empty()) return;
|
||||||
|
|
||||||
|
// Try to compile the code.
|
||||||
|
open_lthread_state(actor_id, actor_id, 0, false);
|
||||||
|
eng::string errors = source_db_.update(sv);
|
||||||
|
|
||||||
|
if (errors.empty()) {
|
||||||
|
lthread_prints_ << "Compiled source successfully.\n";
|
||||||
|
} else {
|
||||||
|
lthread_prints_ << "Compiling source: \n" << errors;
|
||||||
|
}
|
||||||
|
util::dprint(lthread_prints_.view());
|
||||||
|
lthread_prints_to_actor(actor_id);
|
||||||
|
|
||||||
// Call world.init
|
// Call world.init
|
||||||
if (brand_new) {
|
if (brand_new) {
|
||||||
if (success) {
|
if (errors.empty()) {
|
||||||
{
|
{
|
||||||
lua_State *L = state();
|
lua_State *L = state();
|
||||||
LuaVar lclass, lfunc;
|
LuaVar lclass, lfunc;
|
||||||
|
|||||||
@@ -290,11 +290,7 @@ void World::diff_tanclass(int64_t actor_id, World *master, StreamBuffer *xsb) {
|
|||||||
|
|
||||||
void World::patch_source(StreamBuffer *sb, DebugCollector *dbc) {
|
void World::patch_source(StreamBuffer *sb, DebugCollector *dbc) {
|
||||||
DebugBlock dbb(dbc, "patch_source");
|
DebugBlock dbb(dbc, "patch_source");
|
||||||
bool modified = source_db_.patch(sb, dbc);
|
source_db_.patch(sb, dbc);
|
||||||
if (modified) {
|
|
||||||
rebuild_sourcedb(0);
|
|
||||||
DebugLine(dbc) << "Source DB rebuilt";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::diff_source(World *master, StreamBuffer *sb) {
|
void World::diff_source(World *master, StreamBuffer *sb) {
|
||||||
@@ -359,6 +355,7 @@ void World::diff_globals(World *master, StreamBuffer *sb) {
|
|||||||
|
|
||||||
int64_t World::patch(StreamBuffer *sb, DebugCollector *dbc) {
|
int64_t World::patch(StreamBuffer *sb, DebugCollector *dbc) {
|
||||||
DebugBlock dbb(dbc, "patch");
|
DebugBlock dbb(dbc, "patch");
|
||||||
|
clear_lthread_state();
|
||||||
int64_t actor_id = patch_actor(sb, dbc);
|
int64_t actor_id = patch_actor(sb, dbc);
|
||||||
patch_visible(sb, dbc);
|
patch_visible(sb, dbc);
|
||||||
bool full = sb->read_bool();
|
bool full = sb->read_bool();
|
||||||
|
|||||||
@@ -242,23 +242,6 @@ public:
|
|||||||
//
|
//
|
||||||
SourceDB &get_source() { return source_db_; }
|
SourceDB &get_source() { return source_db_; }
|
||||||
|
|
||||||
// Rebuild the global environment from the source database.
|
|
||||||
//
|
|
||||||
// Error messages go to the specified actor, and also dprint.
|
|
||||||
//
|
|
||||||
// Returns true if the rebuild goes without errors.
|
|
||||||
//
|
|
||||||
bool rebuild_sourcedb(int64_t actor_id);
|
|
||||||
|
|
||||||
// Update the source database from disk, then rebuild the global environment.
|
|
||||||
//
|
|
||||||
// Error messages go to the specified actor, and also dprint.
|
|
||||||
//
|
|
||||||
// Returns true if the update goes without errors.
|
|
||||||
//
|
|
||||||
bool update_source(const util::LuaSourceVec &source, int64_t actor_id);
|
|
||||||
bool update_source(std::string_view sourcepk, int64_t actor_id);
|
|
||||||
|
|
||||||
// Supply an HTTP response to an outstanding HTTP request.
|
// Supply an HTTP response to an outstanding HTTP request.
|
||||||
//
|
//
|
||||||
void http_response(const HttpParser &response);
|
void http_response(const HttpParser &response);
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ function sphere.lookhotkeys(add)
|
|||||||
add("FaceR", "Sphere Yo", function () dprint("Doing Sphere Yo") end)
|
add("FaceR", "Sphere Yo", function () dprint("Doing Sphere Yo") end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function probe.getlookat()
|
function probe.getlookat()
|
||||||
local class = tangible.getclass(place)
|
local class = tangible.getclass(place)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user