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 result;
for (int i = 0; i < AQ.Num(); i++) {

View File

@@ -278,6 +278,10 @@ public:
//
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. This is the step that the

View File

@@ -4,12 +4,14 @@
#include "Tangible.h"
#include "TangibleManager.h"
#define DEFAULT_BLUEPRINT (TEXT("TangibleStaticMesh"))
UlxTangible::UlxTangible()
{
Manager = nullptr;
TangibleId = -1;
CurrentActor = nullptr;
ActorBlueprint = nullptr;
ActorBlueprintName = TEXT("");
NearAccordingToLuprex = false;
NearAccordingToUnreal = false;
}
@@ -20,19 +22,20 @@ void UlxTangible::Init(UlxTangibleManager* tm, int64 id)
TangibleId = id;
}
bool UlxTangible::BlueprintIsTangible(TSubclassOf<AActor> bp) {
if (bp == nullptr) return true;
return bp->ImplementsInterface(UlxTangibleInterface::StaticClass());
}
void UlxTangible::SetActorBlueprintClass(TSubclassOf<AActor> bp) {
void UlxTangible::SetActorBlueprint(const FString &name) {
// If we're already of the right class, do nothing.
if (ActorBlueprint == bp) {
if (ActorBlueprintName == name) {
return;
}
// Sanity check the blueprint. Nullptr is allowed.
check(BlueprintIsTangible(bp));
// Get the blueprint.
// 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 (CurrentActor != nullptr) {
@@ -50,17 +53,17 @@ void UlxTangible::SetActorBlueprintClass(TSubclassOf<AActor> bp) {
CurrentActor->Destroy();
}
// Update the blueprint reference.
ActorBlueprint = bp;
// Update the blueprint name
ActorBlueprintName = name;
// Now create a new actor, unless the BP is nullptr.
if (ActorBlueprint != nullptr) {
if (blueprint != 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);
AActor* a = w->SpawnActor(blueprint, &location, &rotation, params);
// Insert a TangibleComponent into the actor.
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;
limit -= 1;
AnimTracker.ClearChanged();
FString blueprint = AnimTracker.GetCurrentBlueprintName();
if (blueprint.IsEmpty()) blueprint = DEFAULT_BLUEPRINT;
SetActorBlueprint(blueprint);
IlxTangibleInterface::Execute_AnimationStateChanged(GetActor());
}
}
@@ -93,11 +99,11 @@ FVector UlxTangible::GetLocation() const {
}
void UlxTangible::Destroy() {
SetActorBlueprintClass(nullptr);
SetActorBlueprint("");
Manager = nullptr;
TangibleId = -1;
CurrentActor = nullptr;
ActorBlueprint = nullptr;
ActorBlueprintName = "";
AnimTracker.Clear();
NearAccordingToLuprex = false;
NearAccordingToUnreal = false;

View File

@@ -76,9 +76,9 @@ public:
UPROPERTY()
TWeakObjectPtr<AActor> CurrentActor;
// The blueprint class of the actor.
// The name of the current blueprint.
UPROPERTY()
TSubclassOf<AActor> ActorBlueprint;
FString ActorBlueprintName;
// Animation tracker
FlxAnimTracker AnimTracker;
@@ -128,26 +128,6 @@ public:
//
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.
//
// This reads the animation queue, and then based on
@@ -155,13 +135,18 @@ public:
// 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);
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:
UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex)
static void GetCurrentAnimation(AActor *target, FlxAnimationStep &step);

View File

@@ -9,10 +9,31 @@ using namespace DebugPrint;
using TanArray = UlxTangibleManager::TanArray;
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() {
World = nullptr;
ClassTangibleStaticMesh = LoadObject<UClass>(nullptr, TEXT("/Game/Tangibles/TangibleStaticMesh.TangibleStaticMesh_C"));
check(ClassTangibleStaticMesh != nullptr);
}
void UlxTangibleManager::Init(UWorld* world) {
@@ -34,11 +55,6 @@ UlxTangible* UlxTangibleManager::MakeTangible(int64 id) {
if (t == nullptr) {
t = NewObject<UlxTangible>();
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;
}

View File

@@ -23,11 +23,6 @@ public:
UPROPERTY()
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.
UPROPERTY()
TMap<int64, UlxTangible*> IdToTangible;
@@ -80,5 +75,9 @@ public:
// Given an array of tangibles, return an array of tangible Ids.
//
static IdArray GetIds(const TanArray &tans);
// Convert a blueprint name to a blueprint class.
//
UClass *GetTangibleClass(const FString &name);
};