Files
DTFluxAPI/Source/DTFluxCoreSubsystem/Private/DTFluxPursuitManager.cpp

351 lines
11 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "DTFluxPursuitManager.h"
#include <ImportExport.h>
#include "DTFluxCoreSubsystem.h"
#include "DTFluxCoreSubsystemModule.h"
#include "Dataflow/DataflowContextCache.h"
UDTFluxPursuitManager::UDTFluxPursuitManager(const FObjectInitializer& ObjectInitializer):
Super(ObjectInitializer)
{
}
void UDTFluxPursuitManager::InitPursuit(const TArray<int> InContestIds, const int MaxSimultaneousPursuit)
{
CoreSubsystem = Cast<UDTFluxCoreSubsystem>(GetOuter());
if (!CoreSubsystem)
{
UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("CoreSubsystem is not Available !!!"));
return;
}
AllRankings.Reset();
for (const auto& ContestId : InContestIds)
{
FDTFluxContest Contest;
if (CoreSubsystem->GetContestForId(ContestId, Contest))
{
BindRankings();
FDTFluxStageKey StageKey = FDTFluxStageKey(ContestId, Contest.GetLastStageId());
FDTFluxStageRankings TempStageRankings;
//Obtenir les ranking Frais.
CoreSubsystem->GetStageRankingsWithKey(StageKey, TempStageRankings, false);
PendingStageRanking.Add(StageKey, false);
}
}
}
void UDTFluxPursuitManager::SetPursuitInfoIsMassStart(FDTFluxPursuitGroup& NextFocusGroup)
{
for (auto& Pursuit : NextFocusGroup.PursuitGroup)
{
Pursuit.bIsMassStart = Pursuit.StartTime >= MassStartTime;
}
}
void UDTFluxPursuitManager::DebugFocusNext(const TArray<FDTFluxPursuitInfo>& OutPursuitFocusNext)
{
FString FocusBibs;
for (const auto& Pursuit : OutPursuitFocusNext)
{
FocusBibs += FString::Printf(TEXT("%d "), Pursuit.Bib);
}
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Focus Bibs: %s"), *FocusBibs);
}
void UDTFluxPursuitManager::DebugOutPoursuitNext(const TArray<FDTFluxPursuitInfo>& OutPursuitNext)
{
FString NextBibs;
for (int32 i = 0; i < OutPursuitNext.Num(); i++)
{
NextBibs += FString::Printf(TEXT("%d "), OutPursuitNext[i].Bib);
}
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Next Bibs: %s"), *NextBibs);
}
void UDTFluxPursuitManager::GetPursuit(TArray<FDTFluxPursuitInfo>& OutPursuitFocusNext,
TArray<FDTFluxPursuitInfo>& OutPursuitNext, bool& BIsFocusTruncate,
const int MaxSimultaneousPursuit)
{
FDateTime MetricsStartFunction = FDateTime::UtcNow();
FDateTime CurrentTime = FDateTime::Now();
// UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("=== GetPursuit CALLED ==="));
// UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("MaxSimultaneousPursuit: %d"), MaxSimultaneousPursuit);
// UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Available groups: %d"), GroupedPursuit.Num());
// BAd Parameter
if (MaxSimultaneousPursuit <= 0)
{
UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("Invalid MaxSimultaneousPursuit: %d"), MaxSimultaneousPursuit);
OutPursuitFocusNext.Reset();
OutPursuitNext.Reset();
BIsFocusTruncate = false;
return;
}
if (bIsSequenceDone || GroupedPursuit.IsEmpty())
{
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("No groups available or sequence completed"));
OutPursuitFocusNext.Reset();
OutPursuitNext.Reset();
BIsFocusTruncate = false;
return;
}
for (int32 i = GroupedPursuit.Num() - 1; i >= 0; i--) // Parcours inverse pour éviter les problèmes d'index
{
const FDTFluxPursuitGroup& Group = GroupedPursuit[i];
UE_LOG(logDTFluxCoreSubsystem, Log, TEXT("Group.StartTimeGlobal(%s) < CurrentTime(%s) "),
*Group.StartTimeGlobal.ToString(), *CurrentTime.ToString())
// Vérifier si le StartTime du groupe est déjà passé
if (Group.StartTimeGlobal < CurrentTime)
{
UE_LOG(logDTFluxCoreSubsystem, Warning,
TEXT("Removing expired group: StartTime=%s (Current=%s), Participants=%d"),
*Group.StartTimeGlobal.ToString(),
*CurrentTime.ToString(),
Group.PursuitGroup.Num());
GroupedPursuit.RemoveAt(i);
}
}
OutPursuitFocusNext.Reset();
OutPursuitNext.Reset();
// === VÉRIFICATION CRITIQUE : S'assurer qu'il reste des groupes après suppression ===
if (GroupedPursuit.IsEmpty())
{
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("All groups were expired and removed - no groups available"));
OutPursuitFocusNext.Reset();
OutPursuitNext.Reset();
BIsFocusTruncate = false;
bIsSequenceDone = true; // Marquer la séquence comme terminée
return;
}
FDTFluxPursuitGroup FocusGroup = GroupedPursuit[0];
GroupedPursuit.RemoveAt(0);
SetPursuitInfoIsMassStart(FocusGroup);
OutPursuitFocusNext = FocusGroup.PursuitGroup;
BIsFocusTruncate = FocusGroup.PursuitGroup.Num() > 1;
UE_LOG(logDTFluxCoreSubsystem, Warning,
TEXT("Focus Group: StartTime=%s, Participants=%d"),
*FocusGroup.StartTimeGlobal.ToString(),
FocusGroup.PursuitGroup.Num());
int32 TargetNextCount = MaxSimultaneousPursuit - 1;
int32 AddedNextCount = 0;
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Target Next Count: %d"), TargetNextCount);
for (int32 GroupIndex = 0;
GroupIndex < GroupedPursuit.Num() && AddedNextCount < TargetNextCount;
GroupIndex++)
{
FDTFluxPursuitGroup& NextGroup = GroupedPursuit[GroupIndex];
if (NextGroup.PursuitGroup.Num() == 0)
{
continue;
}
int32 AvailableInGroup = NextGroup.PursuitGroup.Num();
int32 NeededFromGroup = FMath::Min(TargetNextCount - AddedNextCount, AvailableInGroup);
UE_LOG(logDTFluxCoreSubsystem, Warning,
TEXT("Processing Next Group %d: StartTime=%s, Available=%d, Taking=%d"),
GroupIndex,
*NextGroup.StartTimeGlobal.ToString(),
AvailableInGroup,
NeededFromGroup);
for (int32 ParticipantIndex = 0; ParticipantIndex < NeededFromGroup; ParticipantIndex++)
{
FDTFluxPursuitInfo NextParticipant = NextGroup.PursuitGroup[ParticipantIndex]; // Copie
NextParticipant.bIsMassStart = NextParticipant.StartTime >= MassStartTime;
OutPursuitNext.Add(NextParticipant);
AddedNextCount++;
UE_LOG(logDTFluxCoreSubsystem, VeryVerbose,
TEXT("Added to Next: Bib %d from Group %d"),
NextParticipant.Bib, GroupIndex);
}
}
// === LOGS DE RÉSUMÉ ===
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("=== PURSUIT RESULTS ==="));
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Focus: %d participants"), OutPursuitFocusNext.Num());
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Next: %d participants"), OutPursuitNext.Num());
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Remaining groups for future: %d"), GroupedPursuit.Num());
if (OutPursuitFocusNext.Num() > 0)
{
DebugFocusNext(OutPursuitFocusNext);
}
// Log détaillé des Next (limité pour éviter spam)
if (OutPursuitNext.Num() > 0)
{
DebugOutPoursuitNext(OutPursuitNext);
}
// Vérifier si la séquence est terminée
if (GroupedPursuit.IsEmpty())
{
bIsSequenceDone = true;
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Pursuit sequence will be completed after this round"));
}
FTimespan Duration = FDateTime::UtcNow() - MetricsStartFunction;
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Metrics Time Out: %d fraction seconds"),
Duration.GetDuration().GetFractionMicro());
}
bool UDTFluxPursuitManager::InitSubSystems()
{
if (NetworkSubsystem)
{
return true;
}
NetworkSubsystem = GEngine->GetEngineSubsystem<UDTFluxNetworkSubsystem>();
return NetworkSubsystem != nullptr;
}
bool UDTFluxPursuitManager::BindRankings()
{
if (CoreSubsystem)
{
if (!bIsRankingBounded)
{
CoreSubsystem->OnStageRankings.AddDynamic(this, &UDTFluxPursuitManager::OnRankingsReceived);
bIsRankingBounded = true;
}
return bIsRankingBounded;
}
UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("CoreSubsystem is not Available !!!"));
return bIsRankingBounded = false;
}
void UDTFluxPursuitManager::UnbindRankings()
{
if (CoreSubsystem)
{
if (bIsRankingBounded)
{
CoreSubsystem->OnStageRankings.RemoveDynamic(this, &UDTFluxPursuitManager::OnRankingsReceived);
bIsRankingBounded = false;
return;
}
}
bIsRankingBounded = false;
UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("CoreSubsystem is not Available !!!"));
}
void UDTFluxPursuitManager::OnRankingsReceived(const FDTFluxStageKey NewStageKey,
const FDTFluxStageRankings NewStageRankings)
{
if (PendingStageRanking.Contains(NewStageKey))
{
PendingStageRanking.Remove(NewStageKey);
AllRankings.Add(NewStageRankings);
if (PendingStageRanking.IsEmpty())
{
//everything is ready to go compute and start
UnbindRankings();
LaunchPursuitSequence();
}
}
}
bool UDTFluxPursuitManager::LaunchPursuitSequence()
{
GroupedPursuit.Empty();
TArray<FDTFluxPursuitInfo> AllPursuits;
TMap<FDateTime, FDTFluxPursuitGroup> TempGroups;
bIsSequenceDone = false;
// Full the Array Of Rankings
for (auto& Ranking : AllRankings)
{
for (auto StageRanking : Ranking.Rankings)
{
int ContestId = Ranking.ContestId;
FDTFluxPursuitInfo PursuitInfo;
PursuitInfo.StartTime = StageRanking.StartTime;
PursuitInfo.Bib = StageRanking.Bib;
PursuitInfo.ContestId = ContestId;
AllPursuits.Add(PursuitInfo);
}
}
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("AllPursuits.Num() = %i"), AllPursuits.Num());
for (auto& Pursuit : AllPursuits)
{
if (TempGroups.Contains(Pursuit.StartTime))
{
FDTFluxPursuitGroup& Group = TempGroups[Pursuit.StartTime];
Group.PursuitGroup.Add(Pursuit);
UE_LOG(logDTFluxCoreSubsystem, Warning,
TEXT("Adding [%i] To PursuitGroup starting At %s, PursuitGroup.Num() %i"),
Pursuit.Bib, *Pursuit.StartTime.ToString(), Group.PursuitGroup.Num());
}
else
{
FDTFluxPursuitGroup NewGroup;
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("New Group starting At %s, Adding Bib [%i]"),
*Pursuit.StartTime.ToString(), Pursuit.Bib);
NewGroup.StartTimeGlobal = Pursuit.StartTime;
NewGroup.PursuitGroup.Add(Pursuit);
TempGroups.Add(Pursuit.StartTime, NewGroup);
for (const auto& Group : TempGroups)
{
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Group.StartTime = %s, Group.PursuitGroup.Num() = %i"),
*Group.Key.ToString(), Group.Value.PursuitGroup.Num());
}
}
}
TempGroups.KeySort([](const FDateTime& A, const FDateTime& B)
{
return A < B;
});
TMap<FDateTime, int> StartTimeFrequency;
int32 MaxFrequency = 0;
GroupedPursuit.Reserve(TempGroups.Num());
// parcours du TMap
for (const auto& Pair : TempGroups)
{
if (Pair.Value.StartTimeGlobal != FDateTime::MinValue() && Pair.Value.StartTimeGlobal != FDateTime::MaxValue())
{
// récuperation de la ref de la valeur actuel de la fréquence dans la TMap Freq
int& CurrentFreq = StartTimeFrequency.FindOrAdd(Pair.Value.StartTimeGlobal, 0);
CurrentFreq = Pair.Value.PursuitGroup.Num();
if (CurrentFreq > MaxFrequency)
{
MaxFrequency = CurrentFreq;
MassStartTime = Pair.Value.StartTimeGlobal;
}
}
GroupedPursuit.Add(Pair.Value);
}
GroupedPursuit.Sort([](const FDTFluxPursuitGroup& A, const FDTFluxPursuitGroup& B)
{
return A.StartTimeGlobal < B.StartTimeGlobal;
});
TArray<FDTFluxPursuitInfo> FocusPursuits;
TArray<FDTFluxPursuitInfo> NextPursuits;
bool bIsFocusTruncate = false;
GetPursuit(FocusPursuits, NextPursuits, bIsFocusTruncate);
FPursuitStarterData PursuitData = FPursuitStarterData(FocusPursuits, NextPursuits, MassStartTime, bIsFocusTruncate);
OnPursuitSequenceReady.Broadcast(PursuitData);
return true;
}