#pragma once #include "CoreMinimal.h" #include "CoreUObject.h" #include "StringDecoder.h" #include "Containers/Deque.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "AnimQueue.generated.h" //////////////////////////////////////////////////////////// // // FlxAnimationStep // // 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. // //////////////////////////////////////////////////////////// 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, use UnpackAnimationStep or the // AnimationStepGetXXX functions. // UPROPERTY() TArray 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 - uses 'xyz' keyword // AutoUpdateFacing - uses 'facing' keyword // AutoUpdatePlane - uses 'plane' keyword // void AutoUpdateXYZ(AActor *actor) const; void AutoUpdateFacing(AActor *actor) const; void AutoUpdatePlane(FName *plane) const; }; //////////////////////////////////////////////////////////// // // 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")); 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. 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; FlxAnimationStepView() : Hash(0), Body("") {} FlxAnimationStepView(int64 h, std::string_view b) : Hash(h), Body(b) {} }; //////////////////////////////////////////////////////////// // // FlxAnimationField // // A single field from an animation step: a variable name, a // persistent flag, a type, and value storage. // // Boolean values are stored in X as 1 or 0. Double values // are stored in X. // //////////////////////////////////////////////////////////// struct FlxAnimationField { std::string_view Name; bool Persistent; LuaValueType Type; double X, Y, Z; std::string_view S; }; //////////////////////////////////////////////////////////// // // FlxAnimQueueDecoder // // Stream reader for animation queues. Reads one // FlxAnimationStepView at a time until EOF. // //////////////////////////////////////////////////////////// class FlxAnimQueueDecoder { private: FlxStreamBuffer Decoder; // Read from the header immediately on // construction. // int SizeLimit; int ActualSize; public: // Initialize with an 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 EOF. // bool AtEOF() { return Decoder.empty(); } // Read one animation step. // FlxAnimationStepView ReadStep(); // Peek at the hash of the next step. // int64 PeekHash(); // Convert an AnimQueue to an FString. // // static FString DebugString(std::string_view s); }; //////////////////////////////////////////////////////////// // // FlxAnimationStepDecoder // // Stream reader for a single animation step. Reads one // FlxAnimationField at a time until EOF. // //////////////////////////////////////////////////////////// class FlxAnimationStepDecoder { private: FlxStreamBuffer Decoder; public: // Initialize from an encoded step body. // FlxAnimationStepDecoder(std::string_view body) : Decoder(body) {} // Return true if the parser has reached EOF. // bool AtEOF() { return Decoder.empty(); } // Read one field. // FlxAnimationField ReadField(); // Convert an animation step to a debug string. // static FString DebugString(bool finished, int64 hash, std::string_view body); }; //////////////////////////////////////////////////////////// // // FlxAnimTracker // // Monitors the animation queue for a single tangible. // Identifies when animations appear or are removed, and // tracks which ones have been marked as finished. // //////////////////////////////////////////////////////////// class FlxAnimTracker { public: // Our copy of the animation queue. The first element // is the oldest item. // TArray AQ; // True if something has recently changed. // bool Changed; public: // Construct a tracker in the empty (Clear) state. // FlxAnimTracker(); // 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. // 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. // 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. // void FinishedAnimation(int64 Hash); // 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. // void SkipToEnd(); // Get the hashes of all animation steps. // TArray 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. // // Set to true whenever the animation queue changes, or // when FinishedAnimation marks a step. Only cleared by // ClearChanged. // bool IsChanged() const { return Changed; } // Return a debug string for the entire animation // tracker. // FString DebugString() const; };