Compare commits

..

3 Commits

5 changed files with 181 additions and 97 deletions

View File

@ -35,73 +35,74 @@ FString FDTFluxPerson::GetNormalizedString() const
bool FDTFluxPerson::IsValid() const
{
return !FirstName.TrimStartAndEnd().IsEmpty() &&
!LastName.TrimStartAndEnd().IsEmpty() &&
!Gender.TrimStartAndEnd().IsEmpty();
return !FirstName.TrimStartAndEnd().IsEmpty() &&
!LastName.TrimStartAndEnd().IsEmpty() &&
!Gender.TrimStartAndEnd().IsEmpty();
}
FDTFluxParticipant::FDTFluxParticipant()
: Bib(-1)
, ContestId(-1)
, Elite(false)
, Status(static_cast<EDTFluxParticipantStatusType>(0))
, bIsMassStartParticipant(false)
, CurrentSplit(-1)
, ContestId(-1)
, Elite(false)
, Status(static_cast<EDTFluxParticipantStatusType>(0))
, bIsMassStartParticipant(false)
, CurrentSplit(-1)
{
Teammate.Reset();
}
FDTFluxParticipant::FDTFluxParticipant(const TSharedPtr<FJsonObject>& JsonObject)
: Bib(JsonObject->GetIntegerField(TEXT("bib")))
, ContestId(JsonObject->GetIntegerField(TEXT("contestId")))
, Category(JsonObject->GetStringField(TEXT("category")))
, Club(JsonObject->GetStringField(TEXT("club")))
, Elite(JsonObject->GetBoolField(TEXT("elite")))
, Status(static_cast<EDTFluxParticipantStatusType>(JsonObject->GetIntegerField(TEXT("status"))))
, Team(JsonObject->GetStringField(TEXT("team")))
, CurrentSplit(-1)
, ContestId(JsonObject->GetIntegerField(TEXT("contestId")))
, Category(JsonObject->GetStringField(TEXT("category")))
, Club(JsonObject->GetStringField(TEXT("club")))
, Elite(JsonObject->GetBoolField(TEXT("elite")))
, Status(static_cast<EDTFluxParticipantStatusType>(JsonObject->GetIntegerField(TEXT("status"))))
, Team(JsonObject->GetStringField(TEXT("team")))
, CurrentSplit(-1)
{
UE_LOG(logDTFluxCore, Log, TEXT("Creating participant from JSON - Bib: %d, Contest: %d"), Bib, ContestId);
for (uint8 Index = 1; Index <= 10; Index++)
{
FString FirstNameKey = Index == 1 ? TEXT("firstName") : FString::Printf(TEXT("firstName%d"), Index);
FString LastNameKey = Index == 1 ? TEXT("lastName") : FString::Printf(TEXT("lastName%d"), Index);
FString GenderKey = Index == 1 ? TEXT("gender") : FString::Printf(TEXT("gender%d"), Index);
// Vérifie si au moins un des champs existe
if (!JsonObject->HasField(FirstNameKey) && !JsonObject->HasField(LastNameKey) && !JsonObject->HasField(GenderKey))
if (!JsonObject->HasField(FirstNameKey) && !JsonObject->HasField(LastNameKey) && !JsonObject->
HasField(GenderKey))
{
break;
}
const FString FirstName = JsonObject->GetStringField(FirstNameKey);
const FString LastName = JsonObject->GetStringField(LastNameKey);
const FString Gender = JsonObject->GetStringField(GenderKey);
if (FirstName.TrimStartAndEnd().IsEmpty() && LastName.TrimStartAndEnd().IsEmpty())
{
continue;
}
FDTFluxPerson Person;
Person.FirstName = FirstName.TrimStartAndEnd();
Person.LastName = LastName.TrimStartAndEnd();
Person.Gender = Gender.TrimStartAndEnd();
if (Person.IsValid())
{
Teammate.Add(Person);
UE_LOG(logDTFluxCore, Verbose, TEXT("Added person %d: %s %s (%s)"),
UE_LOG(logDTFluxCore, Verbose, TEXT("Added person %d: %s %s (%s)"),
Index, *Person.FirstName, *Person.LastName, *Person.Gender);
}
else
{
UE_LOG(logDTFluxCore, Warning, TEXT("Invalid person data at index %d: '%s' '%s' '%s'"),
UE_LOG(logDTFluxCore, Warning, TEXT("Invalid person data at index %d: '%s' '%s' '%s'"),
Index, *FirstName, *LastName, *Gender);
}
}
UE_LOG(logDTFluxCore, Log, TEXT("Participant created with %d teammates"), Teammate.Num());
}
@ -138,7 +139,7 @@ void FDTFluxParticipant::AddTeammate(const FString& LastName, const FString& Fir
Person.FirstName = FirstName.TrimStartAndEnd();
Person.LastName = LastName.TrimStartAndEnd();
Person.Gender = Gender.TrimStartAndEnd();
AddTeammate(Person);
}
@ -157,16 +158,15 @@ const TArray<FDTFluxPerson>& FDTFluxParticipant::GetTeammate() const
return Teammate;
}
FString FDTFluxParticipant::GetFormattedName(const int MaxChar, const FString& Separator, const FString& OverflowChar) const
FString FDTFluxParticipant::GetFormattedName(const int MaxChar, const FString& Separator,
const FString& OverflowChar) const
{
if (MaxChar <= 0)
{
return TEXT("");
}
FString FirstName;
FString LastName;
if (IsTeam())
{
if (!Team.IsEmpty())
@ -197,92 +197,64 @@ FString FDTFluxParticipant::GetFormattedName(const int MaxChar, const FString& S
{
Initial = FirstName.Left(1).ToUpper() + Separator;
}
FString FormattedLastName = LastName.ToUpper();
FString FullName = Initial + FormattedLastName;
if (FullName.Len() <= MaxChar)
{
return FullName;
}
const int32 OverflowLength = OverflowChar.Len();
if (OverflowLength > MaxChar)
{
return FullName.Left(MaxChar);
}
if (Initial.Len() + OverflowLength > MaxChar)
{
return FullName.Left(MaxChar);
}
const int32 AvailableForLastName = MaxChar - Initial.Len() - OverflowLength;
if (AvailableForLastName <= 0)
{
return FullName.Left(MaxChar);
}
FString TruncatedName = Initial + FormattedLastName.Left(AvailableForLastName) + OverflowChar;
if (TruncatedName.Len() > MaxChar)
{
return TruncatedName.Left(MaxChar);
}
return TruncatedName;
return FullName.Left(MaxChar) + OverflowChar;
}
FString FDTFluxParticipant::GetConcatFormattedName(const int MaxChar, const FString& Separator,
const FString& OverflowChar, const FString& BibSeparator) const
FString FDTFluxParticipant::GetConcatFormattedName(const int MaxChar, const FString& Separator,
const FString& OverflowChar, const FString& BibSeparator) const
{
FString BibText = FString::FromInt(Bib) + BibSeparator;
int32 RemainingChars = MaxChar - BibText.Len();
if (RemainingChars <= 0)
{
return BibText.Left(MaxChar);
}
FString FormattedName = GetFormattedName(RemainingChars, Separator, OverflowChar);
return BibText + FormattedName;
}
FText FDTFluxParticipant::GetFormattedNameText(const int MaxChar, const FString& Separator, const FString& OverflowChar) const
FText FDTFluxParticipant::GetFormattedNameText(const int MaxChar, const FString& Separator,
const FString& OverflowChar) const
{
return FText::FromString(GetFormattedName(MaxChar, Separator, OverflowChar));
}
FText FDTFluxParticipant::GetConcatFormattedNameText(const int MaxChar, const FString& Separator,
const FString& OverflowChar, const FString& BibSeparator) const
FText FDTFluxParticipant::GetConcatFormattedNameText(const int MaxChar, const FString& Separator,
const FString& OverflowChar, const FString& BibSeparator) const
{
return FText::FromString(GetConcatFormattedName(MaxChar, Separator, OverflowChar, BibSeparator));
}
FString FDTFluxParticipant::GetFormattedName(const FDTFluxParticipant& Participant, const int MaxChar,
const FString& Separator, const FString& OverflowChar)
const FString& Separator, const FString& OverflowChar)
{
return Participant.GetFormattedName(MaxChar, Separator, OverflowChar);
}
FString FDTFluxParticipant::GetConcatFormattedName(const FDTFluxParticipant& Participant, const int MaxChar,
const FString& Separator, const FString& OverflowChar,
const FString& BibSeparator)
const FString& Separator, const FString& OverflowChar,
const FString& BibSeparator)
{
return Participant.GetConcatFormattedName(MaxChar, Separator, OverflowChar, BibSeparator);
}
FText FDTFluxParticipant::GetFormattedNameText(const FDTFluxParticipant& Participant, const int MaxChar,
const FString& Separator, const FString& OverflowChar)
const FString& Separator, const FString& OverflowChar)
{
return Participant.GetFormattedNameText(MaxChar, Separator, OverflowChar);
}
FText FDTFluxParticipant::GetConcatFormattedNameText(const FDTFluxParticipant& Participant, const int MaxChar,
const FString& Separator, const FString& OverflowChar,
const FString& BibSeparator)
const FString& Separator, const FString& OverflowChar,
const FString& BibSeparator)
{
return Participant.GetConcatFormattedNameText(MaxChar, Separator, OverflowChar, BibSeparator);
}
@ -294,12 +266,12 @@ FDTFluxParticipant FDTFluxParticipant::CreateFromJson(const TSharedPtr<FJsonObje
UE_LOG(logDTFluxCore, Error, TEXT("Cannot create participant from invalid JSON object"));
return FDTFluxParticipant();
}
return FDTFluxParticipant(JsonObject);
}
FDTFluxTeamStatusUpdate::FDTFluxTeamStatusUpdate(const int InBib, const int InStatus)
: Bib(InBib)
, Status(static_cast<EDTFluxParticipantStatusType>(InStatus))
, Status(static_cast<EDTFluxParticipantStatusType>(InStatus))
{
}
}

