// 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 "Struct/DTFluxServerResponseStruct.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(this); } 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::ProcessTrackedResponse(FDTFluxServerResponse& InResponse) { switch (InResponse.GetResponseType()) { case EDTFluxApiDataType::ContestRanking: { FDTFluxContestRankings Rankings; if (InResponse.ParseContestRanking(Rankings)) { OnContestRankings.Broadcast(Rankings.ContestId, Rankings); ProcessContestRanking(Rankings); UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("ContestRanking added for Contest %s"), *Rankings.ContestName); } else { UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("Unable to parse ContestRanking")); } break; } case EDTFluxApiDataType::StageRanking: { FDTFluxStageRankings Rankings; if (InResponse.ParseStageRanking(Rankings)) { FDTFluxStageKey StageKey(Rankings.ContestId, Rankings.StageId); OnStageRankings.Broadcast(StageKey, Rankings); ProcessStageRanking(Rankings); UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("ContestRanking added for Stage %i of Contest %i"), Rankings.StageId, Rankings.ContestId); } else { UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("Unable to parse StageRanking")); } break; } case EDTFluxApiDataType::SplitRanking: { FDTFluxSplitRankings Rankings; if (InResponse.ParseSplitRanking(Rankings)) { FDTFluxSplitKey SplitKey(Rankings.ContestId, Rankings.StageId, Rankings.SplitId); OnSplitRankings.Broadcast(SplitKey, Rankings); ProcessSplitRanking(Rankings); UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("ContestRanking added for Split %i of Stage %i of Contest %i"), Rankings.SplitId, Rankings.StageId, Rankings.ContestId); } else { UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("Unable to parse SplitRanking")); } break; } case EDTFluxApiDataType::RaceData: { FDTFluxRaceData RaceData; if (InResponse.ParseRaceData(RaceData)) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("RaceDataDefinition added for Contest %s"), *RaceData.Datas[0].Name); ProcessRaceData(RaceData); } break; } case EDTFluxApiDataType::TeamList: { FDTFluxTeamListDefinition TeamList; if (InResponse.ParseTeamList(TeamList)) { ProcessTeamList(TeamList); UE_LOG(logDTFluxCoreSubsystem, Log, TEXT("Process TeamList")) } break; } default: UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Unknown DataType %s"), *UEnum::GetValueAsString(InResponse.GetResponseType())); break; } } 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 ); NetworkSubsystem->OnReceivedTeamStatusUpdate().BindUObject( this, &UDTFluxCoreSubsystem::ProcessTeamStatusUpdate ); NetworkSubsystem->OnReceivedTeamUpdate().BindUObject( this, &UDTFluxCoreSubsystem::ProcessTeamUpdate ); NetworkSubsystem->OnReceivedSplitSensor().BindUObject( this, &UDTFluxCoreSubsystem::ProcessSplitSensor ); } } bool UDTFluxCoreSubsystem::IsStageRankingSealed(FDTFluxStageKey StageKey) { FDTFluxStageRankings StageRankings; if (GetStageRankingsWithKey(StageKey, StageRankings)) { FDTFluxStage Stage; if (GetStageDefinition(StageKey, Stage)) { return StageRankings.IsSealed(Stage.EndTime); } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("Unable to find Stage %i"), StageKey.StageId); return false; } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("Unable to find StageRankings for StageKey %i"), StageKey.StageId); return false; } bool UDTFluxCoreSubsystem::IsContestRankingSealed(int ContestId) { if (DataStorage) { FDTFluxContestRankings ContestRankings; if (GetContestRankings(ContestId, ContestRankings)) { FDTFluxContest Contest; if (GetContestForId(ContestId, Contest)) { return ContestRankings.IsSealed(Contest.EndTime); } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("Unable to find Contest %i"), ContestId); return false; } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("Unable to find ContestRankings for ContestId %i"), ContestId); return false; } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DataStorage not available")); return false; } EDTFluxFinisherType UDTFluxCoreSubsystem::GetSplitSensorType(const FDTFluxSplitSensorInfo& SplitSensorInfo) { if (DataStorage != nullptr) { if (DataStorage->LastSplitIdCache.Contains(SplitSensorInfo.ContestId)) { int LastSplitIdForContest = DataStorage->LastSplitIdCache[SplitSensorInfo.ContestId]; if (LastSplitIdForContest == SplitSensorInfo.SplitId) { if (SplitSensorInfo.Rank == 1 ) { return EDTFluxFinisherType::Winner; } return EDTFluxFinisherType::Finish; } } } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DataStorage not available")); return EDTFluxFinisherType::None; } 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); if (bShouldKeepRankings) { SaveDataStorage(); } } void UDTFluxCoreSubsystem::ProcessStageRanking(const FDTFluxStageRankings& StageRankings) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Received StageRankings with %i Items"), StageRankings.Rankings.Num()); DataStorage->UpdateOrCreateStageRanking(StageRankings); if (bShouldKeepRankings) { SaveDataStorage(); } } void UDTFluxCoreSubsystem::ProcessSplitRanking(const FDTFluxSplitRankings& SplitRankings) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Received SplitRanking with %i Items"), SplitRankings.Rankings.Num()); DataStorage->UpdateOrCreateSplitRanking(SplitRankings); if (bShouldKeepRankings) { 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) { if (DataStorage != nullptr) { // Gestion Cache Split Sensor FDTFluxSplitSensorKey SplitSensorKey(SplitSensorInfo.ContestId, SplitSensorInfo.StageId, SplitSensorInfo.SplitId, -1); FDTFluxSplitSensorInfo NewSplitSensorInfo = SplitSensorInfo; NewSplitSensorInfo.SplitName = DataStorage->SplitSensorInfoCache[SplitSensorKey].SplitName; SplitSensorKey.Bib = SplitSensorInfo.Bib; DataStorage->SplitSensorInfoCache.Add(SplitSensorKey, NewSplitSensorInfo); // Update Current currentSplit FDTFluxParticipant Participant; if (DataStorage->Participants.Contains(SplitSensorInfo.Bib)) { DataStorage->Participants[SplitSensorInfo.Bib].CurrentSplit = SplitSensorInfo.SplitId; } // Gestion Finnish Status switch (GetSplitSensorType(SplitSensorInfo)) { case EDTFluxFinisherType::Winner: { OnWinner.Broadcast(SplitSensorInfo); break; } case EDTFluxFinisherType::Finish : { OnFinisher.Broadcast(SplitSensorInfo); break; } default: { OnSplitSensor.Broadcast(SplitSensorInfo); break; } } } } void UDTFluxCoreSubsystem::SendRequest(const FString& Message) { if (NetworkSubsystem) { NetworkSubsystem->SendMessage(Message); } } void UDTFluxCoreSubsystem::InitParticipantTracking(const int Bib, const int ContestId, const int StageId) { FDTFluxContest Contest; if (GetContestForId(ContestId, Contest)) { // get all splits TArray SplitSensorInfos; FDTFluxSplitSensorKey SplitSensorKey; SplitSensorKey.ContestId = ContestId; SplitSensorKey.StageId = StageId; SplitSensorKey.Bib = Bib; for (auto Split : Contest.Splits) { SplitSensorKey.SplitId = Split.SplitId; if (DataStorage->SplitSensorInfoCache.Contains(SplitSensorKey)) { SplitSensorInfos.Add(DataStorage->SplitSensorInfoCache[SplitSensorKey]); } else { SplitSensorInfos.Add(FDTFluxSplitSensorInfo(Split.Name)); } } FDTFluxSplitHistory History; History.SplitSensors = SplitSensorInfos; OnParticipantTrackingReady.Broadcast(History); } FDTFluxSplitHistory SplitHistory; if (GetParticipant(Bib, SplitHistory.Participant)) { } FString Text = "sqfhds"; FName Key = FName(Text); } FGuid UDTFluxCoreSubsystem::InitContestRankingsDisplay(const int ContestId) { if (NetworkSubsystem) { if (DataStorage) { // no need to request StageRankings; if (IsContestRankingSealed(ContestId)) { const FGuid DisplayRequestId = FGuid::NewGuid(); OnContestRankingDisplayReady.Broadcast(DisplayRequestId, true); return DisplayRequestId; } else { FOnDTFluxRequestSuccess OnSuccess = FOnDTFluxRequestSuccess::CreateLambda( [this](const FDTFluxTrackedRequest& Request) { FDTFluxContestRankings Rankings = FDTFluxContestRankings(); if (Request.ParsedResponse.IsSet()) { TSharedPtr ResponsePtr = Request.ParsedResponse.GetValue(); ResponsePtr->ParseContestRanking(Rankings); this->DataStorage->AddContestRanking(Rankings); this->OnContestRankingDisplayReady.Broadcast(Request.RequestId, true); return; } this->OnStageRankingDisplayReady.Broadcast(Request.RequestId, false); }); FOnDTFluxRequestError OnError = FOnDTFluxRequestError::CreateLambda( [this](const FDTFluxTrackedRequest& InReq, const FString& InError) { this->OnStageRankingDisplayReady.Broadcast(InReq.RequestId, false); }); FGuid DisplayRequestId = NetworkSubsystem->SendTrackedRequestWithCallbacks( EDTFluxApiDataType::ContestRanking, ContestId, -1, -1, OnSuccess, OnError, true); return DisplayRequestId; } } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DTFluxDatastorage unavailable ...")); OnContestRankingDisplayReady.Broadcast(FGuid(), false); return FGuid(); } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DTFluxNetworkSubsystem unavailable ...")); OnContestRankingDisplayReady.Broadcast(FGuid(), false); return FGuid(); } FGuid UDTFluxCoreSubsystem::InitStageRankingsDisplay(const int ContestId, const int StageId) { if (NetworkSubsystem) { if (DataStorage) { // no need to request StageRankings; if (IsStageRankingSealed(FDTFluxStageKey(ContestId, StageId))) { const FGuid DisplayRequestId = FGuid::NewGuid(); OnStageRankingDisplayReady.Broadcast(DisplayRequestId, true); return DisplayRequestId; } else { FOnDTFluxRequestSuccess OnSuccess = FOnDTFluxRequestSuccess::CreateLambda( [this](const FDTFluxTrackedRequest& Request) { FDTFluxStageRankings Rankings = FDTFluxStageRankings(); if (Request.ParsedResponse.IsSet()) { TSharedPtr ResponsePtr = Request.ParsedResponse.GetValue(); ResponsePtr->ParseStageRanking(Rankings); this->DataStorage->AddStageRanking(Rankings); this->OnStageRankingDisplayReady.Broadcast(Request.RequestId, true); return; } this->OnStageRankingDisplayReady.Broadcast(Request.RequestId, false); }); FOnDTFluxRequestError OnError = FOnDTFluxRequestError::CreateLambda( [this](const FDTFluxTrackedRequest& InReq, const FString& InError) { this->OnStageRankingDisplayReady.Broadcast(InReq.RequestId, false); }); FGuid DisplayRequestId = NetworkSubsystem->SendTrackedRequestWithCallbacks( EDTFluxApiDataType::StageRanking, ContestId, StageId, -1, OnSuccess, OnError, true); return DisplayRequestId; } } } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DTFluxNetworkSubsystem unavailable ...")); const FGuid RequestId = FGuid::NewGuid(); OnStageRankingDisplayReady.Broadcast(RequestId, false); return RequestId; } FGuid UDTFluxCoreSubsystem::InitSplitRankingsDisplay(const int ContestId, const int StageId, const int SplitId) { if (NetworkSubsystem) { if (DataStorage) { FOnDTFluxRequestSuccess OnSuccess = FOnDTFluxRequestSuccess::CreateLambda( [this](const FDTFluxTrackedRequest& Request) { FDTFluxSplitRankings Rankings = FDTFluxSplitRankings(); if (Request.ParsedResponse.IsSet()) { TSharedPtr ResponsePtr = Request.ParsedResponse.GetValue(); ResponsePtr->ParseSplitRanking(Rankings); this->DataStorage->AddSplitRanking(Rankings); this->OnSplitRankingDisplayReady.Broadcast(Request.RequestId, true); return; } this->OnSplitRankingDisplayReady.Broadcast(Request.RequestId, false); }); FOnDTFluxRequestError OnError = FOnDTFluxRequestError::CreateLambda( [this](const FDTFluxTrackedRequest& InReq, const FString& InError) { this->OnSplitRankingDisplayReady.Broadcast(InReq.RequestId, false); }); FGuid DisplayRequestId = NetworkSubsystem->SendTrackedRequestWithCallbacks( EDTFluxApiDataType::SplitRanking, ContestId, StageId, SplitId, OnSuccess, OnError, true); return DisplayRequestId; } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DTFluxDatastorage unavailable ...")); OnSplitRankingDisplayReady.Broadcast(FGuid(), false); return FGuid(); } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DTFluxNetworkSubsystem unavailable ...")); OnSplitRankingDisplayReady.Broadcast(FGuid(), false); return FGuid(); } bool UDTFluxCoreSubsystem::GetStageRankingForBib(const int ContestId, const int StageId, const int Bib, FDTFluxStageRanking& OutStageRanking) { if (DataStorage) { FDTFluxStageKey StageKey(ContestId, StageId); if (DataStorage->StageRankings.Contains(StageKey)) { FDTFluxStageRankings StageRankings = DataStorage->StageRankings[StageKey]; for (auto& Ranking : StageRankings.Rankings) { if (Ranking.Bib == Bib) { OutStageRanking = static_cast(Ranking); return true; } } } UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Unable to find StageRanking for Bib %i"), Bib); return false; } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DataStorage not available")); return false; } bool UDTFluxCoreSubsystem::GetSplitRankingForBib(const int ContestId, const int StageId, const int SplitId, const int Bib, FDTFluxSplitRanking& OutSplitRankings) { if (DataStorage) { FDTFluxSplitKey SplitKey(ContestId, StageId, SplitId); if (DataStorage->SplitRankings.Contains(SplitKey)) { FDTFluxSplitRankings SplitRankings = DataStorage->SplitRankings[SplitKey]; for (auto& Ranking : SplitRankings.Rankings) { if (Ranking.Bib == Bib) { OutSplitRankings = static_cast(Ranking); return true; } } } UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Unable to find SplitRanking for Bib %i"), Bib); return false; } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DataStorage not available")); return false; } bool UDTFluxCoreSubsystem::GetContestRanking(const int ContestId, FDTFluxContestRanking& OutContestRanking) { if (DataStorage) { FDTFluxContest Contest; if (GetContestForId(ContestId, Contest)) { for (auto& Ranking : DataStorage->ContestRankings[ContestId].Rankings) { OutContestRanking = Ranking; return true; } } UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Unable to find ContestRanking for ContestId %i"), ContestId); return false; } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DataStorage not available")); return false; } bool UDTFluxCoreSubsystem::GetContestRankings(const int ContestId, FDTFluxContestRankings& OutContestRankings) { if (DataStorage->ContestRankings.Contains(ContestId)) { OutContestRankings = DataStorage->ContestRankings[ContestId]; return true; } if (NetworkSubsystem) { TArray TackedContestIds = {ContestId}; TrackedRequestContestRankings(TackedContestIds); return false; } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("NetworkSubsystem unavailable")); return false; } bool UDTFluxCoreSubsystem::GetStageRankings(const int ContestId, const int StageId, FDTFluxStageRankings& OutStageRankings) { return GetStageRankingsWithKey(FDTFluxStageKey(ContestId, StageId), OutStageRankings); } bool UDTFluxCoreSubsystem::GetSplitRankings(const int ContestId, const int StageId, const int SplitId, FDTFluxSplitRankings& OutSplitRankings) { return GetSplitRankingsWithKey(FDTFluxSplitKey(ContestId, StageId, SplitId), OutSplitRankings); } bool UDTFluxCoreSubsystem::GetStageRankingsWithKey(const FDTFluxStageKey StageKey, FDTFluxStageRankings& OutStageRankings, const bool bShouldUseCached) { //We Have the data if (DataStorage->StageRankings.Contains(StageKey) && bShouldUseCached) { OutStageRankings = DataStorage->StageRankings[StageKey]; return true; } else { if (NetworkSubsystem) { TArray TackedStageKeys = {StageKey}; TrackedRequestStageRankings(TackedStageKeys); OutStageRankings = FDTFluxStageRankings(); return false; } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("NetworkSubsystem unavailable")) } return false; } bool UDTFluxCoreSubsystem::GetSplitRankingsWithKey(const FDTFluxSplitKey SplitKey, FDTFluxSplitRankings& OutSplitRankings, const bool bShouldUseCached) { //We Have the data if (DataStorage->SplitRankings.Contains(SplitKey) && bShouldUseCached) { OutSplitRankings = DataStorage->SplitRankings[SplitKey]; return true; } else { if (NetworkSubsystem) { TArray TackedSplitKey = {SplitKey}; TrackedRequestSplitRankings(TackedSplitKey); OutSplitRankings = FDTFluxSplitRankings(); return false; } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("NetworkSubsystem unavailable")) return false; } } TArray UDTFluxCoreSubsystem::TrackedRequestContestRankings(const TArray ForContests, bool bEnableCache) { if (NetworkSubsystem) { TArray RequestIds; FOnDTFluxRequestSuccess OnSuccess = FOnDTFluxRequestSuccess::CreateLambda( [this](const FDTFluxTrackedRequest& Request) { UE_LOG(logDTFluxCoreSubsystem, Log, TEXT("ContestRanking Request %s %s Success"), *Request.RequestId.ToString(), *UEnum::GetValueAsString(Request.RequestType)); if (Request.ParsedResponse.IsSet()) { ProcessTrackedResponse(*Request.ParsedResponse.GetValue()); } }); FOnDTFluxRequestError OnError = FOnDTFluxRequestError::CreateLambda( [this](const FDTFluxTrackedRequest& InReq, const FString& InError) { UE_LOG(logDTFluxCoreSubsystem, Log, TEXT("ContestRanking Request [%s] Error %s"), *InReq.RequestId.ToString(), *InError); }); // if Contest is not ended for (auto ContestId : ForContests) { FGuid ContestRequest = NetworkSubsystem->SendTrackedRequestWithCallbacks(EDTFluxApiDataType::ContestRanking, ContestId, -1, -1, OnSuccess, OnError, bEnableCache); RequestIds.Add(ContestRequest); } return RequestIds; } return TArray(); } TArray UDTFluxCoreSubsystem::TrackedRequestStageRankings(const TArray ForStages, bool bEnableCache) { if (NetworkSubsystem) { TArray RequestIds; FOnDTFluxRequestSuccess OnSuccess = FOnDTFluxRequestSuccess::CreateLambda( [this](const FDTFluxTrackedRequest& Request) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Stage Request %s %s Success"), *Request.RequestId.ToString(), *UEnum::GetValueAsString(Request.RequestType)); if (Request.ParsedResponse.IsSet()) { ProcessTrackedResponse(*Request.ParsedResponse.GetValue()); } }); FOnDTFluxRequestError OnError = FOnDTFluxRequestError::CreateLambda( [this](const FDTFluxTrackedRequest& InReq, const FString& InError) { UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("StageRanking Request [%s] Error %s"), *InReq.RequestId.ToString(), *InError); }); for (auto StageKey : ForStages) { FGuid ContestRequest = NetworkSubsystem->SendTrackedRequestWithCallbacks(EDTFluxApiDataType::StageRanking, StageKey.ContestId, StageKey.StageId, -1, OnSuccess, OnError, bEnableCache); RequestIds.Add(ContestRequest); } return RequestIds; } return TArray(); } TArray UDTFluxCoreSubsystem::TrackedRequestSplitRankings(const TArray ForSplits, bool bEnableCache) { if (NetworkSubsystem) { TArray RequestIds; FOnDTFluxRequestSuccess OnSuccess = FOnDTFluxRequestSuccess::CreateLambda( [this](const FDTFluxTrackedRequest& Request) { UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Stage Request %s %s Success"), *Request.RequestId.ToString(), *UEnum::GetValueAsString(Request.RequestType)); if (Request.ParsedResponse.IsSet()) { ProcessTrackedResponse(*Request.ParsedResponse.GetValue()); } }); FOnDTFluxRequestError OnError = FOnDTFluxRequestError::CreateLambda( [this](const FDTFluxTrackedRequest& InReq, const FString& InError) { UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("StageRanking Request [%s] Error %s"), *InReq.RequestId.ToString(), *InError); }); // if Contest is not ended for (auto SplitKey : ForSplits) { FGuid ContestRequest = NetworkSubsystem->SendTrackedRequestWithCallbacks(EDTFluxApiDataType::SplitRanking, SplitKey.ContestId, SplitKey.StageId, SplitKey.SplitId, OnSuccess, OnError, bEnableCache); RequestIds.Add(ContestRequest); } return RequestIds; } return TArray(); } bool UDTFluxCoreSubsystem::GetParticipant(int InBib, FDTFluxParticipant& OutParticipant) { if (DataStorage->Participants.Contains(InBib)) { OutParticipant = DataStorage->Participants[InBib]; return true; } return false; } TArray UDTFluxCoreSubsystem::GetCurrentContestsId() { return GetContestsIdForTime(FDateTime::Now()); } bool UDTFluxCoreSubsystem::GetCurrentContests(TArray& OutContests) { return GetContestsForTime(FDateTime::Now(), OutContests); } TArray UDTFluxCoreSubsystem::GetContestsIdForTime(const FDateTime Time) { if (DataStorage) { TArray Contests; if (GetContestsForTime(Time, Contests)) { TArray ContestIds = TArray(); for (const auto& Contest : Contests) { ContestIds.Add(Contest.ContestId); } return ContestIds; } UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("No Contest running for Time [%s]"), *Time.ToString()); return TArray(); } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DataStorage not available")); return TArray(); } 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; } bool UDTFluxCoreSubsystem::GetContestsForTime(const FDateTime Time, TArray& OutContests) { if (DataStorage) { OutContests.Empty(); for (const auto& Pair : DataStorage->Contests) { FDTFluxContest Contest = Pair.Value; int ContestId = Contest.ContestId; //ils ont commencé. if (Contest.Date < Time && Contest.EndTime > Time) { // ils sont finis if (!Contest.IsFinished()) { OutContests.Add(Contest); } } } if (!OutContests.IsEmpty()) { return true; } UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("No Contest running for Time [%s]"), *Time.ToString()); } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DataStorage not available")); return false; } bool UDTFluxCoreSubsystem::GetContests(TArray& OutContests) { OutContests.Empty(); if (DataStorage) { DataStorage->Contests.GenerateValueArray(OutContests); return !OutContests.IsEmpty(); } UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("DataStorage not available")); return false; } void UDTFluxCoreSubsystem::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) } bool UDTFluxCoreSubsystem::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; } bool UDTFluxCoreSubsystem::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; } void UDTFluxCoreSubsystem::GetStage(const int ContestId, const int StageId, FDTFluxStage& OutStageDefinition) { if (GetStageDefinition(FDTFluxStageKey(ContestId, StageId), OutStageDefinition)) { return; } OutStageDefinition = FDTFluxStage(); } void UDTFluxCoreSubsystem::GetSplit(const int ContestId, const int StageId, const int SplitId, FDTFluxSplit& OutSplitDefinition) { if (GetSplitDefinition(FDTFluxSplitKey(ContestId, StageId, SplitId), OutSplitDefinition)) { return; } OutSplitDefinition = FDTFluxSplit(); }