Working on unit tests for class world

This commit is contained in:
2021-08-03 11:25:12 -04:00
parent 91d7e1c15d
commit 202c5a24ba
13 changed files with 240 additions and 103 deletions

View File

@@ -425,7 +425,7 @@ std::string AnimQueue::debug_string() const {
return oss.str();
}
void AnimQueue::serialize_size_and_steps(StreamBuffer *sb) const {
void AnimQueue::serialize(StreamBuffer *sb) const {
assert(valid()); // can't serialize an invalid animqueue.
sb->write_uint8(size_limit_);
sb->write_uint8(steps_.size());
@@ -434,12 +434,7 @@ void AnimQueue::serialize_size_and_steps(StreamBuffer *sb) const {
}
}
void AnimQueue::serialize(StreamBuffer *sb) const {
serialize_size_and_steps(sb);
sb->write_int64(version_number_);
}
void AnimQueue::deserialize_size_and_steps(StreamBuffer *sb) {
void AnimQueue::deserialize(StreamBuffer *sb) {
size_limit_ = sb->read_uint8();
size_t nsteps = sb->read_uint8();
steps_.resize(nsteps);
@@ -448,11 +443,7 @@ void AnimQueue::deserialize_size_and_steps(StreamBuffer *sb) {
step.read_from(sb);
if (i > 0) step.echo(steps_[i - 1]);
}
}
void AnimQueue::deserialize(StreamBuffer *sb) {
deserialize_size_and_steps(sb);
version_number_ = sb->read_int64();
version_number_ = 0;
}
bool AnimQueue::need_patch(const AnimQueue &auth) const {
@@ -624,7 +615,7 @@ LuaDefine(unittests_animqueue, "c") {
aqds.deserialize(&sb);
LuaAssertStrEq(L, aqds.debug_string(),
"version=4; limit=5; "
"version=0; limit=5; "
"id=0 action= plane= x=0 y=0 z=0 facing=0 graphic=; "
"id=12345 action=walk x=3 y=4 z=5; "
"id=12346 action=setgraphic graphic=banana; "

View File

@@ -182,8 +182,10 @@ public:
void add(int64_t id, const AnimStep &step);
// Serialize or deserialize to a StreamBuffer
void serialize_size_and_steps(StreamBuffer *sb) const;
void deserialize_size_and_steps(StreamBuffer *sb);
//
// Caution: version numbers are not stored. On deserialize,
// version number is set to zero.
//
void serialize(StreamBuffer *sb) const;
void deserialize(StreamBuffer *sb);
@@ -196,11 +198,21 @@ public:
// Get the final resting place after all animations are complete.
const AnimStep &back() const;
// (For testing): change the size limit.
public:
////////////////////////////////////////////////////////////////////////////
//
// TESTING SUPPORT
//
// The following functions are not designed to be useful for production
// code, they're designed to be helpful for unit testing.
//
////////////////////////////////////////////////////////////////////////////
// Change the size limit.
void full_clear_and_set_limit(int szl);
void set_limit(int szl);
// (For testing): make sure the invariants are preserved.
// Make sure the invariants are preserved.
bool valid() const;
// Convert to a string for debugging purposes.

View File

@@ -37,7 +37,7 @@
//
// THE NUMERIC RANGES
//
// * 0x0000+ : reserved for future expansion.
// * 0x0000+ : reserved for manually-created tangible IDs.
// * 0x0001+ : used by master model's IdGlobalPool to create batches.
// * 0x0010+ : used by master model's IdGlobalPool to create individual IDs.
// * 0x001E+ : used by sync model's IdGlobalPool to create individual IDs.

View File

@@ -69,7 +69,7 @@ void LuaSnap::serialize(StreamBuffer *sb) {
int64_t pos2 = sb->total_writes();
sb->overwrite_int64(pos1, pos2 - pos1);
lua_settop(state_, 0);
std::cerr << "Eris dump is " << pos2-pos1 << " bytes." << std::endl;
// std::cerr << "Eris dump is " << pos2-pos1 << " bytes." << std::endl;
}
void LuaSnap::deserialize(StreamBuffer *sb) {

View File

@@ -12,7 +12,7 @@
#define CELL_SCALE 10.0
// Round a float and return as integer. Clamp result to the specified range.
static int round_and_clamp(double x, int lo, int hi) {
static int round_and_clamp(float x, int lo, int hi) {
x = round(x);
if (x < lo) return lo;
if (x > hi) return hi;
@@ -37,7 +37,7 @@ struct CellRange {
// beyond the maximum cell range. In that case, it clamps to the edge
// of the cell range.
//
static CellRange rect_cell_range(double x1, double y1, double x2, double y2) {
static CellRange rect_cell_range(float x1, float y1, float x2, float y2) {
CellRange result;
result.xlo = round_and_clamp(x1 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
result.ylo = round_and_clamp(y1 / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
@@ -53,9 +53,9 @@ static int64_t cell_id(int64_t cellx, int64_t celly) {
}
// Get the cell ID of the specified point
static int64_t point_cell_id(double x, double y) {
double cellx = round_and_clamp(x / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
double celly = round_and_clamp(y / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
static int64_t point_cell_id(float x, float y) {
float cellx = round_and_clamp(x / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
float celly = round_and_clamp(y / CELL_SCALE, -CELL_LIMIT, CELL_LIMIT);
return cell_id(int64_t(cellx), int64_t(celly));
}
@@ -85,7 +85,7 @@ void PlaneMap::insert(const std::string &plane, int64_t cellid, PlaneItem *clien
l.push_back(client);
}
void PlaneItem::set_pos(const std::string &plane, double x, double y, double z) {
void PlaneItem::set_pos(const std::string &plane, float x, float y, float z) {
int64_t old_cell = point_cell_id(x_, y_);
int64_t new_cell = point_cell_id(x, y);
@@ -160,7 +160,7 @@ int PlaneMap::total_cells() const {
return total;
}
PlaneMap::IdVector PlaneMap::scan_radius(const std::string &plane, double x, double y, double radius, int64_t prepend) const {
PlaneMap::IdVector PlaneMap::scan_radius(const std::string &plane, float x, float y, float radius, int64_t prepend) const {
PlaneMap::IdVector result;
if (prepend != 0) {
result.push_back(prepend);
@@ -169,7 +169,7 @@ PlaneMap::IdVector PlaneMap::scan_radius(const std::string &plane, double x, dou
if (piter != planes_.end()) {
const Plane &p = piter->second;
CellRange range = rect_cell_range(x - radius, y - radius, x + radius, y + radius);
double radsq = radius*radius;
float radsq = radius*radius;
for (int cy = range.ylo; cy <= range.yhi; cy++) {
for (int cx = range.xlo; cx <= range.xhi; cx++) {
auto liter = p.find(cell_id(cx, cy));
@@ -189,8 +189,8 @@ PlaneMap::IdVector PlaneMap::scan_radius(const std::string &plane, double x, dou
}
LuaDefine(unittests_planemap, "c") {
double SC = CELL_SCALE;
double E = CELL_SCALE * 0.4;
float SC = CELL_SCALE;
float E = CELL_SCALE * 0.4;
int LO = -CELL_LIMIT;
int HI = CELL_LIMIT;
PlaneMap pm;

View File

@@ -86,7 +86,7 @@ class PlaneItem {
private:
PlaneMap *pmap_;
std::string plane_;
double x_, y_, z_;
float x_, y_, z_;
int64_t id_;
public:
@@ -98,15 +98,15 @@ public:
int64_t id() const { return id_; }
const std::string &plane() const { return plane_; }
const double x() const { return x_; }
const double y() const { return y_; }
const double z() const { return z_; }
const float x() const { return x_; }
const float y() const { return y_; }
const float z() const { return z_; }
void untrack();
void track(PlaneMap *pmap);
void set_pos(const std::string &plane, double x, double y, double z);
void set_xyz(double x, double y, double z) { set_pos(plane_, x, y, z); }
void set_pos(const std::string &plane, float x, float y, float z);
void set_xyz(float x, float y, float z) { set_pos(plane_, x, y, z); }
};
class PlaneMap {
@@ -124,7 +124,7 @@ public:
~PlaneMap();
// Caution: scan_radius is not deterministically ordered.
IdVector scan_radius(const std::string &plane, double x, double y, double radius, int64_t prepend) const;
IdVector scan_radius(const std::string &plane, float x, float y, float radius, int64_t prepend) const;
private:
// unit testing stuff.

View File

@@ -41,6 +41,10 @@ int64_t StreamBuffer::total_writes() const {
return (write_cursor_ - buf_lo_) + pre_read_count_;
}
int64_t StreamBuffer::fill() const {
return write_cursor_ - read_cursor_;
}
bool StreamBuffer::layout_is(int64_t a, int64_t b, int64_t c) {
if (read_cursor_ - buf_lo_ != a) return false;
if (write_cursor_ - read_cursor_ != b) return false;
@@ -400,6 +404,14 @@ void StreamBuffer::copy_into(StreamBuffer *sb) {
sb->write_bytes(read_cursor_, write_cursor_ - read_cursor_);
}
bool StreamBuffer::contents_equal(const StreamBuffer *other) const {
int64_t len = fill();
if (len != other->fill()) {
return false;
}
return memcmp(read_cursor_, other->read_cursor_, len) == 0;
}
util::HashValue StreamBuffer::hash() const {
uint64_t hash1 = 0x82A7912E7893AC87;
uint64_t hash2 = 0x81D402740DE458F3;
@@ -448,90 +460,90 @@ LuaDefine(unittests_streambuffer, "c") {
StreamBuffer sb11(11, true);
// Check the initial state.
assert(sb11.layout_is(0, 0, 11));
LuaAssert(L, sb11.layout_is(0, 0, 11));
// Write a few bytes.
write_ztbytes(&sb11, "abcdef");
assert(sb11.layout_is(0, 6, 5));
LuaAssert(L, sb11.layout_is(0, 6, 5));
// Try reading some bytes.
assert(streq("abcd", sb11.read_bytes(4)));
assert(sb11.layout_is(4, 2, 5));
LuaAssert(L, streq("abcd", sb11.read_bytes(4)));
LuaAssert(L, sb11.layout_is(4, 2, 5));
// Put back two bytes.
sb11.unread_to(2);
assert(sb11.layout_is(2, 4, 5));
LuaAssert(L, sb11.layout_is(2, 4, 5));
// Read some more bytes.
assert(streq("cdef", sb11.read_bytes(4)));
assert(sb11.layout_is(6, 0, 5));
LuaAssert(L, streq("cdef", sb11.read_bytes(4)));
LuaAssert(L, sb11.layout_is(6, 0, 5));
// Reading bytes now should raise an EOF and should not alter layout
try {
sb11.read_bytes(1);
assert(false && "This should have thrown an exception");
LuaAssert(L, false && "This should have thrown an exception");
} catch (StreamEof) {}
assert(sb11.layout_is(6, 0, 5));
LuaAssert(L, sb11.layout_is(6, 0, 5));
// Write some more bytes into the stream, forcing a shift-left
write_ztbytes(&sb11, "ghijkl");
assert(sb11.layout_is(0, 6, 5));
LuaAssert(L, sb11.layout_is(0, 6, 5));
// Test buffer wrapping a little more.
assert(streq("ghi", sb11.read_bytes(3)));
assert(sb11.layout_is(3, 3, 5));
LuaAssert(L, streq("ghi", sb11.read_bytes(3)));
LuaAssert(L, sb11.layout_is(3, 3, 5));
write_ztbytes(&sb11, "mnopqr");
assert(sb11.layout_is(0, 9, 2));
assert(streq("jklmnopqr", sb11.read_bytes(9)));
assert(sb11.layout_is(9, 0, 2));
LuaAssert(L, sb11.layout_is(0, 9, 2));
LuaAssert(L, streq("jklmnopqr", sb11.read_bytes(9)));
LuaAssert(L, sb11.layout_is(9, 0, 2));
// Test 1-byte integer ops.
sb11.clear();
for (int i = 0; i < 10; i++) {
sb11.write_int8(i);
sb11.write_int8(i+100);
assert(sb11.read_int8() == i);
assert(sb11.read_int8() == i+100);
LuaAssert(L, sb11.read_int8() == i);
LuaAssert(L, sb11.read_int8() == i+100);
}
// Test 2-byte integer ops.
for (int i = 0; i < 10; i++) {
sb11.write_int16(i);
sb11.write_int16(i+10000);
assert(sb11.read_int16() == i);
assert(sb11.read_int16() == i+10000);
LuaAssert(L, sb11.read_int16() == i);
LuaAssert(L, sb11.read_int16() == i+10000);
}
// Test 4-byte integer ops.
for (int i = 0; i < 10; i++) {
sb11.write_int32(i);
sb11.write_int32(i+1000000);
assert(sb11.read_int32() == i);
assert(sb11.read_int32() == i+1000000);
LuaAssert(L, sb11.read_int32() == i);
LuaAssert(L, sb11.read_int32() == i+1000000);
}
// Test 8-byte integer ops.
for (int i = 0; i < 10; i++) {
sb11.write_int64(i + 1000000);
assert(sb11.read_int64() == i + 1000000);
LuaAssert(L, sb11.read_int64() == i + 1000000);
}
// Check the write count and read count accumulator ability.
sb11.clear();
assert(sb11.total_writes() == 0);
assert(sb11.total_reads() == 0);
LuaAssert(L, sb11.total_writes() == 0);
LuaAssert(L, sb11.total_reads() == 0);
for (int i = 0; i < 10; i++) {
assert(sb11.total_writes() == i * 8);
LuaAssert(L, sb11.total_writes() == i * 8);
sb11.write_int32(i);
sb11.write_int32(i+1000000);
assert(sb11.total_reads() == i * 8);
assert(sb11.read_int32() == i);
assert(sb11.read_int32() == i+1000000);
LuaAssert(L, sb11.total_reads() == i * 8);
LuaAssert(L, sb11.read_int32() == i);
LuaAssert(L, sb11.read_int32() == i+1000000);
}
// Try clearing the buffer.
sb11.clear();
assert(sb11.layout_is(0, 0, 11));
LuaAssert(L, sb11.layout_is(0, 0, 11));
// Write a number then overwrite.
for (int i = 0; i < 2; i++) {
@@ -541,10 +553,10 @@ LuaDefine(unittests_streambuffer, "c") {
sb11.write_int16(56);
sb11.write_int16(78);
sb11.overwrite_int16(wc, 90);
assert(sb11.read_int16() == 12);
assert(sb11.read_int16() == 90);
assert(sb11.read_int16() == 56);
assert(sb11.read_int16() == 78);
LuaAssert(L, sb11.read_int16() == 12);
LuaAssert(L, sb11.read_int16() == 90);
LuaAssert(L, sb11.read_int16() == 56);
LuaAssert(L, sb11.read_int16() == 78);
}
// Try compact string encoding.
@@ -552,10 +564,21 @@ LuaDefine(unittests_streambuffer, "c") {
sb11.write_string("abc");
sb11.write_string("");
sb11.write_string("de");
assert(sb11.layout_is(0, 8, 3));
assert(sb11.read_string() == "abc");
assert(sb11.read_string() == "");
assert(sb11.read_string() == "de");
LuaAssert(L, sb11.layout_is(0, 8, 3));
LuaAssert(L, sb11.read_string() == "abc");
LuaAssert(L, sb11.read_string() == "");
LuaAssert(L, sb11.read_string() == "de");
// Make sure that contents_equal is not obviously broken.
StreamBuffer eqsb1, eqsb2;
eqsb1.write_int32(12);
eqsb1.write_int32(34);
eqsb2.write_int32(34);
LuaAssert(L, !eqsb1.contents_equal(&eqsb2));
eqsb1.read_int32();
LuaAssert(L, eqsb1.contents_equal(&eqsb2));
eqsb1.write_int32(34);
LuaAssert(L, !eqsb1.contents_equal(&eqsb2));
return 0;
}

View File

@@ -256,6 +256,9 @@ public:
// Get the total number of bytes ever written to this buffer.
int64_t total_writes() const;
// Amount of data inside the buffer.
int64_t fill() const;
// Discard all data. Reset total read and write counts.
// Frees up as much space as possible.
void clear();
@@ -353,6 +356,9 @@ public:
// Copy the entire contents of this streambuffer into another one.
void copy_into(StreamBuffer *sb);
// Compare the contents of this streambuffer to another one.
bool contents_equal(const StreamBuffer *sb) const;
// Calculate a noncryptographic but good hash of what's in the buffer.
util::HashValue hash() const;

View File

@@ -180,6 +180,8 @@ void TextGame::check_redirects() {
void TextGame::run()
{
world_.reset(new World(util::WORLD_TYPE_STANDALONE));
world_->update_source();
world_->run_unittests();
actor_id_ = world_->create_login_actor();
std::cerr << "Login actor ID: " << actor_id_ << std::endl;
console_.clear();

View File

@@ -15,7 +15,20 @@
#endif
namespace util {
std::string id_vector_debug_string(const IdVector &idv) {
std::ostringstream oss;
bool first = true;
for (int64_t id : idv) {
if (!first) oss << ",";
oss << id;
first = false;
}
return oss.str();
}
IdVector sort_union_id_vectors(const IdVector &v1, const IdVector &v2) {
IdVector result(v1.size() + v2.size());
int next = 0;

View File

@@ -23,6 +23,9 @@ using StringVec = std::vector<std::string>;
using HashValue = std::pair<uint64_t, uint64_t>;
using IdVector = std::vector<int64_t>;
// ID vector debug string.
std::string id_vector_debug_string(const IdVector &idv);
// Unions and sorts two ID vectors.
IdVector sort_union_id_vectors(const IdVector &v1, const IdVector &v2);

View File

@@ -31,7 +31,7 @@ World::World(util::WorldType wt) {
world_type_ = wt;
// Initialize the ID allocator in master mode.
if (wt == util::WORLD_TYPE_MASTER) {
if (wt == util::WORLD_TYPE_MASTER || wt == util::WORLD_TYPE_STANDALONE) {
id_global_pool_.init_master();
} else {
id_global_pool_.init_synch();
@@ -50,19 +50,11 @@ World::World(util::WorldType wt) {
// Create the tangibles table in the registry.
LS.rawset(LuaRegistry, "tangibles", LuaNewTable);
// Initialize the SourceDB
// Initialize the SourceDB. At this stage, the sourcedb is
// empty, so it's just populating the lua builtins.
source_db_.init(state());
source_db_.rebuild();
// Do standalone initializations.
if (world_type_ == util::WORLD_TYPE_STANDALONE) {
// Load the lua source from disk then rebuild the environment.
source_db_.update();
source_db_.rebuild();
// Run unit tests.
source_db_.run_unittests();
}
LS.result();
assert (stack_is_clear());
}
@@ -161,6 +153,29 @@ void World::tangible_delete(lua_State *L, int64_t id) {
LS.result();
}
void World::tangible_walkto(int64_t id, int64_t animid, float x, float y) {
Tangible *t = tangible_get(id);
assert(animid != 0);
assert(t != nullptr);
AnimStep step;
step.set_action("walkto");
step.set_x(x);
step.set_y(y);
t->anim_queue_.add(animid, step);
}
std::string World::tangible_ids_debug_string() const {
util::IdVector idv;
for (const auto &pair : tangibles_) {
idv.push_back(pair.first);
}
std::sort(idv.begin(), idv.end());
return util::id_vector_debug_string(idv);
}
util::IdVector World::get_near(int64_t player_id, float radius, bool exclude_nowhere) const {
const Tangible *player = tangible_get(player_id);
if (player == nullptr) {
@@ -177,6 +192,12 @@ util::IdVector World::get_near(int64_t player_id, float radius, bool exclude_now
}
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);
@@ -446,7 +467,7 @@ void World::run_scheduled_threads(int64_t clk) {
void World::serialize(StreamBuffer *sb) {
assert(stack_is_clear());
assert(redirects_.empty());
int64_t wc0 = sb->total_writes();
// int64_t wc0 = sb->total_writes();
lua_snap_.serialize(sb);
id_global_pool_.serialize(sb);
thread_sched_.serialize(sb);
@@ -455,8 +476,8 @@ void World::serialize(StreamBuffer *sb) {
sb->write_int64(p.first);
p.second->serialize(sb);
}
int64_t wc1 = sb->total_writes();
std::cerr << "World serialized to " << wc1-wc0 << " bytes." << std::endl;
// int64_t wc1 = sb->total_writes();
// std::cerr << "World serialized to " << wc1-wc0 << " bytes." << std::endl;
assert(stack_is_clear());
}
@@ -506,13 +527,12 @@ void World::rollback() {
void World::difference_transmit(int64_t actor_id, const World *master, StreamBuffer *sb) {
StreamBuffer tsb;
// Get the actor in both models.
// 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(s_actor != nullptr);
assert(m_actor != nullptr);
// Pass one: update the actor essentials.
// 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);
@@ -523,7 +543,7 @@ void World::difference_transmit(int64_t actor_id, const World *master, StreamBuf
util::IdVector visible = util::sort_union_id_vectors(
master->get_near(actor_id, 100.0, true),
this->get_near(actor_id, 100.0, true));
TanVector m_visible = tangible_get_all(visible);
TanVector m_visible = master->tangible_get_all(visible);
TanVector s_visible = tangible_get_all(visible);
assert(m_visible.size() == s_visible.size());
@@ -549,17 +569,33 @@ void World::difference_transmit(int64_t actor_id, const World *master, StreamBuf
assert(tsb.at_eof());
}
void World::apply_differences(StreamBuffer *sb) {
patch_actor_essentials(sb);
patch_visible_animations(sb);
}
void World::diff_actor_essentials(const Tangible *m_actor, const Tangible *s_actor, StreamBuffer *sb) {
sb->write_int64(m_actor->id());
s_actor->id_player_pool_.diff(m_actor->id_player_pool_, sb);
s_actor->anim_queue_.diff(m_actor->anim_queue_, sb);
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);
}
}
void World::patch_actor_essentials(StreamBuffer *sb) {
int64_t actor_id = sb->read_int64();
Tangible *s_actor = tangible_get(actor_id);
s_actor->id_player_pool_.patch(sb);
s_actor->anim_queue_.patch(sb);
if (s_actor == nullptr) {
s_actor = tangible_make(nullptr, actor_id, false);
s_actor->id_player_pool_.deserialize(sb);
s_actor->anim_queue_.deserialize(sb);
} else {
s_actor->id_player_pool_.patch(sb);
s_actor->anim_queue_.patch(sb);
}
s_actor->update_plane_item();
}
@@ -575,7 +611,7 @@ void World::diff_visible_animations(const TanVector &mvis, const TanVector &svis
if (st == nullptr) {
count += 1;
sb->write_int64(mt->id());
mt->anim_queue_.serialize_size_and_steps(sb);
mt->anim_queue_.serialize(sb);
}
}
sb->overwrite_int32(count_pos, count);
@@ -620,7 +656,7 @@ void World::patch_visible_animations(StreamBuffer *sb) {
for (int i = 0; i < count; i++) {
int64_t id = sb->read_int64();
Tangible *t = tangible_make(state(), id, false);
t->anim_queue_.deserialize_size_and_steps(sb);
t->anim_queue_.deserialize(sb);
t->update_plane_item();
}
@@ -791,3 +827,30 @@ LuaDefine(world_getregistry, "f") {
lua_pushvalue(L, LUA_REGISTRYINDEX);
return 1;
}
static bool worlds_identical(const std::unique_ptr<World> &w1, const std::unique_ptr<World> &w2) {
StreamBuffer sbw1, sbw2;
w1->serialize(&sbw1);
w2->serialize(&sbw2);
return sbw1.contents_equal(&sbw2);
}
LuaDefine(unittests_world, "c") {
std::unique_ptr<World> m, ss, cs;
StreamBuffer sb;
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));
m->tangible_make(0, 123, false);
m->tangible_make(0, 345, false);
LuaAssertStrEq(L, m->tangible_ids_debug_string(), "123,345");
ss->difference_transmit(123, m.get(), &sb);
cs->apply_differences(&sb);
LuaAssertStrEq(L, ss->tangible_ids_debug_string(), "123,345");
LuaAssert(L, worlds_identical(ss, cs));
return 0;
}

View File

@@ -84,9 +84,7 @@ public:
// Constructor.
//
// The constructor also calls 'lua_open' to create a new
// lua interpreter for this world model. The lua interpreter
// is stored in world::lua_state_. A significant amount of
// initial setup is done by this constructor.
// lua interpreter for this world model.
//
World(util::WorldType wt);
@@ -136,7 +134,7 @@ public:
// Delete the specified tangible.
//
void tangible_delete(lua_State *L, int64_t id);
// Create a login actor.
//
// Creates a tangible of class 'login' and returns its ID.
@@ -160,6 +158,14 @@ public:
//
void invoke(const Invocation &inv);
// Update the source database from disk.
//
void update_source() { source_db_.update(); source_db_.rebuild(); }
// Run all unit tests.
//
void run_unittests() { source_db_.run_unittests(); }
// fetch_global_pointer
//
// Given a lua state, fetch the world model associated with
@@ -190,8 +196,26 @@ public:
// 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(int64_t actor, StreamBuffer *sb);
void apply_differences(StreamBuffer *sb);
public:
////////////////////////////////////////////////////////////////////////////
//
// TESTING SUPPORT
//
// The following functions are not designed to be useful for production
// code, they're designed to be helpful for unit testing.
//
////////////////////////////////////////////////////////////////////////////
// Add a 'walkto' animation to the specified tangible.
//
void tangible_walkto(int64_t id, int64_t animid, float x, float y);
// Get a list of all existing tangibles as a comma-separated string.
//
std::string tangible_ids_debug_string() const;
private:
// Run any threads which according to the scheduler queue are ready.
//