Fix generated-mode executor reruns and dashboard flow
This commit is contained in:
parent
4cc10edf4d
commit
4d50ffaba4
5 changed files with 536 additions and 8 deletions
|
|
@ -10,6 +10,7 @@
|
|||
#include "Components/VerticalBox.h"
|
||||
#include "Components/VerticalBoxSlot.h"
|
||||
#include "HAL/PlatformTime.h"
|
||||
#include "HyperTwistTraining/HyperTwistTrainingRuntimeLibrary.h"
|
||||
|
||||
namespace HyperTwistCoachDashboardWidgetInternal
|
||||
{
|
||||
|
|
@ -35,6 +36,27 @@ namespace HyperTwistCoachDashboardWidgetInternal
|
|||
Weak
|
||||
};
|
||||
|
||||
bool ContainsTagIgnoreCase(const TArray<FString>& Tags, const FString& ExpectedTag)
|
||||
{
|
||||
return Tags.ContainsByPredicate(
|
||||
[&ExpectedTag](const FString& Candidate)
|
||||
{
|
||||
return Candidate.Equals(ExpectedTag, ESearchCase::IgnoreCase);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
bool IsGeneratedModeLaunchDeck(const FHyperTwistTrainingRunState& RunState)
|
||||
{
|
||||
return RunState.ActiveDeck.IsStructurallyValid()
|
||||
&& RunState.ActiveDeck.ImportedRuntimeSurface.IsStructurallyValid()
|
||||
&& RunState.ActiveDeck.ImportedRuntimeSurface.SurfaceKind.Equals(
|
||||
TEXT("generated-mode"),
|
||||
ESearchCase::IgnoreCase
|
||||
)
|
||||
&& !ContainsTagIgnoreCase(RunState.ActiveDeck.Tags, TEXT("generated-mode:owned-execution"));
|
||||
}
|
||||
|
||||
struct FHandoffHistoryDashboardBias
|
||||
{
|
||||
int32 QueueAcceptedDeltaCount = 0;
|
||||
|
|
@ -3648,7 +3670,26 @@ FHyperTwistTrainingRunStepResult UHyperTwistCoachDashboardWidget::SubmitSyntheti
|
|||
bool UHyperTwistCoachDashboardWidget::ContinueCurrentRunFlow()
|
||||
{
|
||||
bool bSucceeded = false;
|
||||
if (CachedRunState.Session.IsStructurallyValid() && CachedRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
|
||||
if (HyperTwistCoachDashboardWidgetInternal::IsGeneratedModeLaunchDeck(CachedRunState))
|
||||
{
|
||||
FHyperTwistTrainingRunState RunState;
|
||||
FString BlockedReason;
|
||||
bSucceeded = UHyperTwistTrainingRuntimeLibrary::TryExecuteActiveImportedGeneratedModeLaunchRequest(
|
||||
this,
|
||||
RunState,
|
||||
BlockedReason
|
||||
);
|
||||
if (bSucceeded)
|
||||
{
|
||||
LastStepResult = FHyperTwistTrainingRunStepResult();
|
||||
RefreshTrainingState();
|
||||
SyncRetainedRunRecap();
|
||||
SyncSelectedQueueEntry();
|
||||
SyncSelectedAttempt();
|
||||
UpdateDashboardPresentation();
|
||||
}
|
||||
}
|
||||
else if (CachedRunState.Session.IsStructurallyValid() && CachedRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
|
||||
{
|
||||
bSucceeded = StartLiveAttemptTimer();
|
||||
}
|
||||
|
|
@ -10203,9 +10244,25 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
== EHyperTwistTrainingSessionState::Aborted);
|
||||
const bool bHasNextCaseFromLastStep = bHasSessionScopedLastStep
|
||||
&& 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 bCanContinueCurrentRun = !bHasLiveAttemptTimer
|
||||
&& bHasRunnableCurrentCase
|
||||
&& !bLastStepCompletedRun;
|
||||
&& !bLastStepCompletedRun
|
||||
&& (!bGeneratedModeLaunchDeck || bCanExecuteGeneratedModeLaunch);
|
||||
const bool bCanLaunchCoachRun = !bHasLiveAttemptTimer
|
||||
&& (
|
||||
CachedCoachPanelState.bCanStartQueuedRun
|
||||
|
|
@ -10249,13 +10306,25 @@ 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.");
|
||||
}
|
||||
else if (bCanContinueCurrentRun)
|
||||
{
|
||||
const FHyperTwistTrainingCase& TransitionCase = CachedRunState.CurrentSelection.TrainingCase;
|
||||
const FString TransitionPrompt = TransitionCase.PromptLabel.IsEmpty()
|
||||
? ActiveCaseId
|
||||
: TransitionCase.PromptLabel;
|
||||
if (bHasNextCaseFromLastStep)
|
||||
if (bGeneratedModeLaunchDeck)
|
||||
{
|
||||
TransitionStatusLine = FString::Printf(
|
||||
TEXT("Transition: generated-mode request is staged on %s. Execute the owned generated run when ready."),
|
||||
*TransitionPrompt
|
||||
);
|
||||
}
|
||||
else if (bHasNextCaseFromLastStep)
|
||||
{
|
||||
TransitionStatusLine = FString::Printf(
|
||||
TEXT("Transition: next case loaded after the last attempt. Continue the run to begin %s."),
|
||||
|
|
@ -10296,11 +10365,13 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
}
|
||||
const FString ContinueRunLabel = bHasLiveAttemptTimer
|
||||
? (bLiveInspectionPhase ? TEXT("Start Solve") : TEXT("Attempt Active"))
|
||||
: (bHasNextCaseFromLastStep
|
||||
? TEXT("Continue Run")
|
||||
: (bCanContinueCurrentRun
|
||||
? (CachedRunSummary.AttemptCount > 0 ? TEXT("Start Next Attempt") : TEXT("Start First Attempt"))
|
||||
: TransitionLaunchLabel));
|
||||
: (bGeneratedModeLaunchDeck
|
||||
? (bCanExecuteGeneratedModeLaunch ? TEXT("Execute Generated Run") : TEXT("Resolve Selectors"))
|
||||
: (bHasNextCaseFromLastStep
|
||||
? TEXT("Continue Run")
|
||||
: (bCanContinueCurrentRun
|
||||
? (CachedRunSummary.AttemptCount > 0 ? TEXT("Start Next Attempt") : TEXT("Start First Attempt"))
|
||||
: TransitionLaunchLabel)));
|
||||
const bool bHasMethodDrillRun = CachedMethodDrillRunState.IsStructurallyValid();
|
||||
const bool bHasMethodDrillDiagnosticPacket = CachedMethodDrillDiagnosticPacket.IsStructurallyValid();
|
||||
const bool bHasMethodDrillFollowUpTemplate = CachedMethodDrillFollowUpTemplate.IsStructurallyValid();
|
||||
|
|
|
|||
|
|
@ -157,6 +157,25 @@ FHyperTwistTrainingImportedGeneratedModeLaunchRequest UHyperTwistTrainingRuntime
|
|||
return FHyperTwistTrainingImportedGeneratedModeLaunchRequest();
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingRuntimeLibrary::TryExecuteActiveImportedGeneratedModeLaunchRequest(
|
||||
UObject* WorldContextObject,
|
||||
FHyperTwistTrainingRunState& OutRunState,
|
||||
FString& OutBlockedReason
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->TryExecuteActiveImportedGeneratedModeLaunchRequest(
|
||||
OutRunState,
|
||||
OutBlockedReason
|
||||
);
|
||||
}
|
||||
|
||||
OutRunState = FHyperTwistTrainingRunState();
|
||||
OutBlockedReason = TEXT("Training subsystem was unavailable.");
|
||||
return false;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingRuntimeLibrary::ApplyActiveImportedRuntimeSelectorOption(
|
||||
UObject* WorldContextObject,
|
||||
const FString& SelectorId,
|
||||
|
|
|
|||
|
|
@ -155,6 +155,258 @@ namespace HyperTwistTrainingSubsystemInternal
|
|||
return SelectorParts.Num() > 0 ? FString::Join(SelectorParts, TEXT(" | ")) : TEXT("no selector choices");
|
||||
}
|
||||
|
||||
FString SanitizeGeneratedModeToken(const FString& Value)
|
||||
{
|
||||
FString Sanitized;
|
||||
Sanitized.Reserve(Value.Len());
|
||||
|
||||
for (const TCHAR Character : Value)
|
||||
{
|
||||
if (FChar::IsAlnum(Character))
|
||||
{
|
||||
Sanitized.AppendChar(FChar::ToLower(Character));
|
||||
}
|
||||
else if (Sanitized.IsEmpty() || Sanitized[Sanitized.Len() - 1] != TEXT('-'))
|
||||
{
|
||||
Sanitized.AppendChar(TEXT('-'));
|
||||
}
|
||||
}
|
||||
|
||||
while (Sanitized.StartsWith(TEXT("-")))
|
||||
{
|
||||
Sanitized.RightChopInline(1, EAllowShrinking::No);
|
||||
}
|
||||
while (Sanitized.EndsWith(TEXT("-")))
|
||||
{
|
||||
Sanitized.LeftChopInline(1, EAllowShrinking::No);
|
||||
}
|
||||
|
||||
return Sanitized.IsEmpty() ? TEXT("value") : Sanitized;
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingCase* FindFirstStructurallyValidCase(const FHyperTwistTrainingDeck& Deck)
|
||||
{
|
||||
return Deck.Cases.FindByPredicate(
|
||||
[](const FHyperTwistTrainingCase& Candidate)
|
||||
{
|
||||
return Candidate.IsStructurallyValid();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
EHyperTwistTrainingPromptKind ResolveGeneratedModePromptKind(
|
||||
const FHyperTwistTrainingCase& SeedCase,
|
||||
const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest
|
||||
)
|
||||
{
|
||||
const FString RuntimeModeId = LaunchRequest.LaunchConfig.RuntimeModeId.ToLower();
|
||||
const FString GeneratorType = LaunchRequest.LaunchConfig.GeneratorType.ToLower();
|
||||
if (RuntimeModeId.Contains(TEXT("recognition")) || GeneratorType.Contains(TEXT("recognition")))
|
||||
{
|
||||
return EHyperTwistTrainingPromptKind::Recognition;
|
||||
}
|
||||
if (RuntimeModeId.Contains(TEXT("state"))
|
||||
|| GeneratorType.Contains(TEXT("state"))
|
||||
|| RuntimeModeId.Contains(TEXT("scramble"))
|
||||
|| GeneratorType.Contains(TEXT("scramble")))
|
||||
{
|
||||
return EHyperTwistTrainingPromptKind::State;
|
||||
}
|
||||
if ((SeedCase.PromptKind == EHyperTwistTrainingPromptKind::Algorithm
|
||||
|| SeedCase.PromptKind == EHyperTwistTrainingPromptKind::Sequence
|
||||
|| SeedCase.PromptKind == EHyperTwistTrainingPromptKind::Memo)
|
||||
&& SeedCase.CanonicalNotation.IsEmpty())
|
||||
{
|
||||
return EHyperTwistTrainingPromptKind::State;
|
||||
}
|
||||
|
||||
return SeedCase.PromptKind;
|
||||
}
|
||||
|
||||
FString BuildGeneratedModeExecutionSessionId(
|
||||
const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest
|
||||
)
|
||||
{
|
||||
const FString BaseSessionId = !LaunchRequest.LaunchConfig.TrainingSessionId.IsEmpty()
|
||||
? LaunchRequest.LaunchConfig.TrainingSessionId
|
||||
: TEXT("generated-mode");
|
||||
const FString ExecutionToken = FGuid::NewGuid().ToString(EGuidFormats::Digits).ToLower();
|
||||
return FString::Printf(
|
||||
TEXT("%s__generated__%s__%s"),
|
||||
*BaseSessionId,
|
||||
*SanitizeGeneratedModeToken(LaunchRequest.RequestId),
|
||||
*ExecutionToken
|
||||
);
|
||||
}
|
||||
|
||||
FString BuildGeneratedModeCanonicalStateRef(
|
||||
const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest
|
||||
)
|
||||
{
|
||||
const FString SurfaceToken = SanitizeGeneratedModeToken(LaunchRequest.LaunchConfig.SurfaceId);
|
||||
const FString RuntimeToken = SanitizeGeneratedModeToken(LaunchRequest.LaunchConfig.RuntimeModeId);
|
||||
const FString RequestToken = SanitizeGeneratedModeToken(LaunchRequest.RequestId);
|
||||
return FString::Printf(
|
||||
TEXT("generated-mode/%s/%s/%s"),
|
||||
*SurfaceToken,
|
||||
*RuntimeToken,
|
||||
*RequestToken
|
||||
);
|
||||
}
|
||||
|
||||
bool TryBuildGeneratedModeExecutionDeck(
|
||||
const FHyperTwistTrainingDeck& SourceDeck,
|
||||
const FHyperTwistTrainingImportedGeneratedModeLaunchRequest& LaunchRequest,
|
||||
FHyperTwistTrainingDeck& OutDeck,
|
||||
FString& OutBlockedReason
|
||||
)
|
||||
{
|
||||
OutDeck = FHyperTwistTrainingDeck();
|
||||
OutBlockedReason.Reset();
|
||||
|
||||
if (!SourceDeck.IsStructurallyValid())
|
||||
{
|
||||
OutBlockedReason = TEXT("Generated-mode executor requires a structurally valid source deck.");
|
||||
return false;
|
||||
}
|
||||
if (!LaunchRequest.IsStructurallyValid())
|
||||
{
|
||||
OutBlockedReason = TEXT("Generated-mode executor requires a structurally valid launch request.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingCase* SeedCase = FindFirstStructurallyValidCase(SourceDeck);
|
||||
if (SeedCase == nullptr)
|
||||
{
|
||||
OutBlockedReason = TEXT("Generated-mode executor could not find a structurally valid source case.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const FString SelectorSummary = FormatGeneratedModeSelectorSummary(SourceDeck, LaunchRequest);
|
||||
const FString PromptBaseLabel = !LaunchRequest.LaunchConfig.SurfaceLabel.IsEmpty()
|
||||
? LaunchRequest.LaunchConfig.SurfaceLabel
|
||||
: SourceDeck.Title;
|
||||
const FString CaseExecutionNote = FString::Printf(
|
||||
TEXT("Owned generated-mode execution case produced from request %s."),
|
||||
*LaunchRequest.RequestId
|
||||
);
|
||||
const FString DeckExecutionNote = FString::Printf(
|
||||
TEXT("Owned generated-mode execution deck produced from request %s."),
|
||||
*LaunchRequest.RequestId
|
||||
);
|
||||
|
||||
FHyperTwistTrainingCase GeneratedCase = *SeedCase;
|
||||
GeneratedCase.CaseId = FString::Printf(
|
||||
TEXT("%s/generated/%s"),
|
||||
*SourceDeck.DeckId,
|
||||
*SanitizeGeneratedModeToken(LaunchRequest.RequestId)
|
||||
);
|
||||
GeneratedCase.PuzzleId = !LaunchRequest.LaunchConfig.PuzzleId.IsEmpty()
|
||||
? LaunchRequest.LaunchConfig.PuzzleId
|
||||
: SeedCase->PuzzleId;
|
||||
GeneratedCase.PromptKind = ResolveGeneratedModePromptKind(*SeedCase, LaunchRequest);
|
||||
GeneratedCase.PromptLabel = !PromptBaseLabel.IsEmpty() && !SelectorSummary.IsEmpty()
|
||||
? FString::Printf(
|
||||
TEXT("%s | %s"),
|
||||
*PromptBaseLabel,
|
||||
*SelectorSummary
|
||||
)
|
||||
: PromptBaseLabel;
|
||||
GeneratedCase.CanonicalStateRef = BuildGeneratedModeCanonicalStateRef(LaunchRequest);
|
||||
GeneratedCase.CanonicalNotation.Reset();
|
||||
GeneratedCase.AlternateNotations.Reset();
|
||||
GeneratedCase.ScrambleNotation.Reset();
|
||||
GeneratedCase.SubsetId = SourceDeck.SubsetId;
|
||||
GeneratedCase.Difficulty = SeedCase->Difficulty;
|
||||
GeneratedCase.Tags = SeedCase->Tags;
|
||||
GeneratedCase.Tags.AddUnique(TEXT("runtime-surface:generated-mode"));
|
||||
GeneratedCase.Tags.AddUnique(TEXT("generated-mode:owned-execution"));
|
||||
GeneratedCase.Tags.AddUnique(
|
||||
FString::Printf(
|
||||
TEXT("generated-request:%s"),
|
||||
*SanitizeGeneratedModeToken(LaunchRequest.RequestId)
|
||||
)
|
||||
);
|
||||
GeneratedCase.Tags.AddUnique(
|
||||
FString::Printf(
|
||||
TEXT("generated-surface:%s"),
|
||||
*SanitizeGeneratedModeToken(LaunchRequest.LaunchConfig.SurfaceId)
|
||||
)
|
||||
);
|
||||
for (const FHyperTwistTrainingImportedRuntimeSelectorChoice& Choice : LaunchRequest.LaunchConfig.SelectorChoices)
|
||||
{
|
||||
if (!Choice.IsStructurallyValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GeneratedCase.Tags.AddUnique(
|
||||
FString::Printf(
|
||||
TEXT("generated-selector:%s=%s"),
|
||||
*SanitizeGeneratedModeToken(Choice.SelectorId),
|
||||
*SanitizeGeneratedModeToken(Choice.SelectedValue)
|
||||
)
|
||||
);
|
||||
}
|
||||
GeneratedCase.AllowedDeliveryModes = SeedCase->AllowedDeliveryModes;
|
||||
if (GeneratedCase.AllowedDeliveryModes.Num() == 0)
|
||||
{
|
||||
GeneratedCase.AllowedDeliveryModes = SourceDeck.DeliveryModes;
|
||||
}
|
||||
GeneratedCase.AllowedDeliveryModes.AddUnique(LaunchRequest.LaunchConfig.DeliveryMode);
|
||||
GeneratedCase.TimeTargetMs = SeedCase->TimeTargetMs;
|
||||
GeneratedCase.SourceAttribution = SeedCase->SourceAttribution.IsStructurallyValid()
|
||||
? SeedCase->SourceAttribution
|
||||
: SourceDeck.SourceAttribution;
|
||||
if (GeneratedCase.SourceAttribution.SourceCaseId.IsEmpty())
|
||||
{
|
||||
GeneratedCase.SourceAttribution.SourceCaseId = SeedCase->CaseId;
|
||||
}
|
||||
GeneratedCase.SourceAttribution.SourceNotes = GeneratedCase.SourceAttribution.SourceNotes.IsEmpty()
|
||||
? CaseExecutionNote
|
||||
: FString::Printf(
|
||||
TEXT("%s | %s"),
|
||||
*GeneratedCase.SourceAttribution.SourceNotes,
|
||||
*CaseExecutionNote
|
||||
);
|
||||
|
||||
OutDeck = SourceDeck;
|
||||
OutDeck.SelectionPolicy = EHyperTwistTrainingSelectionPolicy::Scripted;
|
||||
OutDeck.Title = !SourceDeck.Title.IsEmpty()
|
||||
? SourceDeck.Title
|
||||
: (!LaunchRequest.LaunchConfig.SurfaceLabel.IsEmpty()
|
||||
? LaunchRequest.LaunchConfig.SurfaceLabel
|
||||
: TEXT("Generated mode deck"));
|
||||
OutDeck.bSupportsAlgorithmReveal =
|
||||
SourceDeck.bSupportsAlgorithmReveal && !GeneratedCase.CanonicalNotation.IsEmpty();
|
||||
OutDeck.Cases.Reset();
|
||||
OutDeck.Cases.Add(GeneratedCase);
|
||||
OutDeck.Tags.AddUnique(TEXT("runtime-surface:generated-mode"));
|
||||
OutDeck.Tags.AddUnique(TEXT("generated-mode:owned-execution"));
|
||||
OutDeck.Tags.AddUnique(
|
||||
FString::Printf(
|
||||
TEXT("generated-request:%s"),
|
||||
*SanitizeGeneratedModeToken(LaunchRequest.RequestId)
|
||||
)
|
||||
);
|
||||
OutDeck.ImportedRuntimeSurface = SourceDeck.ImportedRuntimeSurface;
|
||||
OutDeck.SourceAttribution.SourceNotes = OutDeck.SourceAttribution.SourceNotes.IsEmpty()
|
||||
? DeckExecutionNote
|
||||
: FString::Printf(
|
||||
TEXT("%s | %s"),
|
||||
*OutDeck.SourceAttribution.SourceNotes,
|
||||
*DeckExecutionNote
|
||||
);
|
||||
|
||||
if (!OutDeck.IsStructurallyValid() || !OutDeck.ImportedRuntimeSurface.IsStructurallyValid())
|
||||
{
|
||||
OutBlockedReason = TEXT("Generated-mode executor could not build a structurally valid owned execution deck.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TArray<FString> ExtractCaseIdsFromDeck(const FHyperTwistTrainingDeck& Deck)
|
||||
{
|
||||
TArray<FString> CaseIds;
|
||||
|
|
@ -871,6 +1123,179 @@ FHyperTwistTrainingImportedGeneratedModeLaunchRequest UHyperTwistTrainingSubsyst
|
|||
return ActiveImportedGeneratedModeLaunchRequest;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingSubsystem::TryExecuteActiveImportedGeneratedModeLaunchRequest(
|
||||
FHyperTwistTrainingRunState& OutRunState,
|
||||
FString& OutBlockedReason
|
||||
)
|
||||
{
|
||||
OutRunState = FHyperTwistTrainingRunState();
|
||||
OutBlockedReason.Reset();
|
||||
|
||||
if (!HasActiveRun() || !ActiveRunState.IsStructurallyValid())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (bNeedsFreshLaunchRequest)
|
||||
{
|
||||
LaunchRequest = CreateActiveImportedGeneratedModeLaunchRequest(
|
||||
TEXT("runtime-imported-generated-mode-executor")
|
||||
);
|
||||
}
|
||||
if (!LaunchRequest.IsStructurallyValid())
|
||||
{
|
||||
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))
|
||||
{
|
||||
OutBlockedReason = TEXT("Active generated-mode launch request does not match the active runtime surface.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const FHyperTwistTrainingImportedRuntimeSelector& Selector : RuntimeSurface.Selectors)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingRunState SourceRunState = ActiveRunState;
|
||||
FHyperTwistTrainingDeck GeneratedDeck;
|
||||
if (!HyperTwistTrainingSubsystemInternal::TryBuildGeneratedModeExecutionDeck(
|
||||
SourceRunState.ActiveDeck,
|
||||
LaunchRequest,
|
||||
GeneratedDeck,
|
||||
OutBlockedReason))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const FString ExecutionSessionId =
|
||||
HyperTwistTrainingSubsystemInternal::BuildGeneratedModeExecutionSessionId(LaunchRequest);
|
||||
const FHyperTwistTrainingRunState StartedRunState = StartTrainingRunFromDeck(
|
||||
GeneratedDeck,
|
||||
SourceRunState.Session.UserId,
|
||||
ExecutionSessionId,
|
||||
LaunchRequest.LaunchConfig.DeliveryMode
|
||||
);
|
||||
if (!StartedRunState.IsStructurallyValid())
|
||||
{
|
||||
OutBlockedReason = TEXT("Generated-mode executor could not start a structurally valid owned run.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ActiveRunState.ImportedRuntimeSelectionState = SourceRunState.ImportedRuntimeSelectionState;
|
||||
ActiveImportedGeneratedModeLaunchRequest = LaunchRequest;
|
||||
ActiveRunState.ImportedGeneratedModeLaunchRequest = LaunchRequest;
|
||||
RefreshSummary();
|
||||
TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RecordRunState(
|
||||
TrainingRepositoryState,
|
||||
ActiveRunState
|
||||
);
|
||||
RefreshRepositoryViews();
|
||||
|
||||
OutRunState = ActiveRunState;
|
||||
return OutRunState.IsStructurallyValid();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::ApplyActiveImportedRuntimeSelectorOption(
|
||||
const FString& SelectorId,
|
||||
const FString& OptionId
|
||||
|
|
|
|||
|
|
@ -72,6 +72,13 @@ public:
|
|||
const FString& RequestSource
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
|
||||
static bool TryExecuteActiveImportedGeneratedModeLaunchRequest(
|
||||
UObject* WorldContextObject,
|
||||
FHyperTwistTrainingRunState& OutRunState,
|
||||
FString& OutBlockedReason
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingRunState ApplyActiveImportedRuntimeSelectorOption(
|
||||
UObject* WorldContextObject,
|
||||
|
|
|
|||
|
|
@ -58,6 +58,12 @@ public:
|
|||
const FString& RequestSource
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training")
|
||||
bool TryExecuteActiveImportedGeneratedModeLaunchRequest(
|
||||
FHyperTwistTrainingRunState& OutRunState,
|
||||
FString& OutBlockedReason
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training")
|
||||
FHyperTwistTrainingRunState ApplyActiveImportedRuntimeSelectorOption(
|
||||
const FString& SelectorId,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue