Added Pursuit functionality (Untested and not fully implemented) + Global TrackedRequestSending check

This commit is contained in:
2025-07-09 03:27:23 +02:00
parent 8f884f6224
commit 03eb1132ef
22 changed files with 636 additions and 294 deletions

View File

@ -6,6 +6,7 @@
#include "DTFluxCoreSubsystemModule.h"
#include "DTFluxGeneralSettings.h"
#include "DTFluxPursuitManager.h"
#include "FileHelpers.h"
#include "Assets/DTFluxModelAsset.h"
#include "Subsystems/DTFluxNetworkSubsystem.h"
@ -31,6 +32,7 @@ void UDTFluxCoreSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
RegisterDelegates();
}
PursuitManager = NewObject<UDTFluxPursuitManager>();
}
void UDTFluxCoreSubsystem::Deinitialize()
@ -345,3 +347,22 @@ TArray<FDTFluxContest> UDTFluxCoreSubsystem::GetContests()
}
return TArray<FDTFluxContest>();
}
void UDTFluxCoreSubsystem::LaunchPursuitSequenceFor(const TArray<int> ContestIds)
{
TArray<FDTFluxContest> Contests = TArray<FDTFluxContest>();
for (const auto& ContestId : ContestIds)
{
FDTFluxContest Contest;
GetContestForId(ContestId, Contest);
Contests.Add(Contest);
if (PursuitManager)
{
PursuitManager->LaunchPursuitSequenceFor(Contests);
}
else
{
UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("PursuitManager is null"));
}
}
}

View File

