Files
integration/Source/Integration/AnimQueue.h

301 lines
7.7 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "StringDecoder.h"
#include "Containers/Deque.h"
#include "AnimQueue.generated.h"
////////////////////////////////////////////////
//
// This is copied over from Luprex source. Not ideal.
//
////////////////////////////////////////////////
enum class ElxAnimValueType {
STRING,
NUMBER,
BOOLEAN,
XYZ,
INVALID
};
////////////////////////////////////////////////
//
// Playback Modes
//
// There are three different ways to play an animation:
//
// 1. Start Animation. This is the normal way to play an animation.
//
// 2. Warp to Final. Skip the actual animation, and jump
// instantaneously to the final state of the animation.
//
// 3. Blend to Final. Skip the actual animation, and blend
// smoothly to the final state of the animation. If the current
// state is very far from the final state, then maybe
// jump instantaneously instead.
//
////////////////////////////////////////////////
UENUM(BlueprintType)
enum class ElxAnimationMode : uint8 {
StartAnimation,
WarpToFinal,
BlendToFinal,
INVALID,
};
////////////////////////////////////////////////
//
// An single animation step.
//
// The body consists of a sequence of FlxAnimationField
// records. The body is encoded, to read the
// FlxAnimationField records you need an
// FlxAnimationStepDecoder.
//
////////////////////////////////////////////////
USTRUCT(Blueprintable)
struct INTEGRATION_API FlxAnimationStep {
GENERATED_BODY()
public:
UPROPERTY()
uint64 Hash;
UPROPERTY()
TArray<uint8> Body;
FlxAnimationStep() : Hash(0), Body() {}
FlxAnimationStep(uint64 h, std::string_view b);
// Unpack an AnimStep into a UObject
//
// Stores the key-value pairs of the animation step into
// properties of a UObject. For example, if the key-value
// pair "color=blue" is present in the AnimStep, then this
// routine tries to find a string property "color" in the
// UObject, and then it sets that property to "blue."
//
// Returns true if all of the key-value pairs in the
// animation step could be unpacked into fields of the UObject.
// This could fail, for instance, if the UObject just doesn't
// contain one of the necessary properties. It can also
// fail if there's a type mismatch. For example, "color=blue"
// cannot be stored in a property "color" of type int.
//
// The prefix is prepended to the key names. For example,
// if one of the key-value pairs is "color=blue", and the
// prefix is "aq", then the property "aqColor=blue" will be
// stored in the UObject.
//
// If pre-clear is true, then all properties of the UObject
// starting with the specified prefix are cleared before
// unpacking the animation step.
//
bool Unpack(const FString& prefix, UObject* into, bool preclear = true) const;
};
////////////////////////////////////////////////
//
// This UClass is never instantiated. It exists to
// expose certain static functions to the blueprint
// library.
//
////////////////////////////////////////////////
UCLASS()
class INTEGRATION_API UlxAnimationStepLibrary : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintPure, Category = Tangibles)
static FString AnimationStepDebugString(const FlxAnimationStep& step);
UFUNCTION(BlueprintCallable, Category = Tangibles)
static void UnpackAnimationStep(const FlxAnimationStep& step,
const FString& prefix, UObject* into, bool preclear = true);
};
////////////////////////////////////////////////
//
// Exposing functions to blueprints.
//
////////////////////////////////////////////////
//UFUNCTION(BlueprintCallable)
//void Unpack(const FString& prefix, UObject* into, bool preclear = true);
struct FlxAnimationStepView {
uint64 Hash;
std::string_view Body;
FlxAnimationStepView() : Hash(0), Body("") {}
FlxAnimationStepView(uint64 h, std::string_view b) : Hash(h), Body(b) {}
};
////////////////////////////////////////////////
//
// A single animation field.
//
// A field consists of a variable name,
// a persistent flag, a type, and some fields
// to hold the values.
//
// If the value is boolean, it is stored in
// X, as either 1 or 0. If the value is double,
// it is stored in X.
//
////////////////////////////////////////////////
struct FlxAnimationField {
std::string_view Name;
bool Persistent;
ElxAnimValueType Type;
double X, Y, Z;
std::string_view S;
};
////////////////////////////////////////////////
//
// An Animation Queue Decoder.
//
// This acts a lot like a stream reader,
// it reads one AnimEntry at a time from
// the animation queue until you reach
// 'end-of-file'.
//
////////////////////////////////////////////////
class FlxAnimQueueDecoder {
private:
FlxStringDecoder Decoder;
public:
// Initialize the FlxAnimQueueDecoder with the encoded animation queue.
//
FlxAnimQueueDecoder(std::string_view s) : Decoder(s) {}
// Return true if the parser has reached the end of the string.
//
bool AtEOF() { return Decoder.at_eof(); }
// Read one animation step.
//
FlxAnimationStepView ReadStep();
// Convert an AnimQueue to an FString.
//
static FString DebugString(std::string_view s);
};
////////////////////////////////////////////////
//
// An Animation Step Decoder.
//
// This acts a lot like a stream reader,
// it reads one FlxAnimationField at a time from
// the animation queue until you reach
// 'end-of-file'.
//
////////////////////////////////////////////////
class FlxAnimationStepDecoder {
private:
FlxStringDecoder Decoder;
public:
// Initialize the FlxAnimationStepDecoder from the FlxAnimationStepView.
//
FlxAnimationStepDecoder(std::string_view body) : Decoder(body) {}
// Return true if the parser has reached the end of the string.
//
bool AtEOF() { return Decoder.at_eof(); }
// Read one field.
//
FlxAnimationField ReadField();
// Convert an AnimStep to an FString.
//
static FString DebugString(uint64 hash, std::string_view body);
};
////////////////////////////////////////////////
//
// FlxAnimTracker
//
// This class monitors the animation queue for a single
// tangible. It can identify when a new animation has
// appeared on the animation queue, and when animations have
// been removed from the animation queue. It also
// keeps track of which animations have been started.
//
////////////////////////////////////////////////
class FlxAnimTracker {
public:
// Our own copy of the animation queue. We only
// store the hashes, not the steps. The First element
// of the queue is the oldest item.
//
TDeque<FlxAnimationStep> AQ;
// The sequence number of the first item in AQ.
//
int32 FirstSeqno;
// Map from hash to sequence number.
//
TMap<uint64, int32> HashToSeqno;
// The sequence number of the first unstarted animation.
//
int32 UnstartedSeqno;
// Indicates whether the unstarted animation should be played or otherwise.
//
ElxAnimationMode PlaybackMode;
// Array of recently-aborted hash values.
//
TArray<uint64> AbortedHashes;
public:
// Construct a tracker.
//
// Initially, the tracker is in the empty (Clear) state.
//
FlxAnimTracker();
// Update from the specified animation queue.
//
// After the update is done, AQ will be a copy
// of the animation queue that is passed in.
//
void Update(std::string_view encqueue);
// Fetch the aborted hash values.
//
// This gets the array of aborted hashes and clears
// the stored array.
//
TArray<uint64> GetAborted();
// Get the next unstarted animation step.
//
// Get the next animation step. Returns the next step and the
// playback mode. If the playback mode is INVALID then there is
// no next step to play
//
ElxAnimationMode GetNextStep(FlxAnimationStep& step);
// Declare that an animation has been started.
//
// After starting an animation, you should call this.
//
void StartedStep(uint64 Hash);
};