Now passing FlxAnimationStep into the blueprint
This commit is contained in:
BIN
Content/TangibleActor.uasset
LFS
BIN
Content/TangibleActor.uasset
LFS
Binary file not shown.
@@ -1,89 +1,13 @@
|
|||||||
|
|
||||||
#include "AnimQueue.h"
|
#include "AnimQueue.h"
|
||||||
|
|
||||||
FlxAnimStep FlxAnimQueueDecoder::ReadStep() {
|
FlxAnimationStep::FlxAnimationStep(uint64 hash, std::string_view body) {
|
||||||
FlxAnimStep result;
|
Hash = hash;
|
||||||
result.Hash = Decoder.read_uint64();
|
Body.SetNum(body.size());
|
||||||
result.Body = Decoder.read_string_view();
|
memcpy(Body.GetData(), body.data(), body.size());
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FlxAnimField FlxAnimStepDecoder::ReadField() {
|
static bool ClearProperties(const FString& prefix, UObject* obj) {
|
||||||
FlxAnimField result;
|
|
||||||
result.Name = Decoder.read_string_view();
|
|
||||||
result.Persistent = Decoder.read_bool();
|
|
||||||
result.Type = (ElxAnimValueType)Decoder.read_uint8();
|
|
||||||
switch (result.Type) {
|
|
||||||
case ElxAnimValueType::STRING: {
|
|
||||||
result.S = Decoder.read_string_view();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ElxAnimValueType::NUMBER: {
|
|
||||||
result.X = Decoder.read_double();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ElxAnimValueType::BOOLEAN: {
|
|
||||||
result.X = Decoder.read_bool() ? 1.0 : 0.0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ElxAnimValueType::XYZ: {
|
|
||||||
result.X = Decoder.read_double();
|
|
||||||
result.Y = Decoder.read_double();
|
|
||||||
result.Z = Decoder.read_double();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
Decoder.set_at_eof();
|
|
||||||
result.Type = ElxAnimValueType::BOOLEAN;
|
|
||||||
result.X = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
FString FlxAnimQueueDecoder::DebugString(std::string_view queue) {
|
|
||||||
FString result;
|
|
||||||
FlxAnimQueueDecoder decoder(queue);
|
|
||||||
while (!decoder.AtEOF()) {
|
|
||||||
FlxAnimStep step = decoder.ReadStep();
|
|
||||||
FString stepdebug = FlxAnimStepDecoder::DebugString(step.Body);
|
|
||||||
result.Appendf(TEXT("%s\n"), *stepdebug);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
FString FlxAnimStepDecoder::DebugString(std::string_view body) {
|
|
||||||
FString result;
|
|
||||||
FlxAnimStepDecoder decoder(body);
|
|
||||||
bool first = true;
|
|
||||||
while (!decoder.AtEOF()) {
|
|
||||||
FlxAnimField field = decoder.ReadField();
|
|
||||||
if (!first) {
|
|
||||||
result.Append(TEXT(" "));
|
|
||||||
}
|
|
||||||
result.Append(FString(field.Name.size(), (const UTF8CHAR*)field.Name.data()));
|
|
||||||
result.Append(field.Persistent ? TEXT("=") : TEXT(":"));
|
|
||||||
switch (field.Type) {
|
|
||||||
case ElxAnimValueType::STRING:
|
|
||||||
result.Append(FString(field.S.size(), (const UTF8CHAR*)field.S.data()));
|
|
||||||
break;
|
|
||||||
case ElxAnimValueType::NUMBER:
|
|
||||||
result.Appendf(TEXT("%lf"), field.X);
|
|
||||||
break;
|
|
||||||
case ElxAnimValueType::BOOLEAN:
|
|
||||||
result.Append((field.X) == 1.0 ? TEXT("true") : TEXT("false"));
|
|
||||||
break;
|
|
||||||
case ElxAnimValueType::XYZ:
|
|
||||||
result.Appendf(TEXT("%lf,%lf,%lf"), field.X, field.Y, field.Z);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FlxAnimStepDecoder::ClearProperties(const FString& prefix, UObject* obj) {
|
|
||||||
UClass* uclass = obj->GetClass();
|
UClass* uclass = obj->GetClass();
|
||||||
if (prefix.IsEmpty()) {
|
if (prefix.IsEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -103,7 +27,7 @@ bool FlxAnimStepDecoder::ClearProperties(const FString& prefix, UObject* obj) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlxAnimStepDecoder::SetProperty(const FString& name, UObject* obj, const FlxAnimField& field) {
|
static bool SetProperty(const FString& name, UObject* obj, const FlxAnimationField& field) {
|
||||||
UClass* uclass = obj->GetClass();
|
UClass* uclass = obj->GetClass();
|
||||||
FName nname(name);
|
FName nname(name);
|
||||||
switch (field.Type) {
|
switch (field.Type) {
|
||||||
@@ -140,28 +64,118 @@ bool FlxAnimStepDecoder::SetProperty(const FString& name, UObject* obj, const Fl
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma optimize("", off)
|
bool FlxAnimationStep::Unpack(const FString& prefix, UObject* into, bool preclear) const {
|
||||||
bool FlxAnimStepDecoder::UnpackInto(std::string_view body, const FString& prefix, bool preclear, UObject* obj) {
|
UClass* uclass = into->GetClass();
|
||||||
UClass* uclass = obj->GetClass();
|
std::string_view body((const char*)(Body.GetData()), Body.Num());
|
||||||
FlxAnimStepDecoder decoder(body);
|
FlxAnimationStepDecoder decoder(body);
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
if (preclear) {
|
if (preclear) {
|
||||||
ok &= ClearProperties(prefix, obj);
|
ok &= ClearProperties(prefix, into);
|
||||||
}
|
}
|
||||||
while (!decoder.AtEOF()) {
|
while (!decoder.AtEOF()) {
|
||||||
FlxAnimField field = decoder.ReadField();
|
FlxAnimationField field = decoder.ReadField();
|
||||||
FString sname(field.Name.size(), (const UTF8CHAR*)field.Name.data());
|
FString sname(field.Name.size(), (const UTF8CHAR*)field.Name.data());
|
||||||
ok &= SetProperty(prefix + sname, obj, field);
|
ok &= SetProperty(prefix + sname, into, field);
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FString UlxAnimationStepLibrary::AnimationStepDebugString(const FlxAnimationStep& step) {
|
||||||
|
std::string_view body((const char*)(step.Body.GetData()), step.Body.Num());
|
||||||
|
return FlxAnimationStepDecoder::DebugString(step.Hash, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UlxAnimationStepLibrary::UnpackAnimationStep(const FlxAnimationStep& step,
|
||||||
|
const FString& prefix, UObject* into, bool preclear) {
|
||||||
|
step.Unpack(prefix, into, preclear);
|
||||||
|
};
|
||||||
|
|
||||||
|
FlxAnimationStepView FlxAnimQueueDecoder::ReadStep() {
|
||||||
|
FlxAnimationStepView result;
|
||||||
|
result.Hash = Decoder.read_uint64();
|
||||||
|
result.Body = Decoder.read_string_view();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlxAnimationField FlxAnimationStepDecoder::ReadField() {
|
||||||
|
FlxAnimationField result;
|
||||||
|
result.Name = Decoder.read_string_view();
|
||||||
|
result.Persistent = Decoder.read_bool();
|
||||||
|
result.Type = (ElxAnimValueType)Decoder.read_uint8();
|
||||||
|
switch (result.Type) {
|
||||||
|
case ElxAnimValueType::STRING: {
|
||||||
|
result.S = Decoder.read_string_view();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ElxAnimValueType::NUMBER: {
|
||||||
|
result.X = Decoder.read_double();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ElxAnimValueType::BOOLEAN: {
|
||||||
|
result.X = Decoder.read_bool() ? 1.0 : 0.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ElxAnimValueType::XYZ: {
|
||||||
|
result.X = Decoder.read_double();
|
||||||
|
result.Y = Decoder.read_double();
|
||||||
|
result.Z = Decoder.read_double();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
Decoder.set_at_eof();
|
||||||
|
result.Type = ElxAnimValueType::BOOLEAN;
|
||||||
|
result.X = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FString FlxAnimationStepDecoder::DebugString(uint64 hash, std::string_view body) {
|
||||||
|
FString result;
|
||||||
|
FlxAnimationStepDecoder decoder(body);
|
||||||
|
result.Appendf(TEXT("Hash=%016llx"), hash);
|
||||||
|
while (!decoder.AtEOF()) {
|
||||||
|
FlxAnimationField field = decoder.ReadField();
|
||||||
|
result.Append(TEXT(" "));
|
||||||
|
result.Append(FString(field.Name.size(), (const UTF8CHAR*)field.Name.data()));
|
||||||
|
result.Append(field.Persistent ? TEXT("=") : TEXT(":"));
|
||||||
|
switch (field.Type) {
|
||||||
|
case ElxAnimValueType::STRING:
|
||||||
|
result.Append(FString(field.S.size(), (const UTF8CHAR*)field.S.data()));
|
||||||
|
break;
|
||||||
|
case ElxAnimValueType::NUMBER:
|
||||||
|
result.Appendf(TEXT("%lf"), field.X);
|
||||||
|
break;
|
||||||
|
case ElxAnimValueType::BOOLEAN:
|
||||||
|
result.Append((field.X) == 1.0 ? TEXT("true") : TEXT("false"));
|
||||||
|
break;
|
||||||
|
case ElxAnimValueType::XYZ:
|
||||||
|
result.Appendf(TEXT("%lf,%lf,%lf"), field.X, field.Y, field.Z);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FString FlxAnimQueueDecoder::DebugString(std::string_view queue) {
|
||||||
|
FString result;
|
||||||
|
FlxAnimQueueDecoder decoder(queue);
|
||||||
|
while (!decoder.AtEOF()) {
|
||||||
|
FlxAnimationStepView step = decoder.ReadStep();
|
||||||
|
FString stepdebug = FlxAnimationStepDecoder::DebugString(step.Hash, step.Body);
|
||||||
|
result.Appendf(TEXT("%s\n"), *stepdebug);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FlxAnimTracker::FlxAnimTracker() {
|
FlxAnimTracker::FlxAnimTracker() {
|
||||||
AQ.Empty();
|
AQ.Empty();
|
||||||
FirstSeqno = 0;
|
FirstSeqno = 0;
|
||||||
HashToSeqno.Empty();
|
HashToSeqno.Empty();
|
||||||
UnstartedSeqno = 0;
|
UnstartedSeqno = 0;
|
||||||
PlaybackMode = ElxAnimPlaybackMode::INVALID;
|
PlaybackMode = ElxAnimationMode::INVALID;
|
||||||
AbortedHashes.Empty();
|
AbortedHashes.Empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,10 +209,10 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
|||||||
// after the matching record onto a stack of new records.
|
// after the matching record onto a stack of new records.
|
||||||
//
|
//
|
||||||
FlxAnimQueueDecoder decoder(encqueue);
|
FlxAnimQueueDecoder decoder(encqueue);
|
||||||
TArray<FlxAnimStep> newsteps;
|
TArray<FlxAnimationStepView> newsteps;
|
||||||
int32 matchingseqno = -1;
|
int32 matchingseqno = -1;
|
||||||
while (!decoder.AtEOF()) {
|
while (!decoder.AtEOF()) {
|
||||||
FlxAnimStep step = decoder.ReadStep();
|
FlxAnimationStepView step = decoder.ReadStep();
|
||||||
int32* stepseq = HashToSeqno.Find(step.Hash);
|
int32* stepseq = HashToSeqno.Find(step.Hash);
|
||||||
if (stepseq == nullptr) {
|
if (stepseq == nullptr) {
|
||||||
newsteps.Emplace(step);
|
newsteps.Emplace(step);
|
||||||
@@ -233,13 +247,13 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
|||||||
//
|
//
|
||||||
if (UnstartedSeqno > (FirstSeqno + AQ.Num())) {
|
if (UnstartedSeqno > (FirstSeqno + AQ.Num())) {
|
||||||
UnstartedSeqno = matchingseqno;
|
UnstartedSeqno = matchingseqno;
|
||||||
PlaybackMode = ElxAnimPlaybackMode::BLEND_TO_FINAL;
|
PlaybackMode = ElxAnimationMode::BlendToFinal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transfer the new animations onto the queue.
|
// Transfer the new animations onto the queue.
|
||||||
//
|
//
|
||||||
while (!newsteps.IsEmpty()) {
|
while (!newsteps.IsEmpty()) {
|
||||||
FlxAnimStep step = newsteps.Pop();
|
FlxAnimationStepView step = newsteps.Pop();
|
||||||
int32 seqno = FirstSeqno + AQ.Num();
|
int32 seqno = FirstSeqno + AQ.Num();
|
||||||
AQ.EmplaceLast(step.Hash, step.Body);
|
AQ.EmplaceLast(step.Hash, step.Body);
|
||||||
HashToSeqno.Emplace(step.Hash, seqno);
|
HashToSeqno.Emplace(step.Hash, seqno);
|
||||||
@@ -268,7 +282,7 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
|||||||
} else {
|
} else {
|
||||||
UnstartedSeqno = FirstSeqno + AQ.Num() - 1;
|
UnstartedSeqno = FirstSeqno + AQ.Num() - 1;
|
||||||
}
|
}
|
||||||
PlaybackMode = ElxAnimPlaybackMode::WARP_TO_FINAL;
|
PlaybackMode = ElxAnimationMode::WarpToFinal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,15 +293,15 @@ TArray<uint64> FlxAnimTracker::GetAborted() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElxAnimPlaybackMode FlxAnimTracker::GetNextStep(FlxAnimStoredStep &step) {
|
ElxAnimationMode FlxAnimTracker::GetNextStep(FlxAnimationStep &step) {
|
||||||
int offset = UnstartedSeqno - FirstSeqno;
|
int offset = UnstartedSeqno - FirstSeqno;
|
||||||
if (offset < AQ.Num()) {
|
if (offset < AQ.Num()) {
|
||||||
step = AQ[offset];
|
step = AQ[offset];
|
||||||
return PlaybackMode;
|
return PlaybackMode;
|
||||||
} else {
|
} else {
|
||||||
step.Hash = 0;
|
step.Hash = 0;
|
||||||
step.Body = "";
|
step.Body.Empty();
|
||||||
return ElxAnimPlaybackMode::INVALID;
|
return ElxAnimationMode::INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,6 +310,6 @@ void FlxAnimTracker::StartedStep(uint64 hash) {
|
|||||||
check(offset < AQ.Num());
|
check(offset < AQ.Num());
|
||||||
check(AQ[offset].Hash == hash);
|
check(AQ[offset].Hash == hash);
|
||||||
UnstartedSeqno += 1;
|
UnstartedSeqno += 1;
|
||||||
PlaybackMode = ElxAnimPlaybackMode::START_ANIMATION;
|
PlaybackMode = ElxAnimationMode::StartAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "StringDecoder.h"
|
#include "StringDecoder.h"
|
||||||
#include "Containers/Deque.h"
|
#include "Containers/Deque.h"
|
||||||
|
#include "AnimQueue.generated.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -31,15 +32,16 @@ enum class ElxAnimValueType {
|
|||||||
//
|
//
|
||||||
// 3. Blend to Final. Skip the actual animation, and blend
|
// 3. Blend to Final. Skip the actual animation, and blend
|
||||||
// smoothly to the final state of the animation. If the current
|
// smoothly to the final state of the animation. If the current
|
||||||
// state is very far from the final state, then maybe jump instantaneously
|
// state is very far from the final state, then maybe
|
||||||
// instead.
|
// jump instantaneously instead.
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
enum class ElxAnimPlaybackMode {
|
UENUM(BlueprintType)
|
||||||
START_ANIMATION,
|
enum class ElxAnimationMode : uint8 {
|
||||||
WARP_TO_FINAL,
|
StartAnimation,
|
||||||
BLEND_TO_FINAL,
|
WarpToFinal,
|
||||||
|
BlendToFinal,
|
||||||
INVALID,
|
INVALID,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -47,28 +49,91 @@ enum class ElxAnimPlaybackMode {
|
|||||||
//
|
//
|
||||||
// An single animation step.
|
// An single animation step.
|
||||||
//
|
//
|
||||||
// The body consists of a sequence of FlxAnimField
|
// The body consists of a sequence of FlxAnimationField
|
||||||
// records. The body is encoded, to read the
|
// records. The body is encoded, to read the
|
||||||
// FlxAnimField records you need an FlxAnimStepDecoder.
|
// FlxAnimationField records you need an
|
||||||
// This comes in two versions: the string version,
|
// FlxAnimationStepDecoder.
|
||||||
// and the string_view version.
|
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
struct FlxAnimStep {
|
USTRUCT(Blueprintable)
|
||||||
|
struct INTEGRATION_API FlxAnimationStep {
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY()
|
||||||
|
uint64 Hash;
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
TArray<uint8> 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 = Tangibles)
|
||||||
|
static FString AnimationStepDebugString(const FlxAnimationStep& step);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = Tangibles)
|
||||||
|
static void UnpackAnimationStep(const FlxAnimationStep& step,
|
||||||
|
const FString& prefix, UObject* into, bool preclear = true);
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Exposing functions to blueprints.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//UFUNCTION(BlueprintCallable)
|
||||||
|
//void Unpack(const FString& prefix, UObject* into, bool preclear = true);
|
||||||
|
|
||||||
|
struct FlxAnimationStepView {
|
||||||
uint64 Hash;
|
uint64 Hash;
|
||||||
std::string_view Body;
|
std::string_view Body;
|
||||||
|
|
||||||
FlxAnimStep() : Hash(0), Body("") {}
|
FlxAnimationStepView() : Hash(0), Body("") {}
|
||||||
FlxAnimStep(uint64 h, std::string_view b) : Hash(h), Body(b) {}
|
FlxAnimationStepView(uint64 h, std::string_view b) : Hash(h), Body(b) {}
|
||||||
};
|
|
||||||
|
|
||||||
struct FlxAnimStoredStep {
|
|
||||||
uint64 Hash;
|
|
||||||
std::string Body;
|
|
||||||
|
|
||||||
FlxAnimStoredStep() : Hash(0), Body("") {}
|
|
||||||
FlxAnimStoredStep(uint64 h, std::string_view b) : Hash(h), Body(b) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
@@ -85,7 +150,7 @@ struct FlxAnimStoredStep {
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
struct FlxAnimField {
|
struct FlxAnimationField {
|
||||||
std::string_view Name;
|
std::string_view Name;
|
||||||
bool Persistent;
|
bool Persistent;
|
||||||
ElxAnimValueType Type;
|
ElxAnimValueType Type;
|
||||||
@@ -119,7 +184,7 @@ public:
|
|||||||
|
|
||||||
// Read one animation step.
|
// Read one animation step.
|
||||||
//
|
//
|
||||||
FlxAnimStep ReadStep();
|
FlxAnimationStepView ReadStep();
|
||||||
|
|
||||||
// Convert an AnimQueue to an FString.
|
// Convert an AnimQueue to an FString.
|
||||||
//
|
//
|
||||||
@@ -131,22 +196,20 @@ public:
|
|||||||
// An Animation Step Decoder.
|
// An Animation Step Decoder.
|
||||||
//
|
//
|
||||||
// This acts a lot like a stream reader,
|
// This acts a lot like a stream reader,
|
||||||
// it reads one FlxAnimField at a time from
|
// it reads one FlxAnimationField at a time from
|
||||||
// the animation queue until you reach
|
// the animation queue until you reach
|
||||||
// 'end-of-file'.
|
// 'end-of-file'.
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
class FlxAnimStepDecoder {
|
class FlxAnimationStepDecoder {
|
||||||
private:
|
private:
|
||||||
FlxStringDecoder Decoder;
|
FlxStringDecoder Decoder;
|
||||||
|
|
||||||
static bool ClearProperties(const FString& prefix, UObject* obj);
|
|
||||||
static bool SetProperty(const FString& name, UObject *obj, const FlxAnimField& value);
|
|
||||||
public:
|
public:
|
||||||
// Initialize the FlxAnimStepDecoder from the FlxAnimStep.
|
// Initialize the FlxAnimationStepDecoder from the FlxAnimationStepView.
|
||||||
//
|
//
|
||||||
FlxAnimStepDecoder(std::string_view body) : Decoder(body) {}
|
FlxAnimationStepDecoder(std::string_view body) : Decoder(body) {}
|
||||||
|
|
||||||
// Return true if the parser has reached the end of the string.
|
// Return true if the parser has reached the end of the string.
|
||||||
//
|
//
|
||||||
@@ -154,37 +217,11 @@ public:
|
|||||||
|
|
||||||
// Read one field.
|
// Read one field.
|
||||||
//
|
//
|
||||||
FlxAnimField ReadField();
|
FlxAnimationField ReadField();
|
||||||
|
|
||||||
// Convert an AnimStep to an FString.
|
// Convert an AnimStep to an FString.
|
||||||
//
|
//
|
||||||
static FString DebugString(std::string_view body);
|
static FString DebugString(uint64 hash, 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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
@@ -205,7 +242,7 @@ public:
|
|||||||
// store the hashes, not the steps. The First element
|
// store the hashes, not the steps. The First element
|
||||||
// of the queue is the oldest item.
|
// of the queue is the oldest item.
|
||||||
//
|
//
|
||||||
TDeque<FlxAnimStoredStep> AQ;
|
TDeque<FlxAnimationStep> AQ;
|
||||||
|
|
||||||
// The sequence number of the first item in AQ.
|
// The sequence number of the first item in AQ.
|
||||||
//
|
//
|
||||||
@@ -221,7 +258,7 @@ public:
|
|||||||
|
|
||||||
// Indicates whether the unstarted animation should be played or otherwise.
|
// Indicates whether the unstarted animation should be played or otherwise.
|
||||||
//
|
//
|
||||||
ElxAnimPlaybackMode PlaybackMode;
|
ElxAnimationMode PlaybackMode;
|
||||||
|
|
||||||
// Array of recently-aborted hash values.
|
// Array of recently-aborted hash values.
|
||||||
//
|
//
|
||||||
@@ -254,7 +291,7 @@ public:
|
|||||||
// playback mode. If the playback mode is INVALID then there is
|
// playback mode. If the playback mode is INVALID then there is
|
||||||
// no next step to play
|
// no next step to play
|
||||||
//
|
//
|
||||||
ElxAnimPlaybackMode GetNextStep(FlxAnimStoredStep& step);
|
ElxAnimationMode GetNextStep(FlxAnimationStep& step);
|
||||||
|
|
||||||
// Declare that an animation has been started.
|
// Declare that an animation has been started.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -136,28 +136,13 @@ void AIntegrationGameModeBase::UpdateTangibles() {
|
|||||||
for (uint64 hash : aborted) {
|
for (uint64 hash : aborted) {
|
||||||
IlxTangibleInterface::Execute_AbortAnimation(t->Actor, hash);
|
IlxTangibleInterface::Execute_AbortAnimation(t->Actor, hash);
|
||||||
}
|
}
|
||||||
FlxAnimStoredStep step;
|
FlxAnimationStep step;
|
||||||
ElxAnimPlaybackMode mode = t->AnimTracker.GetNextStep(step);
|
ElxAnimationMode mode = t->AnimTracker.GetNextStep(step);
|
||||||
bool started = false;
|
if (mode != ElxAnimationMode::INVALID) {
|
||||||
if (mode != ElxAnimPlaybackMode::INVALID) {
|
bool started = IlxTangibleInterface::Execute_StartAnimation(t->Actor, mode, step);
|
||||||
FlxAnimStepDecoder::UnpackInto(step.Body, TEXT("aq"), true, t->Actor);
|
if (started) {
|
||||||
}
|
t->AnimTracker.StartedStep(step.Hash);
|
||||||
switch (mode) {
|
}
|
||||||
case ElxAnimPlaybackMode::INVALID:
|
|
||||||
started = false; // Nothing to do.
|
|
||||||
break;
|
|
||||||
case ElxAnimPlaybackMode::WARP_TO_FINAL:
|
|
||||||
started = IlxTangibleInterface::Execute_WarpToFinal(t->Actor, step.Hash, step.Body.size());
|
|
||||||
break;
|
|
||||||
case ElxAnimPlaybackMode::BLEND_TO_FINAL:
|
|
||||||
started = IlxTangibleInterface::Execute_BlendToFinal(t->Actor, step.Hash, step.Body.size());
|
|
||||||
break;
|
|
||||||
case ElxAnimPlaybackMode::START_ANIMATION:
|
|
||||||
started = IlxTangibleInterface::Execute_StartAnimation(t->Actor, step.Hash, step.Body.size());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (started) {
|
|
||||||
t->AnimTracker.StartedStep(step.Hash);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "UObject/Interface.h"
|
#include "UObject/Interface.h"
|
||||||
|
#include "AnimQueue.h"
|
||||||
#include "TangibleInterface.generated.h"
|
#include "TangibleInterface.generated.h"
|
||||||
|
|
||||||
// This class does not need to be modified.
|
// This class does not need to be modified.
|
||||||
@@ -23,13 +24,7 @@ class INTEGRATION_API IlxTangibleInterface
|
|||||||
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
|
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
|
||||||
public:
|
public:
|
||||||
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
|
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
|
||||||
bool StartAnimation(int64 hash, int StrLen);
|
bool StartAnimation(ElxAnimationMode mode, const FlxAnimationStep& step);
|
||||||
|
|
||||||
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
|
|
||||||
bool WarpToFinal(int64 hash, int StrLen);
|
|
||||||
|
|
||||||
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
|
|
||||||
bool BlendToFinal(int64 hash, int StrLen);
|
|
||||||
|
|
||||||
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
|
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
|
||||||
bool AbortAnimation(int64 hash);
|
bool AbortAnimation(int64 hash);
|
||||||
|
|||||||
Reference in New Issue
Block a user