Worked on code for difference transmission
This commit is contained in:
@@ -20,6 +20,7 @@ CPP_FILES=\
|
||||
cpp/streambuffer.cpp\
|
||||
cpp/source.cpp\
|
||||
cpp/world.cpp\
|
||||
cpp/world-accessor.cpp\
|
||||
cpp/world-difftab.cpp\
|
||||
cpp/world-pairtab.cpp\
|
||||
cpp/textgame.cpp\
|
||||
|
||||
@@ -200,7 +200,11 @@ static void pprint_r(Inspector &insp, int level, LuaSlot root) {
|
||||
pprint_r(insp, level + 1, key);
|
||||
(*insp.stream) << "]";
|
||||
}
|
||||
(*insp.stream) << " = ";
|
||||
if (insp.indent) {
|
||||
(*insp.stream) << " = ";
|
||||
} else {
|
||||
(*insp.stream) << "=";
|
||||
}
|
||||
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
|
||||
// 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:
|
||||
//
|
||||
|
||||
@@ -36,13 +36,13 @@ bool is_identifier(const std::string &str) {
|
||||
}
|
||||
|
||||
void quote_string(const std::string &s, std::ostream *os) {
|
||||
bool usesinglequote = false;
|
||||
bool anysq = false;
|
||||
bool anydq = false;
|
||||
for (char c : s) {
|
||||
if (c == '"') {
|
||||
usesinglequote = true;
|
||||
break;
|
||||
}
|
||||
if (c == '\'') anysq = true;
|
||||
if (c == '"') anydq = true;
|
||||
}
|
||||
bool usesinglequote = (!anysq)||(anydq);
|
||||
(*os) << (usesinglequote ? '\'' : '"');
|
||||
for (char c : s) {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
sb->overwrite_int32(write_count_after, nmodified);
|
||||
SLS.result();
|
||||
MLS.result();
|
||||
}
|
||||
|
||||
void World::patch_numbered_tables(StreamBuffer *sb) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "animqueue.hpp"
|
||||
#include "gui.hpp"
|
||||
#include "traceback.hpp"
|
||||
#include "print.hpp"
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
lua_State *L = state();
|
||||
LuaVar tangibles, database;
|
||||
@@ -204,6 +248,25 @@ std::string World::tangible_ids_debug_string() const {
|
||||
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 {
|
||||
lua_State *L = state();
|
||||
LuaVar ntmap, tab, tid;
|
||||
@@ -364,49 +427,6 @@ util::IdVector World::get_near(int64_t player_id, float radius, bool exclude_now
|
||||
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 result = std::move(redirects_);
|
||||
redirects_.clear();
|
||||
@@ -701,94 +721,13 @@ void World::rollback() {
|
||||
deserialize(&snapshot_);
|
||||
}
|
||||
|
||||
void World::difference_transmit(int64_t actor_id, World *master, StreamBuffer *sb) {
|
||||
StreamBuffer tsb;
|
||||
|
||||
// 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(
|
||||
util::IdVector World::get_visible_union(int64_t actor_id, World *master) {
|
||||
return util::sort_union_id_vectors(
|
||||
master->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 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 World::patch_actor(StreamBuffer *sb) {
|
||||
int64_t actor_id = sb->read_int64();
|
||||
Tangible *s_actor = tangible_get(actor_id);
|
||||
if (s_actor == nullptr) {
|
||||
@@ -803,58 +742,31 @@ int64_t World::patch_actor_essentials(StreamBuffer *sb) {
|
||||
return actor_id;
|
||||
}
|
||||
|
||||
void World::diff_visible_animations(const TanVector &mvis, const TanVector &svis, StreamBuffer *sb) {
|
||||
// For each tangible missing in the synchronous model, send the
|
||||
// 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);
|
||||
void World::diff_actor(int64_t actor_id, World *master, StreamBuffer *xsb) {
|
||||
StreamBuffer tsb;
|
||||
|
||||
// For each tangible present in the synchronous model that doesn't
|
||||
// exist in the master model, send command to delete it.
|
||||
sb->write_int32(0);
|
||||
count_pos = sb->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) {
|
||||
count += 1;
|
||||
sb->write_int64(st->id());
|
||||
}
|
||||
}
|
||||
sb->overwrite_int32(count_pos, count);
|
||||
// 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);
|
||||
|
||||
// For each tangible present in both models, compare
|
||||
// the animation queues.
|
||||
sb->write_int32(0);
|
||||
count_pos = sb->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++;
|
||||
sb->write_int64(st->id());
|
||||
st->anim_queue_.diff(mt->anim_queue_, sb);
|
||||
}
|
||||
}
|
||||
// Calculate diffs.
|
||||
tsb.write_int64(actor_id);
|
||||
if (s_actor == nullptr) {
|
||||
m_actor->id_player_pool_.serialize(&tsb);
|
||||
m_actor->anim_queue_.serialize(&tsb);
|
||||
} else {
|
||||
s_actor->id_player_pool_.diff(m_actor->id_player_pool_, &tsb);
|
||||
s_actor->anim_queue_.diff(m_actor->anim_queue_, &tsb);
|
||||
}
|
||||
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.
|
||||
int count = sb->read_int32();
|
||||
for (int i = 0; i < count; i++) {
|
||||
@@ -881,187 +793,143 @@ void World::patch_visible_animations(StreamBuffer *sb) {
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
void World::diff_visible(const util::IdVector &visible, World *master, StreamBuffer *xsb) {
|
||||
StreamBuffer tsb;
|
||||
|
||||
// Get the specified tangibles in both models.
|
||||
// Some tangibles may be missing in the master, some may be missing in the sync.
|
||||
TanVector mvis = master->tangible_get_all(visible);
|
||||
TanVector svis = tangible_get_all(visible);
|
||||
assert(mvis.size() == svis.size());
|
||||
|
||||
// For each tangible that exists in the master, but not
|
||||
// in the synchronous model, send a create message.
|
||||
tsb.write_int32(0);
|
||||
int count_pos = tsb.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) && (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") {
|
||||
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();
|
||||
void World::patch_luatabs(StreamBuffer *sb) {
|
||||
int64_t actor_id = sb->read_int64();
|
||||
util::HashValue closehash = sb->read_hashvalue();
|
||||
int ncreate = sb->read_int32();
|
||||
util::IdVector closetans = get_near(actor_id, RadiusClose, true);
|
||||
assert(closehash == util::hash_id_vector(closetans));
|
||||
number_lua_tables(closetans);
|
||||
create_new_tables(ncreate);
|
||||
patch_tangible_databases(sb);
|
||||
patch_numbered_tables(sb);
|
||||
unnumber_lua_tables();
|
||||
}
|
||||
|
||||
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();
|
||||
void World::diff_luatabs(int64_t actor_id, World *master, StreamBuffer *xsb) {
|
||||
StreamBuffer tsb;
|
||||
|
||||
// Calculate the set of close tangibles.
|
||||
util::IdVector closetans = master->get_near(actor_id, RadiusClose, true);
|
||||
assert(get_near(actor_id, RadiusClose, true) == closetans);
|
||||
util::HashValue closehash = util::hash_id_vector(closetans);
|
||||
|
||||
// Number and pair tables in the synchronous and master model.
|
||||
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") {
|
||||
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();
|
||||
void World::diff_everything(int64_t actor_id, World *master, StreamBuffer *sb) {
|
||||
diff_actor(actor_id, master, sb);
|
||||
util::IdVector visible = get_visible_union(actor_id, master);
|
||||
diff_visible(visible, master, sb);
|
||||
diff_luatabs(actor_id, master, sb);
|
||||
}
|
||||
|
||||
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();
|
||||
void World::patch_everything(StreamBuffer *sb) {
|
||||
patch_actor(sb);
|
||||
patch_visible(sb);
|
||||
patch_luatabs(sb);
|
||||
}
|
||||
|
||||
|
||||
@@ -1072,16 +940,14 @@ static bool worlds_identical(const std::unique_ptr<World> &w1, const std::unique
|
||||
return sbw1.contents_equal(&sbw2);
|
||||
}
|
||||
|
||||
LuaDefine(unittests_worlddiffs, "c") {
|
||||
std::unique_ptr<World> m, ss, cs;
|
||||
LuaDefine(unittests_worldpairtab, "c") {
|
||||
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;
|
||||
int ncreate;
|
||||
|
||||
// Test the numbering of lua tables. We create some general
|
||||
// tables using tangible_set_string. Then we install some
|
||||
// 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));
|
||||
// Create a master model containing some general tables, and
|
||||
// some specialty tables (not numberable).
|
||||
m->tangible_make(0, 123, false);
|
||||
m->tangible_set_string(123, "inventory.TID", "inventory");
|
||||
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_copy_global(123, "math", "math");
|
||||
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
|
||||
// exactly the same as that master model, and we're going to pair the tables.
|
||||
// Only some of these tables should pair: inventory, skills, and skills.leet
|
||||
ss.reset(new World(util::WORLD_TYPE_S_SYNC));
|
||||
// exactly the same as that master model.
|
||||
ss->tangible_make(0, 123, false);
|
||||
ss->tangible_set_string(123, "inventory.TID", "inventory");
|
||||
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, "math.TID", "math");
|
||||
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));
|
||||
LuaAssertStrEq(L, ss->numbered_tables_debug_string(),
|
||||
"gltab;inventory;math;skills;skills.crap;skills.leet;");
|
||||
@@ -1121,11 +985,15 @@ LuaDefine(unittests_worlddiffs, "c") {
|
||||
ss->create_new_tables(ncreate);
|
||||
LuaAssertStrEq(L, ss->paired_tables_debug_string(m->state()),
|
||||
"inventory=inventory;inventory.cplx=unknown;skills=skills;skills.leet=skills.leet;transactions=unknown;");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create new clean world models.
|
||||
m.reset(new World(util::WORLD_TYPE_MASTER));
|
||||
ss.reset(new World(util::WORLD_TYPE_S_SYNC));
|
||||
cs.reset(new World(util::WORLD_TYPE_C_SYNC));
|
||||
LuaDefine(unittests_worldanimdiff, "c") {
|
||||
std::unique_ptr<World> m(new World(util::WORLD_TYPE_MASTER));
|
||||
std::unique_ptr<World> ss(new World(util::WORLD_TYPE_S_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.
|
||||
m->tangible_make(0, 123, false);
|
||||
@@ -1141,8 +1009,8 @@ LuaDefine(unittests_worlddiffs, "c") {
|
||||
"id=771 action=walkto x=6 y=2; ");
|
||||
|
||||
// Now difference transmit all that to the client.
|
||||
ss->difference_transmit(123, m.get(), &sb);
|
||||
cs->apply_differences(&sb);
|
||||
ss->diff_visible(ids, m.get(), &sb);
|
||||
cs->patch_visible(&sb);
|
||||
LuaAssertStrEq(L, ss->tangible_ids_debug_string(), "123,345");
|
||||
LuaAssertStrEq(L, ss->tangible_anim_debug_string(123),
|
||||
"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; ");
|
||||
|
||||
// Now difference transmit all that to the client again.
|
||||
ss->difference_transmit(123, m.get(), &sb);
|
||||
cs->apply_differences(&sb);
|
||||
ss->diff_visible(ids, m.get(), &sb);
|
||||
cs->patch_visible(&sb);
|
||||
LuaAssertStrEq(L, ss->tangible_anim_debug_string(123),
|
||||
"id=0 action= plane= x=0 y=0 z=0 facing=0 graphic=; "
|
||||
"id=770 action=walkto x=3 y=4; "
|
||||
@@ -1182,8 +1050,8 @@ LuaDefine(unittests_worlddiffs, "c") {
|
||||
LuaAssertStrEq(L, m->tangible_ids_debug_string(), "123");
|
||||
|
||||
// And difference transmit
|
||||
ss->difference_transmit(123, m.get(), &sb);
|
||||
cs->apply_differences(&sb);
|
||||
ss->diff_visible(ids, m.get(), &sb);
|
||||
cs->patch_visible(&sb);
|
||||
LuaAssertStrEq(L, ss->tangible_ids_debug_string(), "123");
|
||||
LuaAssert(L, worlds_identical(ss, cs));
|
||||
|
||||
|
||||
@@ -197,20 +197,7 @@ public:
|
||||
void snapshot();
|
||||
void rollback();
|
||||
|
||||
// Difference transmission.
|
||||
//
|
||||
// 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);
|
||||
util::IdVector get_visible_union(int64_t actor_id, World *master);
|
||||
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@@ -252,6 +239,10 @@ public:
|
||||
//
|
||||
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:
|
||||
// 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);
|
||||
|
||||
// pass 1 of difference transmission: actor essentials.
|
||||
public:
|
||||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// Before we do anything else, we need to get the actor in the right place.
|
||||
// We also update the actor's ID allocation pipeline.
|
||||
// Difference transmission
|
||||
//
|
||||
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
|
||||
// radius of either model. Creates missing tangibles and deletes excess tangibles.
|
||||
//
|
||||
static void diff_visible_animations(const TanVector &mvis, const TanVector &svis, StreamBuffer *sb);
|
||||
void patch_visible_animations(StreamBuffer *sb);
|
||||
void patch_everything(StreamBuffer *sb);
|
||||
void diff_everything(int64_t actor, World *master, StreamBuffer *sb);
|
||||
|
||||
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);
|
||||
|
||||
// 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 diff_tangible_databases(const IdVector &basis, lua_State *master, StreamBuffer *sb);
|
||||
|
||||
private:
|
||||
// Type of model
|
||||
|
||||
Reference in New Issue
Block a user