Fix bugs in animation queue handling, and add animation timeouts
This commit is contained in:
Binary file not shown.
@@ -94,7 +94,7 @@
|
||||
"body": {
|
||||
"name": "Server=[SERVER]",
|
||||
"request": "launch",
|
||||
"program": "[UNREALENGINE]/Engine/Binaries/Linux/UnrealEditor-Linux-DebugGame",
|
||||
"program": "[UNREALENGINE]/Engine/Binaries/Linux/UnrealEditor-Linux-[DEBUG]",
|
||||
"preLaunchTask": "python3 build.py c++",
|
||||
"args": [
|
||||
"[INTEGRATION]/Integration.uproject",
|
||||
@@ -103,6 +103,7 @@
|
||||
],
|
||||
"cwd": "[INTEGRATION]",
|
||||
"type": "lldb",
|
||||
"console": "integratedTerminal",
|
||||
"initCommands": [
|
||||
"command script import [UNREALENGINE]/Engine/Extras/LLDBDataFormatters/UEDataFormatters_2ByteChars.py",
|
||||
"settings set target.inline-breakpoint-strategy always",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "AnimQueue.h"
|
||||
#include "UtilityLibrary.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include <iostream>
|
||||
|
||||
FlxAnimationStep::FlxAnimationStep(uint64 hash, std::string_view body) {
|
||||
Finished = false;
|
||||
@@ -140,7 +141,7 @@ void UlxAnimationStepLibrary::UnpackAnimationStep(bool &bChanged, FString &Actio
|
||||
|
||||
FString UlxAnimationStepLibrary::AnimationStepDebugString(const FlxAnimationStep& step) {
|
||||
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) {
|
||||
@@ -264,16 +265,15 @@ FlxAnimationField FlxAnimationStepDecoder::ReadField() {
|
||||
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;
|
||||
FlxAnimationStepDecoder decoder(body);
|
||||
result.Appendf(TEXT("Hash=%016llx"), hash);
|
||||
if (injectidle) {
|
||||
result.Appendf(TEXT(" action=idle"));
|
||||
if (finished) {
|
||||
result.Appendf(TEXT(" finished"));
|
||||
}
|
||||
while (!decoder.AtEOF()) {
|
||||
FlxAnimationField field = decoder.ReadField();
|
||||
if (persistentonly && !field.Persistent) continue;
|
||||
result.Append(TEXT(" "));
|
||||
result.Append(FString(field.Name.size(), (const UTF8CHAR*)field.Name.data()));
|
||||
result.Append(field.Persistent ? TEXT("=") : TEXT(":"));
|
||||
@@ -317,16 +317,16 @@ FlxAnimQueueDecoder::FlxAnimQueueDecoder(std::string_view queue) : Decoder(queue
|
||||
ActualSize = Decoder.read_uint8();
|
||||
}
|
||||
|
||||
FString FlxAnimQueueDecoder::DebugString(std::string_view queue) {
|
||||
FString result;
|
||||
FlxAnimQueueDecoder decoder(queue);
|
||||
while (!decoder.AtEOF()) {
|
||||
FlxAnimationStepView step = decoder.ReadStep();
|
||||
FString stepdebug = FlxAnimationStepDecoder::DebugString(false, false, step.Hash, step.Body);
|
||||
result.Appendf(TEXT("%s\n"), *stepdebug);
|
||||
}
|
||||
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(false, step.Hash, step.Body);
|
||||
// result.Appendf(TEXT("%s\n"), *stepdebug);
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
|
||||
FlxAnimTracker::FlxAnimTracker() {
|
||||
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) {
|
||||
check(!encqueue.empty());
|
||||
|
||||
@@ -409,14 +433,14 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
||||
int32 nremove = (AQ.Num() - (matchingindex + 1));
|
||||
check((nremove >= 0) && (nremove <= AQ.Num()));
|
||||
for (int32 i = 0; i < nremove; i++) {
|
||||
AQ.PopLast();
|
||||
AQ.Pop();
|
||||
}
|
||||
|
||||
// Transfer the new animations onto the queue.
|
||||
//
|
||||
while (!newsteps.IsEmpty()) {
|
||||
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
|
||||
@@ -425,12 +449,15 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
|
||||
// TODO: this is hardwired to keep 10. Instead, we
|
||||
// should keep the number specified in the queue.
|
||||
//
|
||||
int limit = 10;
|
||||
int ndiscard = AQ.Num() - limit;
|
||||
if (ndiscard > 0) {
|
||||
for (int i = 0; i < ndiscard; i++) {
|
||||
AQ.PopFirst();
|
||||
const int limit = 10;
|
||||
if (AQ.Num() > limit)
|
||||
{
|
||||
int offset = AQ.Num() - limit;
|
||||
for (int i = 0; i < limit; i++)
|
||||
{
|
||||
AQ[i] = AQ[i + offset];
|
||||
}
|
||||
AQ.SetNum(limit);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
AutoFinish = true;
|
||||
AutoFinishAction = action;
|
||||
@@ -486,3 +541,4 @@ FlxAnimationStep FlxAnimTracker::GetCurrentAnimation() {
|
||||
result.Hash += 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ public:
|
||||
|
||||
// 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.
|
||||
//
|
||||
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
|
||||
// of the queue is the oldest item.
|
||||
//
|
||||
TDeque<FlxAnimationStep> AQ;
|
||||
TArray<FlxAnimationStep> AQ;
|
||||
|
||||
// True if something has recently changed.
|
||||
//
|
||||
@@ -319,6 +319,18 @@ public:
|
||||
//
|
||||
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.
|
||||
//
|
||||
void ClearChanged() { Changed = false; }
|
||||
@@ -331,4 +343,8 @@ public:
|
||||
// The changed flag can only be set to false by 'ClearChanged,' above.
|
||||
//
|
||||
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++) {
|
||||
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
|
||||
// states. Be aware that the blueprint code could call back
|
||||
|
||||
@@ -23,7 +23,32 @@ void UlxTangible::Init(UlxTangibleManager* tm, int64 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) {
|
||||
FString Name = XName.ToLower();
|
||||
|
||||
@@ -32,7 +57,6 @@ void UlxTangible::SetActorBlueprint(const FString &XName) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the blueprint.
|
||||
UClass *blueprint = UlxAssetLookup::LoadTangibleBlueprintAsset(this, Name);
|
||||
if (blueprint == nullptr)
|
||||
{
|
||||
@@ -40,71 +64,50 @@ void UlxTangible::SetActorBlueprint(const FString &XName) {
|
||||
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
|
||||
ActorBlueprintName = Name;
|
||||
|
||||
// Now create a new actor, unless the BP is nullptr.
|
||||
if (blueprint != nullptr) {
|
||||
UWorld* w = Manager->GetWorld();
|
||||
FActorSpawnParameters params;
|
||||
// If there's already an actor, delete it.
|
||||
DeleteCurrentActor();
|
||||
|
||||
// Give the new actor a reasonable name.
|
||||
params.Name = FName(*FString::Printf(TEXT("%s_%ld"), *Name, TangibleId));
|
||||
// Now create a new actor.
|
||||
UWorld* w = Manager->GetWorld();
|
||||
FActorSpawnParameters params;
|
||||
|
||||
// Currently, the actor is spawned at (0,0,0), which is not good.
|
||||
// We should spawn at the actor's current location. I'll get to it
|
||||
// eventually.
|
||||
FTransform transform;
|
||||
transform.SetLocation(FVector(0,0,0));
|
||||
transform.SetRotation(FQuat(FRotator(0,0,0)));
|
||||
// Give the new actor a reasonable name.
|
||||
params.Name = FName(*FString::Printf(TEXT("%s_%ld"), *Name, TangibleId));
|
||||
|
||||
// Create the actor at the specified location even if there's something in the way.
|
||||
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);
|
||||
// Currently, the actor is spawned at (0,0,0), which is not good.
|
||||
// We should spawn at the actor's current location. I'll get to it
|
||||
// eventually.
|
||||
FTransform transform;
|
||||
transform.SetLocation(FVector(0,0,0));
|
||||
transform.SetRotation(FQuat(FRotator(0,0,0)));
|
||||
|
||||
// Make sure the label and the name are the same.
|
||||
a->SetActorLabel(params.Name.ToString());
|
||||
// Create the actor at the specified location even if there's something in the way.
|
||||
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.
|
||||
// Link the actor to its tangible, and the tangible to its actor.
|
||||
UActorComponent* ac = a->AddComponentByClass(UlxTangibleComponent::StaticClass(), false, FTransform::Identity, false);
|
||||
UlxTangibleComponent* tc = Cast<UlxTangibleComponent>(ac);
|
||||
check(tc != nullptr);
|
||||
tc->Tangible = this;
|
||||
CurrentActor = a;
|
||||
// Make sure the label and the name are the same.
|
||||
a->SetActorLabel(params.Name.ToString());
|
||||
|
||||
// This executes the BeginPlay entry point. We have to do this here
|
||||
// because we deferred it in SpawnActor.
|
||||
a->FinishSpawning(transform, true);
|
||||
}
|
||||
// Insert a TangibleComponent into the actor.
|
||||
// Link the actor to its tangible, and the tangible to its actor.
|
||||
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) {
|
||||
@@ -113,6 +116,9 @@ void UlxTangible::UpdateAnimationQueue(std::string_view aq) {
|
||||
|
||||
void UlxTangible::MaybeExecuteAnimStateChanged() {
|
||||
int limit = 3;
|
||||
|
||||
bool AnyChange = AnimTracker.IsChanged();
|
||||
|
||||
while (AnimTracker.IsChanged()) {
|
||||
if (limit == 0) break;
|
||||
limit -= 1;
|
||||
@@ -122,13 +128,47 @@ void UlxTangible::MaybeExecuteAnimStateChanged() {
|
||||
SetActorBlueprint(blueprint);
|
||||
AActor *actor = GetActor();
|
||||
UFunction *aqchanged = actor->GetClass()->FindFunctionByName(FName(TEXT("Animation Queue Changed")));
|
||||
if (aqchanged != nullptr) {
|
||||
if (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) {
|
||||
return FVector(0,0,0);
|
||||
} else {
|
||||
@@ -136,8 +176,9 @@ FVector UlxTangible::GetLocation() const {
|
||||
}
|
||||
}
|
||||
|
||||
void UlxTangible::Destroy() {
|
||||
SetActorBlueprint("");
|
||||
void UlxTangible::Destroy()
|
||||
{
|
||||
DeleteCurrentActor();
|
||||
Manager = nullptr;
|
||||
TangibleId = -1;
|
||||
CurrentActor = nullptr;
|
||||
@@ -147,14 +188,16 @@ void UlxTangible::Destroy() {
|
||||
NearAccordingToUnreal = false;
|
||||
}
|
||||
|
||||
UlxTangible *UlxTangible::GetActorTangibleQuiet(AActor *actor) {
|
||||
UlxTangible *UlxTangible::GetActorTangibleQuiet(AActor *actor)
|
||||
{
|
||||
if (actor == nullptr) return nullptr;
|
||||
UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>();
|
||||
if (comp == nullptr) return nullptr;
|
||||
return comp->Tangible.Get();
|
||||
}
|
||||
|
||||
UlxTangible *UlxTangible::GetActorTangibleOrLog(AActor *actor) {
|
||||
UlxTangible *UlxTangible::GetActorTangibleOrLog(AActor *actor)
|
||||
{
|
||||
UlxTangible *tan = GetActorTangibleQuiet(actor);
|
||||
if (tan == nullptr) {
|
||||
if (actor == nullptr) {
|
||||
@@ -175,18 +218,24 @@ void UlxTangible::GetCurrentAnimation(AActor *target, FlxAnimationStep &step) {
|
||||
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) {
|
||||
UlxTangible *tan = GetActorTangibleOrLog(target);
|
||||
if (tan == nullptr) return;
|
||||
if (AutoUpdate)
|
||||
{
|
||||
step.AutoUpdateXYZ(target);
|
||||
step.AutoUpdateFacing(target);
|
||||
step.AutoUpdatePlane(&(tan->Plane));
|
||||
}
|
||||
tan->AnimTracker.FinishedAnimation(step.Hash);
|
||||
if (AutoUpdate) tan->AutoUpdatePosition();
|
||||
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) {
|
||||
|
||||
@@ -57,6 +57,12 @@ public:
|
||||
// Animation tracker
|
||||
FlxAnimTracker AnimTracker;
|
||||
|
||||
// Animation that is waiting to be finished.
|
||||
uint64 PendingAnimationHash;
|
||||
|
||||
// When do we timeout the pending animation.
|
||||
double PendingAnimationTimeout;
|
||||
|
||||
// Current Plane.
|
||||
FName Plane;
|
||||
|
||||
@@ -66,6 +72,10 @@ public:
|
||||
// True if unreal thinks this object is Near the player.
|
||||
bool NearAccordingToUnreal;
|
||||
|
||||
// Delete the current actor.
|
||||
//
|
||||
void DeleteCurrentActor();
|
||||
|
||||
public:
|
||||
// Initialize a new tangible.
|
||||
//
|
||||
@@ -122,6 +132,9 @@ public:
|
||||
static UlxTangible *GetActorTangibleQuiet(AActor *actor);
|
||||
static UlxTangible *GetActorTangibleOrLog(AActor *actor);
|
||||
|
||||
// Automatically update the tangible's XYZ, Plane, Facing.
|
||||
//
|
||||
void AutoUpdatePosition();
|
||||
|
||||
private:
|
||||
|
||||
|
||||
11
build.py
11
build.py
@@ -156,6 +156,7 @@ def autodetect_system_config():
|
||||
config.DOT_EXE = ".exe"
|
||||
config.USER = "Unknown"
|
||||
config.BUILD_BAT = "Build.bat"
|
||||
config.DEBUG = "DebugGame"
|
||||
else:
|
||||
config.OS = "Linux"
|
||||
config.DLL = "so"
|
||||
@@ -163,6 +164,7 @@ def autodetect_system_config():
|
||||
config.DOT_EXE = ""
|
||||
config.USER = os.environ["USER"]
|
||||
config.BUILD_BAT = "Linux/Build.sh"
|
||||
config.DEBUG = "DebugGame"
|
||||
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.
|
||||
"""
|
||||
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
|
||||
DLL = config.DLL
|
||||
BAT = config.BAT
|
||||
DOT_EXE = config.DOT_EXE
|
||||
USER = config.USER
|
||||
BUILD_BAT = config.BUILD_BAT
|
||||
DEBUG = config.DEBUG
|
||||
INTEGRATION = config.INTEGRATION
|
||||
UNREALENGINE = config.UNREALENGINE
|
||||
|
||||
@@ -278,7 +281,7 @@ def build_luprex_and_integration():
|
||||
This builds our C++ code, and also UnrealEngine's C++ code.
|
||||
"""
|
||||
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.
|
||||
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")
|
||||
mods = list(mods1) + list(mods2)
|
||||
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.
|
||||
"""
|
||||
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)
|
||||
|
||||
#
|
||||
|
||||
@@ -179,7 +179,7 @@ public:
|
||||
}
|
||||
|
||||
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();
|
||||
actor_id_ = actor_id;
|
||||
set_visible_world_and_actor(world_.get(), actor_id_);
|
||||
@@ -257,7 +257,7 @@ public:
|
||||
break;
|
||||
}
|
||||
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..
|
||||
if (channel_ != nullptr) {
|
||||
if (channel_->closed()) {
|
||||
stdostream() << "server closed connection: " << channel_->error() << std::endl;
|
||||
util::dprint("server closed connection: ", channel_->error());
|
||||
abandon_server();
|
||||
} else {
|
||||
while (true) {
|
||||
|
||||
Reference in New Issue
Block a user