/////////////////////////////////////////////////////////////////// // // ANIMATION QUEUES // // An animation queue is a fifo queue of animation steps. New animations are // pushed on the back, and old ones are popped from the front. // // An animation step is a set of key-value pairs, where each key is an // identifier, and each value is either a number, a boolean, an XYZ coordinate, // or a string. A key-value pair can be either persistent or nonpersistent. // So a typical animation step might be: // // action=walk [nonpersistent] // xyz=3,4,5 [persistent] // facing=320 [persistent] // plane=earth [persistent] // // Persistent values are retained from one animation step to the next, // nonpersistent values exist for one animation step only. // // Animation steps are stored encoded as strings, which is convenient for // passing the data to unreal, but it means that the animation step has to be // decoded whenever you want access to the key-value pairs. // // Each animation step has a hash value. The hash value is generated // by mixing the hash value of the previous step with the hash value // of the encoded string of key-value pairs. // /////////////////////////////////////////////////////////////////// #ifndef ANIMQUEUE_HPP #define ANIMQUEUE_HPP #include "wrap-set.hpp" #include "wrap-string.hpp" #include "wrap-deque.hpp" #include "wrap-unordered-map.hpp" #include "luastack.hpp" #include "streambuffer.hpp" #include "debugcollector.hpp" #include "util.hpp" #include #include enum AnimValueType { T_STRING, T_NUMBER, T_BOOLEAN, T_XYZ, T_UNINITIALIZED }; struct AnimValue { AnimValue() : persistent(false), type(T_UNINITIALIZED) {} bool persistent; AnimValueType type; eng::string str; util::DXYZ xyz; // These set the type, str, and xyz fields in a consistent way. void set_boolean(bool b); void set_number(double n); void set_xyz(const util::DXYZ &xyz); void set_string(std::string_view s); // The get the type, str, and xyz fields in a consistent way. bool get_boolean() const; double get_number() const; const util::DXYZ &get_xyz() const; std::string_view get_string() const; // Copy the value from another animvalue. Don't copy the persistent flag. void copy_value(const AnimValue &other); }; class AnimState { private: using Map = eng::map; Map map_; // Set the default value, internal // eng::string add_default(const eng::string &name, const AnimValue &v, const AnimState *other); public: // Clear everything // void clear() { map_.clear(); } // Set the persistent flag on a single variable. // If the variable isn't present, add it. // void set_persistent(const eng::string &name); // Return if it contains a value for the specified name. // bool contains(const eng::string &name) { return map_.find(name) != map_.end(); } // Get the value of a specific variable. // If the variable isn't present, return a default value. // bool get_boolean(const eng::string &name); double get_number(const eng::string &name); util::DXYZ get_xyz(const eng::string &name); std::string_view get_string(const eng::string &name); // Set a single variable to a value of a specified type. // If the variable isn't present, add it. // void set_boolean(const eng::string &name, bool v); void set_number(const eng::string &name, double v); void set_xyz(const eng::string &name, const util::DXYZ &value); void set_string(const eng::string &name, std::string_view value); // Print a debug string into the stringstream. // void print_debug_string(eng::ostringstream &oss); // Return the debug string. eng::string debug_string(); // Constructs an empty state. // AnimState() {} // Convert to an encoded string. // eng::string encode() const; // Decode an encoded string. // void decode(std::string_view enc); // Decode an encoded string, discarding non-persistent data. // void decode_persistent(std::string_view enc); // Add default values for all builtin persistent variables. // // For each builtin default (plane, xyz, facing, bp, model) // // - Will generate an error if a value is already present, // but the present value is of the wrong type. // // - If 'other' is not nullptr, then we look in 'other' for a default // value. If a valid value of the correct type is present, it is // used as the default value. // // - If no default value can be found in 'other', then a hardwired // default value is provided. // eng::string add_defaults(const AnimState *other); // Apply a configuration from a lua table. // // If a key already exists in the state, then type type from the table // must match the type from the existing state. // eng::string apply_lua(LuaCoreStack &LS0, LuaSlot tab, bool setpersist); // Convert an animstate to a lua table. // // You can either convert the persistent key-value pairs, or the // nonpersistent. So you'll need two lua tables to store both. // void to_lua(LuaCoreStack &LS, LuaSlot tab, bool persistent); // Parse a string, for unit testing. // void parse(std::string_view s); void clear_and_parse(std::string_view s); // Constructor from an encoded string. // AnimState(std::string_view s) { decode(s); } }; struct AnimCoreState { util::DXYZ xyz; eng::string plane; void decode(std::string_view enc); }; class AnimQueue : public eng::nevernew { private: struct Step { Step() { hash=0; } Step(const eng::string &e, uint64_t h) : encoding(e), hash(h) {} eng::string encoding; uint64_t hash; }; public: // Construct an empty animation queue. // clears the state to a valid state. // AnimQueue(); // Size limit. // int32_t size_limit() const { return size_limit_; } // Clear and set the initial state. // void clear(); void clear(const AnimState &initial); // Set the size limit. Must be 2-250 // void set_limit(int n); // Add an animation step. // // Note: add does not automatically compose the step with the previous // step, you have to do that yourself. // void add(const AnimState &state); // Serialize or deserialize to a StreamBuffer // void serialize(StreamBuffer *sb) const; void deserialize(StreamBuffer *sb); // Difference transmission // bool diff(const AnimQueue &auth, StreamBuffer *sb) const; void patch(StreamBuffer *sb, DebugCollector *dbc); // Check for exactly equal. This does the full check of all // fields, it is used exclusively for debugging. // bool exactly_equal(const AnimQueue &aq) const; // Check for exactly equal (fast). Compares the size, limit, // and hash of the last entry. If these are equal, then the whole // thing should be equal. // bool exactly_equal_fast(const AnimQueue &aq) const; // Debug strings. // eng::string steps_debug_string() const; eng::string full_debug_string() const; // Get the final hash value. // uint64_t get_final_hash() const { return steps_.back().hash; } // Get the final entry, xyz and plane only. // AnimCoreState get_final_core_state() const; // Get the final entry, all persistent variables. // AnimState get_final_persistent() const; // Get the final entry, everything persistent and non-persistent. // AnimState get_final_everything() const; private: int size_limit_; eng::deque steps_; }; #endif // ANIMQUEUE_HPP