diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp index c43ff09..4fe2716 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistBootstrap/HyperTwistContractLibrary.cpp @@ -1282,7 +1282,8 @@ FHyperTwistTrainingCoachActionPlan UHyperTwistContractLibrary::MakeSampleTrainin TEXT("2026-04-28T12:05:00Z"), 0, 0, - FString() + FString(), + MakeSampleTrainingCoachBrief().FocusCaseIds ); } @@ -1323,7 +1324,8 @@ FHyperTwistTrainingCoachActionSequenceSummary UHyperTwistContractLibrary::MakeSa TEXT("2026-04-28T12:20:00Z"), 0, 0, - FString() + FString(), + FollowUpBrief.FocusCaseIds ); if (FollowUpPlan.IsStructurallyValid()) { @@ -1358,7 +1360,8 @@ FHyperTwistTrainingCoachActionClosureSummary UHyperTwistContractLibrary::MakeSam TEXT("2026-04-28T12:20:00Z"), 0, 0, - FString() + FString(), + FollowUpBrief.FocusCaseIds ); if (FollowUpPlan.IsStructurallyValid()) { @@ -1413,7 +1416,8 @@ FHyperTwistTrainingCoachRecommendationHistorySummary UHyperTwistContractLibrary: TEXT("2026-04-28T12:20:00Z"), 0, 0, - FString() + FString(), + FollowUpBrief.FocusCaseIds ); if (FollowUpPlan.IsStructurallyValid()) { @@ -1448,7 +1452,8 @@ FHyperTwistTrainingCoachCarryForwardPolicySummary UHyperTwistContractLibrary::Ma TEXT("2026-04-28T12:20:00Z"), 0, 0, - FString() + FString(), + FollowUpBrief.FocusCaseIds ); if (FollowUpPlan.IsStructurallyValid()) { @@ -1483,7 +1488,8 @@ FHyperTwistTrainingCoachArchivePolicySummary UHyperTwistContractLibrary::MakeSam TEXT("2026-04-28T12:20:00Z"), 0, 0, - FString() + FString(), + FollowUpBrief.FocusCaseIds ); if (FollowUpPlan.IsStructurallyValid()) { diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.cpp index b6b3545..ad05596 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.cpp @@ -743,6 +743,24 @@ namespace HyperTwistTrainingRepositoryLibraryInternal return UniqueCaseIds; } + TArray ResolveCoachActionPlanFocusCaseIds( + const FHyperTwistCoachBrief& CoachBrief, + const TArray& LaunchedCaseIds, + const int32 PlannedLaunchCaseCount) + { + TArray ResolvedCaseIds = DeduplicateCaseIds( + LaunchedCaseIds.Num() > 0 ? LaunchedCaseIds : CoachBrief.FocusCaseIds + ); + if (LaunchedCaseIds.Num() == 0 + && PlannedLaunchCaseCount > 0 + && ResolvedCaseIds.Num() > PlannedLaunchCaseCount) + { + ResolvedCaseIds.SetNum(PlannedLaunchCaseCount); + } + + return ResolvedCaseIds; + } + TArray DeduplicateMethodDrillResponses( const TArray& Responses ) @@ -6544,7 +6562,8 @@ FHyperTwistTrainingCoachActionPlan UHyperTwistTrainingRepositoryLibrary::BuildCo const FString& ReferenceUtc, const int32 RequestedLaunchCaseCount, const int32 PlannedLaunchCaseCount, - const FString& LaunchBudgetReasonLine + const FString& LaunchBudgetReasonLine, + const TArray& LaunchedCaseIds ) { FHyperTwistTrainingCoachActionPlan ActionPlan; @@ -6593,6 +6612,15 @@ FHyperTwistTrainingCoachActionPlan UHyperTwistTrainingRepositoryLibrary::BuildCo ActionPlan.PlannedLaunchCaseCount = PlannedLaunchCaseCount > 0 ? PlannedLaunchCaseCount : ActionPlan.RequestedLaunchCaseCount; + ActionPlan.FocusCaseIds = HyperTwistTrainingRepositoryLibraryInternal::ResolveCoachActionPlanFocusCaseIds( + CoachBrief, + LaunchedCaseIds, + ActionPlan.PlannedLaunchCaseCount + ); + if (ActionPlan.FocusCaseIds.Num() > 0) + { + ActionPlan.PlannedLaunchCaseCount = ActionPlan.FocusCaseIds.Num(); + } ActionPlan.LaunchBudgetReasonLine = LaunchBudgetReasonLine; ActionPlan.bBroadenedLaunchBudget = ActionPlan.PlannedLaunchCaseCount > ActionPlan.RequestedLaunchCaseCount @@ -6602,7 +6630,10 @@ FHyperTwistTrainingCoachActionPlan UHyperTwistTrainingRepositoryLibrary::BuildCo ActionPlan.PlannedLaunchCaseCount < ActionPlan.RequestedLaunchCaseCount || HyperTwistTrainingRepositoryLibraryInternal::ContainsLaunchBudgetTighteningHint( ActionPlan.LaunchBudgetReasonLine); - ActionPlan.FocusCaseIds = CoachBrief.FocusCaseIds; + if (ActionPlan.FocusCaseIds.Num() == 0) + { + ActionPlan.FocusCaseIds = CoachBrief.FocusCaseIds; + } ActionPlan.PlanState = EHyperTwistTrainingCoachActionPlanState::Draft; ActionPlan.FollowUpDepth = FMath::Max(0, CoachBrief.FollowUpDepth); ActionPlan.CreatedAtUtc = ActionPlan.ReferenceUtc; @@ -6611,11 +6642,11 @@ FHyperTwistTrainingCoachActionPlan UHyperTwistTrainingRepositoryLibrary::BuildCo ActionPlan.bNeedsVarietyRotation = CoachBrief.bNeedsVarietyRotation; ActionPlan.bPreferRecognitionReplayReview = CoachBrief.bPreferRecognitionReplayReview; - for (int32 Index = 0; Index < CoachBrief.FocusCaseIds.Num(); ++Index) + for (int32 Index = 0; Index < ActionPlan.FocusCaseIds.Num(); ++Index) { FHyperTwistTrainingCoachActionPlanEntry Entry; Entry.ActionId = FString::Printf(TEXT("%s_entry_%02d"), *PlanId, Index + 1); - Entry.CaseId = CoachBrief.FocusCaseIds[Index]; + Entry.CaseId = ActionPlan.FocusCaseIds[Index]; Entry.DeckId = CoachBrief.FocusDeckId; Entry.MethodSegmentId = CoachBrief.FocusMethodSegmentId; Entry.ActionLabel = CoachBrief.PrimaryActionLabel; diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp index bbda244..447ea48 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Private/HyperTwistTraining/HyperTwistTrainingSubsystem.cpp @@ -106,6 +106,20 @@ namespace HyperTwistTrainingSubsystemInternal return FString::Printf(TEXT("Launch cases: %d"), CaseCount); } + TArray ExtractCaseIdsFromDeck(const FHyperTwistTrainingDeck& Deck) + { + TArray CaseIds; + for (const FHyperTwistTrainingCase& TrainingCase : Deck.Cases) + { + if (!TrainingCase.CaseId.IsEmpty()) + { + CaseIds.Add(TrainingCase.CaseId); + } + } + + return CaseIds; + } + FResolvedCoachCaseBudget ResolvePreferredCoachCaseBudget( const int32 MaxCases, const EHyperTwistTrainingCoachGuidanceLane DeckLane, @@ -1572,6 +1586,8 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachRecommendedR ActiveCoachMemorySnapshot, false ); + const TArray LaunchedCaseIds = + HyperTwistTrainingSubsystemInternal::ExtractCaseIdsFromDeck(CoachDeck); const FHyperTwistTrainingCoachActionPlan DraftActionPlan = UHyperTwistTrainingRepositoryLibrary::BuildCoachActionPlan( ActiveCoachBrief, @@ -1580,7 +1596,8 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachRecommendedR FString(), LaunchBudget.RequestedCaseCount, CoachDeck.Cases.Num(), - LaunchBudget.ReasonLine + LaunchBudget.ReasonLine, + LaunchedCaseIds ); FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck( CoachDeck, @@ -1646,6 +1663,8 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachFollowUpRun( ActiveCoachMemorySnapshot, false ); + const TArray LaunchedCaseIds = + HyperTwistTrainingSubsystemInternal::ExtractCaseIdsFromDeck(FollowUpDeck); const FHyperTwistTrainingCoachActionPlan DraftActionPlan = UHyperTwistTrainingRepositoryLibrary::BuildCoachActionPlan( FollowUpBrief, @@ -1654,7 +1673,8 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachFollowUpRun( FString(), LaunchBudget.RequestedCaseCount, FollowUpDeck.Cases.Num(), - LaunchBudget.ReasonLine + LaunchBudget.ReasonLine, + LaunchedCaseIds ); FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck( FollowUpDeck, @@ -1748,6 +1768,8 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartNextQueuedCoachRu ActiveCoachMemorySnapshot, true ); + const TArray LaunchedCaseIds = + HyperTwistTrainingSubsystemInternal::ExtractCaseIdsFromDeck(QueueDeck); const FHyperTwistTrainingCoachActionPlan DraftActionPlan = UHyperTwistTrainingRepositoryLibrary::BuildCoachActionPlan( QueueBrief, @@ -1756,7 +1778,8 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartNextQueuedCoachRu FString(), LaunchBudget.RequestedCaseCount, QueueDeck.Cases.Num(), - LaunchBudget.ReasonLine + LaunchBudget.ReasonLine, + LaunchedCaseIds ); FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck( QueueDeck, @@ -1888,6 +1911,8 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachQueueEntry( } const FHyperTwistTrainingCoachSessionQueueState QueueStateBeforeStart = ActiveCoachSessionQueueState; + const TArray LaunchedCaseIds = + HyperTwistTrainingSubsystemInternal::ExtractCaseIdsFromDeck(QueueDeck); const FHyperTwistTrainingCoachActionPlan DraftActionPlan = (!QueueBrief.UserId.IsEmpty() && !QueueBrief.Headline.IsEmpty()) ? UHyperTwistTrainingRepositoryLibrary::BuildCoachActionPlan( @@ -1897,7 +1922,8 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartCoachQueueEntry( FString(), LaunchBudget.RequestedCaseCount, QueueDeck.Cases.Num(), - LaunchBudget.ReasonLine + LaunchBudget.ReasonLine, + LaunchedCaseIds ) : FHyperTwistTrainingCoachActionPlan(); FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck( diff --git a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.h b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.h index 29a6b2f..da16c98 100644 --- a/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.h +++ b/UnrealHyperTwist/Source/UnrealHyperTwist/Public/HyperTwistTraining/HyperTwistTrainingRepositoryLibrary.h @@ -315,7 +315,8 @@ public: const FString& ReferenceUtc, int32 RequestedLaunchCaseCount, int32 PlannedLaunchCaseCount, - const FString& LaunchBudgetReasonLine + const FString& LaunchBudgetReasonLine, + const TArray& LaunchedCaseIds ); UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository|Coach")