#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 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 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 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; };