diff --git a/luprex/core/cpp/animqueue.cpp b/luprex/core/cpp/animqueue.cpp index 51890dcf..06d54fb5 100644 --- a/luprex/core/cpp/animqueue.cpp +++ b/luprex/core/cpp/animqueue.cpp @@ -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); diff --git a/luprex/core/cpp/animqueue.hpp b/luprex/core/cpp/animqueue.hpp index bf6a7049..9c30608b 100644 --- a/luprex/core/cpp/animqueue.hpp +++ b/luprex/core/cpp/animqueue.hpp @@ -75,15 +75,12 @@ public: class AnimQueue { private: - int64_t id_; int32_t size_limit_; std::deque 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_; } diff --git a/luprex/core/cpp/idalloc.cpp b/luprex/core/cpp/idalloc.cpp index 314f3284..934adac2 100644 --- a/luprex/core/cpp/idalloc.cpp +++ b/luprex/core/cpp/idalloc.cpp @@ -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)); diff --git a/luprex/core/cpp/idalloc.hpp b/luprex/core/cpp/idalloc.hpp index 30b95c85..557522e8 100644 --- a/luprex/core/cpp/idalloc.hpp +++ b/luprex/core/cpp/idalloc.hpp @@ -128,22 +128,32 @@ public: class IdPlayerPool { private: IdGlobalPool *global_; + bool fifo_enabled_; std::deque 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. diff --git a/luprex/core/cpp/streambuffer.hpp b/luprex/core/cpp/streambuffer.hpp index f24a2173..d19b75a1 100644 --- a/luprex/core/cpp/streambuffer.hpp +++ b/luprex/core/cpp/streambuffer.hpp @@ -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(); diff --git a/luprex/core/cpp/world.cpp b/luprex/core/cpp/world.cpp index 065e5006..f0cf7167 100644 --- a/luprex/core/cpp/world.cpp +++ b/luprex/core/cpp/world.cpp @@ -6,7 +6,9 @@ #include "traceback.hpp" #include -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 &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. diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index 8a7a7ae1..fe511685 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -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 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 tangibles_; + std::unordered_map> tangibles_; // Thread schedule: must include every thread, except // for the one currently-executing thread.