Class Tangible can now recreate its Actor

This commit is contained in:
2023-09-26 17:00:30 -04:00
parent cc6509a69c
commit 0efd0dd3ad
12 changed files with 261 additions and 207 deletions

Binary file not shown.

View File

@@ -3,12 +3,10 @@
#include "IntegrationGameModeBase.h" #include "IntegrationGameModeBase.h"
#include "lpx-drvutil.hpp" #include "lpx-drvutil.hpp"
#include "DebugPrint.h" #include "DebugPrint.h"
#include "TangibleComponent.h" #include "Tangible.h"
#include "TangibleManager.h" #include "TangibleManager.h"
#include "TangibleInterface.h"
#include "CommonTypes.h" #include "CommonTypes.h"
#include "AnimQueue.h" #include "AnimQueue.h"
#include "IntegrationGameState.h"
#include <string> #include <string>
#include <string_view> #include <string_view>
@@ -17,7 +15,7 @@ using namespace CommonTypes;
AIntegrationGameModeBase::AIntegrationGameModeBase() AIntegrationGameModeBase::AIntegrationGameModeBase()
{ {
TangibleManager = NewObject<UTangibleManager>(); TangibleManager = NewObject<UlxTangibleManager>();
EngineSeconds = 0.0; EngineSeconds = 0.0;
NextThreadTrigger = 1.0; NextThreadTrigger = 1.0;
//PrimaryActorTick.bCanEverTick = true; // Probably wrong //PrimaryActorTick.bCanEverTick = true; // Probably wrong
@@ -127,8 +125,9 @@ void AIntegrationGameModeBase::UpdateTangibles() {
FlxLockedWrapper w(LockableWrapper); FlxLockedWrapper w(LockableWrapper);
int64 actor = w.GetActor(); int64 actor = w.GetActor();
TangibleManager->SetPlayer(actor); TangibleManager->SetPlayer(actor);
TangibleManager->SetNear(w.GetNear(actor, 100, 100, 100)); IdView near = w.GetNear(actor, 100, 100, 100);
for (int64 id : TangibleManager->GetNear()) { TangibleManager->SetNear(near);
for (int64 id : near) {
TangibleManager->MakeTangible(id); TangibleManager->MakeTangible(id);
} }
// Update animation queues of live tangibles. // Update animation queues of live tangibles.
@@ -136,7 +135,7 @@ void AIntegrationGameModeBase::UpdateTangibles() {
StringViewVec aqueues = w.GetAnimationQueues(tanids); StringViewVec aqueues = w.GetAnimationQueues(tanids);
for (int i = 0; i < tanids.Num(); i++) { for (int i = 0; i < tanids.Num(); i++) {
uint64_t tanid = tanids[i]; uint64_t tanid = tanids[i];
UTangibleComponent *t = TangibleManager->GetTangible(tanid); UlxTangible *t = TangibleManager->GetTangible(tanid);
t->AnimTracker.Update(aqueues[i]); t->AnimTracker.Update(aqueues[i]);
TArray<uint64> aborted = t->AnimTracker.GetAborted(); TArray<uint64> aborted = t->AnimTracker.GetAborted();
for (uint64 hash : aborted) { for (uint64 hash : aborted) {
@@ -243,7 +242,7 @@ void AIntegrationGameModeBase::BeginPlay()
} }
// Initialize the tangible manager. // Initialize the tangible manager.
TangibleManager = NewObject<UTangibleManager>(); TangibleManager = NewObject<UlxTangibleManager>();
TangibleManager->Init(GetWorld(), ClassTangibleActor); TangibleManager->Init(GetWorld(), ClassTangibleActor);
} }
@@ -252,16 +251,3 @@ void AIntegrationGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
ResetToInitialState(); ResetToInitialState();
} }
namespace IntegrationGameState {
UTangibleManager* GetTangibleManager(AActor *actor) {
AGameModeBase* gmb = actor->GetWorld()->GetAuthGameMode();
AIntegrationGameModeBase* igmb = Cast<AIntegrationGameModeBase>(gmb);
if (igmb == nullptr) {
return nullptr;
} else {
return igmb->TangibleManager;
}
}
} // namespace IntegrationGameState

View File

@@ -57,7 +57,7 @@ public:
virtual uint32 Run() override; virtual uint32 Run() override;
UPROPERTY() UPROPERTY()
UTangibleManager *TangibleManager; UlxTangibleManager *TangibleManager;
// This stores the entire text currently visible in the console. // This stores the entire text currently visible in the console.
FlxConsoleOutput ConsoleOutput; FlxConsoleOutput ConsoleOutput;

View File

@@ -1,7 +0,0 @@
class UTangibleManager;
namespace IntegrationGameState {
UTangibleManager* GetTangibleManager(AActor *actor);
}

View File

@@ -0,0 +1,81 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Tangible.h"
#include "TangibleManager.h"
UlxTangible::UlxTangible()
{
}
void UlxTangible::Init(UlxTangibleManager* tm, int64 id)
{
Manager = tm;
TangibleId = id;
}
bool UlxTangible::BlueprintIsTangible(TSubclassOf<AActor> bp) {
if (bp == nullptr) return true;
return bp->ImplementsInterface(UlxTangibleInterface::StaticClass());
}
void UlxTangible::SetActorBlueprintClass(TSubclassOf<AActor> bp) {
// If we're already of the right class, do nothing.
if (ActorBlueprint == bp) {
return;
}
// Sanity check the blueprint. Nullptr is allowed.
check(BlueprintIsTangible(bp));
// 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();
}
// Update the blueprint reference.
ActorBlueprint = bp;
// Now create a new actor, unless the BP is nullptr.
if (ActorBlueprint != nullptr) {
// Create the actor.
FActorSpawnParameters params;
FVector location(0, 0, 0);
FRotator rotation(0, 0, 0);
UWorld* w = Manager->GetWorld();
AActor* a = w->SpawnActor(ActorBlueprint, &location, &rotation, params);
// Insert a TangibleComponent into the actor.
UActorComponent* ac = a->AddComponentByClass(UlxTangibleComponent::StaticClass(), false, FTransform::Identity, false);
UlxTangibleComponent* tc = Cast<UlxTangibleComponent>(ac);
check(tc != nullptr);
// Make the tangible point to the actor and vice versa.
tc->Tangible = this;
CurrentActor = a;
}
}
FString UlxTangible::GetTangiblePlane(AActor* actor) {
UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>();
check(comp != nullptr);
return comp->Tangible->Plane;
}
void UlxTangible::SetTangiblePlane(AActor* actor, const FString& plane) {
UlxTangibleComponent* comp = actor->GetComponentByClass<UlxTangibleComponent>();
check(comp != nullptr);
comp->Tangible->Plane = plane;
}

View File

@@ -0,0 +1,139 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "AnimQueue.h"
#include "Tangible.generated.h"
class UlxTangibleManager;
// This class does not need to be modified.
UINTERFACE(Blueprintable)
class UlxTangibleInterface : public UInterface
{
GENERATED_BODY()
};
/**
*
* IlxTangibleInterface
*
* This class implements the interface that an Actor must implement
* in order for that Actor to be usable as a Tangible.
*
*/
class INTEGRATION_API IlxTangibleInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
bool StartAnimation(ElxAnimationMode mode, const FlxAnimationStep& step);
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
bool AbortAnimation(int64 hash);
};
/**
*
* UlxTangible
*
* The Tangible stores all the data we need for a tangible,
* such as the animation queue and so forth.
*
* From time to time, a tangible can change its blueprint class.
* To do that, we have to delete and recreate the actor. This
* is all set up so that it is possible to do that.
*
* The tangible has a place to store an Actor pointer. This
* actor pointer is allowed to be nullptr, especially in the
* case that the blueprint hasn't been set yet.
*
* This also serves as a repository for blueprint functions
* that operate on tangible actors.
*
*/
UCLASS()
class INTEGRATION_API UlxTangible : public UObject
{
GENERATED_BODY()
public:
UlxTangible();
// My Tangible Manager.
UPROPERTY()
TObjectPtr<UlxTangibleManager> Manager;
// The tangible ID.
UPROPERTY()
uint64 TangibleId;
UPROPERTY()
TWeakObjectPtr<AActor> CurrentActor;
// The blueprint class of the actor.
UPROPERTY()
TSubclassOf<AActor> ActorBlueprint;
// Animation tracker
FlxAnimTracker AnimTracker;
// Current Plane.
FString Plane;
// True if luprex thinks this object is Near the player.
bool NearAccordingToLuprex;
public:
void Init(UlxTangibleManager *tm, int64 id);
static bool BlueprintIsTangible(TSubclassOf<AActor> bp);
void SetActorBlueprintClass(TSubclassOf<AActor> bp);
AActor* GetActor() const { return CurrentActor.Get(); }
public:
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex)
static FString GetTangiblePlane(AActor* target);
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex)
static void SetTangiblePlane(AActor* target, const FString& plane);
};
/**
*
* UlxTangibleComponent
*
* The TangibleComponent holds a pointer to the Tangible.
* This is the only purpose it serves: to make it possible to
* have the Actor point to its corresponding Tangible.
*
* The TangibleComponent is procedurally inserted into the Actor.
* The TangibleComponent is not visible to blueprints.
*
*/
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class INTEGRATION_API UlxTangibleComponent : public UActorComponent
{
GENERATED_BODY()
public:
UlxTangibleComponent() : Tangible(nullptr) {}
// The actor that we're a part of.
UPROPERTY()
TWeakObjectPtr<UlxTangible> Tangible;
};

