Tangible creation and destruction in place

This commit is contained in:
2023-09-28 14:32:48 -04:00
parent 9116a7b8fe
commit 642b444d13
7 changed files with 174 additions and 32 deletions

View File

@@ -210,8 +210,11 @@ FString FlxAnimQueueDecoder::DebugString(std::string_view queue) {
return result; return result;
} }
FlxAnimTracker::FlxAnimTracker() { FlxAnimTracker::FlxAnimTracker() {
Clear();
}
void FlxAnimTracker::Clear() {
AQ.Empty(); AQ.Empty();
FirstSeqno = 0; FirstSeqno = 0;
HashToSeqno.Empty(); HashToSeqno.Empty();

View File

@@ -279,6 +279,10 @@ public:
// //
FlxAnimTracker(); FlxAnimTracker();
// Clear everything, reset to the initial state.
//
void Clear();
// Update from the specified animation queue. // Update from the specified animation queue.
// //
// After the update is done, AQ will be a copy // After the update is done, AQ will be a copy

View File

@@ -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<FProperty>(uclass, nname);
// FStructProperty* sprop = FindFProperty<FStructProperty>(uclass, nname);
//}
#pragma optimize("", off) #pragma optimize("", off)
void AIntegrationGameModeBase::UpdateTangibles() { void AIntegrationGameModeBase::UpdateTangibles() {
double radius = 1000.0; // Hardwired for now.
using TanArray = UlxTangibleManager::TanArray; using TanArray = UlxTangibleManager::TanArray;
if (!Playing) return; if (!Playing) return;
FlxLockedWrapper w(LockableWrapper); FlxLockedWrapper w(LockableWrapper);
int64 player = w.GetActor(); 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(); TanArray alltans = TangibleManager->GetAllTangibles();
IdArray allids = TangibleManager->GetIds(alltans); IdArray allids = TangibleManager->GetIds(alltans);
StringViewVec allqueues = w.GetAnimationQueues(allids); StringViewVec allqueues = w.GetAnimationQueues(allids);
for (int i = 0; i < alltans.Num(); i++) { for (int i = 0; i < alltans.Num(); i++) {
UlxTangible *t = alltans[i]; alltans[i]->UpdateAnimationQueue(allqueues[i]);
t->AnimTracker.Update(allqueues[i]);
TArray<uint64> 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);
}
}
} }
TangibleManager->RecalcNearAccordingToUnreal(player, radius);
TangibleManager->DeleteFarawayTangibles();
} }
void AIntegrationGameModeBase::ConsoleSendInput(const FString& fs) void AIntegrationGameModeBase::ConsoleSendInput(const FString& fs)

View File

@@ -6,8 +6,12 @@
UlxTangible::UlxTangible() UlxTangible::UlxTangible()
{ {
Manager = nullptr;
TangibleId = -1; TangibleId = -1;
CurrentActor = nullptr;
ActorBlueprint = nullptr;
NearAccordingToLuprex = false; NearAccordingToLuprex = false;
NearAccordingToUnreal = false;
} }
void UlxTangible::Init(UlxTangibleManager* tm, int64 id) void UlxTangible::Init(UlxTangibleManager* tm, int64 id)
@@ -69,15 +73,50 @@ void UlxTangible::SetActorBlueprintClass(TSubclassOf<AActor> bp) {
} }
} }
void UlxTangible::UpdateAnimationQueue(std::string_view aq) {
AnimTracker.Update(aq);
TArray<uint64> 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) { FString UlxTangible::GetTangiblePlane(AActor* actor) {
UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>(); UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>();
check(comp != nullptr); check(comp != nullptr);
return comp->Tangible->Plane; return comp->Tangible->Plane.ToString();
} }
void UlxTangible::SetTangiblePlane(AActor* actor, const FString& plane) { void UlxTangible::SetTangiblePlane(AActor* actor, const FString& plane) {
UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>(); UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>();
check(comp != nullptr); check(comp != nullptr);
comp->Tangible->Plane = plane; comp->Tangible->Plane = FName(plane);
} }

View File

@@ -89,19 +89,83 @@ public:
FlxAnimTracker AnimTracker; FlxAnimTracker AnimTracker;
// Current Plane. // Current Plane.
FString Plane; FName Plane;
// True if luprex thinks this object is Near the player. // True if luprex thinks this object is Near the player.
bool NearAccordingToLuprex; bool NearAccordingToLuprex;
// True if unreal thinks this object is Near the player.
bool NearAccordingToUnreal;
public: public:
// Initialize a new tangible.
//
// This links the tangible to its TangibleManager and
// sets the tangible's ID.
//
void Init(UlxTangibleManager *tm, int64 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<AActor> bp); static bool BlueprintIsTangible(TSubclassOf<AActor> 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<AActor> bp); void SetActorBlueprintClass(TSubclassOf<AActor> 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: public:
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex) UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex)

View File

@@ -28,6 +28,7 @@ UlxTangible* UlxTangibleManager::GetTangible(int64 id) const {
} }
} }
#pragma optimize("", off)
UlxTangible* UlxTangibleManager::MakeTangible(int64 id) { UlxTangible* UlxTangibleManager::MakeTangible(int64 id) {
UlxTangible*& t = IdToTangible.FindOrAdd(id); UlxTangible*& t = IdToTangible.FindOrAdd(id);
if (t == nullptr) { if (t == nullptr) {
@@ -56,7 +57,8 @@ TanArray UlxTangibleManager::GetAllTangibles() const {
return result; return result;
} }
void UlxTangibleManager::UpdateNear(IdView near) { #pragma optimize("", off)
void UlxTangibleManager::UpdateNearAccordingToLuprex(IdView near) {
// Clear all the 'NearAccordingToLuprex' flags. // Clear all the 'NearAccordingToLuprex' flags.
for (const auto& pair : IdToTangible) { for (const auto& pair : IdToTangible) {
pair.Value->NearAccordingToLuprex = false; 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 UlxTangibleManager::GetIds(const TanArray &arr) {
IdArray result; IdArray result;
result.SetNum(arr.Num()); result.SetNum(arr.Num());

View File

@@ -61,10 +61,21 @@ public:
// Update the 'NearAccordingToLuprex' flags. // Update the 'NearAccordingToLuprex' flags.
// //
// Also creates any tangibles that are in the near-list, // Also creates stub tangibles for every Id in the list.
// if they don't already exist.
// //
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. // Given an array of tangibles, return an array of tangible Ids.
// //