Working on diff xmission

This commit is contained in:
2021-08-23 23:34:30 -04:00
parent 7581ac7278
commit 2be6c2c58e
10 changed files with 702 additions and 149 deletions

View File

@@ -4,6 +4,7 @@
#include "animqueue.hpp"
#include "gui.hpp"
#include "traceback.hpp"
#include "tablecmp.hpp"
#include <iostream>
void World::store_global_pointer(lua_State *L, World *v) {
@@ -48,11 +49,11 @@ World::World(util::WorldType wt) {
Gui::store_global_pointer(state(), nullptr);
// Set the tabletype of the registry.
LS.settabletype(LuaRegistry, LuaStack::TAB_REGISTRY);
LS.settabletype(LuaRegistry, LUA_TT_REGISTRY);
// Set the tabletype of the global environment.
LS.getglobaltable(globtab);
LS.settabletype(globtab, LuaStack::TAB_GLOBALENV);
LS.settabletype(globtab, LUA_TT_GLOBALENV);
// Create the tangibles table in the registry.
LS.rawset(LuaRegistry, "tangibles", LuaNewTable);
@@ -114,25 +115,34 @@ World::TanVector World::tangible_get_all(const IdVector &ids) const {
return result;
}
Tangible *World::tangible_get(lua_State *L, int idx) {
Tangible *result = nullptr;
int top = lua_gettop(L);
if (lua_istable(L, idx)) {
lua_getmetatable(L, idx);
if (lua_istable(L, -1)) {
lua_pushstring(L, "id");
lua_rawget(L, -2);
lua_Number id = lua_tonumber(L, -1);
result = tangible_get(int64_t(id));
}
Tangible *World::tangible_get(const LuaStack &LS, LuaSlot tab) {
int64_t id = tangible_id(LS, tab);
if (id == 0) {
luaL_error(LS.state(), "parameter is not a tangible");
}
lua_settop(L, top);
Tangible *result = tangible_get(id);
if (result == nullptr) {
luaL_error(L, "parameter is not a tangible");
luaL_error(LS.state(), "parameter is not a tangible");
}
return result;
}
int64_t World::tangible_id(const LuaStack &LS, LuaSlot tab) {
int64_t id = 0;
if (LS.istable(tab) && LS.gettabletype(tab) == LUA_TT_TANGIBLE) {
lua_State *L = LS.state();
if (lua_getmetatable(L, tab.index())) {
lua_pushstring(L, "id");
lua_rawget(L, -2);
if (lua_type(L, -1) == LUA_TNUMBER) {
id = lua_tointeger(L, -1);
}
lua_pop(L, 2);
}
}
return id;
}
void World::tangible_delete(int64_t id) {
lua_State *L = state();
LuaVar tangibles, database;
@@ -153,6 +163,7 @@ void World::tangible_delete(int64_t id) {
// Clear out the database.
LS.clearmetatable(database);
LS.cleartable(database);
LS.settabletype(database, LUA_TT_DEADTANGIBLE);
// Remove the lua portion from the tangibles table.
LS.rawset(tangibles, id, LuaNil);
@@ -221,7 +232,7 @@ std::string World::numbered_tables_debug_string() const {
return oss.str();
}
std::string World::paired_tables_debug_string(lua_State *master, const TablePairing *pairing) const {
std::string World::paired_tables_debug_string(lua_State *master) const {
lua_State *synch = state();
LuaVar mntmap, sntmap, mtab, stab, mtid, stid;
LuaStack MLS(master, mntmap, mtab, mtid);
@@ -232,26 +243,26 @@ std::string World::paired_tables_debug_string(lua_State *master, const TablePair
// Fetch the numbered tables map.
MLS.rawget(mntmap, LuaRegistry, "ntmap");
SLS.rawget(sntmap, LuaRegistry, "ntmap");
int m_ntables = MLS.rawlen(mntmap);
int s_ntables = MLS.rawlen(sntmap);
assert(m_ntables == s_ntables);
for (int i = 1; i < pairing->mpair.size(); i++) {
if (pairing->mpair[i] == 0) continue;
for (int i = 1; i <= m_ntables; i++) {
MLS.rawget(mtab, mntmap, i);
SLS.rawget(stab, sntmap, pairing->mpair[i]);
std::string mname = "unknown";
std::string sname = "unknown";
if (MLS.istable(mtab)) {
SLS.rawget(stab, sntmap, i);
if (MLS.istable(mtab) && SLS.istable(stab)) {
std::string mname = "unknown";
std::string sname = "unknown";
MLS.rawget(mtid, mtab, "TID");
if (MLS.isstring(mtid)) {
mname = MLS.ckstring(mtid);
}
}
if (SLS.istable(stab)) {
SLS.rawget(stid, stab, "TID");
if (SLS.isstring(stid)) {
sname = SLS.ckstring(stid);
}
result.push_back(std::make_pair(mname, sname));
}
result.push_back(std::make_pair(mname, sname));
}
MLS.result();
SLS.result();
@@ -376,8 +387,8 @@ Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) {
LS.setmetatable(database, metatab);
// Mark the tangible using the tabletype field.
LS.settabletype(database, LuaStack::TAB_TANGIBLE);
LS.settabletype(metatab, LuaStack::TAB_TANGIBLEMETA);
LS.settabletype(database, LUA_TT_TANGIBLE);
LS.settabletype(metatab, LUA_TT_TANGIBLEMETA);
// Store the database into the tangibles table.
LS.rawget(tangibles, LuaRegistry, "tangibles");
@@ -741,13 +752,11 @@ void World::difference_transmit(int64_t actor_id, World *master, StreamBuffer *s
// Number tables in both the master and the synchronous model.
// Meanwhile, the client will number tables in the client-synchronous model.
master->number_lua_tables(closetans);
int s_ntables = number_lua_tables(closetans);
number_lua_tables(closetans);
// Pair tables from the synchronous and master models.
TablePairing pairing;
pair_lua_tables(closetans, master->state(), &pairing);
int ncreate = pair_new_tables(&pairing);
sb->write_int32(s_ntables);
pair_lua_tables(closetans, master->state());
int ncreate = pair_new_tables(closetans, master->state());
sb->write_int32(ncreate);
create_new_tables(ncreate);
@@ -761,8 +770,7 @@ void World::apply_differences(StreamBuffer *sb) {
util::HashValue closehash = util::hash_id_vector(closetans);
util::HashValue m_closehash = sb->read_hashvalue();
assert(closehash == m_closehash);
int s_ntables = number_lua_tables(closetans);
assert(s_ntables == sb->read_int32());
number_lua_tables(closetans);
int ncreate = sb->read_int32();
create_new_tables(ncreate);
}
@@ -890,19 +898,12 @@ int World::number_lua_tables(const IdVector &basis) {
for (int64_t id : basis) {
LS.rawget(tab, tangibles, id);
assert(LS.istable(tab));
// Maybe I should traverse the metatable?
// Traverse subtables.
LS.set(key, LuaNil);
while (LS.next(tab, key, val)) {
// if (LS.isstring(key)) {
// std::cerr << "Visiting tangible " << LS.ckstring(key) << std::endl;
// } else {
// std::cerr << "Visiting tangible xxxx" << std::endl;
// }
if (LS.istable(val) && LS.gettabletype(val)==LuaStack::TAB_GENERAL) {
if (LS.istable(val) && LS.gettabletype(val)==LUA_TT_GENERAL) {
lua_checkstack(L, 10);
lua_pushvalue(L, val.index());
// std::cerr << "Stack: " << lua_gettop(L) - top << std::endl;
}
}
}
@@ -910,7 +911,6 @@ int World::number_lua_tables(const IdVector &basis) {
// Pop tables from the stack one by one. If the table is not
// already numbered, number it and push subtables onto the stack.
while (lua_gettop(L) > top) {
//std::cerr << "Popping stack with " << lua_gettop(L) - top << std::endl;
lua_replace(L, tab.index());
LS.rawget(xid, tnmap, tab);
if (LS.isnil(xid)) {
@@ -919,22 +919,16 @@ int World::number_lua_tables(const IdVector &basis) {
LS.rawset(ntmap, id, tab);
// Traverse the metatable.
LS.getmetatable(val, tab);
if (LS.istable(val) && LS.gettabletype(val)==LuaStack::TAB_GENERAL) {
if (LS.istable(val) && LS.gettabletype(val)==LUA_TT_GENERAL) {
lua_checkstack(L, 10);
lua_pushvalue(L, val.index());
}
// Traverse the subtables.
LS.set(key, LuaNil);
while (LS.next(tab, key, val)) {
// if (LS.isstring(key)) {
// std::cerr << "Visiting table " << LS.ckstring(key) << std::endl;
// } else {
// std::cerr << "Visiting table xxxx" << std::endl;
// }
if (LS.istable(val) && LS.gettabletype(val)==LuaStack::TAB_GENERAL) {
if (LS.istable(val) && LS.gettabletype(val)==LUA_TT_GENERAL) {
lua_checkstack(L, 10);
lua_pushvalue(L, val.index());
// std::cerr << "Stack: " << lua_gettop(L) - top << std::endl;
}
}
}
@@ -952,24 +946,37 @@ void World::unnumber_lua_tables() {
LS.rawset(LuaRegistry, "ntmap", LuaNil);
}
void World::pair_lua_tables(const IdVector &basis, lua_State *master, TablePairing *pairing) {
void World::pair_lua_tables(const IdVector &basis, lua_State *master) {
lua_State *synch = state();
LuaVar stangibles, mtangibles, sntmap, mntmap, stnmap, mtnmap, stab, mtab, skey, mkey, sval, mval, sidx, midx;
LuaStack SLS(synch, stangibles, stab, skey, sval, sntmap, stnmap, sidx);
LuaStack MLS(master, mtangibles, mtab, mkey, mval, mntmap, mtnmap, midx);
// Fetch the tangible databases
SLS.rawget(stangibles, LuaRegistry, "tangibles");
MLS.rawget(mtangibles, LuaRegistry, "tangibles");
// Fetch the synchronous model tnmap and ntmap
SLS.rawget(stnmap, LuaRegistry, "tnmap");
MLS.rawget(mtnmap, LuaRegistry, "tnmap");
SLS.rawget(sntmap, LuaRegistry, "ntmap");
MLS.rawget(mntmap, LuaRegistry, "ntmap");
assert(SLS.istable(stnmap));
assert(MLS.istable(mtnmap));
assert(SLS.istable(sntmap));
assert(MLS.istable(mntmap));
pairing->mpair.assign(MLS.rawlen(mntmap) + 1, 0);
pairing->spair.assign(SLS.rawlen(sntmap) + 1, 0);
// Initialize the master model tnmap and ntmap
MLS.set(mtnmap, LuaNewTable);
MLS.set(mntmap, LuaNewTable);
MLS.rawset(LuaRegistry, "tnmap", mtnmap);
MLS.rawset(LuaRegistry, "ntmap", mntmap);
int s_ntables = SLS.rawlen(sntmap);
for (int i = 1; i <= s_ntables; i++) {
MLS.rawset(mntmap, i, 0);
}
// Keep track of which tables are already paired
std::vector<bool> paired;
paired.assign(s_ntables + 1, false);
// This records the top of the stack.
int mtop = lua_gettop(master);
for (int64_t id : basis) {
@@ -981,8 +988,7 @@ void World::pair_lua_tables(const IdVector &basis, lua_State *master, TablePairi
while (MLS.next(mtab, mkey, mval)) {
if (!MLS.issortablekey(mkey)) continue;
if (!MLS.istable(mval)) continue;
MLS.movesortablekey(mkey, synch);
lua_replace(synch, skey.index());
MLS.movesortablekey(mkey, SLS, skey);
SLS.rawget(sval, stab, skey);
if (!SLS.istable(sval)) continue;
lua_checkstack(master, 20);
@@ -995,17 +1001,23 @@ void World::pair_lua_tables(const IdVector &basis, lua_State *master, TablePairi
while (lua_gettop(master) > mtop) {
lua_replace(master, mtab.index());
lua_replace(synch, stab.index());
// If the master table is not a general table, skip.
if (MLS.gettabletype(mtab) != LUA_TT_GENERAL) continue;
// If the master table is already paired, skip.
MLS.rawget(midx, mtnmap, mtab);
if (!MLS.isnumber(midx)) continue;
if (MLS.isnumber(midx)) continue;
// If the synch table is not a table, skip.
if (!SLS.istable(stab)) continue;
// If the synch table doesn't have a number, skip.
SLS.rawget(sidx, stnmap, stab);
if (!SLS.isnumber(sidx)) continue;
int imidx = MLS.ckint(midx);
int isidx = SLS.ckint(sidx);
if (pairing->spair[isidx] != 0) continue;
if (pairing->mpair[imidx] != 0) continue;
pairing->spair[isidx] = imidx;
pairing->mpair[imidx] = isidx;
// Pair the metatables.
int idx = SLS.ckinteger(sidx);
assert((idx >= 1) && (idx <= s_ntables));
// Pair the tables.
MLS.rawset(mtnmap, mtab, idx);
MLS.rawset(mntmap, idx, mtab);
paired[idx] = true;
// Potentially pair the metatables.
MLS.getmetatable(mval, mtab);
if (MLS.istable(mval)) {
SLS.getmetatable(sval, stab);
@@ -1019,8 +1031,7 @@ void World::pair_lua_tables(const IdVector &basis, lua_State *master, TablePairi
while (MLS.next(mtab, mkey, mval)) {
if (!MLS.issortablekey(mkey)) continue;
if (!MLS.istable(mval)) continue;
MLS.movesortablekey(mkey, synch);
lua_replace(synch, skey.index());
MLS.movesortablekey(mkey, SLS, skey);
SLS.rawget(sval, stab, skey);
if (!SLS.istable(sval)) continue;
lua_checkstack(master, 20);
@@ -1034,16 +1045,71 @@ void World::pair_lua_tables(const IdVector &basis, lua_State *master, TablePairi
SLS.result();
}
int World::pair_new_tables(TablePairing *pairing) {
int orig = pairing->spair.size();
for (int i = 1; i <= pairing->mpair.size(); i++) {
int id = pairing->mpair[i];
if (id == 0) {
pairing->mpair[i] = pairing->spair.size();
pairing->spair.push_back(i);
int World::pair_new_tables(const IdVector &basis, lua_State *master) {
// This is conceptually recursive, but we're going to use an
// explicit stack (the lua stack).
lua_State *L = master;
LuaVar tnmap, ntmap, tangibles, tab, key, val, xid;
LuaStack LS(L, tnmap, ntmap, tangibles, tab, key, val, xid);
LS.rawget(tnmap, LuaRegistry, "tnmap");
LS.rawget(ntmap, LuaRegistry, "ntmap");
LS.rawget(tangibles, LuaRegistry, "tangibles");
int ntables = LS.rawlen(ntmap);
std::vector<bool> visited;
visited.assign(ntables + 1, false);
int top = lua_gettop(L);
// Push all subtables onto the stack. Note that we may push
// the same table twice, that's OK.
for (int64_t id : basis) {
LS.rawget(tab, tangibles, id);
assert(LS.istable(tab));
LS.set(key, LuaNil);
while (LS.next(tab, key, val)) {
if (LS.istable(val) && LS.gettabletype(val)==LUA_TT_GENERAL) {
lua_checkstack(L, 10);
lua_pushvalue(L, val.index());
}
}
}
return pairing->spair.size() - orig;
// Pop tables from the stack one by one. If the table is not
// numbered, number it. If it is not visited, visit it.
while (lua_gettop(L) > top) {
lua_replace(L, tab.index());
int id = 0;
LS.rawget(xid, tnmap, tab);
if (!LS.isnumber(xid)) {
id = visited.size();
LS.rawset(tnmap, tab, id);
LS.rawset(ntmap, id, tab);
visited.push_back(false);
} else {
id = LS.cknumber(xid);
assert((id >= 0) && (id < int(visited.size())));
}
if (!visited[id]) {
visited[id] = true;
// Traverse the metatable.
LS.getmetatable(val, tab);
if (LS.istable(val) && LS.gettabletype(val)==LUA_TT_GENERAL) {
lua_checkstack(L, 10);
lua_pushvalue(L, val.index());
}
// Traverse the subtables.
LS.set(key, LuaNil);
while (LS.next(tab, key, val)) {
if (LS.istable(val) && LS.gettabletype(val)==LUA_TT_GENERAL) {
lua_checkstack(L, 10);
lua_pushvalue(L, val.index());
}
}
}
}
LS.result();
assert(stack_is_clear());
return visited.size() - 1 - ntables;
}
void World::create_new_tables(int n) {
@@ -1065,12 +1131,87 @@ void World::create_new_tables(int n) {
assert(stack_is_clear());
}
void World::diff_lua_tables(lua_State *master, StreamBuffer *sb) {
lua_State *synch = state();
LuaVar sntmap, mntmap, stnmap, mtnmap;
LuaStack SLS(synch, sntmap, stnmap);
LuaStack MLS(master, mntmap, mtnmap);
SLS.rawget(sntmap, LuaRegistry, "ntmap");
MLS.rawget(mntmap, LuaRegistry, "ntmap");
SLS.rawget(stnmap, LuaRegistry, "tnmap");
MLS.rawget(mtnmap, LuaRegistry, "tnmap");
int m_ntables = MLS.rawlen(mntmap);
int s_ntables = SLS.rawlen(sntmap);
assert(m_ntables == s_ntables);
sb->write_int32(0);
int write_count_after = sb->total_writes();
int nmodified = 0;
int s_top = lua_gettop(synch);
int m_top = lua_gettop(master);
for (int id = 1; id <= m_ntables; id++) {
lua_pushvalue(master, mtnmap.index());
lua_rawgeti(master, mtnmap.index(), id);
if (lua_type(master, -1) == LUA_TTABLE) {
lua_pushvalue(synch, stnmap.index());
lua_rawgeti(synch, sntmap.index(), id);
int tw = sb->total_writes();
sb->write_int32(id);
nmodified += 1;
if (!tablecmp_diff(synch, master, true, sb)) {
sb->unwrite_to(tw);
nmodified -= 1;
}
assert(lua_gettop(synch) == s_top);
assert(lua_gettop(master) == m_top);
} else {
lua_pop(master, 2);
}
}
sb->overwrite_int32(write_count_after, nmodified);
}
void World::diff_tangible_databases(const IdVector &basis, lua_State *master, StreamBuffer *sb) {
lua_State *synch = state();
LuaVar stnmap, mtnmap, stangibles, mtangibles;
LuaStack SLS(synch, stnmap, stangibles);
LuaStack MLS(master, mtnmap, mtangibles);
SLS.rawget(stnmap, LuaRegistry, "tnmap");
MLS.rawget(mtnmap, LuaRegistry, "tnmap");
SLS.rawget(stangibles, LuaRegistry, "tangibles");
MLS.rawget(mtangibles, LuaRegistry, "tangibles");
sb->write_int32(0);
int write_count_after = sb->total_writes();
int nmodified = 0;
int s_top = lua_gettop(synch);
int m_top = lua_gettop(master);
for (int64_t id : basis) {
lua_pushvalue(master, mtnmap.index());
lua_rawgeti(master, mtangibles.index(), id);
lua_pushvalue(synch, stnmap.index());
lua_rawgeti(synch, stangibles.index(), id);
int tw = sb->total_writes();
sb->write_int64(id);
nmodified += 1;
if (!tablecmp_diff(synch, master, false, sb)) {
sb->unwrite_to(tw);
nmodified -= 1;
}
assert(lua_gettop(synch) == s_top);
assert(lua_gettop(master) == m_top);
}
sb->overwrite_int32(write_count_after, nmodified);
}
LuaDefine(tangible_animstate, "c") {
LuaArg tanobj;
LuaRet graphic, plane, x, y, z, facing;
LuaStack LS(L, tanobj, graphic, plane, x, y, z, facing);
World *w = World::fetch_global_pointer(L);
Tangible *tan = w->tangible_get(L, tanobj.index());
Tangible *tan = w->tangible_get(LS, tanobj);
const AnimStep &aqback = tan->anim_queue_.back();
LS.set(graphic, aqback.graphic());
LS.set(plane, aqback.plane());
@@ -1085,7 +1226,7 @@ LuaDefine(tangible_animate, "c") {
LuaArg tanobj, config;
LuaStack LS(L, tanobj, config);
World *w = World::fetch_global_pointer(L);
Tangible *tan = w->tangible_get(L, tanobj.index());
Tangible *tan = w->tangible_get(LS, tanobj);
int64_t id = w->id_global_pool_.alloc_id_for_thread(L);
const AnimStep &prev = tan->anim_queue_.back();
AnimStep step;
@@ -1103,7 +1244,7 @@ LuaDefine(tangible_setclass, "c") {
LuaVar classtab, mt;
LuaStack LS(L, tanobj, classname, classtab, mt);
World *w = World::fetch_global_pointer(L);
w->tangible_get(L, tanobj.index());
w->tangible_get(LS, tanobj);
LS.getclass(classtab, classname);
LS.getmetatable(mt, tanobj);
LS.rawset(mt, "__index", classtab);
@@ -1114,7 +1255,7 @@ LuaDefine(tangible_delete, "c") {
LuaArg tanobj;
LuaStack LS(L, tanobj);
World *w = World::fetch_global_pointer(L);
Tangible *tan = w->tangible_get(L, tanobj.index());
Tangible *tan = w->tangible_get(LS, tanobj);
assert(tan != nullptr); // this should be checked above.
if (tan->is_an_actor()) {
luaL_error(L, "Cannot delete a player using tangible.delete, use tangible.redirect instead.");
@@ -1188,14 +1329,14 @@ LuaDefine(tangible_redirect, "c") {
LuaStack LS(L, actor1, actor2, bldz);
World *w = World::fetch_global_pointer(L);
bool bulldoze = LS.ckboolean(bldz);
Tangible *tan1 = w->tangible_get(L, actor1.index());
Tangible *tan1 = w->tangible_get(LS, actor1);
if (!tan1->is_an_actor()) {
luaL_error(L, "redirect source is not an actor");
}
if (LS.isnil(actor2)) {
w->redirects_[tan1->id()] = 0;
} else {
Tangible *tan2 = w->tangible_get(L, actor2.index());
Tangible *tan2 = w->tangible_get(LS, actor2);
tan2->configure_id_pool_for_actor();
w->redirects_[tan1->id()] = tan2->id();
}
@@ -1205,6 +1346,14 @@ LuaDefine(tangible_redirect, "c") {
return LS.result();
}
LuaDefine(tangible_id, "c") {
LuaArg tanobj;
LuaRet id;
LuaStack LS(L, tanobj, id);
LS.set(id, World::tangible_id(LS, tanobj));
return LS.result();
}
LuaDefine(world_wait, "f") {
if ((lua_gettop(L) != 1) || (lua_type(L, -1) != LUA_TNUMBER)) {
luaL_error(L, "Argument to wait must be a number.");
@@ -1217,16 +1366,12 @@ LuaDefine(world_getregistry, "f") {
return 1;
}
LuaDefine(world_gettabletype, "f") {
LuaDefine(world_xtype, "f") {
LuaArg tab;
LuaRet ttype;
LuaStack LS(L, tab, ttype);
if (LS.istable(tab)) {
LuaStack::TableType tt = LS.gettabletype(tab);
LS.set(ttype, int(tt));
} else {
luaL_error(L, "Not a table");
}
LuaRet rtype;
LuaStack LS(L, tab, rtype);
int xt = LS.xtype(tab);
LS.set(rtype, xt);
return LS.result();
}
@@ -1237,10 +1382,10 @@ LuaDefine(world_settabletype, "f") {
luaL_error(L, "Not a table");
}
int tt = LS.ckinteger(ttype);
if ((tt < 0) || (tt > 15)) {
if ((tt < LUA_TT_GENERAL) || (tt > LUA_TT_CLASS)) {
luaL_error(L, "table type out of range");
}
LS.settabletype(tab, LuaStack::TableType(tt));
LS.settabletype(tab, tt);
return LS.result();
}
@@ -1255,7 +1400,7 @@ static bool worlds_identical(const std::unique_ptr<World> &w1, const std::unique
LuaDefine(unittests_world, "c") {
std::unique_ptr<World> m, ss, cs;
StreamBuffer sb;
int m_ntables, s_ntables, ncreate;
int ncreate;
// Test the numbering of lua tables. We create some general
// tables using tangible_set_string. Then we install some
@@ -1270,8 +1415,7 @@ LuaDefine(unittests_world, "c") {
m->tangible_set_string(123, "inventory.cplx.TID", "inventory.cplx");
m->tangible_copy_global(123, "math", "math");
m->tangible_copy_global(123, "gltab", "_G");
m_ntables = m->number_lua_tables(util::id_vector_create(123));
// LuaAssert(L, m_ntables == 7);
m->number_lua_tables(util::id_vector_create(123));
LuaAssertStrEq(L, m->numbered_tables_debug_string(),
"inventory;inventory.cplx;skills;skills.leet;transactions;");
@@ -1286,23 +1430,21 @@ LuaDefine(unittests_world, "c") {
ss->tangible_set_string(123, "skills.leet.TID", "skills.leet");
ss->tangible_set_string(123, "math.TID", "math");
ss->tangible_set_string(123, "gltab.TID", "gltab");
s_ntables = ss->number_lua_tables(util::id_vector_create(123));
LuaAssert(L, s_ntables == 6);
ss->number_lua_tables(util::id_vector_create(123));
LuaAssertStrEq(L, ss->numbered_tables_debug_string(),
"gltab;inventory;math;skills;skills.crap;skills.leet;");
World::TablePairing pairing;
ss->pair_lua_tables(util::id_vector_create(123), m->state(), &pairing);
LuaAssertStrEq(L, ss->paired_tables_debug_string(m->state(), &pairing),
ss->pair_lua_tables(util::id_vector_create(123), m->state());
LuaAssertStrEq(L, ss->paired_tables_debug_string(m->state()),
"inventory=inventory;skills=skills;skills.leet=skills.leet;");
// Test the creation of new tables during difference transmission.
// The master world model above has two tables that couldn't be paired
// to the client: inventory.cplx, and transactions. These two tables
// should be paired to new, created tables.
ncreate = m->pair_new_tables(&pairing);
ncreate = m->pair_new_tables(util::id_vector_create(123), m->state());
LuaAssert(L, ncreate == 2);
ss->create_new_tables(ncreate);
LuaAssertStrEq(L, ss->paired_tables_debug_string(m->state(), &pairing),
LuaAssertStrEq(L, ss->paired_tables_debug_string(m->state()),
"inventory=inventory;inventory.cplx=unknown;skills=skills;skills.leet=skills.leet;transactions=unknown;");
// Create new clean world models.