// Fill out your copyright notice in the Description page of Project Settings. #include "DTFluxCoreSubsystem.h" #include "DTFluxCoreSubsystemModule.h" #include "DTFluxGeneralSettings.h" #include "DTFluxPursuitManager.h" #include "FileHelpers.h" #include "Assets/DTFluxModelAsset.h" #include "Subsystems/DTFluxNetworkSubsystem.h" #include "UObject/SavePackage.h" void UDTFluxCoreSubsystem::Initialize(FSubsystemCollectionBase& Collection) { Super::Initialize(Collection); UE_LOG(logDTFluxCoreSubsystem, Log, TEXT("[UDTFluxCoreSubsystem] Initializing...")); if (!DataStorage) { const UDTFluxGeneralSettings* GeneralSettings = GetDefault(); TSoftObjectPtr ModelAsset = GeneralSettings->ModelAsset; DataStorage = ModelAsset.LoadSynchronous(); if (!DataStorage) { UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DataStorage Not Valid")); } } //TODO REMOVE This as it's only for testing purpose NetworkSubsystem = GEngine->GetEngineSubsystem(); if (NetworkSubsystem->WsStatus != EDTFluxConnectionStatus::Connected) { RegisterDelegates(); } PursuitManager = NewObject(); } void UDTFluxCoreSubsystem::Deinitialize() { Super::Deinitialize(); } void UDTFluxCoreSubsystem::SaveDataStorage() { if (!DataStorage->MarkPackageDirty()) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Unable to make package dirty !!!")) } if (DataStorage) { UEditorLoadingAndSavingUtils::SavePackages({DataStorage->GetPackage()}, true); } } void UDTFluxCoreSubsystem::RegisterDelegates() { if (NetworkSubsystem) { // ✅ Binding avec vérification automatique des signatures // Si la signature ne correspond pas, erreur de compilation ! NetworkSubsystem->OnReceivedRaceData().BindUObject( this, &UDTFluxCoreSubsystem::ProcessRaceData ); NetworkSubsystem->OnReceivedTeamList().BindUObject( this, &UDTFluxCoreSubsystem::ProcessTeamList ); NetworkSubsystem->OnReceivedContestRanking().BindUObject( this, &UDTFluxCoreSubsystem::ProcessContestRanking ); NetworkSubsystem->OnReceivedStageRanking().BindUObject( this, &UDTFluxCoreSubsystem::ProcessStageRanking ); NetworkSubsystem->OnReceivedSplitRanking().BindUObject( this, &UDTFluxCoreSubsystem::ProcessSplitRanking ); // ⚠️ ATTENTION : Vous avez un doublon ici ! // NetworkSubsystem->OnReceivedTeamUpdate().BindUFunction(this, "ProcessTeamList"); NetworkSubsystem->OnReceivedTeamStatusUpdate().BindUObject( this, &UDTFluxCoreSubsystem::ProcessTeamStatusUpdate ); NetworkSubsystem->OnReceivedTeamUpdate().BindUObject( this, &UDTFluxCoreSubsystem::ProcessTeamUpdate ); NetworkSubsystem->OnReceivedSplitSensor().BindUObject( this, &UDTFluxCoreSubsystem::ProcessSplitSensor ); } } void UDTFluxCoreSubsystem::ProcessRaceData(const FDTFluxRaceData& RaceDataDefinition) { if (RaceDataDefinition.Datas.Num() > 0) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Receiving RaceDataDefinition [%s]"), *RaceDataDefinition.Datas[0].Name); if (DataStorage != nullptr) { UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DataStorage Name %s"), *DataStorage->EventName); for (auto Contest : RaceDataDefinition.Datas) { DataStorage->AddContest(Contest); } } else { UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DataStorage is null")); } SaveDataStorage(); return; } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("RaceDataDefinition is empty !!!")); } void UDTFluxCoreSubsystem::ProcessTeamList(const FDTFluxTeamListDefinition& TeamListDefinition) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Received TeamList with %i Items"), TeamListDefinition.Participants.Num()); for (const auto& Participant : TeamListDefinition.Participants) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Add Participant %i in %i ContestId"), Participant.Bib, Participant.ContestId); DataStorage->AddParticipant(Participant, Participant.ContestId); } SaveDataStorage(); } void UDTFluxCoreSubsystem::ProcessContestRanking(const FDTFluxContestRankings& ContestRankings) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Received ContestRankings with %i Items"), ContestRankings.Rankings.Num()); FDTFluxContestRankings NewContestRankings = ContestRankings; NewContestRankings.SetName(DataStorage->GetContestNameForId(ContestRankings.ContestId)); DataStorage->AddContestRanking(NewContestRankings); UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("ContestRankings added for Contest %s"), *NewContestRankings.ContestName); SaveDataStorage(); } void UDTFluxCoreSubsystem::ProcessStageRanking(const FDTFluxStageRankings& StageRankings) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Received StageRankings with %i Items"), StageRankings.Rankings.Num()); DataStorage->UpdateOrCreateStageRanking(StageRankings); SaveDataStorage(); } void UDTFluxCoreSubsystem::ProcessSplitRanking(const FDTFluxSplitRankings& SplitRankings) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Received SplitRanking with %i Items"), SplitRankings.Rankings.Num()); DataStorage->UpdateOrCreateSplitRanking(SplitRankings); SaveDataStorage(); } void UDTFluxCoreSubsystem::ProcessTeamStatusUpdate(const FDTFluxTeamStatusUpdate& NewParticipantStatus) { DataStorage->UpdateParticipantStatus(NewParticipantStatus); } void UDTFluxCoreSubsystem::ProcessTeamUpdate(const FDTFluxTeamListDefinition& TeamListDefinitiont) { for (const auto& Participant : TeamListDefinitiont.Participants) { DataStorage->UpdateParticipant(Participant); } } void UDTFluxCoreSubsystem::ProcessSplitSensor(const FDTFluxSplitSensorInfo& SplitSensorInfo) { FDTFluxContest Contest; FDTFluxStageKey StageKey(SplitSensorInfo.ContestId, SplitSensorInfo.StageId); FDTFluxStage Stage; DataStorage->GetStage(StageKey, Stage); FDTFluxParticipant Participant; DataStorage->GetParticipantByBib(SplitSensorInfo.Bib, Participant); DataStorage->GetContestById(SplitSensorInfo.ContestId, Contest); UE_LOG(logDTFluxCoreSubsystem, Log, TEXT("%s|%s Split %i Sensor for Participant [Bib] %i [FullName] %s"), *Contest.Name, *Stage.Name, SplitSensorInfo.SplitId, SplitSensorInfo.Bib, *Participant.GetFormattedName()); } void UDTFluxCoreSubsystem::SendRequest(const FString& Message) { if (NetworkSubsystem) { NetworkSubsystem->SendMessage(Message); } } void UDTFluxCoreSubsystem::SendTeamListRequest() { if (NetworkSubsystem) { NetworkSubsystem->SendRequest(EDTFluxRequestType::TeamList); } } void UDTFluxCoreSubsystem::SendRaceDataRequest() { if (NetworkSubsystem) { NetworkSubsystem->SendRequest(EDTFluxRequestType::RaceData); } } void UDTFluxCoreSubsystem::SendContestRankingRequest(int InContestId) { if (NetworkSubsystem) { NetworkSubsystem->SendRequest(EDTFluxRequestType::ContestRanking, InContestId); } } void UDTFluxCoreSubsystem::SendStageRankingRequest(int InContestId, int InStageId, bool bShouldIncludeSplitRanking) { // TODO Implement this } void UDTFluxCoreSubsystem::RequestAllStageRankingOfContest(int InContestId, int InStageId, bool bShouldIncludeSplitRanking) { // TODO Implement this } void UDTFluxCoreSubsystem::SendSplitRankingRequest(int InContestId, int InStageId, int InSplitId) { // TODO Implement this } void UDTFluxCoreSubsystem::RequestAllSplitRankingOfContest(int InContestId, int InStageId) { // TODO Implement this } FDTFluxStageRankings UDTFluxCoreSubsystem::GetStageRankings(FDTFluxStageKey StageKey) { if (DataStorage->StageRankings.Contains(StageKey)) { return DataStorage->StageRankings[StageKey]; } UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Cannot find StageRankings for key [%s]"), *StageKey.GetDisplayName()); return FDTFluxStageRankings(); } void UDTFluxCoreSubsystem::RequestAllSplitRankingOfStage(int InContestId, int InStageId, int InSplitId) { // TODO Implement this } const FDTFluxParticipant UDTFluxCoreSubsystem::GetParticipant(int InBib) { if (DataStorage->Participants.Contains(InBib)) { return DataStorage->Participants[InBib]; } return FDTFluxParticipant(); } void UDTFluxCoreSubsystem::RefreshStorage() { // TODO Implement this } TArray UDTFluxCoreSubsystem::GetCurrentContestsId() { return GetContestsIdForTime(FDateTime::Now()); } TArray UDTFluxCoreSubsystem::GetCurrentContests() { return GetContestsForTime(FDateTime::Now()); } TArray UDTFluxCoreSubsystem::GetContestsIdForTime(const FDateTime Time) { TArray Contests; for (const auto& Pair : DataStorage->Contests) { FDTFluxContest Contest = Pair.Value; int ContestId = Contest.ContestId; if (Contest.Date < Time && Contest.EndTime > Time) { Contests.Add(ContestId); } } return Contests; } bool UDTFluxCoreSubsystem::GetContestForId(const int Id, FDTFluxContest& OutContest) { for (auto KeyPair : DataStorage->Contests) { if (KeyPair.Value.ContestId == Id) { OutContest = KeyPair.Value; return true; } } UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Cannot find Contest for Id [%i]"), Id); return false; } TArray UDTFluxCoreSubsystem::GetContestsForTime(const FDateTime Time) { TArray Contests; for (const auto& Pair : DataStorage->Contests) { FDTFluxContest Contest = Pair.Value; int ContestId = Contest.ContestId; if (Contest.Date < Time && Contest.EndTime > Time) { Contests.Add(Contest); } } return Contests; } void UDTFluxCoreSubsystem::RequestRankingsForStages(TArray RequestedStages) const { } TArray UDTFluxCoreSubsystem::GetContests() { if (DataStorage) { TArray OutContests; DataStorage->Contests.GenerateValueArray(OutContests); return OutContests; } return TArray(); } void UDTFluxCoreSubsystem::LaunchPursuitSequenceFor(const TArray ContestIds) { TArray Contests = TArray(); for (const auto& ContestId : ContestIds) { FDTFluxContest Contest; GetContestForId(ContestId, Contest); Contests.Add(Contest); if (PursuitManager) { PursuitManager->LaunchPursuitSequenceFor(Contests); } else { UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("PursuitManager is null")); } } }