diff --git a/.idea/.idea.HyperTwist.dir/.idea/betterCommentsSettings.xml b/.idea/.idea.HyperTwist.dir/.idea/betterCommentsSettings.xml
new file mode 100644
index 0000000..4f152ed
--- /dev/null
+++ b/.idea/.idea.HyperTwist.dir/.idea/betterCommentsSettings.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.HyperTwist.dir/.idea/indexLayout.xml b/.idea/.idea.HyperTwist.dir/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.HyperTwist.dir/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.HyperTwist.dir/.idea/projectSettingsUpdater.xml b/.idea/.idea.HyperTwist.dir/.idea/projectSettingsUpdater.xml
new file mode 100644
index 0000000..ef20cb0
--- /dev/null
+++ b/.idea/.idea.HyperTwist.dir/.idea/projectSettingsUpdater.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.HyperTwist.dir/.idea/vcs.xml b/.idea/.idea.HyperTwist.dir/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/.idea.HyperTwist.dir/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.HyperTwist.dir/.idea/workspace.xml b/.idea/.idea.HyperTwist.dir/.idea/workspace.xml
new file mode 100644
index 0000000..58a12ee
--- /dev/null
+++ b/.idea/.idea.HyperTwist.dir/.idea/workspace.xml
@@ -0,0 +1,107 @@
+
+
+
+ HyperTwist.vcxproj
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1777910478151
+
+
+ 1777910478151
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.HyperTwist/.idea/.gitignore b/.idea/.idea.HyperTwist/.idea/.gitignore
new file mode 100644
index 0000000..0f3e92c
--- /dev/null
+++ b/.idea/.idea.HyperTwist/.idea/.gitignore
@@ -0,0 +1,15 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/projectSettingsUpdater.xml
+/.idea.HyperTwist.iml
+/contentModel.xml
+/modules.xml
+# Ignored default folder with query files
+/queries/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/.idea.HyperTwist/.idea/betterCommentsSettings.xml b/.idea/.idea.HyperTwist/.idea/betterCommentsSettings.xml
new file mode 100644
index 0000000..4f152ed
--- /dev/null
+++ b/.idea/.idea.HyperTwist/.idea/betterCommentsSettings.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.HyperTwist/.idea/indexLayout.xml b/.idea/.idea.HyperTwist/.idea/indexLayout.xml
new file mode 100644
index 0000000..ad10ff1
--- /dev/null
+++ b/.idea/.idea.HyperTwist/.idea/indexLayout.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ .
+ ../Workspaces
+ ../visual_studio_solutions/multi_project
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.HyperTwist/.idea/vcs.xml b/.idea/.idea.HyperTwist/.idea/vcs.xml
new file mode 100644
index 0000000..52ea7ec
--- /dev/null
+++ b/.idea/.idea.HyperTwist/.idea/vcs.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp
index c6b6a62..b736035 100644
--- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp
+++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp
@@ -3682,12 +3682,13 @@ bool UHyperTwistCoachDashboardWidget::ContinueCurrentRunFlow()
if (bSucceeded)
{
LastStepResult = FHyperTwistTrainingRunStepResult();
- RefreshTrainingState();
- SyncRetainedRunRecap();
- SyncSelectedQueueEntry();
- SyncSelectedAttempt();
- UpdateDashboardPresentation();
}
+
+ RefreshTrainingState();
+ SyncRetainedRunRecap();
+ SyncSelectedQueueEntry();
+ SyncSelectedAttempt();
+ UpdateDashboardPresentation();
}
else if (CachedRunState.Session.IsStructurallyValid() && CachedRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
{
@@ -10246,19 +10247,9 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
&& LastStepResult.AttemptResolution.NextCaseSelection.IsStructurallyValid();
const bool bGeneratedModeLaunchDeck =
HyperTwistCoachDashboardWidgetInternal::IsGeneratedModeLaunchDeck(CachedRunState);
- const bool bCanExecuteGeneratedModeLaunch = [this, bGeneratedModeLaunchDeck]()
- {
- if (!bGeneratedModeLaunchDeck)
- {
- return false;
- }
-
- FHyperTwistTrainingImportedGeneratedModeLaunchConfig ActiveGeneratedModeLaunchConfig;
- return UHyperTwistTrainingRuntimeLibrary::TryGetActiveImportedGeneratedModeLaunchConfig(
- this,
- ActiveGeneratedModeLaunchConfig
- );
- }();
+ const bool bCanExecuteGeneratedModeLaunch =
+ bGeneratedModeLaunchDeck
+ && CachedCoachPanelState.bCanExecuteActiveGeneratedModeLaunchRequest;
const bool bCanContinueCurrentRun = !bHasLiveAttemptTimer
&& bHasRunnableCurrentCase
&& !bLastStepCompletedRun
@@ -10308,8 +10299,12 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
}
else if (bGeneratedModeLaunchDeck && !bCanExecuteGeneratedModeLaunch)
{
- TransitionStatusLine =
- TEXT("Transition: generated-mode selectors are still incomplete. Finish the active selector choices before executing the owned generated run.");
+ TransitionStatusLine = CachedCoachPanelState.ActiveGeneratedModeExecutionBlockedReason.IsEmpty()
+ ? TEXT("Transition: generated-mode selectors are still incomplete. Finish the active selector choices before executing the owned generated run.")
+ : FString::Printf(
+ TEXT("Transition: %s"),
+ *CachedCoachPanelState.ActiveGeneratedModeExecutionBlockedReason
+ );
}
else if (bCanContinueCurrentRun)
{
@@ -10320,8 +10315,11 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
if (bGeneratedModeLaunchDeck)
{
TransitionStatusLine = FString::Printf(
- TEXT("Transition: generated-mode request is staged on %s. Execute the owned generated run when ready."),
- *TransitionPrompt
+ TEXT("Transition: generated-mode request is staged on %s. Execute the owned generated run%s."),
+ *TransitionPrompt,
+ CachedCoachPanelState.bActiveGeneratedModeExecutionWillRefreshLaunchRequest
+ ? TEXT("; the stored request will refresh on execute")
+ : TEXT(" when ready")
);
}
else if (bHasNextCaseFromLastStep)
@@ -15661,8 +15659,21 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
: *CachedCoachPanelState.LatestGeneratedModeSelectorSummaryLine
)
: TEXT("\nGenerated request: none for active deck");
+ const FString GeneratedExecutionDetail =
+ CachedCoachPanelState.bHasActiveGeneratedModeExecutionTarget
+ ? FString::Printf(
+ TEXT("\nGenerated execution ready: %s | Request refresh on execute: %s | Blocked: %s"),
+ CachedCoachPanelState.bCanExecuteActiveGeneratedModeLaunchRequest ? TEXT("yes") : TEXT("no"),
+ CachedCoachPanelState.bActiveGeneratedModeExecutionWillRefreshLaunchRequest
+ ? TEXT("yes")
+ : TEXT("no"),
+ CachedCoachPanelState.ActiveGeneratedModeExecutionBlockedReason.IsEmpty()
+ ? TEXT("none")
+ : *CachedCoachPanelState.ActiveGeneratedModeExecutionBlockedReason
+ )
+ : TEXT("");
VerificationDetailTextBlock->SetText(FText::FromString(FString::Printf(
- TEXT("Path: %s\nRound-trip pass: %s | Save: %s | Load: %s | Count parity: %s | State parity: %s | Integrity parity: %s\nRuns %d/%d | Learners %d/%d | Reviews %d/%d | Plans %d/%d | Queues %d/%d | History %d/%d | Notes: %s%s"),
+ TEXT("Path: %s\nRound-trip pass: %s | Save: %s | Load: %s | Count parity: %s | State parity: %s | Integrity parity: %s\nRuns %d/%d | Learners %d/%d | Reviews %d/%d | Plans %d/%d | Queues %d/%d | History %d/%d | Notes: %s%s%s"),
CachedRepositoryRoundTripVerification.ResolvedPath.IsEmpty()
? TEXT("not yet verified")
: *CachedRepositoryRoundTripVerification.ResolvedPath,
@@ -15685,7 +15696,8 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
CachedRepositoryRoundTripVerification.LoadedCoachSessionQueueHistoryCount,
CachedRepositoryRoundTripVerification.ExpectedCoachSessionQueueHistoryCount,
*VerificationNotePreview,
- *GeneratedLaunchRequestDetail
+ *GeneratedLaunchRequestDetail,
+ *GeneratedExecutionDetail
)));
}
diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp
index 5d7e18e..38f1b56 100644
--- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp
+++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp
@@ -254,6 +254,139 @@ namespace HyperTwistTrainingSubsystemInternal
);
}
+ bool DoGeneratedModeSelectorChoiceSetsMatch(
+ const TArray& Selectors,
+ const TArray& LeftChoices,
+ const TArray& RightChoices
+ )
+ {
+ for (const FHyperTwistTrainingImportedRuntimeSelector& Selector : Selectors)
+ {
+ const FHyperTwistTrainingImportedRuntimeSelectorChoice* LeftChoice =
+ LeftChoices.FindByPredicate(
+ [&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
+ {
+ return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
+ }
+ );
+ const FHyperTwistTrainingImportedRuntimeSelectorChoice* RightChoice =
+ RightChoices.FindByPredicate(
+ [&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
+ {
+ return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
+ }
+ );
+ if (LeftChoice == nullptr || RightChoice == nullptr)
+ {
+ return false;
+ }
+ if (LeftChoice->SelectedValue != RightChoice->SelectedValue)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool DoesGeneratedModeLaunchRequestMatchLaunchConfig(
+ const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest,
+ const FHyperTwistTrainingImportedRuntimeSurface& RuntimeSurface,
+ const FHyperTwistTrainingImportedGeneratedModeLaunchConfig& ExpectedLaunchConfig
+ )
+ {
+ return LaunchRequest.IsStructurallyValid()
+ && LaunchRequest.LaunchConfig.DeckId == ExpectedLaunchConfig.DeckId
+ && LaunchRequest.LaunchConfig.SurfaceId == ExpectedLaunchConfig.SurfaceId
+ && LaunchRequest.LaunchConfig.RuntimeModeId.Equals(
+ ExpectedLaunchConfig.RuntimeModeId,
+ ESearchCase::IgnoreCase
+ )
+ && DoGeneratedModeSelectorChoiceSetsMatch(
+ RuntimeSurface.Selectors,
+ LaunchRequest.LaunchConfig.SelectorChoices,
+ ExpectedLaunchConfig.SelectorChoices
+ );
+ }
+
+ bool TryResolveGeneratedModeExecutionLaunchConfig(
+ const FHyperTwistTrainingRunState& RunState,
+ const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& ExistingLaunchRequest,
+ FHyperTwistTrainingImportedGeneratedModeLaunchConfig& OutLaunchConfig,
+ bool& bOutRequiresLaunchRequestRefresh,
+ FString& OutBlockedReason
+ )
+ {
+ OutLaunchConfig = FHyperTwistTrainingImportedGeneratedModeLaunchConfig();
+ bOutRequiresLaunchRequestRefresh = false;
+ OutBlockedReason.Reset();
+
+ if (!RunState.IsStructurallyValid())
+ {
+ OutBlockedReason = TEXT("Generated-mode execution requires an active training run.");
+ return false;
+ }
+
+ FHyperTwistTrainingImportedRuntimeSurface RuntimeSurface;
+ if (!UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck(
+ RunState.ActiveDeck,
+ RuntimeSurface)
+ || !RuntimeSurface.IsStructurallyValid()
+ || !RuntimeSurface.SurfaceKind.Equals(TEXT("generated-mode"), ESearchCase::IgnoreCase))
+ {
+ OutBlockedReason = TEXT("Active run is not a generated-mode imported runtime surface.");
+ return false;
+ }
+
+ if (!RunState.ImportedRuntimeSelectionState.IsStructurallyValid()
+ || RunState.ImportedRuntimeSelectionState.SurfaceId != RuntimeSurface.SurfaceId
+ || !RunState.ImportedRuntimeSelectionState.SurfaceKind.Equals(
+ RuntimeSurface.SurfaceKind,
+ ESearchCase::IgnoreCase))
+ {
+ OutBlockedReason =
+ TEXT("Generated-mode execution requires imported selector state that matches the active runtime surface.");
+ return false;
+ }
+
+ for (const FHyperTwistTrainingImportedRuntimeSelector& Selector : RuntimeSurface.Selectors)
+ {
+ const FHyperTwistTrainingImportedRuntimeSelectorChoice* ActiveChoice =
+ RunState.ImportedRuntimeSelectionState.SelectorChoices.FindByPredicate(
+ [&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
+ {
+ return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
+ }
+ );
+ if (ActiveChoice == nullptr)
+ {
+ OutBlockedReason = FString::Printf(
+ TEXT("Generated-mode execution is blocked because selector %s is unresolved."),
+ *Selector.Label
+ );
+ return false;
+ }
+ }
+
+ if (!UHyperTwistTrainingCatalogLibrary::TryBuildImportedGeneratedModeLaunchConfig(
+ RunState.ActiveDeck,
+ RunState.ImportedRuntimeSelectionState,
+ RunState.Session,
+ OutLaunchConfig))
+ {
+ OutBlockedReason =
+ TEXT("Generated-mode execution could not derive a structurally valid launch request from the active selector state.");
+ return false;
+ }
+
+ bOutRequiresLaunchRequestRefresh = !DoesGeneratedModeLaunchRequestMatchLaunchConfig(
+ ExistingLaunchRequest,
+ RuntimeSurface,
+ OutLaunchConfig
+ );
+ return true;
+ }
+
bool TryBuildGeneratedModeExecutionDeck(
const FHyperTwistTrainingDeck& SourceDeck,
const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest,
@@ -1131,75 +1264,24 @@ bool UHyperTwistTrainingSubsystem::TryExecuteActiveImportedGeneratedModeLaunchRe
OutRunState = FHyperTwistTrainingRunState();
OutBlockedReason.Reset();
- if (!HasActiveRun() || !ActiveRunState.IsStructurallyValid())
+ if (!HasActiveRun())
{
OutBlockedReason = TEXT("Generated-mode execution requires an active training run.");
return false;
}
- FHyperTwistTrainingImportedRuntimeSurface RuntimeSurface;
- if (!UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck(
- ActiveRunState.ActiveDeck,
- RuntimeSurface)
- || !RuntimeSurface.IsStructurallyValid()
- || !RuntimeSurface.SurfaceKind.Equals(TEXT("generated-mode"), ESearchCase::IgnoreCase))
- {
- OutBlockedReason = TEXT("Active run is not a generated-mode imported runtime surface.");
- return false;
- }
-
- if (!ActiveRunState.ImportedRuntimeSelectionState.IsStructurallyValid()
- || ActiveRunState.ImportedRuntimeSelectionState.SurfaceId != RuntimeSurface.SurfaceId
- || !ActiveRunState.ImportedRuntimeSelectionState.SurfaceKind.Equals(
- RuntimeSurface.SurfaceKind,
- ESearchCase::IgnoreCase))
- {
- OutBlockedReason = TEXT("Generated-mode execution requires imported selector state that matches the active runtime surface.");
- return false;
- }
-
+ FHyperTwistTrainingImportedGeneratedModeLaunchConfig ExpectedLaunchConfig;
FHyperTwistTrainingImportedGeneratedModeLaunchRequest LaunchRequest =
ActiveImportedGeneratedModeLaunchRequest;
- bool bNeedsFreshLaunchRequest = !LaunchRequest.IsStructurallyValid();
- if (!bNeedsFreshLaunchRequest
- && (LaunchRequest.LaunchConfig.DeckId != ActiveRunState.ActiveDeck.DeckId
- || LaunchRequest.LaunchConfig.SurfaceId != RuntimeSurface.SurfaceId
- || !LaunchRequest.LaunchConfig.RuntimeModeId.Equals(
- RuntimeSurface.RuntimeModeId,
- ESearchCase::IgnoreCase)))
+ bool bNeedsFreshLaunchRequest = false;
+ if (!HyperTwistTrainingSubsystemInternal::TryResolveGeneratedModeExecutionLaunchConfig(
+ ActiveRunState,
+ LaunchRequest,
+ ExpectedLaunchConfig,
+ bNeedsFreshLaunchRequest,
+ OutBlockedReason))
{
- bNeedsFreshLaunchRequest = true;
- }
-
- for (const FHyperTwistTrainingImportedRuntimeSelector& Selector : RuntimeSurface.Selectors)
- {
- const FHyperTwistTrainingImportedRuntimeSelectorChoice* ActiveChoice =
- ActiveRunState.ImportedRuntimeSelectionState.SelectorChoices.FindByPredicate(
- [&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
- {
- return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
- }
- );
- if (ActiveChoice == nullptr)
- {
- OutBlockedReason = FString::Printf(
- TEXT("Generated-mode execution is blocked because selector %s is unresolved."),
- *Selector.Label
- );
- return false;
- }
-
- const FHyperTwistTrainingImportedRuntimeSelectorChoice* RequestChoice =
- LaunchRequest.LaunchConfig.SelectorChoices.FindByPredicate(
- [&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
- {
- return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
- }
- );
- if (RequestChoice == nullptr || RequestChoice->SelectedValue != ActiveChoice->SelectedValue)
- {
- bNeedsFreshLaunchRequest = true;
- }
+ return false;
}
if (bNeedsFreshLaunchRequest)
@@ -1213,48 +1295,28 @@ bool UHyperTwistTrainingSubsystem::TryExecuteActiveImportedGeneratedModeLaunchRe
OutBlockedReason = TEXT("Generated-mode execution could not derive a structurally valid launch request.");
return false;
}
- if (LaunchRequest.LaunchConfig.DeckId != ActiveRunState.ActiveDeck.DeckId
- || LaunchRequest.LaunchConfig.SurfaceId != RuntimeSurface.SurfaceId
- || !LaunchRequest.LaunchConfig.RuntimeModeId.Equals(
- RuntimeSurface.RuntimeModeId,
- ESearchCase::IgnoreCase))
+ if (!UHyperTwistTrainingCatalogLibrary::TryBuildImportedGeneratedModeLaunchConfig(
+ ActiveRunState.ActiveDeck,
+ ActiveRunState.ImportedRuntimeSelectionState,
+ ActiveRunState.Session,
+ ExpectedLaunchConfig))
{
- OutBlockedReason = TEXT("Active generated-mode launch request does not match the active runtime surface.");
+ OutBlockedReason =
+ TEXT("Generated-mode execution could not derive a structurally valid launch request from the active selector state.");
return false;
}
-
- for (const FHyperTwistTrainingImportedRuntimeSelector& Selector : RuntimeSurface.Selectors)
+ FHyperTwistTrainingImportedRuntimeSurface RuntimeSurface;
+ if (!UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck(
+ ActiveRunState.ActiveDeck,
+ RuntimeSurface)
+ || !HyperTwistTrainingSubsystemInternal::DoesGeneratedModeLaunchRequestMatchLaunchConfig(
+ LaunchRequest,
+ RuntimeSurface,
+ ExpectedLaunchConfig))
{
- const FHyperTwistTrainingImportedRuntimeSelectorChoice* RequestChoice =
- LaunchRequest.LaunchConfig.SelectorChoices.FindByPredicate(
- [&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
- {
- return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
- }
- );
- const FHyperTwistTrainingImportedRuntimeSelectorChoice* ActiveChoice =
- ActiveRunState.ImportedRuntimeSelectionState.SelectorChoices.FindByPredicate(
- [&Selector](const FHyperTwistTrainingImportedRuntimeSelectorChoice& Candidate)
- {
- return Candidate.SelectorId == Selector.SelectorId && Candidate.IsStructurallyValid();
- }
- );
- if (RequestChoice == nullptr || ActiveChoice == nullptr)
- {
- OutBlockedReason = FString::Printf(
- TEXT("Generated-mode execution is blocked because selector %s is unresolved."),
- *Selector.Label
- );
- return false;
- }
- if (RequestChoice->SelectedValue != ActiveChoice->SelectedValue)
- {
- OutBlockedReason = FString::Printf(
- TEXT("Generated-mode execution is blocked because selector %s no longer matches the active selection state."),
- *Selector.Label
- );
- return false;
- }
+ OutBlockedReason =
+ TEXT("Generated-mode execution could not persist a launch request that matched the active selector state.");
+ return false;
}
const FHyperTwistTrainingRunState SourceRunState = ActiveRunState;
@@ -1716,6 +1778,36 @@ FHyperTwistTrainingCoachPanelState UHyperTwistTrainingSubsystem::GetActiveCoachP
LatestGeneratedModeLaunchRequest
);
}
+
+ FHyperTwistTrainingImportedRuntimeSurface ActiveRuntimeSurface;
+ if (UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSurfaceFromDeck(
+ ActiveRunState.ActiveDeck,
+ ActiveRuntimeSurface)
+ && ActiveRuntimeSurface.IsStructurallyValid()
+ && ActiveRuntimeSurface.SurfaceKind.Equals(TEXT("generated-mode"), ESearchCase::IgnoreCase))
+ {
+ PanelState.bHasActiveGeneratedModeExecutionTarget = true;
+
+ FHyperTwistTrainingImportedGeneratedModeLaunchConfig ActiveExecutionLaunchConfig;
+ bool bRequiresLaunchRequestRefresh = false;
+ FString GeneratedModeExecutionBlockedReason;
+ if (HyperTwistTrainingSubsystemInternal::TryResolveGeneratedModeExecutionLaunchConfig(
+ ActiveRunState,
+ ActiveImportedGeneratedModeLaunchRequest,
+ ActiveExecutionLaunchConfig,
+ bRequiresLaunchRequestRefresh,
+ GeneratedModeExecutionBlockedReason))
+ {
+ PanelState.bCanExecuteActiveGeneratedModeLaunchRequest = true;
+ PanelState.bActiveGeneratedModeExecutionWillRefreshLaunchRequest =
+ bRequiresLaunchRequestRefresh;
+ }
+ else
+ {
+ PanelState.ActiveGeneratedModeExecutionBlockedReason =
+ GeneratedModeExecutionBlockedReason;
+ }
+ }
}
const FHyperTwistTrainingCoachSessionQueueStateEntry* NextRunnableEntry =
diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h
index 30dc2a9..f8077e1 100644
--- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h
+++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h
@@ -6738,6 +6738,18 @@ struct FHyperTwistTrainingCoachPanelState
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString LatestGeneratedModeSelectorSummaryLine;
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
+ bool bHasActiveGeneratedModeExecutionTarget = false;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
+ bool bCanExecuteActiveGeneratedModeLaunchRequest = false;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
+ bool bActiveGeneratedModeExecutionWillRefreshLaunchRequest = false;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
+ FString ActiveGeneratedModeExecutionBlockedReason;
+
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
FString PrimaryActionLabel;
diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/UnrealHyperTwist.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/UnrealHyperTwist.cpp
index 2bdb555..547fbc8 100644
--- a/UnrealHyperTwist/Source/UnrealHyperTwist/UnrealHyperTwist.cpp
+++ b/UnrealHyperTwist/Source/UnrealHyperTwist/UnrealHyperTwist.cpp
@@ -3,4 +3,4 @@
#include "UnrealHyperTwist.h"
#include "Modules/ModuleManager.h"
-IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, UnrealHyperTwist, "UnrealHyperTwist" );
+IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, UnrealHyperTwist, "UnrealHyperTwist");
diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/UnrealHyperTwist.h b/UnrealHyperTwist/Source/UnrealHyperTwist/UnrealHyperTwist.h
index 677c8e2..ddbf2e2 100644
--- a/UnrealHyperTwist/Source/UnrealHyperTwist/UnrealHyperTwist.h
+++ b/UnrealHyperTwist/Source/UnrealHyperTwist/UnrealHyperTwist.h
@@ -3,4 +3,3 @@
#pragma once
#include "CoreMinimal.h"
-
diff --git a/docs/Deepseek C# Prompt b/docs/Deepseek C# Prompt
deleted file mode 100644
index ec2196b..0000000
--- a/docs/Deepseek C# Prompt
+++ /dev/null
@@ -1,100 +0,0 @@
-Role: Principal Software Engineer at a AAA Game Studio, building tooling for Unreal Engine 5.
-Project: VR Codebase Inspector and Security Pen-Testing Analyzer.
-Architecture: Unreal Engine 5 (C++ Client) <---WebSocket---> C# .NET 8 Backend Analysis Server.
-Constraint: The C# server runs on a local workstation (or cloud VM) alongside the VR headset. It must process arbitrary open-source codebases (C++, C#, Python, JS) and return JSON graphs of vulnerabilities and call hierarchies.
-
-Technical Directives (To Prevent AI Model Degradation into .NET Framework patterns):
-1. AOT Compatibility: This server may eventually run inside a Docker container with `-p:PublishAot=true`. Therefore, YOU CANNOT USE REFLECTION (`GetProperties()`, `GetMethods()`). All type scanning MUST use **Roslyn Source Generators** OR **Microsoft.CodeAnalysis** (Compilation APIs) which are AOT-safe.
-2. Roslyn Analyzer: Write a C# Script that uses `Microsoft.CodeAnalysis.CSharp` to parse a given folder of C# code and return a list of `UnsafeMethodCall` objects (e.g., `Process.Start` usage, `DllImport` attributes). YOU MUST PROVIDE A `Solution` file and `Project` loader that handles `AdhocWorkspace`.
-3. C++ Parsing: For the Unreal side, DO NOT attempt to wrap Unreal C++ in C#. Instead, C# will shell out to `clang-tidy` or `cppcheck`. Show me the `Process` spawning logic with **OutputDataReceived** event handlers that send progress updates back to the client via SignalR.
-4. Performance: Use `System.IO.Pipelines` (PipeReader) to stream massive source files (e.g., 100MB `Intermediate/Build/Source.cpp`) without allocating huge strings on the Large Object Heap.
-5. Frontend Interop: Generate a TypeScript client definition from the C# SignalR hub using `@microsoft/signalr-protocol-msgpack`. Include the command for `nswag` or `openapi-generator`.
-
-Output Expected:
-1. A detailed architecture diagram in Mermaid format.
-2. The C# code for `RoslynAnalyzerService.cs` and `CppAnalyzerService.cs`.
-3. Explanation of how to handle the **Impedance Mismatch**: C# wants deterministic disposal, Unreal expects persistent open sockets. How will you manage lifetime of the WebSocket connection?
-4. A note on **Security**: This tool will be used for pen-testing. The C# server executes untrusted user scripts (via shell). Provide the `ProcessStartInfo` configuration to ensure **Sandboxing** (e.g., `UseShellExecute=false`, `WorkingDirectory` restriction, `EnvironmentVariables` scrub).
-
-Continue generating the response now. Provide full code blocks, do not use placeholders like "// logic here". Be explicit.
-
----
-
-Role: Senior systems architect for math-heavy multiplayer applications with Unreal frontends and C# backend services.
-
-Project: Hypercubing virtual reality application. Unreal will render and handle immersive interaction. C# is being considered for simulation, multiplayer backend, persistence, telemetry, and orchestration.
-
-Objective: Design a high-performance architecture where Unreal remains the client/runtime and C# owns the durable and computational service layer.
-
-Hard constraints:
-1. Do not propose replacing Unreal gameplay/runtime with C#.
-2. Use C# for:
- - simulation services where server authority is needed
- - session state
- - matchmaking
- - persistence
- - replay/event logs
- - analytics
- - user/session/account services
- - collaboration or shared puzzle state
-3. Assume the math may become non-trivial and should remain strongly typed and testable.
-4. Prefer explicit contracts and deterministic state transitions.
-5. No reflection-driven architecture in core simulation paths.
-6. Design for low-latency updates, reconnect, state recovery, and versioned protocol evolution.
-7. Assume future scale from single-user local mode up to networked synchronized sessions.
-
-Deliverables:
-- Service layout
-- Unreal-to-backend communication model
-- State authority model
-- Sync strategy
-- Persistence model
-- Replay/event sourcing recommendation
-- Math/simulation placement
-- Testing strategy for deterministic correctness
-- Deployment options from local to hosted
-- AI-assisted development constraints for C# code generation on this project
-
-If output is interrupted, continue from the exact next unfinished section. Do not summarize. Continue raw technical output only.
-
----
-
-Role: Senior architect for C# backends and Unreal-integrated systems.
-
-Project: Virtual reality codebase inspector and pentest platform. Unreal is the client/runtime. C# is being considered for backend, analysis, orchestration, collaboration, and data services.
-
-Objective: Design the system so Unreal remains responsible for rendering and interaction, while C# owns the heavy platform logic.
-
-Hard constraints:
-1. Do not propose writing Unreal gameplay code in C#.
-2. Treat Unreal as C++/Blueprint client only.
-3. Use C# for:
- - repository ingestion
- - graph/index building
- - code intelligence
- - plugin and tool orchestration
- - pentest job scheduling
- - evidence storage
- - collaboration services
- - multiplayer/session backend
-4. The system must support polyglot repositories and external scanners written in many languages.
-5. Prefer out-of-process boundaries, gRPC/HTTP/WebSocket boundaries, or worker sandbox boundaries over in-process interop.
-6. No reflection-heavy magic in core runtime paths.
-7. Assume large repos, long-running scans, and untrusted tool output.
-8. Design for cancellation, resumability, auditability, and multi-tenant isolation.
-
-Deliverables:
-- Full architecture with Unreal placement and C# placement
-- Recommended service decomposition
-- Worker sandbox strategy
-- Plugin execution strategy
-- Security boundaries for pentest tooling
-- Repository indexing pipeline
-- Real-time event streaming into VR
-- Storage model for findings, graphs, evidence, and sessions
-- Auth model and operator roles
-- Queueing and scheduling design
-- Deployment topology for local workstation, single VPS, and larger multi-node setups
-- AI integration boundaries and safe prompting strategy for code and security tasks
-
-If output is interrupted, continue exactly where you stopped. Do not summarize. Output the remaining architecture in the same level of detail.