diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp index 2dba5f1..cb882a7 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistCoachDashboardWidget.cpp @@ -172,6 +172,32 @@ namespace HyperTwistCoachDashboardWidgetInternal } } + FString ExtractDetailFieldValue( + const FString& DetailLine, + const FString& FieldName) + { + if (DetailLine.IsEmpty() || FieldName.IsEmpty()) + { + return FString(); + } + + const FString Prefix = FieldName + TEXT("="); + const int32 PrefixIndex = DetailLine.Find(Prefix, ESearchCase::CaseSensitive); + if (PrefixIndex == INDEX_NONE) + { + return FString(); + } + + const int32 ValueStart = PrefixIndex + Prefix.Len(); + int32 ValueEnd = DetailLine.Find(TEXT(","), ESearchCase::CaseSensitive, ESearchDir::FromStart, ValueStart); + if (ValueEnd == INDEX_NONE) + { + ValueEnd = DetailLine.Len(); + } + + return DetailLine.Mid(ValueStart, ValueEnd - ValueStart).TrimStartAndEnd(); + } + FString DescribeRetainedMethodDrillRecoveryPosture( const bool bUsedStrongRetainedMethodDrillRecoveryPosture, const bool bUsedWeakRetainedMethodDrillRecoveryPosture) @@ -4887,6 +4913,9 @@ void UHyperTwistCoachDashboardWidget::SyncRetainedRunRecap() ActiveMethodDrillFollowUpLaunchDiagnosticPacket = FHyperTwistTrainingMethodDrillDiagnosticPacket(); ActiveMethodDrillFollowUpLaunchTemplate = FHyperTwistTrainingSessionTemplate(); + ActiveMethodDrillFollowUpLaunchPacketStructureLabel.Reset(); + ActiveMethodDrillFollowUpLaunchPacketLaneLabel.Reset(); + ActiveMethodDrillFollowUpLaunchPacketStanceLabel.Reset(); } } } @@ -5098,6 +5127,25 @@ void UHyperTwistCoachDashboardWidget::CaptureActiveMethodDrillFollowUpLaunchCont ActiveMethodDrillFollowUpLaunchSessionId = SessionId; ActiveMethodDrillFollowUpLaunchDiagnosticPacket = CachedMethodDrillDiagnosticPacket; ActiveMethodDrillFollowUpLaunchTemplate = CachedMethodDrillFollowUpTemplate; + ActiveMethodDrillFollowUpLaunchPacketStructureLabel.Reset(); + ActiveMethodDrillFollowUpLaunchPacketLaneLabel.Reset(); + ActiveMethodDrillFollowUpLaunchPacketStanceLabel.Reset(); + if (CachedCoachFollowUpBrief.Signals.Num() > 0) + { + const FHyperTwistCoachSignal& Signal = CachedCoachFollowUpBrief.Signals[0]; + ActiveMethodDrillFollowUpLaunchPacketStructureLabel = + HyperTwistCoachDashboardWidgetInternal::ExtractDetailFieldValue( + Signal.Detail, + TEXT("deferredPacketOrdering")); + ActiveMethodDrillFollowUpLaunchPacketLaneLabel = + HyperTwistCoachDashboardWidgetInternal::ExtractDetailFieldValue( + Signal.Detail, + TEXT("drillRecoveryPacketLane")); + ActiveMethodDrillFollowUpLaunchPacketStanceLabel = + HyperTwistCoachDashboardWidgetInternal::ExtractDetailFieldValue( + Signal.Detail, + TEXT("drillRecoveryPacketStance")); + } } FHyperTwistTrainingDeck UHyperTwistCoachDashboardWidget::BuildSelectedGuidancePreviewCaseDeck() const @@ -6057,6 +6105,47 @@ UHyperTwistCoachDashboardWidget::BuildMethodDrillFollowUpWeighting() const { ++Weighting.RedirectCoachBias; } + if (Entry.PacketStructureLabel.Equals(TEXT("queue-entry-first"), ESearchCase::IgnoreCase)) + { + ++Weighting.QueueEntryFirstStructureCount; + } + else if (Entry.PacketStructureLabel.Equals(TEXT("follow-up-packet-first"), ESearchCase::IgnoreCase)) + { + ++Weighting.FollowUpPacketFirstStructureCount; + } + else if (Entry.PacketStructureLabel.Equals(TEXT("recommended-brief-first"), ESearchCase::IgnoreCase)) + { + ++Weighting.RecommendedBriefFirstStructureCount; + } + else if (Entry.PacketStructureLabel.Equals(TEXT("recommended-brief-redirect"), ESearchCase::IgnoreCase) + || Entry.PacketStructureLabel.Equals(TEXT("broadened-redirect-first"), ESearchCase::IgnoreCase)) + { + ++Weighting.RecommendedRedirectStructureCount; + } + if (Entry.bPacketProvenStrongContinuation) + { + ++Weighting.StrongPacketContinuationCount; + if (bStrongOutcome) + { + Weighting.ContinueNarrowBias += 2; + } + else if (bWeakOutcome) + { + ++Weighting.RedirectCoachBias; + } + } + if (Entry.bPacketProvenWeakRedirect) + { + ++Weighting.WeakPacketRedirectCount; + if (bStrongOutcome) + { + Weighting.RedirectCoachBias += 2; + } + else if (bWeakOutcome) + { + ++Weighting.ContinueNarrowBias; + } + } } if (Weighting.MatchingHistoryCount <= 0) @@ -6559,12 +6648,19 @@ void UHyperTwistCoachDashboardWidget::RecordMethodDrillFollowUpHistoryEntry( Entry.CompletedAttemptCount = CompletedRunRecap.CompletedAttemptCount; Entry.TotalMistakes = CompletedRunRecap.TotalMistakes; Entry.SuccessRate = CompletedRunRecap.SuccessRate; + Entry.PacketStructureLabel = ActiveMethodDrillFollowUpLaunchPacketStructureLabel; + Entry.PacketLaneLabel = ActiveMethodDrillFollowUpLaunchPacketLaneLabel; + Entry.PacketStanceLabel = ActiveMethodDrillFollowUpLaunchPacketStanceLabel; Entry.bBoundaryPending = ActiveMethodDrillFollowUpLaunchDiagnosticPacket.bBoundaryTriggeredByPendingCases; Entry.bBoundaryRepeatBurden = ActiveMethodDrillFollowUpLaunchDiagnosticPacket.bBoundaryTriggeredByRepeatBurden; Entry.bBoundaryAssistance = ActiveMethodDrillFollowUpLaunchDiagnosticPacket.bBoundaryTriggeredByAssistance; + Entry.bPacketProvenStrongContinuation = + Entry.PacketStanceLabel.Equals(TEXT("strong continuation"), ESearchCase::IgnoreCase); + Entry.bPacketProvenWeakRedirect = + Entry.PacketStanceLabel.Equals(TEXT("weak redirect"), ESearchCase::IgnoreCase); if (!Entry.IsStructurallyValid()) { return; @@ -7211,7 +7307,7 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() const FString MethodDrillFollowUpHistoryDetailLine = SelectedMethodDrillFollowUpHistoryEntry != nullptr ? FString::Printf( - TEXT("State: %s | template: %s | mode: %s | selection: %s | focus %d | launched %d | success %.2f | attempts %d | mistakes %d | pending: %s | repeat burden: %s | assistance: %s"), + TEXT("State: %s | template: %s | mode: %s | selection: %s | focus %d | launched %d | success %.2f | attempts %d | mistakes %d | packet structure: %s | packet lane: %s | packet stance: %s | pending: %s | repeat burden: %s | assistance: %s"), *HyperTwistCoachDashboardWidgetInternal::EnumDisplayName( SelectedMethodDrillFollowUpHistoryEntry->DiagnosticState), *HyperTwistCoachDashboardWidgetInternal::EnumDisplayName( @@ -7225,6 +7321,15 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() SelectedMethodDrillFollowUpHistoryEntry->SuccessRate, SelectedMethodDrillFollowUpHistoryEntry->CompletedAttemptCount, SelectedMethodDrillFollowUpHistoryEntry->TotalMistakes, + SelectedMethodDrillFollowUpHistoryEntry->PacketStructureLabel.IsEmpty() + ? TEXT("default") + : *SelectedMethodDrillFollowUpHistoryEntry->PacketStructureLabel, + SelectedMethodDrillFollowUpHistoryEntry->PacketLaneLabel.IsEmpty() + ? TEXT("none") + : *SelectedMethodDrillFollowUpHistoryEntry->PacketLaneLabel, + SelectedMethodDrillFollowUpHistoryEntry->PacketStanceLabel.IsEmpty() + ? TEXT("none") + : *SelectedMethodDrillFollowUpHistoryEntry->PacketStanceLabel, SelectedMethodDrillFollowUpHistoryEntry->bBoundaryPending ? TEXT("yes") : TEXT("no"), SelectedMethodDrillFollowUpHistoryEntry->bBoundaryRepeatBurden ? TEXT("yes") : TEXT("no"), SelectedMethodDrillFollowUpHistoryEntry->bBoundaryAssistance ? TEXT("yes") : TEXT("no")) @@ -7237,13 +7342,19 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation() *MethodDrillOutcomePreferenceLine ); MethodDrillDiagnosticsDetailLine = FString::Printf( - TEXT("%s || History match %d | strong %d | weak %d | avg success %.2f | avg mistakes %.2f"), + TEXT("%s || History match %d | strong %d | weak %d | avg success %.2f | avg mistakes %.2f | strong packet cont %d | weak packet redirect %d | queue/follow-up/recommended-first %d/%d/%d | redirect packets %d"), *MethodDrillDiagnosticsDetailLine, MethodDrillFollowUpWeighting.MatchingHistoryCount, MethodDrillFollowUpWeighting.StrongOutcomeCount, MethodDrillFollowUpWeighting.WeakOutcomeCount, MethodDrillFollowUpWeighting.AverageSuccessRate, - MethodDrillFollowUpWeighting.AverageMistakes + MethodDrillFollowUpWeighting.AverageMistakes, + MethodDrillFollowUpWeighting.StrongPacketContinuationCount, + MethodDrillFollowUpWeighting.WeakPacketRedirectCount, + MethodDrillFollowUpWeighting.QueueEntryFirstStructureCount, + MethodDrillFollowUpWeighting.FollowUpPacketFirstStructureCount, + MethodDrillFollowUpWeighting.RecommendedBriefFirstStructureCount, + MethodDrillFollowUpWeighting.RecommendedRedirectStructureCount ); } if (bCanLaunchMethodDrillFollowUp && MethodDrillFollowUpWeighting.bPreferDrillFollowUp) diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h index 4a5cc04..c516e33 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistCoachDashboardWidget.h @@ -315,9 +315,14 @@ struct FHyperTwistCoachDashboardMethodDrillFollowUpHistoryEntry int32 CompletedAttemptCount = 0; int32 TotalMistakes = 0; float SuccessRate = 0.0f; + FString PacketStructureLabel; + FString PacketLaneLabel; + FString PacketStanceLabel; bool bBoundaryPending = false; bool bBoundaryRepeatBurden = false; bool bBoundaryAssistance = false; + bool bPacketProvenStrongContinuation = false; + bool bPacketProvenWeakRedirect = false; bool IsStructurallyValid() const { @@ -369,6 +374,12 @@ struct FHyperTwistCoachDashboardMethodDrillFollowUpWeighting int32 WeakOutcomeCount = 0; int32 ContinueNarrowBias = 0; int32 RedirectCoachBias = 0; + int32 StrongPacketContinuationCount = 0; + int32 WeakPacketRedirectCount = 0; + int32 QueueEntryFirstStructureCount = 0; + int32 FollowUpPacketFirstStructureCount = 0; + int32 RecommendedBriefFirstStructureCount = 0; + int32 RecommendedRedirectStructureCount = 0; float AverageSuccessRate = 0.0f; float AverageMistakes = 0.0f; bool bPreferDrillFollowUp = false; @@ -1446,6 +1457,9 @@ private: FString ActiveMethodDrillFollowUpLaunchSessionId; FHyperTwistTrainingMethodDrillDiagnosticPacket ActiveMethodDrillFollowUpLaunchDiagnosticPacket; FHyperTwistTrainingSessionTemplate ActiveMethodDrillFollowUpLaunchTemplate; + FString ActiveMethodDrillFollowUpLaunchPacketStructureLabel; + FString ActiveMethodDrillFollowUpLaunchPacketLaneLabel; + FString ActiveMethodDrillFollowUpLaunchPacketStanceLabel; bool bHasRetainedGuidanceComparison = false; FString RetainedGuidanceComparisonSessionId; EHyperTwistCoachDashboardGuidancePreviewLane RetainedGuidanceComparisonLane =