Fix bugs in animation queue handling, and add animation timeouts
This commit is contained in:
Binary file not shown.
@@ -94,7 +94,7 @@
|
|||||||
"body": {
|
"body": {
|
||||||
"name": "Server=[SERVER]",
|
"name": "Server=[SERVER]",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "[UNREALENGINE]/Engine/Binaries/Linux/UnrealEditor-Linux-DebugGame",
|
"program": "[UNREALENGINE]/Engine/Binaries/Linux/UnrealEditor-Linux-[DEBUG]",
|
||||||
"preLaunchTask": "python3 build.py c++",
|
"preLaunchTask": "python3 build.py c++",
|
||||||
"args": [
|
"args": [
|
||||||
"[INTEGRATION]/Integration.uproject",
|
"[INTEGRATION]/Integration.uproject",
|
||||||
@@ -103,6 +103,7 @@
|
|||||||
],
|
],
|
||||||
"cwd": "[INTEGRATION]",
|
"cwd": "[INTEGRATION]",
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
|
"console": "integratedTerminal",
|
||||||
"initCommands": [
|
"initCommands": [
|
||||||
"command script import [UNREALENGINE]/Engine/Extras/LLDBDataFormatters/UEDataFormatters_2ByteChars.py",
|
"command script import [UNREALENGINE]/Engine/Extras/LLDBDataFormatters/UEDataFormatters_2ByteChars.py",
|
||||||
"settings set target.inline-breakpoint-strategy always",
|
"settings set target.inline-breakpoint-strategy always",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "AnimQueue.h"
|
#include "AnimQueue.h"
|
||||||
#include "UtilityLibrary.h"
|
#include "UtilityLibrary.h"
|
||||||
#include "GameFramework/Actor.h"
|
#include "GameFramework/Actor.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
FlxAnimationStep::FlxAnimationStep(uint64 hash, std::string_view body) {
|
FlxAnimationStep::FlxAnimationStep(uint64 hash, std::string_view body) {
|
||||||
Finished = false;
|
Finished = false;
|
||||||
@@ -140,7 +141,7 @@ void UlxAnimationStepLibrary::UnpackAnimationStep(bool &bChanged, FString &Actio
|
|||||||
|
|
||||||
FString UlxAnimationStepLibrary::AnimationStepDebugString(const FlxAnimationStep& step) {
|
FString UlxAnimationStepLibrary::AnimationStepDebugString(const FlxAnimationStep& step) {
|
||||||
std::string_view body((const char*)(step.Body.GetData()), step.Body.Num());
|
std::string_view body((const char*)(step.Body.GetData()), step.Body.Num());
|
||||||
return FlxAnimationStepDecoder::DebugString(step.Finished, step.Finished, step.Hash, body);
|
return FlxAnimationStepDecoder::DebugString(step.Finished, step.Hash, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FlxAnimationField FindAnimationFieldLL(const FlxAnimationStep& step, std::string_view name) {
|
static FlxAnimationField FindAnimationFieldLL(const FlxAnimationStep& step, std::string_view name) {
|
||||||
@@ -264,16 +265,15 @@ FlxAnimationField FlxAnimationStepDecoder::ReadField() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FString FlxAnimationStepDecoder::DebugString(bool injectidle, bool persistentonly, uint64 hash, std::string_view body) {
|
FString FlxAnimationStepDecoder::DebugString(bool finished, uint64 hash, std::string_view body) {
|
||||||
FString result;
|
FString result;
|
||||||
FlxAnimationStepDecoder decoder(body);
|
FlxAnimationStepDecoder decoder(body);
|
||||||
result.Appendf(TEXT("Hash=%016llx"), hash);
|
result.Appendf(TEXT("Hash=%016llx"), hash);
|
||||||
if (injectidle) {
|
if (finished) {
|
||||||
result.Appendf(TEXT(" action=idle"));
|
result.Appendf(TEXT(" finished"));
|
||||||
}
|
}
|
||||||
while (!decoder.AtEOF()) {
|
while (!decoder.AtEOF()) {
|
||||||
FlxAnimationField field = decoder.ReadField();
|
FlxAnimationField field = decoder.ReadField();
|
||||||
if (persistentonly && !field.Persistent) continue;
|
|
||||||
result.Append(TEXT(" "));
|
result.Append(TEXT(" "));
|
||||||
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(":"));
|
||||||
@@ -317,16 +317,16 @@ FlxAnimQueueDecoder::FlxAnimQueueDecoder(std::string_view queue) : Decoder(queue
|
|||||||
ActualSize = 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);
|
||||||
while (!decoder.AtEOF()) {
|
// while (!decoder.AtEOF()) {
|
||||||
FlxAnimationStepView step = decoder.ReadStep();
|
// FlxAnimationStepView step = decoder.ReadStep();
|
||||||
FString stepdebug = FlxAnimationStepDecoder::DebugString(false, false, step.Hash, step.Body);
|
// FString stepdebug = FlxAnimationStepDecoder::DebugString(false, step.Hash, step.Body);
|
||||||
result.Appendf(TEXT("%s\n"), *stepdebug);
|
// result.Appendf(TEXT("%s\n"), *stepdebug);
|
||||||
}
|
// }
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
|
||||||
FlxAnimTracker::FlxAnimTracker() {
|
FlxAnimTracker::FlxAnimTracker() {
|
||||||
Clear();
|
Clear();
|
||||||
@@ -358,6 +358,30 @@ void FlxAnimTracker::SkipToEnd() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FlxAnimationStep *FlxAnimTracker::FirstUnfinished() const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < AQ.Num(); i++) {
|
||||||
|
if (!AQ[i].Finished) return &AQ[i];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FlxAnimationStep *FlxAnimTracker::LastFinished() const
|
||||||
|
{
|
||||||
|
for (int i = AQ.Num() - 1; i >= 0; i--) {
|
||||||
|
if (AQ[i].Finished) return &AQ[i];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FlxAnimationStep *FlxAnimTracker::FindAnimation(uint64 hash) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < AQ.Num(); i++) {
|
||||||
|
if (AQ[i].Hash == hash) return &AQ[i];
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void FlxAnimTracker::Update(std::string_view encqueue) {
|
void FlxAnimTracker::Update(std::string_view encqueue) {
|
||||||
check(!encqueue.empty());
|
check(!encqueue.empty());
|
||||||
|
|
||||||
@@ -409,14 +433,14 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
|||||||
int32 nremove = (AQ.Num() - (matchingindex + 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++) {
|
||||||
AQ.PopLast();
|
AQ.Pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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();
|
||||||
AQ.EmplaceLast(step.Hash, step.Body);
|
AQ.Emplace(step.Hash, step.Body);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are too many animations in AQ, discard
|
// If there are too many animations in AQ, discard
|
||||||
@@ -425,12 +449,15 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
|||||||
// TODO: this is hardwired to keep 10. Instead, we
|
// TODO: this is hardwired to keep 10. Instead, we
|
||||||
// should keep the number specified in the queue.
|
// should keep the number specified in the queue.
|
||||||
//
|
//
|
||||||
int limit = 10;
|
const int limit = 10;
|
||||||
int ndiscard = AQ.Num() - limit;
|
if (AQ.Num() > limit)
|
||||||
if (ndiscard > 0) {
|
{
|
||||||
for (int i = 0; i < ndiscard; i++) {
|
int offset = AQ.Num() - limit;
|
||||||
AQ.PopFirst();
|
for (int i = 0; i < limit; i++)
|
||||||
|
{
|
||||||
|
AQ[i] = AQ[i + offset];
|
||||||
}
|
}
|
||||||
|
AQ.SetNum(limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Autofinish up to one animation.
|
// Autofinish up to one animation.
|
||||||
@@ -450,6 +477,34 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FString FlxAnimTracker::DebugString() const
|
||||||
|
{
|
||||||
|
FString Result;
|
||||||
|
if (Changed)
|
||||||
|
{
|
||||||
|
Result += TEXT("changed=true ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Result += TEXT("changed=false ");
|
||||||
|
}
|
||||||
|
if (AutoFinish)
|
||||||
|
{
|
||||||
|
Result += TEXT("autofinish=true");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Result += TEXT("autofinish=false");
|
||||||
|
}
|
||||||
|
Result += TEXT("\n");
|
||||||
|
for (int i = 0; i < AQ.Num(); i++)
|
||||||
|
{
|
||||||
|
Result += UlxAnimationStepLibrary::AnimationStepDebugString(AQ[i]);
|
||||||
|
Result += TEXT("\n");
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
void FlxAnimTracker::SetAutoFinish(const FString &action, const FVector &xyz) {
|
void FlxAnimTracker::SetAutoFinish(const FString &action, const FVector &xyz) {
|
||||||
AutoFinish = true;
|
AutoFinish = true;
|
||||||
AutoFinishAction = action;
|
AutoFinishAction = action;
|
||||||
@@ -486,3 +541,4 @@ FlxAnimationStep FlxAnimTracker::GetCurrentAnimation() {
|
|||||||
result.Hash += 1;
|
result.Hash += 1;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ public:
|
|||||||
|
|
||||||
// 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
@@ -230,7 +230,7 @@ public:
|
|||||||
|
|
||||||
// Convert an AnimStep to an FString.
|
// Convert an AnimStep to an FString.
|
||||||
//
|
//
|
||||||
static FString DebugString(bool injectidle, bool persistentonly, uint64 hash, std::string_view body);
|
static FString DebugString(bool finished, uint64 hash, std::string_view body);
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
@@ -251,7 +251,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<FlxAnimationStep> AQ;
|
TArray<FlxAnimationStep> AQ;
|
||||||
|
|
||||||
// True if something has recently changed.
|
// True if something has recently changed.
|
||||||
//
|
//
|
||||||
@@ -319,6 +319,18 @@ public:
|
|||||||
//
|
//
|
||||||
void SkipToEnd();
|
void SkipToEnd();
|
||||||
|
|
||||||
|
// Return the first unfinished animation.
|
||||||
|
//
|
||||||
|
const FlxAnimationStep *FirstUnfinished() const;
|
||||||
|
|
||||||
|
// Return the last finished animation.
|
||||||
|
//
|
||||||
|
const FlxAnimationStep *LastFinished() const;
|
||||||
|
|
||||||
|
// Return the first animation with the specified hash.
|
||||||
|
//
|
||||||
|
const FlxAnimationStep *FindAnimation(uint64 hash) const;
|
||||||
|
|
||||||
// Clear the 'Changed' flag.
|
// Clear the 'Changed' flag.
|
||||||
//
|
//
|
||||||
void ClearChanged() { Changed = false; }
|
void ClearChanged() { Changed = false; }
|
||||||
@@ -331,4 +343,8 @@ public:
|
|||||||
// The changed flag can only be set to false by 'ClearChanged,' above.
|
// The changed flag can only be set to false by 'ClearChanged,' above.
|
||||||
//
|
//
|
||||||
bool IsChanged() const { return Changed; }
|
bool IsChanged() const { return Changed; }
|
||||||
|
|
||||||
|
// Return a debug string for the entire animation tracker.
|
||||||
|
//
|
||||||
|
FString DebugString() const;
|
||||||
};
|
};
|
||||||
@@ -155,6 +155,13 @@ void ALuprexGameModeBase::UpdateTangibles() {
|
|||||||
for (int i = 0; i < alltans.Num(); i++) {
|
for (int i = 0; i < alltans.Num(); i++) {
|
||||||
alltans[i]->UpdateAnimationQueue(allqueues[i]);
|
alltans[i]->UpdateAnimationQueue(allqueues[i]);
|
||||||
}
|
}
|
||||||
|
// Debugging hook.
|
||||||
|
volatile bool printaqs = false;
|
||||||
|
if (printaqs) {
|
||||||
|
for (int i = 0; i < alltans.Num(); i++) {
|
||||||
|
UE_LOG(LogLuprex, Display, TEXT("\n--- AQ of %ld ---\n%s\n"), allids[i], *(alltans[i]->AnimTracker.DebugString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// This is where we run the blueprint code that updates animation
|
// This is where we run the blueprint code that updates animation
|
||||||
// states. Be aware that the blueprint code could call back
|
// states. Be aware that the blueprint code could call back
|
||||||
|
|||||||
@@ -23,7 +23,32 @@ void UlxTangible::Init(UlxTangibleManager* tm, int64 id)
|
|||||||
TangibleId = id;
|
TangibleId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma optimize("", off)
|
void UlxTangible::DeleteCurrentActor()
|
||||||
|
{
|
||||||
|
if (CurrentActor == nullptr) return;
|
||||||
|
|
||||||
|
// Remove the tangible component. This is probably
|
||||||
|
// unnecessary, but it makes it more likely that we'll
|
||||||
|
// catch bugs early.
|
||||||
|
UlxTangibleComponent* comp = CurrentActor->GetComponentByClass<UlxTangibleComponent>();
|
||||||
|
if (comp != nullptr) {
|
||||||
|
comp->DestroyComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now destroy the actor itself. According to various
|
||||||
|
// documents I've read online, it may be necessary to take
|
||||||
|
// further steps to delete the object. Not clear.
|
||||||
|
CurrentActor->Destroy();
|
||||||
|
|
||||||
|
// If this actor previously was posessed by a player controller,
|
||||||
|
// then it's not posessed anymore, because there is no actor any more.
|
||||||
|
if (Manager->PossessedTangible == this) {
|
||||||
|
Manager->PossessedTangible = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
CurrentActor = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void UlxTangible::SetActorBlueprint(const FString &XName) {
|
void UlxTangible::SetActorBlueprint(const FString &XName) {
|
||||||
FString Name = XName.ToLower();
|
FString Name = XName.ToLower();
|
||||||
|
|
||||||
@@ -32,7 +57,6 @@ void UlxTangible::SetActorBlueprint(const FString &XName) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the blueprint.
|
|
||||||
UClass *blueprint = UlxAssetLookup::LoadTangibleBlueprintAsset(this, Name);
|
UClass *blueprint = UlxAssetLookup::LoadTangibleBlueprintAsset(this, Name);
|
||||||
if (blueprint == nullptr)
|
if (blueprint == nullptr)
|
||||||
{
|
{
|
||||||
@@ -40,71 +64,50 @@ void UlxTangible::SetActorBlueprint(const FString &XName) {
|
|||||||
check(blueprint != nullptr);
|
check(blueprint != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's already an actor, delete it.
|
|
||||||
if (CurrentActor != nullptr) {
|
|
||||||
// Remove the tangible component. This is probably
|
|
||||||
// unnecessary, but it makes it more likely that we'll
|
|
||||||
// catch bugs early.
|
|
||||||
UlxTangibleComponent* comp = CurrentActor->GetComponentByClass<UlxTangibleComponent>();
|
|
||||||
if (comp != nullptr) {
|
|
||||||
comp->DestroyComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now destroy the actor itself. According to various
|
|
||||||
// documents I've read online, it may be necessary to take
|
|
||||||
// further steps to delete the object. Not clear.
|
|
||||||
CurrentActor->Destroy();
|
|
||||||
|
|
||||||
// If this actor previously was posessed by a player controller,
|
|
||||||
// then it's not posessed anymore, because there is no actor any more.
|
|
||||||
if (Manager->PossessedTangible == this) {
|
|
||||||
Manager->PossessedTangible = nullptr;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the blueprint name
|
// Update the blueprint name
|
||||||
ActorBlueprintName = Name;
|
ActorBlueprintName = Name;
|
||||||
|
|
||||||
// Now create a new actor, unless the BP is nullptr.
|
// If there's already an actor, delete it.
|
||||||
if (blueprint != nullptr) {
|
DeleteCurrentActor();
|
||||||
UWorld* w = Manager->GetWorld();
|
|
||||||
FActorSpawnParameters params;
|
|
||||||
|
|
||||||
// Give the new actor a reasonable name.
|
// Now create a new actor.
|
||||||
params.Name = FName(*FString::Printf(TEXT("%s_%ld"), *Name, TangibleId));
|
UWorld* w = Manager->GetWorld();
|
||||||
|
FActorSpawnParameters params;
|
||||||
|
|
||||||
// Currently, the actor is spawned at (0,0,0), which is not good.
|
// Give the new actor a reasonable name.
|
||||||
// We should spawn at the actor's current location. I'll get to it
|
params.Name = FName(*FString::Printf(TEXT("%s_%ld"), *Name, TangibleId));
|
||||||
// eventually.
|
|
||||||
FTransform transform;
|
|
||||||
transform.SetLocation(FVector(0,0,0));
|
|
||||||
transform.SetRotation(FQuat(FRotator(0,0,0)));
|
|
||||||
|
|
||||||
// Create the actor at the specified location even if there's something in the way.
|
// Currently, the actor is spawned at (0,0,0), which is not good.
|
||||||
params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
|
// We should spawn at the actor's current location. I'll get to it
|
||||||
|
// eventually.
|
||||||
// Normally, SpawnActor runs the BeginPlay entry point. We
|
FTransform transform;
|
||||||
// want to delay that until after we've had a chance to set
|
transform.SetLocation(FVector(0,0,0));
|
||||||
// up the TangibleComponent.
|
transform.SetRotation(FQuat(FRotator(0,0,0)));
|
||||||
params.bDeferConstruction = true;
|
|
||||||
AActor* a = w->SpawnActor(blueprint, &transform, params);
|
|
||||||
check(a != nullptr);
|
|
||||||
|
|
||||||
// Make sure the label and the name are the same.
|
// Create the actor at the specified location even if there's something in the way.
|
||||||
a->SetActorLabel(params.Name.ToString());
|
params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
|
||||||
|
|
||||||
|
// Normally, SpawnActor runs the BeginPlay entry point. We
|
||||||
|
// want to delay that until after we've had a chance to set
|
||||||
|
// up the TangibleComponent.
|
||||||
|
params.bDeferConstruction = true;
|
||||||
|
AActor* a = w->SpawnActor(blueprint, &transform, params);
|
||||||
|
check(a != nullptr);
|
||||||
|
|
||||||
// Insert a TangibleComponent into the actor.
|
// Make sure the label and the name are the same.
|
||||||
// Link the actor to its tangible, and the tangible to its actor.
|
a->SetActorLabel(params.Name.ToString());
|
||||||
UActorComponent* ac = a->AddComponentByClass(UlxTangibleComponent::StaticClass(), false, FTransform::Identity, false);
|
|
||||||
UlxTangibleComponent* tc = Cast<UlxTangibleComponent>(ac);
|
|
||||||
check(tc != nullptr);
|
|
||||||
tc->Tangible = this;
|
|
||||||
CurrentActor = a;
|
|
||||||
|
|
||||||
// This executes the BeginPlay entry point. We have to do this here
|
// Insert a TangibleComponent into the actor.
|
||||||
// because we deferred it in SpawnActor.
|
// Link the actor to its tangible, and the tangible to its actor.
|
||||||
a->FinishSpawning(transform, true);
|
UActorComponent* ac = a->AddComponentByClass(UlxTangibleComponent::StaticClass(), false, FTransform::Identity, false);
|
||||||
}
|
UlxTangibleComponent* tc = Cast<UlxTangibleComponent>(ac);
|
||||||
|
check(tc != nullptr);
|
||||||
|
tc->Tangible = this;
|
||||||
|
CurrentActor = a;
|
||||||
|
|
||||||
|
// This executes the BeginPlay entry point. We have to do this here
|
||||||
|
// because we deferred it in SpawnActor.
|
||||||
|
a->FinishSpawning(transform, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UlxTangible::UpdateAnimationQueue(std::string_view aq) {
|
void UlxTangible::UpdateAnimationQueue(std::string_view aq) {
|
||||||
@@ -113,6 +116,9 @@ void UlxTangible::UpdateAnimationQueue(std::string_view aq) {
|
|||||||
|
|
||||||
void UlxTangible::MaybeExecuteAnimStateChanged() {
|
void UlxTangible::MaybeExecuteAnimStateChanged() {
|
||||||
int limit = 3;
|
int limit = 3;
|
||||||
|
|
||||||
|
bool AnyChange = AnimTracker.IsChanged();
|
||||||
|
|
||||||
while (AnimTracker.IsChanged()) {
|
while (AnimTracker.IsChanged()) {
|
||||||
if (limit == 0) break;
|
if (limit == 0) break;
|
||||||
limit -= 1;
|
limit -= 1;
|
||||||
@@ -122,13 +128,47 @@ void UlxTangible::MaybeExecuteAnimStateChanged() {
|
|||||||
SetActorBlueprint(blueprint);
|
SetActorBlueprint(blueprint);
|
||||||
AActor *actor = GetActor();
|
AActor *actor = GetActor();
|
||||||
UFunction *aqchanged = actor->GetClass()->FindFunctionByName(FName(TEXT("Animation Queue Changed")));
|
UFunction *aqchanged = actor->GetClass()->FindFunctionByName(FName(TEXT("Animation Queue Changed")));
|
||||||
if (aqchanged != nullptr) {
|
if (aqchanged != nullptr)
|
||||||
|
{
|
||||||
actor->ProcessEvent(aqchanged, nullptr);
|
actor->ProcessEvent(aqchanged, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refresh the pending animation state.
|
||||||
|
double Now = GetWorld()->GetTimeSeconds();
|
||||||
|
if (AnyChange)
|
||||||
|
{
|
||||||
|
const FlxAnimationStep *Unfinished = AnimTracker.FirstUnfinished();
|
||||||
|
if (Unfinished == nullptr)
|
||||||
|
{
|
||||||
|
PendingAnimationHash = 0;
|
||||||
|
PendingAnimationTimeout = 0.0;
|
||||||
|
}
|
||||||
|
else if (Unfinished->Hash != PendingAnimationHash)
|
||||||
|
{
|
||||||
|
PendingAnimationHash = Unfinished->Hash;
|
||||||
|
PendingAnimationTimeout = Now + 10.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement the animation timeout.
|
||||||
|
if ((PendingAnimationHash != 0) && (Now > PendingAnimationTimeout))
|
||||||
|
{
|
||||||
|
const FlxAnimationStep *Step = AnimTracker.FindAnimation(PendingAnimationHash);
|
||||||
|
if (Step != nullptr)
|
||||||
|
{
|
||||||
|
FString DS = UlxAnimationStepLibrary::AnimationStepDebugString(*Step);
|
||||||
|
UE_LOG(LogLuprex, Warning, TEXT("Timeout - blueprint didn't finish animation: %s"), *DS);
|
||||||
|
AnimTracker.FinishedAnimation(PendingAnimationHash);
|
||||||
|
}
|
||||||
|
AutoUpdatePosition();
|
||||||
|
PendingAnimationHash = 0;
|
||||||
|
PendingAnimationTimeout = 0.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FVector UlxTangible::GetLocation() const {
|
FVector UlxTangible::GetLocation() const
|
||||||
|
{
|
||||||
if (CurrentActor == nullptr) {
|
if (CurrentActor == nullptr) {
|
||||||
return FVector(0,0,0);
|
return FVector(0,0,0);
|
||||||
} else {
|
} else {
|
||||||
@@ -136,8 +176,9 @@ FVector UlxTangible::GetLocation() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UlxTangible::Destroy() {
|
void UlxTangible::Destroy()
|
||||||
SetActorBlueprint("");
|
{
|
||||||
|
DeleteCurrentActor();
|
||||||
Manager = nullptr;
|
Manager = nullptr;
|
||||||
TangibleId = -1;
|
TangibleId = -1;
|
||||||
CurrentActor = nullptr;
|
CurrentActor = nullptr;
|
||||||
@@ -147,14 +188,16 @@ void UlxTangible::Destroy() {
|
|||||||
NearAccordingToUnreal = false;
|
NearAccordingToUnreal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
UlxTangible *UlxTangible::GetActorTangibleQuiet(AActor *actor) {
|
UlxTangible *UlxTangible::GetActorTangibleQuiet(AActor *actor)
|
||||||
|
{
|
||||||
if (actor == nullptr) return nullptr;
|
if (actor == nullptr) return nullptr;
|
||||||
UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>();
|
UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>();
|
||||||
if (comp == nullptr) return nullptr;
|
if (comp == nullptr) return nullptr;
|
||||||
return comp->Tangible.Get();
|
return comp->Tangible.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
UlxTangible *UlxTangible::GetActorTangibleOrLog(AActor *actor) {
|
UlxTangible *UlxTangible::GetActorTangibleOrLog(AActor *actor)
|
||||||
|
{
|
||||||
UlxTangible *tan = GetActorTangibleQuiet(actor);
|
UlxTangible *tan = GetActorTangibleQuiet(actor);
|
||||||
if (tan == nullptr) {
|
if (tan == nullptr) {
|
||||||
if (actor == nullptr) {
|
if (actor == nullptr) {
|
||||||
@@ -175,18 +218,24 @@ void UlxTangible::GetCurrentAnimation(AActor *target, FlxAnimationStep &step) {
|
|||||||
step = tan->AnimTracker.GetCurrentAnimation();
|
step = tan->AnimTracker.GetCurrentAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UlxTangible::AutoUpdatePosition()
|
||||||
|
{
|
||||||
|
const FlxAnimationStep *Step = AnimTracker.LastFinished();
|
||||||
|
if (Step != nullptr)
|
||||||
|
{
|
||||||
|
Step->AutoUpdateXYZ(GetActor());
|
||||||
|
Step->AutoUpdateFacing(GetActor());
|
||||||
|
Step->AutoUpdatePlane(&(this->Plane));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UlxTangible::FinishedAnimation(AActor *target, const FlxAnimationStep &step, bool AutoUpdate) {
|
void UlxTangible::FinishedAnimation(AActor *target, const FlxAnimationStep &step, bool AutoUpdate) {
|
||||||
UlxTangible *tan = GetActorTangibleOrLog(target);
|
UlxTangible *tan = GetActorTangibleOrLog(target);
|
||||||
if (tan == nullptr) return;
|
if (tan == nullptr) return;
|
||||||
if (AutoUpdate)
|
|
||||||
{
|
|
||||||
step.AutoUpdateXYZ(target);
|
|
||||||
step.AutoUpdateFacing(target);
|
|
||||||
step.AutoUpdatePlane(&(tan->Plane));
|
|
||||||
}
|
|
||||||
tan->AnimTracker.FinishedAnimation(step.Hash);
|
tan->AnimTracker.FinishedAnimation(step.Hash);
|
||||||
|
if (AutoUpdate) tan->AutoUpdatePosition();
|
||||||
FString DebugString = UlxAnimationStepLibrary::AnimationStepDebugString(step);
|
FString DebugString = UlxAnimationStepLibrary::AnimationStepDebugString(step);
|
||||||
UE_LOG(LogBlueprint, Display, TEXT("Animation Finished: %s"), *DebugString);
|
UE_LOG(LogLuprex, Display, TEXT("Animation Finished: %s"), *DebugString);
|
||||||
}
|
}
|
||||||
|
|
||||||
FString UlxTangible::GetTangiblePlane(AActor* target) {
|
FString UlxTangible::GetTangiblePlane(AActor* target) {
|
||||||
|
|||||||
@@ -57,6 +57,12 @@ public:
|
|||||||
// Animation tracker
|
// Animation tracker
|
||||||
FlxAnimTracker AnimTracker;
|
FlxAnimTracker AnimTracker;
|
||||||
|
|
||||||
|
// Animation that is waiting to be finished.
|
||||||
|
uint64 PendingAnimationHash;
|
||||||
|
|
||||||
|
// When do we timeout the pending animation.
|
||||||
|
double PendingAnimationTimeout;
|
||||||
|
|
||||||
// Current Plane.
|
// Current Plane.
|
||||||
FName Plane;
|
FName Plane;
|
||||||
|
|
||||||
@@ -66,6 +72,10 @@ public:
|
|||||||
// True if unreal thinks this object is Near the player.
|
// True if unreal thinks this object is Near the player.
|
||||||
bool NearAccordingToUnreal;
|
bool NearAccordingToUnreal;
|
||||||
|
|
||||||
|
// Delete the current actor.
|
||||||
|
//
|
||||||
|
void DeleteCurrentActor();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Initialize a new tangible.
|
// Initialize a new tangible.
|
||||||
//
|
//
|
||||||
@@ -122,6 +132,9 @@ public:
|
|||||||
static UlxTangible *GetActorTangibleQuiet(AActor *actor);
|
static UlxTangible *GetActorTangibleQuiet(AActor *actor);
|
||||||
static UlxTangible *GetActorTangibleOrLog(AActor *actor);
|
static UlxTangible *GetActorTangibleOrLog(AActor *actor);
|
||||||
|
|
||||||
|
// Automatically update the tangible's XYZ, Plane, Facing.
|
||||||
|
//
|
||||||
|
void AutoUpdatePosition();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
11
build.py
11
build.py
@@ -156,6 +156,7 @@ def autodetect_system_config():
|
|||||||
config.DOT_EXE = ".exe"
|
config.DOT_EXE = ".exe"
|
||||||
config.USER = "Unknown"
|
config.USER = "Unknown"
|
||||||
config.BUILD_BAT = "Build.bat"
|
config.BUILD_BAT = "Build.bat"
|
||||||
|
config.DEBUG = "DebugGame"
|
||||||
else:
|
else:
|
||||||
config.OS = "Linux"
|
config.OS = "Linux"
|
||||||
config.DLL = "so"
|
config.DLL = "so"
|
||||||
@@ -163,6 +164,7 @@ def autodetect_system_config():
|
|||||||
config.DOT_EXE = ""
|
config.DOT_EXE = ""
|
||||||
config.USER = os.environ["USER"]
|
config.USER = os.environ["USER"]
|
||||||
config.BUILD_BAT = "Linux/Build.sh"
|
config.BUILD_BAT = "Linux/Build.sh"
|
||||||
|
config.DEBUG = "DebugGame"
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
@@ -170,13 +172,14 @@ def store_system_config_in_globals(config):
|
|||||||
"""
|
"""
|
||||||
Copy all the config data from the config object into global variables.
|
Copy all the config data from the config object into global variables.
|
||||||
"""
|
"""
|
||||||
global OS,DLL,BAT,DOT_EXE,USER,BUILD_BAT,INTEGRATION,UNREALENGINE
|
global OS,DLL,BAT,DOT_EXE,USER,BUILD_BAT,DEBUG,INTEGRATION,UNREALENGINE
|
||||||
OS = config.OS
|
OS = config.OS
|
||||||
DLL = config.DLL
|
DLL = config.DLL
|
||||||
BAT = config.BAT
|
BAT = config.BAT
|
||||||
DOT_EXE = config.DOT_EXE
|
DOT_EXE = config.DOT_EXE
|
||||||
USER = config.USER
|
USER = config.USER
|
||||||
BUILD_BAT = config.BUILD_BAT
|
BUILD_BAT = config.BUILD_BAT
|
||||||
|
DEBUG = config.DEBUG
|
||||||
INTEGRATION = config.INTEGRATION
|
INTEGRATION = config.INTEGRATION
|
||||||
UNREALENGINE = config.UNREALENGINE
|
UNREALENGINE = config.UNREALENGINE
|
||||||
|
|
||||||
@@ -278,7 +281,7 @@ def build_luprex_and_integration():
|
|||||||
This builds our C++ code, and also UnrealEngine's C++ code.
|
This builds our C++ code, and also UnrealEngine's C++ code.
|
||||||
"""
|
"""
|
||||||
shell(f"{INTEGRATION}/luprex", "make all")
|
shell(f"{INTEGRATION}/luprex", "make all")
|
||||||
shell(INTEGRATION, f"{UNREALENGINE}/Engine/Build/BatchFiles/{BUILD_BAT} -waitmutex IntegrationEditor {OS} DebugGame {INTEGRATION}/Integration.uproject")
|
shell(INTEGRATION, f"{UNREALENGINE}/Engine/Build/BatchFiles/{BUILD_BAT} -waitmutex IntegrationEditor {OS} {DEBUG} {INTEGRATION}/Integration.uproject")
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -291,7 +294,7 @@ def build_intellisense_database_for_clangd():
|
|||||||
based on clangd how to compile each source file.
|
based on clangd how to compile each source file.
|
||||||
This also installs a .clangd file in the UnrealEngine directory.
|
This also installs a .clangd file in the UnrealEngine directory.
|
||||||
"""
|
"""
|
||||||
mods1 = Path(f"{INTEGRATION}/Intermediate/Build/{OS}").rglob("UnrealEditor/DebugGame/**/Module.*.o.rsp")
|
mods1 = Path(f"{INTEGRATION}/Intermediate/Build/{OS}").rglob("UnrealEditor/{DEBUG}/**/Module.*.o.rsp")
|
||||||
mods2 = Path(f"{UNREALENGINE}/Engine/Intermediate/Build/{OS}").rglob("UnrealEditor/Development/**/Module.*.o.rsp")
|
mods2 = Path(f"{UNREALENGINE}/Engine/Intermediate/Build/{OS}").rglob("UnrealEditor/Development/**/Module.*.o.rsp")
|
||||||
mods = list(mods1) + list(mods2)
|
mods = list(mods1) + list(mods2)
|
||||||
clangs = list(Path(f"{UNREALENGINE}/Engine/Extras/ThirdPartyNotUE/SDKs").rglob("*-linux-gnu/bin/clang++"))
|
clangs = list(Path(f"{UNREALENGINE}/Engine/Extras/ThirdPartyNotUE/SDKs").rglob("*-linux-gnu/bin/clang++"))
|
||||||
@@ -333,7 +336,7 @@ def build_clean():
|
|||||||
This code is underdeveloped.
|
This code is underdeveloped.
|
||||||
"""
|
"""
|
||||||
shell(f"{INTEGRATION}/luprex", "make clean")
|
shell(f"{INTEGRATION}/luprex", "make clean")
|
||||||
shell(INTEGRATION, f"{UNREALENGINE}/Engine/Build/BatchFiles/{BUILD_BAT} -waitmutex IntegrationEditor {OS} DebugGame {INTEGRATION}/Integration.uproject -clean")
|
shell(INTEGRATION, f"{UNREALENGINE}/Engine/Build/BatchFiles/{BUILD_BAT} -waitmutex IntegrationEditor {OS} {DEBUG} {INTEGRATION}/Integration.uproject -clean")
|
||||||
Path(f"{INTEGRATION}/.vscode/compile_commands.json").unlink(missing_ok = True)
|
Path(f"{INTEGRATION}/.vscode/compile_commands.json").unlink(missing_ok = True)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void change_actor_id(int64_t actor_id) {
|
void change_actor_id(int64_t actor_id) {
|
||||||
stdostream() << "Actor ID changing: " << actor_id << std::endl;
|
util::dprint("Actor ID changing: ", actor_id);
|
||||||
print_channeler_.reset();
|
print_channeler_.reset();
|
||||||
actor_id_ = actor_id;
|
actor_id_ = actor_id;
|
||||||
set_visible_world_and_actor(world_.get(), actor_id_);
|
set_visible_world_and_actor(world_.get(), actor_id_);
|
||||||
@@ -257,7 +257,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
stdostream() << "Invalid event_access: " << int(kind) << std::endl;
|
util::dprint("Invalid event_access: ", int(kind));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ public:
|
|||||||
// Check for communication from server..
|
// Check for communication from server..
|
||||||
if (channel_ != nullptr) {
|
if (channel_ != nullptr) {
|
||||||
if (channel_->closed()) {
|
if (channel_->closed()) {
|
||||||
stdostream() << "server closed connection: " << channel_->error() << std::endl;
|
util::dprint("server closed connection: ", channel_->error());
|
||||||
abandon_server();
|
abandon_server();
|
||||||
} else {
|
} else {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|||||||
Reference in New Issue
Block a user