View File

@@ -1,29 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "TangibleComponent.h"
#include "TangibleManager.h"
UTangibleComponent::UTangibleComponent()
{
}
void UTangibleComponent::Init(UTangibleManager* tm, AActor* a, int64 id)
{
TangibleManager = tm;
OwningActor = a;
TangibleId = id;
}
FString UTangibleComponent::GetTangiblePlane(AActor* actor) {
UTangibleComponent* comp = actor->GetComponentByClass<UTangibleComponent>();
check(comp != nullptr);
return comp->Plane;
}
void UTangibleComponent::SetTangiblePlane(AActor* actor, const FString& plane) {
UTangibleComponent* comp = actor->GetComponentByClass<UTangibleComponent>();
check(comp != nullptr);
comp->Plane = plane;
}

View File

@@ -1,64 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "AnimQueue.h"
#include "TangibleComponent.generated.h"
/*
* TangibleComponent
*
* The TangibleManager procedurally injects a TangibleComponent
* into the actor. This gives us a place to store tangible-specific
* actor properties, such as the tangible Id, the animation queue,
* and so forth.
*
* To cooperate the with the garbage collector, don't store pointers
* to TangibleComponents in data structures. Instead, store a pointer
* to the actor and then use GetComponentByClass to retrieve the
* TangibleComponent on demand.
*
*/
class UTangibleManager;
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class INTEGRATION_API UTangibleComponent : public UActorComponent
{
GENERATED_BODY()
public:
UTangibleComponent();
// The tangible ID.
UPROPERTY()
uint64 TangibleId;
// The actor that we're a part of.
UPROPERTY()
TWeakObjectPtr<AActor> OwningActor;
// Our tangible Manager.
UPROPERTY()
TWeakObjectPtr<UTangibleManager> TangibleManager;
// Animation tracker
FlxAnimTracker AnimTracker;
// Current Plane.
FString Plane;
public:
void Init(UTangibleManager* tm, AActor* a, int64 id);
AActor* GetActor() const { return OwningActor.Get(); }
public:
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex)
static FString GetTangiblePlane(AActor* target);
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex)
static void SetTangiblePlane(AActor* target, const FString& plane);
};

