From f1b7834743bd25c7bad00882d70cac60ae64f3fd Mon Sep 17 00:00:00 2001 From: Ange-Marie MAURIN Date: Tue, 16 Jul 2024 17:03:33 +0200 Subject: [PATCH] Added Subsystem Timer --- .../DTFluxCountDownComponent.cpp | 10 +- .../DTFluxDataStorage/DTFluxDataStorage.cpp | 255 ++++++++++++------ .../DTFluxSubsystem/DTFluxSubsystem.cpp | 100 +++---- .../DTFluxSubsystem/DTFluxSubsystemTimer.cpp | 189 +++++++++++++ .../Private/DTFluxUtils/DTFluxUtils.cpp | 21 ++ .../DTFluxCountDownComponent.h | 14 +- .../DTFluxDataStorage/DTFluxDataStorage.h | 42 ++- .../Public/DTFluxModel/DTFluxModel.h | 136 ++++++++-- .../Public/DTFluxModel/DTFluxModelResponse.h | 10 +- .../Public/DTFluxSubsystem/DTFluxSubsystem.h | 20 +- .../DTFluxSubsystem/DTFluxSubsystemTimer.h | 84 ++++++ .../Public/DTFluxUtils/DTFluxEnums.h | 49 +++- .../Public/DTFluxUtils/DTFluxUtils.h | 98 +++++++ 13 files changed, 823 insertions(+), 205 deletions(-) create mode 100644 Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystemTimer.cpp create mode 100644 Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystemTimer.h diff --git a/Source/DTFluxAPI/Private/DTFluxCountDown/DTFluxCountDownComponent.cpp b/Source/DTFluxAPI/Private/DTFluxCountDown/DTFluxCountDownComponent.cpp index e91202c..1ab5d85 100644 --- a/Source/DTFluxAPI/Private/DTFluxCountDown/DTFluxCountDownComponent.cpp +++ b/Source/DTFluxAPI/Private/DTFluxCountDown/DTFluxCountDownComponent.cpp @@ -4,6 +4,7 @@ #include "DTFluxCountDown/DTFluxCountDownComponent.h" #include "DTFluxAPILog.h" +#include "DTFluxSubsystem/DTFluxSubsystem.h" // Sets default values for this component's properties @@ -12,7 +13,14 @@ UDTFluxCountDownComponent::UDTFluxCountDownComponent() // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features // off to improve performance if you don't need them. PrimaryComponentTick.bCanEverTick = true; - + if(FModuleManager::Get().IsModuleLoaded("DTFluxApi")) + { + DataStorage = GEngine->GetEngineSubsystem()->GetDataStorage(); + UE_LOG(LogDTFluxAPI, Log, TEXT("DTFluxApi loaded")) + }else + { + UE_LOG(LogDTFluxAPI, Error, TEXT("DTFluxApi Not Loaded")) + } // ... } diff --git a/Source/DTFluxAPI/Private/DTFluxDataStorage/DTFluxDataStorage.cpp b/Source/DTFluxAPI/Private/DTFluxDataStorage/DTFluxDataStorage.cpp index 6da26ce..bb4676b 100644 --- a/Source/DTFluxAPI/Private/DTFluxDataStorage/DTFluxDataStorage.cpp +++ b/Source/DTFluxAPI/Private/DTFluxDataStorage/DTFluxDataStorage.cpp @@ -3,7 +3,6 @@ #include "DTFluxDataStorage/DTFluxDataStorage.h" -// #include "AsyncTreeDifferences.h" #include "DTFluxAPILog.h" #include "DTFluxModel/DTFluxModel.h" @@ -138,73 +137,110 @@ FDTFluxFinisher UDTFluxDataStorage::GetFinisherStatus(const FDTFluxSplitSensorRe return Finisher; } -bool UDTFluxDataStorage::GetContest(FDTFluxContest& OutContest, const int& ContestId) +bool UDTFluxDataStorage::GetContest(const int ContestId, FDTFluxContest& OutContest ) { - // Current contest requested - if(ContestId == -1) + // UE_LOG(LogDTFluxAPI, Warning, TEXT("RequestedContest %d"), + // ContestId); + for(auto& Contest : Contests) { - FDateTime Now = FDateTime::Now(); - for(auto& Contest : Contests) + // UE_LOG(LogDTFluxAPI, Warning, TEXT("Checking Contest %d"), + // Contest.Id); + if(Contest.Id == ContestId) { - for( auto& Stage : Contest.Stages) + // UE_LOG(LogDTFluxAPI, Warning, TEXT("Found Contest %d"), + // Contest.Id); + OutContest = Contest; + return true; + } + } + // UE_LOG(LogDTFluxAPI, Error, TEXT("Contest %d not Found "), + // ContestId); + return false; +} + +bool UDTFluxDataStorage::GetStage(const int ContestId, const int StageId, FDTFluxStage& OutStage) +{ + FDTFluxContest Contest; + // UE_LOG(LogDTFluxAPI, Warning, TEXT("RequestedStage %d in Contest%02d ****"), + // ContestId, StageId); + if(GetContest(ContestId, Contest)) + { + for(auto & Stage: Contest.Stages) + { +// UE_LOG(LogDTFluxAPI, Warning, TEXT("Checking Stage %d "), +// Stage.Id); + if(Stage.Id == StageId) { - if(Stage.StartTime >= Now && Stage.EndTime <= Now) - { - //We have a winner - OutContest = Contest; - return true; - } + + // UE_LOG(LogDTFluxAPI, Warning, TEXT("Found %s in Stage ***"), + // *Stage.Name); + OutStage = Stage; + return true; } } } - else + // UE_LOG(LogDTFluxAPI, Error, TEXT("Stage %d Not Found in Contest %d ****"), + // StageId, ContestId); + return false; +} + +bool UDTFluxDataStorage::GetSplit(const int ContestId, const int StageId, const int SplitId, FDTFluxSplit& OutSplit) +{ + // DumpContest(); + FDTFluxStage Stage; + // UE_LOG(LogDTFluxAPI, Warning, TEXT("RequestedSplit %d in Stage%02d of Contest%02d"), + // ContestId, StageId, SplitId); + if(GetStage(ContestId, StageId, Stage)) { - for( auto& Contest : Contests) + for(auto& Split: Stage.Splits) { - if(Contest.Id == ContestId) + if(Split.Id == SplitId) { - OutContest = Contest; + // UE_LOG(LogDTFluxAPI, Warning, TEXT("Get Split %s in Stage%02d of Contest%02d"), + // *Split.Name, StageId, SplitId); + OutSplit = Split; return true; } } } return false; + } -bool UDTFluxDataStorage::GetStage(FDTFluxStage& CurrentStage, const int& StageId) +FDTFluxSplitRanking UDTFluxDataStorage::AddSplitRanking(const FDTFluxSplitSensorItemResponse& SplitSensorItem) { - // Current contest requested - if(StageId == -1) + FDTFluxSplitRanking NewSplitRanking; + NewSplitRanking.Bib = SplitSensorItem.Bib; + NewSplitRanking.Gap = SplitSensorItem.Gap; + NewSplitRanking.Rank = SplitSensorItem.Rank; + NewSplitRanking.Time = SplitSensorItem.Time; + FDTFluxSplit Split; + if(GetSplit(SplitSensorItem.ContestID, SplitSensorItem.StageID, + SplitSensorItem.SplitID, Split)) { - FDateTime Now = FDateTime::Now(); - for(auto& Contest : Contests) - { - for( auto& Stage : Contest.Stages) - { - if(StageId <= -1) - { - if(Stage.StartTime >= Now && Stage.EndTime <= Now) - { - //We have a winner for current stage - CurrentStage = Stage; - return true; - } - }else - { - if(Stage.Id == StageId) - { - //We have a winner for the search stage - CurrentStage = Stage; - return true; - } - } - - } - } + Split.SplitRankings.Add(NewSplitRanking); + return NewSplitRanking; } - return false; + UE_LOG(LogDTFluxAPI, Error, + TEXT("Error, Cannot process split sensor.")) + UE_LOG(LogDTFluxAPI, Error, TEXT("Split %d from stage %d of Contest %d does not exist"), + SplitSensorItem.SplitID, SplitSensorItem.StageID, SplitSensorItem.ContestID); + return NewSplitRanking; } +EDTFluxSplitType UDTFluxDataStorage::GetSplitStatus(int ContestID, int StageID, int SplitID) +{ + FDTFluxStage Stage; + if(GetStage(ContestID, StageID, Stage)) + { + int SplitCount = Stage.Splits.Num(); + FDTFluxSplit S; + return Stage.GetSplitType(SplitID); + } + return EDTFluxSplitType::UnknownSplitType; +} + + TArray UDTFluxDataStorage::GetParticipants(const int ContestId) { TArray Participants; @@ -254,6 +290,7 @@ void UDTFluxDataStorage::AddOrUpdateContest(const FDTFluxContestResponse& Contes FDTFluxContest Contest; bool NewContest = false; int ContestIdx = 0; + // UE_LOG(LogDTFluxAPI, Warning, TEXT("DateTime Json Contest \"%s\""), *ContestResponse.Date.ToString() ); if(!Contests.IsEmpty() ) { for(auto& OldContest: Contests) @@ -277,6 +314,7 @@ void UDTFluxDataStorage::AddOrUpdateContest(const FDTFluxContestResponse& Contes // Updating values Contest.Id = ContestResponse.Id; Contest.Name = ContestResponse.Name; + Contest.Date = ContestResponse.Date; TArray Splits; for(auto Split: ContestResponse.Splits) { @@ -290,18 +328,32 @@ void UDTFluxDataStorage::AddOrUpdateContest(const FDTFluxContestResponse& Contes FDTFluxStage Stage; Stage.Id = StageResp.Id; Stage.Name = StageResp.Name; - FDateTime::Parse(StageResp.StartTime, Stage.StartTime); - FDateTime::Parse(StageResp.EndTime, Stage.EndTime); + // UE_LOG(LogDTFluxAPI, Warning, TEXT("ContestResponse.Stage StartTime = %s"), *StageResp.StartTime); + // UE_LOG(LogDTFluxAPI, Warning, TEXT("ContestResponse.Stage EndTime = %s"), *StageResp.EndTime); + // UE_LOG(LogDTFluxAPI, Warning, TEXT("ContestResponse.Stage CutOff = %s"), *StageResp.CutOff); + FTimespan StartTimeSpan; + FTimespan::Parse(StageResp.StartTime, StartTimeSpan); + FTimespan EndTimeSpan; + FTimespan::Parse(StageResp.EndTime, EndTimeSpan); + FTimespan CutOffTimeSpan; + FTimespan::Parse(StageResp.CutOff, CutOffTimeSpan); + Stage.StartTime = Contest.Date + StartTimeSpan; + Stage.EndTime = Contest.Date + EndTimeSpan; + Stage.CutOff = Stage.StartTime + CutOffTimeSpan; + // UE_LOG(LogDTFluxAPI, Warning, TEXT("STAGE StartTime = %s"), *Stage.StartTime.ToString()); + // UE_LOG(LogDTFluxAPI, Warning, TEXT("STAGE EndTime = %s"), *Stage.EndTime.ToString()); + // UE_LOG(LogDTFluxAPI, Warning, TEXT("STAGE CutOff = %s"), *Stage.CutOff.ToString()); + Stage.Splits = Splits; Contest.Stages.Add(Stage); } if(NewContest) { - Contest.Dump(); + // Contest.Dump(); Contests.Add(Contest); return; } - Contest.Dump(); + // Contest.Dump(); Contests.RemoveAt(ContestIdx); Contests.Insert(Contest, ContestIdx); // handle updating contest @@ -309,10 +361,10 @@ void UDTFluxDataStorage::AddOrUpdateContest(const FDTFluxContestResponse& Contes void UDTFluxDataStorage::AddOrUpdateParticipant(const FDTFluxTeamListItemResponse& TeamListItemResponse) { - UE_LOG(LogDTFluxAPI, Log, TEXT("In DataStorage::AddOrUpdateParticipant")); - UE_LOG(LogDTFluxAPI, Log, TEXT("AboutToUpdateOrAdd Participant %d %s %s in Contest%02d "), - TeamListItemResponse.Bib, *TeamListItemResponse.FirstName, *TeamListItemResponse.LastName, - TeamListItemResponse.ContestId); + // UE_LOG(LogDTFluxAPI, Log, TEXT("In DataStorage::AddOrUpdateParticipant")); + // UE_LOG(LogDTFluxAPI, Log, TEXT("AboutToUpdateOrAdd Participant %d %s %s in Contest%02d "), + // TeamListItemResponse.Bib, *TeamListItemResponse.FirstName, *TeamListItemResponse.LastName, + // TeamListItemResponse.ContestId); FDTFluxParticipant Participant; Participant.Bib = TeamListItemResponse.Bib; Participant.Category = TeamListItemResponse.Category; @@ -330,15 +382,15 @@ void UDTFluxDataStorage::AddOrUpdateParticipant(const FDTFluxTeamListItemRespons { if(Contest.Id == TeamListItemResponse.ContestId) { - UE_LOG(LogDTFluxAPI, Log, TEXT("AboutToUpdateOrAdd Participant %d %s %s in Contest%02d "), - Participant.Bib, *Participant.Person1.FirstName, *Participant.Person1.LastName, - Contest.Id); + // UE_LOG(LogDTFluxAPI, Log, TEXT("AboutToUpdateOrAdd Participant %d %s %s in Contest%02d "), + // Participant.Bib, *Participant.Person1.FirstName, *Participant.Person1.LastName, + // Contest.Id); Contest.AddParticipant(Participant); return; } - UE_LOG(LogDTFluxAPI, Log, TEXT("Contest%02d has now %04d Participants"), Contest.Id, - Contest.Participants.Num()); + // UE_LOG(LogDTFluxAPI, Log, TEXT("Contest%02d has now %04d Participants"), Contest.Id, + // Contest.Participants.Num()); } } @@ -389,16 +441,21 @@ void UDTFluxDataStorage::UpdateStageRanking(const FDTFluxStageRankingResponse& S // UE_LOG(LogDTFluxAPI, Log, TEXT("Found Stage::%02d "),Stage.Id); // Cleaning StageRanking Stage.StageRanking.Empty(); - for(auto& StageRanking: StageRankingResponse.Datas ) + for(auto& StageRankingResp: StageRankingResponse.Datas ) { FDTFluxStageRanking NewStageRanking; - NewStageRanking.TimeRun = StageRanking.TimeRun; - NewStageRanking.TimeStart = StageRanking.TimeStart; - NewStageRanking.TimeTransition = StageRanking.TimeTransition; - NewStageRanking.TimeSwim = StageRanking.TimeSwim; - NewStageRanking.Bib = StageRanking.Bib; - NewStageRanking.Gap = StageRanking.Gap; - NewStageRanking.Rank = StageRanking.Rank; + NewStageRanking.TimeRun = StageRankingResp.TimeRun; + FTimespan StartTimeSpan; + FTimespan::Parse(StageRankingResp.TimeStart, StartTimeSpan); + NewStageRanking.TimeStart = Contest.Date + StartTimeSpan; + NewStageRanking.TimeTransition = StageRankingResp.TimeTransition; + NewStageRanking.TimeSwim = StageRankingResp.TimeSwim; + NewStageRanking.Bib = StageRankingResp.Bib; + NewStageRanking.Gap = StageRankingResp.Gap; + NewStageRanking.Rank = StageRankingResp.Rank; + NewStageRanking.SpeedRunning = StageRankingResp.SpeedRunning; + NewStageRanking.SpeedSwim = StageRankingResp.SpeedSwim; + NewStageRanking.SpeedTotal = StageRankingResp.SpeedTotal; Stage.StageRanking.Add(NewStageRanking); Stage.SortStageRanking(); // UE_LOG(LogDTFluxAPI, Log, @@ -414,15 +471,8 @@ void UDTFluxDataStorage::UpdateStageRanking(const FDTFluxStageRankingResponse& S void UDTFluxDataStorage::AddSplitSensorResult(FDTFluxSplitSensorItemResponse Response) { // Send SplitSensor Result to BP - FDTFluxStage CurrentStage; - if(GetStage(CurrentStage, Response.StageID)) - { - // this is an empty stage - if(CurrentStage.Id == -1 ) - { - - } - } + + } @@ -470,3 +520,56 @@ const FString UDTFluxDataStorage::GetConcurrentFormatedName(int Bib, bool Trunca return ""; }; } + +bool UDTFluxDataStorage::GetFirstStageOfContest(const int ContestId, FDTFluxStage& Stage) +{ + if(Contests.IsEmpty()) + { + return false; + } + for (auto& Contest : Contests) + { + if(Contest.Id == ContestId) + { + Contest.Stages.Sort([](const FDTFluxStage& A, const FDTFluxStage& B) + { + return A.Id < B.Id; + }); + if(Contest.Stages.IsValidIndex(0)) + { + Stage = Contest.Stages[0]; + return true; + } + return false; + + } + } + return false; +} + +void UDTFluxDataStorage::DumpContest() +{ + for(const auto& Contest : Contests) + { + UE_LOG(LogDTFluxAPI, Warning, TEXT("Contest%02d with name %s : Date %s\n"), + Contest.Id, *Contest.Name, *Contest.Date.ToString()); + // UE_LOG(LogDTFluxAPI, Warning, TEXT("Participants :\n")); + // for(const auto& Participant : Contest.Participants) + // { + // Participant.Dump(); + // } + UE_LOG(LogDTFluxAPI, Warning, TEXT("Stages :\n")); + for(const auto& Stage : Contest.Stages) + { + Stage.Dump(); + } + UE_LOG(LogDTFluxAPI, Warning, TEXT("ContestRanking :\n")); + for(const auto& ContestRankingItem : Contest.ContestRanking) + { + ContestRankingItem.Dump(); + } + + } +} + + diff --git a/Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystem.cpp b/Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystem.cpp index 14a1e3c..2b2f3bc 100644 --- a/Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystem.cpp +++ b/Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystem.cpp @@ -34,63 +34,7 @@ void UDTFluxSubsystem::Initialize(FSubsystemCollectionBase& Collection) FDateTime Now = FDateTime::Now(); FDateTime Send1Min = Now + FTimespan::FromMinutes(1); UE_LOG(LogDTFluxAPI, Log, TEXT("TEST timer timeSpan Duration : %s"), *Send1Min.ToString()); - // SetTimerEvent( Send1Min ); - // UWorld* World = nullptr; - // TIndirectArray WorldCtx = GEngine->GetWorldContexts(); - // for(const auto& Ctx : WorldCtx) - // { - // EWorldType::Type Type = Ctx.WorldType.GetValue(); - // switch(Type) - // { - // case EWorldType::None: - // UE_LOG(LogDTFluxAPI, Log, TEXT("Ctx world is None ")); - // break; - // - // case EWorldType::Editor: - // UE_LOG(LogDTFluxAPI, Log, TEXT("Ctx world is EDITOR ")); - // break; - // - // case EWorldType::Game: - // UE_LOG(LogDTFluxAPI, Log, TEXT("Ctx world is GAME ")); - // break; - // - // case EWorldType::GamePreview : - // UE_LOG(LogDTFluxAPI, Log, TEXT("Ctx world is GamePreview ")); - // break; - // - // case EWorldType::EditorPreview: - // UE_LOG(LogDTFluxAPI, Log, TEXT("Ctx world is EditorPreview ")); - // break; - // - // case EWorldType::Inactive: - // UE_LOG(LogDTFluxAPI, Log, TEXT("Ctx world is Inactive ")); - // break; - // - // case EWorldType::PIE: - // UE_LOG(LogDTFluxAPI, Log, TEXT("Ctx world is PIE ")); - // break; - // - // case EWorldType::GameRPC: - // UE_LOG(LogDTFluxAPI, Log, TEXT("Ctx world is GameRPC ")); - // break; - // - // default: - // break; - // } - // } - // if(World) - // { - // UE_LOG(LogDTFluxAPI, Log, TEXT("World IS NOT NULL")); - // - // World->GetTimerManager().SetTimer( - // TestTimerHandle, this, &UDTFluxSubsystem::TestTimers, 1.0f, true); - // } - // else - // { - // UE_LOG(LogDTFluxAPI, Log, TEXT("World IS NULL:-D")); - // } - // WsServer Event binding } void UDTFluxSubsystem::Deinitialize() @@ -185,8 +129,6 @@ void UDTFluxSubsystem::Tick(float DeltaTime) } } - - void UDTFluxSubsystem::RequestRaceDatas() { WsClient->SendMessage(TEXT("{\"path\": \"race-datas\"}")); @@ -260,7 +202,6 @@ void UDTFluxSubsystem::BroadcastTimerEvent() } - void UDTFluxSubsystem::SetTimerEvent(const FDateTime& When) { FTimespan TimeSpan = FDateTime::Now() - When; @@ -270,14 +211,12 @@ void UDTFluxSubsystem::SetTimerEvent(const FDateTime& When) // AddTimer(When, ) } - bool UDTFluxSubsystem::AddTimer(FDateTime Time, FOnTimer NewTimer) { Timer.Add(Time, NewTimer); return true; } - /** * END TIMER HANDLING ***/ @@ -403,6 +342,7 @@ void UDTFluxSubsystem::WsReceivedMessage( const FString& MessageReceived) UE_LOG(LogDTFluxAPI, Error, TEXT("Message %s is not a valid split-sensor data"), *MessageReceived) } UE_LOG(LogDTFluxAPI, Log, TEXT("Received split-sensor data")); + ProcessSplitSensor(SplitSensorResponse); Event.WsResponseType = SplitSensor; } @@ -479,6 +419,7 @@ void UDTFluxSubsystem::ProcessRaceDataResponse(const FDTFluxRaceDataResponse& Da Event.WsResponseType = RaceData; Event.RawData = "race-data"; OnWsEvent.Broadcast(Event); + OnRaceDataReceived.Broadcast(); // UE_LOG(LogDTFluxAPI, Log, TEXT("New Contest Size %d"), DataStorage->Contests.Num()) } @@ -537,15 +478,40 @@ void UDTFluxSubsystem::ProcessSplitSensor(const FDTFluxSplitSensorResponse& Spli { // + for(auto& SplitSensorItem : SplitSensorResponse.Datas) + { + FDTFluxSplitRanking NewRanking = DataStorage->AddSplitRanking(SplitSensorItem); + UE_LOG(LogDTFluxAPI, Log, TEXT("Checking SplitStatus ...")) + EDTFluxSplitType SplitType = DataStorage->GetSplitStatus(SplitSensorItem.ContestID, + SplitSensorItem.StageID, SplitSensorItem.SplitID); + switch(SplitType) + { + case PreFinnishSplit: + UE_LOG(LogDTFluxAPI, Warning, TEXT("SplitSensor %d for Stage%02d in Contest%02d is a Prefinish Sensor"), + SplitSensorItem.SplitID, SplitSensorItem.StageID, SplitSensorItem.ContestID); + OnSpotter.Broadcast(NewRanking); + break; + case FinishSplit: + UE_LOG(LogDTFluxAPI, Warning, TEXT("SplitSensor %d for Stage%02d in Contest%02d is a Finish Sensor"), + SplitSensorItem.SplitID, SplitSensorItem.StageID, SplitSensorItem.ContestID); + OnFinisher.Broadcast(NewRanking); + break; + case NormalSplit: + UE_LOG(LogDTFluxAPI, Warning, TEXT("SplitSensor %d for Stage%02d in Contest%02d is a Normal Split"), + SplitSensorItem.SplitID, SplitSensorItem.StageID, SplitSensorItem.ContestID); + OnSplitSensor.Broadcast(NewRanking); + break; + default: + UE_LOG(LogDTFluxAPI, Error, TEXT("SplitSensor %d for Stage%02d in Contest%02d %s"), + SplitSensorItem.SplitID, SplitSensorItem.StageID, SplitSensorItem.ContestID, + *UEnum::GetValueAsString(SplitType)); + break; + } + } FDTFluxWsResponseEvent Event; Event.WsResponseType = SplitSensor; Event.RawData = "split-sensor"; OnWsEvent.Broadcast(Event); - // determine if SplitSensorResponse come from a finisher spot - if(DataStorage->IsFinisherSplit(SplitSensorResponse)) - { - FDTFluxFinisher Finisher = DataStorage->GetFinisherStatus(SplitSensorResponse); - OnFinisher.Broadcast(Finisher); - } + } diff --git a/Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystemTimer.cpp b/Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystemTimer.cpp new file mode 100644 index 0000000..e57051f --- /dev/null +++ b/Source/DTFluxAPI/Private/DTFluxSubsystem/DTFluxSubsystemTimer.cpp @@ -0,0 +1,189 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "DTFluxSubsystem/DTFluxSubsystemTimer.h" + +#include "DTFluxAPILog.h" +#include "DTFluxSubsystem/DTFluxSubsystem.h" + +void UDTFluxSubsystemTimer::Initialize(FSubsystemCollectionBase& Collection) +{ + Super::Initialize(Collection); + + UDTFluxSubsystem* Subsystem = GetDTFluxSubSystem(); + Subsystem->OnRaceDataReceived.AddDynamic(this, &UDTFluxSubsystemTimer::OnDataStorageInit); + +} + +void UDTFluxSubsystemTimer::Deinitialize() +{ + Super::Deinitialize(); +} + +void UDTFluxSubsystemTimer::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); +} + + + +void UDTFluxSubsystemTimer::OnDataStorageInit() +{ + UE_LOG(LogDTFluxAPI, Log, TEXT("DataStorage Has been Set Or Updated")); + UDTFluxDataStorage* DataStorage = GetDTFluxDataStorage(); + + for(const auto&Contest : DataStorage->Contests) + { + for (const auto& Stage: Contest.Stages) + { + + UWorld* World = GetWorld(); + if(World) + { + + FDTFluxContestTimerHandle StartContestTimerHandle; + StartContestTimerHandle.Type = EDTFluxTimerEventType::StageStart; + StartContestTimerHandle.ContestId = Contest.Id; + StartContestTimerHandle.StageId = Stage.Id; + + FDTFluxContestTimerHandle CutOffContestTimerHandle; + CutOffContestTimerHandle.Type = EDTFluxTimerEventType::StageCutOff; + CutOffContestTimerHandle.ContestId = Contest.Id; + CutOffContestTimerHandle.StageId = Stage.Id; + + float StartTimeTriggerSeconds = GetSecondsFrom(Stage.StartTime); + float CutOffTimeTriggerSeconds = GetSecondsFrom(Stage.CutOff); + if( StartTimeTriggerSeconds > 0) + { + UE_LOG(LogDTFluxAPI, Log, TEXT("Can Set Time to %04f Seconds"), StartTimeTriggerSeconds ); + World->GetTimerManager().SetTimer(StartContestTimerHandle.Handle, this, &UDTFluxSubsystemTimer::OnStartTimer, StartTimeTriggerSeconds); + World->GetTimerManager().SetTimer(CutOffContestTimerHandle.Handle, this, &UDTFluxSubsystemTimer::OnCutOffTimer, CutOffTimeTriggerSeconds); + Timers.Add(StartContestTimerHandle); + Timers.Add(CutOffContestTimerHandle); + + } + else + { + UE_LOG(LogDTFluxAPI, Warning, TEXT("Unable to Set Time to %04f Seconds"), StartTimeTriggerSeconds); + } + } + + } + + + } + +} + +void UDTFluxSubsystemTimer::AddCutoffTimer(const int ContestID, const int StageID) +{ + UWorld* World = GetWorld(); + if(World) + { + FTimerHandle Timer; + World->GetTimerManager().SetTimer(Timer, this, &UDTFluxSubsystemTimer::OnStartTimer, 1.0, true); + UE_LOG(LogDTFluxAPI, Warning, TEXT("AddCutoffTimer Added")); + } + UE_LOG(LogDTFluxAPI, Error, + TEXT("UDTFluxSubsystemTimer::AddCutoffTimer Cannot have the World")); +} + + +void UDTFluxSubsystemTimer::AddStageStartedTimer(const int ContestID, const int StageID) +{ + UWorld* World = GetWorld(); + if(World) + { + FTimerHandle Timer; + World->GetTimerManager().SetTimer(Timer, this, &UDTFluxSubsystemTimer::OnStartTimer, 1.0, true); + UE_LOG(LogDTFluxAPI, Warning, TEXT("AddStageStartedTimer Added")); + } + UE_LOG(LogDTFluxAPI, Error, + TEXT("UDTFluxSubsystemTimer::AddStageStartedTimer Cannot have the World")); + +} + +void UDTFluxSubsystemTimer::OnStartTimer() +{ + + UWorld* World = GetWorld(); + if(World) + { + int Idx = 0 ; + for(auto& Timer : Timers) + { + if(Timer.Type == EDTFluxTimerEventType::StageStart) + { + if(World->GetTimerManager().GetTimerRemaining(Timer.Handle) == 0) + { + OnStageStarted.Broadcast(Timer.ContestId, Timer.StageId); + break; + } + } + Idx++; + } + if(Timers.IsValidIndex(Idx)) + { + Timers.RemoveAt(Idx); + } + } + +} +void UDTFluxSubsystemTimer::OnCutOffTimer() +{ + UWorld* World = GetWorld(); + if(World) + { + int Idx = 0 ; + for(auto& Timer : Timers) + { + if(Timer.Type == EDTFluxTimerEventType::StageCutOff) + { + if(World->GetTimerManager().GetTimerRemaining(Timer.Handle) == 0) + { + OnCutoff.Broadcast(Timer.ContestId, Timer.StageId); + break; + } + } + Idx++; + } + if(Timers.IsValidIndex(Idx)) + { + Timers.RemoveAt(Idx); + } + } +} + +void UDTFluxSubsystemTimer::ClearTimer(FDTFluxContestTimerHandle TimerHandle) +{ + UWorld* World = GetWorld(); + if(World) + { + World->GetTimerManager().ClearTimer(TimerHandle.Handle); + } + UE_LOG(LogDTFluxAPI, Error, TEXT("Cannot Clear Timer %s of type %s for Stage%02d of Contest%02d"), + *TimerHandle.Handle.ToString(), *UEnum::GetValueAsString(TimerHandle.Type), + TimerHandle.StageId, TimerHandle.ContestId) + +} + +void UDTFluxSubsystemTimer::ClearTimer(const int HandleIndex) +{ +} + +UDTFluxSubsystem* UDTFluxSubsystemTimer::GetDTFluxSubSystem() +{ + return GEngine->GetEngineSubsystem(); +} + +UDTFluxDataStorage* UDTFluxSubsystemTimer::GetDTFluxDataStorage() +{ + return GetDTFluxSubSystem()->GetDataStorage(); +} + +float UDTFluxSubsystemTimer::GetSecondsFrom(const FDateTime When) +{ + FTimespan Delta = When - FDateTime::Now(); + return static_cast(Delta.GetTotalSeconds()) ; +} + diff --git a/Source/DTFluxAPI/Private/DTFluxUtils/DTFluxUtils.cpp b/Source/DTFluxAPI/Private/DTFluxUtils/DTFluxUtils.cpp index e20cef9..d4209c6 100644 --- a/Source/DTFluxAPI/Private/DTFluxUtils/DTFluxUtils.cpp +++ b/Source/DTFluxAPI/Private/DTFluxUtils/DTFluxUtils.cpp @@ -5,3 +5,24 @@ #include "DTFluxModel/DTFluxModel.h" +EDTFluxStageStatusType UDTFluxModelHelper::GetStatusType(const int ContestID, const int StageID, + UDTFluxDataStorage* DataStorage) +{ + EDTFluxStageStatusType StageStatus = UnknownStatus; + + FDTFluxStage SelectedStage; + if( DataStorage->GetStage(ContestID, StageID, SelectedStage)) + { + StageStatus = StageWaiting; + FDateTime Now = FDateTime::Now(); + if(SelectedStage.StartTime <= Now) + { + StageStatus = StageStarted; + } + if(SelectedStage.CutOff <= Now) + { + StageStatus = StageEnded; + } + } + return StageStatus; +} diff --git a/Source/DTFluxAPI/Public/DTFluxCountDown/DTFluxCountDownComponent.h b/Source/DTFluxAPI/Public/DTFluxCountDown/DTFluxCountDownComponent.h index a76b635..a8d50bf 100644 --- a/Source/DTFluxAPI/Public/DTFluxCountDown/DTFluxCountDownComponent.h +++ b/Source/DTFluxAPI/Public/DTFluxCountDown/DTFluxCountDownComponent.h @@ -5,6 +5,7 @@ #include "CoreMinimal.h" #include "AvaText3DComponent.h" #include "Components/ActorComponent.h" +#include "DTFluxDataStorage/DTFluxDataStorage.h" #include "DTFluxCountDownComponent.generated.h" @@ -35,11 +36,12 @@ protected: int64 InternalDuration; bool IsWaiting; bool IsCounting; + UDTFluxDataStorage* DataStorage; public: - + UPROPERTY(BlueprintReadWrite, Category="DTFlux|Counter") FString EndString; UPROPERTY(BlueprintReadWrite, Category="DTFlux|Counter") @@ -51,11 +53,21 @@ public: virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + + UFUNCTION(BlueprintCallable, Category="DTFlux|Counter") void SetGoTime(FDateTime NewGoTime); UFUNCTION(BlueprintCallable, Category="DTFlux|Counter") void SetDuration(int32 NewDuration); + // set the current stage + UFUNCTION(BlueprintCallable, Category="DTFlux|Counter") + void SetStage(const int ContestId, const int StageId){}; + + // set the current contest + UFUNCTION(BlueprintCallable, Category="DTFlux|Counter") + void SetContest(const int ContestId){}; + UFUNCTION(BlueprintCallable, Category="DTFlux|Counter") void SetTarget(UAvaText3DComponent* TextComponent); diff --git a/Source/DTFluxAPI/Public/DTFluxDataStorage/DTFluxDataStorage.h b/Source/DTFluxAPI/Public/DTFluxDataStorage/DTFluxDataStorage.h index 60eb742..a852c96 100644 --- a/Source/DTFluxAPI/Public/DTFluxDataStorage/DTFluxDataStorage.h +++ b/Source/DTFluxAPI/Public/DTFluxDataStorage/DTFluxDataStorage.h @@ -16,26 +16,9 @@ struct FDTFluxParticipant; struct FDTFluxStage; struct FDTFluxContest; -UENUM(BlueprintType, Category="DTFlux|DataStorage") -// ReSharper disable once IdentifierTypo -enum EDTFluxDataStorageEventType : uint8 -{ - UnknownEvent = 0 UMETA(DisplayName="ParticipantUpdateEvent"), - ParticipantCreateEvent = 1 UMETA(DisplayName="ParticipantUpdateEvent"), - ParticipantUpdateEvent = 2 UMETA(DisplayName="ParticipantUpdateEvent"), - ParticipantDeleteEvent = 3 UMETA(DisplayName="ParticipantUpdateEvent"), - ParticipantStatusUpdateEvent = 4 UMETA(DisplayName="ParticipantUpdateEvent"), - RaceDataCreateEvent = 5 UMETA(DisplayName="ParticipantUpdateEvent"), - RaceDataUpdateEvent = 6 UMETA(DisplayName="ParticipantUpdateEvent"), - RaceDataDeleteEvent = 7 UMETA(DisplayName="ParticipantUpdateEvent"), - ContestRankingUpdate = 8 UMETA(DisplayName="ParticipantUpdateEvent"), - StageRankingUpdate = 9 UMETA(DisplayName="ParticipantUpdateEvent"), - SplitRankingUpdate = 10 UMETA(DisplayName="ParticipantUpdateEvent"), -}; - - DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnDataStorageUpdated, FString, What); +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDataStorageInit); UCLASS(BlueprintType, Category="DTFlux|Datastorage") class DTFLUXAPI_API UDTFluxDataStorage : public UObject @@ -46,7 +29,12 @@ class DTFLUXAPI_API UDTFluxDataStorage : public UObject public: - UPROPERTY(BlueprintReadOnly, Category="DTFlux|DataStorage") + UPROPERTY(BlueprintAssignable, Category="DTFlux|DataStorage|Event") + FOnDataStorageInit OnDataStorageInit; + UPROPERTY(BlueprintAssignable, Category="DTFlux|DataStorage|Event") + FOnDataStorageUpdated OnDataStorageUpdated; + + UPROPERTY(BlueprintReadOnly, Category="DTFlux|DataStorage") TArray Contests; UPROPERTY(BlueprintReadOnly, Category="DTFlux|DataStorage") int CurrentStageId = 0; @@ -70,11 +58,12 @@ public: UFUNCTION(BlueprintCallable, Category="DTFlux|DataStorage") - bool GetContest(FDTFluxContest& OutContest, const int& ContestId); + bool GetContest(const int ContestId, FDTFluxContest& OutContest); UFUNCTION(BlueprintCallable, Category="DTFlux|DataStorage") TArray GetStages(const int ContestId); UFUNCTION(BlueprintCallable, Category="DTFlux|DataStorage") - bool GetStage( FDTFluxStage& Stage,const int& StageId = -1); + bool GetStage( const int ContestId, const int StageId, FDTFluxStage& OutStage); + UFUNCTION(BlueprintCallable, Category="DTFlux|DataStorage") TArray GetParticipants(const int ContestId = -1); UFUNCTION() @@ -123,6 +112,13 @@ public: void ChangeCurrentContest(); UFUNCTION(BlueprintCallable, Category="DTFlux|DataStorage") const FString GetConcurrentFormatedName( int Bib, bool Truncate = true, int MaxSize = 20); - - + UFUNCTION() + bool GetFirstStageOfContest(const int ContestId, FDTFluxStage& Stage); + void DumpContest(); + UFUNCTION() + bool GetSplit(const int ContestID, const int StageID, const int SplitID, FDTFluxSplit& OutSplit); + UFUNCTION() + FDTFluxSplitRanking AddSplitRanking(const FDTFluxSplitSensorItemResponse& SplitSensorItem); + UFUNCTION() + EDTFluxSplitType GetSplitStatus(int ContestID, int StageID, int SplitID); }; diff --git a/Source/DTFluxAPI/Public/DTFluxModel/DTFluxModel.h b/Source/DTFluxAPI/Public/DTFluxModel/DTFluxModel.h index 7051763..7ce6f0e 100644 --- a/Source/DTFluxAPI/Public/DTFluxModel/DTFluxModel.h +++ b/Source/DTFluxAPI/Public/DTFluxModel/DTFluxModel.h @@ -144,7 +144,7 @@ public: FString Gap; UPROPERTY(BlueprintReadWrite, Category="DTFlux|Model") FString Time; - void Dump() + void Dump () const { UE_LOG(LogDTFluxAPI, Log, TEXT("FDTFluxContestRanking ->> \n \"rank\" : %d, Participant with Bib %d \"Gap\" : %s, \"Time\" : %s "), @@ -170,13 +170,21 @@ public: UPROPERTY(BlueprintReadWrite, Category="DTFlux|Model") FString TimeRun; UPROPERTY(BlueprintReadWrite, Category="DTFlux|Model") - FString TimeStart; + FDateTime TimeStart; + UPROPERTY(BlueprintReadWrite, Category="DTFlux|Model") + float SpeedRunning; + UPROPERTY(BlueprintReadWrite, Category="DTFlux|Model") + float SpeedTotal; + UPROPERTY(BlueprintReadWrite, Category="DTFlux|Model") + float SpeedSwim; + + void Dump() const { UE_LOG(LogDTFluxAPI, Log, TEXT("RANKING : %02d. Participant bib %d %s %s %s %s %s"), Rank, Bib, *Gap, *TimeSwim, - *TimeTransition, *TimeRun, *TimeStart); + *TimeTransition, *TimeRun, *TimeStart.ToString()); } }; @@ -192,12 +200,14 @@ public: UPROPERTY(BlueprintReadWrite, Category="DTFlux|Model") FString Time; UPROPERTY(BlueprintReadWrite, Category="DTFlux|Model") - int Rank; + int Rank = 0; + UPROPERTY(BlueprintReadWrite, Category="DTFlux|Model") + bool Display = false; void Dump() const { UE_LOG(LogDTFluxAPI, Log, TEXT("SplitGapItem")) // Participant.Dump(); - UE_LOG(LogDTFluxAPI, Log, TEXT("Bib %02d Gap %s"), Bib, *Gap); + UE_LOG(LogDTFluxAPI, Log, TEXT("Bib %02d Rank %02d Gap %s Time %s"), Bib, Rank, *Gap, *Time); } }; @@ -211,12 +221,12 @@ public: UPROPERTY(BlueprintReadWrite, Category="DTFlux|Model") FString Name; UPROPERTY(BlueprintReadWrite, Category="DTFlux|model") - TArray SplitGaps; + TArray SplitRankings; void Dump() const { UE_LOG(LogDTFluxAPI, Log, TEXT("Split %02d::%s *****\n"), Id, *Name); - for(const auto& SplitGapItem : SplitGaps) + for(const auto& SplitGapItem : SplitRankings) { SplitGapItem.Dump(); } @@ -227,14 +237,16 @@ public: FDTFluxSplitRanking NewSplitGapItem; NewSplitGapItem.Bib = SplitRankingItemResp.Bib; NewSplitGapItem.Gap = SplitRankingItemResp.Gap; - if(SplitGaps.IsEmpty()) + NewSplitGapItem.Rank = SplitRankingItemResp.Rank; + NewSplitGapItem.Time = SplitRankingItemResp.Time; + if(SplitRankings.IsEmpty()) { - SplitGaps.Add(NewSplitGapItem); + SplitRankings.Add(NewSplitGapItem); return; } bool Update = true; int Idx = 0; - for(auto& SplitGapItem : SplitGaps) + for(auto& SplitGapItem : SplitRankings) { if(SplitGapItem.Bib == SplitRankingItemResp.Bib) { @@ -244,13 +256,46 @@ public: } if(Update) { - if(SplitGaps.IsValidIndex(Idx)) + if(SplitRankings.IsValidIndex(Idx)) { - SplitGaps.RemoveAt(Idx); + SplitRankings.RemoveAt(Idx); } } - SplitGaps.Add(NewSplitGapItem); + SplitRankings.Add(NewSplitGapItem); }; + + void SortByRank() + { + SplitRankings.Sort([](const FDTFluxSplitRanking& A, const FDTFluxSplitRanking& B) + { + if(A.Rank == 0 && B.Rank == 0) + return true; + return A.Rank < B.Rank; + }); + } + + TArray GetSplitRanking(const int From = 0, const int DisplayNumber = 0) + { + TArray NewSplitRankings; + SortByRank(); + NewSplitRankings.Append(SplitRankings); + + if(From == 0 && DisplayNumber == 0) + return NewSplitRankings; + for(auto& SRank : SplitRankings) + { + if(SRank.Rank >= From) + { + NewSplitRankings.Add(SRank); + if(NewSplitRankings.Num() >= DisplayNumber) + { + return NewSplitRankings; + } + } + } + return NewSplitRankings; + + } }; USTRUCT(BlueprintType, Category="DTFlux|Model") @@ -267,6 +312,8 @@ public: UPROPERTY(BlueprintReadWrite, Category="DTFlux|model") FDateTime EndTime; UPROPERTY(BlueprintReadWrite, Category="DTFlux|model") + FDateTime CutOff; + UPROPERTY(BlueprintReadWrite, Category="DTFlux|model") TArray Splits; UPROPERTY(BlueprintReadWrite, Category="DTFlux|model") TArray StageRanking; @@ -288,6 +335,31 @@ public: Split.Dump(); } + } + + EDTFluxSplitType GetSplitType(int SplitID) + { + int SplitCount = Splits.Num(); + //sort by ID + Splits.Sort([](const FDTFluxSplit& A, const FDTFluxSplit& B) + { + return A.Id < B.Id; + }); + int SplitIndex = Splits.IndexOfByPredicate([SplitID](const FDTFluxSplit& Split) + { + return Split.Id == SplitID; + }); + + if(SplitCount -2 == SplitIndex ) + { + return EDTFluxSplitType::PreFinnishSplit; + } + if(SplitCount -1 == SplitIndex) + { + return EDTFluxSplitType::FinishSplit; + } + return EDTFluxSplitType::NormalSplit; + }; void SortStageRanking() { @@ -410,12 +482,9 @@ public: NewRanking.Bib, NewRanking.Rank, Id ); return true; } - else - { - ContestRanking.Add(NewRanking); - return true; - } - return false; + + ContestRanking.Add(NewRanking); + return true; } void Dump() { @@ -445,7 +514,7 @@ public: }; USTRUCT(BlueprintType, Category="FDTFlux|Model") -struct FDTFluxFinisher +struct DTFLUXAPI_API FDTFluxFinisher { GENERATED_BODY() @@ -457,9 +526,8 @@ struct FDTFluxFinisher FDTFluxStageRanking CurrentRanking; }; - USTRUCT(BlueprintType, Category="DTFlux|Subsystem|Events") -struct FDTFluxWsResponseEvent +struct DTFLUXAPI_API FDTFluxWsResponseEvent { GENERATED_BODY() @@ -468,3 +536,27 @@ struct FDTFluxWsResponseEvent UPROPERTY(BlueprintReadOnly, Category="DTFlux|Subsystem|Events") FString RawData; }; + +USTRUCT(BlueprintType, Category="DTFlux|Subsystem|Events") +struct DTFLUXAPI_API FDTFluxStageFinished +{ + GENERATED_BODY() + + UPROPERTY(BlueprintReadOnly, Category="DTFlux|Subsystem|Events") + int ContestId = 0; + UPROPERTY(BlueprintReadOnly, Category="DTFlux|Subsystem|Events") + int StageId = 0; + UPROPERTY(BlueprintReadOnly, Category="DTFlux|Subsystem|Events") + TArray Rankings; +}; + +USTRUCT(BlueprintType, Category="DTFlux|Subsystem|Events") +struct DTFLUXAPI_API FDTFluxContestFinished +{ + GENERATED_BODY() + + UPROPERTY(BlueprintReadOnly, Category="DTFlux|Subsystem|Events") + int ContestId = 0; + UPROPERTY(BlueprintReadOnly, Category="DTFlux|Subsystem|Events") + TArray Rankings; +}; diff --git a/Source/DTFluxAPI/Public/DTFluxModel/DTFluxModelResponse.h b/Source/DTFluxAPI/Public/DTFluxModel/DTFluxModelResponse.h index 1977d63..185748e 100644 --- a/Source/DTFluxAPI/Public/DTFluxModel/DTFluxModelResponse.h +++ b/Source/DTFluxAPI/Public/DTFluxModel/DTFluxModelResponse.h @@ -39,6 +39,8 @@ public: FString StartTime; UPROPERTY() FString EndTime; + UPROPERTY() + FString CutOff; }; @@ -54,7 +56,7 @@ public: UPROPERTY() FString Name; UPROPERTY() - FString Date; + FDateTime Date; UPROPERTY() TArray Stages; UPROPERTY() @@ -124,11 +126,11 @@ public: UPROPERTY(); FString TimeStart; UPROPERTY() - FString SpeedSwim; + float SpeedSwim; UPROPERTY() - FString SpeedRunning; + float SpeedRunning; UPROPERTY() - FString SpeedTotal; + float SpeedTotal; }; diff --git a/Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystem.h b/Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystem.h index 2fb8294..ec51e48 100644 --- a/Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystem.h +++ b/Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystem.h @@ -26,9 +26,12 @@ class UDTFluxProjectSettings; DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnTimerTriggered); +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnRaceDataReceived); DECLARE_DYNAMIC_DELEGATE_OneParam(FOnTimer, FString, TimerName); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWsEvent, FDTFluxWsResponseEvent, WsResponseEvent); -DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnFinisher, FDTFluxFinisher, Finisher); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnFinisher, FDTFluxSplitRanking, FinisherData); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnSpotter, FDTFluxSplitRanking, SpotterData); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnSplitSensor, FDTFluxSplitRanking, ParticipantSplitData); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnContestBegin, int, ContestId); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnStageBegin, int, ContestId, int, StageId); DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnTimesUp, int, ContestId, int, StageId); @@ -104,6 +107,10 @@ public: UPROPERTY(BlueprintAssignable, Category="DTFlux|Events") FOnWsEvent OnWsEvent; UPROPERTY(BlueprintAssignable, Category="DTFlux|Events") + FOnSplitSensor OnSplitSensor; + UPROPERTY(BlueprintAssignable, Category="DTFlux|Events") + FOnSpotter OnSpotter; + UPROPERTY(BlueprintAssignable, Category="DTFlux|Events") FOnFinisher OnFinisher; UPROPERTY(BlueprintAssignable, Category="DTFlux|Events") FOnContestBegin OnContestBegin; @@ -113,6 +120,8 @@ public: FOnTimesUp OnTimesUp; UPROPERTY(BlueprintAssignable, Category="DTFlux|Events") FOnRestTimeBegin FOnRestTimeBegin; + UPROPERTY(BlueprintAssignable, Category="DTFlux|Events") + FOnRaceDataReceived OnRaceDataReceived; // UPROPERTY(BlueprintReadWrite, Category="DTFlux|Subsystem|Websocket") // int ReconnectTimeout = 60; //seconds @@ -172,14 +181,5 @@ public: UFUNCTION(BlueprintCallable, Category="DTFlux|subsystem") bool IsConnected() const; - - - FTimerHandle TestTimerHandle; - - - void TestTimers() - { - UE_LOG(LogDTFluxAPI, Log, TEXT("IT WORKS !!!!")); - } }; diff --git a/Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystemTimer.h b/Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystemTimer.h new file mode 100644 index 0000000..725d5b8 --- /dev/null +++ b/Source/DTFluxAPI/Public/DTFluxSubsystem/DTFluxSubsystemTimer.h @@ -0,0 +1,84 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "DTFluxUtils/DTFluxEnums.h" +#include "Subsystems/WorldSubsystem.h" +#include "DTFluxSubsystemTimer.generated.h" + +/** + * + */ + +class UDTFluxDataStorage; +class UDTFluxSubsystem; + +USTRUCT() +struct FDTFluxContestTimerHandle +{ + GENERATED_BODY() + +public: + + UPROPERTY() + int ContestId; + UPROPERTY() + int StageId; + UPROPERTY(); + TEnumAsByte Type; + UPROPERTY(); + FTimerHandle Handle; +}; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnCutoff, int, ContestId, int, StageId); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnStageStarted, int, ContestId, int, StageId); + + +UCLASS(BlueprintType, Category="DTFlux|Timer") +class DTFLUXAPI_API UDTFluxSubsystemTimer : public UTickableWorldSubsystem +{ + GENERATED_BODY() +public: + /** Implement this for initialization of instances of the system */ + virtual void Initialize(FSubsystemCollectionBase& Collection) override; + + /** Implement this for deinitialization of instances of the system */ + virtual void Deinitialize() override; + + virtual void Tick(float DeltaTime) override; + + virtual TStatId GetStatId() const override + { + RETURN_QUICK_DECLARE_CYCLE_STAT(UDTFluxSubsystemTimer, STATGROUP_Tickables); + } + + UPROPERTY() + TArray Timers; + + + UPROPERTY(BlueprintAssignable, Category="DTFlux|Timer") + FOnCutoff OnCutoff; + + UPROPERTY(BlueprintAssignable, Category="DTFlux|Timer") + FOnStageStarted OnStageStarted; + + UFUNCTION() + void OnDataStorageInit(); + + void AddCutoffTimer(const int ContestID, const int StageID); + void AddStageStartedTimer(const int ContestID, const int StageID); + + void OnStartTimer(); + void OnCutOffTimer(); + + void ClearTimer(FDTFluxContestTimerHandle TimerHandle); + void ClearTimer(const int HandleIndex); + + static UDTFluxSubsystem* GetDTFluxSubSystem(); + static UDTFluxDataStorage* GetDTFluxDataStorage(); + + static float GetSecondsFrom(const FDateTime When); +}; + + diff --git a/Source/DTFluxAPI/Public/DTFluxUtils/DTFluxEnums.h b/Source/DTFluxAPI/Public/DTFluxUtils/DTFluxEnums.h index f9e1368..eca4f74 100644 --- a/Source/DTFluxAPI/Public/DTFluxUtils/DTFluxEnums.h +++ b/Source/DTFluxAPI/Public/DTFluxUtils/DTFluxEnums.h @@ -52,4 +52,51 @@ enum EDTFluxResponseType: uint8 WsConnected = 9 UMETA(DisplayName="WsConnected"), WsClosed = 10 UMETA(DisplayName="WsClosed"), WsError = 11 UMETA(DisplayName="WsError"), -}; \ No newline at end of file +}; + +UENUM(BlueprintType, Category="DTFlux|Subsystem") +enum EDTFluxSplitType : uint8 +{ + UnknownSplitType = 0 UMETA(DisplayName="UnknownSplitType"), + NormalSplit = 1 UMETA(DisplayName="NormalSplit"), + PreFinnishSplit = 2 UMETA(DisplayName="PreFinnishSplit"), + FinishSplit = 3 UMETA(DisplayName="FinishSplit"), +}; + + +UENUM(BlueprintType, Category="DTFlux|DataStorage") +// ReSharper disable once IdentifierTypo +enum EDTFluxDataStorageEventType : uint8 +{ + UnknownEvent = 0 UMETA(DisplayName="ParticipantUpdateEvent"), + ParticipantCreateEvent = 1 UMETA(DisplayName="ParticipantUpdateEvent"), + ParticipantUpdateEvent = 2 UMETA(DisplayName="ParticipantUpdateEvent"), + ParticipantDeleteEvent = 3 UMETA(DisplayName="ParticipantDeleteEvent"), + ParticipantStatusUpdateEvent = 4 UMETA(DisplayName="ParticipantUpdateEvent"), + RaceDataCreateEvent = 5 UMETA(DisplayName="RaceDataCreateEvent"), + RaceDataUpdateEvent = 6 UMETA(DisplayName="RaceDataUpdateEvent"), + RaceDataDeleteEvent = 7 UMETA(DisplayName="RaceDataDeleteEvent"), + ContestRankingUpdate = 8 UMETA(DisplayName="ContestRankingUpdate"), + StageRankingUpdate = 9 UMETA(DisplayName="StageRankingUpdate"), + SplitRankingUpdate = 10 UMETA(DisplayName="SplitRankingUpdate"), +}; + + +UENUM() +enum EDTFluxTimerEventType : uint8 +{ + StageStart = 0 UMETA(DisplayName="StageStart"), + StageCutOff = 1 UMETA(DisplayName="StageCutOff"), + +}; + +UENUM() +enum EDTFluxStageStatusType : uint8 +{ + UnknownStatus = 0 UMETA(DisplayName="UnknownStatus"), + StageWaiting = 1 UMETA(DisplayName="StageWaiting"), + StageStarted = 2 UMETA(DisplayName="StageStarted"), + StageEnded = 3 UMETA(DisplayName="StageCutOff") +}; + + diff --git a/Source/DTFluxAPI/Public/DTFluxUtils/DTFluxUtils.h b/Source/DTFluxAPI/Public/DTFluxUtils/DTFluxUtils.h index 7876a1f..aa9cde9 100644 --- a/Source/DTFluxAPI/Public/DTFluxUtils/DTFluxUtils.h +++ b/Source/DTFluxAPI/Public/DTFluxUtils/DTFluxUtils.h @@ -4,6 +4,7 @@ #include "CoreMinimal.h" #include "DTFluxModel/DTFluxModel.h" +#include "DTFluxSubsystem/DTFluxSubsystem.h" #include "UObject/Object.h" #include "DTFluxUtils.generated.h" @@ -21,4 +22,101 @@ public: { return Participant.Person2.FirstName != ""; } + + UFUNCTION(BlueprintCallable, Category="DTFlux|Model|Helpers") + static TArray GetSplitRanking(const int ContestId, const int StageId, + const int SplitId, const int From = 0, const int DisplayNumber = 0) + { + TArray SplitRankings; + UDTFluxSubsystem* Subsystem = GEngine->GetEngineSubsystem(); + TArray Contests = Subsystem->GetDataStorage()->Contests; + for( auto& Contest : Contests) + { + if(Contest.Id == ContestId) + { + for( auto& Stage : Contest.Stages) + { + if(Stage.Id == StageId) + { + for( auto& Split : Stage.Splits) + { + if(Split.Id == SplitId) + { + Split.SortByRank(); + return Split.GetSplitRanking(From, DisplayNumber); + } + } + } + } + } + } + return SplitRankings; + + } + + UFUNCTION(BlueprintCallable, Category="DTFlux|Model|Helpers") + static TArray GetStageRanking(const int ContestId, const int StageId, const int From = 0, const int DisplayNumber = 0) + { + TArray StageRankings; + UDTFluxSubsystem* Subsystem = GEngine->GetEngineSubsystem(); + TArray Contests = Subsystem->GetDataStorage()->Contests; + for( auto& Contest : Contests) + { + if(Contest.Id == ContestId) + { + for( auto& Stage : Contest.Stages) + { + if(Stage.Id == StageId) + { + StageRankings = Stage.StageRanking; + } + } + } + } + //CAREFUL Can Be Empty + return StageRankings; + } + + UFUNCTION(BlueprintCallable, Category="DTFlux|Model|Helpers") + static TArray GetContestRanking(const int ContestId, const int StageId, const int From = 0, const int DisplayNumber = 0) + { + TArray ContestRankings; + UDTFluxSubsystem* Subsystem = GEngine->GetEngineSubsystem(); + TArray Contests = Subsystem->GetDataStorage()->Contests; + for( auto& Contest : Contests) + { + if(Contest.Id == ContestId) + { + ContestRankings = Contest.ContestRanking; + } + } + //CAREFUL Can Be Empty + return ContestRankings; + } + + UFUNCTION(BlueprintCallable, Category="DTFlux|Model|Helpers") + static bool GetParticipant(const int Bib, FDTFluxParticipant& Participant) + { + UDTFluxSubsystem* Subsystem= GEngine->GetEngineSubsystem(); + UDTFluxDataStorage* DataStorage = Subsystem->GetDataStorage(); + + return DataStorage->GetParticipantByBib(Bib, Participant); + + } + + UFUNCTION(BlueprintCallable, Category="DTFlux|Model|Helpers") + static FString GetParticipantString(const int Bib, bool Truncate = true, int MaxSize = 20) + { + FString ParticipantStr = ""; + FDTFluxParticipant Participant; + if(UDTFluxModelHelper::GetParticipant(Bib, Participant)) + { + ParticipantStr = Participant.GetParticipantFormatedName(Truncate, MaxSize); + } + return ParticipantStr; + } + + UFUNCTION(BlueprintCallable, Category="DTFlux|Model|Helpers") + static EDTFluxStageStatusType GetStatusType(const int ContestID, const int StageID, UDTFluxDataStorage* DataStorage); + };