Files
integration/luprex/cpp/core/animqueue.hpp

275 lines
7.7 KiB
C++
Raw Normal View History

2021-01-12 14:14:38 -05:00
///////////////////////////////////////////////////////////////////
//
// 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:
2021-01-12 14:14:38 -05:00
//
// action=walk [nonpersistent]
// xyz=3,4,5 [persistent]
// facing=320 [persistent]
// plane=earth [persistent]
2021-01-12 14:14:38 -05:00
//
// Persistent values are retained from one animation step to the next,
// nonpersistent values exist for one animation step only.
2021-01-12 14:14:38 -05:00
//
// 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.
2021-07-18 17:48:39 -04:00
//
// 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.
2021-07-18 17:48:39 -04:00
//
2021-01-12 14:14:38 -05:00
///////////////////////////////////////////////////////////////////
#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"
2021-11-21 13:35:39 -05:00
#include "debugcollector.hpp"
2021-01-12 14:14:38 -05:00
#include "util.hpp"
#include <cassert>
#include <ostream>
2021-01-12 14:14:38 -05:00
enum AnimValueType {
T_STRING,
T_NUMBER,
T_BOOLEAN,
T_XYZ,
T_UNINITIALIZED
};
2021-01-12 14:14:38 -05:00
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<eng::string, AnimValue>;
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);
2021-07-21 16:10:29 -04:00
// Decode an encoded string, discarding non-persistent data.
//
void decode_persistent(std::string_view enc);
2021-07-21 16:10:29 -04:00
// 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);
2021-07-21 16:10:29 -04:00
// Constructor from an encoded string.
//
AnimState(std::string_view s) { decode(s); }
2021-01-12 14:14:38 -05:00
};
struct AnimCoreState
{
util::DXYZ xyz;
eng::string plane;
void decode(std::string_view enc);
};
2022-03-02 14:52:51 -05:00
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;
};
2021-07-21 16:10:29 -04:00
public:
// Construct an empty animation queue.
// clears the state to a valid state.
//
AnimQueue();
2021-01-12 14:14:38 -05:00
// Size limit.
//
int32_t size_limit() const { return size_limit_; }
// Clear and set the initial state.
//
void clear();
void clear(const AnimState &initial);
2021-09-10 17:06:07 -04:00
// 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.
2021-08-03 11:25:12 -04:00
//
void add(const AnimState &state);
// Serialize or deserialize to a StreamBuffer
2021-08-03 11:25:12 -04:00
//
2021-07-26 13:12:44 -04:00
void serialize(StreamBuffer *sb) const;
void deserialize(StreamBuffer *sb);
// Difference transmission
//
2021-11-21 13:35:39 -05:00
bool diff(const AnimQueue &auth, StreamBuffer *sb) const;
void patch(StreamBuffer *sb, DebugCollector *dbc);
2021-01-17 16:23:10 -05:00
// Check for exactly equal. This does the full check of all
// fields, it is used exclusively for debugging.
2021-08-03 11:25:12 -04:00
//
bool exactly_equal(const AnimQueue &aq) const;
2021-08-03 11:25:12 -04:00
// 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;
2021-07-21 16:10:29 -04:00
2023-07-24 17:20:45 -04:00
// 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;
2021-07-21 16:10:29 -04:00
private:
int size_limit_;
eng::deque<Step> steps_;
2021-01-12 14:14:38 -05:00
};
#endif // ANIMQUEUE_HPP