From 20d5b113e9bc34816458497ea18471babf80c42f Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Fri, 1 May 2026 22:54:00 +0200 Subject: [PATCH] Expose imported runtime surface selectors at runtime --- .../HyperTwistTrainingCatalogLibrary.cpp | 93 +++++++++++++++++++ .../HyperTwistTrainingRuntimeLibrary.cpp | 44 +++++++++ .../HyperTwistTrainingSubsystem.cpp | 34 +++++++ .../HyperTwistTrainingCatalogLibrary.h | 20 ++++ .../HyperTwistTrainingRuntimeLibrary.h | 20 ++++ .../HyperTwistTrainingSubsystem.h | 15 +++ 6 files changed, 226 insertions(+) diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCatalogLibrary.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCatalogLibrary.cpp index 243fbf7..2175bc1 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCatalogLibrary.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCatalogLibrary.cpp @@ -256,6 +256,28 @@ namespace HyperTwistTrainingCatalogLibraryInternal return ToTitleLabel(MethodKey); } + bool DoesSelectorOptionMatchCase( + const FHyperTwistTrainingImportedRuntimeSelectorOption& Option, + const FHyperTwistTrainingCase& TrainingCase + ) + { + if (!Option.IsStructurallyValid() || !TrainingCase.IsStructurallyValid()) + { + return false; + } + + if (TrainingCase.SourceAttribution.SourceCaseId.Equals(Option.OptionValue, ESearchCase::IgnoreCase) + || TrainingCase.SourceAttribution.SourceCaseId.Equals(Option.OptionId, ESearchCase::IgnoreCase)) + { + return true; + } + + const FString ExpectedCaseSuffixA = FString::Printf(TEXT("/%s"), *Option.OptionValue); + const FString ExpectedCaseSuffixB = FString::Printf(TEXT("/%s"), *Option.OptionId); + return TrainingCase.CaseId.EndsWith(ExpectedCaseSuffixA, ESearchCase::IgnoreCase) + || TrainingCase.CaseId.EndsWith(ExpectedCaseSuffixB, ESearchCase::IgnoreCase); + } + FString TemplateKindToTag(EHyperTwistTrainingSessionTemplateKind TemplateKind) { switch (TemplateKind) @@ -2667,6 +2689,77 @@ bool UHyperTwistTrainingCatalogLibrary::TryGetDefaultDeckFromContentPack( return OutDeck.IsStructurallyValid(); } +bool UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck( + const FHyperTwistTrainingDeck& Deck, + FHyperTwistTrainingImportedRuntimeSurface& OutRuntimeSurface +) +{ + OutRuntimeSurface = FHyperTwistTrainingImportedRuntimeSurface(); + if (!Deck.IsStructurallyValid() || !Deck.ImportedRuntimeSurface.IsStructurallyValid()) + { + return false; + } + + OutRuntimeSurface = Deck.ImportedRuntimeSurface; + return OutRuntimeSurface.IsStructurallyValid(); +} + +bool UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSelectorFromDeck( + const FHyperTwistTrainingDeck& Deck, + const FString& SelectorId, + FHyperTwistTrainingImportedRuntimeSelector& OutSelector +) +{ + OutSelector = FHyperTwistTrainingImportedRuntimeSelector(); + FHyperTwistTrainingImportedRuntimeSurface RuntimeSurface; + if (!TryGetImportedRuntimeSurfaceFromDeck(Deck, RuntimeSurface) || SelectorId.IsEmpty()) + { + return false; + } + + for (const FHyperTwistTrainingImportedRuntimeSelector& Selector : RuntimeSurface.Selectors) + { + if (Selector.SelectorId == SelectorId) + { + OutSelector = Selector; + return OutSelector.IsStructurallyValid(); + } + } + + return false; +} + +bool UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSelectorOptionCasesFromDeck( + const FHyperTwistTrainingDeck& Deck, + const FString& SelectorId, + TArray& OutCases +) +{ + OutCases.Reset(); + + FHyperTwistTrainingImportedRuntimeSelector Selector; + if (!TryGetImportedRuntimeSelectorFromDeck(Deck, SelectorId, Selector) || Selector.Options.Num() == 0) + { + return false; + } + + for (const FHyperTwistTrainingImportedRuntimeSelectorOption& Option : Selector.Options) + { + const FHyperTwistTrainingCase* MatchingCase = Deck.Cases.FindByPredicate( + [&Option](const FHyperTwistTrainingCase& Candidate) + { + return HyperTwistTrainingCatalogLibraryInternal::DoesSelectorOptionMatchCase(Option, Candidate); + } + ); + if (MatchingCase != nullptr) + { + OutCases.Add(*MatchingCase); + } + } + + return OutCases.Num() > 0; +} + FHyperTwistTrainingMethodDescriptor UHyperTwistTrainingCatalogLibrary::DescribeTrainingDeckMethod( const FHyperTwistTrainingDeck& Deck ) diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.cpp index a674a99..4596800 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.cpp @@ -58,6 +58,50 @@ FHyperTwistTrainingRunState UHyperTwistTrainingRuntimeLibrary::GetActiveTraining return FHyperTwistTrainingRunState(); } +bool UHyperTwistTrainingRuntimeLibrary::TryGetActiveImportedRuntimeSurface( + UObject* WorldContextObject, + FHyperTwistTrainingImportedRuntimeSurface& OutRuntimeSurface +) +{ + if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject)) + { + return TrainingSubsystem->TryGetActiveImportedRuntimeSurface(OutRuntimeSurface); + } + + OutRuntimeSurface = FHyperTwistTrainingImportedRuntimeSurface(); + return false; +} + +bool UHyperTwistTrainingRuntimeLibrary::TryGetActiveImportedRuntimeSelector( + UObject* WorldContextObject, + const FString& SelectorId, + FHyperTwistTrainingImportedRuntimeSelector& OutSelector +) +{ + if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject)) + { + return TrainingSubsystem->TryGetActiveImportedRuntimeSelector(SelectorId, OutSelector); + } + + OutSelector = FHyperTwistTrainingImportedRuntimeSelector(); + return false; +} + +bool UHyperTwistTrainingRuntimeLibrary::TryGetActiveImportedRuntimeSelectorOptionCases( + UObject* WorldContextObject, + const FString& SelectorId, + TArray& OutCases +) +{ + if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject)) + { + return TrainingSubsystem->TryGetActiveImportedRuntimeSelectorOptionCases(SelectorId, OutCases); + } + + OutCases.Reset(); + return false; +} + FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingRuntimeLibrary::GetActiveMethodDrillRunState( UObject* WorldContextObject ) diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp index c16e56e..36bb8d9 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp @@ -711,6 +711,40 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::GetActiveRunState() co return ActiveRunState; } +bool UHyperTwistTrainingSubsystem::TryGetActiveImportedRuntimeSurface( + FHyperTwistTrainingImportedRuntimeSurface& OutRuntimeSurface +) const +{ + return UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck( + ActiveRunState.ActiveDeck, + OutRuntimeSurface + ); +} + +bool UHyperTwistTrainingSubsystem::TryGetActiveImportedRuntimeSelector( + const FString& SelectorId, + FHyperTwistTrainingImportedRuntimeSelector& OutSelector +) const +{ + return UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSelectorFromDeck( + ActiveRunState.ActiveDeck, + SelectorId, + OutSelector + ); +} + +bool UHyperTwistTrainingSubsystem::TryGetActiveImportedRuntimeSelectorOptionCases( + const FString& SelectorId, + TArray& OutCases +) const +{ + return UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSelectorOptionCasesFromDeck( + ActiveRunState.ActiveDeck, + SelectorId, + OutCases + ); +} + FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::GetActiveMethodDrillRunState() const { return ActiveMethodDrillRunState; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCatalogLibrary.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCatalogLibrary.h index 6700370..ae5ae36 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCatalogLibrary.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCatalogLibrary.h @@ -134,6 +134,26 @@ public: FHyperTwistTrainingDeck& OutDeck ); + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Catalog") + static bool TryGetImportedRuntimeSurfaceFromDeck( + const FHyperTwistTrainingDeck& Deck, + FHyperTwistTrainingImportedRuntimeSurface& OutRuntimeSurface + ); + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Catalog") + static bool TryGetImportedRuntimeSelectorFromDeck( + const FHyperTwistTrainingDeck& Deck, + const FString& SelectorId, + FHyperTwistTrainingImportedRuntimeSelector& OutSelector + ); + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Catalog") + static bool TryGetImportedRuntimeSelectorOptionCasesFromDeck( + const FHyperTwistTrainingDeck& Deck, + const FString& SelectorId, + TArray& OutCases + ); + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Catalog") static FHyperTwistTrainingMethodDescriptor DescribeTrainingDeckMethod( const FHyperTwistTrainingDeck& Deck diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.h index 2d0dd99..96afd0c 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.h @@ -28,6 +28,26 @@ public: UFUNCTION(BlueprintPure, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject")) static FHyperTwistTrainingRunState GetActiveTrainingRunState(UObject* WorldContextObject); + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject")) + static bool TryGetActiveImportedRuntimeSurface( + UObject* WorldContextObject, + FHyperTwistTrainingImportedRuntimeSurface& OutRuntimeSurface + ); + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject")) + static bool TryGetActiveImportedRuntimeSelector( + UObject* WorldContextObject, + const FString& SelectorId, + FHyperTwistTrainingImportedRuntimeSelector& OutSelector + ); + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject")) + static bool TryGetActiveImportedRuntimeSelectorOptionCases( + UObject* WorldContextObject, + const FString& SelectorId, + TArray& OutCases + ); + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject")) static FHyperTwistTrainingMethodDrillRunState GetActiveMethodDrillRunState(UObject* WorldContextObject); diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSubsystem.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSubsystem.h index 6e0137b..4caf483 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSubsystem.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSubsystem.h @@ -23,6 +23,21 @@ public: UFUNCTION(BlueprintPure, Category = "HyperTwist|Training") FHyperTwistTrainingRunState GetActiveRunState() const; + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training") + bool TryGetActiveImportedRuntimeSurface(FHyperTwistTrainingImportedRuntimeSurface& OutRuntimeSurface) const; + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training") + bool TryGetActiveImportedRuntimeSelector( + const FString& SelectorId, + FHyperTwistTrainingImportedRuntimeSelector& OutSelector + ) const; + + UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training") + bool TryGetActiveImportedRuntimeSelectorOptionCases( + const FString& SelectorId, + TArray& OutCases + ) const; + UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill") FHyperTwistTrainingMethodDrillRunState GetActiveMethodDrillRunState() const;