From 642b444d1336a57d366b9ad51fab9493265b3f48 Mon Sep 17 00:00:00 2001 From: teppy999 Date: Thu, 28 Sep 2023 14:32:48 -0400 Subject: [PATCH] Tangible creation and destruction in place --- Source/Integration/AnimQueue.cpp | 5 +- Source/Integration/AnimQueue.h | 4 ++ .../Integration/IntegrationGameModeBase.cpp | 30 ++------ Source/Integration/Tangible.cpp | 43 +++++++++++- Source/Integration/Tangible.h | 68 ++++++++++++++++++- Source/Integration/TangibleManager.cpp | 39 ++++++++++- Source/Integration/TangibleManager.h | 17 ++++- 7 files changed, 174 insertions(+), 32 deletions(-) diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index a0b8d060..050747f4 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -210,8 +210,11 @@ FString FlxAnimQueueDecoder::DebugString(std::string_view queue) { return result; } - FlxAnimTracker::FlxAnimTracker() { + Clear(); +} + +void FlxAnimTracker::Clear() { AQ.Empty(); FirstSeqno = 0; HashToSeqno.Empty(); diff --git a/Source/Integration/AnimQueue.h b/Source/Integration/AnimQueue.h index 0d9bb512..5df05d1f 100644 --- a/Source/Integration/AnimQueue.h +++ b/Source/Integration/AnimQueue.h @@ -279,6 +279,10 @@ public: // FlxAnimTracker(); + // Clear everything, reset to the initial state. + // + void Clear(); + // Update from the specified animation queue. // // After the update is done, AQ will be a copy diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index b9efd041..71745761 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -109,42 +109,26 @@ void AIntegrationGameModeBase::MaybeTriggerUpdateTask(float deltaseconds) { } } -//#pragma optimize( "", off ) -//void SetLocal(UObject* obj, const char *name, int value) { -// FString sname((const UTF8CHAR *)name); -// FName nname(sname); -// UClass* uclass = obj->GetClass(); -// FProperty* fprop = FindFProperty(uclass, nname); -// FStructProperty* sprop = FindFProperty(uclass, nname); -//} + #pragma optimize("", off) void AIntegrationGameModeBase::UpdateTangibles() { + double radius = 1000.0; // Hardwired for now. using TanArray = UlxTangibleManager::TanArray; if (!Playing) return; FlxLockedWrapper w(LockableWrapper); int64 player = w.GetActor(); - TangibleManager->UpdateNear(w.GetNear(player, 100, 100, 100)); + IdView nearids = w.GetNear(player, radius, radius, radius); + TangibleManager->UpdateNearAccordingToLuprex(nearids); TanArray alltans = TangibleManager->GetAllTangibles(); IdArray allids = TangibleManager->GetIds(alltans); StringViewVec allqueues = w.GetAnimationQueues(allids); for (int i = 0; i < alltans.Num(); i++) { - UlxTangible *t = alltans[i]; - t->AnimTracker.Update(allqueues[i]); - TArray aborted = t->AnimTracker.GetAborted(); - for (uint64 hash : aborted) { - IlxTangibleInterface::Execute_AbortAnimation(t->GetActor(), hash); - } - FlxAnimationStep step; - ElxAnimationMode mode = t->AnimTracker.GetNextStep(step); - if (mode != ElxAnimationMode::INVALID) { - bool started = IlxTangibleInterface::Execute_StartAnimation(t->GetActor(), mode, step); - if (started) { - t->AnimTracker.StartedStep(step.Hash); - } - } + alltans[i]->UpdateAnimationQueue(allqueues[i]); } + TangibleManager->RecalcNearAccordingToUnreal(player, radius); + TangibleManager->DeleteFarawayTangibles(); } void AIntegrationGameModeBase::ConsoleSendInput(const FString& fs) diff --git a/Source/Integration/Tangible.cpp b/Source/Integration/Tangible.cpp index 17b97851..68a885f7 100644 --- a/Source/Integration/Tangible.cpp +++ b/Source/Integration/Tangible.cpp @@ -6,8 +6,12 @@ UlxTangible::UlxTangible() { + Manager = nullptr; TangibleId = -1; + CurrentActor = nullptr; + ActorBlueprint = nullptr; NearAccordingToLuprex = false; + NearAccordingToUnreal = false; } void UlxTangible::Init(UlxTangibleManager* tm, int64 id) @@ -69,15 +73,50 @@ void UlxTangible::SetActorBlueprintClass(TSubclassOf bp) { } } +void UlxTangible::UpdateAnimationQueue(std::string_view aq) { + AnimTracker.Update(aq); + TArray aborted = AnimTracker.GetAborted(); + for (uint64 hash : aborted) { + IlxTangibleInterface::Execute_AbortAnimation(GetActor(), hash); + } + FlxAnimationStep step; + ElxAnimationMode mode = AnimTracker.GetNextStep(step); + if (mode != ElxAnimationMode::INVALID) { + bool started = IlxTangibleInterface::Execute_StartAnimation(GetActor(), mode, step); + if (started) { + AnimTracker.StartedStep(step.Hash); + } + } +} + +FVector UlxTangible::GetLocation() const { + if (CurrentActor == nullptr) { + return FVector(0,0,0); + } else { + return CurrentActor->GetActorLocation(); + } +} + +void UlxTangible::Destroy() { + SetActorBlueprintClass(nullptr); + Manager = nullptr; + TangibleId = -1; + CurrentActor = nullptr; + ActorBlueprint = nullptr; + AnimTracker.Clear(); + NearAccordingToLuprex = false; + NearAccordingToUnreal = false; +} + FString UlxTangible::GetTangiblePlane(AActor* actor) { UlxTangibleComponent* comp = actor->GetComponentByClass(); check(comp != nullptr); - return comp->Tangible->Plane; + return comp->Tangible->Plane.ToString(); } void UlxTangible::SetTangiblePlane(AActor* actor, const FString& plane) { UlxTangibleComponent* comp = actor->GetComponentByClass(); check(comp != nullptr); - comp->Tangible->Plane = plane; + comp->Tangible->Plane = FName(plane); } diff --git a/Source/Integration/Tangible.h b/Source/Integration/Tangible.h index 5d5d4cbe..d3323a22 100644 --- a/Source/Integration/Tangible.h +++ b/Source/Integration/Tangible.h @@ -89,19 +89,83 @@ public: FlxAnimTracker AnimTracker; // Current Plane. - FString Plane; + FName Plane; // True if luprex thinks this object is Near the player. bool NearAccordingToLuprex; + // True if unreal thinks this object is Near the player. + bool NearAccordingToUnreal; + public: + // Initialize a new tangible. + // + // This links the tangible to its TangibleManager and + // sets the tangible's ID. + // void Init(UlxTangibleManager *tm, int64 id); + // Destroy a tangible. + // + // Delete the actor associated with the tangible, if any, + // and clean up everything else. + // + void Destroy(); + + // Get the actor associated with this tangible. + // + // Note that this may return nullptr: it is valid for a + // tangible to have no actor associated with it. This + // is most commonly the case if the blueprint class of + // the tangible is set to nullptr. + // + // Also bear in mind that if a tangible changes its blueprint + // class, then the actor will have to be deleted and + // recreated. In that case, GetActor will return a different + // pointer than before the blueprint change. + // + AActor* GetActor() const { return CurrentActor.Get(); } + + // Get the location of the tangible. + // + // Note that if the actor is nullptr, the location is always + // at the origin. + // + FVector GetLocation() const; + + // Check a blueprint class to see if it is valid as a Tangible. + // + // In order for a blueprint class to be used as a tangible, + // it must implement the interface IlxTangibleInterface. + // This function also returns true for nullptr. + // static bool BlueprintIsTangible(TSubclassOf bp); + // Change the blueprint class of the tangible. + // + // This requires the deletion and recreation of the Actor. + // The blueprint class must satisfy 'BlueprintIsTangible' above. + // + // It is legal to pass in nullptr for the blueprint class. + // Whenever the blueprint class is nullptr, the Actor is + // also nullptr. Ie, a tangible will have no Actor associated + // with it if its blueprint class is nullptr. + // void SetActorBlueprintClass(TSubclassOf bp); - AActor* GetActor() const { return CurrentActor.Get(); } + // Update the animation queue from Luprex. + // + // This reads the animation queue, and then based on + // what is new in the animation queue, it calls into + // the Actor's TangibleInterface, calling methods such + // as 'StartAnimation' and 'AbortAnimation' as necessary. + // + // If the animation queue specifies a blueprint change, + // this function will eventually implement that by calling + // SetActorBlueprintClass above. This is not implemented + // yet. + // + void UpdateAnimationQueue(std::string_view aq); public: UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex) diff --git a/Source/Integration/TangibleManager.cpp b/Source/Integration/TangibleManager.cpp index 0559b5de..3bbeda20 100644 --- a/Source/Integration/TangibleManager.cpp +++ b/Source/Integration/TangibleManager.cpp @@ -28,6 +28,7 @@ UlxTangible* UlxTangibleManager::GetTangible(int64 id) const { } } +#pragma optimize("", off) UlxTangible* UlxTangibleManager::MakeTangible(int64 id) { UlxTangible*& t = IdToTangible.FindOrAdd(id); if (t == nullptr) { @@ -56,7 +57,8 @@ TanArray UlxTangibleManager::GetAllTangibles() const { return result; } -void UlxTangibleManager::UpdateNear(IdView near) { +#pragma optimize("", off) +void UlxTangibleManager::UpdateNearAccordingToLuprex(IdView near) { // Clear all the 'NearAccordingToLuprex' flags. for (const auto& pair : IdToTangible) { pair.Value->NearAccordingToLuprex = false; @@ -69,6 +71,41 @@ void UlxTangibleManager::UpdateNear(IdView near) { } } +#pragma optimize("", off) +void UlxTangibleManager::RecalcNearAccordingToUnreal(int64 player, double radius) { + UlxTangible *p = GetTangible(player); + check (p != nullptr); + FVector playerpos = p->CurrentActor->GetActorLocation(); + FName playerplane = p->Plane; + double radiussq = radius * radius; + for (const auto& pair : IdToTangible) { + UlxTangible *tan = pair.Value; + if (tan->Plane != playerplane) { + tan->NearAccordingToUnreal = false; + } else { + FVector pos = tan->GetLocation(); + double distsq = FVector::DistSquared(pos, playerpos); + tan->NearAccordingToUnreal = (distsq <= radiussq); + } + } +} + +void UlxTangibleManager::DeleteFarawayTangibles() { + // Make a list of tangibles that need to be deleted. + TanArray faraway; + for (const auto& pair : IdToTangible) { + UlxTangible *tan = pair.Value; + if (!(tan->NearAccordingToLuprex || tan->NearAccordingToUnreal)) { + faraway.Add(tan); + } + } + + for (UlxTangible *tan : faraway) { + IdToTangible.Remove(tan->TangibleId); + tan->Destroy(); // Remove the actor from the scene. + } +} + IdArray UlxTangibleManager::GetIds(const TanArray &arr) { IdArray result; result.SetNum(arr.Num()); diff --git a/Source/Integration/TangibleManager.h b/Source/Integration/TangibleManager.h index ca83831b..6d9c8827 100644 --- a/Source/Integration/TangibleManager.h +++ b/Source/Integration/TangibleManager.h @@ -61,10 +61,21 @@ public: // Update the 'NearAccordingToLuprex' flags. // - // Also creates any tangibles that are in the near-list, - // if they don't already exist. + // Also creates stub tangibles for every Id in the list. // - void UpdateNear(IdView near); + void UpdateNearAccordingToLuprex(IdView near); + + // Recalculate the 'NearAccordingToUnreal' flags. + // + void RecalcNearAccordingToUnreal(int64 player, double radius); + + // Delete Far Tangibles. + // + // Any tangible whose 'NearAccordingToLuprex' and 'NearAccordingToUnreal' + // flags are both false is deleted. You probably want to update both + // flags by calling the two routines above before calling this. + // + void DeleteFarawayTangibles(); // Given an array of tangibles, return an array of tangible Ids. //