From 95cd378dc00f77c516ba9e4984b44f87501ea328 Mon Sep 17 00:00:00 2001 From: jyelon Date: Wed, 25 Feb 2026 02:54:54 -0500 Subject: [PATCH] Empty-string anim queues are now allowed --- Docs/Module-Dependencies-in-Luprex.md | 38 ++++++++++++--------------- Source/Integration/AnimQueue.cpp | 12 +++++++-- luprex/cpp/core/animqueue.cpp | 7 ----- luprex/cpp/core/animqueue.hpp | 14 ---------- luprex/cpp/core/drivenengine.cpp | 5 ++-- luprex/cpp/core/world-core.cpp | 9 ++++--- 6 files changed, 34 insertions(+), 51 deletions(-) diff --git a/Docs/Module-Dependencies-in-Luprex.md b/Docs/Module-Dependencies-in-Luprex.md index 88737f0f..d6a0e0da 100644 --- a/Docs/Module-Dependencies-in-Luprex.md +++ b/Docs/Module-Dependencies-in-Luprex.md @@ -14,23 +14,24 @@ the `.cpp` file (not the `.hpp`), it is marked **(cpp-only)**. - **debugcollector** → util - **streambuffer** → eng-malloc, luastack, util - **table** → luastack -- **pprint** → luastack, table, util -- **drivenengine** → enginewrapper, invocation, streambuffer, util +- **keywords** → luastack, util(cpp-only) +- **pprint** → luastack, table(cpp-only), util(cpp-only) - **json** → luastack, util -- **http** → drivenengine, json(cpp-only), luastack, streambuffer -- **planemap** → luastack, util +- **invocation** → enginewrapper, streambuffer +- **drivenengine** → enginewrapper, invocation, streambuffer, util, animqueue(cpp-only) - **luasnap** → luastack, streambuffer - **serializelua** → luastack, streambuffer - **sched** → luastack, streambuffer - **idalloc** → debugcollector, luastack, streambuffer -- **invocation** → enginewrapper, streambuffer -- **source** → debugcollector, luastack, luasnap, streambuffer, table(cpp-only), traceback, util - **animqueue** → debugcollector, luastack, streambuffer, util - **printbuffer** → debugcollector, invocation, streambuffer, util -- **world** → animqueue, debugcollector, http, idalloc, invocation, luasnap, luastack, planemap, printbuffer, pprint, sched, serializelua, source, streambuffer, table, traceback +- **source** → debugcollector, luastack, streambuffer, util, luasnap(cpp-only), table(cpp-only), traceback(cpp-only) +- **planemap** → luastack, util +- **http** → drivenengine, keywords, luastack, streambuffer, json(cpp-only), util(cpp-only) +- **world** → animqueue, debugcollector, http, idalloc, invocation, luasnap, luastack, planemap, printbuffer, pprint(cpp-only), sched, serializelua(cpp-only), source, streambuffer, table(cpp-only), traceback(cpp-only) - **lpxclient** → drivenengine, invocation, printbuffer, util, world - **lpxserver** → drivenengine, luastack, printbuffer, util, world -- **eng-tests** → drivenengine, streambuffer, world +- **unit-testing** → drivenengine(cpp-only), streambuffer(cpp-only), traceback(cpp-only), world(cpp-only) ## Observations @@ -38,20 +39,15 @@ the `.cpp` file (not the `.hpp`), it is marked **(cpp-only)**. `http.hpp` includes `drivenengine.hpp` because it uses `SharedChannel` (defined in drivenengine). Meanwhile, `world` -depends on both `http` and `drivenengine`, and `drivenengine` -depends on `world`. This creates a layering tangle: +depends on both `http` and `drivenengine`, but `drivenengine` no +longer depends on `world` (that circular dependency was broken). +The remaining concern is that `SharedChannel` is an I/O concept +from the driver boundary. Moving `SharedChannel` and `Channel` +into a smaller, lower-level header (perhaps `enginewrapper.hpp` +or a new `channel.hpp`) would let `http` drop its dependency on +`drivenengine` entirely. -``` -world -> http -> drivenengine -> world -``` - -The `SharedChannel` type (`std::shared_ptr`) is really an -I/O concept from the driver boundary. Moving `SharedChannel` and -`Channel` into a smaller, lower-level header (perhaps -`enginewrapper.hpp` or a new `channel.hpp`) would let `http` drop -its dependency on `drivenengine` entirely. - -### world is a mega-consumer (16 dependencies) +### world is a mega-consumer `world` depends on nearly every other module. This is expected for the central game-state container, but it does make `world` hard to diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index cd0ad754..fe7e9e1a 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -420,8 +420,16 @@ const FlxAnimationStep *FlxAnimTracker::FindAnimation(int64 hash) const } void FlxAnimTracker::Update(std::string_view encqueue) { - check(!encqueue.empty()); - + // An empty encqueue represents a blank queue: one step with hash=0, empty body. + // + if (encqueue.empty()) { + if (AQ.Num() == 1 && AQ[0].Hash == 0) return; + Changed = true; + AQ.Empty(); + AQ.Emplace(0, std::string_view()); + return; + } + // If the first hash matches, we don't bother updating at all. // FlxAnimQueueDecoder decoder(encqueue); diff --git a/luprex/cpp/core/animqueue.cpp b/luprex/cpp/core/animqueue.cpp index c0ef72ec..41cc07c0 100644 --- a/luprex/cpp/core/animqueue.cpp +++ b/luprex/cpp/core/animqueue.cpp @@ -12,13 +12,6 @@ #include -util::SharedStdString AnimQueue::blankqueue_; - -void AnimQueue::initialize_module() { - AnimQueue queue; - blankqueue_ = queue.get_encoded_queue(); -} - static int64_t hash_encstep(int64_t prev, std::string_view s) { // We drop the most significant bit to ensure that the value // can be represented as a nonnegative int64. diff --git a/luprex/cpp/core/animqueue.hpp b/luprex/cpp/core/animqueue.hpp index e841e71d..783f4a3b 100644 --- a/luprex/cpp/core/animqueue.hpp +++ b/luprex/cpp/core/animqueue.hpp @@ -364,17 +364,6 @@ public: // util::SharedStdString get_encoded_queue() const { return encqueue_; } - // Get a serialized representation of a blank queue. - // - // Since an animqueue must have at least one step, the blank queue - // contains a single default step. - // - static util::SharedStdString get_encoded_blank_queue() { return blankqueue_; } - - // Initialize the animqueue module. - // - static void initialize_module(); - private: struct QueueRange { int size; @@ -425,9 +414,6 @@ private: // util::SharedStdString encqueue_; - // The blank animation queue. - // - static util::SharedStdString blankqueue_; }; diff --git a/luprex/cpp/core/drivenengine.cpp b/luprex/cpp/core/drivenengine.cpp index ab4e7cba..42c21db9 100644 --- a/luprex/cpp/core/drivenengine.cpp +++ b/luprex/cpp/core/drivenengine.cpp @@ -852,10 +852,9 @@ static void default_get_tangibles_near(EngineWrapper *, uint64_t, double, double } static void default_get_animation_queues(EngineWrapper *, uint32_t count, const int64_t *, uint32_t *lengths, const char **strings) { - util::SharedStdString blank = AnimQueue::get_encoded_blank_queue(); for (int i = 0; i < int(count); i++) { - lengths[i] = blank->size(); - strings[i] = blank->c_str(); + lengths[i] = 0; + strings[i] = ""; } } diff --git a/luprex/cpp/core/world-core.cpp b/luprex/cpp/core/world-core.cpp index 1a34617c..ac24cbd0 100644 --- a/luprex/cpp/core/world-core.cpp +++ b/luprex/cpp/core/world-core.cpp @@ -1264,7 +1264,6 @@ void World::rollback() { // void engine_initialization() { SourceDB::register_lua_builtins(); - AnimQueue::initialize_module(); } static DrivenEngineInitializerReg eireg(engine_initialization); @@ -1280,12 +1279,14 @@ void World::get_animation_queues(uint32_t count, const int64_t *ids, uint32_t *l for (int i = 0; i < int(count); i++) { Tangible *tan = tangible_get(ids[i]); if (tan == nullptr) { - wrapper_anim_queues_[i] = AnimQueue::get_encoded_blank_queue(); + wrapper_anim_queues_[i] = nullptr; + lengths[i] = 0; + strings[i] = ""; } else { wrapper_anim_queues_[i] = tan->anim_queue_.get_encoded_queue(); + lengths[i] = wrapper_anim_queues_[i]->size(); + strings[i] = wrapper_anim_queues_[i]->c_str(); } - lengths[i] = wrapper_anim_queues_[i]->size(); - strings[i] = wrapper_anim_queues_[i]->c_str(); } }