View File

@@ -1,6 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "TangibleInterface.h"
// Add default functionality here for any IlxTangibleInterface functions that are not pure virtual.

View File

@@ -1,33 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "AnimQueue.h"
#include "TangibleInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(Blueprintable)
class UlxTangibleInterface : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class INTEGRATION_API IlxTangibleInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
bool StartAnimation(ElxAnimationMode mode, const FlxAnimationStep& step);
UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality")
bool AbortAnimation(int64 hash);
};

View File

@@ -2,73 +2,60 @@
#include "TangibleManager.h" #include "TangibleManager.h"
#include "TangibleInterface.h" #include "Tangible.h"
#include "IntegrationGameState.h"
#include "TangibleComponent.h"
#include "DebugPrint.h" #include "DebugPrint.h"
using namespace DebugPrint; using namespace DebugPrint;
UTangibleManager::UTangibleManager() { UlxTangibleManager::UlxTangibleManager() {
World = nullptr; World = nullptr;
ClassTangibleActor = nullptr; ClassTangibleActor = nullptr;
Player = 0; Player = 0;
Near = IdView(); Near = IdView();
} }
void UTangibleManager::Init(UWorld *world, UClass* tanact) { void UlxTangibleManager::Init(UWorld* world, UClass* tanact) {
World = world; World = world;
ClassTangibleActor = tanact; ClassTangibleActor = tanact;
Player = 0; Player = 0;
Near = IdView(); Near = IdView();
} }
UTangibleComponent *UTangibleManager::GetTangible(int64 id) { UlxTangible* UlxTangibleManager::GetTangible(int64 id) {
AActor **p = IdToActor.Find(id); UlxTangible** p = IdToTangible.Find(id);
if (p == nullptr) { if (p == nullptr) {
return nullptr; return nullptr;
} else { }
AActor* a = *p; else {
UTangibleComponent* comp = a->FindComponentByClass<UTangibleComponent>(); return *p;
check(comp != nullptr);
return comp;
} }
} }
UTangibleComponent *UTangibleManager::MakeTangible(int64 id) { UlxTangible* UlxTangibleManager::MakeTangible(int64 id) {
AActor *& p = IdToActor.FindOrAdd(id); UlxTangible*& t = IdToTangible.FindOrAdd(id);
if (p == nullptr) { if (t == nullptr) {
FActorSpawnParameters params; t = NewObject<UlxTangible>();
FVector location(0, 0, 0); t->Init(this, id);
FRotator rotation(0, 0, 0);
UWorld* w = GetWorld(); // TODO: fix this. The blueprint needs to be assigned
AActor* a = w->SpawnActor(ClassTangibleActor, &location, &rotation, params); // during animation queue parsing, based on the animation
check(a != nullptr); // queue keyword 'bp'.
check(a->GetClass()->ImplementsInterface(UlxTangibleInterface::StaticClass())); t->SetActorBlueprintClass(ClassTangibleActor);
// Insert a TangibleComponent into the actor.
UActorComponent* ac = a->AddComponentByClass(UTangibleComponent::StaticClass(), false, FTransform::Identity, false);
UTangibleComponent* tc = Cast<UTangibleComponent>(ac);
check(tc != nullptr);
tc->Init(this, a, id);
p = a;
return tc;
} else {
UTangibleComponent* comp = p->FindComponentByClass<UTangibleComponent>();
check(comp != nullptr);
return comp;
} }
return t;
} }
void UTangibleManager::DeleteTangible(int64 id) { void UlxTangibleManager::DeleteTangible(int64 id) {
// IMPLEMENT ME // IMPLEMENT ME
} }
UTangibleManager::IdArray UTangibleManager::GetLive() { UlxTangibleManager::IdArray UlxTangibleManager::GetLive() {
IdArray result; IdArray result;
result.SetNum(IdToActor.Num()); result.SetNum(IdToTangible.Num());
int next = 0; int next = 0;
for (auto &pair : IdToActor) { for (auto& pair : IdToTangible) {
result[next++] = pair.Key; result[next++] = pair.Key;
} }
return result; return result;
} }

