Expose gameplay selector owned-execution scope preview surface
This commit is contained in:
parent
9ece8389bc
commit
80fbca56fd
9 changed files with 839 additions and 2 deletions
|
|
@ -12631,3 +12631,476 @@ UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeSelectorOptionOwnedExec
|
|||
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface(
|
||||
const FHyperTwistTrainingRunState& RunState,
|
||||
const FString& SelectorId,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface& OptionMenuSurface,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface&
|
||||
OptionLaunchRequestPreviewSurface
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface
|
||||
Surface;
|
||||
Surface.SelectorId = SelectorId;
|
||||
Surface.SelectorLabel = OptionMenuSurface.SelectorLabel;
|
||||
Surface.BindingLabel = OptionMenuSurface.BindingLabel;
|
||||
Surface.Headline =
|
||||
TEXT("Generated Mode Selector Option Owned-Execution Puzzle/Subset/Difficulty Preview");
|
||||
Surface.bHasSelector = OptionMenuSurface.bHasSelector;
|
||||
|
||||
if (!SelectorId.IsEmpty())
|
||||
{
|
||||
Surface.Headline = OptionMenuSurface.SelectorLabel.IsEmpty()
|
||||
? FString::Printf(
|
||||
TEXT("Generated Mode Selector Option Owned-Execution Puzzle/Subset/Difficulty Preview: %s"),
|
||||
*SelectorId
|
||||
)
|
||||
: FString::Printf(
|
||||
TEXT("Generated Mode Selector Option Owned-Execution Puzzle/Subset/Difficulty Preview: %s"),
|
||||
*OptionMenuSurface.SelectorLabel
|
||||
);
|
||||
}
|
||||
|
||||
if (SelectorId.IsEmpty())
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Generated-mode selector option owned-execution puzzle/subset/difficulty preview requires a selector id from the active selector roster.");
|
||||
Surface.PuzzleIdSummaryLine = TEXT("Puzzle id: n/a");
|
||||
Surface.SubsetIdSummaryLine = TEXT("Subset: n/a");
|
||||
Surface.DifficultySummaryLine = TEXT("Difficulty: n/a");
|
||||
Surface.CurrentSelectionScopeLine = TEXT("Current selection: n/a");
|
||||
Surface.DetailLine = OptionLaunchRequestPreviewSurface.StatusLine.IsEmpty()
|
||||
? TEXT("Launch-request preview: n/a")
|
||||
: FString::Printf(
|
||||
TEXT("Launch-request preview: %s"),
|
||||
*OptionLaunchRequestPreviewSurface.StatusLine
|
||||
);
|
||||
return Surface;
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingImportedRuntimeSurface& RuntimeSurface =
|
||||
RunState.ActiveDeck.ImportedRuntimeSurface;
|
||||
const bool bHasGeneratedModeSurface = RuntimeSurface.IsStructurallyValid()
|
||||
&& RuntimeSurface.SurfaceKind.Equals(TEXT("generated-mode"), ESearchCase::IgnoreCase);
|
||||
const FHyperTwistTrainingCase* SeedCase = RunState.ActiveDeck.Cases.FindByPredicate(
|
||||
[](const FHyperTwistTrainingCase& Candidate)
|
||||
{
|
||||
return Candidate.IsStructurallyValid();
|
||||
}
|
||||
);
|
||||
|
||||
const auto DescribeDifficultyBand = [](const float Difficulty) -> FString
|
||||
{
|
||||
if (Difficulty <= 0.0f)
|
||||
{
|
||||
return TEXT("Unspecified");
|
||||
}
|
||||
if (Difficulty <= 0.25f)
|
||||
{
|
||||
return TEXT("Beginner");
|
||||
}
|
||||
if (Difficulty <= 0.5f)
|
||||
{
|
||||
return TEXT("Intermediate");
|
||||
}
|
||||
if (Difficulty <= 0.75f)
|
||||
{
|
||||
return TEXT("Advanced");
|
||||
}
|
||||
|
||||
return TEXT("Expert");
|
||||
};
|
||||
|
||||
const auto BuildDifficultyLine = [&DescribeDifficultyBand](
|
||||
const float Difficulty
|
||||
) -> FString
|
||||
{
|
||||
return Difficulty > 0.0f
|
||||
? FString::Printf(
|
||||
TEXT("Difficulty on execute: %.2f [%s]"),
|
||||
Difficulty,
|
||||
*DescribeDifficultyBand(Difficulty)
|
||||
)
|
||||
: TEXT("Difficulty on execute: unspecified");
|
||||
};
|
||||
|
||||
const auto IncrementPuzzleFamilyCounts = [&Surface](const FString& PuzzleId)
|
||||
{
|
||||
if (PuzzleId.StartsWith(TEXT("cube/")))
|
||||
{
|
||||
++Surface.CubePuzzleOptionCount;
|
||||
}
|
||||
else if (PuzzleId.StartsWith(TEXT("hypercube/")))
|
||||
{
|
||||
++Surface.HypercubePuzzleOptionCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++Surface.OtherPuzzleOptionCount;
|
||||
}
|
||||
};
|
||||
|
||||
const auto IncrementDifficultyCounts = [&Surface](const float Difficulty)
|
||||
{
|
||||
if (Difficulty <= 0.0f)
|
||||
{
|
||||
++Surface.UnspecifiedDifficultyOptionCount;
|
||||
}
|
||||
else if (Difficulty <= 0.25f)
|
||||
{
|
||||
++Surface.BeginnerDifficultyOptionCount;
|
||||
}
|
||||
else if (Difficulty <= 0.5f)
|
||||
{
|
||||
++Surface.IntermediateDifficultyOptionCount;
|
||||
}
|
||||
else if (Difficulty <= 0.75f)
|
||||
{
|
||||
++Surface.AdvancedDifficultyOptionCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++Surface.ExpertDifficultyOptionCount;
|
||||
}
|
||||
};
|
||||
|
||||
if (!RunState.IsStructurallyValid() || !bHasGeneratedModeSurface)
|
||||
{
|
||||
Surface.StatusLine = OptionMenuSurface.StatusLine.IsEmpty()
|
||||
? TEXT("Generated-mode selector option owned-execution puzzle/subset/difficulty preview is not currently available.")
|
||||
: OptionMenuSurface.StatusLine;
|
||||
Surface.PuzzleIdSummaryLine = TEXT("Puzzle id: n/a");
|
||||
Surface.SubsetIdSummaryLine = TEXT("Subset: n/a");
|
||||
Surface.DifficultySummaryLine = TEXT("Difficulty: n/a");
|
||||
Surface.CurrentSelectionScopeLine = OptionMenuSurface.bHasUnresolvedSelectionDetail
|
||||
? OptionMenuSurface.UnresolvedSelectionLine
|
||||
: (OptionMenuSurface.bHasSelection
|
||||
? TEXT("Current selection remains cached, but no active owned-execution scope preview is available.")
|
||||
: TEXT("Current selection: unresolved"));
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Launch-request preview: %s"),
|
||||
OptionLaunchRequestPreviewSurface.StatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *OptionLaunchRequestPreviewSurface.StatusLine
|
||||
);
|
||||
return Surface;
|
||||
}
|
||||
|
||||
for (const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewEntrySurface&
|
||||
PreviewEntry : OptionLaunchRequestPreviewSurface.OptionEntries)
|
||||
{
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewEntrySurface
|
||||
Entry;
|
||||
Entry.OptionId = PreviewEntry.OptionId;
|
||||
Entry.Label = PreviewEntry.Label;
|
||||
Entry.OptionValue = PreviewEntry.OptionValue;
|
||||
Entry.LaunchRequestPreviewKind = PreviewEntry.LaunchRequestPreviewKind;
|
||||
Entry.bMatchesCurrentSelection = PreviewEntry.bMatchesCurrentSelection;
|
||||
Entry.bStartsOwnedCaseImmediately = PreviewEntry.bStartsOwnedCaseImmediately;
|
||||
|
||||
switch (PreviewEntry.LaunchRequestPreviewKind)
|
||||
{
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
DirectOwnedCaseStart:
|
||||
{
|
||||
FHyperTwistTrainingCase MatchingCase;
|
||||
if (UHyperTwistTrainingCatalogLibrary::TryGetImportedRuntimeSelectorOptionCaseFromDeck(
|
||||
RunState.ActiveDeck,
|
||||
SelectorId,
|
||||
PreviewEntry.OptionId,
|
||||
MatchingCase))
|
||||
{
|
||||
Entry.PreviewPuzzleId = MatchingCase.PuzzleId;
|
||||
Entry.PreviewSubsetId = MatchingCase.SubsetId;
|
||||
Entry.PreviewDifficulty = MatchingCase.Difficulty;
|
||||
Entry.PreviewDifficultyBandLabel =
|
||||
DescribeDifficultyBand(Entry.PreviewDifficulty);
|
||||
Entry.bHasPuzzleId = !Entry.PreviewPuzzleId.IsEmpty();
|
||||
Entry.bHasSubsetId = !Entry.PreviewSubsetId.IsEmpty();
|
||||
Entry.bHasDifficulty = Entry.PreviewDifficulty > 0.0f;
|
||||
Entry.PuzzleIdLine = Entry.bHasPuzzleId
|
||||
? FString::Printf(
|
||||
TEXT("Puzzle id on execute: %s"),
|
||||
*Entry.PreviewPuzzleId
|
||||
)
|
||||
: TEXT("Puzzle id on execute: unavailable");
|
||||
Entry.SubsetIdLine = Entry.bHasSubsetId
|
||||
? FString::Printf(
|
||||
TEXT("Subset on execute: %s"),
|
||||
*Entry.PreviewSubsetId
|
||||
)
|
||||
: TEXT("Subset on execute: none");
|
||||
Entry.DifficultyLine = BuildDifficultyLine(Entry.PreviewDifficulty);
|
||||
Entry.ScopeSourceLine =
|
||||
TEXT("Scope source: exact direct covered-case scope from the resolved imported option case.");
|
||||
Entry.PreviewStabilityLine =
|
||||
TEXT("Preview stability: exact direct owned-case scope preview from covered-case launch.");
|
||||
Entry.bHasExactScopePreview = true;
|
||||
Entry.bCanPreview = true;
|
||||
++Surface.DirectExactOptionCount;
|
||||
if (Entry.bHasPuzzleId)
|
||||
{
|
||||
IncrementPuzzleFamilyCounts(Entry.PreviewPuzzleId);
|
||||
}
|
||||
if (Entry.bHasSubsetId)
|
||||
{
|
||||
++Surface.SubsetScopedOptionCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++Surface.UnscopedSubsetOptionCount;
|
||||
}
|
||||
IncrementDifficultyCounts(Entry.PreviewDifficulty);
|
||||
}
|
||||
else
|
||||
{
|
||||
Entry.PuzzleIdLine = TEXT("Puzzle id on execute: unavailable");
|
||||
Entry.SubsetIdLine = TEXT("Subset on execute: unavailable");
|
||||
Entry.DifficultyLine = TEXT("Difficulty on execute: unavailable");
|
||||
Entry.ScopeSourceLine =
|
||||
TEXT("Scope source: unavailable because the covered case could not be re-resolved from the active deck.");
|
||||
Entry.PreviewStabilityLine = TEXT("Preview stability: unavailable");
|
||||
Entry.bCanPreview = false;
|
||||
++Surface.UnavailableOptionCount;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
StoredRequestReusable:
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
RefreshRequired:
|
||||
if (SeedCase == nullptr)
|
||||
{
|
||||
Entry.PuzzleIdLine = TEXT("Puzzle id on execute: unavailable");
|
||||
Entry.SubsetIdLine = TEXT("Subset on execute: unavailable");
|
||||
Entry.DifficultyLine = TEXT("Difficulty on execute: unavailable");
|
||||
Entry.ScopeSourceLine =
|
||||
TEXT("Scope source: unavailable because the active generated-mode surface has no structurally valid seed case.");
|
||||
Entry.PreviewStabilityLine = TEXT("Preview stability: unavailable");
|
||||
Entry.bCanPreview = false;
|
||||
++Surface.UnavailableOptionCount;
|
||||
break;
|
||||
}
|
||||
|
||||
Entry.PreviewPuzzleId = PreviewEntry.HypotheticalPuzzleId;
|
||||
Entry.PreviewSubsetId = RunState.ActiveDeck.SubsetId;
|
||||
Entry.PreviewDifficulty = SeedCase->Difficulty;
|
||||
Entry.PreviewDifficultyBandLabel =
|
||||
DescribeDifficultyBand(Entry.PreviewDifficulty);
|
||||
Entry.bHasPuzzleId = !Entry.PreviewPuzzleId.IsEmpty();
|
||||
Entry.bHasSubsetId = !Entry.PreviewSubsetId.IsEmpty();
|
||||
Entry.bHasDifficulty = Entry.PreviewDifficulty > 0.0f;
|
||||
Entry.PuzzleIdLine = Entry.bHasPuzzleId
|
||||
? FString::Printf(
|
||||
TEXT("Puzzle id on execute: %s"),
|
||||
*Entry.PreviewPuzzleId
|
||||
)
|
||||
: TEXT("Puzzle id on execute: unavailable");
|
||||
Entry.SubsetIdLine = Entry.bHasSubsetId
|
||||
? FString::Printf(
|
||||
TEXT("Subset on execute: %s"),
|
||||
*Entry.PreviewSubsetId
|
||||
)
|
||||
: TEXT("Subset on execute: none");
|
||||
Entry.DifficultyLine = BuildDifficultyLine(Entry.PreviewDifficulty);
|
||||
Entry.ScopeSourceLine =
|
||||
TEXT("Scope source: exact generated owned execution scope from the hypothetical launch-config puzzle id, active deck subset, and seed-case difficulty.");
|
||||
Entry.PreviewStabilityLine =
|
||||
PreviewEntry.LaunchRequestPreviewKind
|
||||
== EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
StoredRequestReusable
|
||||
? TEXT("Preview stability: exact while execute reuses the current stored request.")
|
||||
: TEXT("Preview stability: exact even though execute still needs launch-request refresh.");
|
||||
Entry.bHasExactScopePreview = true;
|
||||
Entry.bCanPreview = true;
|
||||
++Surface.GeneratedExactOptionCount;
|
||||
if (Entry.bHasPuzzleId)
|
||||
{
|
||||
IncrementPuzzleFamilyCounts(Entry.PreviewPuzzleId);
|
||||
}
|
||||
if (Entry.bHasSubsetId)
|
||||
{
|
||||
++Surface.SubsetScopedOptionCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
++Surface.UnscopedSubsetOptionCount;
|
||||
}
|
||||
IncrementDifficultyCounts(Entry.PreviewDifficulty);
|
||||
break;
|
||||
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
UnresolvedAfterChoice:
|
||||
Entry.PuzzleIdLine =
|
||||
TEXT("Puzzle id on execute: blocked until every required selector is resolved.");
|
||||
Entry.SubsetIdLine =
|
||||
TEXT("Subset on execute: blocked until every required selector is resolved.");
|
||||
Entry.DifficultyLine =
|
||||
TEXT("Difficulty on execute: blocked until every required selector is resolved.");
|
||||
Entry.ScopeSourceLine =
|
||||
TEXT("Scope source: blocked while selector coverage remains incomplete.");
|
||||
Entry.PreviewStabilityLine =
|
||||
TEXT("Preview stability: blocked while selector coverage remains incomplete.");
|
||||
Entry.bPreviewBlocked = true;
|
||||
Entry.bCanPreview = true;
|
||||
++Surface.BlockedOptionCount;
|
||||
break;
|
||||
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::
|
||||
PayloadUnavailable:
|
||||
Entry.PuzzleIdLine =
|
||||
TEXT("Puzzle id on execute: blocked until a structurally valid launch payload can be derived.");
|
||||
Entry.SubsetIdLine =
|
||||
TEXT("Subset on execute: blocked until a structurally valid launch payload can be derived.");
|
||||
Entry.DifficultyLine =
|
||||
TEXT("Difficulty on execute: blocked until a structurally valid launch payload can be derived.");
|
||||
Entry.ScopeSourceLine =
|
||||
TEXT("Scope source: blocked while the hypothetical generated-mode payload remains structurally invalid.");
|
||||
Entry.PreviewStabilityLine =
|
||||
TEXT("Preview stability: blocked while the hypothetical generated-mode payload remains structurally invalid.");
|
||||
Entry.bPreviewBlocked = true;
|
||||
Entry.bCanPreview = true;
|
||||
++Surface.BlockedOptionCount;
|
||||
break;
|
||||
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::Unavailable:
|
||||
case EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::None:
|
||||
default:
|
||||
Entry.PuzzleIdLine = TEXT("Puzzle id on execute: unavailable");
|
||||
Entry.SubsetIdLine = TEXT("Subset on execute: unavailable");
|
||||
Entry.DifficultyLine = TEXT("Difficulty on execute: unavailable");
|
||||
Entry.ScopeSourceLine = TEXT("Scope source: unavailable");
|
||||
Entry.PreviewStabilityLine = TEXT("Preview stability: unavailable");
|
||||
Entry.bCanPreview = false;
|
||||
++Surface.UnavailableOptionCount;
|
||||
break;
|
||||
}
|
||||
|
||||
Entry.DetailLine = PreviewEntry.DetailLine.IsEmpty()
|
||||
? Entry.PreviewStabilityLine
|
||||
: FString::Printf(
|
||||
TEXT("%s | %s"),
|
||||
*Entry.PreviewStabilityLine,
|
||||
*PreviewEntry.DetailLine
|
||||
);
|
||||
|
||||
if (Entry.bMatchesCurrentSelection)
|
||||
{
|
||||
Surface.bCurrentSelectionHasExactScopePreview = Entry.bHasExactScopePreview;
|
||||
Surface.bCurrentSelectionHasPuzzleId = Entry.bHasPuzzleId;
|
||||
Surface.bCurrentSelectionHasSubsetId = Entry.bHasSubsetId;
|
||||
Surface.bCurrentSelectionHasDifficulty = Entry.bHasDifficulty;
|
||||
Surface.CurrentSelectionScopeLine = FString::Printf(
|
||||
TEXT("%s | %s | %s"),
|
||||
*Entry.PuzzleIdLine,
|
||||
*Entry.SubsetIdLine,
|
||||
*Entry.DifficultyLine
|
||||
);
|
||||
}
|
||||
|
||||
Surface.OptionEntries.Add(MoveTemp(Entry));
|
||||
}
|
||||
|
||||
Surface.bHasOwnedExecutionPuzzleSubsetDifficultyPreviewOptions =
|
||||
Surface.OptionEntries.Num() > 0;
|
||||
Surface.bHasDirectScopePreviewOptions = Surface.DirectExactOptionCount > 0;
|
||||
Surface.bHasGeneratedScopePreviewOptions = Surface.GeneratedExactOptionCount > 0;
|
||||
Surface.bHasBlockedScopePreviewOptions = Surface.BlockedOptionCount > 0;
|
||||
|
||||
Surface.PuzzleIdSummaryLine = Surface.OptionEntries.Num() > 0
|
||||
? FString::Printf(
|
||||
TEXT("Puzzle id: %d cube | %d hypercube | %d other | %d blocked | %d unavailable"),
|
||||
Surface.CubePuzzleOptionCount,
|
||||
Surface.HypercubePuzzleOptionCount,
|
||||
Surface.OtherPuzzleOptionCount,
|
||||
Surface.BlockedOptionCount,
|
||||
Surface.UnavailableOptionCount
|
||||
)
|
||||
: TEXT("Puzzle id: no imported options");
|
||||
Surface.SubsetIdSummaryLine = Surface.OptionEntries.Num() > 0
|
||||
? FString::Printf(
|
||||
TEXT("Subset: %d scoped | %d unscoped | %d blocked | %d unavailable"),
|
||||
Surface.SubsetScopedOptionCount,
|
||||
Surface.UnscopedSubsetOptionCount,
|
||||
Surface.BlockedOptionCount,
|
||||
Surface.UnavailableOptionCount
|
||||
)
|
||||
: TEXT("Subset: no imported options");
|
||||
Surface.DifficultySummaryLine = Surface.OptionEntries.Num() > 0
|
||||
? FString::Printf(
|
||||
TEXT("Difficulty: %d beginner | %d intermediate | %d advanced | %d expert | %d unspecified"),
|
||||
Surface.BeginnerDifficultyOptionCount,
|
||||
Surface.IntermediateDifficultyOptionCount,
|
||||
Surface.AdvancedDifficultyOptionCount,
|
||||
Surface.ExpertDifficultyOptionCount,
|
||||
Surface.UnspecifiedDifficultyOptionCount
|
||||
)
|
||||
: TEXT("Difficulty: no imported options");
|
||||
|
||||
if (Surface.CurrentSelectionScopeLine.IsEmpty())
|
||||
{
|
||||
if (OptionMenuSurface.bHasUnresolvedSelectionDetail)
|
||||
{
|
||||
Surface.CurrentSelectionScopeLine = OptionMenuSurface.UnresolvedSelectionLine;
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelection)
|
||||
{
|
||||
Surface.CurrentSelectionScopeLine =
|
||||
TEXT("Current selection has no additional owned-execution scope preview.");
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelector)
|
||||
{
|
||||
Surface.CurrentSelectionScopeLine = TEXT("Current selection: unresolved");
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.CurrentSelectionScopeLine = TEXT("Current selection: n/a");
|
||||
}
|
||||
}
|
||||
|
||||
if (OptionMenuSurface.bHasSelector && Surface.OptionEntries.Num() > 0)
|
||||
{
|
||||
Surface.StatusLine = FString::Printf(
|
||||
TEXT("Generated-mode selector option owned-execution puzzle/subset/difficulty preview exposes %d direct-case exact option%s, %d generated exact option%s, %d blocked option%s, and %d unavailable option%s."),
|
||||
Surface.DirectExactOptionCount,
|
||||
Surface.DirectExactOptionCount == 1 ? TEXT("") : TEXT("s"),
|
||||
Surface.GeneratedExactOptionCount,
|
||||
Surface.GeneratedExactOptionCount == 1 ? TEXT("") : TEXT("s"),
|
||||
Surface.BlockedOptionCount,
|
||||
Surface.BlockedOptionCount == 1 ? TEXT("") : TEXT("s"),
|
||||
Surface.UnavailableOptionCount,
|
||||
Surface.UnavailableOptionCount == 1 ? TEXT("") : TEXT("s")
|
||||
);
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelector)
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Generated-mode selector option owned-execution puzzle/subset/difficulty preview is active, but this selector does not expose imported options.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.StatusLine = OptionMenuSurface.StatusLine.IsEmpty()
|
||||
? TEXT("Generated-mode selector option owned-execution puzzle/subset/difficulty preview is not currently available.")
|
||||
: OptionMenuSurface.StatusLine;
|
||||
}
|
||||
|
||||
const FString SelectorSummary = Surface.SelectorLabel.IsEmpty()
|
||||
? (Surface.SelectorId.IsEmpty() ? FString(TEXT("n/a")) : Surface.SelectorId)
|
||||
: Surface.SelectorLabel;
|
||||
const FString BindingSummary = Surface.BindingLabel.IsEmpty()
|
||||
? FString(TEXT("n/a"))
|
||||
: Surface.BindingLabel;
|
||||
Surface.DetailLine = FString::Printf(
|
||||
TEXT("Launch-request preview: %s | Selector: %s | Binding: %s"),
|
||||
OptionLaunchRequestPreviewSurface.StatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *OptionLaunchRequestPreviewSurface.StatusLine,
|
||||
*SelectorSummary,
|
||||
*BindingSummary
|
||||
);
|
||||
|
||||
return Surface;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -929,6 +929,25 @@ UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeSelectorOptionOwne
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface
|
||||
UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface(
|
||||
const FString& SelectorId
|
||||
) const
|
||||
{
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface OptionMenuSurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionMenuSurface(SelectorId);
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface
|
||||
OptionLaunchRequestPreviewSurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface(SelectorId);
|
||||
return UHyperTwistTrainingCoachLibrary::
|
||||
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface(
|
||||
CachedRunState,
|
||||
SelectorId,
|
||||
OptionMenuSurface,
|
||||
OptionLaunchRequestPreviewSurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachRecommendedRun(
|
||||
const int32 MaxCases,
|
||||
const FString& StartActionSourceLabel
|
||||
|
|
|
|||
|
|
@ -910,6 +910,25 @@ AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeSelectorOptionOwn
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface
|
||||
AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface(
|
||||
const FString& SelectorId
|
||||
) const
|
||||
{
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface OptionMenuSurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionMenuSurface(SelectorId);
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface
|
||||
OptionLaunchRequestPreviewSurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface(SelectorId);
|
||||
return UHyperTwistTrainingCoachLibrary::
|
||||
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface(
|
||||
CachedRunState,
|
||||
SelectorId,
|
||||
OptionMenuSurface,
|
||||
OptionLaunchRequestPreviewSurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState AHyperTwistTrainingSessionActor::StartCoachRecommendedTrainingRun(
|
||||
const int32 MaxCases
|
||||
)
|
||||
|
|
|
|||
|
|
@ -807,4 +807,14 @@ public:
|
|||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface&
|
||||
OptionLaunchRequestPreviewSurface
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
static FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface
|
||||
DeriveCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface(
|
||||
const FHyperTwistTrainingRunState& RunState,
|
||||
const FString& SelectorId,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface& OptionMenuSurface,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionLaunchRequestPreviewSurface&
|
||||
OptionLaunchRequestPreviewSurface
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -314,6 +314,12 @@ public:
|
|||
const FString& SelectorId
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface(
|
||||
const FString& SelectorId
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedRun(
|
||||
int32 MaxCases,
|
||||
|
|
|
|||
|
|
@ -295,6 +295,12 @@ public:
|
|||
const FString& SelectorId
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface(
|
||||
const FString& SelectorId
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedTrainingRun(int32 MaxCases);
|
||||
|
||||
|
|
|
|||
|
|
@ -10679,3 +10679,206 @@ struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionDelivery
|
|||
|| bHasOwnedExecutionDeliveryPreviewOptions;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewEntrySurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString OptionId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Label;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString OptionValue;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind LaunchRequestPreviewKind =
|
||||
EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PuzzleIdLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SubsetIdLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DifficultyLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ScopeSourceLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreviewStabilityLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreviewPuzzleId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreviewSubsetId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float PreviewDifficulty = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PreviewDifficultyBandLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bMatchesCurrentSelection = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bStartsOwnedCaseImmediately = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasExactScopePreview = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasPuzzleId = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasSubsetId = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDifficulty = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bPreviewBlocked = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCanPreview = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !OptionId.IsEmpty()
|
||||
|| !Label.IsEmpty()
|
||||
|| !PuzzleIdLine.IsEmpty()
|
||||
|| !SubsetIdLine.IsEmpty()
|
||||
|| !DifficultyLine.IsEmpty()
|
||||
|| LaunchRequestPreviewKind
|
||||
!= EHyperTwistTrainingCoachGeneratedModeOptionLaunchRequestPreviewKind::None
|
||||
|| bCanPreview;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SelectorId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SelectorLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BindingLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PuzzleIdSummaryLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SubsetIdSummaryLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DifficultySummaryLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CurrentSelectionScopeLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewEntrySurface>
|
||||
OptionEntries;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DirectExactOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 GeneratedExactOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 BlockedOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 UnavailableOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CubePuzzleOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 HypercubePuzzleOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 OtherPuzzleOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 SubsetScopedOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 UnscopedSubsetOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 BeginnerDifficultyOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 IntermediateDifficultyOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AdvancedDifficultyOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ExpertDifficultyOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 UnspecifiedDifficultyOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasSelector = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasOwnedExecutionPuzzleSubsetDifficultyPreviewOptions = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDirectScopePreviewOptions = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasGeneratedScopePreviewOptions = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasBlockedScopePreviewOptions = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCurrentSelectionHasExactScopePreview = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCurrentSelectionHasPuzzleId = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCurrentSelectionHasSubsetId = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCurrentSelectionHasDifficulty = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| !SelectorId.IsEmpty()
|
||||
|| OptionEntries.Num() > 0
|
||||
|| bHasSelector
|
||||
|| bHasOwnedExecutionPuzzleSubsetDifficultyPreviewOptions;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ Current correction call from the source-exposed audit and current execution refr
|
|||
- the imported generated-mode gap is closed; request/config/selection plumbing and the bounded clean-room executor are already landed in first-party code
|
||||
- the latest landed bounded `Phase 4` packet closes the retained-idle comparison/outcome actionability gap at the end of the recognition-assisted coach-to-review continuity lane, and the final retained-surface confirmation pass now leaves that closure lane functionally complete
|
||||
- the retained idle widget surface now keeps retained comparison and decision history inspectable without continuing to advertise live launch or guidance-outcome actions once the coach-to-review loop has already collapsed to truthful closed-loop idle
|
||||
- the latest landed bounded `Phase 4` packet stays on that same gameplay-facing consumer lane and adds one thin generated-mode selector option owned execution delivery-mode / reveal-posture / time-target preview surface over the already-cached selector/runtime/request state, so gameplay/Blueprint callers can render exact direct-case delivery posture and exact generated owned execution modality, reveal posture, and target time for a chosen option without rebuilding generated deck composition rules directly
|
||||
- the current next bounded packet is to expose one thin generated-mode selector option owned execution puzzle-id / subset-id / difficulty preview surface on those same two consumer surfaces so gameplay/Blueprint callers can render the resulting owned execution scope and difficulty posture for a chosen option without rebuilding generated deck composition rules directly
|
||||
- the latest landed bounded `Phase 4` packet stays on that same gameplay-facing consumer lane and adds one thin generated-mode selector option owned execution puzzle-id / subset-id / difficulty preview surface over the already-cached selector/runtime/request state, so gameplay/Blueprint callers can render exact direct-case scope and exact generated owned execution puzzle, subset, and difficulty posture for a chosen option without rebuilding generated deck composition rules directly
|
||||
- the current next bounded packet is to expose one thin generated-mode selector option owned execution source-attribution / tag provenance preview surface on those same two consumer surfaces so gameplay/Blueprint callers can render the resulting owned execution provenance and tag posture for a chosen option without rebuilding generated deck composition rules directly
|
||||
- the current execution-discipline rule that broad refactor / monolith-splitting work should not interrupt the active bounded roadmap packet unless structure is actually blocking it
|
||||
|
||||
## Current execution-reality references
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
# HyperTwist Phase 4 gameplay generated-mode selector option owned execution puzzle-id / subset-id / difficulty preview surface packet
|
||||
|
||||
Created on `2026-05-08`
|
||||
|
||||
Status:
|
||||
|
||||
- first-party HyperTwist packet
|
||||
- bounded Phase `4` gameplay-facing consumer slice
|
||||
|
||||
## Purpose
|
||||
|
||||
This packet closes the next thin gameplay-facing consumer seam above the panel-widget and session-actor generated-mode selector option owned execution delivery-mode / reveal-posture / time-target preview surface by exposing one parameterized owned execution puzzle-id / subset-id / difficulty preview surface for a chosen selector id.
|
||||
|
||||
The open tasks were:
|
||||
|
||||
- stop forcing gameplay / Blueprint callers to rebuild generated deck scope rules just to explain what owned execution domain a chosen imported option would actually run in
|
||||
- expose exact direct covered-case puzzle, subset, and difficulty posture plus exact generated owned execution puzzle, subset, and difficulty posture whenever the generated-mode payload is previewable
|
||||
- keep the surface derived from already-cached gameplay consumer run, selector, and launch-request preview state instead of widening into backend logic
|
||||
|
||||
It is not:
|
||||
|
||||
- a selector-dispatch behavior change
|
||||
- a generated-mode launch-request persistence behavior change
|
||||
- a generated-mode execution deck synthesis change
|
||||
- a broader gameplay UI composition pass
|
||||
|
||||
## Scope
|
||||
|
||||
Bounded lane:
|
||||
|
||||
- add first-party owned execution puzzle/subset/difficulty preview surfaces in shared training types
|
||||
- add a coach-library helper that projects puzzle id, subset id, and difficulty over the already-landed launch-request preview surface
|
||||
- expose that parameterized scope preview surface on `HyperTwistTrainingPanelWidget` and `HyperTwistTrainingSessionActor`
|
||||
- keep the derivation presentation-only and rooted in the already-owned selector/runtime/request surfaces
|
||||
|
||||
Out of scope:
|
||||
|
||||
- changing selector-choice apply behavior
|
||||
- changing stored launch-request creation, refresh, or execute behavior
|
||||
- changing generated-mode execution deck synthesis
|
||||
- widening into dashboard-only or broader gameplay composition work
|
||||
|
||||
## Why this was the right next packet
|
||||
|
||||
Before this slice:
|
||||
|
||||
- gameplay-facing panel/session consumers already exposed truthful owned case identity, prompt presentation, delivery mode, reveal posture, and target-time preview for imported selector options
|
||||
- callers could tell how the resulting owned execution would launch
|
||||
|
||||
But one thin consumer seam was still open:
|
||||
|
||||
- callers still had to reconstruct puzzle id, subset id, and difficulty posture from direct covered-case fields, active deck state, and generated owned-execution synthesis rules if they wanted to explain the resulting owned execution scope
|
||||
|
||||
That meant:
|
||||
|
||||
- launch posture was already thin and reusable
|
||||
- but concrete execution scope still leaked generated deck composition and direct launch rules into callers
|
||||
|
||||
So the next bounded move was:
|
||||
|
||||
- keep the already-landed owned execution delivery preview surface unchanged in behavior
|
||||
- reuse the already-cached launch-request preview surface to expose one narrow owned execution puzzle/subset/difficulty preview surface above it
|
||||
|
||||
## What landed
|
||||
|
||||
Primary code changes:
|
||||
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h`
|
||||
- added `FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewEntrySurface`
|
||||
- added `FHyperTwistTrainingCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp`
|
||||
- added `DeriveCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface(...)`
|
||||
- scope preview is derived from cached run state plus the already-landed launch-request preview surface
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp`
|
||||
- added `GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface(const FString& SelectorId)`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp`
|
||||
- added `GetDisplayedCoachGeneratedModeSelectorOptionOwnedExecutionPuzzleSubsetDifficultyPreviewSurface(const FString& SelectorId)`
|
||||
|
||||
Surface behavior:
|
||||
|
||||
- reports exact direct covered-case puzzle id, subset id, and difficulty posture for selector options that dispatch straight to owned cases
|
||||
- reports exact generated owned execution puzzle id from the hypothetical launch config, exact subset posture from the active deck, and exact difficulty posture from the seed case whenever the chosen option yields a previewable generated-mode payload
|
||||
- keeps unresolved or payload-invalid choices inspectable as blocked scope-preview states instead of collapsing them into a generic unavailable branch
|
||||
- keeps the surface presentation-only and compatible with the already-landed launch / execution, request-alignment, stored-request delta, launch-request payload / refresh-preview, launch-request metadata / origin-notes preview, launch-request envelope / request-source preview, owned execution case / canonical-state preview, owned execution prompt preview, and owned execution delivery preview surfaces
|
||||
|
||||
## Validation
|
||||
|
||||
Validation target:
|
||||
|
||||
- full `Development Editor|Win64` build of `C:\HyperTwist\UnrealHyperTwist\UnrealHyperTwist.sln`
|
||||
|
||||
Result:
|
||||
|
||||
- passed with `0` warnings and `0` errors
|
||||
|
||||
## Follow-on
|
||||
|
||||
The next bounded packet on this same gameplay-facing consumer lane should stay thin and expose one generated-mode selector option owned execution source-attribution / tag provenance preview surface so callers can render the resulting owned execution provenance and tag posture for a chosen option without rebuilding generated deck composition rules directly.
|
||||
Loading…
Add table
Reference in a new issue