Tangible serialization and design improvements

This commit is contained in:
2021-03-14 18:17:34 -04:00
parent 4426fa157a
commit 7c9fd1e46b
7 changed files with 108 additions and 44 deletions

View File

@@ -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);

View File

@@ -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_; }

View File

@@ -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));

View File

@@ -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.

View File

@@ -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();

View File

@@ -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.

View File

@@ -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.