View File

@@ -5,11 +5,11 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "UObject/NoExportTypes.h" #include "UObject/NoExportTypes.h"
#include "CommonTypes.h" #include "CommonTypes.h"
#include "TangibleComponent.h" #include "Tangible.h"
#include "TangibleManager.generated.h" #include "TangibleManager.generated.h"
UCLASS() UCLASS()
class INTEGRATION_API UTangibleManager : public UObject class INTEGRATION_API UlxTangibleManager : public UObject
{ {
GENERATED_BODY() GENERATED_BODY()
@@ -27,9 +27,9 @@ public:
UPROPERTY() UPROPERTY()
TSubclassOf<AActor> ClassTangibleActor; TSubclassOf<AActor> ClassTangibleActor;
// Given a tangible ID, look up actor pointer (or NULL if actor was deleted) // Given a tangible ID, look up the TangibleComponent of that actor.
UPROPERTY() UPROPERTY()
TMap<int64, AActor*> IdToActor; TMap<int64, UlxTangible*> IdToTangible;
// Player's tangible Id. // Player's tangible Id.
int64 Player; int64 Player;
@@ -38,7 +38,7 @@ public:
IdView Near; IdView Near;
public: public:
UTangibleManager(); UlxTangibleManager();
// Initialize the tangible manager. // Initialize the tangible manager.
// //
@@ -49,10 +49,10 @@ public:
UWorld* GetWorld() const override { return World.Get(); } UWorld* GetWorld() const override { return World.Get(); }
// Get the tangible if it exists, otherwise return NULL // Get the tangible if it exists, otherwise return NULL
UTangibleComponent* GetTangible(int64 id); UlxTangible* GetTangible(int64 id);
// Get the tangible if it exists, otherwise create it. // Get the tangible if it exists, otherwise create it.
UTangibleComponent* MakeTangible(int64 id); UlxTangible* MakeTangible(int64 id);
// Delete the tangible. // Delete the tangible.
void DeleteTangible(int64 id); void DeleteTangible(int64 id);