Expose gameplay generated-mode selector option dispatch surface
This commit is contained in:
parent
046ff8ee62
commit
3521d4ca4d
9 changed files with 518 additions and 2 deletions
|
|
@ -7583,3 +7583,235 @@ UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeSelectorOptionActionabi
|
|||
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchSurface
|
||||
UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeSelectorOptionDispatchSurface(
|
||||
const FString& SelectorId,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface& OptionMenuSurface,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionActionabilitySurface&
|
||||
OptionActionabilitySurface
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchSurface Surface;
|
||||
Surface.SelectorId = SelectorId;
|
||||
Surface.SelectorLabel = OptionMenuSurface.SelectorLabel;
|
||||
Surface.BindingLabel = OptionMenuSurface.BindingLabel;
|
||||
Surface.Headline = TEXT("Generated Mode Selector Option Dispatch");
|
||||
Surface.bHasSelector = OptionMenuSurface.bHasSelector;
|
||||
|
||||
if (!SelectorId.IsEmpty())
|
||||
{
|
||||
Surface.Headline = OptionMenuSurface.SelectorLabel.IsEmpty()
|
||||
? FString::Printf(TEXT("Generated Mode Selector Option Dispatch: %s"), *SelectorId)
|
||||
: FString::Printf(
|
||||
TEXT("Generated Mode Selector Option Dispatch: %s"),
|
||||
*OptionMenuSurface.SelectorLabel
|
||||
);
|
||||
}
|
||||
|
||||
if (SelectorId.IsEmpty())
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Generated-mode selector option dispatch requires a selector id from the active selector roster.");
|
||||
Surface.DispatchSummaryLine = TEXT("Dispatch: n/a");
|
||||
Surface.CurrentSelectionDispatchLine = TEXT("Current selection: n/a");
|
||||
Surface.DetailLine = OptionActionabilitySurface.StatusLine.IsEmpty()
|
||||
? TEXT("Coverage: n/a")
|
||||
: FString::Printf(TEXT("Coverage: %s"), *OptionActionabilitySurface.StatusLine);
|
||||
return Surface;
|
||||
}
|
||||
|
||||
for (const FHyperTwistTrainingCoachGeneratedModeSelectorOptionEntrySurface& OptionEntry :
|
||||
OptionMenuSurface.OptionEntries)
|
||||
{
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchEntrySurface Entry;
|
||||
Entry.OptionId = OptionEntry.OptionId;
|
||||
Entry.Label = OptionEntry.Label;
|
||||
Entry.OptionValue = OptionEntry.OptionValue;
|
||||
Entry.bMatchesCurrentSelection = OptionEntry.bMatchesCurrentSelection;
|
||||
Entry.GeneratedChoiceSelectedValue = OptionEntry.OptionValue.IsEmpty()
|
||||
? OptionEntry.OptionId
|
||||
: OptionEntry.OptionValue;
|
||||
Entry.GeneratedChoiceDisplayValue = OptionEntry.Label.IsEmpty()
|
||||
? Entry.GeneratedChoiceSelectedValue
|
||||
: OptionEntry.Label;
|
||||
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionActionabilityEntrySurface*
|
||||
MatchingActionabilityEntry =
|
||||
OptionActionabilitySurface.OptionEntries.FindByPredicate(
|
||||
[&OptionEntry](
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionActionabilityEntrySurface&
|
||||
Candidate
|
||||
)
|
||||
{
|
||||
return Candidate.OptionId == OptionEntry.OptionId;
|
||||
}
|
||||
);
|
||||
const bool bHasCoveredCase =
|
||||
MatchingActionabilityEntry != nullptr && MatchingActionabilityEntry->bHasCoveredCase;
|
||||
|
||||
if (bHasCoveredCase)
|
||||
{
|
||||
Entry.DispatchKind =
|
||||
EHyperTwistTrainingCoachGeneratedModeOptionDispatchKind::DirectCaseLaunch;
|
||||
Entry.DirectLaunchOptionId = OptionEntry.OptionId;
|
||||
Entry.DispatchLine = TEXT("Dispatch: launch direct owned case");
|
||||
Entry.DetailLine = MatchingActionabilityEntry->MatchedCaseLabel.IsEmpty()
|
||||
? TEXT("Launch path: ApplyActiveImportedRuntimeSelectorOption")
|
||||
: FString::Printf(
|
||||
TEXT("Launch path: ApplyActiveImportedRuntimeSelectorOption | Case: %s"),
|
||||
*MatchingActionabilityEntry->MatchedCaseLabel
|
||||
);
|
||||
Entry.bCanDispatch = true;
|
||||
++Surface.DirectLaunchOptionCount;
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelector)
|
||||
{
|
||||
Entry.DispatchKind =
|
||||
EHyperTwistTrainingCoachGeneratedModeOptionDispatchKind::ApplyGeneratedChoice;
|
||||
Entry.DispatchLine = TEXT("Dispatch: apply generated-mode selector choice");
|
||||
Entry.DetailLine = FString::Printf(
|
||||
TEXT("Choice path: ApplyActiveImportedGeneratedModeSelectorChoice | Value: %s"),
|
||||
Entry.GeneratedChoiceSelectedValue.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *Entry.GeneratedChoiceSelectedValue
|
||||
);
|
||||
Entry.bCanDispatch = !Entry.GeneratedChoiceSelectedValue.IsEmpty();
|
||||
++Surface.GeneratedChoiceOptionCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
Entry.DispatchKind = EHyperTwistTrainingCoachGeneratedModeOptionDispatchKind::Unavailable;
|
||||
Entry.DispatchLine = TEXT("Dispatch: unavailable");
|
||||
Entry.DetailLine = TEXT("Option dispatch is unavailable because the selector is not active.");
|
||||
Entry.bCanDispatch = false;
|
||||
++Surface.UnavailableOptionCount;
|
||||
}
|
||||
|
||||
if (Entry.bMatchesCurrentSelection)
|
||||
{
|
||||
Surface.bCurrentSelectionDispatchesDirectLaunch =
|
||||
Entry.DispatchKind
|
||||
== EHyperTwistTrainingCoachGeneratedModeOptionDispatchKind::DirectCaseLaunch;
|
||||
Surface.bCurrentSelectionDispatchesGeneratedChoice =
|
||||
Entry.DispatchKind
|
||||
== EHyperTwistTrainingCoachGeneratedModeOptionDispatchKind::ApplyGeneratedChoice;
|
||||
}
|
||||
|
||||
if (!Entry.bCanDispatch
|
||||
&& Entry.DispatchKind
|
||||
!= EHyperTwistTrainingCoachGeneratedModeOptionDispatchKind::Unavailable)
|
||||
{
|
||||
++Surface.UnavailableOptionCount;
|
||||
}
|
||||
|
||||
Surface.OptionEntries.Add(MoveTemp(Entry));
|
||||
}
|
||||
|
||||
Surface.bHasDispatchOptions = Surface.OptionEntries.Num() > 0;
|
||||
Surface.bHasDirectLaunchOptions = Surface.DirectLaunchOptionCount > 0;
|
||||
Surface.bHasGeneratedChoiceOptions = Surface.GeneratedChoiceOptionCount > 0;
|
||||
|
||||
if (Surface.bHasDispatchOptions)
|
||||
{
|
||||
Surface.DispatchSummaryLine = FString::Printf(
|
||||
TEXT("Dispatch: %d direct-launch | %d generated-choice | %d unavailable"),
|
||||
Surface.DirectLaunchOptionCount,
|
||||
Surface.GeneratedChoiceOptionCount,
|
||||
Surface.UnavailableOptionCount
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.DispatchSummaryLine = TEXT("Dispatch: no imported options");
|
||||
}
|
||||
|
||||
if (Surface.bCurrentSelectionDispatchesDirectLaunch)
|
||||
{
|
||||
Surface.CurrentSelectionDispatchLine =
|
||||
TEXT("Current selection dispatches as direct owned-case launch.");
|
||||
}
|
||||
else if (Surface.bCurrentSelectionDispatchesGeneratedChoice)
|
||||
{
|
||||
Surface.CurrentSelectionDispatchLine =
|
||||
TEXT("Current selection dispatches as generated-mode selector choice apply.");
|
||||
}
|
||||
else if (OptionMenuSurface.bHasUnresolvedSelectionDetail)
|
||||
{
|
||||
Surface.CurrentSelectionDispatchLine = OptionMenuSurface.UnresolvedSelectionLine.IsEmpty()
|
||||
? TEXT("Current selection does not currently map to an imported option.")
|
||||
: OptionMenuSurface.UnresolvedSelectionLine;
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelection)
|
||||
{
|
||||
Surface.CurrentSelectionDispatchLine =
|
||||
TEXT("Current selection has no additional dispatch detail.");
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelector)
|
||||
{
|
||||
Surface.CurrentSelectionDispatchLine = TEXT("Current selection: unresolved");
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.CurrentSelectionDispatchLine = TEXT("Current selection: n/a");
|
||||
}
|
||||
|
||||
if (OptionMenuSurface.bHasSelector && Surface.DirectLaunchOptionCount > 0
|
||||
&& Surface.GeneratedChoiceOptionCount == 0 && Surface.UnavailableOptionCount == 0)
|
||||
{
|
||||
Surface.StatusLine = FString::Printf(
|
||||
TEXT("Generated-mode selector option dispatch exposes %d direct-launch option%s and no fallback choice applies."),
|
||||
Surface.DirectLaunchOptionCount,
|
||||
Surface.DirectLaunchOptionCount == 1 ? TEXT("") : TEXT("s")
|
||||
);
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelector && Surface.GeneratedChoiceOptionCount > 0
|
||||
&& Surface.DirectLaunchOptionCount == 0 && Surface.UnavailableOptionCount == 0)
|
||||
{
|
||||
Surface.StatusLine = FString::Printf(
|
||||
TEXT("Generated-mode selector option dispatch exposes %d generated-choice option%s and no direct-launch cases."),
|
||||
Surface.GeneratedChoiceOptionCount,
|
||||
Surface.GeneratedChoiceOptionCount == 1 ? TEXT("") : TEXT("s")
|
||||
);
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelector && Surface.bHasDispatchOptions)
|
||||
{
|
||||
Surface.StatusLine = FString::Printf(
|
||||
TEXT("Generated-mode selector option dispatch exposes %d direct-launch option%s, %d generated-choice option%s, and %d unavailable option%s."),
|
||||
Surface.DirectLaunchOptionCount,
|
||||
Surface.DirectLaunchOptionCount == 1 ? TEXT("") : TEXT("s"),
|
||||
Surface.GeneratedChoiceOptionCount,
|
||||
Surface.GeneratedChoiceOptionCount == 1 ? TEXT("") : TEXT("s"),
|
||||
Surface.UnavailableOptionCount,
|
||||
Surface.UnavailableOptionCount == 1 ? TEXT("") : TEXT("s")
|
||||
);
|
||||
}
|
||||
else if (OptionMenuSurface.bHasSelector)
|
||||
{
|
||||
Surface.StatusLine =
|
||||
TEXT("Generated-mode selector option dispatch is active, but this selector does not expose imported options.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Surface.StatusLine = OptionMenuSurface.StatusLine.IsEmpty()
|
||||
? TEXT("Generated-mode selector option dispatch 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("Coverage: %s | Selector: %s | Binding: %s"),
|
||||
OptionActionabilitySurface.StatusLine.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *OptionActionabilitySurface.StatusLine,
|
||||
*SelectorSummary,
|
||||
*BindingSummary
|
||||
);
|
||||
|
||||
return Surface;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -733,6 +733,23 @@ UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeSelectorOptionActi
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchSurface
|
||||
UHyperTwistTrainingPanelWidget::GetDisplayedCoachGeneratedModeSelectorOptionDispatchSurface(
|
||||
const FString& SelectorId
|
||||
) const
|
||||
{
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface OptionMenuSurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionMenuSurface(SelectorId);
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionActionabilitySurface
|
||||
OptionActionabilitySurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionActionabilitySurface(SelectorId);
|
||||
return UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeSelectorOptionDispatchSurface(
|
||||
SelectorId,
|
||||
OptionMenuSurface,
|
||||
OptionActionabilitySurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachRecommendedRun(
|
||||
const int32 MaxCases,
|
||||
const FString& StartActionSourceLabel
|
||||
|
|
|
|||
|
|
@ -714,6 +714,23 @@ AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeSelectorOptionAct
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchSurface
|
||||
AHyperTwistTrainingSessionActor::GetDisplayedCoachGeneratedModeSelectorOptionDispatchSurface(
|
||||
const FString& SelectorId
|
||||
) const
|
||||
{
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface OptionMenuSurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionMenuSurface(SelectorId);
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionActionabilitySurface
|
||||
OptionActionabilitySurface =
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionActionabilitySurface(SelectorId);
|
||||
return UHyperTwistTrainingCoachLibrary::DeriveCoachGeneratedModeSelectorOptionDispatchSurface(
|
||||
SelectorId,
|
||||
OptionMenuSurface,
|
||||
OptionActionabilitySurface
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState AHyperTwistTrainingSessionActor::StartCoachRecommendedTrainingRun(
|
||||
const int32 MaxCases
|
||||
)
|
||||
|
|
|
|||
|
|
@ -704,4 +704,13 @@ public:
|
|||
const FString& SelectorId,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface& OptionMenuSurface
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
static FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchSurface
|
||||
DeriveCoachGeneratedModeSelectorOptionDispatchSurface(
|
||||
const FString& SelectorId,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionMenuSurface& OptionMenuSurface,
|
||||
const FHyperTwistTrainingCoachGeneratedModeSelectorOptionActionabilitySurface&
|
||||
OptionActionabilitySurface
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -264,6 +264,10 @@ public:
|
|||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionActionabilitySurface
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionActionabilitySurface(const FString& SelectorId) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchSurface
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionDispatchSurface(const FString& SelectorId) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedRun(
|
||||
int32 MaxCases,
|
||||
|
|
|
|||
|
|
@ -245,6 +245,10 @@ public:
|
|||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionActionabilitySurface
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionActionabilitySurface(const FString& SelectorId) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchSurface
|
||||
GetDisplayedCoachGeneratedModeSelectorOptionDispatchSurface(const FString& SelectorId) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
|
||||
FHyperTwistTrainingRunState StartCoachRecommendedTrainingRun(int32 MaxCases);
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,15 @@ enum class EHyperTwistTrainingCoachEligibilityKind : uint8
|
|||
NoEligibleAction UMETA(DisplayName = "No Eligible Action")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingCoachGeneratedModeOptionDispatchKind : uint8
|
||||
{
|
||||
None UMETA(DisplayName = "None"),
|
||||
DirectCaseLaunch UMETA(DisplayName = "Direct Case Launch"),
|
||||
ApplyGeneratedChoice UMETA(DisplayName = "Apply Generated Choice"),
|
||||
Unavailable UMETA(DisplayName = "Unavailable")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingPromptKind : uint8
|
||||
{
|
||||
|
|
@ -8776,3 +8785,121 @@ struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionActionabilitySurface
|
|||
|| bHasCaseCoverage;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchEntrySurface
|
||||
{
|
||||
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")
|
||||
EHyperTwistTrainingCoachGeneratedModeOptionDispatchKind DispatchKind =
|
||||
EHyperTwistTrainingCoachGeneratedModeOptionDispatchKind::None;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DispatchLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DirectLaunchOptionId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString GeneratedChoiceSelectedValue;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString GeneratedChoiceDisplayValue;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bMatchesCurrentSelection = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCanDispatch = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !OptionId.IsEmpty()
|
||||
|| !Label.IsEmpty()
|
||||
|| !DispatchLine.IsEmpty()
|
||||
|| DispatchKind != EHyperTwistTrainingCoachGeneratedModeOptionDispatchKind::None
|
||||
|| bCanDispatch;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchSurface
|
||||
{
|
||||
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 DispatchSummaryLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CurrentSelectionDispatchLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DetailLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchEntrySurface> OptionEntries;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DirectLaunchOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 GeneratedChoiceOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 UnavailableOptionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasSelector = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDispatchOptions = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasDirectLaunchOptions = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasGeneratedChoiceOptions = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCurrentSelectionDispatchesDirectLaunch = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCurrentSelectionDispatchesGeneratedChoice = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| !SelectorId.IsEmpty()
|
||||
|| OptionEntries.Num() > 0
|
||||
|| bHasSelector
|
||||
|| bHasDispatchOptions;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 actionability / case-coverage surface over the already-cached selector/runtime state, so gameplay/Blueprint callers can render which imported options still map cleanly to owned cases and which remain selection-only choices without reading raw option-case payloads or runtime probes directly
|
||||
- the current next bounded packet is to expose one thin generated-mode selector option interaction / dispatch surface on those same two consumer surfaces so gameplay/Blueprint callers can render whether choosing an option should launch a direct owned case, apply a generated-mode selector choice, or stay unavailable without reaching into raw runtime action-path 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 interaction / dispatch surface over the already-cached selector/runtime state, so gameplay/Blueprint callers can render whether choosing an option should launch a direct owned case, apply a generated-mode selector choice, or stay unavailable without reaching into raw runtime action-path rules directly
|
||||
- the current next bounded packet is to expose one thin generated-mode selector option execution-impact / launch-request-refresh surface on those same two consumer surfaces so gameplay/Blueprint callers can render whether a choice would start an owned case immediately, leave generated-mode execute posture unchanged, or require launch-request refresh before execute without reading raw launch-request freshness or blocked-reason 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,106 @@
|
|||
# HyperTwist Phase 4 gameplay generated-mode selector option interaction / dispatch 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 case-coverage surface by exposing one parameterized option interaction / dispatch surface for a chosen selector id.
|
||||
|
||||
The open tasks were:
|
||||
|
||||
- stop forcing gameplay / Blueprint callers to reconstruct runtime action-path rules just to decide whether choosing an imported option should launch a direct owned case or apply a generated-mode selector choice
|
||||
- expose exact dispatch posture and dispatch arguments for each imported option
|
||||
- keep the surface derived from already-cached gameplay consumer selector/runtime state plus the already-landed option-detail and case-coverage surfaces instead of widening into new backend behavior
|
||||
|
||||
It is not:
|
||||
|
||||
- a new selector-application behavior packet
|
||||
- a generated-mode execution packet
|
||||
- a launch-request refresh / execute-impact packet
|
||||
- a broader gameplay UI composition pass
|
||||
|
||||
## Scope
|
||||
|
||||
Bounded lane:
|
||||
|
||||
- add first-party generated-mode selector option dispatch surfaces in shared training types
|
||||
- add a coach-library helper that derives dispatch posture from the requested selector id plus the already-landed option-detail and case-coverage surfaces
|
||||
- expose that parameterized dispatch surface on `HyperTwistTrainingPanelWidget` and `HyperTwistTrainingSessionActor`
|
||||
- keep the derivation presentation-only and rooted in the already-owned runtime action paths
|
||||
|
||||
Out of scope:
|
||||
|
||||
- changing direct option-launch behavior
|
||||
- changing generated-mode selector-choice apply behavior
|
||||
- changing launch-request freshness rules
|
||||
- widening into execute-impact posture yet
|
||||
|
||||
## Why this was the right next packet
|
||||
|
||||
Before this slice:
|
||||
|
||||
- gameplay-facing panel/session consumers already exposed truthful generated-mode launch / execution context
|
||||
- those same consumers already exposed truthful selector / application context
|
||||
- those same consumers already exposed truthful selector roster / option-availability summary
|
||||
- those same consumers already exposed truthful chosen-selector option detail
|
||||
- those same consumers already exposed truthful chosen-selector option case coverage
|
||||
|
||||
But one thin consumer seam was still open:
|
||||
|
||||
- callers could tell whether an option still mapped to an owned case
|
||||
- but they still had to know raw runtime branching rules to decide whether interacting with that option should launch a direct case, apply a generated-mode selector choice, or stay unavailable
|
||||
|
||||
That meant:
|
||||
|
||||
- case coverage was thin and reusable
|
||||
- but actual option dispatch posture still leaked runtime action-path rules into callers
|
||||
|
||||
So the next bounded move was:
|
||||
|
||||
- keep the already-landed generated-mode context, roster, option-detail, and option-coverage surfaces unchanged
|
||||
- and expose one narrow option interaction / dispatch surface above those already-cached surfaces
|
||||
|
||||
## What landed
|
||||
|
||||
Primary code changes:
|
||||
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingTypes.h`
|
||||
- added `EHyperTwistTrainingCoachGeneratedModeOptionDispatchKind`
|
||||
- added `FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchEntrySurface`
|
||||
- added `FHyperTwistTrainingCoachGeneratedModeSelectorOptionDispatchSurface`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingCoachLibrary.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingCoachLibrary.cpp`
|
||||
- added `DeriveCoachGeneratedModeSelectorOptionDispatchSurface(...)`
|
||||
- dispatch posture is derived from the requested selector id plus the already-landed option-detail and option-coverage surfaces
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingPanelWidget.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingPanelWidget.cpp`
|
||||
- added `GetDisplayedCoachGeneratedModeSelectorOptionDispatchSurface(const FString& SelectorId)`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingSessionActor.h`
|
||||
- `UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSessionActor.cpp`
|
||||
- added `GetDisplayedCoachGeneratedModeSelectorOptionDispatchSurface(const FString& SelectorId)`
|
||||
|
||||
Surface behavior:
|
||||
|
||||
- reports whether each imported option dispatches as direct owned-case launch, generated-mode selector-choice apply, or unavailable
|
||||
- exposes exact dispatch arguments for direct launch and generated-choice apply flows
|
||||
- reports how the current cached selection would dispatch right now
|
||||
- keeps the surface presentation-only and compatible with the already-landed generated-mode option-detail and case-coverage 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 execution-impact / launch-request-refresh surface so callers can render whether choosing an option would start an owned case immediately, leave generated-mode execute posture unchanged, or require launch-request refresh before execute without reading raw launch-request freshness or blocked-reason rules directly.
|
||||
Loading…
Add table
Reference in a new issue