Files
integration/Source/Integration/AnimQueue.h

362 lines
9.9 KiB
C
Raw Normal View History

2023-09-08 05:38:09 -04:00
#pragma once
#include "CoreMinimal.h"
#include "CoreUObject.h"
2023-09-08 05:38:09 -04:00
#include "StringDecoder.h"
2023-09-15 00:01:41 -04:00
#include "Containers/Deque.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "AnimQueue.generated.h"
2023-09-08 05:38:09 -04:00
////////////////////////////////////////////////////////////
2023-09-08 05:38:09 -04:00
//
// FlxAnimationStep
2023-09-08 05:38:09 -04:00
//
// A single animation step. The key-value pairs
// are stored in an encoded form, which is not
// directly accessible to blueprints. To read
// them, use UnpackAnimationStep or the
// AnimationStepGetXXX functions.
//
////////////////////////////////////////////////////////////
2023-09-08 05:38:09 -04:00
2025-01-07 18:46:40 -05:00
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;
2023-09-15 00:01:41 -04:00
// The Body contains all the key-value pairs
// in an encoded form. To obtain these in a
// useful form, use UnpackAnimationStep or the
// AnimationStepGetXXX functions.
//
UPROPERTY()
TArray<uint8> Body;
UPROPERTY()
FString Blueprint;
FlxAnimationStep() : Finished(false), Hash(0), Body(), Blueprint() {}
FlxAnimationStep(int64 h, std::string_view b);
2023-10-09 14:59:48 -04:00
// Auto-Execute
//
// These functions automatically update certain
// actor properties:
//
// AutoUpdateXYZ - uses 'xyz' keyword
// AutoUpdateFacing - uses 'facing' keyword
// AutoUpdatePlane - uses 'plane' keyword
2023-10-09 14:59:48 -04:00
//
void AutoUpdateXYZ(AActor *actor) const;
void AutoUpdateFacing(AActor *actor) const;
void AutoUpdatePlane(FName *plane) const;
2023-09-15 00:01:41 -04:00
};
////////////////////////////////////////////////////////////
//
// UlxAnimationStepLibrary
//
// Blueprint function library for reading and
// applying animation steps.
//
////////////////////////////////////////////////////////////
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 prefix parameter is prepended to the property
// names. For example, if the pairs are "color=blue,
// speed=20" and the prefix is "aq", then "aq Color" is
// set to "blue" and "aq Speed" is set to 20. A
// property "aq Animation Step" is also written,
// containing the entire animation step.
//
// If a key has no corresponding property, it is
// silently ignored. If a property has no corresponding
// key, it is cleared.
//
// Returns bChanged=true if the hash of the "aq
// Animation Step" property has changed. Returns the
// Action string from action=xxx.
//
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"));
2023-10-12 18:15:56 -04:00
UFUNCTION(BlueprintPure, Category = "Luprex|Animation Step")
2023-10-12 18:15:56 -04:00
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. 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);
};
////////////////////////////////////////////////////////////
//
// FlxAnimationStepView
//
// A lightweight, non-owning view of an animation
// step (hash + body as a string_view).
//
////////////////////////////////////////////////////////////
struct FlxAnimationStepView {
int64 Hash;
std::string_view Body;
2023-09-15 00:01:41 -04:00
FlxAnimationStepView() : Hash(0), Body("") {}
FlxAnimationStepView(int64 h, std::string_view b) : Hash(h), Body(b) {}
2023-09-08 05:38:09 -04:00
};
////////////////////////////////////////////////////////////
//
// FlxAnimationField
//
// A single field from an animation step: a variable name, a
// persistent flag, a type, and value storage.
2023-09-08 05:38:09 -04:00
//
// Boolean values are stored in X as 1 or 0. Double values
// are stored in X.
2023-09-08 05:38:09 -04:00
//
////////////////////////////////////////////////////////////
2023-09-08 05:38:09 -04:00
struct FlxAnimationField {
2023-09-08 05:38:09 -04:00
std::string_view Name;
bool Persistent;
2026-02-09 13:54:00 -05:00
LuaValueType Type;
2023-09-08 05:38:09 -04:00
double X, Y, Z;
std::string_view S;
};
////////////////////////////////////////////////////////////
2023-09-08 05:38:09 -04:00
//
// FlxAnimQueueDecoder
2023-09-08 05:38:09 -04:00
//
// Stream reader for animation queues. Reads one
// FlxAnimationStepView at a time until EOF.
2023-09-08 05:38:09 -04:00
//
////////////////////////////////////////////////////////////
2023-09-08 05:38:09 -04:00
2023-09-15 13:28:18 -04:00
class FlxAnimQueueDecoder {
2023-09-08 05:38:09 -04:00
private:
FlxStreamBuffer Decoder;
// Read from the header immediately on
// construction.
//
int SizeLimit;
int ActualSize;
2023-09-08 05:38:09 -04:00
public:
// Initialize with an encoded animation queue.
2023-09-08 05:38:09 -04:00
//
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; }
2023-09-08 05:38:09 -04:00
// Return true if the parser has reached EOF.
2023-09-08 05:38:09 -04:00
//
bool AtEOF() { return Decoder.empty(); }
2023-09-08 05:38:09 -04:00
// Read one animation step.
//
FlxAnimationStepView ReadStep();
2023-09-08 05:38:09 -04:00
// Peek at the hash of the next step.
//
int64 PeekHash();
2023-09-08 05:38:09 -04:00
// Convert an AnimQueue to an FString.
//
// static FString DebugString(std::string_view s);
2023-09-08 05:38:09 -04:00
};
////////////////////////////////////////////////////////////
2023-09-08 05:38:09 -04:00
//
// FlxAnimationStepDecoder
2023-09-08 05:38:09 -04:00
//
// Stream reader for a single animation step. Reads one
// FlxAnimationField at a time until EOF.
2023-09-08 05:38:09 -04:00
//
////////////////////////////////////////////////////////////
2023-09-08 05:38:09 -04:00
class FlxAnimationStepDecoder {
2023-09-08 05:38:09 -04:00
private:
FlxStreamBuffer Decoder;
2023-09-08 05:38:09 -04:00
public:
// Initialize from an encoded step body.
//
FlxAnimationStepDecoder(std::string_view body) : Decoder(body) {}
2023-09-08 05:38:09 -04:00
// Return true if the parser has reached EOF.
2023-09-08 05:38:09 -04:00
//
bool AtEOF() { return Decoder.empty(); }
2023-09-08 05:38:09 -04:00
// Read one field.
//
FlxAnimationField ReadField();
2023-09-08 05:38:09 -04:00
// Convert an animation step to a debug string.
2023-09-08 05:38:09 -04:00
//
static FString DebugString(bool finished, int64 hash, std::string_view body);
2023-09-08 05:38:09 -04:00
};
2023-09-15 00:01:41 -04:00
////////////////////////////////////////////////////////////
2023-09-15 00:01:41 -04:00
//
2023-09-15 13:28:18 -04:00
// FlxAnimTracker
2023-09-15 00:01:41 -04:00
//
// Monitors the animation queue for a single tangible.
// Identifies when animations appear or are removed, and
// tracks which ones have been marked as finished.
//
////////////////////////////////////////////////////////////
2023-09-15 00:01:41 -04:00
2023-09-15 13:28:18 -04:00
class FlxAnimTracker {
2023-09-15 00:01:41 -04:00
public:
// Our copy of the animation queue. The first element
// is the oldest item.
2023-09-15 00:01:41 -04:00
//
TArray<FlxAnimationStep> AQ;
2023-09-15 00:01:41 -04:00
// True if something has recently changed.
2023-09-15 00:01:41 -04:00
//
bool Changed;
2023-09-15 00:01:41 -04:00
public:
// Construct a tracker in the empty (Clear) state.
2023-09-15 00:01:41 -04:00
//
2023-09-15 13:28:18 -04:00
FlxAnimTracker();
2023-09-15 00:01:41 -04:00
// Clear everything, reset to initial state.
//
void Clear();
// Update from the specified animation queue. After the
// update, AQ will be a copy of the queue that was
// passed in.
2023-09-15 00:01:41 -04:00
//
void Update(std::string_view encqueue);
// Get the current blueprint name.
//
FString GetCurrentBlueprintName();
// Get the current animation step. This is the step
// that the blueprint should currently be playing.
2023-09-15 00:01:41 -04:00
//
FlxAnimationStep GetCurrentAnimation();
// Declare that an animation is finished. The blueprint
// calls this to indicate that it is done playing the
// specified animation. This causes GetCurrentAnimation
// to advance to the next step.
2023-09-15 00:01:41 -04:00
//
void FinishedAnimation(int64 Hash);
2023-09-15 00:01:41 -04:00
// Return true if an animation step is marked finished.
// Also returns true if the step is not found.
//
bool IsFinished(int64 Hash);
// Skip to the end of the animation queue. Equivalent to
// calling FinishedAnimation on every animation in the
// queue.
2023-09-15 00:01:41 -04:00
//
void SkipToEnd();
// Get the hashes of all 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.
2023-09-15 00:01:41 -04:00
//
void ClearChanged() { Changed = false; }
2023-09-15 00:01:41 -04:00
// Get the Changed flag.
2023-09-15 00:01:41 -04:00
//
// Set to true whenever the animation queue changes, or
// when FinishedAnimation marks a step. Only cleared by
// ClearChanged.
2023-09-15 00:01:41 -04:00
//
bool IsChanged() const { return Changed; }
// Return a debug string for the entire animation
// tracker.
//
FString DebugString() const;
};