View File

@ -7,6 +7,7 @@
#include "DTFluxCoreSubsystem.h"
#include "DTFluxCoreSubsystemModule.h"
#include "Dataflow/DataflowContextCache.h"
UDTFluxPursuitManager::UDTFluxPursuitManager(const FObjectInitializer& ObjectInitializer):
Super(ObjectInitializer)
@ -69,11 +70,14 @@ void UDTFluxPursuitManager::GetPursuit(TArray<FDTFluxPursuitInfo>& OutPursuitFoc
TArray<FDTFluxPursuitInfo>& OutPursuitNext, bool& BIsFocusTruncate,
const int MaxSimultaneousPursuit)
{
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());
FDateTime MetricsStartFunction = FDateTime::UtcNow();
FDateTime CurrentTime = FDateTime::Now();
// Validation
// 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);
@ -82,7 +86,6 @@ void UDTFluxPursuitManager::GetPursuit(TArray<FDTFluxPursuitInfo>& OutPursuitFoc
BIsFocusTruncate = false;
return;
}
if (bIsSequenceDone || GroupedPursuit.IsEmpty())
{
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("No groups available or sequence completed"));
@ -91,13 +94,41 @@ void UDTFluxPursuitManager::GetPursuit(TArray<FDTFluxPursuitInfo>& OutPursuitFoc
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();
// === ÉTAPE 1: FOCUS = PREMIER GROUPE (et le supprimer) ===
FDTFluxPursuitGroup FocusGroup = GroupedPursuit[0]; // Copie du premier groupe
GroupedPursuit.RemoveAt(0); // ✅ SUPPRIMER le premier groupe
// === 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;
@ -114,7 +145,6 @@ void UDTFluxPursuitManager::GetPursuit(TArray<FDTFluxPursuitInfo>& OutPursuitFoc
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Target Next Count: %d"), TargetNextCount);
// ✅ PARCOURIR les groupes restants SANS les modifier
for (int32 GroupIndex = 0;
GroupIndex < GroupedPursuit.Num() && AddedNextCount < TargetNextCount;
GroupIndex++)
@ -136,7 +166,6 @@ void UDTFluxPursuitManager::GetPursuit(TArray<FDTFluxPursuitInfo>& OutPursuitFoc
AvailableInGroup,
NeededFromGroup);
// ✅ COPIER les participants nécessaires (SANS les supprimer du groupe)
for (int32 ParticipantIndex = 0; ParticipantIndex < NeededFromGroup; ParticipantIndex++)
{
FDTFluxPursuitInfo NextParticipant = NextGroup.PursuitGroup[ParticipantIndex]; // Copie
@ -176,6 +205,10 @@ void UDTFluxPursuitManager::GetPursuit(TArray<FDTFluxPursuitInfo>& OutPursuitFoc
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()

View File

@ -1,6 +1,8 @@
#pragma once
#include "CoreMinimal.h"
#include "DTFluxCoreSubsystemModule.h"
#include "Assets/DTFluxModelAsset.h"
#include "Containers/Deque.h"
#include "Types/Struct/FDTFluxPursuitInfo.h"
#include "Subsystems/EngineSubsystem.h"
@ -98,9 +100,9 @@ public:
TArray<FDTFluxContest> GetCurrentContests();
UFUNCTION()
TArray<int> GetContestsIdForTime(const FDateTime Time) const;
UFUNCTION()
UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem")
bool GetContestForId(const int Id, FDTFluxContest& OutContest);
UFUNCTION()
UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem")
TArray<FDTFluxContest> GetContestsForTime(const FDateTime Time);
UFUNCTION()
@ -108,6 +110,85 @@ public:
UFUNCTION()
TArray<FDTFluxContest> GetContests();
UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem")
void GetContest(const int ContestId, FDTFluxContest& OutContest)
{
OutContest = FDTFluxContest();
if (GetContestForId(ContestId, OutContest))
{
return;
}
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("ContestId %d not found in ContestDefinition"), ContestId)
}
UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem")
bool GetStageDefinition(const FDTFluxStageKey StageKey, FDTFluxStage& OutStageDefinition)
{
int ContestId = StageKey.ContestId;
int StageId = StageKey.StageId;
FDTFluxContest ContestDefinition;
if (GetContestForId(ContestId, ContestDefinition))
{
for (auto& Stage : ContestDefinition.Stages)
{
if (Stage.StageId == StageId)
{
OutStageDefinition = Stage;
return true;
}
}
}
OutStageDefinition = FDTFluxStage();
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("ContestId %d, StageId %d not found in ContestDefinition"),
ContestId, StageId)
return false;
}
UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem")
bool GetSplitDefinition(const FDTFluxSplitKey SplitKey, FDTFluxSplit& OutSplitDefinition)
{
int ContestId = SplitKey.ContestId;
int SplitId = SplitKey.SplitId;
FDTFluxContest ContestDefinition;
if (GetContestForId(ContestId, ContestDefinition))
{
for (auto& Split : ContestDefinition.Splits)
{
if (Split.SplitId == SplitId)
{
OutSplitDefinition = Split;
return true;
}
}
}
OutSplitDefinition = FDTFluxSplit();
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("ContestId %d, SplitId %d not found in ContestDefinition"),
ContestId, SplitId);
return false;
}
UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem")
void GetStage(const int ContestId, const int StageId, FDTFluxStage& OutStageDefinition)
{
if (GetStageDefinition(FDTFluxStageKey(ContestId, StageId),
OutStageDefinition))
{
return;
}
OutStageDefinition = FDTFluxStage();
}
UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem")
void GetSplit(const int ContestId, const int StageId, const int SplitId, FDTFluxSplit& OutSplitDefinition)
{
if (GetSplitDefinition(FDTFluxSplitKey(ContestId, StageId, SplitId),
OutSplitDefinition))
{
return;
}
OutSplitDefinition = FDTFluxSplit();
}
protected:
// ~Subsystem Interface
virtual void Initialize(FSubsystemCollectionBase& Collection) override;

View File

@ -1,6 +1,5 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "DTFluxDatesUtilities.h"
#include "DTFluxUtilitiesModule.h"
@ -16,18 +15,20 @@ DTFluxDatesUtilities::~DTFluxDatesUtilities()
bool DTFluxDatesUtilities::CompileDateAndTime(const FString& Time, const FString& Date, FDateTime& OutDateTime)
{
if(Time.Len() < 8 && Date.Len() < 10)
if (Time.Len() < 8 && Date.Len() < 10)
{
TArray<FString> ExplodedTime;
Time.ParseIntoArray(ExplodedTime, TEXT(":"));
if(ExplodedTime.Num() != 3 && !ExplodedTime[0].IsNumeric() && !ExplodedTime[1].IsNumeric() & !ExplodedTime[2].IsNumeric())
if (ExplodedTime.Num() != 3 && !ExplodedTime[0].IsNumeric() && !ExplodedTime[1].IsNumeric() & !ExplodedTime[2].
IsNumeric())
{
UE_LOG(logDTFluxUtilities, Error, TEXT("Bad Time Format [%s]. Unable to parse"), *Time);
return false;
}
TArray<FString> ExplodedDate;
Date.ParseIntoArray(ExplodedDate, TEXT("-"));
if(ExplodedDate.Num() != 3 && !ExplodedDate[0].IsNumeric() && !ExplodedDate[1].IsNumeric() && !ExplodedDate[2].IsNumeric() )
if (ExplodedDate.Num() != 3 && !ExplodedDate[0].IsNumeric() && !ExplodedDate[1].IsNumeric() && !ExplodedDate[2].
IsNumeric())
{
UE_LOG(logDTFluxUtilities, Error, TEXT("Bad Date Format [%s]. Unable to parse"), *Date);
return false;
@ -38,7 +39,7 @@ bool DTFluxDatesUtilities::CompileDateAndTime(const FString& Time, const FString
int32 Day = FCString::Atoi(*ExplodedDate[2]);
int32 Month = FCString::Atoi(*ExplodedDate[1]);
int32 Year = FCString::Atoi(*ExplodedDate[0]);
if(FDateTime::Validate(Year, Month, Day, Hours, Minutes, Seconds, 0))
if (FDateTime::Validate(Year, Month, Day, Hours, Minutes, Seconds, 0))
{
OutDateTime = FDateTime(Year, Month, Day, Hours, Minutes, Seconds);
return true;

View File

@ -1,17 +1,14 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
class DTFLUXUTILITIES_API DTFluxDatesUtilities
{
public:
DTFluxDatesUtilities();
~DTFluxDatesUtilities();
static bool CompileDateAndTime(const FString& Time, const FString& Date, FDateTime& OutDateTime);
static bool CompileDateAndTime(const FDateTime& Time, const FDateTime& Date, FDateTime& OutDateTime);
};