Worked on code for difference transmission
This commit is contained in:
@@ -20,6 +20,7 @@ CPP_FILES=\
|
|||||||
cpp/streambuffer.cpp\
|
cpp/streambuffer.cpp\
|
||||||
cpp/source.cpp\
|
cpp/source.cpp\
|
||||||
cpp/world.cpp\
|
cpp/world.cpp\
|
||||||
|
cpp/world-accessor.cpp\
|
||||||
cpp/world-difftab.cpp\
|
cpp/world-difftab.cpp\
|
||||||
cpp/world-pairtab.cpp\
|
cpp/world-pairtab.cpp\
|
||||||
cpp/textgame.cpp\
|
cpp/textgame.cpp\
|
||||||
|
|||||||
@@ -200,7 +200,11 @@ static void pprint_r(Inspector &insp, int level, LuaSlot root) {
|
|||||||
pprint_r(insp, level + 1, key);
|
pprint_r(insp, level + 1, key);
|
||||||
(*insp.stream) << "]";
|
(*insp.stream) << "]";
|
||||||
}
|
}
|
||||||
(*insp.stream) << " = ";
|
if (insp.indent) {
|
||||||
|
(*insp.stream) << " = ";
|
||||||
|
} else {
|
||||||
|
(*insp.stream) << "=";
|
||||||
|
}
|
||||||
pprint_r(insp, level + 1, val);
|
pprint_r(insp, level + 1, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ bool string_quote(LuaStack &LS, LuaSlot val, std::ostream *os);
|
|||||||
// Maxlen specifies the maximum number of characters output. If
|
// Maxlen specifies the maximum number of characters output. If
|
||||||
// this is exceeded, then the printout is truncated.
|
// this is exceeded, then the printout is truncated.
|
||||||
//
|
//
|
||||||
void pprint(LuaStack &LS, LuaSlot val, int indent, int maxlen, std::ostream *os);
|
void pprint(LuaStack &LS, LuaSlot val, bool indent, std::ostream *os);
|
||||||
|
|
||||||
// The following lua interfaces to this code are included:
|
// The following lua interfaces to this code are included:
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -36,13 +36,13 @@ bool is_identifier(const std::string &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void quote_string(const std::string &s, std::ostream *os) {
|
void quote_string(const std::string &s, std::ostream *os) {
|
||||||
bool usesinglequote = false;
|
bool anysq = false;
|
||||||
|
bool anydq = false;
|
||||||
for (char c : s) {
|
for (char c : s) {
|
||||||
if (c == '"') {
|
if (c == '\'') anysq = true;
|
||||||
usesinglequote = true;
|
if (c == '"') anydq = true;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
bool usesinglequote = (!anysq)||(anydq);
|
||||||
(*os) << (usesinglequote ? '\'' : '"');
|
(*os) << (usesinglequote ? '\'' : '"');
|
||||||
for (char c : s) {
|
for (char c : s) {
|
||||||
if (c >= 32) {
|
if (c >= 32) {
|
||||||
|
|||||||
186
luprex/core/cpp/world-accessor.cpp
Normal file
186
luprex/core/cpp/world-accessor.cpp
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
|
||||||
|
#include "world.hpp"
|
||||||
|
|
||||||
|
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(LS, tanobj);
|
||||||
|
const AnimStep &aqback = tan->anim_queue_.back();
|
||||||
|
LS.set(graphic, aqback.graphic());
|
||||||
|
LS.set(plane, aqback.plane());
|
||||||
|
LS.set(x, aqback.xyz().x);
|
||||||
|
LS.set(y, aqback.xyz().y);
|
||||||
|
LS.set(z, aqback.xyz().z);
|
||||||
|
LS.set(facing, aqback.facing());
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaDefine(tangible_animate, "c") {
|
||||||
|
LuaArg tanobj, config;
|
||||||
|
LuaStack LS(L, tanobj, config);
|
||||||
|
World *w = World::fetch_global_pointer(L);
|
||||||
|
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;
|
||||||
|
step.from_lua(L, config.index(), prev);
|
||||||
|
if (step.action() == "") {
|
||||||
|
luaL_error(L, "animation action must be specified");
|
||||||
|
}
|
||||||
|
tan->anim_queue_.add(id, step);
|
||||||
|
tan->update_plane_item();
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaDefine(tangible_setclass, "c") {
|
||||||
|
LuaArg tanobj, classname;
|
||||||
|
LuaVar classtab, mt;
|
||||||
|
LuaStack LS(L, tanobj, classname, classtab, mt);
|
||||||
|
World *w = World::fetch_global_pointer(L);
|
||||||
|
w->tangible_get(LS, tanobj);
|
||||||
|
LS.getclass(classtab, classname);
|
||||||
|
LS.getmetatable(mt, tanobj);
|
||||||
|
LS.rawset(mt, "__index", classtab);
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaDefine(tangible_delete, "c") {
|
||||||
|
LuaArg tanobj;
|
||||||
|
LuaStack LS(L, tanobj);
|
||||||
|
World *w = World::fetch_global_pointer(L);
|
||||||
|
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.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
w->tangible_delete(tan->id());
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaDefine(tangible_build, "c") {
|
||||||
|
LuaArg config;
|
||||||
|
LuaVar classname, classtab, mt;
|
||||||
|
LuaRet database;
|
||||||
|
LuaStack LS(L, config, classname, classtab, database, mt);
|
||||||
|
|
||||||
|
LS.checktable(config);
|
||||||
|
// Get the class of the new tangible.
|
||||||
|
LS.rawget(classname, config, "class");
|
||||||
|
if (LS.isnil(classname)) {
|
||||||
|
luaL_error(L, "must specify a class name");
|
||||||
|
}
|
||||||
|
LS.getclass(classtab, classname);
|
||||||
|
|
||||||
|
// Parse the initial animation step.
|
||||||
|
AnimStep initstep, blank;
|
||||||
|
initstep.from_lua(L, config.index(), blank);
|
||||||
|
if (!initstep.has_xyz()) {
|
||||||
|
luaL_error(L, "You must specify (X,Y,Z) for new tangible");
|
||||||
|
}
|
||||||
|
if (!initstep.has_plane()) {
|
||||||
|
luaL_error(L, "You must specify plane for new tangible");
|
||||||
|
}
|
||||||
|
if (!initstep.has_graphic()) {
|
||||||
|
luaL_error(L, "You must specify graphic for new tangible");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: generate error if there's extra crap in the config table.
|
||||||
|
|
||||||
|
World *w = World::fetch_global_pointer(L);
|
||||||
|
Tangible *tan = w->tangible_make(L, 0, true);
|
||||||
|
lua_replace(L, database.index());
|
||||||
|
|
||||||
|
// Update the class of the new tangible.
|
||||||
|
LS.getmetatable(mt, database);
|
||||||
|
LS.rawset(mt, "__index", classtab);
|
||||||
|
|
||||||
|
// Update the animation queue and planemap of the new tangible.
|
||||||
|
int64_t stepid = w->id_global_pool_.alloc_id_for_thread(L);
|
||||||
|
tan->anim_queue_.add(stepid, initstep);
|
||||||
|
tan->update_plane_item();
|
||||||
|
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaDefine(tangible_get, "c") {
|
||||||
|
LuaArg id;
|
||||||
|
LuaVar tangibles;
|
||||||
|
LuaRet database;
|
||||||
|
LuaStack LS(L, id, tangibles, database);
|
||||||
|
int64_t nid = LS.ckinteger(id);
|
||||||
|
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
||||||
|
LS.rawget(database, tangibles, id);
|
||||||
|
if (!LS.istable(database)) {
|
||||||
|
luaL_error(L, "Not a tangible ID: %d", nid);
|
||||||
|
}
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaDefine(tangible_redirect, "c") {
|
||||||
|
LuaArg actor1, actor2, bldz;
|
||||||
|
LuaStack LS(L, actor1, actor2, bldz);
|
||||||
|
World *w = World::fetch_global_pointer(L);
|
||||||
|
bool bulldoze = LS.ckboolean(bldz);
|
||||||
|
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(LS, actor2);
|
||||||
|
tan2->configure_id_pool_for_actor();
|
||||||
|
w->redirects_[tan1->id()] = tan2->id();
|
||||||
|
}
|
||||||
|
if (bulldoze) {
|
||||||
|
w->tangible_delete(tan1->id());
|
||||||
|
}
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
return lua_yield(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaDefine(world_getregistry, "f") {
|
||||||
|
lua_pushvalue(L, LUA_REGISTRYINDEX);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaDefine(world_xtype, "f") {
|
||||||
|
LuaArg tab;
|
||||||
|
LuaRet rtype;
|
||||||
|
LuaStack LS(L, tab, rtype);
|
||||||
|
int xt = LS.xtype(tab);
|
||||||
|
LS.set(rtype, xt);
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaDefine(world_settabletype, "f") {
|
||||||
|
LuaArg tab, ttype;
|
||||||
|
LuaStack LS(L, tab, ttype);
|
||||||
|
if (!LS.istable(tab)) {
|
||||||
|
luaL_error(L, "Not a table");
|
||||||
|
}
|
||||||
|
int tt = LS.ckinteger(ttype);
|
||||||
|
if ((tt < LUA_TT_GENERAL) || (tt > LUA_TT_CLASS)) {
|
||||||
|
luaL_error(L, "table type out of range");
|
||||||
|
}
|
||||||
|
LS.settabletype(tab, tt);
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -341,6 +341,8 @@ void World::diff_numbered_tables(lua_State *master, StreamBuffer *sb) {
|
|||||||
assert(lua_gettop(master) == m_top);
|
assert(lua_gettop(master) == m_top);
|
||||||
}
|
}
|
||||||
sb->overwrite_int32(write_count_after, nmodified);
|
sb->overwrite_int32(write_count_after, nmodified);
|
||||||
|
SLS.result();
|
||||||
|
MLS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -373,6 +375,8 @@ void World::diff_tangible_databases(const IdVector &basis, lua_State *master, St
|
|||||||
assert(lua_gettop(master) == m_top);
|
assert(lua_gettop(master) == m_top);
|
||||||
}
|
}
|
||||||
sb->overwrite_int32(write_count_after, nmodified);
|
sb->overwrite_int32(write_count_after, nmodified);
|
||||||
|
SLS.result();
|
||||||
|
MLS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::patch_numbered_tables(StreamBuffer *sb) {
|
void World::patch_numbered_tables(StreamBuffer *sb) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "animqueue.hpp"
|
#include "animqueue.hpp"
|
||||||
#include "gui.hpp"
|
#include "gui.hpp"
|
||||||
#include "traceback.hpp"
|
#include "traceback.hpp"
|
||||||
|
#include "print.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
void World::store_global_pointer(lua_State *L, World *v) {
|
void World::store_global_pointer(lua_State *L, World *v) {
|
||||||
@@ -145,6 +146,49 @@ int64_t World::tangible_id(const LuaStack &LS, LuaSlot tab) {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) {
|
||||||
|
// Get a state if we don't already have one.
|
||||||
|
if (L == nullptr) {
|
||||||
|
L = state();
|
||||||
|
assert(!pushdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaVar tangibles, metatab;
|
||||||
|
LuaRet database;
|
||||||
|
LuaStack LS(L, tangibles, database, metatab);
|
||||||
|
|
||||||
|
// Allocate an ID if we don't already have one.
|
||||||
|
if (id == 0) id = id_global_pool_.alloc_id_for_thread(L);
|
||||||
|
|
||||||
|
// Create the C++ part of the structure.
|
||||||
|
std::unique_ptr<Tangible> &t = tangibles_[id];
|
||||||
|
assert (t == nullptr);
|
||||||
|
t.reset(new Tangible(this, id));
|
||||||
|
|
||||||
|
// Create the tangible's database and metatable.
|
||||||
|
LS.set(database, LuaNewTable);
|
||||||
|
LS.set(metatab, LuaNewTable);
|
||||||
|
LS.setmetatable(database, metatab);
|
||||||
|
|
||||||
|
// Mark the tangible using the tabletype field.
|
||||||
|
LS.settabletype(database, LUA_TT_TANGIBLE);
|
||||||
|
LS.settabletype(metatab, LUA_TT_TANGIBLEMETA);
|
||||||
|
|
||||||
|
// Store the database into the tangibles table.
|
||||||
|
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
||||||
|
LS.rawset(tangibles, id, database);
|
||||||
|
|
||||||
|
// Populate the database and metatable with initial stuff.
|
||||||
|
LS.rawset(database, "inventory", LuaNewTable);
|
||||||
|
LS.rawset(metatab, "id", id);
|
||||||
|
LS.rawset(metatab, "threads", LuaNewTable);
|
||||||
|
// LS.rawset(metatab, "__metatable", LuaNil);
|
||||||
|
|
||||||
|
LS.result();
|
||||||
|
if (!pushdb) lua_pop(L, 1);
|
||||||
|
return t.get();
|
||||||
|
}
|
||||||
|
|
||||||
void World::tangible_delete(int64_t id) {
|
void World::tangible_delete(int64_t id) {
|
||||||
lua_State *L = state();
|
lua_State *L = state();
|
||||||
LuaVar tangibles, database;
|
LuaVar tangibles, database;
|
||||||
@@ -204,6 +248,25 @@ std::string World::tangible_ids_debug_string() const {
|
|||||||
return util::id_vector_debug_string(idv);
|
return util::id_vector_debug_string(idv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string World::tangible_pprint(int64_t id) const {
|
||||||
|
lua_State *L = state();
|
||||||
|
LuaVar tangibles, tan, meta;
|
||||||
|
LuaStack LS(L, tangibles, tan, meta);
|
||||||
|
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
||||||
|
LS.rawgeti(tan, tangibles, id);
|
||||||
|
std::ostringstream oss;
|
||||||
|
if (LS.istable(tan)) {
|
||||||
|
LS.getmetatable(meta, tan);
|
||||||
|
LS.clearmetatable(tan);
|
||||||
|
pprint(LS, tan, false, &oss);
|
||||||
|
LS.setmetatable(tan, meta);
|
||||||
|
} else {
|
||||||
|
oss << "<no such tangible: " << id << ">";
|
||||||
|
}
|
||||||
|
LS.result();
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
std::string World::numbered_tables_debug_string() const {
|
std::string World::numbered_tables_debug_string() const {
|
||||||
lua_State *L = state();
|
lua_State *L = state();
|
||||||
LuaVar ntmap, tab, tid;
|
LuaVar ntmap, tab, tid;
|
||||||
@@ -364,49 +427,6 @@ util::IdVector World::get_near(int64_t player_id, float radius, bool exclude_now
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) {
|
|
||||||
// Get a state if we don't already have one.
|
|
||||||
if (L == nullptr) {
|
|
||||||
L = state();
|
|
||||||
assert(!pushdb);
|
|
||||||
}
|
|
||||||
|
|
||||||
LuaVar tangibles, metatab;
|
|
||||||
LuaRet database;
|
|
||||||
LuaStack LS(L, tangibles, database, metatab);
|
|
||||||
|
|
||||||
// Allocate an ID if we don't already have one.
|
|
||||||
if (id == 0) id = id_global_pool_.alloc_id_for_thread(L);
|
|
||||||
|
|
||||||
// Create the C++ part of the structure.
|
|
||||||
std::unique_ptr<Tangible> &t = tangibles_[id];
|
|
||||||
assert (t == nullptr);
|
|
||||||
t.reset(new Tangible(this, id));
|
|
||||||
|
|
||||||
// Create the tangible's database and metatable.
|
|
||||||
LS.set(database, LuaNewTable);
|
|
||||||
LS.set(metatab, LuaNewTable);
|
|
||||||
LS.setmetatable(database, metatab);
|
|
||||||
|
|
||||||
// Mark the tangible using the tabletype field.
|
|
||||||
LS.settabletype(database, LUA_TT_TANGIBLE);
|
|
||||||
LS.settabletype(metatab, LUA_TT_TANGIBLEMETA);
|
|
||||||
|
|
||||||
// Store the database into the tangibles table.
|
|
||||||
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
|
||||||
LS.rawset(tangibles, id, database);
|
|
||||||
|
|
||||||
// Populate the database and metatable with initial stuff.
|
|
||||||
LS.rawset(database, "inventory", LuaNewTable);
|
|
||||||
LS.rawset(metatab, "id", id);
|
|
||||||
LS.rawset(metatab, "threads", LuaNewTable);
|
|
||||||
// LS.rawset(metatab, "__metatable", LuaNil);
|
|
||||||
|
|
||||||
LS.result();
|
|
||||||
if (!pushdb) lua_pop(L, 1);
|
|
||||||
return t.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
World::Redirects World::fetch_redirects() {
|
World::Redirects World::fetch_redirects() {
|
||||||
World::Redirects result = std::move(redirects_);
|
World::Redirects result = std::move(redirects_);
|
||||||
redirects_.clear();
|
redirects_.clear();
|
||||||
@@ -701,94 +721,13 @@ void World::rollback() {
|
|||||||
deserialize(&snapshot_);
|
deserialize(&snapshot_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::difference_transmit(int64_t actor_id, World *master, StreamBuffer *sb) {
|
util::IdVector World::get_visible_union(int64_t actor_id, World *master) {
|
||||||
StreamBuffer tsb;
|
return util::sort_union_id_vectors(
|
||||||
|
|
||||||
// Get the actor in both models. s_actor may be nil.
|
|
||||||
const Tangible *s_actor = tangible_get(actor_id);
|
|
||||||
const Tangible *m_actor = master->tangible_get(actor_id);
|
|
||||||
assert(m_actor != nullptr);
|
|
||||||
|
|
||||||
// Pass one: update the actor essentials. Create actor if doesn't exist.
|
|
||||||
assert(tsb.at_eof());
|
|
||||||
diff_actor_essentials(m_actor, s_actor, &tsb);
|
|
||||||
tsb.copy_into(sb);
|
|
||||||
patch_actor_essentials(&tsb);
|
|
||||||
|
|
||||||
// Get the list of tangibles visible in either model.
|
|
||||||
// Some tangibles may be missing in the master, some may be missing in the sync.
|
|
||||||
util::IdVector visible = util::sort_union_id_vectors(
|
|
||||||
master->get_near_unsorted(actor_id, RadiusVisibility, true),
|
master->get_near_unsorted(actor_id, RadiusVisibility, true),
|
||||||
get_near_unsorted(actor_id, RadiusVisibility, true));
|
get_near_unsorted(actor_id, RadiusVisibility, true));
|
||||||
TanVector m_visible = master->tangible_get_all(visible);
|
|
||||||
TanVector s_visible = tangible_get_all(visible);
|
|
||||||
assert(m_visible.size() == s_visible.size());
|
|
||||||
|
|
||||||
// Pass two: update visible animations.
|
|
||||||
assert(tsb.at_eof());
|
|
||||||
diff_visible_animations(m_visible, s_visible, &tsb);
|
|
||||||
tsb.copy_into(sb);
|
|
||||||
patch_visible_animations(&tsb);
|
|
||||||
|
|
||||||
// Copy the version number from master animqueue to synch animqueue.
|
|
||||||
for (int i = 0; i < int(m_visible.size()); i++) {
|
|
||||||
const Tangible *m_tan = m_visible[i];
|
|
||||||
if (m_tan != nullptr) {
|
|
||||||
Tangible *s_tan = const_cast<Tangible *>(s_visible[i]);
|
|
||||||
if (s_tan == nullptr) {
|
|
||||||
s_tan = tangible_get(m_tan->id());
|
|
||||||
assert(s_tan != nullptr);
|
|
||||||
}
|
|
||||||
s_tan->anim_queue_.update_version(m_tan->anim_queue_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain the list of tangibles whose tables we're going to transmit.
|
|
||||||
util::IdVector closetans = get_near(actor_id, RadiusClose, true);
|
|
||||||
assert(closetans == master->get_near(actor_id, RadiusClose, true));
|
|
||||||
util::HashValue closehash = util::hash_id_vector(closetans);
|
|
||||||
|
|
||||||
// Confirm the close tangibles with the client.
|
|
||||||
sb->write_hashvalue(closehash);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
number_lua_tables(closetans);
|
|
||||||
|
|
||||||
// Pair tables from the synchronous and master models.
|
|
||||||
pair_lua_tables(closetans, master->state());
|
|
||||||
int ncreate = number_remaining_tables(closetans, master->state());
|
|
||||||
sb->write_int32(ncreate);
|
|
||||||
create_new_tables(ncreate);
|
|
||||||
|
|
||||||
assert(tsb.at_eof());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::apply_differences(StreamBuffer *sb) {
|
int64_t World::patch_actor(StreamBuffer *sb) {
|
||||||
int64_t actor_id = patch_actor_essentials(sb);
|
|
||||||
patch_visible_animations(sb);
|
|
||||||
util::IdVector closetans = get_near(actor_id, RadiusClose, true);
|
|
||||||
util::HashValue closehash = util::hash_id_vector(closetans);
|
|
||||||
util::HashValue m_closehash = sb->read_hashvalue();
|
|
||||||
assert(closehash == m_closehash);
|
|
||||||
number_lua_tables(closetans);
|
|
||||||
int ncreate = sb->read_int32();
|
|
||||||
create_new_tables(ncreate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::diff_actor_essentials(const Tangible *m_actor, const Tangible *s_actor, StreamBuffer *sb) {
|
|
||||||
sb->write_int64(m_actor->id());
|
|
||||||
if (s_actor == nullptr) {
|
|
||||||
m_actor->id_player_pool_.serialize(sb);
|
|
||||||
m_actor->anim_queue_.serialize(sb);
|
|
||||||
} else {
|
|
||||||
s_actor->id_player_pool_.diff(m_actor->id_player_pool_, sb);
|
|
||||||
s_actor->anim_queue_.diff(m_actor->anim_queue_, sb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t World::patch_actor_essentials(StreamBuffer *sb) {
|
|
||||||
int64_t actor_id = sb->read_int64();
|
int64_t actor_id = sb->read_int64();
|
||||||
Tangible *s_actor = tangible_get(actor_id);
|
Tangible *s_actor = tangible_get(actor_id);
|
||||||
if (s_actor == nullptr) {
|
if (s_actor == nullptr) {
|
||||||
@@ -803,58 +742,31 @@ int64_t World::patch_actor_essentials(StreamBuffer *sb) {
|
|||||||
return actor_id;
|
return actor_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::diff_visible_animations(const TanVector &mvis, const TanVector &svis, StreamBuffer *sb) {
|
void World::diff_actor(int64_t actor_id, World *master, StreamBuffer *xsb) {
|
||||||
// For each tangible missing in the synchronous model, send the
|
StreamBuffer tsb;
|
||||||
// necessary information to create the tangible.
|
|
||||||
sb->write_int32(0);
|
|
||||||
int count_pos = sb->total_writes();
|
|
||||||
int count = 0;
|
|
||||||
for (int i = 0; i < int(svis.size()); i++) {
|
|
||||||
const Tangible *mt = mvis[i];
|
|
||||||
const Tangible *st = svis[i];
|
|
||||||
if (st == nullptr) {
|
|
||||||
count += 1;
|
|
||||||
sb->write_int64(mt->id());
|
|
||||||
mt->anim_queue_.serialize(sb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb->overwrite_int32(count_pos, count);
|
|
||||||
|
|
||||||
// For each tangible present in the synchronous model that doesn't
|
// Get the actor in both models. s_actor may be nil.
|
||||||
// exist in the master model, send command to delete it.
|
const Tangible *s_actor = tangible_get(actor_id);
|
||||||
sb->write_int32(0);
|
const Tangible *m_actor = master->tangible_get(actor_id);
|
||||||
count_pos = sb->total_writes();
|
assert(m_actor != nullptr);
|
||||||
count = 0;
|
|
||||||
for (int i = 0; i < int(svis.size()); i++) {
|
|
||||||
const Tangible *mt = mvis[i];
|
|
||||||
const Tangible *st = svis[i];
|
|
||||||
if (mt == nullptr) {
|
|
||||||
count += 1;
|
|
||||||
sb->write_int64(st->id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb->overwrite_int32(count_pos, count);
|
|
||||||
|
|
||||||
// For each tangible present in both models, compare
|
// Calculate diffs.
|
||||||
// the animation queues.
|
tsb.write_int64(actor_id);
|
||||||
sb->write_int32(0);
|
if (s_actor == nullptr) {
|
||||||
count_pos = sb->total_writes();
|
m_actor->id_player_pool_.serialize(&tsb);
|
||||||
count = 0;
|
m_actor->anim_queue_.serialize(&tsb);
|
||||||
for (int i = 0; i < int(svis.size()); i++) {
|
} else {
|
||||||
const Tangible *mt = mvis[i];
|
s_actor->id_player_pool_.diff(m_actor->id_player_pool_, &tsb);
|
||||||
const Tangible *st = svis[i];
|
s_actor->anim_queue_.diff(m_actor->anim_queue_, &tsb);
|
||||||
if ((mt != nullptr) && (st != nullptr)) {
|
|
||||||
if (st->anim_queue_.need_patch(mt->anim_queue_)) {
|
|
||||||
count++;
|
|
||||||
sb->write_int64(st->id());
|
|
||||||
st->anim_queue_.diff(mt->anim_queue_, sb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sb->overwrite_int32(count_pos, count);
|
|
||||||
|
// Forward to client, and apply to server-synchronous.
|
||||||
|
tsb.copy_into(xsb);
|
||||||
|
patch_actor(&tsb);
|
||||||
|
assert(tsb.at_eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::patch_visible_animations(StreamBuffer *sb) {
|
void World::patch_visible(StreamBuffer *sb) {
|
||||||
// Receive create messages.
|
// Receive create messages.
|
||||||
int count = sb->read_int32();
|
int count = sb->read_int32();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
@@ -881,187 +793,143 @@ void World::patch_visible_animations(StreamBuffer *sb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_animstate, "c") {
|
void World::diff_visible(const util::IdVector &visible, World *master, StreamBuffer *xsb) {
|
||||||
LuaArg tanobj;
|
StreamBuffer tsb;
|
||||||
LuaRet graphic, plane, x, y, z, facing;
|
|
||||||
LuaStack LS(L, tanobj, graphic, plane, x, y, z, facing);
|
// Get the specified tangibles in both models.
|
||||||
World *w = World::fetch_global_pointer(L);
|
// Some tangibles may be missing in the master, some may be missing in the sync.
|
||||||
Tangible *tan = w->tangible_get(LS, tanobj);
|
TanVector mvis = master->tangible_get_all(visible);
|
||||||
const AnimStep &aqback = tan->anim_queue_.back();
|
TanVector svis = tangible_get_all(visible);
|
||||||
LS.set(graphic, aqback.graphic());
|
assert(mvis.size() == svis.size());
|
||||||
LS.set(plane, aqback.plane());
|
|
||||||
LS.set(x, aqback.xyz().x);
|
// For each tangible that exists in the master, but not
|
||||||
LS.set(y, aqback.xyz().y);
|
// in the synchronous model, send a create message.
|
||||||
LS.set(z, aqback.xyz().z);
|
tsb.write_int32(0);
|
||||||
LS.set(facing, aqback.facing());
|
int count_pos = tsb.total_writes();
|
||||||
return LS.result();
|
int count = 0;
|
||||||
|
for (int i = 0; i < int(svis.size()); i++) {
|
||||||
|
const Tangible *mt = mvis[i];
|
||||||
|
const Tangible *st = svis[i];
|
||||||
|
if ((st == nullptr) && (mt != nullptr)) {
|
||||||
|
count += 1;
|
||||||
|
tsb.write_int64(mt->id());
|
||||||
|
mt->anim_queue_.serialize(&tsb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tsb.overwrite_int32(count_pos, count);
|
||||||
|
|
||||||
|
// For each tangible present in the synchronous model that doesn't
|
||||||
|
// exist in the master model, send command to delete it.
|
||||||
|
tsb.write_int32(0);
|
||||||
|
count_pos = tsb.total_writes();
|
||||||
|
count = 0;
|
||||||
|
for (int i = 0; i < int(svis.size()); i++) {
|
||||||
|
const Tangible *mt = mvis[i];
|
||||||
|
const Tangible *st = svis[i];
|
||||||
|
if ((mt == nullptr) && (st != nullptr)) {
|
||||||
|
count += 1;
|
||||||
|
tsb.write_int64(st->id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tsb.overwrite_int32(count_pos, count);
|
||||||
|
|
||||||
|
// For each tangible present in both models, compare
|
||||||
|
// the animation queues.
|
||||||
|
tsb.write_int32(0);
|
||||||
|
count_pos = tsb.total_writes();
|
||||||
|
count = 0;
|
||||||
|
for (int i = 0; i < int(svis.size()); i++) {
|
||||||
|
const Tangible *mt = mvis[i];
|
||||||
|
const Tangible *st = svis[i];
|
||||||
|
if ((mt != nullptr) && (st != nullptr)) {
|
||||||
|
if (st->anim_queue_.need_patch(mt->anim_queue_)) {
|
||||||
|
count++;
|
||||||
|
tsb.write_int64(st->id());
|
||||||
|
st->anim_queue_.diff(mt->anim_queue_, &tsb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tsb.overwrite_int32(count_pos, count);
|
||||||
|
|
||||||
|
// Forward to client, and apply to server-synchronous.
|
||||||
|
tsb.copy_into(xsb);
|
||||||
|
patch_visible(&tsb);
|
||||||
|
assert(tsb.at_eof());
|
||||||
|
|
||||||
|
// Copy the version number from master animqueue to synch animqueue.
|
||||||
|
for (int i = 0; i < int(mvis.size()); i++) {
|
||||||
|
const Tangible *m_tan = mvis[i];
|
||||||
|
if (m_tan != nullptr) {
|
||||||
|
Tangible *s_tan = const_cast<Tangible *>(svis[i]);
|
||||||
|
if (s_tan == nullptr) {
|
||||||
|
s_tan = tangible_get(m_tan->id());
|
||||||
|
assert(s_tan != nullptr);
|
||||||
|
}
|
||||||
|
s_tan->anim_queue_.update_version(m_tan->anim_queue_);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_animate, "c") {
|
void World::patch_luatabs(StreamBuffer *sb) {
|
||||||
LuaArg tanobj, config;
|
int64_t actor_id = sb->read_int64();
|
||||||
LuaStack LS(L, tanobj, config);
|
util::HashValue closehash = sb->read_hashvalue();
|
||||||
World *w = World::fetch_global_pointer(L);
|
int ncreate = sb->read_int32();
|
||||||
Tangible *tan = w->tangible_get(LS, tanobj);
|
util::IdVector closetans = get_near(actor_id, RadiusClose, true);
|
||||||
int64_t id = w->id_global_pool_.alloc_id_for_thread(L);
|
assert(closehash == util::hash_id_vector(closetans));
|
||||||
const AnimStep &prev = tan->anim_queue_.back();
|
number_lua_tables(closetans);
|
||||||
AnimStep step;
|
create_new_tables(ncreate);
|
||||||
step.from_lua(L, config.index(), prev);
|
patch_tangible_databases(sb);
|
||||||
if (step.action() == "") {
|
patch_numbered_tables(sb);
|
||||||
luaL_error(L, "animation action must be specified");
|
unnumber_lua_tables();
|
||||||
}
|
|
||||||
tan->anim_queue_.add(id, step);
|
|
||||||
tan->update_plane_item();
|
|
||||||
return LS.result();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_setclass, "c") {
|
void World::diff_luatabs(int64_t actor_id, World *master, StreamBuffer *xsb) {
|
||||||
LuaArg tanobj, classname;
|
StreamBuffer tsb;
|
||||||
LuaVar classtab, mt;
|
|
||||||
LuaStack LS(L, tanobj, classname, classtab, mt);
|
// Calculate the set of close tangibles.
|
||||||
World *w = World::fetch_global_pointer(L);
|
util::IdVector closetans = master->get_near(actor_id, RadiusClose, true);
|
||||||
w->tangible_get(LS, tanobj);
|
assert(get_near(actor_id, RadiusClose, true) == closetans);
|
||||||
LS.getclass(classtab, classname);
|
util::HashValue closehash = util::hash_id_vector(closetans);
|
||||||
LS.getmetatable(mt, tanobj);
|
|
||||||
LS.rawset(mt, "__index", classtab);
|
// Number and pair tables in the synchronous and master model.
|
||||||
return LS.result();
|
number_lua_tables(closetans);
|
||||||
|
pair_lua_tables(closetans, master->state());
|
||||||
|
int ncreate = number_remaining_tables(closetans, master->state());
|
||||||
|
create_new_tables(ncreate);
|
||||||
|
|
||||||
|
// Difference transmit.
|
||||||
|
tsb.write_int64(actor_id);
|
||||||
|
tsb.write_hashvalue(closehash);
|
||||||
|
tsb.write_int32(ncreate);
|
||||||
|
diff_tangible_databases(closetans, master->state(), &tsb);
|
||||||
|
diff_numbered_tables(master->state(), &tsb);
|
||||||
|
|
||||||
|
// Patch
|
||||||
|
tsb.copy_into(xsb);
|
||||||
|
assert(tsb.read_int64() == actor_id);
|
||||||
|
assert(tsb.read_hashvalue() == closehash);
|
||||||
|
assert(tsb.read_int32() == ncreate);
|
||||||
|
patch_tangible_databases(&tsb);
|
||||||
|
patch_numbered_tables(&tsb);
|
||||||
|
unnumber_lua_tables();
|
||||||
|
assert(tsb.at_eof());
|
||||||
|
|
||||||
|
// Unnumber tables in both models.
|
||||||
|
unnumber_lua_tables();
|
||||||
|
master->unnumber_lua_tables();
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_delete, "c") {
|
void World::diff_everything(int64_t actor_id, World *master, StreamBuffer *sb) {
|
||||||
LuaArg tanobj;
|
diff_actor(actor_id, master, sb);
|
||||||
LuaStack LS(L, tanobj);
|
util::IdVector visible = get_visible_union(actor_id, master);
|
||||||
World *w = World::fetch_global_pointer(L);
|
diff_visible(visible, master, sb);
|
||||||
Tangible *tan = w->tangible_get(LS, tanobj);
|
diff_luatabs(actor_id, master, sb);
|
||||||
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.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
w->tangible_delete(tan->id());
|
|
||||||
return LS.result();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_build, "c") {
|
void World::patch_everything(StreamBuffer *sb) {
|
||||||
LuaArg config;
|
patch_actor(sb);
|
||||||
LuaVar classname, classtab, mt;
|
patch_visible(sb);
|
||||||
LuaRet database;
|
patch_luatabs(sb);
|
||||||
LuaStack LS(L, config, classname, classtab, database, mt);
|
|
||||||
|
|
||||||
LS.checktable(config);
|
|
||||||
// Get the class of the new tangible.
|
|
||||||
LS.rawget(classname, config, "class");
|
|
||||||
if (LS.isnil(classname)) {
|
|
||||||
luaL_error(L, "must specify a class name");
|
|
||||||
}
|
|
||||||
LS.getclass(classtab, classname);
|
|
||||||
|
|
||||||
// Parse the initial animation step.
|
|
||||||
AnimStep initstep, blank;
|
|
||||||
initstep.from_lua(L, config.index(), blank);
|
|
||||||
if (!initstep.has_xyz()) {
|
|
||||||
luaL_error(L, "You must specify (X,Y,Z) for new tangible");
|
|
||||||
}
|
|
||||||
if (!initstep.has_plane()) {
|
|
||||||
luaL_error(L, "You must specify plane for new tangible");
|
|
||||||
}
|
|
||||||
if (!initstep.has_graphic()) {
|
|
||||||
luaL_error(L, "You must specify graphic for new tangible");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: generate error if there's extra crap in the config table.
|
|
||||||
|
|
||||||
World *w = World::fetch_global_pointer(L);
|
|
||||||
Tangible *tan = w->tangible_make(L, 0, true);
|
|
||||||
lua_replace(L, database.index());
|
|
||||||
|
|
||||||
// Update the class of the new tangible.
|
|
||||||
LS.getmetatable(mt, database);
|
|
||||||
LS.rawset(mt, "__index", classtab);
|
|
||||||
|
|
||||||
// Update the animation queue and planemap of the new tangible.
|
|
||||||
int64_t stepid = w->id_global_pool_.alloc_id_for_thread(L);
|
|
||||||
tan->anim_queue_.add(stepid, initstep);
|
|
||||||
tan->update_plane_item();
|
|
||||||
|
|
||||||
return LS.result();
|
|
||||||
}
|
|
||||||
|
|
||||||
LuaDefine(tangible_get, "c") {
|
|
||||||
LuaArg id;
|
|
||||||
LuaVar tangibles;
|
|
||||||
LuaRet database;
|
|
||||||
LuaStack LS(L, id, tangibles, database);
|
|
||||||
int64_t nid = LS.ckinteger(id);
|
|
||||||
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
|
||||||
LS.rawget(database, tangibles, id);
|
|
||||||
if (!LS.istable(database)) {
|
|
||||||
luaL_error(L, "Not a tangible ID: %d", nid);
|
|
||||||
}
|
|
||||||
return LS.result();
|
|
||||||
}
|
|
||||||
|
|
||||||
LuaDefine(tangible_redirect, "c") {
|
|
||||||
LuaArg actor1, actor2, bldz;
|
|
||||||
LuaStack LS(L, actor1, actor2, bldz);
|
|
||||||
World *w = World::fetch_global_pointer(L);
|
|
||||||
bool bulldoze = LS.ckboolean(bldz);
|
|
||||||
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(LS, actor2);
|
|
||||||
tan2->configure_id_pool_for_actor();
|
|
||||||
w->redirects_[tan1->id()] = tan2->id();
|
|
||||||
}
|
|
||||||
if (bulldoze) {
|
|
||||||
w->tangible_delete(tan1->id());
|
|
||||||
}
|
|
||||||
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.");
|
|
||||||
}
|
|
||||||
return lua_yield(L, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
LuaDefine(world_getregistry, "f") {
|
|
||||||
lua_pushvalue(L, LUA_REGISTRYINDEX);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
LuaDefine(world_xtype, "f") {
|
|
||||||
LuaArg tab;
|
|
||||||
LuaRet rtype;
|
|
||||||
LuaStack LS(L, tab, rtype);
|
|
||||||
int xt = LS.xtype(tab);
|
|
||||||
LS.set(rtype, xt);
|
|
||||||
return LS.result();
|
|
||||||
}
|
|
||||||
|
|
||||||
LuaDefine(world_settabletype, "f") {
|
|
||||||
LuaArg tab, ttype;
|
|
||||||
LuaStack LS(L, tab, ttype);
|
|
||||||
if (!LS.istable(tab)) {
|
|
||||||
luaL_error(L, "Not a table");
|
|
||||||
}
|
|
||||||
int tt = LS.ckinteger(ttype);
|
|
||||||
if ((tt < LUA_TT_GENERAL) || (tt > LUA_TT_CLASS)) {
|
|
||||||
luaL_error(L, "table type out of range");
|
|
||||||
}
|
|
||||||
LS.settabletype(tab, tt);
|
|
||||||
return LS.result();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1072,16 +940,14 @@ static bool worlds_identical(const std::unique_ptr<World> &w1, const std::unique
|
|||||||
return sbw1.contents_equal(&sbw2);
|
return sbw1.contents_equal(&sbw2);
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(unittests_worlddiffs, "c") {
|
LuaDefine(unittests_worldpairtab, "c") {
|
||||||
std::unique_ptr<World> m, ss, cs;
|
std::unique_ptr<World> m(new World(util::WORLD_TYPE_MASTER));
|
||||||
|
std::unique_ptr<World> ss(new World(util::WORLD_TYPE_S_SYNC));
|
||||||
StreamBuffer sb;
|
StreamBuffer sb;
|
||||||
int ncreate;
|
int ncreate;
|
||||||
|
|
||||||
// Test the numbering of lua tables. We create some general
|
// Create a master model containing some general tables, and
|
||||||
// tables using tangible_set_string. Then we install some
|
// some specialty tables (not numberable).
|
||||||
// specialty tables (not numberable) using tangible_copy_global.
|
|
||||||
// Finally, we number and dump the list of numbered tables.
|
|
||||||
m.reset(new World(util::WORLD_TYPE_MASTER));
|
|
||||||
m->tangible_make(0, 123, false);
|
m->tangible_make(0, 123, false);
|
||||||
m->tangible_set_string(123, "inventory.TID", "inventory");
|
m->tangible_set_string(123, "inventory.TID", "inventory");
|
||||||
m->tangible_set_string(123, "transactions.TID", "transactions");
|
m->tangible_set_string(123, "transactions.TID", "transactions");
|
||||||
@@ -1090,14 +956,9 @@ LuaDefine(unittests_worlddiffs, "c") {
|
|||||||
m->tangible_set_string(123, "inventory.cplx.TID", "inventory.cplx");
|
m->tangible_set_string(123, "inventory.cplx.TID", "inventory.cplx");
|
||||||
m->tangible_copy_global(123, "math", "math");
|
m->tangible_copy_global(123, "math", "math");
|
||||||
m->tangible_copy_global(123, "gltab", "_G");
|
m->tangible_copy_global(123, "gltab", "_G");
|
||||||
m->number_lua_tables(util::id_vector_create(123));
|
|
||||||
LuaAssertStrEq(L, m->numbered_tables_debug_string(),
|
|
||||||
"inventory;inventory.cplx;skills;skills.leet;transactions;");
|
|
||||||
|
|
||||||
// Now we're going to create a synchronous model that's similar to, but not
|
// Now we're going to create a synchronous model that's similar to, but not
|
||||||
// exactly the same as that master model, and we're going to pair the tables.
|
// exactly the same as that master model.
|
||||||
// Only some of these tables should pair: inventory, skills, and skills.leet
|
|
||||||
ss.reset(new World(util::WORLD_TYPE_S_SYNC));
|
|
||||||
ss->tangible_make(0, 123, false);
|
ss->tangible_make(0, 123, false);
|
||||||
ss->tangible_set_string(123, "inventory.TID", "inventory");
|
ss->tangible_set_string(123, "inventory.TID", "inventory");
|
||||||
ss->tangible_set_string(123, "skills.TID", "skills");
|
ss->tangible_set_string(123, "skills.TID", "skills");
|
||||||
@@ -1105,6 +966,9 @@ LuaDefine(unittests_worlddiffs, "c") {
|
|||||||
ss->tangible_set_string(123, "skills.leet.TID", "skills.leet");
|
ss->tangible_set_string(123, "skills.leet.TID", "skills.leet");
|
||||||
ss->tangible_set_string(123, "math.TID", "math");
|
ss->tangible_set_string(123, "math.TID", "math");
|
||||||
ss->tangible_set_string(123, "gltab.TID", "gltab");
|
ss->tangible_set_string(123, "gltab.TID", "gltab");
|
||||||
|
|
||||||
|
// Now we're going to test the numbering and pairing of tables.
|
||||||
|
// Only these tables should pair: inventory, skills, and skills.leet
|
||||||
ss->number_lua_tables(util::id_vector_create(123));
|
ss->number_lua_tables(util::id_vector_create(123));
|
||||||
LuaAssertStrEq(L, ss->numbered_tables_debug_string(),
|
LuaAssertStrEq(L, ss->numbered_tables_debug_string(),
|
||||||
"gltab;inventory;math;skills;skills.crap;skills.leet;");
|
"gltab;inventory;math;skills;skills.crap;skills.leet;");
|
||||||
@@ -1121,11 +985,15 @@ LuaDefine(unittests_worlddiffs, "c") {
|
|||||||
ss->create_new_tables(ncreate);
|
ss->create_new_tables(ncreate);
|
||||||
LuaAssertStrEq(L, ss->paired_tables_debug_string(m->state()),
|
LuaAssertStrEq(L, ss->paired_tables_debug_string(m->state()),
|
||||||
"inventory=inventory;inventory.cplx=unknown;skills=skills;skills.leet=skills.leet;transactions=unknown;");
|
"inventory=inventory;inventory.cplx=unknown;skills=skills;skills.leet=skills.leet;transactions=unknown;");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Create new clean world models.
|
LuaDefine(unittests_worldanimdiff, "c") {
|
||||||
m.reset(new World(util::WORLD_TYPE_MASTER));
|
std::unique_ptr<World> m(new World(util::WORLD_TYPE_MASTER));
|
||||||
ss.reset(new World(util::WORLD_TYPE_S_SYNC));
|
std::unique_ptr<World> ss(new World(util::WORLD_TYPE_S_SYNC));
|
||||||
cs.reset(new World(util::WORLD_TYPE_C_SYNC));
|
std::unique_ptr<World> cs(new World(util::WORLD_TYPE_C_SYNC));
|
||||||
|
StreamBuffer sb;
|
||||||
|
util::IdVector ids = util::id_vector_create(123, 345);
|
||||||
|
|
||||||
// Create some tangibles, and add some animations.
|
// Create some tangibles, and add some animations.
|
||||||
m->tangible_make(0, 123, false);
|
m->tangible_make(0, 123, false);
|
||||||
@@ -1141,8 +1009,8 @@ LuaDefine(unittests_worlddiffs, "c") {
|
|||||||
"id=771 action=walkto x=6 y=2; ");
|
"id=771 action=walkto x=6 y=2; ");
|
||||||
|
|
||||||
// Now difference transmit all that to the client.
|
// Now difference transmit all that to the client.
|
||||||
ss->difference_transmit(123, m.get(), &sb);
|
ss->diff_visible(ids, m.get(), &sb);
|
||||||
cs->apply_differences(&sb);
|
cs->patch_visible(&sb);
|
||||||
LuaAssertStrEq(L, ss->tangible_ids_debug_string(), "123,345");
|
LuaAssertStrEq(L, ss->tangible_ids_debug_string(), "123,345");
|
||||||
LuaAssertStrEq(L, ss->tangible_anim_debug_string(123),
|
LuaAssertStrEq(L, ss->tangible_anim_debug_string(123),
|
||||||
"id=0 action= plane= x=0 y=0 z=0 facing=0 graphic=; "
|
"id=0 action= plane= x=0 y=0 z=0 facing=0 graphic=; "
|
||||||
@@ -1165,8 +1033,8 @@ LuaDefine(unittests_worlddiffs, "c") {
|
|||||||
"id=773 action=walkto x=2 y=5; ");
|
"id=773 action=walkto x=2 y=5; ");
|
||||||
|
|
||||||
// Now difference transmit all that to the client again.
|
// Now difference transmit all that to the client again.
|
||||||
ss->difference_transmit(123, m.get(), &sb);
|
ss->diff_visible(ids, m.get(), &sb);
|
||||||
cs->apply_differences(&sb);
|
cs->patch_visible(&sb);
|
||||||
LuaAssertStrEq(L, ss->tangible_anim_debug_string(123),
|
LuaAssertStrEq(L, ss->tangible_anim_debug_string(123),
|
||||||
"id=0 action= plane= x=0 y=0 z=0 facing=0 graphic=; "
|
"id=0 action= plane= x=0 y=0 z=0 facing=0 graphic=; "
|
||||||
"id=770 action=walkto x=3 y=4; "
|
"id=770 action=walkto x=3 y=4; "
|
||||||
@@ -1182,8 +1050,8 @@ LuaDefine(unittests_worlddiffs, "c") {
|
|||||||
LuaAssertStrEq(L, m->tangible_ids_debug_string(), "123");
|
LuaAssertStrEq(L, m->tangible_ids_debug_string(), "123");
|
||||||
|
|
||||||
// And difference transmit
|
// And difference transmit
|
||||||
ss->difference_transmit(123, m.get(), &sb);
|
ss->diff_visible(ids, m.get(), &sb);
|
||||||
cs->apply_differences(&sb);
|
cs->patch_visible(&sb);
|
||||||
LuaAssertStrEq(L, ss->tangible_ids_debug_string(), "123");
|
LuaAssertStrEq(L, ss->tangible_ids_debug_string(), "123");
|
||||||
LuaAssert(L, worlds_identical(ss, cs));
|
LuaAssert(L, worlds_identical(ss, cs));
|
||||||
|
|
||||||
|
|||||||
@@ -197,20 +197,7 @@ public:
|
|||||||
void snapshot();
|
void snapshot();
|
||||||
void rollback();
|
void rollback();
|
||||||
|
|
||||||
// Difference transmission.
|
util::IdVector get_visible_union(int64_t actor_id, World *master);
|
||||||
//
|
|
||||||
// This generates diffs and stores them in the specified buffer,
|
|
||||||
// so that they can be sent to the client. It also applies the diffs
|
|
||||||
// to this model.
|
|
||||||
//
|
|
||||||
void difference_transmit(int64_t actor, World *master, StreamBuffer *sb);
|
|
||||||
|
|
||||||
// Apply differences.
|
|
||||||
//
|
|
||||||
// Note that difference_transmit applies the differences to the server
|
|
||||||
// synchronous model, so this is only used by the client synchronous model.
|
|
||||||
//
|
|
||||||
void apply_differences(StreamBuffer *sb);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -252,6 +239,10 @@ public:
|
|||||||
//
|
//
|
||||||
void tangible_copy_global(int64_t id, const std::string &path, const std::string &global);
|
void tangible_copy_global(int64_t id, const std::string &path, const std::string &global);
|
||||||
|
|
||||||
|
// Pretty-print the entire tangible database and return it as a string.
|
||||||
|
//
|
||||||
|
std::string tangible_pprint(int64_t id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Run any threads which according to the scheduler queue are ready.
|
// Run any threads which according to the scheduler queue are ready.
|
||||||
//
|
//
|
||||||
@@ -269,21 +260,26 @@ private:
|
|||||||
//
|
//
|
||||||
void invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &idata);
|
void invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &idata);
|
||||||
|
|
||||||
// pass 1 of difference transmission: actor essentials.
|
public:
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Before we do anything else, we need to get the actor in the right place.
|
// Difference transmission
|
||||||
// We also update the actor's ID allocation pipeline.
|
|
||||||
//
|
//
|
||||||
static void diff_actor_essentials(const Tangible *mactor, const Tangible *sactor, StreamBuffer *sb);
|
///////////////////////////////////////////////////////////
|
||||||
int64_t patch_actor_essentials(StreamBuffer *sb);
|
|
||||||
|
|
||||||
// Pass 2 of difference transmission: visible animations.
|
int64_t patch_actor(StreamBuffer *sb);
|
||||||
|
void diff_actor(int64_t actor_id, World *master, StreamBuffer *sb);
|
||||||
|
|
||||||
|
void patch_visible(StreamBuffer *sb);
|
||||||
|
void diff_visible(const util::IdVector &ids, World *master, StreamBuffer *sb);
|
||||||
|
|
||||||
|
void patch_luatabs(StreamBuffer *sb);
|
||||||
|
void diff_luatabs(int64_t actor_id, World *master, StreamBuffer *sb);
|
||||||
|
|
||||||
|
// This is the main entry point for difference transmission.
|
||||||
//
|
//
|
||||||
// Synchronizes the animation status of every tangible inside the visibility
|
void patch_everything(StreamBuffer *sb);
|
||||||
// radius of either model. Creates missing tangibles and deletes excess tangibles.
|
void diff_everything(int64_t actor, World *master, StreamBuffer *sb);
|
||||||
//
|
|
||||||
static void diff_visible_animations(const TanVector &mvis, const TanVector &svis, StreamBuffer *sb);
|
|
||||||
void patch_visible_animations(StreamBuffer *sb);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
@@ -350,17 +346,11 @@ public:
|
|||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Compare the numbered general tables.
|
void patch_numbered_tables(StreamBuffer *sb);
|
||||||
//
|
|
||||||
void diff_numbered_tables(lua_State *master, StreamBuffer *sb);
|
void diff_numbered_tables(lua_State *master, StreamBuffer *sb);
|
||||||
|
|
||||||
// Compare the tangible databases.
|
|
||||||
//
|
|
||||||
void diff_tangible_databases(const IdVector &basis, lua_State *master, StreamBuffer *sb);
|
|
||||||
|
|
||||||
void patch_numbered_tables(StreamBuffer *sb);
|
|
||||||
|
|
||||||
void patch_tangible_databases(StreamBuffer *sb);
|
void patch_tangible_databases(StreamBuffer *sb);
|
||||||
|
void diff_tangible_databases(const IdVector &basis, lua_State *master, StreamBuffer *sb);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Type of model
|
// Type of model
|
||||||
|
|||||||
Reference in New Issue
Block a user