Files
integration/Source/Integration/AnimQueue.h
2026-02-09 13:54:00 -05:00

370 lines
11 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "CoreUObject.h"
#include "StringDecoder.h"
#include "Containers/Deque.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "AnimQueue.generated.h"
////////////////////////////////////////////////
//
// An single animation step.
//
// This struct contains an entire animation step. The
// key-value pairs are stored in an encoded form, which is not
// directly accessible to blueprints. To read these key-value
// pairs, blueprints will need to use UnpackAnimationStep or
// AnimationStepGetXXX.
//
////////////////////////////////////////////////
USTRUCT(BlueprintType)
struct INTEGRATION_API FlxAnimationStep {
GENERATED_BODY()
public:
UPROPERTY()
bool Finished;
// The hash of the animation step, a 63-bit unique identifier.
//
UPROPERTY()
int64 Hash;
// The Body contains all the key-value pairs in an encoded form. To
// obtain these in a useful form, you will need to use
// UnpackAnimationStep or AnimationStepGetXXX.
//
UPROPERTY()
TArray<uint8> Body;
UPROPERTY()
FString Blueprint;
FlxAnimationStep() : Finished(false), Hash(0), Body(), Blueprint() {}
FlxAnimationStep(int64 h, std::string_view b);
// Auto-Execute
//
// These functions automatically update certain actor
// properties:
//
// AutoUpdateXYZ(AActor *actor); // uses 'xyz' keyword
// AutoUpdateFacing(AActor *actor); // uses 'facing' keyword.
// AutoUpdatePlane(FName *plane); // uses 'plane' keyword
//
void AutoUpdateXYZ(AActor *actor) const;
void AutoUpdateFacing(AActor *actor) const;
void AutoUpdatePlane(FName *plane) const;
};
////////////////////////////////////////////////
//
// This UClass is never instantiated. It exists to
// expose certain static functions to the blueprint
// library.
//
////////////////////////////////////////////////
UCLASS()
class INTEGRATION_API UlxAnimationStepLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintPure, Category = "Luprex|Animation Step")
static FString AnimationStepDebugString(const FlxAnimationStep& step);
// Stores the key-value pairs in properties of the target object.
//
// The animation step contains key-value pairs. The goal of this function
// is to store these in properties of the target. The prefix parameter
// is prepended to the property names.
//
// For example, suppose the key-value pairs are "color=blue, speed=20",
// and suppose the prefix is "aq". In that case, two properties would
// be written: "aq Color" would be set to "blue", and "aq Speed" would be
// set to 20. In addition, a property "aq Animation Step" would
// be written, containing the entire animation step.
//
// If the step contains a key-value pair, but there is no corresponding
// property in the target, then the key-value pair is silently
// ignored. If the target contains properties that begin with the prefix,
// but which don't have any corresponding key-value pair, those properties
// are cleared.
//
// Returns 'Changed' if the hash-value of the "aq Animation Step" property
// has changed. Returns 'Action' string from the action=xxx property.
//
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = "Luprex|Animation Step")
static void UnpackAnimationStep(bool &bChanged, FString &Action, const FlxAnimationStep& step, UObject* target, const FString& VariableNamePrefix = TEXT("aq"));
UFUNCTION(BlueprintPure, Category = "Luprex|Animation Step")
static bool AnimationStepEqual(const FlxAnimationStep &StepA, const FlxAnimationStep &StepB);
UFUNCTION(BlueprintPure, Category = "Luprex|Animation Step")
static bool AnimationStepIsIdle(const FlxAnimationStep &step);
UFUNCTION(BlueprintPure, Category = "Luprex|Animation Step")
static FVector AnimationStepGetVector(const FlxAnimationStep& step, const FString& name);
UFUNCTION(BlueprintPure, Category = "Luprex|Animation Step")
static double AnimationStepGetFloat(const FlxAnimationStep& step, const FString& name);
UFUNCTION(BlueprintPure, Category = "Luprex|Animation Step")
static FString AnimationStepGetString(const FlxAnimationStep& step, const FString& name);
UFUNCTION(BlueprintPure, Category = "Luprex|Animation Step")
static FName AnimationStepGetName(const FlxAnimationStep& step, const FString& name);
UFUNCTION(BlueprintPure, Category = "Luprex|Animation Step")
static bool AnimationStepGetBool(const FlxAnimationStep& step, const FString& name);
UFUNCTION(BlueprintPure, meta = (BlueprintAutocast), Category = "Luprex|Animation Step")
static int64 AnimationStepID(const FlxAnimationStep& step) { return step.Hash; }
// Scan an animation step for key-value pairs of the form mat_XXXX={x,y,z}.
// For each match, create a dynamic material instance on the actor's mesh
// components and set the vector parameter XXXX. Materials are restored to
// their base (non-dynamic) state before applying, so parameters from
// previous calls do not persist.
//
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "actor"), Category = "Luprex|Animation Step")
static void AnimationStepApplyMaterials(const FlxAnimationStep& step, AActor* actor);
// Look for a mesh=name key-value pair in the animation step.
// If found, load the named mesh and apply it to the actor's
// mesh component. The actor must have exactly one mesh component.
//
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "actor"), Category = "Luprex|Animation Step")
static void AnimationStepApplyMesh(const FlxAnimationStep& step, bool FallbackToBP, AActor* actor);
};
////////////////////////////////////////////////
//
//
////////////////////////////////////////////////
struct FlxAnimationStepView {
int64 Hash;
std::string_view Body;
FlxAnimationStepView() : Hash(0), Body("") {}
FlxAnimationStepView(int64 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;
LuaValueType 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:
FlxStreamBuffer Decoder;
// These values are immediately read from the header.
//
int SizeLimit;
int ActualSize;
public:
// Initialize the FlxAnimQueueDecoder with the encoded animation queue.
//
FlxAnimQueueDecoder(std::string_view s);
// Get the size limit of the animation queue.
//
int GetSizeLimit() const { return SizeLimit; }
// Get the Actual Size of the animation queue.
//
int GetActualSize() const { return ActualSize; }
// Return true if the parser has reached the end of the string.
//
bool AtEOF() { return Decoder.empty(); }
// Read one animation step.
//
FlxAnimationStepView ReadStep();
// Peek at the hash of the next animation step.
//
int64 PeekHash();
// 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:
FlxStreamBuffer 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.empty(); }
// Read one field.
//
FlxAnimationField ReadField();
// Convert an AnimStep to an FString.
//
static FString DebugString(bool finished, int64 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.
//
TArray<FlxAnimationStep> AQ;
// True if something has recently changed.
//
bool Changed;
public:
// Construct a tracker.
//
// Initially, the tracker is in the empty (Clear) state.
//
FlxAnimTracker();
// Clear everything, reset to the initial state.
//
void Clear();
// 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);
// Get the current blueprint name, as a string.
//
FString GetCurrentBlueprintName();
// Get the current animation step.
//
// Get the current animation step. This is the step that the
// blueprint should currently be playing.
//
FlxAnimationStep GetCurrentAnimation();
// Declare that an animation is finished.
//
// The blueprint uses this function call to indicate that it
// is done playing the specified animation. This will cause the
// animation to be marked as finished, which in turn causes
// 'GetCurrentStep' to advance to the next animation.
//
void FinishedAnimation(int64 Hash);
// Return true if an animation step is marked finished.
//
// Also return true if the animation step is not found.
//
bool IsFinished(int64 Hash);
// Skip to the end of the animation queue.
//
// This is equivalent to calling 'FinishedHash' on every
// animation in the entire queue.
//
void SkipToEnd();
// Get all the hashes of all the animation steps.
//
TArray<int64> GetHashes();
// Return the first unfinished animation.
//
const FlxAnimationStep *FirstUnfinished() const;
// Return the last finished animation.
//
const FlxAnimationStep *LastFinished() const;
// Return the first animation with the specified hash.
//
const FlxAnimationStep *FindAnimation(int64 hash) const;
// Clear the 'Changed' flag.
//
void ClearChanged() { Changed = false; }
// Get the 'Changed' flag.
//
// The changed flag is set to true whenever the Luprex animation
// queue changes from its previous state. The changed flag is also
// set to true whenever 'SetFinished' marks an animation as finished.
// The changed flag can only be set to false by 'ClearChanged,' above.
//
bool IsChanged() const { return Changed; }
// Return a debug string for the entire animation tracker.
//
FString DebugString() const;
};