diff --git a/Content/TangibleActor.uasset b/Content/TangibleActor.uasset index 8caa1ae1..b1af93f6 100644 --- a/Content/TangibleActor.uasset +++ b/Content/TangibleActor.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff28db0da7cc626522df8323b269291d5796c29889d52cd62528489e5471cd67 -size 89310 +oid sha256:b16c6946e9c9604d021490b1cf4a60a216b9c22d17c5885ce242866e3949ad02 +size 95418 diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index 4bf31cbf..eaa1cb62 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -47,15 +47,15 @@ FString FlxAnimQueueDecoder::DebugString(std::string_view queue) { FlxAnimQueueDecoder decoder(queue); while (!decoder.AtEOF()) { FlxAnimStep step = decoder.ReadStep(); - FString stepdebug = FlxAnimStepDecoder::DebugString(step); + FString stepdebug = FlxAnimStepDecoder::DebugString(step.Body); result.Appendf(TEXT("%s\n"), *stepdebug); } return result; } -FString FlxAnimStepDecoder::DebugString(const FlxAnimStep& step) { +FString FlxAnimStepDecoder::DebugString(std::string_view body) { FString result; - FlxAnimStepDecoder decoder(step); + FlxAnimStepDecoder decoder(body); bool first = true; while (!decoder.AtEOF()) { FlxAnimField field = decoder.ReadField(); @@ -83,6 +83,78 @@ FString FlxAnimStepDecoder::DebugString(const FlxAnimStep& step) { return result; } +bool FlxAnimStepDecoder::ClearProperties(const FString& prefix, UObject* obj) { + 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; + bool match1 = (fprop->GetFName().Compare(prefixlo) > 0); + bool match2 = (fprop->GetFName().Compare(prefixhi) < 0); + if (match1 && match2) { + uint8* pptr = fprop->ContainerPtrToValuePtr(obj); + fprop->ClearValue(pptr); + } + } + return true; +} + +bool FlxAnimStepDecoder::SetProperty(const FString& name, UObject* obj, const FlxAnimField& field) { + UClass* uclass = obj->GetClass(); + FName nname(name); + switch (field.Type) { + case ElxAnimValueType::STRING: { + FStrProperty* fprop = FindFProperty(uclass, nname); + if (fprop == nullptr) return false; + FString* pptr = fprop->ContainerPtrToValuePtr(obj); + *pptr = FString(field.S.size(), (const UTF8CHAR*)field.S.data()); + return true; + } + case ElxAnimValueType::NUMBER: { + FDoubleProperty* fprop = FindFProperty(uclass, nname); + if (fprop == nullptr) return false; + double* pptr = fprop->ContainerPtrToValuePtr(obj); + fprop->SetPropertyValue(pptr, field.X); + return true; + } + case ElxAnimValueType::BOOLEAN: { + FBoolProperty* fprop = FindFProperty(uclass, nname); + if (fprop == nullptr) return false; + uint8* pptr = fprop->ContainerPtrToValuePtr(obj); + fprop->SetPropertyValue(pptr, (field.X == 1.0)); + return true; + } + case ElxAnimValueType::XYZ: { + FStructProperty* fprop = FindFProperty(uclass, nname); + if (fprop == nullptr) return false; + if (fprop->Struct != TBaseStructure::Get()) return false; + FVector* pptr = fprop->ContainerPtrToValuePtr(obj); + *pptr = FVector(field.X, field.Y, field.Z); + return true; + } + } + return false; +} + +#pragma optimize("", off) +bool FlxAnimStepDecoder::UnpackInto(std::string_view body, const FString& prefix, bool preclear, UObject* obj) { + UClass* uclass = obj->GetClass(); + FlxAnimStepDecoder decoder(body); + bool ok = true; + if (preclear) { + ok &= ClearProperties(prefix, obj); + } + while (!decoder.AtEOF()) { + FlxAnimField field = decoder.ReadField(); + FString sname(field.Name.size(), (const UTF8CHAR*)field.Name.data()); + ok &= SetProperty(prefix + sname, obj, field); + } + return ok; +} FlxAnimTracker::FlxAnimTracker() { AQ.Empty(); diff --git a/Source/Integration/AnimQueue.h b/Source/Integration/AnimQueue.h index eeec04f3..338dad14 100644 --- a/Source/Integration/AnimQueue.h +++ b/Source/Integration/AnimQueue.h @@ -141,11 +141,12 @@ class FlxAnimStepDecoder { private: FlxStringDecoder Decoder; + static bool ClearProperties(const FString& prefix, UObject* obj); + static bool SetProperty(const FString& name, UObject *obj, const FlxAnimField& value); public: // Initialize the FlxAnimStepDecoder from the FlxAnimStep. // - FlxAnimStepDecoder(const FlxAnimStep &step) : Decoder(step.Body) {} - FlxAnimStepDecoder(const FlxAnimStoredStep& step) : Decoder(step.Body) {} + FlxAnimStepDecoder(std::string_view body) : Decoder(body) {} // Return true if the parser has reached the end of the string. // @@ -157,7 +158,33 @@ public: // Convert an AnimStep to an FString. // - static FString DebugString(const FlxAnimStep &step); + static FString DebugString(std::string_view body); + + // 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. + // + static bool UnpackInto(std::string_view body, const FString &prefix, bool preclear, UObject* obj); }; //////////////////////////////////////////////// diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index 73d08994..d338527c 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -104,6 +104,15 @@ void AIntegrationGameModeBase::MaybeTriggerUpdateTask(float deltaseconds) { } } +//#pragma optimize( "", off ) +//void SetLocal(UObject* obj, const char *name, int value) { +// FString sname((const UTF8CHAR *)name); +// FName nname(sname); +// UClass* uclass = obj->GetClass(); +// FProperty* fprop = FindFProperty(uclass, nname); +// FStructProperty* sprop = FindFProperty(uclass, nname); +//} + void AIntegrationGameModeBase::UpdateTangibles() { if (!Playing) return; FlxLockedWrapper w(LockableWrapper); @@ -130,6 +139,9 @@ void AIntegrationGameModeBase::UpdateTangibles() { FlxAnimStoredStep step; ElxAnimPlaybackMode mode = t->AnimTracker.GetNextStep(step); bool started = false; + if (mode != ElxAnimPlaybackMode::INVALID) { + FlxAnimStepDecoder::UnpackInto(step.Body, TEXT("aq"), true, t->Actor); + } switch (mode) { case ElxAnimPlaybackMode::INVALID: started = false; // Nothing to do.