From 982b6cab625346fc4e5033416268cbe47cc589b1 Mon Sep 17 00:00:00 2001 From: teppy999 Date: Wed, 20 Sep 2023 14:32:55 -0400 Subject: [PATCH 01/19] Wrote blueprints to set facing,xyz,model --- Content/MeshStruct.uasset | 3 +++ Content/NameToMeshTable.uasset | 3 +++ Content/TangibleActor.uasset | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 Content/MeshStruct.uasset create mode 100644 Content/NameToMeshTable.uasset diff --git a/Content/MeshStruct.uasset b/Content/MeshStruct.uasset new file mode 100644 index 00000000..201f8829 --- /dev/null +++ b/Content/MeshStruct.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4da1df1663ba609d6eb11c11579b145d91974724b22e07e48d254538c7b4025 +size 3822 diff --git a/Content/NameToMeshTable.uasset b/Content/NameToMeshTable.uasset new file mode 100644 index 00000000..28c6409f --- /dev/null +++ b/Content/NameToMeshTable.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d249735bd7d209a398b187c4ef754ce075af5e308b583fa2a9da9a39e428aa6f +size 2726 diff --git a/Content/TangibleActor.uasset b/Content/TangibleActor.uasset index d3ef1772..84081bce 100644 --- a/Content/TangibleActor.uasset +++ b/Content/TangibleActor.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f55b8b1967273b907cccf5f44a780d091c4bacba418c4d371192c4d0709e07c5 -size 82316 +oid sha256:cb67f71a0d3b103417566d3386575bf84b4819ef2c1589792812dfcc2499fb35 +size 140290 From 2f5baf2e9ff78455be3bf03e1660f386189dfa32 Mon Sep 17 00:00:00 2001 From: teppy999 Date: Mon, 25 Sep 2023 14:25:24 -0400 Subject: [PATCH 02/19] Make TangibleManager a UObject --- Content/TangibleActor.uasset | 4 ++-- Source/Integration/AnimQueue.cpp | 2 +- Source/Integration/AnimQueue.h | 5 ----- .../Integration/IntegrationGameModeBase.cpp | 21 ++++++++++++------- Source/Integration/IntegrationGameModeBase.h | 2 +- Source/Integration/Tangible.h | 6 ++++-- Source/Integration/TangibleManager.cpp | 14 ++++++------- Source/Integration/TangibleManager.h | 7 ++++--- 8 files changed, 33 insertions(+), 28 deletions(-) diff --git a/Content/TangibleActor.uasset b/Content/TangibleActor.uasset index 84081bce..4f16996b 100644 --- a/Content/TangibleActor.uasset +++ b/Content/TangibleActor.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cb67f71a0d3b103417566d3386575bf84b4819ef2c1589792812dfcc2499fb35 -size 140290 +oid sha256:1c38181c8e0c13615ed114567f6afa150dc6f06f49f7aefc66629b624d5f2834 +size 140308 diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index 28983a7a..a0b8d060 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -42,7 +42,7 @@ static bool SetProperty(const FString& name, UObject* obj, const FlxAnimationFie FDoubleProperty* fprop = FindFProperty(uclass, nname); if (fprop == nullptr) return false; double* pptr = fprop->ContainerPtrToValuePtr(obj); - fprop->SetPropertyValue(pptr, field.X); + *pptr = field.X; return true; } case ElxAnimValueType::BOOLEAN: { diff --git a/Source/Integration/AnimQueue.h b/Source/Integration/AnimQueue.h index 3673796c..0d9bb512 100644 --- a/Source/Integration/AnimQueue.h +++ b/Source/Integration/AnimQueue.h @@ -129,18 +129,13 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex) static bool AnimationStepGetBool(const FlxAnimationStep& step, const FString& name); - }; //////////////////////////////////////////////// // -// Exposing functions to blueprints. // //////////////////////////////////////////////// -//UFUNCTION(BlueprintCallable) -//void Unpack(const FString& prefix, UObject* into, bool preclear = true); - struct FlxAnimationStepView { uint64 Hash; std::string_view Body; diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index 2f6dfb69..cab1292e 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -16,6 +16,7 @@ using namespace CommonTypes; AIntegrationGameModeBase::AIntegrationGameModeBase() { + TangibleManager = NewObject(); EngineSeconds = 0.0; NextThreadTrigger = 1.0; //PrimaryActorTick.bCanEverTick = true; // Probably wrong @@ -47,6 +48,11 @@ void AIntegrationGameModeBase::ResetToInitialState() { Playing = false; + if (TangibleManager != nullptr) { + TangibleManager->ConditionalBeginDestroy(); + TangibleManager = nullptr; + } + // Shut down the thread LuprexUpdateTask.Shutdown(); @@ -117,18 +123,18 @@ void AIntegrationGameModeBase::UpdateTangibles() { if (!Playing) return; FlxLockedWrapper w(LockableWrapper); int64 actor = w.GetActor(); - TangibleManager.SetActor(actor); - TangibleManager.SetNear(w.GetNear(actor, 100, 100, 100)); - for (int64 id : TangibleManager.GetNear()) { - TangibleManager.MakeTangible(id); + TangibleManager->SetActor(actor); + TangibleManager->SetNear(w.GetNear(actor, 100, 100, 100)); + for (int64 id : TangibleManager->GetNear()) { + TangibleManager->MakeTangible(id); } // Update animation queues of live tangibles. - IdArray tanids = TangibleManager.GetLive(); + IdArray tanids = TangibleManager->GetLive(); StringViewVec aqueues = w.GetAnimationQueues(tanids); for (int i = 0; i < tanids.Num(); i++) { uint64_t tanid = tanids[i]; std::string_view aqueue = aqueues[i]; - UlxTangible* t = TangibleManager.GetTangible(tanid); + UlxTangible* t = TangibleManager->GetTangible(tanid); check(t != nullptr); t->AnimTracker.Update(aqueue); @@ -237,7 +243,8 @@ void AIntegrationGameModeBase::BeginPlay() } // Initialize the tangible manager. - TangibleManager.Init(GetWorld(), ClassTangibleActor); + TangibleManager = NewObject(); + TangibleManager->Init(GetWorld(), ClassTangibleActor); } void AIntegrationGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason) diff --git a/Source/Integration/IntegrationGameModeBase.h b/Source/Integration/IntegrationGameModeBase.h index fa72e6ad..b6ec9d0f 100644 --- a/Source/Integration/IntegrationGameModeBase.h +++ b/Source/Integration/IntegrationGameModeBase.h @@ -57,7 +57,7 @@ public: virtual uint32 Run() override; UPROPERTY() - FTangibleManager TangibleManager; + UTangibleManager *TangibleManager; // This stores the entire text currently visible in the console. FlxConsoleOutput ConsoleOutput; diff --git a/Source/Integration/Tangible.h b/Source/Integration/Tangible.h index 84f0686f..590d03b8 100644 --- a/Source/Integration/Tangible.h +++ b/Source/Integration/Tangible.h @@ -22,8 +22,10 @@ public: FlxAnimTracker AnimTracker; - void Init(AActor* a) { + FString Plane; + + void Init(AActor* a, const FString &plane) { Actor = a; + Plane = plane; } }; - diff --git a/Source/Integration/TangibleManager.cpp b/Source/Integration/TangibleManager.cpp index 046d42c7..06a07c18 100644 --- a/Source/Integration/TangibleManager.cpp +++ b/Source/Integration/TangibleManager.cpp @@ -7,21 +7,21 @@ using namespace DebugPrint; -FTangibleManager::FTangibleManager() { +UTangibleManager::UTangibleManager() { World = nullptr; ClassTangibleActor = nullptr; Actor = 0; Near = IdView(); } -void FTangibleManager::Init(UWorld *world, UClass* tanact) { +void UTangibleManager::Init(UWorld *world, UClass* tanact) { World = world; ClassTangibleActor = tanact; Actor = 0; Near = IdView(); } -UlxTangible *FTangibleManager::GetTangible(int64 id) { +UlxTangible *UTangibleManager::GetTangible(int64 id) { UlxTangible **p = IdToTangible.Find(id); if (p == nullptr) { return nullptr; @@ -30,7 +30,7 @@ UlxTangible *FTangibleManager::GetTangible(int64 id) { } } -UlxTangible *FTangibleManager::MakeTangible(int64 id) { +UlxTangible *UTangibleManager::MakeTangible(int64 id) { UlxTangible *& p = IdToTangible.FindOrAdd(id); if (p == nullptr) { FVector location(0,0,0); @@ -40,16 +40,16 @@ UlxTangible *FTangibleManager::MakeTangible(int64 id) { check(a != nullptr); check(a->GetClass()->ImplementsInterface(UlxTangibleInterface::StaticClass())); p = NewObject(); - p->Init(a); + p->Init(a, TEXT("")); } return p; } -void FTangibleManager::DeleteTangible(int64 id) { +void UTangibleManager::DeleteTangible(int64 id) { // IMPLEMENT ME } -FTangibleManager::IdArray FTangibleManager::GetLive() { +UTangibleManager::IdArray UTangibleManager::GetLive() { IdArray result; result.SetNum(IdToTangible.Num()); int next = 0; diff --git a/Source/Integration/TangibleManager.h b/Source/Integration/TangibleManager.h index 9a4e1a06..60f305b5 100644 --- a/Source/Integration/TangibleManager.h +++ b/Source/Integration/TangibleManager.h @@ -8,10 +8,11 @@ #include "Tangible.h" #include "TangibleManager.generated.h" -USTRUCT() -struct INTEGRATION_API FTangibleManager +UCLASS() +class INTEGRATION_API UTangibleManager : public UObject { GENERATED_BODY() + public: // Import these types into our Namespace. using IdArray = CommonTypes::IdArray; @@ -35,7 +36,7 @@ public: IdView Near; public: - FTangibleManager(); + UTangibleManager(); // Initialize the tangible manager. // From 254524aab68c68e85cbb1007fa3d2d5d18e52066 Mon Sep 17 00:00:00 2001 From: teppy999 Date: Mon, 25 Sep 2023 18:00:34 -0400 Subject: [PATCH 03/19] Move tangible state into TangibleComponent --- .../Integration/IntegrationGameModeBase.cpp | 30 +++++++--- Source/Integration/IntegrationGameState.h | 7 +++ Source/Integration/SampleActorComponent.cpp | 34 +++++++++++ Source/Integration/SampleActorComponent.h | 28 ++++++++++ Source/Integration/Tangible.cpp | 5 -- Source/Integration/Tangible.h | 31 ---------- Source/Integration/TangibleComponent.cpp | 16 ++++++ Source/Integration/TangibleComponent.h | 56 +++++++++++++++++++ Source/Integration/TangibleInterface.h | 2 + Source/Integration/TangibleManager.cpp | 46 +++++++++------ Source/Integration/TangibleManager.h | 28 ++++++---- 11 files changed, 211 insertions(+), 72 deletions(-) create mode 100644 Source/Integration/IntegrationGameState.h create mode 100644 Source/Integration/SampleActorComponent.cpp create mode 100644 Source/Integration/SampleActorComponent.h delete mode 100644 Source/Integration/Tangible.cpp delete mode 100644 Source/Integration/Tangible.h create mode 100644 Source/Integration/TangibleComponent.cpp create mode 100644 Source/Integration/TangibleComponent.h diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index cab1292e..51dc3a63 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -3,11 +3,12 @@ #include "IntegrationGameModeBase.h" #include "lpx-drvutil.hpp" #include "DebugPrint.h" -#include "Tangible.h" +#include "TangibleComponent.h" #include "TangibleManager.h" #include "TangibleInterface.h" #include "CommonTypes.h" #include "AnimQueue.h" +#include "IntegrationGameState.h" #include #include @@ -119,11 +120,13 @@ void AIntegrationGameModeBase::MaybeTriggerUpdateTask(float deltaseconds) { // FStructProperty* sprop = FindFProperty(uclass, nname); //} +#pragma optimize("", off) + void AIntegrationGameModeBase::UpdateTangibles() { if (!Playing) return; FlxLockedWrapper w(LockableWrapper); int64 actor = w.GetActor(); - TangibleManager->SetActor(actor); + TangibleManager->SetPlayer(actor); TangibleManager->SetNear(w.GetNear(actor, 100, 100, 100)); for (int64 id : TangibleManager->GetNear()) { TangibleManager->MakeTangible(id); @@ -133,19 +136,16 @@ void AIntegrationGameModeBase::UpdateTangibles() { StringViewVec aqueues = w.GetAnimationQueues(tanids); for (int i = 0; i < tanids.Num(); i++) { uint64_t tanid = tanids[i]; - std::string_view aqueue = aqueues[i]; - UlxTangible* t = TangibleManager->GetTangible(tanid); - check(t != nullptr); - t->AnimTracker.Update(aqueue); - + UTangibleComponent *t = TangibleManager->GetTangible(tanid); + t->AnimTracker.Update(aqueues[i]); TArray aborted = t->AnimTracker.GetAborted(); for (uint64 hash : aborted) { - IlxTangibleInterface::Execute_AbortAnimation(t->Actor, hash); + IlxTangibleInterface::Execute_AbortAnimation(t->GetActor(), hash); } FlxAnimationStep step; ElxAnimationMode mode = t->AnimTracker.GetNextStep(step); if (mode != ElxAnimationMode::INVALID) { - bool started = IlxTangibleInterface::Execute_StartAnimation(t->Actor, mode, step); + bool started = IlxTangibleInterface::Execute_StartAnimation(t->GetActor(), mode, step); if (started) { t->AnimTracker.StartedStep(step.Hash); } @@ -252,4 +252,16 @@ void AIntegrationGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason) ResetToInitialState(); } +namespace IntegrationGameState { + UTangibleManager* GetTangibleManager(AActor *actor) { + AGameModeBase* gmb = actor->GetWorld()->GetAuthGameMode(); + AIntegrationGameModeBase* igmb = Cast(gmb); + if (igmb == nullptr) { + return nullptr; + } else { + return igmb->TangibleManager; + } + } + +} // namespace IntegrationGameState diff --git a/Source/Integration/IntegrationGameState.h b/Source/Integration/IntegrationGameState.h new file mode 100644 index 00000000..467cb881 --- /dev/null +++ b/Source/Integration/IntegrationGameState.h @@ -0,0 +1,7 @@ + +class UTangibleManager; + +namespace IntegrationGameState { + UTangibleManager* GetTangibleManager(AActor *actor); +} + diff --git a/Source/Integration/SampleActorComponent.cpp b/Source/Integration/SampleActorComponent.cpp new file mode 100644 index 00000000..b5142a32 --- /dev/null +++ b/Source/Integration/SampleActorComponent.cpp @@ -0,0 +1,34 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "SampleActorComponent.h" + +// Sets default values for this component's properties +USampleActorComponent::USampleActorComponent() +{ + // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features + // off to improve performance if you don't need them. + PrimaryComponentTick.bCanEverTick = true; + + // ... +} + + +// Called when the game starts +void USampleActorComponent::BeginPlay() +{ + Super::BeginPlay(); + + // ... + +} + + +// Called every frame +void USampleActorComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + // ... +} + diff --git a/Source/Integration/SampleActorComponent.h b/Source/Integration/SampleActorComponent.h new file mode 100644 index 00000000..fe00ca06 --- /dev/null +++ b/Source/Integration/SampleActorComponent.h @@ -0,0 +1,28 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/ActorComponent.h" +#include "SampleActorComponent.generated.h" + + +UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) +class INTEGRATION_API USampleActorComponent : public UActorComponent +{ + GENERATED_BODY() + +public: + // Sets default values for this component's properties + USampleActorComponent(); + +protected: + // Called when the game starts + virtual void BeginPlay() override; + +public: + // Called every frame + virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + + +}; diff --git a/Source/Integration/Tangible.cpp b/Source/Integration/Tangible.cpp deleted file mode 100644 index 094c20c7..00000000 --- a/Source/Integration/Tangible.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - - -#include "Tangible.h" - diff --git a/Source/Integration/Tangible.h b/Source/Integration/Tangible.h deleted file mode 100644 index 590d03b8..00000000 --- a/Source/Integration/Tangible.h +++ /dev/null @@ -1,31 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/NoExportTypes.h" -#include "AnimQueue.h" -#include "TangibleInterface.h" -#include "Tangible.generated.h" - -/** - * - */ -UCLASS() -class INTEGRATION_API UlxTangible : public UObject -{ - GENERATED_BODY() - -public: - UPROPERTY() - AActor* Actor; - - FlxAnimTracker AnimTracker; - - FString Plane; - - void Init(AActor* a, const FString &plane) { - Actor = a; - Plane = plane; - } -}; diff --git a/Source/Integration/TangibleComponent.cpp b/Source/Integration/TangibleComponent.cpp new file mode 100644 index 00000000..8a4f9210 --- /dev/null +++ b/Source/Integration/TangibleComponent.cpp @@ -0,0 +1,16 @@ +// 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; + Actor = a; + TangibleId = id; +} diff --git a/Source/Integration/TangibleComponent.h b/Source/Integration/TangibleComponent.h new file mode 100644 index 00000000..4a0a432d --- /dev/null +++ b/Source/Integration/TangibleComponent.h @@ -0,0 +1,56 @@ +// 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 Actor; + + // Our tangible Manager. + UPROPERTY() + TWeakObjectPtr TangibleManager; + + // Animation tracker + FlxAnimTracker AnimTracker; + + // Current Plane. + FString Plane; + + void Init(UTangibleManager* tm, AActor* a, int64 id); + + AActor* GetActor() const { return Actor.Get(); } +}; diff --git a/Source/Integration/TangibleInterface.h b/Source/Integration/TangibleInterface.h index 89f9c4e7..37a7f7cf 100644 --- a/Source/Integration/TangibleInterface.h +++ b/Source/Integration/TangibleInterface.h @@ -29,3 +29,5 @@ public: UFUNCTION(BlueprintImplementableEvent, Category = "Tangible Functionality") bool AbortAnimation(int64 hash); }; + + diff --git a/Source/Integration/TangibleManager.cpp b/Source/Integration/TangibleManager.cpp index 06a07c18..c98d58e3 100644 --- a/Source/Integration/TangibleManager.cpp +++ b/Source/Integration/TangibleManager.cpp @@ -3,6 +3,8 @@ #include "TangibleManager.h" #include "TangibleInterface.h" +#include "IntegrationGameState.h" +#include "TangibleComponent.h" #include "DebugPrint.h" using namespace DebugPrint; @@ -10,39 +12,51 @@ using namespace DebugPrint; UTangibleManager::UTangibleManager() { World = nullptr; ClassTangibleActor = nullptr; - Actor = 0; + Player = 0; Near = IdView(); } void UTangibleManager::Init(UWorld *world, UClass* tanact) { World = world; ClassTangibleActor = tanact; - Actor = 0; + Player = 0; Near = IdView(); } -UlxTangible *UTangibleManager::GetTangible(int64 id) { - UlxTangible **p = IdToTangible.Find(id); +UTangibleComponent *UTangibleManager::GetTangible(int64 id) { + AActor **p = IdToActor.Find(id); if (p == nullptr) { return nullptr; } else { - return *p; + AActor* a = *p; + UTangibleComponent* comp = a->FindComponentByClass(); + check(comp != nullptr); + return comp; } } -UlxTangible *UTangibleManager::MakeTangible(int64 id) { - UlxTangible *& p = IdToTangible.FindOrAdd(id); +UTangibleComponent *UTangibleManager::MakeTangible(int64 id) { + AActor *& p = IdToActor.FindOrAdd(id); if (p == nullptr) { - FVector location(0,0,0); - FRotator rotation(0, 0, 0); FActorSpawnParameters params; - AActor* a = World->SpawnActor(ClassTangibleActor, &location, &rotation, params); + FVector location(0, 0, 0); + FRotator rotation(0, 0, 0); + UWorld* w = GetWorld(); + AActor* a = w->SpawnActor(ClassTangibleActor, &location, &rotation, params); check(a != nullptr); check(a->GetClass()->ImplementsInterface(UlxTangibleInterface::StaticClass())); - p = NewObject(); - p->Init(a, TEXT("")); + // Insert a TangibleComponent into the actor. + UActorComponent* ac = a->AddComponentByClass(UTangibleComponent::StaticClass(), false, FTransform::Identity, false); + UTangibleComponent* tc = Cast(ac); + check(tc != nullptr); + tc->Init(this, a, id); + p = a; + return tc; + } else { + UTangibleComponent* comp = p->FindComponentByClass(); + check(comp != nullptr); + return comp; } - return p; } void UTangibleManager::DeleteTangible(int64 id) { @@ -51,10 +65,10 @@ void UTangibleManager::DeleteTangible(int64 id) { UTangibleManager::IdArray UTangibleManager::GetLive() { IdArray result; - result.SetNum(IdToTangible.Num()); + result.SetNum(IdToActor.Num()); int next = 0; - for (auto &pair : IdToTangible) { + for (auto &pair : IdToActor) { result[next++] = pair.Key; } return result; -} \ No newline at end of file +} diff --git a/Source/Integration/TangibleManager.h b/Source/Integration/TangibleManager.h index 60f305b5..7e77b565 100644 --- a/Source/Integration/TangibleManager.h +++ b/Source/Integration/TangibleManager.h @@ -5,7 +5,7 @@ #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "CommonTypes.h" -#include "Tangible.h" +#include "TangibleComponent.h" #include "TangibleManager.generated.h" UCLASS() @@ -18,19 +18,21 @@ public: using IdArray = CommonTypes::IdArray; using IdView = CommonTypes::IdView; - // A pointer to the UWorld. - UWorld* World; + // A pointer to our world. + UPROPERTY() + TWeakObjectPtr World; - // A pointer to uclass TangibleActor. + // A pointer to uclass TangibleActor. This is the class + // of actors that we create (for now). UPROPERTY() TSubclassOf ClassTangibleActor; // Given a tangible ID, look up actor pointer (or NULL if actor was deleted) UPROPERTY() - TMap IdToTangible; + TMap IdToActor; - // Actor tangible Id. - int64 Actor; + // Player's tangible Id. + int64 Player; // Tangibles near the actor. IdView Near; @@ -42,19 +44,23 @@ public: // void Init(UWorld *world, UClass* tanact); + // Get a pointer to our world. + // + UWorld* GetWorld() const override { return World.Get(); } + // Get the tangible if it exists, otherwise return NULL - UlxTangible* GetTangible(int64 id); + UTangibleComponent* GetTangible(int64 id); // Get the tangible if it exists, otherwise create it. - UlxTangible* MakeTangible(int64 id); + UTangibleComponent* MakeTangible(int64 id); // Delete the tangible. void DeleteTangible(int64 id); // Get/Set the Id of the actor. // - int64 GetActor() const { return Actor; }; - void SetActor(int64 id) { Actor = id; } + int64 GetPlayer() const { return Player; }; + void SetPlayer(int64 id) { Player = id; } // Get/Set the list of tangibles near the player, according to Luprex. // From cc6509a69c73091a1dbbc12eb6de1560c1c3ff9f Mon Sep 17 00:00:00 2001 From: teppy999 Date: Mon, 25 Sep 2023 18:32:05 -0400 Subject: [PATCH 04/19] Implement 'Set Tangible Plane' --- Content/TangibleActor.uasset | 4 ++-- Source/Integration/TangibleComponent.cpp | 15 ++++++++++++++- Source/Integration/TangibleComponent.h | 12 ++++++++++-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/Content/TangibleActor.uasset b/Content/TangibleActor.uasset index 4f16996b..80484671 100644 --- a/Content/TangibleActor.uasset +++ b/Content/TangibleActor.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1c38181c8e0c13615ed114567f6afa150dc6f06f49f7aefc66629b624d5f2834 -size 140308 +oid sha256:84fc90f15eb6e91880d390067a96949e0bd7990a8f90bb469049ddc505a07926 +size 142745 diff --git a/Source/Integration/TangibleComponent.cpp b/Source/Integration/TangibleComponent.cpp index 8a4f9210..c6b70c6b 100644 --- a/Source/Integration/TangibleComponent.cpp +++ b/Source/Integration/TangibleComponent.cpp @@ -11,6 +11,19 @@ UTangibleComponent::UTangibleComponent() void UTangibleComponent::Init(UTangibleManager* tm, AActor* a, int64 id) { TangibleManager = tm; - Actor = a; + OwningActor = a; TangibleId = id; } + +FString UTangibleComponent::GetTangiblePlane(AActor* actor) { + UTangibleComponent* comp = actor->GetComponentByClass(); + check(comp != nullptr); + return comp->Plane; +} + +void UTangibleComponent::SetTangiblePlane(AActor* actor, const FString& plane) { + UTangibleComponent* comp = actor->GetComponentByClass(); + check(comp != nullptr); + comp->Plane = plane; +} + diff --git a/Source/Integration/TangibleComponent.h b/Source/Integration/TangibleComponent.h index 4a0a432d..c2bfd6d1 100644 --- a/Source/Integration/TangibleComponent.h +++ b/Source/Integration/TangibleComponent.h @@ -38,7 +38,7 @@ public: // The actor that we're a part of. UPROPERTY() - TWeakObjectPtr Actor; + TWeakObjectPtr OwningActor; // Our tangible Manager. UPROPERTY() @@ -50,7 +50,15 @@ public: // Current Plane. FString Plane; +public: void Init(UTangibleManager* tm, AActor* a, int64 id); - AActor* GetActor() const { return Actor.Get(); } + 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); }; From 0efd0dd3ad3e16ca2b312f7324e8b970b4739b84 Mon Sep 17 00:00:00 2001 From: teppy999 Date: Tue, 26 Sep 2023 17:00:30 -0400 Subject: [PATCH 05/19] Class Tangible can now recreate its Actor --- Content/TangibleActor.uasset | 4 +- .../Integration/IntegrationGameModeBase.cpp | 28 +--- Source/Integration/IntegrationGameModeBase.h | 2 +- Source/Integration/IntegrationGameState.h | 7 - Source/Integration/Tangible.cpp | 81 ++++++++++ Source/Integration/Tangible.h | 139 ++++++++++++++++++ Source/Integration/TangibleComponent.cpp | 29 ---- Source/Integration/TangibleComponent.h | 64 -------- Source/Integration/TangibleInterface.cpp | 6 - Source/Integration/TangibleInterface.h | 33 ----- Source/Integration/TangibleManager.cpp | 61 +++----- Source/Integration/TangibleManager.h | 14 +- 12 files changed, 261 insertions(+), 207 deletions(-) delete mode 100644 Source/Integration/IntegrationGameState.h create mode 100644 Source/Integration/Tangible.cpp create mode 100644 Source/Integration/Tangible.h delete mode 100644 Source/Integration/TangibleComponent.cpp delete mode 100644 Source/Integration/TangibleComponent.h delete mode 100644 Source/Integration/TangibleInterface.cpp delete mode 100644 Source/Integration/TangibleInterface.h diff --git a/Content/TangibleActor.uasset b/Content/TangibleActor.uasset index 80484671..a13f4cdd 100644 --- a/Content/TangibleActor.uasset +++ b/Content/TangibleActor.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84fc90f15eb6e91880d390067a96949e0bd7990a8f90bb469049ddc505a07926 -size 142745 +oid sha256:05b62c5757100adf5d29b718f75d9f540e11267ca0aa8e03cd33d2676fea9b91 +size 142754 diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index 51dc3a63..04dfc472 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -3,12 +3,10 @@ #include "IntegrationGameModeBase.h" #include "lpx-drvutil.hpp" #include "DebugPrint.h" -#include "TangibleComponent.h" +#include "Tangible.h" #include "TangibleManager.h" -#include "TangibleInterface.h" #include "CommonTypes.h" #include "AnimQueue.h" -#include "IntegrationGameState.h" #include #include @@ -17,7 +15,7 @@ using namespace CommonTypes; AIntegrationGameModeBase::AIntegrationGameModeBase() { - TangibleManager = NewObject(); + TangibleManager = NewObject(); EngineSeconds = 0.0; NextThreadTrigger = 1.0; //PrimaryActorTick.bCanEverTick = true; // Probably wrong @@ -127,8 +125,9 @@ void AIntegrationGameModeBase::UpdateTangibles() { FlxLockedWrapper w(LockableWrapper); int64 actor = w.GetActor(); TangibleManager->SetPlayer(actor); - TangibleManager->SetNear(w.GetNear(actor, 100, 100, 100)); - for (int64 id : TangibleManager->GetNear()) { + IdView near = w.GetNear(actor, 100, 100, 100); + TangibleManager->SetNear(near); + for (int64 id : near) { TangibleManager->MakeTangible(id); } // Update animation queues of live tangibles. @@ -136,7 +135,7 @@ void AIntegrationGameModeBase::UpdateTangibles() { StringViewVec aqueues = w.GetAnimationQueues(tanids); for (int i = 0; i < tanids.Num(); i++) { uint64_t tanid = tanids[i]; - UTangibleComponent *t = TangibleManager->GetTangible(tanid); + UlxTangible *t = TangibleManager->GetTangible(tanid); t->AnimTracker.Update(aqueues[i]); TArray aborted = t->AnimTracker.GetAborted(); for (uint64 hash : aborted) { @@ -243,7 +242,7 @@ void AIntegrationGameModeBase::BeginPlay() } // Initialize the tangible manager. - TangibleManager = NewObject(); + TangibleManager = NewObject(); TangibleManager->Init(GetWorld(), ClassTangibleActor); } @@ -252,16 +251,3 @@ void AIntegrationGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason) ResetToInitialState(); } -namespace IntegrationGameState { - - UTangibleManager* GetTangibleManager(AActor *actor) { - AGameModeBase* gmb = actor->GetWorld()->GetAuthGameMode(); - AIntegrationGameModeBase* igmb = Cast(gmb); - if (igmb == nullptr) { - return nullptr; - } else { - return igmb->TangibleManager; - } - } - -} // namespace IntegrationGameState diff --git a/Source/Integration/IntegrationGameModeBase.h b/Source/Integration/IntegrationGameModeBase.h index b6ec9d0f..da155315 100644 --- a/Source/Integration/IntegrationGameModeBase.h +++ b/Source/Integration/IntegrationGameModeBase.h @@ -57,7 +57,7 @@ public: virtual uint32 Run() override; UPROPERTY() - UTangibleManager *TangibleManager; + UlxTangibleManager *TangibleManager; // This stores the entire text currently visible in the console. FlxConsoleOutput ConsoleOutput; diff --git a/Source/Integration/IntegrationGameState.h b/Source/Integration/IntegrationGameState.h deleted file mode 100644 index 467cb881..00000000 --- a/Source/Integration/IntegrationGameState.h +++ /dev/null @@ -1,7 +0,0 @@ - -class UTangibleManager; - -namespace IntegrationGameState { - UTangibleManager* GetTangibleManager(AActor *actor); -} - diff --git a/Source/Integration/Tangible.cpp b/Source/Integration/Tangible.cpp new file mode 100644 index 00000000..c12838c9 --- /dev/null +++ b/Source/Integration/Tangible.cpp @@ -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 bp) { + if (bp == nullptr) return true; + return bp->ImplementsInterface(UlxTangibleInterface::StaticClass()); +} + +void UlxTangible::SetActorBlueprintClass(TSubclassOf 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(); + 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(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(); + check(comp != nullptr); + return comp->Tangible->Plane; +} + +void UlxTangible::SetTangiblePlane(AActor* actor, const FString& plane) { + UlxTangibleComponent* comp = actor->GetComponentByClass(); + check(comp != nullptr); + comp->Tangible->Plane = plane; +} + diff --git a/Source/Integration/Tangible.h b/Source/Integration/Tangible.h new file mode 100644 index 00000000..5d5d4cbe --- /dev/null +++ b/Source/Integration/Tangible.h @@ -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 Manager; + + // The tangible ID. + UPROPERTY() + uint64 TangibleId; + + UPROPERTY() + TWeakObjectPtr CurrentActor; + + // The blueprint class of the actor. + UPROPERTY() + TSubclassOf 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 bp); + + void SetActorBlueprintClass(TSubclassOf 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 Tangible; +}; diff --git a/Source/Integration/TangibleComponent.cpp b/Source/Integration/TangibleComponent.cpp deleted file mode 100644 index c6b70c6b..00000000 --- a/Source/Integration/TangibleComponent.cpp +++ /dev/null @@ -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(); - check(comp != nullptr); - return comp->Plane; -} - -void UTangibleComponent::SetTangiblePlane(AActor* actor, const FString& plane) { - UTangibleComponent* comp = actor->GetComponentByClass(); - check(comp != nullptr); - comp->Plane = plane; -} - diff --git a/Source/Integration/TangibleComponent.h b/Source/Integration/TangibleComponent.h deleted file mode 100644 index c2bfd6d1..00000000 --- a/Source/Integration/TangibleComponent.h +++ /dev/null @@ -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 OwningActor; - - // Our tangible Manager. - UPROPERTY() - TWeakObjectPtr 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); -}; diff --git a/Source/Integration/TangibleInterface.cpp b/Source/Integration/TangibleInterface.cpp deleted file mode 100644 index ae86e205..00000000 --- a/Source/Integration/TangibleInterface.cpp +++ /dev/null @@ -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. diff --git a/Source/Integration/TangibleInterface.h b/Source/Integration/TangibleInterface.h deleted file mode 100644 index 37a7f7cf..00000000 --- a/Source/Integration/TangibleInterface.h +++ /dev/null @@ -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); -}; - - diff --git a/Source/Integration/TangibleManager.cpp b/Source/Integration/TangibleManager.cpp index c98d58e3..30c4ff1e 100644 --- a/Source/Integration/TangibleManager.cpp +++ b/Source/Integration/TangibleManager.cpp @@ -2,73 +2,60 @@ #include "TangibleManager.h" -#include "TangibleInterface.h" -#include "IntegrationGameState.h" -#include "TangibleComponent.h" +#include "Tangible.h" #include "DebugPrint.h" using namespace DebugPrint; -UTangibleManager::UTangibleManager() { +UlxTangibleManager::UlxTangibleManager() { World = nullptr; ClassTangibleActor = nullptr; Player = 0; Near = IdView(); } -void UTangibleManager::Init(UWorld *world, UClass* tanact) { +void UlxTangibleManager::Init(UWorld* world, UClass* tanact) { World = world; ClassTangibleActor = tanact; Player = 0; Near = IdView(); } -UTangibleComponent *UTangibleManager::GetTangible(int64 id) { - AActor **p = IdToActor.Find(id); +UlxTangible* UlxTangibleManager::GetTangible(int64 id) { + UlxTangible** p = IdToTangible.Find(id); if (p == nullptr) { return nullptr; - } else { - AActor* a = *p; - UTangibleComponent* comp = a->FindComponentByClass(); - check(comp != nullptr); - return comp; + } + else { + return *p; } } -UTangibleComponent *UTangibleManager::MakeTangible(int64 id) { - AActor *& p = IdToActor.FindOrAdd(id); - if (p == nullptr) { - FActorSpawnParameters params; - FVector location(0, 0, 0); - FRotator rotation(0, 0, 0); - UWorld* w = GetWorld(); - AActor* a = w->SpawnActor(ClassTangibleActor, &location, &rotation, params); - check(a != nullptr); - check(a->GetClass()->ImplementsInterface(UlxTangibleInterface::StaticClass())); - // Insert a TangibleComponent into the actor. - UActorComponent* ac = a->AddComponentByClass(UTangibleComponent::StaticClass(), false, FTransform::Identity, false); - UTangibleComponent* tc = Cast(ac); - check(tc != nullptr); - tc->Init(this, a, id); - p = a; - return tc; - } else { - UTangibleComponent* comp = p->FindComponentByClass(); - check(comp != nullptr); - return comp; +UlxTangible* UlxTangibleManager::MakeTangible(int64 id) { + UlxTangible*& t = IdToTangible.FindOrAdd(id); + if (t == nullptr) { + t = NewObject(); + 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(ClassTangibleActor); } + return t; } -void UTangibleManager::DeleteTangible(int64 id) { +void UlxTangibleManager::DeleteTangible(int64 id) { // IMPLEMENT ME } -UTangibleManager::IdArray UTangibleManager::GetLive() { +UlxTangibleManager::IdArray UlxTangibleManager::GetLive() { IdArray result; - result.SetNum(IdToActor.Num()); + result.SetNum(IdToTangible.Num()); int next = 0; - for (auto &pair : IdToActor) { + for (auto& pair : IdToTangible) { result[next++] = pair.Key; } return result; } + diff --git a/Source/Integration/TangibleManager.h b/Source/Integration/TangibleManager.h index 7e77b565..4a307540 100644 --- a/Source/Integration/TangibleManager.h +++ b/Source/Integration/TangibleManager.h @@ -5,11 +5,11 @@ #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "CommonTypes.h" -#include "TangibleComponent.h" +#include "Tangible.h" #include "TangibleManager.generated.h" UCLASS() -class INTEGRATION_API UTangibleManager : public UObject +class INTEGRATION_API UlxTangibleManager : public UObject { GENERATED_BODY() @@ -27,9 +27,9 @@ public: UPROPERTY() TSubclassOf 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() - TMap IdToActor; + TMap IdToTangible; // Player's tangible Id. int64 Player; @@ -38,7 +38,7 @@ public: IdView Near; public: - UTangibleManager(); + UlxTangibleManager(); // Initialize the tangible manager. // @@ -49,10 +49,10 @@ public: UWorld* GetWorld() const override { return World.Get(); } // 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. - UTangibleComponent* MakeTangible(int64 id); + UlxTangible* MakeTangible(int64 id); // Delete the tangible. void DeleteTangible(int64 id); From 9116a7b8fed0d8243d3f5d34c83d67c6e582caf4 Mon Sep 17 00:00:00 2001 From: teppy999 Date: Tue, 26 Sep 2023 19:26:09 -0400 Subject: [PATCH 06/19] Some progress toward tangible GC: --- .../Integration/IntegrationGameModeBase.cpp | 23 ++++------- Source/Integration/Tangible.cpp | 2 + Source/Integration/TangibleManager.cpp | 41 ++++++++++++++----- Source/Integration/TangibleManager.h | 41 +++++++++---------- 4 files changed, 60 insertions(+), 47 deletions(-) diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index 04dfc472..b9efd041 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -121,22 +121,17 @@ void AIntegrationGameModeBase::MaybeTriggerUpdateTask(float deltaseconds) { #pragma optimize("", off) void AIntegrationGameModeBase::UpdateTangibles() { + using TanArray = UlxTangibleManager::TanArray; if (!Playing) return; FlxLockedWrapper w(LockableWrapper); - int64 actor = w.GetActor(); - TangibleManager->SetPlayer(actor); - IdView near = w.GetNear(actor, 100, 100, 100); - TangibleManager->SetNear(near); - for (int64 id : near) { - TangibleManager->MakeTangible(id); - } - // Update animation queues of live tangibles. - IdArray tanids = TangibleManager->GetLive(); - StringViewVec aqueues = w.GetAnimationQueues(tanids); - for (int i = 0; i < tanids.Num(); i++) { - uint64_t tanid = tanids[i]; - UlxTangible *t = TangibleManager->GetTangible(tanid); - t->AnimTracker.Update(aqueues[i]); + int64 player = w.GetActor(); + TangibleManager->UpdateNear(w.GetNear(player, 100, 100, 100)); + 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); diff --git a/Source/Integration/Tangible.cpp b/Source/Integration/Tangible.cpp index c12838c9..17b97851 100644 --- a/Source/Integration/Tangible.cpp +++ b/Source/Integration/Tangible.cpp @@ -6,6 +6,8 @@ UlxTangible::UlxTangible() { + TangibleId = -1; + NearAccordingToLuprex = false; } void UlxTangible::Init(UlxTangibleManager* tm, int64 id) diff --git a/Source/Integration/TangibleManager.cpp b/Source/Integration/TangibleManager.cpp index 30c4ff1e..0559b5de 100644 --- a/Source/Integration/TangibleManager.cpp +++ b/Source/Integration/TangibleManager.cpp @@ -6,27 +6,24 @@ #include "DebugPrint.h" using namespace DebugPrint; +using TanArray = UlxTangibleManager::TanArray; +using IdArray = UlxTangibleManager::IdArray; UlxTangibleManager::UlxTangibleManager() { World = nullptr; ClassTangibleActor = nullptr; - Player = 0; - Near = IdView(); } void UlxTangibleManager::Init(UWorld* world, UClass* tanact) { World = world; ClassTangibleActor = tanact; - Player = 0; - Near = IdView(); } -UlxTangible* UlxTangibleManager::GetTangible(int64 id) { - UlxTangible** p = IdToTangible.Find(id); +UlxTangible* UlxTangibleManager::GetTangible(int64 id) const { + UlxTangible*const* p = IdToTangible.Find(id); if (p == nullptr) { return nullptr; - } - else { + } else { return *p; } } @@ -49,12 +46,34 @@ void UlxTangibleManager::DeleteTangible(int64 id) { // IMPLEMENT ME } -UlxTangibleManager::IdArray UlxTangibleManager::GetLive() { - IdArray result; +TanArray UlxTangibleManager::GetAllTangibles() const { + TanArray result; result.SetNum(IdToTangible.Num()); int next = 0; for (auto& pair : IdToTangible) { - result[next++] = pair.Key; + result[next++] = pair.Value; + } + return result; +} + +void UlxTangibleManager::UpdateNear(IdView near) { + // Clear all the 'NearAccordingToLuprex' flags. + for (const auto& pair : IdToTangible) { + pair.Value->NearAccordingToLuprex = false; + } + // For every ID on the list, create it if it doesn't exist, + // mark it, and return it. + for (int64 id : near) { + UlxTangible* tan = MakeTangible(id); + tan->NearAccordingToLuprex = true; + } +} + +IdArray UlxTangibleManager::GetIds(const TanArray &arr) { + IdArray result; + result.SetNum(arr.Num()); + for (int i = 0; i < arr.Num(); i++) { + result[i] = arr[i]->TangibleId; } return result; } diff --git a/Source/Integration/TangibleManager.h b/Source/Integration/TangibleManager.h index 4a307540..ca83831b 100644 --- a/Source/Integration/TangibleManager.h +++ b/Source/Integration/TangibleManager.h @@ -14,9 +14,10 @@ class INTEGRATION_API UlxTangibleManager : public UObject GENERATED_BODY() public: - // Import these types into our Namespace. - using IdArray = CommonTypes::IdArray; + // Types used frequently. using IdView = CommonTypes::IdView; + using IdArray = CommonTypes::IdArray; + using TanArray = TArray; // A pointer to our world. UPROPERTY() @@ -31,12 +32,6 @@ public: UPROPERTY() TMap IdToTangible; - // Player's tangible Id. - int64 Player; - - // Tangibles near the actor. - IdView Near; - public: UlxTangibleManager(); @@ -49,28 +44,30 @@ public: UWorld* GetWorld() const override { return World.Get(); } // Get the tangible if it exists, otherwise return NULL - UlxTangible* GetTangible(int64 id); + // + UlxTangible* GetTangible(int64 id) const; // Get the tangible if it exists, otherwise create it. + // UlxTangible* MakeTangible(int64 id); // Delete the tangible. + // void DeleteTangible(int64 id); - // Get/Set the Id of the actor. - // - int64 GetPlayer() const { return Player; }; - void SetPlayer(int64 id) { Player = id; } + // Get an array of all tangibles. + // + TanArray GetAllTangibles() const; + + // Update the 'NearAccordingToLuprex' flags. + // + // Also creates any tangibles that are in the near-list, + // if they don't already exist. + // + void UpdateNear(IdView near); - // Get/Set the list of tangibles near the player, according to Luprex. + // Given an array of tangibles, return an array of tangible Ids. // - IdView GetNear() const { return Near; } - void SetNear(IdView near) { Near = near; } - - // Get the Live list. - // - // Efficiency note: this makes a copy of the array. - // - IdArray GetLive(); + static IdArray GetIds(const TanArray &tans); }; From 642b444d1336a57d366b9ad51fab9493265b3f48 Mon Sep 17 00:00:00 2001 From: teppy999 Date: Thu, 28 Sep 2023 14:32:48 -0400 Subject: [PATCH 07/19] 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. // From a2e49338cfc52429c72834f145a98040ca7a7fd0 Mon Sep 17 00:00:00 2001 From: teppy999 Date: Mon, 2 Oct 2023 15:48:42 -0400 Subject: [PATCH 08/19] Overhaul of tangible/blueprint animation interface --- Content/TangibleActor.uasset | 4 +- Source/Integration/AnimQueue.cpp | 173 ++++++++++++--------------- Source/Integration/AnimQueue.h | 125 ++++++++++--------- Source/Integration/StringDecoder.cpp | 16 ++- Source/Integration/StringDecoder.h | 11 ++ Source/Integration/Tangible.cpp | 41 ++++--- Source/Integration/Tangible.h | 13 +- 7 files changed, 197 insertions(+), 186 deletions(-) diff --git a/Content/TangibleActor.uasset b/Content/TangibleActor.uasset index a13f4cdd..3a1da417 100644 --- a/Content/TangibleActor.uasset +++ b/Content/TangibleActor.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:05b62c5757100adf5d29b718f75d9f540e11267ca0aa8e03cd33d2676fea9b91 -size 142754 +oid sha256:e99102328387901e912868879c8f206986da80d8e38ba0352da7b12df46400b0 +size 160277 diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index 050747f4..7301d4ab 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -2,9 +2,11 @@ #include "AnimQueue.h" FlxAnimationStep::FlxAnimationStep(uint64 hash, std::string_view body) { + Finished = false; Hash = hash; Body.SetNum(body.size()); memcpy(Body.GetData(), body.data(), body.size()); + Blueprint = UlxAnimationStepLibrary::AnimationStepGetString(*this, "bp"); } static bool ClearProperties(const FString& prefix, UObject* obj) { @@ -85,10 +87,9 @@ FString UlxAnimationStepLibrary::AnimationStepDebugString(const FlxAnimationStep return FlxAnimationStepDecoder::DebugString(step.Hash, body); } -void UlxAnimationStepLibrary::UnpackAnimationStep(const FlxAnimationStep& step, - const FString& prefix, UObject* into) { +void UlxAnimationStepLibrary::UnpackAnimationStep(UObject* into, const FlxAnimationStep& step, const FString& prefix) { step.Unpack(prefix, into, true); -}; +} static FlxAnimationField FindAnimationField(const FlxAnimationStep& step, const FString& name) { std::string_view body((const char*)(step.Body.GetData()), step.Body.Num()); @@ -106,6 +107,10 @@ static FlxAnimationField FindAnimationField(const FlxAnimationStep& step, const return result; } +bool UlxAnimationStepLibrary::AnimationStepIsIdle(const FlxAnimationStep &step) { + return step.Finished; +} + FVector UlxAnimationStepLibrary::AnimationStepGetVector(const FlxAnimationStep& step, const FString& name) { FlxAnimationField field = FindAnimationField(step, name); if (field.Type != ElxAnimValueType::XYZ) return FVector(0, 0, 0); @@ -138,6 +143,13 @@ FlxAnimationStepView FlxAnimQueueDecoder::ReadStep() { return result; } +uint64 FlxAnimQueueDecoder::PeekHash() { + std::string_view rest = Decoder.GetRest(); + uint64 result = Decoder.read_uint64(); + Decoder.Reset(rest, false); + return result; +} + FlxAnimationField FlxAnimationStepDecoder::ReadField() { FlxAnimationField result; result.Name = Decoder.read_string_view(); @@ -199,6 +211,11 @@ FString FlxAnimationStepDecoder::DebugString(uint64 hash, std::string_view body) return result; } +FlxAnimQueueDecoder::FlxAnimQueueDecoder(std::string_view queue) : Decoder(queue) { + SizeLimit = Decoder.read_uint8(); + ActualSize = Decoder.read_uint8(); +} + FString FlxAnimQueueDecoder::DebugString(std::string_view queue) { FString result; FlxAnimQueueDecoder decoder(queue); @@ -216,33 +233,50 @@ FlxAnimTracker::FlxAnimTracker() { void FlxAnimTracker::Clear() { AQ.Empty(); - FirstSeqno = 0; - HashToSeqno.Empty(); - UnstartedSeqno = 0; - PlaybackMode = ElxAnimationMode::INVALID; - AbortedHashes.Empty(); + Changed = true; +} + +void FlxAnimTracker::FinishedAnimation(uint64 hash) { + for (int i = 0; i < AQ.Num(); i++) { + if (AQ[i].Hash == hash) { + AQ[i].Finished = true; + Changed = true; + } + } +} + +void FlxAnimTracker::SkipToEnd() { + for (int i = 0; i < AQ.Num(); i++) { + if (!AQ[i].Finished) { + AQ[i].Finished = true; + Changed = true; + } + } } void FlxAnimTracker::Update(std::string_view encqueue) { - // Check for an exact match. If the most recent entry - // in encqueue has the same hash as the most recent - // entry in AQ, then that's an exact match. Or, - // if both are empty, that's also an exact match. - // In case of exact match, abort early, there's no - // further work needed. + check(!encqueue.empty()); + + // If the first hash matches, we don't bother updating at all. // - if (encqueue.empty()) { - if (AQ.IsEmpty()) { + FlxAnimQueueDecoder decoder(encqueue); + if (!AQ.IsEmpty()) { + if (decoder.PeekHash() == AQ.Last().Hash) { return; } - } else { - if (!AQ.IsEmpty()) { - FlxStringDecoder qdecoder(encqueue); - uint64 hash = qdecoder.read_uint64(); - if (hash == AQ.Last().Hash) { - return; - } - } + } + + + // The Changed flag is set whenever there is any change to + // the animation queue of any kind. + // + Changed = true; + + // Build a map indexing the steps in AQ. + // + TMap HashToIndex; + for (int i = 0; i < AQ.Num(); i++) { + HashToIndex.Emplace(AQ[i].Hash, i); } // Search for a Luprex animation record that matches @@ -252,108 +286,55 @@ void FlxAnimTracker::Update(std::string_view encqueue) { // At the same time, push all non-matching records // after the matching record onto a stack of new records. // - FlxAnimQueueDecoder decoder(encqueue); TArray newsteps; - int32 matchingseqno = -1; + int32 matchingindex = -1; while (!decoder.AtEOF()) { FlxAnimationStepView step = decoder.ReadStep(); - int32* stepseq = HashToSeqno.Find(step.Hash); - if (stepseq == nullptr) { + int32* indexp = HashToIndex.Find(step.Hash); + if (indexp == nullptr) { newsteps.Emplace(step); } else { - matchingseqno = *stepseq; + matchingindex = *indexp; break; } } // Remove all animations after the most recent matching - // record. If we remove a 'started' animation, add that - // animation to the list of aborted animations. + // record. // - int32 nremove = (FirstSeqno + AQ.Num()) - (matchingseqno + 1); + int32 nremove = (AQ.Num() - (matchingindex + 1)); check((nremove >= 0) && (nremove <= AQ.Num())); for (int32 i = 0; i < nremove; i++) { - uint64 lasthash = AQ.Last().Hash; - int32 seqno = FirstSeqno + AQ.Num() - 1; - HashToSeqno.Remove(lasthash); - if (seqno < UnstartedSeqno) { - AbortedHashes.Emplace(lasthash); - } AQ.PopLast(); } - // If we aborted a 'started' animation, we have to fix - // up the Unstarted animation pointer. - // - // Note: this could leave the Unstarted pointer at - // seqno less than FirstSeqno. We will fix that state - // of affairs up later. - // - if (UnstartedSeqno > (FirstSeqno + AQ.Num())) { - UnstartedSeqno = matchingseqno; - PlaybackMode = ElxAnimationMode::BlendToFinal; - } - // Transfer the new animations onto the queue. // while (!newsteps.IsEmpty()) { FlxAnimationStepView step = newsteps.Pop(); - int32 seqno = FirstSeqno + AQ.Num(); AQ.EmplaceLast(step.Hash, step.Body); - HashToSeqno.Emplace(step.Hash, seqno); } // If there are too many animations in AQ, discard // any very old ones. // - if (AQ.Num() > 10) { - int ndiscard = AQ.Num() - 10; - for (int i = 0; i < ndiscard; i++) { - uint64 hash = AQ.First().Hash; - HashToSeqno.Remove(hash); - AQ.PopFirst(); - FirstSeqno += 1; - } - } - - // If UnstartedSeqno is before the live range, - // then the whole queue has to be replayed. Don't - // do that: just fast skip to the end. + // TODO: this is hardwired to keep 10. Instead, we + // should keep the number specified in the queue. // - if (UnstartedSeqno <= FirstSeqno) { - if (AQ.Num() == 0) { - UnstartedSeqno = FirstSeqno; - } else { - UnstartedSeqno = FirstSeqno + AQ.Num() - 1; + int limit = 10; + int ndiscard = AQ.Num() - limit; + if (ndiscard > 0) { + for (int i = 0; i < ndiscard; i++) { + AQ.PopFirst(); } - PlaybackMode = ElxAnimationMode::WarpToFinal; } } -TArray FlxAnimTracker::GetAborted() { - TArray result; - result = std::move(AbortedHashes); - AbortedHashes.Empty(); - return result; -} - -ElxAnimationMode FlxAnimTracker::GetNextStep(FlxAnimationStep &step) { - int offset = UnstartedSeqno - FirstSeqno; - if (offset < AQ.Num()) { - step = AQ[offset]; - return PlaybackMode; - } else { - step.Hash = 0; - step.Body.Empty(); - return ElxAnimationMode::INVALID; +FlxAnimationStep FlxAnimTracker::GetCurrentAnimation() { + for (int i = 0; i < AQ.Num(); i++) { + if (!AQ[i].Finished) { + return AQ[i]; + } } + return AQ.Last(); } - -void FlxAnimTracker::StartedStep(uint64 hash) { - int offset = UnstartedSeqno - FirstSeqno; - check(offset < AQ.Num()); - check(AQ[offset].Hash == hash); - UnstartedSeqno += 1; - PlaybackMode = ElxAnimationMode::StartAnimation; -} - diff --git a/Source/Integration/AnimQueue.h b/Source/Integration/AnimQueue.h index 5df05d1f..1f5d8188 100644 --- a/Source/Integration/AnimQueue.h +++ b/Source/Integration/AnimQueue.h @@ -19,32 +19,6 @@ enum class ElxAnimValueType { INVALID }; -//////////////////////////////////////////////// -// -// Playback Modes -// -// There are three different ways to play an animation: -// -// 1. Start Animation. This is the normal way to play an animation. -// -// 2. Warp to Final. Skip the actual animation, and jump -// instantaneously to the final state of the animation. -// -// 3. Blend to Final. Skip the actual animation, and blend -// smoothly to the final state of the animation. If the current -// state is very far from the final state, then maybe -// jump instantaneously instead. -// -//////////////////////////////////////////////// - -UENUM(BlueprintType) -enum class ElxAnimationMode : uint8 { - StartAnimation, - WarpToFinal, - BlendToFinal, - INVALID, -}; - //////////////////////////////////////////////// // // An single animation step. @@ -61,13 +35,19 @@ struct INTEGRATION_API FlxAnimationStep { GENERATED_BODY() public: + UPROPERTY() + bool Finished; + UPROPERTY() uint64 Hash; UPROPERTY() TArray Body; - FlxAnimationStep() : Hash(0), Body() {} + UPROPERTY() + FString Blueprint; + + FlxAnimationStep() : Finished(false), Hash(0), Body(), Blueprint() {} FlxAnimationStep(uint64 h, std::string_view b); // Unpack an AnimStep into a UObject @@ -114,10 +94,12 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex) static FString AnimationStepDebugString(const FlxAnimationStep& step); - UFUNCTION(BlueprintCallable, Category = Luprex) - static void UnpackAnimationStep(const FlxAnimationStep& step, - const FString& VariableNamePrefix, UObject* into); + UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "into"), Category = Luprex) + static void UnpackAnimationStep(UObject* into, const FlxAnimationStep& step, const FString& VariableNamePrefix); + UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex) + static bool AnimationStepIsIdle(const FlxAnimationStep &step); + UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex) static FVector AnimationStepGetVector(const FlxAnimationStep& step, const FString& name); @@ -180,11 +162,24 @@ struct FlxAnimationField { class FlxAnimQueueDecoder { private: FlxStringDecoder Decoder; + + // These values are immediately read from the header. + // + int SizeLimit; + int ActualSize; public: // Initialize the FlxAnimQueueDecoder with the encoded animation queue. // - FlxAnimQueueDecoder(std::string_view s) : Decoder(s) {} + FlxAnimQueueDecoder(std::string_view s); + + // Get the size limit of the animation queue. + // + int GetSizeLimit() const { return SizeLimit; } + + // Get the Actual Size of the animation queue. + // + int GetActualSize() const { return ActualSize; } // Return true if the parser has reached the end of the string. // @@ -194,6 +189,10 @@ public: // FlxAnimationStepView ReadStep(); + // Peek at the hash of the next animation step. + // + uint64 PeekHash(); + // Convert an AnimQueue to an FString. // static FString DebugString(std::string_view s); @@ -252,26 +251,11 @@ public: // TDeque AQ; - // The sequence number of the first item in AQ. + // True if something has recently changed. // - int32 FirstSeqno; - - // Map from hash to sequence number. - // - TMap HashToSeqno; - - // The sequence number of the first unstarted animation. - // - int32 UnstartedSeqno; - - // Indicates whether the unstarted animation should be played or otherwise. - // - ElxAnimationMode PlaybackMode; - - // Array of recently-aborted hash values. - // - TArray AbortedHashes; + bool Changed; +private: public: // Construct a tracker. // @@ -290,24 +274,39 @@ public: // void Update(std::string_view encqueue); - // Fetch the aborted hash values. + // Get the current animation step. // - // This gets the array of aborted hashes and clears - // the stored array. - // - TArray GetAborted(); + // Get the current animation step. This is the step that the + // blueprint should currently be playing. + // + FlxAnimationStep GetCurrentAnimation(); - // Get the next unstarted animation step. + // Declare that an animation is finished. // - // Get the next animation step. Returns the next step and the - // playback mode. If the playback mode is INVALID then there is - // no next step to play - // - ElxAnimationMode GetNextStep(FlxAnimationStep& step); + // The blueprint uses this function call to indicate that it + // is done playing the specified animation. This will cause the + // animation to be marked as finished, which in turn causes + // 'GetCurrentStep' to advance to the next animation. + // + void FinishedAnimation(uint64 Hash); - // Declare that an animation has been started. + // Skip to the end of the animation queue. + // + // This is equivalent to calling 'FinishedHash' on every + // animation in the entire queue. // - // After starting an animation, you should call this. + void SkipToEnd(); + + // Clear the 'Changed' flag. // - void StartedStep(uint64 Hash); + void ClearChanged() { Changed = false; } + + // Get the 'Changed' flag. + // + // The changed flag is set to true whenever the Luprex animation + // queue changes from its previous state. The changed flag is also + // set to true whenever 'SetFinished' marks an animation as finished. + // The changed flag can only be set to false by 'ClearChanged,' above. + // + bool IsChanged() const { return Changed; } }; \ No newline at end of file diff --git a/Source/Integration/StringDecoder.cpp b/Source/Integration/StringDecoder.cpp index 1182914d..a5b5a75f 100644 --- a/Source/Integration/StringDecoder.cpp +++ b/Source/Integration/StringDecoder.cpp @@ -7,6 +7,19 @@ FlxStringDecoder::FlxStringDecoder(std::string_view s) { ErrStringTooLong = false; } +void FlxStringDecoder::Reset(std::string_view s, bool clear) { + Text = s.data(); + Size = s.size(); + if (clear) { + ErrBeyondEOF = false; + ErrStringTooLong = false; + } +} + +std::string_view FlxStringDecoder::GetRest() { + return std::string_view(Text, Size); +} + std::string_view FlxStringDecoder::read_string_view() { size_t length = read_length(); if (length > Size) { @@ -22,5 +35,4 @@ std::string_view FlxStringDecoder::read_string_view() { void FlxStringDecoder::set_at_eof() { Text += Size; Size = 0; - -} \ No newline at end of file +} diff --git a/Source/Integration/StringDecoder.h b/Source/Integration/StringDecoder.h index e585e741..b5d2abc8 100644 --- a/Source/Integration/StringDecoder.h +++ b/Source/Integration/StringDecoder.h @@ -70,6 +70,16 @@ public: // FlxStringDecoder(std::string_view s); + // Get the remaining text as a string_view. + // + std::string_view GetRest(); + + // Reinitialize with a new string_view. + // + // If clear is true, clears the error flags. + // + void Reset(std::string_view s, bool clear); + // Get the size of the remaining text. // size_t get_size() { return Size; } @@ -82,6 +92,7 @@ public: // void set_at_eof(); + // Read a string as a string_view // // This reads a string from the source, returning diff --git a/Source/Integration/Tangible.cpp b/Source/Integration/Tangible.cpp index 68a885f7..4ec72d9f 100644 --- a/Source/Integration/Tangible.cpp +++ b/Source/Integration/Tangible.cpp @@ -75,17 +75,12 @@ 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); - } + int limit = 3; + while (AnimTracker.IsChanged()) { + if (limit == 0) break; + limit -= 1; + AnimTracker.ClearChanged(); + IlxTangibleInterface::Execute_AnimationStateChanged(GetActor()); } } @@ -108,15 +103,27 @@ void UlxTangible::Destroy() { NearAccordingToUnreal = false; } -FString UlxTangible::GetTangiblePlane(AActor* actor) { +static UlxTangible *GetActorTangible(AActor *actor) { UlxTangibleComponent* comp = actor->GetComponentByClass(); check(comp != nullptr); - return comp->Tangible->Plane.ToString(); + UlxTangible *result = comp->Tangible.Get(); + check(result != nullptr); + return result; } -void UlxTangible::SetTangiblePlane(AActor* actor, const FString& plane) { - UlxTangibleComponent* comp = actor->GetComponentByClass(); - check(comp != nullptr); - comp->Tangible->Plane = FName(plane); +void UlxTangible::GetCurrentAnimation(AActor *target, FlxAnimationStep &step) { + step = GetActorTangible(target)->AnimTracker.GetCurrentAnimation(); +} + +void UlxTangible::FinishedAnimation(AActor *target, const FlxAnimationStep &step) { + GetActorTangible(target)->AnimTracker.FinishedAnimation(step.Hash); +} + +FString UlxTangible::GetTangiblePlane(AActor* target) { + return GetActorTangible(target)->Plane.ToString(); +} + +void UlxTangible::SetTangiblePlane(AActor* target, const FString& plane) { + GetActorTangible(target)->Plane = FName(plane); } diff --git a/Source/Integration/Tangible.h b/Source/Integration/Tangible.h index d3323a22..fc7e9e79 100644 --- a/Source/Integration/Tangible.h +++ b/Source/Integration/Tangible.h @@ -33,15 +33,10 @@ class INTEGRATION_API IlxTangibleInterface // 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); + bool AnimationStateChanged(); }; - - /** * * UlxTangible @@ -168,6 +163,12 @@ public: void UpdateAnimationQueue(std::string_view aq); public: + UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex) + static void GetCurrentAnimation(AActor *target, FlxAnimationStep &step); + + UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex) + static void FinishedAnimation(AActor *target, const FlxAnimationStep &step); + UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex) static FString GetTangiblePlane(AActor* target); From 334a95481d078887e22768ef435fa3b3ff53125f Mon Sep 17 00:00:00 2001 From: teppy999 Date: Mon, 9 Oct 2023 14:59:48 -0400 Subject: [PATCH 09/19] Checking everything in --- Content/TangibleActor.uasset | 4 ++-- Source/Integration/AnimQueue.cpp | 34 ++++++++++++++++++++++++++++---- Source/Integration/AnimQueue.h | 13 ++++++++++++ Source/Integration/Tangible.cpp | 8 ++++++-- Source/Integration/Tangible.h | 3 ++- 5 files changed, 53 insertions(+), 9 deletions(-) diff --git a/Content/TangibleActor.uasset b/Content/TangibleActor.uasset index 3a1da417..24cba782 100644 --- a/Content/TangibleActor.uasset +++ b/Content/TangibleActor.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e99102328387901e912868879c8f206986da80d8e38ba0352da7b12df46400b0 -size 160277 +oid sha256:90b49cd7987f58dbe07e6c7af9896ce38633e1212eef5fe3b7132b12e13df4d7 +size 160465 diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index 7301d4ab..2fca5ce0 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -91,15 +91,13 @@ void UlxAnimationStepLibrary::UnpackAnimationStep(UObject* into, const FlxAnimat step.Unpack(prefix, into, true); } -static FlxAnimationField FindAnimationField(const FlxAnimationStep& step, const FString& name) { +static FlxAnimationField FindAnimationFieldLL(const FlxAnimationStep& step, std::string_view name) { std::string_view body((const char*)(step.Body.GetData()), step.Body.Num()); - FTCHARToUTF8 utf8name(name); - std::string_view uname(utf8name.Get(), utf8name.Length()); FlxAnimationStepDecoder decoder(body); FlxAnimationField result; while (!decoder.AtEOF()) { result = decoder.ReadField(); - if (result.Name == uname) { + if (result.Name == name) { return result; } } @@ -107,6 +105,34 @@ static FlxAnimationField FindAnimationField(const FlxAnimationStep& step, const return result; } +static FlxAnimationField FindAnimationField(const FlxAnimationStep& step, const FString& name) { + FTCHARToUTF8 utf8name(name); + std::string_view uname(utf8name.Get(), utf8name.Length()); + return FindAnimationFieldLL(step, uname); +} + +void FlxAnimationStep::AutoUpdateXYZ(AActor *actor) const { + FlxAnimationField xyz = FindAnimationFieldLL(*this, "xyz"); + if (xyz.Type == ElxAnimValueType::XYZ) { + actor->SetActorLocation(FVector(xyz.X, xyz.Y, xyz.Z)); + } +} + +void FlxAnimationStep::AutoUpdateFacing(AActor *actor) const { + FlxAnimationField facing = FindAnimationFieldLL(*this, "facing"); + if (facing.Type == ElxAnimValueType::NUMBER) { + actor->SetActorRotation(FRotator(0, facing.X, 0)); + } +} + +void FlxAnimationStep::AutoUpdatePlane(FName *planep) const { + FlxAnimationField plane = FindAnimationFieldLL(*this, "plane"); + if (plane.Type == ElxAnimValueType::STRING) { + FString pname(plane.S.size(), (const UTF8CHAR*)(plane.S.data())); + *planep = FName(pname); + } +} + bool UlxAnimationStepLibrary::AnimationStepIsIdle(const FlxAnimationStep &step) { return step.Finished; } diff --git a/Source/Integration/AnimQueue.h b/Source/Integration/AnimQueue.h index 1f5d8188..02ab3300 100644 --- a/Source/Integration/AnimQueue.h +++ b/Source/Integration/AnimQueue.h @@ -75,6 +75,19 @@ public: // unpacking the animation step. // bool Unpack(const FString& prefix, UObject* into, bool preclear = true) const; + + // Auto-Execute + // + // These functions automatically update certain actor + // properties: + // + // AutoUpdateXYZ(AActor *actor); // uses 'xyz' keyword + // AutoUpdateFacing(AActor *actor); // uses 'facing' keyword. + // AutoUpdatePlane(FName *plane); // uses 'plane' keyword + // + void AutoUpdateXYZ(AActor *actor) const; + void AutoUpdateFacing(AActor *actor) const; + void AutoUpdatePlane(FName *plane) const; }; //////////////////////////////////////////////// diff --git a/Source/Integration/Tangible.cpp b/Source/Integration/Tangible.cpp index 4ec72d9f..259776a2 100644 --- a/Source/Integration/Tangible.cpp +++ b/Source/Integration/Tangible.cpp @@ -115,8 +115,12 @@ void UlxTangible::GetCurrentAnimation(AActor *target, FlxAnimationStep &step) { step = GetActorTangible(target)->AnimTracker.GetCurrentAnimation(); } -void UlxTangible::FinishedAnimation(AActor *target, const FlxAnimationStep &step) { - GetActorTangible(target)->AnimTracker.FinishedAnimation(step.Hash); +void UlxTangible::FinishedAnimation(AActor *target, const FlxAnimationStep &step, bool autoxyz, bool autofacing, bool autoplane) { + UlxTangible *tan = GetActorTangible(target); + if (autoxyz) step.AutoUpdateXYZ(target); + if (autofacing) step.AutoUpdateFacing(target); + if (autoplane) step.AutoUpdatePlane(&(tan->Plane)); + tan->AnimTracker.FinishedAnimation(step.Hash); } FString UlxTangible::GetTangiblePlane(AActor* target) { diff --git a/Source/Integration/Tangible.h b/Source/Integration/Tangible.h index fc7e9e79..4545a33b 100644 --- a/Source/Integration/Tangible.h +++ b/Source/Integration/Tangible.h @@ -167,7 +167,8 @@ public: static void GetCurrentAnimation(AActor *target, FlxAnimationStep &step); UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex) - static void FinishedAnimation(AActor *target, const FlxAnimationStep &step); + static void FinishedAnimation(AActor *target, const FlxAnimationStep &step, + bool AutoUpdateXYZ = true, bool AutoUpdateFacing = true, bool AutoUpdatePlane = true); UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "target"), Category = Luprex) static FString GetTangiblePlane(AActor* target); From f7249e4d29982b98ea831dcdddbbff8af2571f9b Mon Sep 17 00:00:00 2001 From: teppy999 Date: Thu, 12 Oct 2023 18:15:56 -0400 Subject: [PATCH 10/19] More work on anim queues --- Content/TangibleActor.uasset | 4 +-- Source/Integration/AnimQueue.cpp | 53 +++++++++++++++++++++++--------- Source/Integration/AnimQueue.h | 27 +++++++++------- 3 files changed, 56 insertions(+), 28 deletions(-) diff --git a/Content/TangibleActor.uasset b/Content/TangibleActor.uasset index 24cba782..781f917d 100644 --- a/Content/TangibleActor.uasset +++ b/Content/TangibleActor.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:90b49cd7987f58dbe07e6c7af9896ce38633e1212eef5fe3b7132b12e13df4d7 -size 160465 +oid sha256:e25fe70233549efcc19085e8c000dae416a86ae171cb3526039a07a50af1e1a5 +size 290458 diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index 2fca5ce0..78ce2563 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -29,9 +29,12 @@ static bool ClearProperties(const FString& prefix, UObject* obj) { return true; } -static bool SetProperty(const FString& name, UObject* obj, const FlxAnimationField& field) { +#pragma optimize("", off) + +static bool SetProperty(const FString& prefix, UObject* obj, const FlxAnimationField& field) { UClass* uclass = obj->GetClass(); - FName nname(name); + FString sname(field.Name.size(), (const UTF8CHAR*)field.Name.data()); + FName nname(prefix + sname); switch (field.Type) { case ElxAnimValueType::STRING: { FStrProperty* fprop = FindFProperty(uclass, nname); @@ -66,29 +69,35 @@ static bool SetProperty(const FString& name, UObject* obj, const FlxAnimationFie return false; } -bool FlxAnimationStep::Unpack(const FString& prefix, UObject* into, bool preclear) const { +#pragma optimize("", off) +bool FlxAnimationStep::Unpack(const FString& prefix, UObject* into) const { UClass* uclass = into->GetClass(); std::string_view body((const char*)(Body.GetData()), Body.Num()); FlxAnimationStepDecoder decoder(body); - bool ok = true; - if (preclear) { - ok &= ClearProperties(prefix, into); - } + bool ok = ClearProperties(prefix, into); while (!decoder.AtEOF()) { FlxAnimationField field = decoder.ReadField(); - FString sname(field.Name.size(), (const UTF8CHAR*)field.Name.data()); - ok &= SetProperty(prefix + sname, into, field); + if (Finished && !field.Persistent) continue; + ok &= SetProperty(prefix, into, field); + } + if (Finished) { + FlxAnimationField field; + field.Name = "action"; + field.Persistent = false; + field.Type = ElxAnimValueType::STRING; + field.S = "idle"; + ok &= SetProperty(prefix, into, field); } return ok; } FString UlxAnimationStepLibrary::AnimationStepDebugString(const FlxAnimationStep& step) { std::string_view body((const char*)(step.Body.GetData()), step.Body.Num()); - return FlxAnimationStepDecoder::DebugString(step.Hash, body); + return FlxAnimationStepDecoder::DebugString(step.Finished, step.Finished, step.Hash, body); } void UlxAnimationStepLibrary::UnpackAnimationStep(UObject* into, const FlxAnimationStep& step, const FString& prefix) { - step.Unpack(prefix, into, true); + step.Unpack(prefix, into); } static FlxAnimationField FindAnimationFieldLL(const FlxAnimationStep& step, std::string_view name) { @@ -133,6 +142,10 @@ void FlxAnimationStep::AutoUpdatePlane(FName *planep) const { } } +bool UlxAnimationStepLibrary::AnimationStepEqual(const FlxAnimationStep &stepa, const FlxAnimationStep &stepb) { + return (stepa.Finished == stepb.Finished) && (stepa.Hash == stepb.Hash); +} + bool UlxAnimationStepLibrary::AnimationStepIsIdle(const FlxAnimationStep &step) { return step.Finished; } @@ -149,8 +162,10 @@ double UlxAnimationStepLibrary::AnimationStepGetFloat(const FlxAnimationStep& st return field.X; } -#pragma optimize("", off) FString UlxAnimationStepLibrary::AnimationStepGetString(const FlxAnimationStep& step, const FString& name) { + if (step.Finished && (name == TEXT("action"))) { + return TEXT("idle"); + } FlxAnimationField field = FindAnimationField(step, name); if (field.Type != ElxAnimValueType::STRING) return TEXT(""); return FString(field.S.size(), (const UTF8CHAR*)(field.S.data())); @@ -210,12 +225,16 @@ FlxAnimationField FlxAnimationStepDecoder::ReadField() { return result; } -FString FlxAnimationStepDecoder::DebugString(uint64 hash, std::string_view body) { +FString FlxAnimationStepDecoder::DebugString(bool injectidle, bool persistentonly, uint64 hash, std::string_view body) { FString result; FlxAnimationStepDecoder decoder(body); result.Appendf(TEXT("Hash=%016llx"), hash); + if (injectidle) { + result.Appendf(TEXT(" action=idle")); + } while (!decoder.AtEOF()) { FlxAnimationField field = decoder.ReadField(); + if (persistentonly && !field.Persistent) continue; result.Append(TEXT(" ")); result.Append(FString(field.Name.size(), (const UTF8CHAR*)field.Name.data())); result.Append(field.Persistent ? TEXT("=") : TEXT(":")); @@ -247,7 +266,7 @@ FString FlxAnimQueueDecoder::DebugString(std::string_view queue) { FlxAnimQueueDecoder decoder(queue); while (!decoder.AtEOF()) { FlxAnimationStepView step = decoder.ReadStep(); - FString stepdebug = FlxAnimationStepDecoder::DebugString(step.Hash, step.Body); + FString stepdebug = FlxAnimationStepDecoder::DebugString(false, false, step.Hash, step.Body); result.Appendf(TEXT("%s\n"), *stepdebug); } return result; @@ -339,6 +358,7 @@ void FlxAnimTracker::Update(std::string_view encqueue) { while (!newsteps.IsEmpty()) { FlxAnimationStepView step = newsteps.Pop(); AQ.EmplaceLast(step.Hash, step.Body); + } // If there are too many animations in AQ, discard @@ -357,10 +377,13 @@ void FlxAnimTracker::Update(std::string_view encqueue) { } FlxAnimationStep FlxAnimTracker::GetCurrentAnimation() { + FlxAnimationStep result; for (int i = 0; i < AQ.Num(); i++) { if (!AQ[i].Finished) { return AQ[i]; } } - return AQ.Last(); + result = AQ.Last(); + result.Hash = 0; + return result; } diff --git a/Source/Integration/AnimQueue.h b/Source/Integration/AnimQueue.h index 02ab3300..ff576088 100644 --- a/Source/Integration/AnimQueue.h +++ b/Source/Integration/AnimQueue.h @@ -58,6 +58,14 @@ public: // routine tries to find a string property "color" in the // UObject, and then it sets that property to "blue." // + // The prefix is prepended to the key names. For example, + // if one of the key-value pairs is "color=blue", and the + // prefix is "aq", then the property "aqColor=blue" will be + // stored in the UObject. + // + // All properties of the UObject starting with the specified + // prefix are cleared before unpacking the animation step. + // // Returns true if all of the key-value pairs in the // animation step could be unpacked into fields of the UObject. // This could fail, for instance, if the UObject just doesn't @@ -65,16 +73,10 @@ public: // fail if there's a type mismatch. For example, "color=blue" // cannot be stored in a property "color" of type int. // - // The prefix is prepended to the key names. For example, - // if one of the key-value pairs is "color=blue", and the - // prefix is "aq", then the property "aqColor=blue" will be - // stored in the UObject. + // Automatically injects a boolean property "idle" representing + // whether the property's finished flag is set. // - // If pre-clear is true, then all properties of the UObject - // starting with the specified prefix are cleared before - // unpacking the animation step. - // - bool Unpack(const FString& prefix, UObject* into, bool preclear = true) const; + bool Unpack(const FString& prefix, UObject* into) const; // Auto-Execute // @@ -108,7 +110,10 @@ public: static FString AnimationStepDebugString(const FlxAnimationStep& step); UFUNCTION(BlueprintCallable, Meta = (DefaultToSelf = "into"), Category = Luprex) - static void UnpackAnimationStep(UObject* into, const FlxAnimationStep& step, const FString& VariableNamePrefix); + static void UnpackAnimationStep(UObject* into, const FlxAnimationStep& step, const FString& VariableNamePrefix = TEXT("aq")); + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex) + static bool AnimationStepEqual(const FlxAnimationStep &StepA, const FlxAnimationStep &StepB); UFUNCTION(BlueprintCallable, BlueprintPure, Category = Luprex) static bool AnimationStepIsIdle(const FlxAnimationStep &step); @@ -241,7 +246,7 @@ public: // Convert an AnimStep to an FString. // - static FString DebugString(uint64 hash, std::string_view body); + static FString DebugString(bool injectidle, bool persistentonly, uint64 hash, std::string_view body); }; //////////////////////////////////////////////// From 311920b79cf03b38317a0c20a6666f59e7d24e22 Mon Sep 17 00:00:00 2001 From: Joshua Yelon Date: Mon, 16 Oct 2023 14:13:42 -0400 Subject: [PATCH 11/19] Don't check in lpx-*.* any more --- Source/Integration/lpx-basewriter.hpp | 1 - Source/Integration/lpx-drvutil.cpp | 1 - Source/Integration/lpx-drvutil.hpp | 1 - Source/Integration/lpx-enginewrapper.hpp | 1 - 4 files changed, 4 deletions(-) delete mode 100644 Source/Integration/lpx-basewriter.hpp delete mode 100644 Source/Integration/lpx-drvutil.cpp delete mode 100644 Source/Integration/lpx-drvutil.hpp delete mode 100644 Source/Integration/lpx-enginewrapper.hpp diff --git a/Source/Integration/lpx-basewriter.hpp b/Source/Integration/lpx-basewriter.hpp deleted file mode 100644 index 92f52af6..00000000 --- a/Source/Integration/lpx-basewriter.hpp +++ /dev/null @@ -1 +0,0 @@ -#include "c:/luprex/ext/base-writer.hpp" \ No newline at end of file diff --git a/Source/Integration/lpx-drvutil.cpp b/Source/Integration/lpx-drvutil.cpp deleted file mode 100644 index c88f328a..00000000 --- a/Source/Integration/lpx-drvutil.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "c:/luprex/cpp/drv/drvutil.cpp" \ No newline at end of file diff --git a/Source/Integration/lpx-drvutil.hpp b/Source/Integration/lpx-drvutil.hpp deleted file mode 100644 index f47576cb..00000000 --- a/Source/Integration/lpx-drvutil.hpp +++ /dev/null @@ -1 +0,0 @@ -#include "c:/luprex/cpp/drv/drvutil.hpp" \ No newline at end of file diff --git a/Source/Integration/lpx-enginewrapper.hpp b/Source/Integration/lpx-enginewrapper.hpp deleted file mode 100644 index 39a03edd..00000000 --- a/Source/Integration/lpx-enginewrapper.hpp +++ /dev/null @@ -1 +0,0 @@ -#include "c:/luprex/cpp/core/enginewrapper.hpp" \ No newline at end of file From 6fe5968ebb0792651435eab829d067f22bb878fe Mon Sep 17 00:00:00 2001 From: Joshua Yelon Date: Mon, 16 Oct 2023 14:19:49 -0400 Subject: [PATCH 12/19] Add script to link to luprex under linux --- .gitignore | 2 ++ luprex-install.sh | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100755 luprex-install.sh diff --git a/.gitignore b/.gitignore index 44540061..b7d34254 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,8 @@ gmon.out *.pdb *.sln *.vcproj +Source/Integration/lpx-*.hpp +Source/Integration/lpx-*.cpp .vscode/** Saved/** diff --git a/luprex-install.sh b/luprex-install.sh new file mode 100755 index 00000000..c02912d7 --- /dev/null +++ b/luprex-install.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# +# +# Install symbolic links to the Luprex source and the Luprex DLL. +# +# These symbolic links are needed to be able to build integration. +# +# + +LUPREX=$HOME/luprex + +rm -f Source/Integration/lpx-*.hpp +rm -f Source/Integration/lpx-*.cpp +rm -f Binaries/Linux/luprexlib.so +mkdir -p Binaries/Linux + +ln -s $LUPREX/ext/base-writer.hpp Source/Integration/lpx-basewriter.hpp +ln -s $LUPREX/cpp/drv/drvutil.hpp Source/Integration/lpx-drvutil.hpp +ln -s $LUPREX/cpp/drv/drvutil.cpp Source/Integration/lpx-drvutil.cpp +ln -s $LUPREX/cpp/core/enginewrapper.hpp Source/Integration/lpx-enginewrapper.hpp +ln -s $LUPREX/build/linux/luprexlib.so Binaries/Linux/luprexlib.so + From 320b4dd714a571d6b2daec890468a2a00e319b0e Mon Sep 17 00:00:00 2001 From: jyelon Date: Mon, 16 Oct 2023 15:08:11 -0400 Subject: [PATCH 13/19] Porting to Linux --- .gitignore | 5 ++++ Source/Integration/LockedWrapper.cpp | 6 ++--- Source/Integration/LuprexSockets.cpp | 35 +++++++++++++++++++++++++++- luprex-install.sh | 9 +++---- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index b7d34254..940d0336 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,11 @@ gmon.out *.pdb *.sln *.vcproj +.ignore + +Integration.code-workspace +Makefile + Source/Integration/lpx-*.hpp Source/Integration/lpx-*.cpp diff --git a/Source/Integration/LockedWrapper.cpp b/Source/Integration/LockedWrapper.cpp index ddc53146..563cf181 100644 --- a/Source/Integration/LockedWrapper.cpp +++ b/Source/Integration/LockedWrapper.cpp @@ -43,7 +43,7 @@ int64 FlxLockedWrapper::GetActor() { IdView FlxLockedWrapper::GetNear(int64 id, double rx, double ry, double rz) { uint32 size; int64* data; - Lockable.Wrapper.get_tangibles_near(Get(), id, rx, ry, rz, &size, &data); + Lockable.Wrapper.get_tangibles_near(Get(), id, rx, ry, rz, &size, (int64_t**)&data); return IdView(data, size); } @@ -64,7 +64,7 @@ StringViewVec FlxLockedWrapper::GetAnimationQueues(IdView ids) { const char** StrBuf = Lockable.AQStrBuffer.GetData(); // Get the animation queues into the static buffers. - Lockable.Wrapper.get_animation_queues(Get(), num, ids.GetData(), LenBuf, StrBuf); + Lockable.Wrapper.get_animation_queues(Get(), num, (const int64_t *)ids.GetData(), LenBuf, StrBuf); // Transfer data from static buffers into an array of string_view StringViewVec result; @@ -73,4 +73,4 @@ StringViewVec FlxLockedWrapper::GetAnimationQueues(IdView ids) { result[i] = std::string_view(StrBuf[i], LenBuf[i]); } return result; -} \ No newline at end of file +} diff --git a/Source/Integration/LuprexSockets.cpp b/Source/Integration/LuprexSockets.cpp index a7d213c4..4ad0c0fc 100644 --- a/Source/Integration/LuprexSockets.cpp +++ b/Source/Integration/LuprexSockets.cpp @@ -23,9 +23,13 @@ THIRD_PARTY_INCLUDES_START THIRD_PARTY_INCLUDES_END #undef UI +#ifdef __linux__ +#else #define WIN32_LEAN_AND_MEAN #include #include +#endif + #include #include #include @@ -241,6 +245,26 @@ public: // ///////////////////////////////////////////////////////////////// +#ifdef __linux__ +inline static void strerror_helper(int status, int errnum, char errbuf[256]) { + if (status != 0) { + snprintf(errbuf, 256, "unknown errno %d", errnum); + } +} + +inline static void strerror_helper(const char *result, int errnum, char errbuf[256]) { + if (result != errbuf) { + snprintf(errbuf, 256, "%s", result); + } +} + +static std::string strerror_str(int errnum) { + char buf[256]; + auto rval = strerror_r(errnum, buf, 256); + strerror_helper(rval, errnum, buf); + return buf; +} +#else static std::string strerror_str(int errnum) { char buf[256]; int status = strerror_s(buf, 256, errnum); @@ -250,6 +274,8 @@ static std::string strerror_str(int errnum) { } return buf; } +#endif + static FSocket* OpenConnection(ISocketSubsystem *subsys, const std::string& host, const std::string& port, std::string& err) { @@ -401,6 +427,12 @@ static SSL_CTX* SSLNewContext(int verify, const SSL_METHOD *method, BIO *tracebi return ctx; } +#ifdef __linux__ +static std::string SSLLoadCertificateAuthorities(SSL_CTX* ctx) { + check(SSL_CTX_set_default_verify_paths(ctx) == 1); + return ""; +} +#else static std::string SSLLoadCertificateAuthorities(SSL_CTX* ctx) { HCERTSTORE hStore = CertOpenSystemStoreW(0, L"ROOT"); @@ -427,6 +459,7 @@ static std::string SSLLoadCertificateAuthorities(SSL_CTX* ctx) { CertCloseStore(hStore, 0); return ""; } +#endif static std::string SSLUseCertificateString(SSL_CTX* ctx, const char* str) { SSLClearErrors(); @@ -747,7 +780,7 @@ void FLpxChannel::Advance() AdvanceReadWrite(); break; default: - checkf(false, L"EChanState is invalid"); + checkf(false, TEXT("EChanState is invalid")); break; } diff --git a/luprex-install.sh b/luprex-install.sh index c02912d7..edc17b8e 100755 --- a/luprex-install.sh +++ b/luprex-install.sh @@ -14,9 +14,10 @@ rm -f Source/Integration/lpx-*.cpp rm -f Binaries/Linux/luprexlib.so mkdir -p Binaries/Linux -ln -s $LUPREX/ext/base-writer.hpp Source/Integration/lpx-basewriter.hpp -ln -s $LUPREX/cpp/drv/drvutil.hpp Source/Integration/lpx-drvutil.hpp -ln -s $LUPREX/cpp/drv/drvutil.cpp Source/Integration/lpx-drvutil.cpp -ln -s $LUPREX/cpp/core/enginewrapper.hpp Source/Integration/lpx-enginewrapper.hpp +echo '#include "'$LUPREX'/ext/base-writer.hpp"' > Source/Integration/lpx-basewriter.hpp +echo '#include "'$LUPREX'/cpp/drv/drvutil.hpp"' > Source/Integration/lpx-drvutil.hpp +echo '#include "'$LUPREX'/cpp/drv/drvutil.cpp"' > Source/Integration/lpx-drvutil.cpp +echo '#include "'$LUPREX'/cpp/core/enginewrapper.hpp"' > Source/Integration/lpx-enginewrapper.hpp + ln -s $LUPREX/build/linux/luprexlib.so Binaries/Linux/luprexlib.so From f647025a979c3c955dfc3bb2769422871b245209 Mon Sep 17 00:00:00 2001 From: jyelon Date: Mon, 16 Oct 2023 16:54:41 -0400 Subject: [PATCH 14/19] Finish porting to Linux --- Config/DefaultEngine.ini | 9 +++++++ .../Integration/IntegrationGameModeBase.cpp | 26 +++++++++++-------- Source/Integration/LockedWrapper.cpp | 5 +++- luprex-install.sh | 15 +++++------ 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index ef3c9672..74dd158a 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -71,3 +71,12 @@ ConnectionType=USBOnly bUseManualIPAddress=False ManualIPAddress= +[/Script/LinuxTargetPlatform.LinuxTargetSettings] +SpatializationPlugin= +SourceDataOverridePlugin= +ReverbPlugin= +OcclusionPlugin= +SoundCueCookQualityIndex=-1 +-TargetedRHIs=SF_VULKAN_SM5 ++TargetedRHIs=SF_VULKAN_SM6 + diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index 71745761..7cbcc519 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -2,6 +2,7 @@ #include "IntegrationGameModeBase.h" #include "lpx-drvutil.hpp" +#include "lpx-paths.hpp" #include "DebugPrint.h" #include "Tangible.h" #include "TangibleManager.h" @@ -193,22 +194,25 @@ void AIntegrationGameModeBase::BeginPlay() if (w->play_initialize != nullptr) { drvutil::ostringstream srcpak; - std::string srcpakerr = drvutil::package_lua_source("c:\\Luprex", &srcpak); + std::string srcpakerr = drvutil::package_lua_source(LUPREX_ROOT_PATH, &srcpak); if (!srcpakerr.empty()) { DPrint(srcpakerr.c_str()); } - std::string_view srcpakv = srcpak.view(); - char* argv[1]; - argv[0] = const_cast("lpxserver"); - w->play_initialize(w.Get(), 1, argv, srcpakv.size(), srcpakv.data(), ""); - if (w->error[0]) + else { - DPrint(w->error); - } - if (w->engine != nullptr) { - DPrint("Luprex initialize success"); - Playing = true; + std::string_view srcpakv = srcpak.view(); + char* argv[1]; + argv[0] = const_cast("lpxserver"); + w->play_initialize(w.Get(), 1, argv, srcpakv.size(), srcpakv.data(), ""); + if (w->error[0]) + { + DPrint(w->error); + } + if (w->engine != nullptr) { + DPrint("Luprex initialize success"); + Playing = true; + } } } diff --git a/Source/Integration/LockedWrapper.cpp b/Source/Integration/LockedWrapper.cpp index 563cf181..0b1a4432 100644 --- a/Source/Integration/LockedWrapper.cpp +++ b/Source/Integration/LockedWrapper.cpp @@ -2,6 +2,7 @@ #include "LockedWrapper.h" #include "DebugPrint.h" #include "lpx-drvutil.hpp" +#include "lpx-paths.hpp" using namespace CommonTypes; @@ -10,7 +11,9 @@ void FlxLockedWrapper::InitWrapper() { // Already initialized. return; } - void* DLL = FPlatformProcess::GetDllHandle(TEXT("c:\\Luprex\\build\\visual\\luprexlib.dll")); + FString dll((const UTF8CHAR*)LUPREX_DLL_PATH); + DebugPrint::DPrint(dll); + void* DLL = FPlatformProcess::GetDllHandle(*dll); if (DLL != nullptr) { using InitFn = void (*)(EngineWrapper*); InitFn init = (InitFn)FPlatformProcess::GetDllExport(DLL, TEXT("init_engine_wrapper")); diff --git a/luprex-install.sh b/luprex-install.sh index edc17b8e..e75119b7 100755 --- a/luprex-install.sh +++ b/luprex-install.sh @@ -11,13 +11,10 @@ LUPREX=$HOME/luprex rm -f Source/Integration/lpx-*.hpp rm -f Source/Integration/lpx-*.cpp -rm -f Binaries/Linux/luprexlib.so -mkdir -p Binaries/Linux - -echo '#include "'$LUPREX'/ext/base-writer.hpp"' > Source/Integration/lpx-basewriter.hpp -echo '#include "'$LUPREX'/cpp/drv/drvutil.hpp"' > Source/Integration/lpx-drvutil.hpp -echo '#include "'$LUPREX'/cpp/drv/drvutil.cpp"' > Source/Integration/lpx-drvutil.cpp -echo '#include "'$LUPREX'/cpp/core/enginewrapper.hpp"' > Source/Integration/lpx-enginewrapper.hpp - -ln -s $LUPREX/build/linux/luprexlib.so Binaries/Linux/luprexlib.so +echo '#include "'$LUPREX'/ext/base-writer.hpp"' > Source/Integration/lpx-basewriter.hpp +echo '#include "'$LUPREX'/cpp/drv/drvutil.hpp"' > Source/Integration/lpx-drvutil.hpp +echo '#include "'$LUPREX'/cpp/drv/drvutil.cpp"' > Source/Integration/lpx-drvutil.cpp +echo '#include "'$LUPREX'/cpp/core/enginewrapper.hpp"' > Source/Integration/lpx-enginewrapper.hpp +echo '#define LUPREX_DLL_PATH "'$LUPREX'/build/linux/luprexlib.so"' > Source/Integration/lpx-paths.hpp +echo '#define LUPREX_ROOT_PATH "'$LUPREX'"' >> Source/Integration/lpx-paths.hpp From 7080f3d8c7c128b6bba6b550d18a08479d781f39 Mon Sep 17 00:00:00 2001 From: teppy999 Date: Mon, 16 Oct 2023 17:19:39 -0400 Subject: [PATCH 15/19] Modify luprex-install.sh for windows --- .gitattributes | 1 + luprex-install.sh | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.gitattributes b/.gitattributes index 90bd4e26..1bded486 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,6 @@ * text=auto *.bat text eol=crlf +*.sh text eol=lf *.lib filter=lfs diff=lfs merge=lfs -text *.exe filter=lfs diff=lfs merge=lfs -text *.a filter=lfs diff=lfs merge=lfs -text diff --git a/luprex-install.sh b/luprex-install.sh index e75119b7..c0dbec72 100755 --- a/luprex-install.sh +++ b/luprex-install.sh @@ -7,14 +7,20 @@ # # -LUPREX=$HOME/luprex +if [ -d c:/luprex ] ; then + LUPREX=c:/luprex + DLL=$LUPREX/build/visual/luprexlib.dll +else + LUPREX=$HOME/luprex + DLL=$LUPREX/build/linux/luprexlib.so +fi rm -f Source/Integration/lpx-*.hpp rm -f Source/Integration/lpx-*.cpp -echo '#include "'$LUPREX'/ext/base-writer.hpp"' > Source/Integration/lpx-basewriter.hpp -echo '#include "'$LUPREX'/cpp/drv/drvutil.hpp"' > Source/Integration/lpx-drvutil.hpp -echo '#include "'$LUPREX'/cpp/drv/drvutil.cpp"' > Source/Integration/lpx-drvutil.cpp -echo '#include "'$LUPREX'/cpp/core/enginewrapper.hpp"' > Source/Integration/lpx-enginewrapper.hpp -echo '#define LUPREX_DLL_PATH "'$LUPREX'/build/linux/luprexlib.so"' > Source/Integration/lpx-paths.hpp -echo '#define LUPREX_ROOT_PATH "'$LUPREX'"' >> Source/Integration/lpx-paths.hpp +echo '#include "'$LUPREX'/ext/base-writer.hpp"' > Source/Integration/lpx-basewriter.hpp +echo '#include "'$LUPREX'/cpp/drv/drvutil.hpp"' > Source/Integration/lpx-drvutil.hpp +echo '#include "'$LUPREX'/cpp/drv/drvutil.cpp"' > Source/Integration/lpx-drvutil.cpp +echo '#include "'$LUPREX'/cpp/core/enginewrapper.hpp"' > Source/Integration/lpx-enginewrapper.hpp +echo '#define LUPREX_DLL_PATH "'$DLL'"' > Source/Integration/lpx-paths.hpp +echo '#define LUPREX_ROOT_PATH "'$LUPREX'"' >> Source/Integration/lpx-paths.hpp From e14b05a95d4af775b6ab1dc58f60b5234fc99197 Mon Sep 17 00:00:00 2001 From: jyelon Date: Wed, 18 Oct 2023 17:38:53 -0400 Subject: [PATCH 16/19] Renamed base-writer to base-buffer. --- Source/Integration/StringDecoder.h | 2 +- luprex-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Integration/StringDecoder.h b/Source/Integration/StringDecoder.h index b5d2abc8..79378c0c 100644 --- a/Source/Integration/StringDecoder.h +++ b/Source/Integration/StringDecoder.h @@ -1,7 +1,7 @@ #pragma once #include "CoreMinimal.h" -#include "lpx-basewriter.hpp" +#include "lpx-basebuffer.hpp" ///////////////////////////////////////////////////// // diff --git a/luprex-install.sh b/luprex-install.sh index e75119b7..8bd7e74f 100755 --- a/luprex-install.sh +++ b/luprex-install.sh @@ -12,7 +12,7 @@ LUPREX=$HOME/luprex rm -f Source/Integration/lpx-*.hpp rm -f Source/Integration/lpx-*.cpp -echo '#include "'$LUPREX'/ext/base-writer.hpp"' > Source/Integration/lpx-basewriter.hpp +echo '#include "'$LUPREX'/ext/base-buffer.hpp"' > Source/Integration/lpx-basebuffer.hpp echo '#include "'$LUPREX'/cpp/drv/drvutil.hpp"' > Source/Integration/lpx-drvutil.hpp echo '#include "'$LUPREX'/cpp/drv/drvutil.cpp"' > Source/Integration/lpx-drvutil.cpp echo '#include "'$LUPREX'/cpp/core/enginewrapper.hpp"' > Source/Integration/lpx-enginewrapper.hpp From 5381b5708a254f7ef81de79f948852301b8c1ce5 Mon Sep 17 00:00:00 2001 From: jyelon Date: Tue, 24 Oct 2023 01:44:09 -0400 Subject: [PATCH 17/19] Implement FlxStreamBuffer and beginnings of ConsoleCommands in unreal --- Source/Integration/AnimQueue.cpp | 76 ++++----- Source/Integration/AnimQueue.h | 24 +-- .../Integration/IntegrationGameModeBase.cpp | 35 ++-- Source/Integration/IntegrationGameModeBase.h | 3 + Source/Integration/StringDecoder.cpp | 36 ----- Source/Integration/StringDecoder.h | 151 ++++-------------- 6 files changed, 106 insertions(+), 219 deletions(-) diff --git a/Source/Integration/AnimQueue.cpp b/Source/Integration/AnimQueue.cpp index 78ce2563..cea94d5b 100644 --- a/Source/Integration/AnimQueue.cpp +++ b/Source/Integration/AnimQueue.cpp @@ -36,28 +36,28 @@ static bool SetProperty(const FString& prefix, UObject* obj, const FlxAnimationF FString sname(field.Name.size(), (const UTF8CHAR*)field.Name.data()); FName nname(prefix + sname); switch (field.Type) { - case ElxAnimValueType::STRING: { + case SimpleDynamicTag::STRING: { FStrProperty* fprop = FindFProperty(uclass, nname); if (fprop == nullptr) return false; FString* pptr = fprop->ContainerPtrToValuePtr(obj); *pptr = FString(field.S.size(), (const UTF8CHAR*)field.S.data()); return true; } - case ElxAnimValueType::NUMBER: { + case SimpleDynamicTag::NUMBER: { FDoubleProperty* fprop = FindFProperty(uclass, nname); if (fprop == nullptr) return false; double* pptr = fprop->ContainerPtrToValuePtr(obj); *pptr = field.X; return true; } - case ElxAnimValueType::BOOLEAN: { + case SimpleDynamicTag::BOOLEAN: { FBoolProperty* fprop = FindFProperty(uclass, nname); if (fprop == nullptr) return false; uint8* pptr = fprop->ContainerPtrToValuePtr(obj); fprop->SetPropertyValue(pptr, (field.X == 1.0)); return true; } - case ElxAnimValueType::XYZ: { + case SimpleDynamicTag::VECTOR: { FStructProperty* fprop = FindFProperty(uclass, nname); if (fprop == nullptr) return false; if (fprop->Struct != TBaseStructure::Get()) return false; @@ -84,7 +84,7 @@ bool FlxAnimationStep::Unpack(const FString& prefix, UObject* into) const { FlxAnimationField field; field.Name = "action"; field.Persistent = false; - field.Type = ElxAnimValueType::STRING; + field.Type = SimpleDynamicTag::STRING; field.S = "idle"; ok &= SetProperty(prefix, into, field); } @@ -110,7 +110,7 @@ static FlxAnimationField FindAnimationFieldLL(const FlxAnimationStep& step, std: return result; } } - result.Type = ElxAnimValueType::INVALID; + result.Type = SimpleDynamicTag::UNINITIALIZED; return result; } @@ -122,21 +122,21 @@ static FlxAnimationField FindAnimationField(const FlxAnimationStep& step, const void FlxAnimationStep::AutoUpdateXYZ(AActor *actor) const { FlxAnimationField xyz = FindAnimationFieldLL(*this, "xyz"); - if (xyz.Type == ElxAnimValueType::XYZ) { + if (xyz.Type == SimpleDynamicTag::VECTOR) { actor->SetActorLocation(FVector(xyz.X, xyz.Y, xyz.Z)); } } void FlxAnimationStep::AutoUpdateFacing(AActor *actor) const { FlxAnimationField facing = FindAnimationFieldLL(*this, "facing"); - if (facing.Type == ElxAnimValueType::NUMBER) { + if (facing.Type == SimpleDynamicTag::NUMBER) { actor->SetActorRotation(FRotator(0, facing.X, 0)); } } void FlxAnimationStep::AutoUpdatePlane(FName *planep) const { FlxAnimationField plane = FindAnimationFieldLL(*this, "plane"); - if (plane.Type == ElxAnimValueType::STRING) { + if (plane.Type == SimpleDynamicTag::STRING) { FString pname(plane.S.size(), (const UTF8CHAR*)(plane.S.data())); *planep = FName(pname); } @@ -152,13 +152,13 @@ bool UlxAnimationStepLibrary::AnimationStepIsIdle(const FlxAnimationStep &step) FVector UlxAnimationStepLibrary::AnimationStepGetVector(const FlxAnimationStep& step, const FString& name) { FlxAnimationField field = FindAnimationField(step, name); - if (field.Type != ElxAnimValueType::XYZ) return FVector(0, 0, 0); + if (field.Type != SimpleDynamicTag::VECTOR) return FVector(0, 0, 0); return FVector(field.X, field.Y, field.Z); } double UlxAnimationStepLibrary::AnimationStepGetFloat(const FlxAnimationStep& step, const FString& name) { FlxAnimationField field = FindAnimationField(step, name); - if (field.Type != ElxAnimValueType::NUMBER) return 0.0; + if (field.Type != SimpleDynamicTag::NUMBER) return 0.0; return field.X; } @@ -167,58 +167,44 @@ FString UlxAnimationStepLibrary::AnimationStepGetString(const FlxAnimationStep& return TEXT("idle"); } FlxAnimationField field = FindAnimationField(step, name); - if (field.Type != ElxAnimValueType::STRING) return TEXT(""); + if (field.Type != SimpleDynamicTag::STRING) return TEXT(""); return FString(field.S.size(), (const UTF8CHAR*)(field.S.data())); } bool UlxAnimationStepLibrary::AnimationStepGetBool(const FlxAnimationStep& step, const FString& name) { FlxAnimationField field = FindAnimationField(step, name); - if (field.Type != ElxAnimValueType::BOOLEAN) return false; + if (field.Type != SimpleDynamicTag::BOOLEAN) return false; return field.X == 1.0; } -FlxAnimationStepView FlxAnimQueueDecoder::ReadStep() { - FlxAnimationStepView result; - result.Hash = Decoder.read_uint64(); - result.Body = Decoder.read_string_view(); - return result; -} - -uint64 FlxAnimQueueDecoder::PeekHash() { - std::string_view rest = Decoder.GetRest(); - uint64 result = Decoder.read_uint64(); - Decoder.Reset(rest, false); - return result; -} FlxAnimationField FlxAnimationStepDecoder::ReadField() { FlxAnimationField result; result.Name = Decoder.read_string_view(); result.Persistent = Decoder.read_bool(); - result.Type = (ElxAnimValueType)Decoder.read_uint8(); + result.Type = (SimpleDynamicTag)Decoder.read_uint8(); switch (result.Type) { - case ElxAnimValueType::STRING: { + case SimpleDynamicTag::STRING: { result.S = Decoder.read_string_view(); break; } - case ElxAnimValueType::NUMBER: { + case SimpleDynamicTag::NUMBER: { result.X = Decoder.read_double(); break; } - case ElxAnimValueType::BOOLEAN: { + case SimpleDynamicTag::BOOLEAN: { result.X = Decoder.read_bool() ? 1.0 : 0.0; break; } - case ElxAnimValueType::XYZ: { + case SimpleDynamicTag::VECTOR: { result.X = Decoder.read_double(); result.Y = Decoder.read_double(); result.Z = Decoder.read_double(); break; } default: { - Decoder.set_at_eof(); - result.Type = ElxAnimValueType::BOOLEAN; - result.X = 0; + Decoder.read_bytes(Decoder.fill()); + result.Type = SimpleDynamicTag::UNINITIALIZED; break; } } @@ -239,16 +225,16 @@ FString FlxAnimationStepDecoder::DebugString(bool injectidle, bool persistentonl result.Append(FString(field.Name.size(), (const UTF8CHAR*)field.Name.data())); result.Append(field.Persistent ? TEXT("=") : TEXT(":")); switch (field.Type) { - case ElxAnimValueType::STRING: + case SimpleDynamicTag::STRING: result.Append(FString(field.S.size(), (const UTF8CHAR*)field.S.data())); break; - case ElxAnimValueType::NUMBER: + case SimpleDynamicTag::NUMBER: result.Appendf(TEXT("%lf"), field.X); break; - case ElxAnimValueType::BOOLEAN: + case SimpleDynamicTag::BOOLEAN: result.Append((field.X) == 1.0 ? TEXT("true") : TEXT("false")); break; - case ElxAnimValueType::XYZ: + case SimpleDynamicTag::VECTOR: result.Appendf(TEXT("%lf,%lf,%lf"), field.X, field.Y, field.Z); break; } @@ -256,6 +242,20 @@ FString FlxAnimationStepDecoder::DebugString(bool injectidle, bool persistentonl return result; } +FlxAnimationStepView FlxAnimQueueDecoder::ReadStep() { + FlxAnimationStepView result; + result.Hash = Decoder.read_uint64(); + result.Body = Decoder.read_string_view(); + return result; +} + +uint64 FlxAnimQueueDecoder::PeekHash() { + int64_t read_count = Decoder.total_reads(); + uint64 result = Decoder.read_uint64(); + Decoder.unread_to(read_count); + return result; +} + FlxAnimQueueDecoder::FlxAnimQueueDecoder(std::string_view queue) : Decoder(queue) { SizeLimit = Decoder.read_uint8(); ActualSize = Decoder.read_uint8(); diff --git a/Source/Integration/AnimQueue.h b/Source/Integration/AnimQueue.h index ff576088..52d0aa14 100644 --- a/Source/Integration/AnimQueue.h +++ b/Source/Integration/AnimQueue.h @@ -5,20 +5,6 @@ #include "Containers/Deque.h" #include "AnimQueue.generated.h" -//////////////////////////////////////////////// -// -// This is copied over from Luprex source. Not ideal. -// -//////////////////////////////////////////////// - -enum class ElxAnimValueType { - STRING, - NUMBER, - BOOLEAN, - XYZ, - INVALID -}; - //////////////////////////////////////////////// // // An single animation step. @@ -161,7 +147,7 @@ struct FlxAnimationStepView { struct FlxAnimationField { std::string_view Name; bool Persistent; - ElxAnimValueType Type; + SimpleDynamicTag Type; double X, Y, Z; std::string_view S; }; @@ -179,7 +165,7 @@ struct FlxAnimationField { class FlxAnimQueueDecoder { private: - FlxStringDecoder Decoder; + FlxStreamBuffer Decoder; // These values are immediately read from the header. // @@ -201,7 +187,7 @@ public: // Return true if the parser has reached the end of the string. // - bool AtEOF() { return Decoder.at_eof(); } + bool AtEOF() { return Decoder.empty(); } // Read one animation step. // @@ -229,7 +215,7 @@ public: class FlxAnimationStepDecoder { private: - FlxStringDecoder Decoder; + FlxStreamBuffer Decoder; public: // Initialize the FlxAnimationStepDecoder from the FlxAnimationStepView. @@ -238,7 +224,7 @@ public: // Return true if the parser has reached the end of the string. // - bool AtEOF() { return Decoder.at_eof(); } + bool AtEOF() { return Decoder.empty(); } // Read one field. // diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index 7cbcc519..8b965dc6 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -132,24 +132,41 @@ void AIntegrationGameModeBase::UpdateTangibles() { TangibleManager->DeleteFarawayTangibles(); } +void AIntegrationGameModeBase::ExecuteDebuggingCommand(const FString &fs) { + if (fs == "\\invokeplayer") { + // FlxLockedWrapper w(LockableWrapper); + // int64 player = w.GetActor(); + // w->play_invoke_player(w.Get(), player, datapk); + } else { + ConsoleOutput.AppendLine(TEXT("Unknown Command")); + } +} + + void AIntegrationGameModeBase::ConsoleSendInput(const FString& fs) { FlxLockedWrapper w(LockableWrapper); if (w->engine != nullptr) { - const TCHAR* fstchar = *fs; - if (sizeof(TCHAR) == 2) - { - ConsoleOutput.AppendLine(FString("> ") + fs); - std::u16string_view fsview((const char16_t*)fstchar, fs.Len()); - std::string utf8 = drvutil::utf16_to_utf8(fsview); - utf8 = utf8 + "\n"; - w->play_recv_incoming(w.Get(), 0, utf8.size(), utf8.c_str()); + ConsoleOutput.AppendLine(FString("> ") + fs); + // This is a bad way to do this. The problem is that if some + // lua code contains '\\', we'll catch it instead of passing it + // through. There's no simple solution, though. + if (fs[0] == '\\') { + ExecuteDebuggingCommand(fs); + } else { + const TCHAR* fstchar = *fs; + if (sizeof(TCHAR) == 2) + { + std::u16string_view fsview((const char16_t*)fstchar, fs.Len()); + std::string utf8 = drvutil::utf16_to_utf8(fsview); + utf8 = utf8 + "\n"; + w->play_recv_incoming(w.Get(), 0, utf8.size(), utf8.c_str()); + } } } } - void AIntegrationGameModeBase::Tick(float deltaseconds) { Super::Tick(deltaseconds); diff --git a/Source/Integration/IntegrationGameModeBase.h b/Source/Integration/IntegrationGameModeBase.h index da155315..62acb052 100644 --- a/Source/Integration/IntegrationGameModeBase.h +++ b/Source/Integration/IntegrationGameModeBase.h @@ -43,6 +43,9 @@ public: UPROPERTY(EditDefaultsOnly, Category = TangibleClasses) TSubclassOf ClassTangibleActor; + // Execute a debugging command, typed on the GUI. + void ExecuteDebuggingCommand(const FString &fs); + // Transfer console output from the Luprex engine to unreal. void UpdateConsoleOutput(); diff --git a/Source/Integration/StringDecoder.cpp b/Source/Integration/StringDecoder.cpp index a5b5a75f..a25b4a7a 100644 --- a/Source/Integration/StringDecoder.cpp +++ b/Source/Integration/StringDecoder.cpp @@ -1,38 +1,2 @@ #include "StringDecoder.h" -FlxStringDecoder::FlxStringDecoder(std::string_view s) { - Text = s.data(); - Size = s.size(); - ErrBeyondEOF = false; - ErrStringTooLong = false; -} - -void FlxStringDecoder::Reset(std::string_view s, bool clear) { - Text = s.data(); - Size = s.size(); - if (clear) { - ErrBeyondEOF = false; - ErrStringTooLong = false; - } -} - -std::string_view FlxStringDecoder::GetRest() { - return std::string_view(Text, Size); -} - -std::string_view FlxStringDecoder::read_string_view() { - size_t length = read_length(); - if (length > Size) { - ErrBeyondEOF = true; - return std::string_view(); - } - std::string_view result(Text, length); - Text += length; - Size -= length; - return result; -} - -void FlxStringDecoder::set_at_eof() { - Text += Size; - Size = 0; -} diff --git a/Source/Integration/StringDecoder.h b/Source/Integration/StringDecoder.h index 79378c0c..44ebf251 100644 --- a/Source/Integration/StringDecoder.h +++ b/Source/Integration/StringDecoder.h @@ -3,125 +3,42 @@ #include "CoreMinimal.h" #include "lpx-basebuffer.hpp" -///////////////////////////////////////////////////// -// -// FlxStringDecoder -// -// This class is used to decipher 8-bit strings that -// contain packed ints, strings, and other data. -// The typical example of usage is to decipher the -// serialized animation queues fed to us by Luprex. -// -// The FlxStringDecoder doesn't make a copy of the string -// you pass in, instead, it stores a pointer to it. -// So be sure not to free the string until you're -// done analyzing it. -// -// You'll note that some of the function names are -// lowercase, with underscores. That's because they're -// inherited from Luprex classes, and luprex classes -// use that naming convention. There's not any easy -// workaround for that. -// -///////////////////////////////////////////////////// - -class FlxStringDecoder : public BaseReader { +class FlxStreamBufferCore { private: - const char* Text; - size_t Size; + bool err_eof_on_read_; + bool err_string_too_long_; + bool err_integer_truncated_; +protected: -public: - // You can check and clear these error flags at will. - // - bool ErrBeyondEOF; - bool ErrStringTooLong; - -public: - // This function is required by BaseReader. - // It's not meant for end users. - // - void read_bytes_into(char* buffer, size_t size) { - if (size > Size) { - memset(buffer, 0, size); - ErrBeyondEOF = true; - set_at_eof(); - } - else { - memcpy(buffer, Text, size); - Text += size; - Size -= size; - } - } - - // This function is required by BaseReader. - // It's not meant for end users. - // - void raise_string_too_long() { - ErrStringTooLong = true; - } - -public: - // The type returned by read_string. - // - using read_string_type = std::string; - - // Initialize the string decoder with a text to analyze. - // - FlxStringDecoder(std::string_view s); - - // Get the remaining text as a string_view. - // - std::string_view GetRest(); - - // Reinitialize with a new string_view. - // - // If clear is true, clears the error flags. - // - void Reset(std::string_view s, bool clear); - - // Get the size of the remaining text. - // - size_t get_size() { return Size; } + void *basebuffer_malloc(size_t size) { return malloc(size); } + void basebuffer_free(void *p) { free(p); } + void clear_error_flags() { err_eof_on_read_ = err_string_too_long_ = err_integer_truncated_ = false; } + void raise_eof_on_read() { err_eof_on_read_ = true; } + void raise_string_too_long() { err_string_too_long_ = true; } + void raise_integer_truncated() { err_integer_truncated_ = true; } - // Return true if the remaining text is empty. - // - bool at_eof() { return Size == 0; } - - // Move the cursor to EOF. - // - void set_at_eof(); - - - // Read a string as a string_view - // - // This reads a string from the source, returning - // it as a string_view that points into the buffer. - // Naturally, if you release the buffer, the - // string_view is invalidated. - // - // This is considerably faster than read_string. - // - std::string_view read_string_view(); - - // Inherited Methods: - // - // The following methods are inherited from BaseReader: - // - // uint8_t read_uint8(); - // uint16_t read_uint16(); - // uint32_t read_uint32(); - // uint64_t read_uint64(); - // int8_t read_int8(); - // int16_t read_int16(); - // int32_t read_int32(); - // int64_t read_int64(); - // bool read_bool(); - // char read_char(); - // float read_float(); - // double read_double(); - // size_t read_length(); - // std::string read_string_limit(uint64_t size); - // std::string read_string(); - // + bool get_err_eof_on_read() const { return err_eof_on_read_; } + bool get_err_string_too_long() const { return err_string_too_long_; } + bool get_err_integer_truncated() const { return err_integer_truncated_; } + bool any_error() const { return err_eof_on_read_ || err_string_too_long_ || err_integer_truncated_; } }; + +class FlxStreamBuffer : public BaseBuffer { +public: + using BaseBuffer::BaseBuffer; + + void write_dxyz(const FVector &xyz) { + write_double(xyz.X); + write_double(xyz.Y); + write_double(xyz.Z); + } + + FVector read_dxyz() { + double x = read_double(); + double y = read_double(); + double z = read_double(); + return FVector(x, y, z); + } +}; + From 0ccc08c7dcc48a54868785c7b2e303574a8ad030 Mon Sep 17 00:00:00 2001 From: jyelon Date: Tue, 24 Oct 2023 17:12:03 -0400 Subject: [PATCH 18/19] Implement initial engio experiments --- Source/Integration/IntegrationGameModeBase.cpp | 16 +++++++++++++--- Source/Integration/StringDecoder.h | 6 ++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index 8b965dc6..342e54fb 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -134,9 +134,19 @@ void AIntegrationGameModeBase::UpdateTangibles() { void AIntegrationGameModeBase::ExecuteDebuggingCommand(const FString &fs) { if (fs == "\\invokeplayer") { - // FlxLockedWrapper w(LockableWrapper); - // int64 player = w.GetActor(); - // w->play_invoke_player(w.Get(), player, datapk); + DPrint(TEXT("Trying to invoke 'myfunction' in lua")); + FlxLockedWrapper w(LockableWrapper); + FlxStreamBuffer sb; + sb.write_string("myfunction"); + sb.write_simple_dynamic_tag(SimpleDynamicTag::NUMBER); + sb.write_double(3.0); + sb.write_simple_dynamic_tag(SimpleDynamicTag::STRING); + sb.write_string("Howdy"); + sb.write_simple_dynamic_tag(SimpleDynamicTag::BOOLEAN); + sb.write_bool(true); + std::string_view datapk = sb.view(); + int64 player = w.GetActor(); + w->play_invoke_engio(w.Get(), player, datapk.size(), datapk.data()); } else { ConsoleOutput.AppendLine(TEXT("Unknown Command")); } diff --git a/Source/Integration/StringDecoder.h b/Source/Integration/StringDecoder.h index 44ebf251..0527f8ff 100644 --- a/Source/Integration/StringDecoder.h +++ b/Source/Integration/StringDecoder.h @@ -4,6 +4,8 @@ #include "lpx-basebuffer.hpp" +using FlxSimpleDynamic = SimpleDynamic; + class FlxStreamBufferCore { private: bool err_eof_on_read_; @@ -28,13 +30,13 @@ class FlxStreamBuffer : public BaseBuffer { public: using BaseBuffer::BaseBuffer; - void write_dxyz(const FVector &xyz) { + void write_dvector(const FVector &xyz) { write_double(xyz.X); write_double(xyz.Y); write_double(xyz.Z); } - FVector read_dxyz() { + FVector read_dvector() { double x = read_double(); double y = read_double(); double z = read_double(); From 265c2462be9f9bae90f999a87c16d34dab2b2784 Mon Sep 17 00:00:00 2001 From: jyelon Date: Tue, 31 Oct 2023 13:33:00 -0400 Subject: [PATCH 19/19] Engio invocation successful --- Source/Integration/IntegrationGameModeBase.cpp | 4 ++-- Source/Integration/StringDecoder.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Integration/IntegrationGameModeBase.cpp b/Source/Integration/IntegrationGameModeBase.cpp index 342e54fb..ce4d277b 100644 --- a/Source/Integration/IntegrationGameModeBase.cpp +++ b/Source/Integration/IntegrationGameModeBase.cpp @@ -142,8 +142,8 @@ void AIntegrationGameModeBase::ExecuteDebuggingCommand(const FString &fs) { sb.write_double(3.0); sb.write_simple_dynamic_tag(SimpleDynamicTag::STRING); sb.write_string("Howdy"); - sb.write_simple_dynamic_tag(SimpleDynamicTag::BOOLEAN); - sb.write_bool(true); + sb.write_simple_dynamic_tag(SimpleDynamicTag::VECTOR); + sb.write_fvector(FVector(2,3,4)); std::string_view datapk = sb.view(); int64 player = w.GetActor(); w->play_invoke_engio(w.Get(), player, datapk.size(), datapk.data()); diff --git a/Source/Integration/StringDecoder.h b/Source/Integration/StringDecoder.h index 0527f8ff..6ddec598 100644 --- a/Source/Integration/StringDecoder.h +++ b/Source/Integration/StringDecoder.h @@ -30,13 +30,13 @@ class FlxStreamBuffer : public BaseBuffer { public: using BaseBuffer::BaseBuffer; - void write_dvector(const FVector &xyz) { + void write_fvector(const FVector &xyz) { write_double(xyz.X); write_double(xyz.Y); write_double(xyz.Z); } - FVector read_dvector() { + FVector read_fvector() { double x = read_double(); double y = read_double(); double z = read_double();