Can now specify bp= in the animation queue, and it works

This commit is contained in:
2024-01-24 14:51:21 -05:00
parent 0b5e4e60e5
commit 864ecf0015
6 changed files with 74 additions and 55 deletions

View File

@@ -376,6 +376,15 @@ void FlxAnimTracker::Update(std::string_view encqueue) {
} }
} }
FString FlxAnimTracker::GetCurrentBlueprintName() {
for (int i = 0; i < AQ.Num(); i++) {
if (!AQ[i].Finished) {
return AQ[i].Blueprint;
}
}
return AQ.Last().Blueprint;
}
FlxAnimationStep FlxAnimTracker::GetCurrentAnimation() { FlxAnimationStep FlxAnimTracker::GetCurrentAnimation() {
FlxAnimationStep result; FlxAnimationStep result;
for (int i = 0; i < AQ.Num(); i++) { for (int i = 0; i < AQ.Num(); i++) {

View File

@@ -278,6 +278,10 @@ public:
// //
void Update(std::string_view encqueue); void Update(std::string_view encqueue);
// Get the current blueprint name, as a string.
//
FString GetCurrentBlueprintName();
// Get the current animation step. // Get the current animation step.
// //
// Get the current animation step. This is the step that the // Get the current animation step. This is the step that the

View File

@@ -4,12 +4,14 @@
#include "Tangible.h" #include "Tangible.h"
#include "TangibleManager.h" #include "TangibleManager.h"
#define DEFAULT_BLUEPRINT (TEXT("TangibleStaticMesh"))
UlxTangible::UlxTangible() UlxTangible::UlxTangible()
{ {
Manager = nullptr; Manager = nullptr;
TangibleId = -1; TangibleId = -1;
CurrentActor = nullptr; CurrentActor = nullptr;
ActorBlueprint = nullptr; ActorBlueprintName = TEXT("");
NearAccordingToLuprex = false; NearAccordingToLuprex = false;
NearAccordingToUnreal = false; NearAccordingToUnreal = false;
} }
@@ -20,19 +22,20 @@ void UlxTangible::Init(UlxTangibleManager* tm, int64 id)
TangibleId = id; TangibleId = id;
} }
bool UlxTangible::BlueprintIsTangible(TSubclassOf<AActor> bp) { void UlxTangible::SetActorBlueprint(const FString &name) {
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 we're already of the right class, do nothing.
if (ActorBlueprint == bp) { if (ActorBlueprintName == name) {
return; return;
} }
// Sanity check the blueprint. Nullptr is allowed. // Get the blueprint.
check(BlueprintIsTangible(bp)); // If the blueprint doesn't exist, or doesn't implement
// TangibleInterface, then use the fallback blueprint.
UClass *blueprint = Manager->GetTangibleClass(name);
if ((!name.IsEmpty()) && (blueprint == nullptr)) {
blueprint = Manager->GetTangibleClass(DEFAULT_BLUEPRINT);
check(blueprint != nullptr);
}
// If there's already an actor, delete it. // If there's already an actor, delete it.
if (CurrentActor != nullptr) { if (CurrentActor != nullptr) {
@@ -50,17 +53,17 @@ void UlxTangible::SetActorBlueprintClass(TSubclassOf<AActor> bp) {
CurrentActor->Destroy(); CurrentActor->Destroy();
} }
// Update the blueprint reference. // Update the blueprint name
ActorBlueprint = bp; ActorBlueprintName = name;
// Now create a new actor, unless the BP is nullptr. // Now create a new actor, unless the BP is nullptr.
if (ActorBlueprint != nullptr) { if (blueprint != nullptr) {
// Create the actor. // Create the actor.
FActorSpawnParameters params; FActorSpawnParameters params;
FVector location(0, 0, 0); FVector location(0, 0, 0);
FRotator rotation(0, 0, 0); FRotator rotation(0, 0, 0);
UWorld* w = Manager->GetWorld(); UWorld* w = Manager->GetWorld();
AActor* a = w->SpawnActor(ActorBlueprint, &location, &rotation, params); AActor* a = w->SpawnActor(blueprint, &location, &rotation, params);
// Insert a TangibleComponent into the actor. // Insert a TangibleComponent into the actor.
UActorComponent* ac = a->AddComponentByClass(UlxTangibleComponent::StaticClass(), false, FTransform::Identity, false); UActorComponent* ac = a->AddComponentByClass(UlxTangibleComponent::StaticClass(), false, FTransform::Identity, false);
@@ -80,6 +83,9 @@ void UlxTangible::UpdateAnimationQueue(std::string_view aq) {
if (limit == 0) break; if (limit == 0) break;
limit -= 1; limit -= 1;
AnimTracker.ClearChanged(); AnimTracker.ClearChanged();
FString blueprint = AnimTracker.GetCurrentBlueprintName();
if (blueprint.IsEmpty()) blueprint = DEFAULT_BLUEPRINT;
SetActorBlueprint(blueprint);
IlxTangibleInterface::Execute_AnimationStateChanged(GetActor()); IlxTangibleInterface::Execute_AnimationStateChanged(GetActor());
} }
} }
@@ -93,11 +99,11 @@ FVector UlxTangible::GetLocation() const {
} }
void UlxTangible::Destroy() { void UlxTangible::Destroy() {
SetActorBlueprintClass(nullptr); SetActorBlueprint("");
Manager = nullptr; Manager = nullptr;
TangibleId = -1; TangibleId = -1;
CurrentActor = nullptr; CurrentActor = nullptr;
ActorBlueprint = nullptr; ActorBlueprintName = "";
AnimTracker.Clear(); AnimTracker.Clear();
NearAccordingToLuprex = false; NearAccordingToLuprex = false;
NearAccordingToUnreal = false; NearAccordingToUnreal = false;

View File

@@ -76,9 +76,9 @@ public:
UPROPERTY() UPROPERTY()
TWeakObjectPtr<AActor> CurrentActor; TWeakObjectPtr<AActor> CurrentActor;
// The blueprint class of the actor. // The name of the current blueprint.
UPROPERTY() UPROPERTY()
TSubclassOf<AActor> ActorBlueprint; FString ActorBlueprintName;
// Animation tracker // Animation tracker
FlxAnimTracker AnimTracker; FlxAnimTracker AnimTracker;
@@ -128,26 +128,6 @@ public:
// //
FVector GetLocation() const; 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);
// 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);
// Update the animation queue from Luprex. // Update the animation queue from Luprex.
// //
// This reads the animation queue, and then based on // This reads the animation queue, and then based on
@@ -155,13 +135,18 @@ public:
// the Actor's TangibleInterface, calling methods such // the Actor's TangibleInterface, calling methods such
// as 'StartAnimation' and 'AbortAnimation' as necessary. // 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); void UpdateAnimationQueue(std::string_view aq);
private:
// Set the actor's blueprint, and recreate the actor if necessary.
//
// If the blueprint is the empty string, deletes the actor.
// If the blueprint is not the empty string, creates an actor of the
// correct class. This is a no-op if the actor already exists and
// is already of the correct blueprint class.
//
void SetActorBlueprint(const FString &name);
public: public:
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex) UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex)
static void GetCurrentAnimation(AActor *target, FlxAnimationStep &step); static void GetCurrentAnimation(AActor *target, FlxAnimationStep &step);

View File

@@ -9,10 +9,31 @@ using namespace DebugPrint;
using TanArray = UlxTangibleManager::TanArray; using TanArray = UlxTangibleManager::TanArray;
using IdArray = UlxTangibleManager::IdArray; using IdArray = UlxTangibleManager::IdArray;
UClass *UlxTangibleManager::GetTangibleClass(const FString &name) {
if (name.IsEmpty()) {
return nullptr;
}
FString path(TEXT("/Game/Tangibles/"));
path += name;
path += TCHAR('.');
path += name;
path += TCHAR('_');
path += TCHAR('C');
UClass *result = LoadObject<UClass>(nullptr, *path);
if (result != nullptr) {
if (!result->IsChildOf(AActor::StaticClass())) {
return nullptr;
}
if (!result->ImplementsInterface(UlxTangibleInterface::StaticClass())) {
return nullptr;
}
}
return result;
}
UlxTangibleManager::UlxTangibleManager() { UlxTangibleManager::UlxTangibleManager() {
World = nullptr; World = nullptr;
ClassTangibleStaticMesh = LoadObject<UClass>(nullptr, TEXT("/Game/Tangibles/TangibleStaticMesh.TangibleStaticMesh_C"));
check(ClassTangibleStaticMesh != nullptr);
} }
void UlxTangibleManager::Init(UWorld* world) { void UlxTangibleManager::Init(UWorld* world) {
@@ -34,11 +55,6 @@ UlxTangible* UlxTangibleManager::MakeTangible(int64 id) {
if (t == nullptr) { if (t == nullptr) {
t = NewObject<UlxTangible>(); t = NewObject<UlxTangible>();
t->Init(this, id); t->Init(this, id);
// TODO: fix this. The blueprint needs to be assigned
// during animation queue parsing, based on the animation
// queue keyword 'bp'.
t->SetActorBlueprintClass(ClassTangibleStaticMesh);
} }
return t; return t;
} }

View File

@@ -23,11 +23,6 @@ public:
UPROPERTY() UPROPERTY()
TWeakObjectPtr<UWorld> World; TWeakObjectPtr<UWorld> World;
// A pointer to uclass TangibleStaticMesh. This is the blueprint
// we use when all else fails.
UPROPERTY()
TSubclassOf<AActor> ClassTangibleStaticMesh;
// Given a tangible ID, look up the TangibleComponent of that actor. // Given a tangible ID, look up the TangibleComponent of that actor.
UPROPERTY() UPROPERTY()
TMap<int64, UlxTangible*> IdToTangible; TMap<int64, UlxTangible*> IdToTangible;
@@ -80,5 +75,9 @@ public:
// Given an array of tangibles, return an array of tangible Ids. // Given an array of tangibles, return an array of tangible Ids.
// //
static IdArray GetIds(const TanArray &tans); static IdArray GetIds(const TanArray &tans);
// Convert a blueprint name to a blueprint class.
//
UClass *GetTangibleClass(const FString &name);
}; };