Support for StartAnimation,WarpToFinal,BlendToFinal
This commit is contained in:
BIN
Content/TangibleActor.uasset
LFS
BIN
Content/TangibleActor.uasset
LFS
Binary file not shown.
@@ -14,19 +14,19 @@ FlxAnimField FlxAnimStepDecoder::ReadField() {
|
|||||||
result.Persistent = Decoder.read_bool();
|
result.Persistent = Decoder.read_bool();
|
||||||
result.Type = (ElxAnimValueType)Decoder.read_uint8();
|
result.Type = (ElxAnimValueType)Decoder.read_uint8();
|
||||||
switch (result.Type) {
|
switch (result.Type) {
|
||||||
case T_STRING: {
|
case ElxAnimValueType::STRING: {
|
||||||
result.S = Decoder.read_string_view();
|
result.S = Decoder.read_string_view();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_NUMBER: {
|
case ElxAnimValueType::NUMBER: {
|
||||||
result.X = Decoder.read_double();
|
result.X = Decoder.read_double();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_BOOLEAN: {
|
case ElxAnimValueType::BOOLEAN: {
|
||||||
result.X = Decoder.read_bool() ? 1.0 : 0.0;
|
result.X = Decoder.read_bool() ? 1.0 : 0.0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_XYZ: {
|
case ElxAnimValueType::XYZ: {
|
||||||
result.X = Decoder.read_double();
|
result.X = Decoder.read_double();
|
||||||
result.Y = Decoder.read_double();
|
result.Y = Decoder.read_double();
|
||||||
result.Z = Decoder.read_double();
|
result.Z = Decoder.read_double();
|
||||||
@@ -34,7 +34,7 @@ FlxAnimField FlxAnimStepDecoder::ReadField() {
|
|||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
Decoder.set_at_eof();
|
Decoder.set_at_eof();
|
||||||
result.Type = T_BOOLEAN;
|
result.Type = ElxAnimValueType::BOOLEAN;
|
||||||
result.X = 0;
|
result.X = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -65,16 +65,16 @@ FString FlxAnimStepDecoder::DebugString(const FlxAnimStep& step) {
|
|||||||
result.Append(FString(field.Name.size(), (const UTF8CHAR*)field.Name.data()));
|
result.Append(FString(field.Name.size(), (const UTF8CHAR*)field.Name.data()));
|
||||||
result.Append(field.Persistent ? TEXT("=") : TEXT(":"));
|
result.Append(field.Persistent ? TEXT("=") : TEXT(":"));
|
||||||
switch (field.Type) {
|
switch (field.Type) {
|
||||||
case ElxAnimValueType::T_STRING:
|
case ElxAnimValueType::STRING:
|
||||||
result.Append(FString(field.S.size(), (const UTF8CHAR*)field.S.data()));
|
result.Append(FString(field.S.size(), (const UTF8CHAR*)field.S.data()));
|
||||||
break;
|
break;
|
||||||
case ElxAnimValueType::T_NUMBER:
|
case ElxAnimValueType::NUMBER:
|
||||||
result.Appendf(TEXT("%lf"), field.X);
|
result.Appendf(TEXT("%lf"), field.X);
|
||||||
break;
|
break;
|
||||||
case ElxAnimValueType::T_BOOLEAN:
|
case ElxAnimValueType::BOOLEAN:
|
||||||
result.Append((field.X) == 1.0 ? TEXT("true") : TEXT("false"));
|
result.Append((field.X) == 1.0 ? TEXT("true") : TEXT("false"));
|
||||||
break;
|
break;
|
||||||
case ElxAnimValueType::T_XYZ:
|
case ElxAnimValueType::XYZ:
|
||||||
result.Appendf(TEXT("%lf,%lf,%lf"), field.X, field.Y, field.Z);
|
result.Appendf(TEXT("%lf,%lf,%lf"), field.X, field.Y, field.Z);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -84,33 +84,12 @@ FString FlxAnimStepDecoder::DebugString(const FlxAnimStep& step) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//// 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<FlxAnimStoredStep> AQ;
|
|
||||||
|
|
||||||
//// The sequence number of the first item in AQ.
|
|
||||||
////
|
|
||||||
//int32 FirstSeqno;
|
|
||||||
|
|
||||||
//// Map from hash to sequence number.
|
|
||||||
////
|
|
||||||
//TMap<uint64, int32> HashToSeqno;
|
|
||||||
|
|
||||||
//// The sequence number of the first unstarted animation.
|
|
||||||
////
|
|
||||||
//int32 UnstartedSeqno;
|
|
||||||
|
|
||||||
//// Array of recently-aborted hash values.
|
|
||||||
//TArray<uint64> AbortedHashes;
|
|
||||||
|
|
||||||
|
|
||||||
FlxAnimTracker::FlxAnimTracker() {
|
FlxAnimTracker::FlxAnimTracker() {
|
||||||
AQ.Empty();
|
AQ.Empty();
|
||||||
FirstSeqno = 0;
|
FirstSeqno = 0;
|
||||||
HashToSeqno.Empty();
|
HashToSeqno.Empty();
|
||||||
UnstartedSeqno = 0;
|
UnstartedSeqno = 0;
|
||||||
|
PlaybackMode = ElxAnimPlaybackMode::INVALID;
|
||||||
AbortedHashes.Empty();
|
AbortedHashes.Empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,18 +136,34 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abort all animations after the most recent matching
|
// Remove all animations after the most recent matching
|
||||||
// record. Animations are aborted in most-recent-first order.
|
// record. If we remove a 'started' animation, add that
|
||||||
//
|
// animation to the list of aborted animations.
|
||||||
int32 nabort = (FirstSeqno + AQ.Num()) - (matchingseqno + 1);
|
//
|
||||||
check((nabort >= 0) && (nabort <= AQ.Num()));
|
int32 nremove = (FirstSeqno + AQ.Num()) - (matchingseqno + 1);
|
||||||
for (int32 i = 0; i < nabort; i++) {
|
check((nremove >= 0) && (nremove <= AQ.Num()));
|
||||||
|
for (int32 i = 0; i < nremove; i++) {
|
||||||
uint64 lasthash = AQ.Last().Hash;
|
uint64 lasthash = AQ.Last().Hash;
|
||||||
|
int32 seqno = FirstSeqno + AQ.Num() - 1;
|
||||||
HashToSeqno.Remove(lasthash);
|
HashToSeqno.Remove(lasthash);
|
||||||
AbortedHashes.Emplace(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 = ElxAnimPlaybackMode::BLEND_TO_FINAL;
|
||||||
|
}
|
||||||
|
|
||||||
// Transfer the new animations onto the queue.
|
// Transfer the new animations onto the queue.
|
||||||
//
|
//
|
||||||
while (!newsteps.IsEmpty()) {
|
while (!newsteps.IsEmpty()) {
|
||||||
@@ -178,13 +173,6 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
|||||||
HashToSeqno.Emplace(step.Hash, seqno);
|
HashToSeqno.Emplace(step.Hash, seqno);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move back the Unstarted pointer, so that the
|
|
||||||
// unstarted range includes all the new animations.
|
|
||||||
//
|
|
||||||
if (UnstartedSeqno > matchingseqno + 1) {
|
|
||||||
UnstartedSeqno = matchingseqno + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
||||||
//
|
//
|
||||||
@@ -194,11 +182,21 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
|||||||
uint64 hash = AQ.First().Hash;
|
uint64 hash = AQ.First().Hash;
|
||||||
HashToSeqno.Remove(hash);
|
HashToSeqno.Remove(hash);
|
||||||
AQ.PopFirst();
|
AQ.PopFirst();
|
||||||
|
FirstSeqno += 1;
|
||||||
}
|
}
|
||||||
FirstSeqno += ndiscard;
|
}
|
||||||
if (UnstartedSeqno < FirstSeqno) {
|
|
||||||
|
// 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) {
|
||||||
|
if (AQ.Num() == 0) {
|
||||||
UnstartedSeqno = FirstSeqno;
|
UnstartedSeqno = FirstSeqno;
|
||||||
|
} else {
|
||||||
|
UnstartedSeqno = FirstSeqno + AQ.Num() - 1;
|
||||||
}
|
}
|
||||||
|
PlaybackMode = ElxAnimPlaybackMode::WARP_TO_FINAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,21 +207,23 @@ TArray<uint64> FlxAnimTracker::GetAborted() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlxAnimTracker::AnyUnstarted() {
|
ElxAnimPlaybackMode FlxAnimTracker::GetNextStep(FlxAnimStoredStep &step) {
|
||||||
int offset = UnstartedSeqno - FirstSeqno;
|
int offset = UnstartedSeqno - FirstSeqno;
|
||||||
return (offset < AQ.Num());
|
if (offset < AQ.Num()) {
|
||||||
|
step = AQ[offset];
|
||||||
|
return PlaybackMode;
|
||||||
|
} else {
|
||||||
|
step.Hash = 0;
|
||||||
|
step.Body = "";
|
||||||
|
return ElxAnimPlaybackMode::INVALID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlxAnimStoredStep FlxAnimTracker::GetUnstarted() {
|
void FlxAnimTracker::StartedStep(uint64 hash) {
|
||||||
int offset = UnstartedSeqno - FirstSeqno;
|
|
||||||
check(offset < AQ.Num());
|
|
||||||
return AQ[offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlxAnimTracker::Started(uint64 hash) {
|
|
||||||
int offset = UnstartedSeqno - FirstSeqno;
|
int offset = UnstartedSeqno - FirstSeqno;
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,37 @@
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
enum ElxAnimValueType {
|
enum class ElxAnimValueType {
|
||||||
T_STRING,
|
STRING,
|
||||||
T_NUMBER,
|
NUMBER,
|
||||||
T_BOOLEAN,
|
BOOLEAN,
|
||||||
T_XYZ,
|
XYZ,
|
||||||
T_UNINITIALIZED
|
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.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
|
enum class ElxAnimPlaybackMode {
|
||||||
|
START_ANIMATION,
|
||||||
|
WARP_TO_FINAL,
|
||||||
|
BLEND_TO_FINAL,
|
||||||
|
INVALID,
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
@@ -167,7 +192,12 @@ public:
|
|||||||
//
|
//
|
||||||
int32 UnstartedSeqno;
|
int32 UnstartedSeqno;
|
||||||
|
|
||||||
|
// Indicates whether the unstarted animation should be played or otherwise.
|
||||||
|
//
|
||||||
|
ElxAnimPlaybackMode PlaybackMode;
|
||||||
|
|
||||||
// Array of recently-aborted hash values.
|
// Array of recently-aborted hash values.
|
||||||
|
//
|
||||||
TArray<uint64> AbortedHashes;
|
TArray<uint64> AbortedHashes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -191,19 +221,17 @@ public:
|
|||||||
//
|
//
|
||||||
TArray<uint64> GetAborted();
|
TArray<uint64> GetAborted();
|
||||||
|
|
||||||
// Return true if there are any unstarted animation steps.
|
|
||||||
//
|
|
||||||
bool AnyUnstarted();
|
|
||||||
|
|
||||||
// Get the next unstarted animation step.
|
// Get the next unstarted animation step.
|
||||||
//
|
//
|
||||||
// You may only call this if AnyUnstarted returns true.
|
// 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
|
||||||
//
|
//
|
||||||
FlxAnimStoredStep GetUnstarted();
|
ElxAnimPlaybackMode GetNextStep(FlxAnimStoredStep& step);
|
||||||
|
|
||||||
// Declare that an animation has been started.
|
// Declare that an animation has been started.
|
||||||
//
|
//
|
||||||
// After starting an animation, you should call this.
|
// After starting an animation, you should call this.
|
||||||
//
|
//
|
||||||
void Started(uint64 Hash);
|
void StartedStep(uint64 Hash);
|
||||||
};
|
};
|
||||||
@@ -127,13 +127,25 @@ 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;
|
||||||
if (t->AnimTracker.AnyUnstarted()) {
|
ElxAnimPlaybackMode mode = t->AnimTracker.GetNextStep(step);
|
||||||
FlxAnimStoredStep step = t->AnimTracker.GetUnstarted();
|
bool started = false;
|
||||||
bool started = IlxTangibleInterface::Execute_StartAnimation(t->Actor, step.Hash, step.Body.size());
|
switch (mode) {
|
||||||
if (started) {
|
case ElxAnimPlaybackMode::INVALID:
|
||||||
t->AnimTracker.Started(step.Hash);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ public:
|
|||||||
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
|
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
|
||||||
bool StartAnimation(int64 hash, int StrLen);
|
bool StartAnimation(int64 hash, int StrLen);
|
||||||
|
|
||||||
|
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