Working on unit tests for class world
This commit is contained in:
@@ -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; "
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user