Tangible serialization and design improvements
This commit is contained in:
@@ -6,7 +6,6 @@ AnimStep::AnimStep() {}
|
||||
AnimStep::~AnimStep() {}
|
||||
|
||||
AnimQueue::AnimQueue() {
|
||||
id_ = 0;
|
||||
size_limit_ = 10; // Default size limit.
|
||||
clear_steps();
|
||||
}
|
||||
@@ -204,7 +203,6 @@ bool AnimQueue::valid() {
|
||||
|
||||
void AnimQueue::serialize(StreamBuffer *sb) {
|
||||
assert(valid()); // can't serialize an invalid animqueue.
|
||||
sb->write_int64(id_);
|
||||
sb->write_int32(size_limit_);
|
||||
sb->write_size(steps_.size());
|
||||
for (const AnimStep &step : steps_) {
|
||||
@@ -229,7 +227,6 @@ void AnimQueue::serialize(StreamBuffer *sb) {
|
||||
}
|
||||
|
||||
void AnimQueue::deserialize(StreamBuffer *sb) {
|
||||
id_ = sb->read_int64();
|
||||
size_limit_ = sb->read_int32();
|
||||
size_t nsteps = sb->read_size();
|
||||
steps_.clear();
|
||||
@@ -330,7 +327,6 @@ LuaDefine(unittests_animqueue, "c") {
|
||||
LuaAssert(L, aq.valid());
|
||||
|
||||
// Test serialization and deserialization.
|
||||
aq.set_id(123);
|
||||
aq.set_size_limit(5);
|
||||
aq.clear_steps();
|
||||
aq.add(12345, "walk");
|
||||
@@ -342,7 +338,6 @@ LuaDefine(unittests_animqueue, "c") {
|
||||
aq.serialize(&sb);
|
||||
aqds.deserialize(&sb);
|
||||
|
||||
LuaAssert(L, aqds.get_id() == 123);
|
||||
LuaAssert(L, aqds.size_limit() == 5);
|
||||
LuaAssert(L, aqds.size() == 4);
|
||||
|
||||
|
||||
@@ -75,15 +75,12 @@ public:
|
||||
|
||||
class AnimQueue {
|
||||
private:
|
||||
int64_t id_;
|
||||
int32_t size_limit_;
|
||||
std::deque<AnimStep> steps_;
|
||||
|
||||
public:
|
||||
AnimQueue();
|
||||
|
||||
int64_t get_id() const { return id_; }
|
||||
void set_id(int64_t id) { id_ = id; }
|
||||
const AnimStep &nth(int n) const { return steps_[n]; }
|
||||
size_t size() const { return steps_.size(); }
|
||||
int32_t size_limit() const { return size_limit_; }
|
||||
|
||||
@@ -104,22 +104,34 @@ void IdGlobalPool::deserialize(StreamBuffer *sb) {
|
||||
}
|
||||
}
|
||||
|
||||
IdPlayerPool::IdPlayerPool(IdGlobalPool *gp) {
|
||||
global_ = gp;
|
||||
IdPlayerPool::IdPlayerPool(IdGlobalPool *g) {
|
||||
global_ = g;
|
||||
fifo_enabled_ = false;
|
||||
}
|
||||
|
||||
IdPlayerPool::~IdPlayerPool() {
|
||||
}
|
||||
|
||||
void IdPlayerPool::enable_fifo() {
|
||||
fifo_enabled_ = true;
|
||||
}
|
||||
|
||||
void IdPlayerPool::disable_fifo() {
|
||||
unqueue();
|
||||
fifo_enabled_ = false;
|
||||
}
|
||||
|
||||
void IdPlayerPool::purge() {
|
||||
ranges_.clear();
|
||||
}
|
||||
|
||||
void IdPlayerPool::refill() {
|
||||
while (int(ranges_.size()) < global_->queue_fill()) {
|
||||
int64_t batch = global_->get_batch();
|
||||
if (batch == 0) break;
|
||||
ranges_.push_back(batch);
|
||||
if (fifo_enabled_) {
|
||||
while (int(ranges_.size()) < global_->queue_fill()) {
|
||||
int64_t batch = global_->get_batch();
|
||||
if (batch == 0) break;
|
||||
ranges_.push_back(batch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +143,8 @@ void IdPlayerPool::unqueue() {
|
||||
}
|
||||
|
||||
int64_t IdPlayerPool::get_batch() {
|
||||
while (int(ranges_.size()) < global_->queue_fill() + 1) {
|
||||
int fill = fifo_enabled_ ? global_->queue_fill() : 0;
|
||||
while (int(ranges_.size()) < fill + 1) {
|
||||
int64_t batch = global_->get_batch();
|
||||
if (batch == 0) break;
|
||||
ranges_.push_back(batch);
|
||||
@@ -155,6 +168,7 @@ void IdPlayerPool::prepare_thread(lua_State *L) {
|
||||
}
|
||||
|
||||
void IdPlayerPool::serialize(StreamBuffer *sb) {
|
||||
sb->write_bool(fifo_enabled_);
|
||||
sb->write_size(ranges_.size());
|
||||
for (int64_t batch : ranges_) {
|
||||
sb->write_int64(batch);
|
||||
@@ -162,6 +176,7 @@ void IdPlayerPool::serialize(StreamBuffer *sb) {
|
||||
}
|
||||
|
||||
void IdPlayerPool::deserialize(StreamBuffer *sb) {
|
||||
fifo_enabled_ = sb->read_bool();
|
||||
size_t ranges_size = sb->read_size();
|
||||
ranges_.resize(ranges_size);
|
||||
for (int i=0; i < int(ranges_size); i++) {
|
||||
@@ -230,6 +245,7 @@ LuaDefine(unittests_idalloc, "c") {
|
||||
|
||||
// In the synchronous model, refill should do nothing.
|
||||
pp.purge();
|
||||
pp.enable_fifo();
|
||||
gp.init_synch(3);
|
||||
pp.refill();
|
||||
LuaAssert(L, pp.size() == 0);
|
||||
@@ -237,8 +253,20 @@ LuaDefine(unittests_idalloc, "c") {
|
||||
LuaAssert(L, pp.size() == 0);
|
||||
LuaAssert(L, pp.get_batch() == 0);
|
||||
|
||||
// Test refill from master.
|
||||
// In the master model, with fifo disabled. Fifo should remain
|
||||
// empty, but batches should be returned.
|
||||
pp.purge();
|
||||
pp.disable_fifo();
|
||||
gp.init_master(3);
|
||||
pp.refill();
|
||||
LuaAssert(L, pp.size() == 0);
|
||||
LuaAssert(L, pp.get_batch() == nthbatch(0));
|
||||
LuaAssert(L, pp.size() == 0);
|
||||
LuaAssert(L, pp.get_batch() == nthbatch(1));
|
||||
|
||||
// Test refill from master (with enabled fifo).
|
||||
pp.purge();
|
||||
pp.enable_fifo();
|
||||
gp.init_master(3);
|
||||
pp.refill();
|
||||
LuaAssert(L, ranges_equal(pp.ranges_, nthbatch(0), nthbatch(1), nthbatch(2)));
|
||||
@@ -258,6 +286,7 @@ LuaDefine(unittests_idalloc, "c") {
|
||||
|
||||
// Try preparing a thread and salvaging a thread.
|
||||
pp.purge();
|
||||
pp.enable_fifo();
|
||||
gp.init_master(3);
|
||||
lua_setnextid(L, 0);
|
||||
pp.prepare_thread(L);
|
||||
@@ -300,11 +329,14 @@ LuaDefine(unittests_idalloc, "c") {
|
||||
gpds.init_synch(5);
|
||||
LuaAssert(L, gp.get_batch() == nthbatch(0));
|
||||
pp.purge();
|
||||
pp.enable_fifo();
|
||||
pp.refill();
|
||||
LuaAssert(L, pp.fifo_enabled());
|
||||
LuaAssert(L, pp.size() == 3);
|
||||
ppds.purge();
|
||||
pp.serialize(&sb);
|
||||
ppds.deserialize(&sb);
|
||||
LuaAssert(L, ppds.fifo_enabled());
|
||||
LuaAssert(L, ppds.size() == 3);
|
||||
LuaAssert(L, ppds.get_batch() == nthbatch(1));
|
||||
LuaAssert(L, ppds.get_batch() == nthbatch(2));
|
||||
|
||||
@@ -128,22 +128,32 @@ public:
|
||||
class IdPlayerPool {
|
||||
private:
|
||||
IdGlobalPool *global_;
|
||||
bool fifo_enabled_;
|
||||
std::deque<int64_t> ranges_;
|
||||
friend int unittests_idalloc(lua_State *L);
|
||||
|
||||
public:
|
||||
// Construct a player pool.
|
||||
// The Player pool stores a pointer to the global pool.
|
||||
IdPlayerPool(IdGlobalPool *igp);
|
||||
//
|
||||
// The fifo is initially in the disabled state. In the disabled state, the
|
||||
// fifo is not kept filled. You can still use the allocator when the fifo is
|
||||
// disabled - doing so just fetches a batch from the global pool.
|
||||
//
|
||||
IdPlayerPool(IdGlobalPool *g);
|
||||
~IdPlayerPool();
|
||||
|
||||
// Refill the fifo queue of batches from the global pool.
|
||||
void refill();
|
||||
// Enable or disable the fifo.
|
||||
void enable_fifo();
|
||||
void disable_fifo();
|
||||
bool fifo_enabled() { return fifo_enabled_; }
|
||||
|
||||
// Return all batches to the global pool. Leave the fifo empty.
|
||||
// Return all batches from the fifo to the global pool.
|
||||
void unqueue();
|
||||
|
||||
// Discard all batches. This is only for unit testing.
|
||||
// Refill the fifo of batches from the global pool.
|
||||
void refill();
|
||||
|
||||
// Discard all batches in the fifo. This is only for unit testing.
|
||||
void purge();
|
||||
|
||||
// Get a batch from the fifo. Also refills the fifo.
|
||||
|
||||
@@ -320,6 +320,7 @@ public:
|
||||
void write_uint32(uint32_t v) { write_int32(v); }
|
||||
void write_uint64(uint64_t v) { write_int64(v); }
|
||||
void write_size(size_t sz) { write_int64(sz); }
|
||||
void write_bool(bool b) { write_int8(b ? 1 : 0); }
|
||||
|
||||
// Write strings or blocks of bytes into the buffer.
|
||||
void write_string(const std::string &s);
|
||||
@@ -347,6 +348,7 @@ public:
|
||||
uint16_t read_uint16() { return read_int16(); }
|
||||
uint32_t read_uint32() { return read_int32(); }
|
||||
uint64_t read_uint64() { return read_int64(); }
|
||||
bool read_bool() { return read_int8(); }
|
||||
|
||||
// May throw StreamEof or StreamCorruption.
|
||||
size_t read_size();
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
#include "traceback.hpp"
|
||||
#include <iostream>
|
||||
|
||||
Tangible::Tangible() : world_(nullptr) {
|
||||
Tangible::Tangible(World *w, int64_t id) : world_(w), id_player_pool_(&w->id_global_pool_) {
|
||||
plane_item_.set_id(id);
|
||||
w->plane_map_.track(&plane_item_);
|
||||
}
|
||||
|
||||
World::~World() {
|
||||
@@ -43,9 +45,23 @@ void Tangible::update_plane_item() {
|
||||
plane_item_.set_pos(plane, xyz.x, xyz.y, xyz.z);
|
||||
}
|
||||
|
||||
void Tangible::serialize(StreamBuffer *sb) {
|
||||
sb->write_int64(id());
|
||||
anim_queue_.serialize(sb);
|
||||
id_player_pool_.serialize(sb);
|
||||
}
|
||||
|
||||
void Tangible::deserialize(StreamBuffer *sb) {
|
||||
int64_t id = sb->read_int64();
|
||||
plane_item_.set_id(id);
|
||||
anim_queue_.deserialize(sb);
|
||||
id_player_pool_.deserialize(sb);
|
||||
update_plane_item();
|
||||
}
|
||||
|
||||
void Tangible::be_a_player() {
|
||||
if (id_player_pool_ == nullptr) {
|
||||
id_player_pool_.reset(new IdPlayerPool(&world_->id_global_pool_));
|
||||
if (!id_player_pool_.fifo_enabled()) {
|
||||
id_player_pool_.enable_fifo();
|
||||
|
||||
anim_queue_.add(world_->id_global_pool_.get_one(), "");
|
||||
anim_queue_.set_graphic("player");
|
||||
@@ -55,7 +71,7 @@ void Tangible::be_a_player() {
|
||||
|
||||
LS.makeclass(classtab, "player");
|
||||
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
||||
LS.rawget(place, tangibles, anim_queue_.get_id());
|
||||
LS.rawget(place, tangibles, id());
|
||||
LS.getmetatable(mt, place);
|
||||
LS.rawset(mt, "__index", classtab);
|
||||
LS.result();
|
||||
@@ -80,7 +96,7 @@ Tangible *World::tangible_get(int64_t id) {
|
||||
if (iter == tangibles_.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return &iter->second;
|
||||
return iter->second.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,12 +138,9 @@ Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) {
|
||||
if (id == 0) id = id_global_pool_.alloc_id_for_thread(L);
|
||||
|
||||
// Create the C++ part of the structure.
|
||||
Tangible *t = &tangibles_[id];
|
||||
assert(t->world_ == nullptr);
|
||||
t->world_ = this;
|
||||
t->plane_item_.set_id(id);
|
||||
t->anim_queue_.set_id(id);
|
||||
plane_map_.track(&t->plane_item_);
|
||||
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);
|
||||
@@ -146,7 +159,7 @@ Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) {
|
||||
|
||||
LS.result();
|
||||
if (!pushdb) lua_pop(L, 1);
|
||||
return t;
|
||||
return t.get();
|
||||
}
|
||||
|
||||
void World::store_global_pointer(lua_State *L, World *v) {
|
||||
@@ -227,7 +240,7 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a
|
||||
|
||||
// Get an ID batch for the thread, and take one for the thread itself.
|
||||
Tangible *tactor = tangible_get(actor_id);
|
||||
int64_t id_batch = tactor->id_player_pool_->get_batch();
|
||||
int64_t id_batch = tactor->id_player_pool_.get_batch();
|
||||
int64_t tid = id_batch++;
|
||||
|
||||
// Set up for Lua manipulation.
|
||||
|
||||
@@ -19,10 +19,6 @@ class World;
|
||||
|
||||
class Tangible {
|
||||
public:
|
||||
// Simple constructor initializes everything to null.
|
||||
//
|
||||
Tangible();
|
||||
|
||||
// Always points back to the world model.
|
||||
World *world_;
|
||||
|
||||
@@ -33,17 +29,36 @@ public:
|
||||
// Plane Item.
|
||||
//
|
||||
// The PlaneItem also contains this tangible's ID.
|
||||
// To move this Tangible, update the anim_queue first, then update
|
||||
// this plane_item_ from the anim_queue.
|
||||
// To move this PlaneItem, update the anim_queue first, then call
|
||||
// update_plane_item, which copies the data from the anim_queue.
|
||||
//
|
||||
PlaneItem plane_item_;
|
||||
|
||||
// Player ID pool
|
||||
//
|
||||
// Note: this is only allocated if this Tangible is a player.
|
||||
std::unique_ptr<IdPlayerPool> id_player_pool_;
|
||||
// This is present in every tangible, whether a player or not.
|
||||
// However, the fifo is only enabled in logged-in players.
|
||||
//
|
||||
IdPlayerPool id_player_pool_;
|
||||
|
||||
// constructor.
|
||||
//
|
||||
Tangible(World *w, int64_t id);
|
||||
|
||||
// Get the ID
|
||||
//
|
||||
int64_t id() { return plane_item_.id(); }
|
||||
void be_a_player();
|
||||
void update_plane_item();
|
||||
|
||||
// Serialize and deserialize
|
||||
//
|
||||
// PlaneItem is not serialized except the ID. The deserialize routine
|
||||
// rebuilds the PlaneItem from the AnimQueue. World pointer is not
|
||||
// serialized.
|
||||
//
|
||||
void serialize(StreamBuffer *sb);
|
||||
void deserialize(StreamBuffer *sb);
|
||||
};
|
||||
|
||||
class World {
|
||||
@@ -60,7 +75,7 @@ public:
|
||||
//
|
||||
SourceDB source_db_;
|
||||
PlaneMap plane_map_;
|
||||
std::unordered_map<int64_t, Tangible> tangibles_;
|
||||
std::unordered_map<int64_t, std::unique_ptr<Tangible>> tangibles_;
|
||||
|
||||
// Thread schedule: must include every thread, except
|
||||
// for the one currently-executing thread.
|
||||
|
||||
Reference in New Issue
Block a user