#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 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 = Luprex) static FString AnimationStepDebugString(const FlxAnimationStep& step); UFUNCTION(BlueprintCallable, Category = Luprex) static void UnpackAnimationStep(const FlxAnimationStep& step, const FString& VariableNamePrefix, UObject* into); UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex) static FVector AnimationStepGetVector(const FlxAnimationStep& step, const FString& name); UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex) static double AnimationStepGetFloat(const FlxAnimationStep& step, const FString& name); UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex) static FString AnimationStepGetString(const FlxAnimationStep& step, const FString& name); UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex) static bool AnimationStepGetBool(const FlxAnimationStep& step, const FString& name); }; //////////////////////////////////////////////// // // 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 AQ; // The sequence number of the first item in AQ. // int32 FirstSeqno; // Map from hash to sequence number. // TMap 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 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 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); };