@ -0,0 +1,152 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "DTFluxPursuitManager.h"
#include "DTFluxCoreSubsystemModule.h"
UDTFluxPursuitManager::UDTFluxPursuitManager(const FObjectInitializer& ObjectInitializer):
Super(ObjectInitializer)
{
}
// TODO : Add way to pass MaxSimultaneousPursuit and MassStartDelay
// For now it's done in UPROPERTIES
void UDTFluxPursuitManager::LaunchPursuitSequenceFor(const TArray<FDTFluxContest> InContests)
{
if (InitSubSystems())
{
for (const auto Contest : InContests)
{
FRequestData RequestData;
RequestData.ContestId = Contest.ContestId;
uint8 StageId = Contest.Stages.Last().StageId;
FGuid Guid = NetworkSubsystem->SendTrackedRequestWithCallback(EDTFluxApiDataType::StageRanking,
Contest.ContestId, StageId, -1,
FOnDTFluxTrackedRequestResponse::CreateUObject(
this,
&UDTFluxPursuitManager::OnRequestResponse),
FOnDTFluxTrackedRequestTimeout::CreateUObject(
this,
&UDTFluxPursuitManager::OnRequestTimeoutResponse),
FOnDTFluxRequestResponseError::CreateUObject(
this,
&UDTFluxPursuitManager::OnRequestError));
RequestData.RequestIds.Add(Guid);
PendingRequestData.Add(RequestData);
}
}
}
void UDTFluxPursuitManager::OnRequestResponse(const FGuid& RequestId, FDTFluxServerResponse& Response)
{
UE_LOG(logDTFluxCoreSubsystem, Log,
TEXT("UDTFluxPursuitManager::OnRequestResponse() Received Ranking For Stage %i"), Response.StageID)
UE_LOG(logDTFluxCoreSubsystem, Log, TEXT("Response is %s"), *UEnum::GetValueAsString(Response.GetResponseType()))
//check if request
if (Response.GetResponseType() == EDTFluxApiDataType::StageRanking)
{
FDTFluxStageRankings Rankings;
FRequestData FoundData;
if (Response.ParseStageRankingResponse(Rankings))
{
for (auto& PendingReq : PendingRequestData)
{
// Check for a matching PendingReq
if (PendingReq.IsWaitingFor(RequestId, Rankings))
{
FoundData = PendingReq;
// A request Is Terminated
UE_LOG(logDTFluxCoreSubsystem, Log,
TEXT("UDTFluxPursuitManager::OnRequestResponse() Ranking for Stage %i is complete"),
Response.StageID)
break;
}
}
if (InitPursuit(FoundData))
{
OnPursuitSequenceReady.Broadcast(NextFocusPursuits, NextFocusPursuits, bFocusIsTruncate);
}
}
}
}
void UDTFluxPursuitManager::OnRequestTimeoutResponse(const FGuid& RequestId, const FString& TimeoutMessage)
{
UE_LOG(logDTFluxCoreSubsystem, Warning, TEXT("Request Timeout [%s]"), *TimeoutMessage);
}
void UDTFluxPursuitManager::OnRequestError(const FGuid& RequestId, const FString& ErrorMessage)
{
UE_LOG(logDTFluxCoreSubsystem, Error, TEXT("Request Error [%s]"), *ErrorMessage);
}
bool UDTFluxPursuitManager::InitSubSystems()
{
if (NetworkSubsystem)
{
return true;
}
NetworkSubsystem = GEngine->GetEngineSubsystem<UDTFluxNetworkSubsystem>();
return NetworkSubsystem != nullptr;
}
bool UDTFluxPursuitManager::InitPursuit(FRequestData Data)
{
//Clean Data
NextFocusPursuits.Empty();
NextPursuits.Empty();
PursuitGrouped.Empty();
TArray<FDTFluxDetailedRankingItem> AllRankings;
TArray<FDTFluxPursuitInfo> AllPursuits;
TMap<FDateTime, FDTFluxPursuitGroup> TempGroups;
// Full the Array Of Rankings
for (auto& KeyPair : Data.StageRankings)
{
for (auto StageRanking : KeyPair.Value.Rankings)
{
int ContestId = KeyPair.Value.ContestId;
FDTFluxPursuitInfo PursuitInfo;
PursuitInfo.StartTime = StageRanking.StartTime;
PursuitInfo.Bib = StageRanking.Bib;
PursuitInfo.ContestId = ContestId;
AllPursuits.Add(PursuitInfo);
}
}
// Sort Rankings
// AllPursuits.Sort([](const FDTFluxPursuitInfo& A, const FDTFluxPursuitInfo& B) {
// return A.StartTime < B.StartTime;
// });
for (auto& Pursuit : AllPursuits)
{
if (TempGroups.Contains(Pursuit.StartTime))
{
TempGroups[Pursuit.StartTime].PursuitGroup.Add(Pursuit);
}
else
{
FDTFluxPursuitGroup Group;
Group.StartTimeGlobal = Pursuit.StartTime;
Group.PursuitGroup.Add(Pursuit);
TempGroups.Add(Pursuit.StartTime, Group);
}
}
TempGroups.KeySort([](const FDateTime& A, const FDateTime& B)
{
return A < B;
});
PursuitGrouped.Reserve(TempGroups.Num());
for (const auto& Pair : TempGroups)
{
PursuitGrouped.Add(Pair.Value);
}
PursuitGrouped.Sort([](const FDTFluxPursuitGroup& A, const FDTFluxPursuitGroup& B)
{
return A.StartTimeGlobal < B.StartTimeGlobal;
});
return true;
}

View File

