diff --git a/Content/Luprex/lxUtilityFunctionsLibrary.uasset b/Content/Luprex/lxUtilityFunctionsLibrary.uasset index 5dacf2e3..b6182899 100644 --- a/Content/Luprex/lxUtilityFunctionsLibrary.uasset +++ b/Content/Luprex/lxUtilityFunctionsLibrary.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91469decab760473c36712e55bb4427cda0cd7fbf68929deb921f0592bd1ec84 -size 90818 +oid sha256:7932b2aa3de47daaf3dbc9d499037d1ee63485d193906c6261e21eb3b950c9d9 +size 160377 diff --git a/Content/Luprex/lxUtilityMacroLibrary.uasset b/Content/Luprex/lxUtilityMacroLibrary.uasset new file mode 100644 index 00000000..21ca4704 --- /dev/null +++ b/Content/Luprex/lxUtilityMacroLibrary.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c5f812a5d667f54a9585d7d34501694c2266db3987509522f0b2b1afd980afc0 +size 13898 diff --git a/Content/Tangibles/TangibleStaticMesh.uasset b/Content/Tangibles/TangibleStaticMesh.uasset index 62a5f0f2..2dc6b42a 100644 --- a/Content/Tangibles/TangibleStaticMesh.uasset +++ b/Content/Tangibles/TangibleStaticMesh.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68e750faad98195083ce2162f12e1b34940b83bdf137227de5b48669cb41032b -size 266069 +oid sha256:393dcdb54cb09fa58a75b276ef4dfce6f1065cbf4e83a211753919af74afa88d +size 226548 diff --git a/Content/Tangibles/tangiblecharacter.uasset b/Content/Tangibles/tangiblecharacter.uasset index 1cfdaee4..50987d15 100644 --- a/Content/Tangibles/tangiblecharacter.uasset +++ b/Content/Tangibles/tangiblecharacter.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00f3431474dcca1b28ba7ce0f893ad7c8df012190eb49e12e1f0f65c03e8f7ee -size 394328 +oid sha256:d5a8c6306d4963b626e77c4467dc2c31c128a538c9a4f5c6432ae385eb469811 +size 364481 diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index ad5a4440..1309b659 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -1,5 +1,6 @@ #include "AnimQueue.h" +#include "UtilityLibrary.h" FlxAnimationStep::FlxAnimationStep(uint64 hash, std::string_view body) { Finished = false; @@ -9,16 +10,14 @@ FlxAnimationStep::FlxAnimationStep(uint64 hash, std::string_view body) { Blueprint = UlxAnimationStepLibrary::AnimationStepGetString(*this, "bp"); } -static bool ClearProperties(const FString& prefix, UObject* obj) { +static void ClearProperties(const FString& prefix, UObject* obj, FProperty *except) { UClass* uclass = obj->GetClass(); - if (prefix.IsEmpty()) { - return false; - } FName prefixlo(prefix); FName prefixhi(prefix + TEXT("\xFFFF")); for (TFieldIterator It(uclass); It; ++It) { FProperty* fprop = *It; + if (fprop == except) continue; bool match1 = (fprop->GetFName().Compare(prefixlo) > 0); bool match2 = (fprop->GetFName().Compare(prefixhi) < 0); if (match1 && match2) { @@ -26,7 +25,6 @@ static bool ClearProperties(const FString& prefix, UObject* obj) { fprop->ClearValue(pptr); } } - return true; } #pragma optimize("", off) @@ -70,25 +68,66 @@ static bool SetProperty(const FString& prefix, UObject* obj, const FlxAnimationF } #pragma optimize("", off) -bool FlxAnimationStep::Unpack(const FString& prefix, UObject* into) const { - UClass* uclass = into->GetClass(); - std::string_view body((const char*)(Body.GetData()), Body.Num()); +static FStructProperty *FindAnimationStepProperty(UClass *uclass, const FString &prefix) { + FName nname(prefix + TEXT("Animation Step")); + FStructProperty* fprop = FindFProperty(uclass, nname); + if (fprop == nullptr) return nullptr; + if (fprop->Struct != TBaseStructure::Get()) return nullptr; + return fprop; +} + +#pragma optimize("", off) +void UlxAnimationStepLibrary::UnpackAnimationStep(bool &bChanged, FString &Action, const FlxAnimationStep& step, UObject* target, const FString& prefix) { + bChanged = false; + Action = TEXT(""); + + if (prefix.IsEmpty()) { + UlxUtilityLibrary::Assert(false, TEXT("You may not pass an empty string for prefix")); + return; + } + + UClass* uclass = target->GetClass(); + std::string_view body((const char*)(step.Body.GetData()), step.Body.Num()); FlxAnimationStepDecoder decoder(body); - bool ok = ClearProperties(prefix, into); + + FStructProperty* stepproperty = FindAnimationStepProperty(uclass, prefix); + if (stepproperty == nullptr) { + UE_LOG(LogBlueprint, Error, TEXT("Target object: %s Prefix: %s"), *(target->GetName()), *prefix); + UlxUtilityLibrary::Assert(false, TEXT("Target object does not have an variable named ' Animation Step'")); + return; + } + + FlxAnimationStep* stepstorage = stepproperty->ContainerPtrToValuePtr(target); + uint64 oldhash = stepstorage->Hash; + + FlxAnimationField actionfield; + actionfield.Name = "action"; + actionfield.Persistent = false; + actionfield.Type = SimpleDynamicTag::STRING; + actionfield.S = "unknown"; + + // Decode everything. If an action field is found, save it for later. + ClearProperties(prefix, target, stepproperty); while (!decoder.AtEOF()) { FlxAnimationField field = decoder.ReadField(); - if (Finished && !field.Persistent) continue; - ok &= SetProperty(prefix, into, field); + if ((field.Type == SimpleDynamicTag::STRING) && (field.Name == "action")) { + actionfield.S = field.S; + continue; + } + if (step.Finished && !field.Persistent) continue; + SetProperty(prefix, target, field); } - if (Finished) { - FlxAnimationField field; - field.Name = "action"; - field.Persistent = false; - field.Type = SimpleDynamicTag::STRING; - field.S = "idle"; - ok &= SetProperty(prefix, into, field); - } - return ok; + + // Store the action field. + if (step.Finished) actionfield.S = "idle"; + SetProperty(prefix, target, actionfield); + + // Store the whole step. + *stepstorage = step; + + // Return the correct values. + Action = FString(actionfield.S.size(), (const UTF8CHAR*)actionfield.S.data()); + bChanged = (step.Hash != oldhash); } FString UlxAnimationStepLibrary::AnimationStepDebugString(const FlxAnimationStep& step) { @@ -96,10 +135,6 @@ FString UlxAnimationStepLibrary::AnimationStepDebugString(const FlxAnimationStep return FlxAnimationStepDecoder::DebugString(step.Finished, step.Finished, step.Hash, body); } -void UlxAnimationStepLibrary::UnpackAnimationStep(UObject* into, const FlxAnimationStep& step, const FString& prefix) { - step.Unpack(prefix, into); -} - static FlxAnimationField FindAnimationFieldLL(const FlxAnimationStep& step, std::string_view name) { std::string_view body((const char*)(step.Body.GetData()), step.Body.Num()); FlxAnimationStepDecoder decoder(body); diff --git a/Source/Integration/AnimQueue.h b/Source/Integration/AnimQueue.h index 987545c0..7acafc42 100644 --- a/Source/Integration/AnimQueue.h +++ b/Source/Integration/AnimQueue.h @@ -36,34 +36,6 @@ public: FlxAnimationStep() : Finished(false), Hash(0), Body(), Blueprint() {} 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." - // - // 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. - // - // All properties of the UObject starting with the specified - // prefix are cleared before unpacking the animation step. - // - // 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. - // - // Automatically injects a boolean property "idle" representing - // whether the property's finished flag is set. - // - bool Unpack(const FString& prefix, UObject* into) const; - // Auto-Execute // // These functions automatically update certain actor @@ -95,8 +67,29 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Luprex|Animation Step") static FString AnimationStepDebugString(const FlxAnimationStep& step); - UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "into"), Category = "Luprex|Animation Step") - static void UnpackAnimationStep(UObject* into, const FlxAnimationStep& step, const FString& VariableNamePrefix = TEXT("aq")); + // 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(BlueprintCallable, BlueprintPure, Category = "Luprex|Animation Step") static bool AnimationStepEqual(const FlxAnimationStep &StepA, const FlxAnimationStep &StepB); diff --git a/Source/Integration/UtilityLibrary.cpp b/Source/Integration/UtilityLibrary.cpp index 10710ae6..6a1b28ea 100644 --- a/Source/Integration/UtilityLibrary.cpp +++ b/Source/Integration/UtilityLibrary.cpp @@ -22,10 +22,7 @@ void UlxUtilityLibrary::CallFunctionByName(UObject *object, const FString &namep FBlueprintCoreDelegates::ThrowScriptException(FFrame::GetThreadLocalTopStackFrame()->Object, *FFrame::GetThreadLocalTopStackFrame(), ExceptionInfo); return; } -// UFunction* function = object->FindFunction(FName(*fullname)); - - UClass *uclass = object->GetClass(); - UFunction* function = uclass->FindFunctionByName(FName(*fullname)); + UFunction* function = object->FindFunction(FName(*fullname)); if (function == nullptr) { function = object->FindFunction(FName(*fallback)); if (function == nullptr) {