From 0a175f7813e1b825655178ce4f388ab547ebf1d4 Mon Sep 17 00:00:00 2001 From: Ange-Marie MAURIN Date: Mon, 14 Jul 2025 15:40:03 +0200 Subject: [PATCH] Added Events OnDisplayRankings to launch Display of rankings in BluePrints. --- .../Private/Assets/DTFluxModelAsset.cpp | 31 ++++ .../Types/Struct/DTFluxRaceDataStucts.cpp | 8 +- .../Types/Struct/DTFluxRankingStructs.cpp | 6 + .../Public/Assets/DTFluxModelAsset.h | 9 + .../Types/Struct/DTFluxRaceDataStructs.h | 3 +- .../Types/Struct/DTFluxRankingStructs.h | 16 +- .../Private/DTFluxCoreSubsystem.cpp | 173 +++++++++++++++++- .../Public/DTFluxCoreSubsystem.h | 36 ++++ 8 files changed, 275 insertions(+), 7 deletions(-) diff --git a/Source/DTFluxCore/Private/Assets/DTFluxModelAsset.cpp b/Source/DTFluxCore/Private/Assets/DTFluxModelAsset.cpp index 683c765..7d9a3a0 100644 --- a/Source/DTFluxCore/Private/Assets/DTFluxModelAsset.cpp +++ b/Source/DTFluxCore/Private/Assets/DTFluxModelAsset.cpp @@ -13,6 +13,11 @@ UDTFluxModelAsset::UDTFluxModelAsset(const FObjectInitializer& ObjectInitializer void UDTFluxModelAsset::AddContest(const FDTFluxContest& Contest) { Contests.Add(Contest.Name, Contest); + // initialisation + for (const auto& Stage : Contest.Stages) + { + FinishedStagesCache.Add(FDTFluxStageKey(Contest.ContestId, Stage.StageId), Stage.IsFinished()); + } } bool UDTFluxModelAsset::GetContestById(const int InContestId, FDTFluxContest& OutContest) @@ -132,6 +137,32 @@ bool UDTFluxModelAsset::GetParticipantByBib(int Bib, FDTFluxParticipant& OutPart return false; } +bool UDTFluxModelAsset::IsStageFinished(FDTFluxStageKey StageKey) +{ + if (!FinishedStagesCache.Contains(StageKey)) + { + if (FinishedStagesCache[StageKey]) + { + return true; + } + //maybe stage is finished because we have not be able to set it ? + return CheckStageIsFinished(StageKey); + } + return false; +} + + +bool UDTFluxModelAsset::CheckStageIsFinished(FDTFluxStageKey StageKey) +{ + FDTFluxStage Stage; + if (GetStage(StageKey, Stage)) + { + FinishedStagesCache.Add(StageKey, Stage.IsFinished()); + return FinishedStagesCache[StageKey]; + } + return false; +} + void UDTFluxModelAsset::UpdateOrCreateStageRanking(const FDTFluxStageRankings& InStageRankings) { diff --git a/Source/DTFluxCore/Private/Types/Struct/DTFluxRaceDataStucts.cpp b/Source/DTFluxCore/Private/Types/Struct/DTFluxRaceDataStucts.cpp index 70cff33..f799c4d 100644 --- a/Source/DTFluxCore/Private/Types/Struct/DTFluxRaceDataStucts.cpp +++ b/Source/DTFluxCore/Private/Types/Struct/DTFluxRaceDataStucts.cpp @@ -2,6 +2,11 @@ #include "Types/Struct/DTFluxRaceDataStructs.h" +bool FDTFluxStage::IsFinished() const +{ + return EndTime <= FDateTime::Now(); +} + bool FDTFluxContest::IsFinished() const { return EndTime <= FDateTime::Now(); @@ -62,6 +67,3 @@ bool FDTFluxContest::GetStage(const int StageID, FDTFluxStage& OutStage) const } return false; } - - - diff --git a/Source/DTFluxCore/Private/Types/Struct/DTFluxRankingStructs.cpp b/Source/DTFluxCore/Private/Types/Struct/DTFluxRankingStructs.cpp index bfe1d5d..e9102cc 100644 --- a/Source/DTFluxCore/Private/Types/Struct/DTFluxRankingStructs.cpp +++ b/Source/DTFluxCore/Private/Types/Struct/DTFluxRankingStructs.cpp @@ -3,6 +3,12 @@ #include "Types/Struct/DTFluxRankingStructs.h" #include "DTFluxCoreModule.h" +bool FDTFluxBaseRankings::IsSealed(const FDateTime EndTime) const + +{ + return ReceivedAt >= EndTime; +} + void FDTFluxContestRanking::Dump() const { UE_LOG(logDTFluxCore, Log, diff --git a/Source/DTFluxCore/Public/Assets/DTFluxModelAsset.h b/Source/DTFluxCore/Public/Assets/DTFluxModelAsset.h index 8cac78d..5647017 100644 --- a/Source/DTFluxCore/Public/Assets/DTFluxModelAsset.h +++ b/Source/DTFluxCore/Public/Assets/DTFluxModelAsset.h @@ -89,4 +89,13 @@ public: UFUNCTION(BlueprintCallable, CallInEditor, Category="DTFlux|Participant") bool GetParticipantByBib(int Bib, FDTFluxParticipant& OutParticipant); + + UFUNCTION() + bool IsStageFinished(FDTFluxStageKey StageKey); + +private: + UPROPERTY() + TMap FinishedStagesCache; + UFUNCTION() + bool CheckStageIsFinished(FDTFluxStageKey StageKey); }; diff --git a/Source/DTFluxCore/Public/Types/Struct/DTFluxRaceDataStructs.h b/Source/DTFluxCore/Public/Types/Struct/DTFluxRaceDataStructs.h index c7fd5f4..f3934c4 100644 --- a/Source/DTFluxCore/Public/Types/Struct/DTFluxRaceDataStructs.h +++ b/Source/DTFluxCore/Public/Types/Struct/DTFluxRaceDataStructs.h @@ -51,6 +51,7 @@ public: FDateTime EndTime; UPROPERTY(BlueprintReadWrite, Category="DTFlux|model", EditAnywhere) FDateTime CutOff; + bool IsFinished() const; }; /** @@ -98,4 +99,4 @@ public: UPROPERTY() // ReSharper disable once IdentifierTypo TArray Datas; -}; \ No newline at end of file +}; diff --git a/Source/DTFluxCore/Public/Types/Struct/DTFluxRankingStructs.h b/Source/DTFluxCore/Public/Types/Struct/DTFluxRankingStructs.h index 3232676..1d62b34 100644 --- a/Source/DTFluxCore/Public/Types/Struct/DTFluxRankingStructs.h +++ b/Source/DTFluxCore/Public/Types/Struct/DTFluxRankingStructs.h @@ -8,6 +8,18 @@ #include "DTFluxRankingStructs.generated.h" +USTRUCT(BlueprintType) +struct DTFLUXCORE_API FDTFluxBaseRankings +{ + GENERATED_BODY() + +public: + UPROPERTY(BlueprintReadOnly, Category="DTFlux|Model", VisibleAnywhere) + FDateTime ReceivedAt = FDateTime::Now(); + + bool IsSealed(const FDateTime EndTime) const; +}; + /** * @struct FDTFluxContestRanking * Representing a contest ranking for a participant @@ -37,7 +49,7 @@ public: USTRUCT(BlueprintType) -struct FDTFluxContestRankings +struct FDTFluxContestRankings : public FDTFluxBaseRankings { GENERATED_BODY() @@ -94,7 +106,7 @@ public: }; USTRUCT(BlueprintType) -struct FDTFluxDetailedRankings +struct FDTFluxDetailedRankings : public FDTFluxBaseRankings { GENERATED_BODY() diff --git a/Source/DTFluxCoreSubsystem/Private/DTFluxCoreSubsystem.cpp b/Source/DTFluxCoreSubsystem/Private/DTFluxCoreSubsystem.cpp index 6557b65..8499282 100644 --- a/Source/DTFluxCoreSubsystem/Private/DTFluxCoreSubsystem.cpp +++ b/Source/DTFluxCoreSubsystem/Private/DTFluxCoreSubsystem.cpp @@ -185,6 +185,46 @@ void UDTFluxCoreSubsystem::RegisterDelegates() } } +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; +} + + void UDTFluxCoreSubsystem::ProcessRaceData(const FDTFluxRaceData& RaceDataDefinition) { if (RaceDataDefinition.Datas.Num() > 0) @@ -288,6 +328,138 @@ void UDTFluxCoreSubsystem::SendRequest(const FString& Message) } } +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::ContestRanking, 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) { @@ -491,7 +663,6 @@ TArray UDTFluxCoreSubsystem::TrackedRequestStageRankings(const TArraySendTrackedRequestWithCallbacks(EDTFluxApiDataType::StageRanking, diff --git a/Source/DTFluxCoreSubsystem/Public/DTFluxCoreSubsystem.h b/Source/DTFluxCoreSubsystem/Public/DTFluxCoreSubsystem.h index 8029005..180fd98 100644 --- a/Source/DTFluxCoreSubsystem/Public/DTFluxCoreSubsystem.h +++ b/Source/DTFluxCoreSubsystem/Public/DTFluxCoreSubsystem.h @@ -41,6 +41,25 @@ public: UPROPERTY(BlueprintAssignable, Category="DTFlux|Core Subsystem") FOnStageRankings OnStageRankings; + + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnContestRankingDisplayReady, const FGuid, RequestId, const bool, + bSuccesRequest); + + UPROPERTY(BlueprintAssignable, Category="DTFlux|Core Subsystem") + FOnContestRankingDisplayReady OnContestRankingDisplayReady; + + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnStageRankingDisplayReady, const FGuid, RequestId, const bool, + bSuccesRequest); + + UPROPERTY(BlueprintAssignable, Category="DTFlux|Core Subsystem") + FOnStageRankingDisplayReady OnStageRankingDisplayReady; + + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSplitRankingDisplayReady, const FGuid, RequestId, const bool, + bSuccesRequest); + + UPROPERTY(BlueprintAssignable, Category="DTFlux|Core Subsystem") + FOnSplitRankingDisplayReady OnSplitRankingDisplayReady; + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnContestRankings, const int, ContestId, FDTFluxContestRankings, ContestRankings); @@ -78,6 +97,18 @@ public: UPROPERTY(BlueprintReadOnly, Category="DTFlux|Core Subsystem") bool bShouldKeepRankings = true; + + UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem") + FGuid InitContestRankingsDisplay(const int ContestIds); + + + UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem") + FGuid InitStageRankingsDisplay(const int ContestId, const int StageId); + + UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem") + FGuid InitSplitRankingsDisplay(const int ContestId, const int StageId, const int SplitId); + + UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem") bool GetStageRankingForBib(const int ContestId, const int StageId, const int Bib, FDTFluxStageRanking& OutStageRankings); @@ -165,4 +196,9 @@ private: void SendRequest(const FString& Message); UFUNCTION() void RegisterDelegates(); + + UFUNCTION() + bool IsStageRankingSealed(FDTFluxStageKey StageKey); + UFUNCTION() + bool IsContestRankingSealed(int ContestId); };