@ -1,6 +1,4 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#pragma once
#include "CoreMinimal.h"
#include "Containers/Deque.h"
@ -15,6 +13,7 @@
class UDTFluxNetworkSubsystem;
/** Forward Decl */
class UDTFluxModelAsset;
class UDTFluxPursuitManager;
/**
*
@ -107,12 +106,18 @@ public:
UFUNCTION()
TArray<FDTFluxContest> GetContests();
UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem")
void LaunchPursuitSequenceFor(const TArray<int> ContestIds);
protected:
// ~Subsystem Interface
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
// ~Subsystem Interface
UPROPERTY()
UDTFluxPursuitManager* PursuitManager = nullptr;
UFUNCTION()
void SaveDataStorage();

View File

@ -0,0 +1,133 @@
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/DTFluxNetworkSubsystem.h"
#include "Types/Struct/DTFluxRaceDataStructs.h"
#include "Types/Struct/FDTFluxPursuitInfo.h"
#include "UObject/Object.h"
#include "DTFluxPursuitManager.generated.h"
USTRUCT()
struct FRequestData
{
GENERATED_BODY()
UPROPERTY()
TArray<FGuid> RequestIds;
UPROPERTY()
TMap<FGuid, FDTFluxStageRankings> StageRankings;
UPROPERTY()
int ContestId;
UPROPERTY()
bool bIsReady = false;
FRequestData() = default;
FRequestData(const TArray<FGuid>& InRequestIds, const TMap<FGuid, FDTFluxStageRankings>& InStageRankings)
: RequestIds(InRequestIds), StageRankings(InStageRankings)
{
};
/**
*
* @param RequestId
* @param InRankings
* @return True if all needed requests have responses
*/
bool IsWaitingFor(const FGuid& RequestId, const FDTFluxStageRankings& InRankings)
{
if (!StageRankings.Contains(RequestId))
{
StageRankings.Add(RequestId, InRankings);
}
bIsReady = StageRankings.Num() <= RequestIds.Num();
return bIsReady;
}
};
USTRUCT()
struct FDTFluxPursuitGroup
{
GENERATED_BODY()
UPROPERTY()
TArray<FDTFluxPursuitInfo> PursuitGroup = TArray<FDTFluxPursuitInfo>();
UPROPERTY()
FDateTime StartTimeGlobal = FDateTime::MinValue();
UPROPERTY()
bool bHasStarted = false;
UPROPERTY()
bool bIsFocus = false;
};
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnPursuitSequenceReady, const TArray<FDTFluxPursuitInfo>,
NextFocusPursuits,
const TArray<FDTFluxPursuitInfo>, NextPursuit, bool, bIsTrtuncate);
/**
*
*/
UCLASS(BlueprintType)
class DTFLUXCORESUBSYSTEM_API UDTFluxPursuitManager : public UObject
{
GENERATED_BODY()
public:
UDTFluxPursuitManager(const FObjectInitializer& ObjectInitializer);
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
TArray<FDTFluxPursuitInfo> NextFocusPursuits;
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
TArray<FDTFluxPursuitInfo> NextPursuits;
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
bool bFocusIsTruncate = false;
//
// UPROPERTY()
// TArray<FDTFluxStage> TargetStages;
UPROPERTY()
int MaxSimultaneousPursuit = 7;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="DTFlux|Pursuit",
meta=(ClampMin="1", ClampMax="60", UIMin="0", UIMax="60"))
int MassStartDelay = 10;
UPROPERTY()
TArray<FDTFluxPursuitGroup> PursuitGrouped;
UPROPERTY()
int CurrentIndex = -1;
UPROPERTY(BlueprintCallable, Category="DTFlux|Pursuit")
FOnPursuitSequenceReady OnPursuitSequenceReady;
UFUNCTION(BlueprintCallable, Category="DTFlux|Pursuit", meta=(Keywords="pursuit, launch, poursuite"))
void LaunchPursuitSequenceFor(const TArray<FDTFluxContest> InContests);
UFUNCTION()
void OnRequestResponse(const FGuid& RequestId, FDTFluxServerResponse& Response);
UFUNCTION()
void OnRequestTimeoutResponse(const FGuid& RequestId, const FString& TimeoutMessage);
UFUNCTION()
void OnRequestError(const FGuid& RequestId, const FString& ErrorMessage);
UFUNCTION()
bool InitSubSystems();
private:
TArray<FRequestData> PendingRequestData;
public:
UFUNCTION()
bool InitPursuit(FRequestData Data);
private:
UDTFluxNetworkSubsystem* NetworkSubsystem = nullptr;
};