Added Subsystem Timer

This commit is contained in:
2024-07-16 17:03:33 +02:00
parent 2d2b3015bc
commit f1b7834743
13 changed files with 823 additions and 205 deletions

View File

@ -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<UDTFluxSubsystem>()->GetDataStorage();
UE_LOG(LogDTFluxAPI, Log, TEXT("DTFluxApi loaded"))
}else
{
UE_LOG(LogDTFluxAPI, Error, TEXT("DTFluxApi Not Loaded"))
}
// ...
}

View File

@ -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)
{
FDateTime Now = FDateTime::Now();
// UE_LOG(LogDTFluxAPI, Warning, TEXT("RequestedContest %d"),
// ContestId);
for(auto& Contest : Contests)
{
for( auto& Stage : Contest.Stages)
{
if(Stage.StartTime >= Now && Stage.EndTime <= Now)
{
//We have a winner
OutContest = Contest;
return true;
}
}
}
}
else
{
for( auto& Contest : Contests)
{
// UE_LOG(LogDTFluxAPI, Warning, TEXT("Checking Contest %d"),
// Contest.Id);
if(Contest.Id == ContestId)
{
// 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(FDTFluxStage& CurrentStage, const int& StageId)
bool UDTFluxDataStorage::GetStage(const int ContestId, const int StageId, FDTFluxStage& OutStage)
{
// Current contest requested
if(StageId == -1)
FDTFluxContest Contest;
// UE_LOG(LogDTFluxAPI, Warning, TEXT("RequestedStage %d in Contest%02d ****"),
// ContestId, StageId);
if(GetContest(ContestId, Contest))
{
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
for(auto & Stage: Contest.Stages)
{
// UE_LOG(LogDTFluxAPI, Warning, TEXT("Checking Stage %d "),
// Stage.Id);
if(Stage.Id == StageId)
{
//We have a winner for the search stage
CurrentStage = Stage;
// UE_LOG(LogDTFluxAPI, Warning, TEXT("Found %s in Stage ***"),
// *Stage.Name);
OutStage = Stage;
return true;
}
}
}
// 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& Split: Stage.Splits)
{
if(Split.Id == SplitId)
{
// UE_LOG(LogDTFluxAPI, Warning, TEXT("Get Split %s in Stage%02d of Contest%02d"),
// *Split.Name, StageId, SplitId);
OutSplit = Split;
return true;
}
}
}
return false;
}
FDTFluxSplitRanking UDTFluxDataStorage::AddSplitRanking(const FDTFluxSplitSensorItemResponse& SplitSensorItem)
{
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))
{
Split.SplitRankings.Add(NewSplitRanking);
return NewSplitRanking;
}
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<FDTFluxParticipant> UDTFluxDataStorage::GetParticipants(const int ContestId)
{
TArray<FDTFluxParticipant> 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<FDTFluxSplit> 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();
}
}
}

View File

@ -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<FWorldContext> 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);
}
}

View File

@ -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<UDTFluxSubsystem>();
}
UDTFluxDataStorage* UDTFluxSubsystemTimer::GetDTFluxDataStorage()
{
return GetDTFluxSubSystem()->GetDataStorage();
}
float UDTFluxSubsystemTimer::GetSecondsFrom(const FDateTime When)
{
FTimespan Delta = When - FDateTime::Now();
return static_cast<float>(Delta.GetTotalSeconds()) ;
}

View File

@ -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;
}

View File

@ -5,6 +5,7 @@
#include "CoreMinimal.h"
#include "AvaText3DComponent.h"
#include "Components/ActorComponent.h"
#include "DTFluxDataStorage/DTFluxDataStorage.h"
#include "DTFluxCountDownComponent.generated.h"
@ -35,6 +36,7 @@ protected:
int64 InternalDuration;
bool IsWaiting;
bool IsCounting;
UDTFluxDataStorage* DataStorage;
@ -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);

View File

@ -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,6 +29,11 @@ class DTFLUXAPI_API UDTFluxDataStorage : public UObject
public:
UPROPERTY(BlueprintAssignable, Category="DTFlux|DataStorage|Event")
FOnDataStorageInit OnDataStorageInit;
UPROPERTY(BlueprintAssignable, Category="DTFlux|DataStorage|Event")
FOnDataStorageUpdated OnDataStorageUpdated;
UPROPERTY(BlueprintReadOnly, Category="DTFlux|DataStorage")
TArray<FDTFluxContest> Contests;
UPROPERTY(BlueprintReadOnly, Category="DTFlux|DataStorage")
@ -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<FDTFluxStage> 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<FDTFluxParticipant> 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);
};

View File

@ -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<FDTFluxSplitRanking> SplitGaps;
TArray<FDTFluxSplitRanking> 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<FDTFluxSplitRanking> GetSplitRanking(const int From = 0, const int DisplayNumber = 0)
{
TArray<FDTFluxSplitRanking> 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<FDTFluxSplit> Splits;
UPROPERTY(BlueprintReadWrite, Category="DTFlux|model")
TArray<FDTFluxStageRanking> 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,13 +482,10 @@ public:
NewRanking.Bib, NewRanking.Rank, Id );
return true;
}
else
{
ContestRanking.Add(NewRanking);
return true;
}
return false;
}
void Dump()
{
UE_LOG(LogDTFluxAPI, Log, TEXT("CONTEST DUMP BEGIN *****%s::%02d *****\n"), *Name, Id);
@ -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<FDTFluxStageRanking> 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<FDTFluxStageRanking> Rankings;
};

View File

@ -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<FStageResponse> 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;
};

View File

@ -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 !!!!"));
}
};

View File

@ -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<EDTFluxTimerEventType> 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<FDTFluxContestTimerHandle> 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);
};

View File

@ -53,3 +53,50 @@ enum EDTFluxResponseType: uint8
WsClosed = 10 UMETA(DisplayName="WsClosed"),
WsError = 11 UMETA(DisplayName="WsError"),
};
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")
};

View File

@ -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<FDTFluxSplitRanking> GetSplitRanking(const int ContestId, const int StageId,
const int SplitId, const int From = 0, const int DisplayNumber = 0)
{
TArray<FDTFluxSplitRanking> SplitRankings;
UDTFluxSubsystem* Subsystem = GEngine->GetEngineSubsystem<UDTFluxSubsystem>();
TArray<FDTFluxContest> 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<FDTFluxStageRanking> GetStageRanking(const int ContestId, const int StageId, const int From = 0, const int DisplayNumber = 0)
{
TArray<FDTFluxStageRanking> StageRankings;
UDTFluxSubsystem* Subsystem = GEngine->GetEngineSubsystem<UDTFluxSubsystem>();
TArray<FDTFluxContest> 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<FDTFluxContestRanking> GetContestRanking(const int ContestId, const int StageId, const int From = 0, const int DisplayNumber = 0)
{
TArray<FDTFluxContestRanking> ContestRankings;
UDTFluxSubsystem* Subsystem = GEngine->GetEngineSubsystem<UDTFluxSubsystem>();
TArray<FDTFluxContest> 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<UDTFluxSubsystem>();
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);
};