Overhaul of tangible/blueprint animation interface
This commit is contained in:
BIN
Content/TangibleActor.uasset
LFS
BIN
Content/TangibleActor.uasset
LFS
Binary file not shown.
@@ -2,9 +2,11 @@
|
|||||||
#include "AnimQueue.h"
|
#include "AnimQueue.h"
|
||||||
|
|
||||||
FlxAnimationStep::FlxAnimationStep(uint64 hash, std::string_view body) {
|
FlxAnimationStep::FlxAnimationStep(uint64 hash, std::string_view body) {
|
||||||
|
Finished = false;
|
||||||
Hash = hash;
|
Hash = hash;
|
||||||
Body.SetNum(body.size());
|
Body.SetNum(body.size());
|
||||||
memcpy(Body.GetData(), body.data(), body.size());
|
memcpy(Body.GetData(), body.data(), body.size());
|
||||||
|
Blueprint = UlxAnimationStepLibrary::AnimationStepGetString(*this, "bp");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ClearProperties(const FString& prefix, UObject* obj) {
|
static bool ClearProperties(const FString& prefix, UObject* obj) {
|
||||||
@@ -85,10 +87,9 @@ FString UlxAnimationStepLibrary::AnimationStepDebugString(const FlxAnimationStep
|
|||||||
return FlxAnimationStepDecoder::DebugString(step.Hash, body);
|
return FlxAnimationStepDecoder::DebugString(step.Hash, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UlxAnimationStepLibrary::UnpackAnimationStep(const FlxAnimationStep& step,
|
void UlxAnimationStepLibrary::UnpackAnimationStep(UObject* into, const FlxAnimationStep& step, const FString& prefix) {
|
||||||
const FString& prefix, UObject* into) {
|
|
||||||
step.Unpack(prefix, into, true);
|
step.Unpack(prefix, into, true);
|
||||||
};
|
}
|
||||||
|
|
||||||
static FlxAnimationField FindAnimationField(const FlxAnimationStep& step, const FString& name) {
|
static FlxAnimationField FindAnimationField(const FlxAnimationStep& step, const FString& name) {
|
||||||
std::string_view body((const char*)(step.Body.GetData()), step.Body.Num());
|
std::string_view body((const char*)(step.Body.GetData()), step.Body.Num());
|
||||||
@@ -106,6 +107,10 @@ static FlxAnimationField FindAnimationField(const FlxAnimationStep& step, const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UlxAnimationStepLibrary::AnimationStepIsIdle(const FlxAnimationStep &step) {
|
||||||
|
return step.Finished;
|
||||||
|
}
|
||||||
|
|
||||||
FVector UlxAnimationStepLibrary::AnimationStepGetVector(const FlxAnimationStep& step, const FString& name) {
|
FVector UlxAnimationStepLibrary::AnimationStepGetVector(const FlxAnimationStep& step, const FString& name) {
|
||||||
FlxAnimationField field = FindAnimationField(step, name);
|
FlxAnimationField field = FindAnimationField(step, name);
|
||||||
if (field.Type != ElxAnimValueType::XYZ) return FVector(0, 0, 0);
|
if (field.Type != ElxAnimValueType::XYZ) return FVector(0, 0, 0);
|
||||||
@@ -138,6 +143,13 @@ FlxAnimationStepView FlxAnimQueueDecoder::ReadStep() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64 FlxAnimQueueDecoder::PeekHash() {
|
||||||
|
std::string_view rest = Decoder.GetRest();
|
||||||
|
uint64 result = Decoder.read_uint64();
|
||||||
|
Decoder.Reset(rest, false);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
FlxAnimationField FlxAnimationStepDecoder::ReadField() {
|
FlxAnimationField FlxAnimationStepDecoder::ReadField() {
|
||||||
FlxAnimationField result;
|
FlxAnimationField result;
|
||||||
result.Name = Decoder.read_string_view();
|
result.Name = Decoder.read_string_view();
|
||||||
@@ -199,6 +211,11 @@ FString FlxAnimationStepDecoder::DebugString(uint64 hash, std::string_view body)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FlxAnimQueueDecoder::FlxAnimQueueDecoder(std::string_view queue) : Decoder(queue) {
|
||||||
|
SizeLimit = Decoder.read_uint8();
|
||||||
|
ActualSize = Decoder.read_uint8();
|
||||||
|
}
|
||||||
|
|
||||||
FString FlxAnimQueueDecoder::DebugString(std::string_view queue) {
|
FString FlxAnimQueueDecoder::DebugString(std::string_view queue) {
|
||||||
FString result;
|
FString result;
|
||||||
FlxAnimQueueDecoder decoder(queue);
|
FlxAnimQueueDecoder decoder(queue);
|
||||||
@@ -216,33 +233,50 @@ FlxAnimTracker::FlxAnimTracker() {
|
|||||||
|
|
||||||
void FlxAnimTracker::Clear() {
|
void FlxAnimTracker::Clear() {
|
||||||
AQ.Empty();
|
AQ.Empty();
|
||||||
FirstSeqno = 0;
|
Changed = true;
|
||||||
HashToSeqno.Empty();
|
}
|
||||||
UnstartedSeqno = 0;
|
|
||||||
PlaybackMode = ElxAnimationMode::INVALID;
|
void FlxAnimTracker::FinishedAnimation(uint64 hash) {
|
||||||
AbortedHashes.Empty();
|
for (int i = 0; i < AQ.Num(); i++) {
|
||||||
|
if (AQ[i].Hash == hash) {
|
||||||
|
AQ[i].Finished = true;
|
||||||
|
Changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlxAnimTracker::SkipToEnd() {
|
||||||
|
for (int i = 0; i < AQ.Num(); i++) {
|
||||||
|
if (!AQ[i].Finished) {
|
||||||
|
AQ[i].Finished = true;
|
||||||
|
Changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlxAnimTracker::Update(std::string_view encqueue) {
|
void FlxAnimTracker::Update(std::string_view encqueue) {
|
||||||
// Check for an exact match. If the most recent entry
|
check(!encqueue.empty());
|
||||||
// in encqueue has the same hash as the most recent
|
|
||||||
// entry in AQ, then that's an exact match. Or,
|
// If the first hash matches, we don't bother updating at all.
|
||||||
// if both are empty, that's also an exact match.
|
|
||||||
// In case of exact match, abort early, there's no
|
|
||||||
// further work needed.
|
|
||||||
//
|
//
|
||||||
if (encqueue.empty()) {
|
FlxAnimQueueDecoder decoder(encqueue);
|
||||||
if (AQ.IsEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!AQ.IsEmpty()) {
|
if (!AQ.IsEmpty()) {
|
||||||
FlxStringDecoder qdecoder(encqueue);
|
if (decoder.PeekHash() == AQ.Last().Hash) {
|
||||||
uint64 hash = qdecoder.read_uint64();
|
|
||||||
if (hash == AQ.Last().Hash) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The Changed flag is set whenever there is any change to
|
||||||
|
// the animation queue of any kind.
|
||||||
|
//
|
||||||
|
Changed = true;
|
||||||
|
|
||||||
|
// Build a map indexing the steps in AQ.
|
||||||
|
//
|
||||||
|
TMap<uint64, int32> HashToIndex;
|
||||||
|
for (int i = 0; i < AQ.Num(); i++) {
|
||||||
|
HashToIndex.Emplace(AQ[i].Hash, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for a Luprex animation record that matches
|
// Search for a Luprex animation record that matches
|
||||||
@@ -252,108 +286,55 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
|||||||
// At the same time, push all non-matching records
|
// At the same time, push all non-matching records
|
||||||
// after the matching record onto a stack of new records.
|
// after the matching record onto a stack of new records.
|
||||||
//
|
//
|
||||||
FlxAnimQueueDecoder decoder(encqueue);
|
|
||||||
TArray<FlxAnimationStepView> newsteps;
|
TArray<FlxAnimationStepView> newsteps;
|
||||||
int32 matchingseqno = -1;
|
int32 matchingindex = -1;
|
||||||
while (!decoder.AtEOF()) {
|
while (!decoder.AtEOF()) {
|
||||||
FlxAnimationStepView step = decoder.ReadStep();
|
FlxAnimationStepView step = decoder.ReadStep();
|
||||||
int32* stepseq = HashToSeqno.Find(step.Hash);
|
int32* indexp = HashToIndex.Find(step.Hash);
|
||||||
if (stepseq == nullptr) {
|
if (indexp == nullptr) {
|
||||||
newsteps.Emplace(step);
|
newsteps.Emplace(step);
|
||||||
} else {
|
} else {
|
||||||
matchingseqno = *stepseq;
|
matchingindex = *indexp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all animations after the most recent matching
|
// Remove all animations after the most recent matching
|
||||||
// record. If we remove a 'started' animation, add that
|
// record.
|
||||||
// animation to the list of aborted animations.
|
|
||||||
//
|
//
|
||||||
int32 nremove = (FirstSeqno + AQ.Num()) - (matchingseqno + 1);
|
int32 nremove = (AQ.Num() - (matchingindex + 1));
|
||||||
check((nremove >= 0) && (nremove <= AQ.Num()));
|
check((nremove >= 0) && (nremove <= AQ.Num()));
|
||||||
for (int32 i = 0; i < nremove; i++) {
|
for (int32 i = 0; i < nremove; i++) {
|
||||||
uint64 lasthash = AQ.Last().Hash;
|
|
||||||
int32 seqno = FirstSeqno + AQ.Num() - 1;
|
|
||||||
HashToSeqno.Remove(lasthash);
|
|
||||||
if (seqno < UnstartedSeqno) {
|
|
||||||
AbortedHashes.Emplace(lasthash);
|
|
||||||
}
|
|
||||||
AQ.PopLast();
|
AQ.PopLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we aborted a 'started' animation, we have to fix
|
|
||||||
// up the Unstarted animation pointer.
|
|
||||||
//
|
|
||||||
// Note: this could leave the Unstarted pointer at
|
|
||||||
// seqno less than FirstSeqno. We will fix that state
|
|
||||||
// of affairs up later.
|
|
||||||
//
|
|
||||||
if (UnstartedSeqno > (FirstSeqno + AQ.Num())) {
|
|
||||||
UnstartedSeqno = matchingseqno;
|
|
||||||
PlaybackMode = ElxAnimationMode::BlendToFinal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transfer the new animations onto the queue.
|
// Transfer the new animations onto the queue.
|
||||||
//
|
//
|
||||||
while (!newsteps.IsEmpty()) {
|
while (!newsteps.IsEmpty()) {
|
||||||
FlxAnimationStepView step = newsteps.Pop();
|
FlxAnimationStepView step = newsteps.Pop();
|
||||||
int32 seqno = FirstSeqno + AQ.Num();
|
|
||||||
AQ.EmplaceLast(step.Hash, step.Body);
|
AQ.EmplaceLast(step.Hash, step.Body);
|
||||||
HashToSeqno.Emplace(step.Hash, seqno);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are too many animations in AQ, discard
|
// If there are too many animations in AQ, discard
|
||||||
// any very old ones.
|
// any very old ones.
|
||||||
//
|
//
|
||||||
if (AQ.Num() > 10) {
|
// TODO: this is hardwired to keep 10. Instead, we
|
||||||
int ndiscard = AQ.Num() - 10;
|
// should keep the number specified in the queue.
|
||||||
for (int i = 0; i < ndiscard; i++) {
|
|
||||||
uint64 hash = AQ.First().Hash;
|
|
||||||
HashToSeqno.Remove(hash);
|
|
||||||
AQ.PopFirst();
|
|
||||||
FirstSeqno += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If UnstartedSeqno is before the live range,
|
|
||||||
// then the whole queue has to be replayed. Don't
|
|
||||||
// do that: just fast skip to the end.
|
|
||||||
//
|
//
|
||||||
if (UnstartedSeqno <= FirstSeqno) {
|
int limit = 10;
|
||||||
if (AQ.Num() == 0) {
|
int ndiscard = AQ.Num() - limit;
|
||||||
UnstartedSeqno = FirstSeqno;
|
if (ndiscard > 0) {
|
||||||
} else {
|
for (int i = 0; i < ndiscard; i++) {
|
||||||
UnstartedSeqno = FirstSeqno + AQ.Num() - 1;
|
AQ.PopFirst();
|
||||||
}
|
}
|
||||||
PlaybackMode = ElxAnimationMode::WarpToFinal;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TArray<uint64> FlxAnimTracker::GetAborted() {
|
FlxAnimationStep FlxAnimTracker::GetCurrentAnimation() {
|
||||||
TArray<uint64> result;
|
for (int i = 0; i < AQ.Num(); i++) {
|
||||||
result = std::move(AbortedHashes);
|
if (!AQ[i].Finished) {
|
||||||
AbortedHashes.Empty();
|
return AQ[i];
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ElxAnimationMode FlxAnimTracker::GetNextStep(FlxAnimationStep &step) {
|
|
||||||
int offset = UnstartedSeqno - FirstSeqno;
|
|
||||||
if (offset < AQ.Num()) {
|
|
||||||
step = AQ[offset];
|
|
||||||
return PlaybackMode;
|
|
||||||
} else {
|
|
||||||
step.Hash = 0;
|
|
||||||
step.Body.Empty();
|
|
||||||
return ElxAnimationMode::INVALID;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return AQ.Last();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlxAnimTracker::StartedStep(uint64 hash) {
|
|
||||||
int offset = UnstartedSeqno - FirstSeqno;
|
|
||||||
check(offset < AQ.Num());
|
|
||||||
check(AQ[offset].Hash == hash);
|
|
||||||
UnstartedSeqno += 1;
|
|
||||||
PlaybackMode = ElxAnimationMode::StartAnimation;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,32 +19,6 @@ enum class ElxAnimValueType {
|
|||||||
INVALID
|
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.
|
// An single animation step.
|
||||||
@@ -61,13 +35,19 @@ struct INTEGRATION_API FlxAnimationStep {
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
UPROPERTY()
|
||||||
|
bool Finished;
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
uint64 Hash;
|
uint64 Hash;
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
TArray<uint8> Body;
|
TArray<uint8> Body;
|
||||||
|
|
||||||
FlxAnimationStep() : Hash(0), Body() {}
|
UPROPERTY()
|
||||||
|
FString Blueprint;
|
||||||
|
|
||||||
|
FlxAnimationStep() : Finished(false), Hash(0), Body(), Blueprint() {}
|
||||||
FlxAnimationStep(uint64 h, std::string_view b);
|
FlxAnimationStep(uint64 h, std::string_view b);
|
||||||
|
|
||||||
// Unpack an AnimStep into a UObject
|
// Unpack an AnimStep into a UObject
|
||||||
@@ -114,9 +94,11 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex)
|
UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex)
|
||||||
static FString AnimationStepDebugString(const FlxAnimationStep& step);
|
static FString AnimationStepDebugString(const FlxAnimationStep& step);
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Category = Luprex)
|
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "into"), Category = Luprex)
|
||||||
static void UnpackAnimationStep(const FlxAnimationStep& step,
|
static void UnpackAnimationStep(UObject* into, const FlxAnimationStep& step, const FString& VariableNamePrefix);
|
||||||
const FString& VariableNamePrefix, UObject* into);
|
|
||||||
|
UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex)
|
||||||
|
static bool AnimationStepIsIdle(const FlxAnimationStep &step);
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex)
|
UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex)
|
||||||
static FVector AnimationStepGetVector(const FlxAnimationStep& step, const FString& name);
|
static FVector AnimationStepGetVector(const FlxAnimationStep& step, const FString& name);
|
||||||
@@ -181,10 +163,23 @@ class FlxAnimQueueDecoder {
|
|||||||
private:
|
private:
|
||||||
FlxStringDecoder Decoder;
|
FlxStringDecoder Decoder;
|
||||||
|
|
||||||
|
// These values are immediately read from the header.
|
||||||
|
//
|
||||||
|
int SizeLimit;
|
||||||
|
int ActualSize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Initialize the FlxAnimQueueDecoder with the encoded animation queue.
|
// Initialize the FlxAnimQueueDecoder with the encoded animation queue.
|
||||||
//
|
//
|
||||||
FlxAnimQueueDecoder(std::string_view s) : Decoder(s) {}
|
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.
|
// Return true if the parser has reached the end of the string.
|
||||||
//
|
//
|
||||||
@@ -194,6 +189,10 @@ public:
|
|||||||
//
|
//
|
||||||
FlxAnimationStepView ReadStep();
|
FlxAnimationStepView ReadStep();
|
||||||
|
|
||||||
|
// Peek at the hash of the next animation step.
|
||||||
|
//
|
||||||
|
uint64 PeekHash();
|
||||||
|
|
||||||
// Convert an AnimQueue to an FString.
|
// Convert an AnimQueue to an FString.
|
||||||
//
|
//
|
||||||
static FString DebugString(std::string_view s);
|
static FString DebugString(std::string_view s);
|
||||||
@@ -252,26 +251,11 @@ public:
|
|||||||
//
|
//
|
||||||
TDeque<FlxAnimationStep> AQ;
|
TDeque<FlxAnimationStep> AQ;
|
||||||
|
|
||||||
// The sequence number of the first item in AQ.
|
// True if something has recently changed.
|
||||||
//
|
//
|
||||||
int32 FirstSeqno;
|
bool Changed;
|
||||||
|
|
||||||
// Map from hash to sequence number.
|
|
||||||
//
|
|
||||||
TMap<uint64, int32> 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<uint64> AbortedHashes;
|
|
||||||
|
|
||||||
|
private:
|
||||||
public:
|
public:
|
||||||
// Construct a tracker.
|
// Construct a tracker.
|
||||||
//
|
//
|
||||||
@@ -290,24 +274,39 @@ public:
|
|||||||
//
|
//
|
||||||
void Update(std::string_view encqueue);
|
void Update(std::string_view encqueue);
|
||||||
|
|
||||||
// Fetch the aborted hash values.
|
// Get the current animation step.
|
||||||
//
|
//
|
||||||
// This gets the array of aborted hashes and clears
|
// Get the current animation step. This is the step that the
|
||||||
// the stored array.
|
// blueprint should currently be playing.
|
||||||
//
|
//
|
||||||
TArray<uint64> GetAborted();
|
FlxAnimationStep GetCurrentAnimation();
|
||||||
|
|
||||||
// Get the next unstarted animation step.
|
// Declare that an animation is finished.
|
||||||
//
|
//
|
||||||
// Get the next animation step. Returns the next step and the
|
// The blueprint uses this function call to indicate that it
|
||||||
// playback mode. If the playback mode is INVALID then there is
|
// is done playing the specified animation. This will cause the
|
||||||
// no next step to play
|
// animation to be marked as finished, which in turn causes
|
||||||
|
// 'GetCurrentStep' to advance to the next animation.
|
||||||
//
|
//
|
||||||
ElxAnimationMode GetNextStep(FlxAnimationStep& step);
|
void FinishedAnimation(uint64 Hash);
|
||||||
|
|
||||||
// Declare that an animation has been started.
|
// Skip to the end of the animation queue.
|
||||||
//
|
//
|
||||||
// After starting an animation, you should call this.
|
// This is equivalent to calling 'FinishedHash' on every
|
||||||
|
// animation in the entire queue.
|
||||||
//
|
//
|
||||||
void StartedStep(uint64 Hash);
|
void SkipToEnd();
|
||||||
|
|
||||||
|
// 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; }
|
||||||
};
|
};
|
||||||
@@ -7,6 +7,19 @@ FlxStringDecoder::FlxStringDecoder(std::string_view s) {
|
|||||||
ErrStringTooLong = false;
|
ErrStringTooLong = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FlxStringDecoder::Reset(std::string_view s, bool clear) {
|
||||||
|
Text = s.data();
|
||||||
|
Size = s.size();
|
||||||
|
if (clear) {
|
||||||
|
ErrBeyondEOF = false;
|
||||||
|
ErrStringTooLong = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view FlxStringDecoder::GetRest() {
|
||||||
|
return std::string_view(Text, Size);
|
||||||
|
}
|
||||||
|
|
||||||
std::string_view FlxStringDecoder::read_string_view() {
|
std::string_view FlxStringDecoder::read_string_view() {
|
||||||
size_t length = read_length();
|
size_t length = read_length();
|
||||||
if (length > Size) {
|
if (length > Size) {
|
||||||
@@ -22,5 +35,4 @@ std::string_view FlxStringDecoder::read_string_view() {
|
|||||||
void FlxStringDecoder::set_at_eof() {
|
void FlxStringDecoder::set_at_eof() {
|
||||||
Text += Size;
|
Text += Size;
|
||||||
Size = 0;
|
Size = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -70,6 +70,16 @@ public:
|
|||||||
//
|
//
|
||||||
FlxStringDecoder(std::string_view s);
|
FlxStringDecoder(std::string_view s);
|
||||||
|
|
||||||
|
// Get the remaining text as a string_view.
|
||||||
|
//
|
||||||
|
std::string_view GetRest();
|
||||||
|
|
||||||
|
// Reinitialize with a new string_view.
|
||||||
|
//
|
||||||
|
// If clear is true, clears the error flags.
|
||||||
|
//
|
||||||
|
void Reset(std::string_view s, bool clear);
|
||||||
|
|
||||||
// Get the size of the remaining text.
|
// Get the size of the remaining text.
|
||||||
//
|
//
|
||||||
size_t get_size() { return Size; }
|
size_t get_size() { return Size; }
|
||||||
@@ -82,6 +92,7 @@ public:
|
|||||||
//
|
//
|
||||||
void set_at_eof();
|
void set_at_eof();
|
||||||
|
|
||||||
|
|
||||||
// Read a string as a string_view
|
// Read a string as a string_view
|
||||||
//
|
//
|
||||||
// This reads a string from the source, returning
|
// This reads a string from the source, returning
|
||||||
|
|||||||
@@ -75,17 +75,12 @@ void UlxTangible::SetActorBlueprintClass(TSubclassOf<AActor> bp) {
|
|||||||
|
|
||||||
void UlxTangible::UpdateAnimationQueue(std::string_view aq) {
|
void UlxTangible::UpdateAnimationQueue(std::string_view aq) {
|
||||||
AnimTracker.Update(aq);
|
AnimTracker.Update(aq);
|
||||||
TArray<uint64> aborted = AnimTracker.GetAborted();
|
int limit = 3;
|
||||||
for (uint64 hash : aborted) {
|
while (AnimTracker.IsChanged()) {
|
||||||
IlxTangibleInterface::Execute_AbortAnimation(GetActor(), hash);
|
if (limit == 0) break;
|
||||||
}
|
limit -= 1;
|
||||||
FlxAnimationStep step;
|
AnimTracker.ClearChanged();
|
||||||
ElxAnimationMode mode = AnimTracker.GetNextStep(step);
|
IlxTangibleInterface::Execute_AnimationStateChanged(GetActor());
|
||||||
if (mode != ElxAnimationMode::INVALID) {
|
|
||||||
bool started = IlxTangibleInterface::Execute_StartAnimation(GetActor(), mode, step);
|
|
||||||
if (started) {
|
|
||||||
AnimTracker.StartedStep(step.Hash);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,15 +103,27 @@ void UlxTangible::Destroy() {
|
|||||||
NearAccordingToUnreal = false;
|
NearAccordingToUnreal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FString UlxTangible::GetTangiblePlane(AActor* actor) {
|
static UlxTangible *GetActorTangible(AActor *actor) {
|
||||||
UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>();
|
UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>();
|
||||||
check(comp != nullptr);
|
check(comp != nullptr);
|
||||||
return comp->Tangible->Plane.ToString();
|
UlxTangible *result = comp->Tangible.Get();
|
||||||
|
check(result != nullptr);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UlxTangible::SetTangiblePlane(AActor* actor, const FString& plane) {
|
void UlxTangible::GetCurrentAnimation(AActor *target, FlxAnimationStep &step) {
|
||||||
UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>();
|
step = GetActorTangible(target)->AnimTracker.GetCurrentAnimation();
|
||||||
check(comp != nullptr);
|
}
|
||||||
comp->Tangible->Plane = FName(plane);
|
|
||||||
|
void UlxTangible::FinishedAnimation(AActor *target, const FlxAnimationStep &step) {
|
||||||
|
GetActorTangible(target)->AnimTracker.FinishedAnimation(step.Hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
FString UlxTangible::GetTangiblePlane(AActor* target) {
|
||||||
|
return GetActorTangible(target)->Plane.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UlxTangible::SetTangiblePlane(AActor* target, const FString& plane) {
|
||||||
|
GetActorTangible(target)->Plane = FName(plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,15 +33,10 @@ 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(ElxAnimationMode mode, const FlxAnimationStep& step);
|
bool AnimationStateChanged();
|
||||||
|
|
||||||
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
|
|
||||||
bool AbortAnimation(int64 hash);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* UlxTangible
|
* UlxTangible
|
||||||
@@ -168,6 +163,12 @@ public:
|
|||||||
void UpdateAnimationQueue(std::string_view aq);
|
void UpdateAnimationQueue(std::string_view aq);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex)
|
||||||
|
static void GetCurrentAnimation(AActor *target, FlxAnimationStep &step);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex)
|
||||||
|
static void FinishedAnimation(AActor *target, const FlxAnimationStep &step);
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex)
|
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex)
|
||||||
static FString GetTangiblePlane(AActor* target);
|
static FString GetTangiblePlane(AActor* target);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user