Adds Custom DataAsset UI + Added Request buttons for RaceDatas/TeamList/Rankings request to ApiStatus Tab + Addes Tracked Requests For Rankings + Added Utils Module For Blueprint Utilities Functions

This commit is contained in:
2025-07-08 16:50:31 +02:00
parent 7e1ce2cdfa
commit b63f2dd7b5
40 changed files with 4027 additions and 1199 deletions

View File

@ -3,6 +3,7 @@
#pragma once
#include "CoreMinimal.h"
#include "DTFluxQueuedManager.h"
#include "Struct/DTFluxServerResponseStruct.h"
#include "Subsystems/EngineSubsystem.h"
#include "Types/DTFluxNetworkSettingsTypes.h"
@ -14,12 +15,24 @@
#include "DTFluxNetworkSubsystem.generated.h"
class FDTFluxWebSocketClient;
class UDTFluxQueuedManager;
typedef TSharedPtr<FDTFluxWebSocketClient> FDTFluxWebSocketClientSP;
class FDTFluxHttpClient;
typedef TSharedPtr<FDTFluxHttpClient> FDTFluxHttpClientSP;
// Delegates pour les requêtes avec callback
DECLARE_DELEGATE_TwoParams(FOnDTFluxRequestResponse, const FGuid&, const FString&);
DECLARE_DELEGATE_TwoParams(FOnDTFluxRequestTimeout, const FGuid&, const FString&);
// Delegates Blueprint pour les requêtes avec tracking
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnDTFluxTrackedRequestCompleted, const FGuid&, RequestId,
EDTFluxApiDataType, RequestType, const FString&, ResponseData);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnDTFluxTrackedRequestFailed, const FGuid&, RequestId,
EDTFluxApiDataType, RequestType, const FString&, ErrorMessage);
/**
*
*/
@ -27,25 +40,28 @@ UCLASS(Blueprintable)
class DTFLUXNETWORK_API UDTFluxNetworkSubsystem : public UEngineSubsystem
{
GENERATED_BODY()
public:
public:
UPROPERTY()
EDTFluxConnectionStatus WsStatus = EDTFluxConnectionStatus::Unset;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnWebSocketConnected);
UPROPERTY(BlueprintAssignable, Category="DTFlux|Network")
FOnWebSocketConnected OnWebSocketConnected;
DECLARE_DELEGATE_OneParam(FOnRaceDataReceived, const FDTFluxRaceData& /*RaceDataDefinition*/);
FOnRaceDataReceived OnRaceDataReceived;
FOnRaceDataReceived& OnReceivedRaceData()
{
return OnRaceDataReceived;
};
// === DELEGATES POUR LES DONNÉES REÇUES (PUSH) ===
DECLARE_DELEGATE_OneParam(FOnTeamListReceived, const FDTFluxTeamListDefinition& /*TeamListDefinition*/);
FOnTeamListReceived OnTeamListReceived;
FOnTeamListReceived& OnReceivedTeamList()
{
return OnTeamListReceived;
@ -53,32 +69,40 @@ public:
DECLARE_DELEGATE_OneParam(FOnStageRankingReceived, const FDTFluxStageRankings& /*StageRankings*/);
FOnStageRankingReceived OnStageRankingReceived;
FOnStageRankingReceived& OnReceivedStageRanking()
{
return OnStageRankingReceived;
}
DECLARE_DELEGATE_OneParam(FOnSplitRankingReceived, const FDTFluxSplitRankings& /*SplitRankings*/);
FOnSplitRankingReceived OnSplitRankingReceived;
FOnSplitRankingReceived& OnReceivedSplitRanking()
{
return OnSplitRankingReceived;
}
DECLARE_DELEGATE_OneParam(FOnContestRankingReceived, const FDTFluxContestRankings& /*ContestRankings*/);
FOnContestRankingReceived OnContestRankingReceived;
FOnContestRankingReceived& OnReceivedContestRanking()
{
return OnContestRankingReceived;
};
// === DELEGATES POUR LES DONNÉES REÇUES (PULL) ===
DECLARE_DELEGATE_OneParam(FOnSplitSensorReceived, const FDTFluxSplitSensorInfo& /*ContestRankings*/);
FOnSplitSensorReceived OnSplitSensorReceived;
FOnSplitSensorReceived& OnReceivedSplitSensor()
{
return OnSplitSensorReceived;
};
DECLARE_DELEGATE_OneParam(FOnTeamUpdateReceived, const FDTFluxParticipant& /*ParticipantToUpdate*/);
DECLARE_DELEGATE_OneParam(FOnTeamUpdateReceived, const FDTFluxTeamListDefinition& /*ParticipantToUpdate*/);
FOnTeamUpdateReceived OnTeamUpdateReceived;
FOnTeamUpdateReceived& OnReceivedTeamUpdate()
{
return OnTeamUpdateReceived;
@ -86,6 +110,7 @@ public:
DECLARE_DELEGATE_OneParam(FOnTeamStatusUpdateReceived, const FDTFluxTeamStatusUpdate& /*TeamToUpdate*/);
FOnTeamStatusUpdateReceived OnTeamStatusUpdateReceived;
FOnTeamStatusUpdateReceived& OnReceivedTeamStatusUpdate()
{
return OnTeamStatusUpdateReceived;
@ -99,13 +124,41 @@ public:
void Reconnect();
// === REQUÊTES AVEC QUEUE ET TRACKING ===
UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests")
FGuid SendTrackedRequest(EDTFluxApiDataType RequestType, int32 ContestId = -1, int32 StageId = -1,
int32 SplitId = -1, float TimeoutSeconds = 30.0f);
FGuid SendTrackedRequestWithCallback(EDTFluxApiDataType RequestType, int32 ContestId, int32 StageId, int32 SplitId,
FOnDTFluxRequestResponse OnCompleted, FOnDTFluxRequestTimeout OnTimeout,
float TimeoutSeconds = 30.0f);
UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests")
bool GetTrackedRequest(const FGuid& RequestId, FDTFluxQueuedRequest& OutRequest) const;
const FDTFluxQueuedRequest* GetTrackedRequestPtr(const FGuid& RequestId) const;
UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests", CallInEditor)
bool HasRequestReceivedResponse(const FGuid& RequestId) const;
UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests")
FString GetRequestResponseData(const FGuid& RequestId) const;
UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests")
bool IsRequestPending(EDTFluxApiDataType RequestType, int32 ContestId = -1, int32 StageId = -1,
int32 SplitId = -1) const;
UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests")
int32 GetPendingRequestCount() const;
UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests")
UDTFluxQueuedManager* GetQueueManager() const;
// === EVENTS BLUEPRINT POUR LE TRACKING ===
UPROPERTY(BlueprintAssignable, Category="DTFlux|Tracked Requests")
FOnDTFluxTrackedRequestCompleted OnTrackedRequestCompleted;
UPROPERTY(BlueprintAssignable, Category="DTFlux|Tracked Requests")
FOnDTFluxTrackedRequestFailed OnTrackedRequestFailed;
UFUNCTION(BlueprintCallable, Category="DTFlux|Core Subsystem")
void SendRequest(const EDTFluxRequestType RequestType, int InContestId = -1, int InStageId = -1, int InSplitId = -1);
UFUNCTION(BlueprintCallable, Category="DTFlux|Network")
// === REQUÊTES DIRECTES (LEGACY) ===
void SendRequest(const EDTFluxApiDataType RequestType, int InContestId = -1, int InStageId = -1,
int InSplitId = -1);
UFUNCTION(BlueprintCallable, Category="DTFlux|Network")
void SendMessage(const FString& Message);
protected:
// ~Subsystem Interface
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
@ -114,9 +167,22 @@ protected:
private:
// === CONFIGURATION ===
FDTFluxWsSettings WsSettings;
FDTFluxHttpSettings HttpSettings;
UPROPERTY()
UDTFluxQueuedManager* QueueManager;
// === MAPPING DES CALLBACKS C++ ===
TMap<FGuid, FOnDTFluxRequestResponse> PendingCallbacks;
TMap<FGuid, FOnDTFluxRequestTimeout> PendingTimeoutCallbacks;
// === CLIENTS RÉSEAU ===
FDTFluxWebSocketClientSP WsClient = nullptr;
FDTFluxHttpClientSP HttpClient = nullptr;
// === MÉTHODES DE CONFIGURATION ===
UFUNCTION()
void WsSettingsChanged(const FDTFluxWsSettings& NewWsSettings);
UFUNCTION()
@ -124,40 +190,46 @@ private:
void ReconnectWs(const FName WsClientId);
void ReconnectHttp(const FName WsClientId);
// === GESTION DES ÉVÉNEMENTS WEBSOCKET ===
void RegisterWebSocketEvents();
void RegisterHttpEvents();
void UnregisterWebSocketEvents();
void UnregisterHttpEvents();
void OnWebSocketConnected_Subsystem();
void OnWebSocketConnectionError_Subsystem(const FString& Error);
void OnWebSocketClosedEvent_Subsystem(int32 StatusCode , const FString& Reason, bool bWasClean);
void ParseTeamListResponse(const FDTFluxServerResponse& ServerResponse);
void ParseRaceData(const FDTFluxServerResponse& Response);
void ParseContestRanking(const FDTFluxServerResponse& Response);
void ParseStageRankingResponse(const FDTFluxServerResponse& Response);
void ParseSplitRankingResponse(const FDTFluxServerResponse& Response);
void ParseStatusUpdateResponse(const FDTFluxServerResponse& Response);
void ParseSplitSensorResponse(const FDTFluxServerResponse& Response);
void OnWebSocketMessageEvent_Subsystem(const FString& MessageString);
void OnWebSocketMessageSentEvent_Subsystem(const FString& MessageSent);
// TODO : Allow multiple instances of network clients.
// // For Future use of Multi-Connections
// TArray<FDTFluxWebSocketClientSP> WsClients;
// // For Future use of Multi-Connections
// TArray<FDTFluxHttpClientSP> HttpClient;
// Fo now we jest stick to only one client for each protocol
void OnWebSocketClosedEvent_Subsystem(int32 StatusCode, const FString& Reason, bool bWasClean);
FDelegateHandle OnWsConnectedEventDelegateHandle;
FDelegateHandle OnWsConnectionErrorEventDelegateHandle;
FDelegateHandle OnWsClosedEventDelegateHandle;
FDelegateHandle OnWsMessageEventDelegateHandle;
FDelegateHandle OnWsMessageSentEventDelegateHandle;
FDTFluxWebSocketClientSP WsClient = nullptr;
FDTFluxHttpClientSP HttpClient = nullptr;
// === GESTION DES ÉVÉNEMENTS HTTP ===
void RegisterHttpEvents();
void UnregisterHttpEvents();
// === PARSING DES RÉPONSES ===
void ParseTeamListResponse(FDTFluxServerResponse& ServerResponse);
void ParseRaceData(FDTFluxServerResponse& Response);
void ParseContestRanking(FDTFluxServerResponse& Response);
void ParseStageRankingResponse(FDTFluxServerResponse& Response);
void ParseSplitRankingResponse(FDTFluxServerResponse& Response);
void ParseStatusUpdateResponse(FDTFluxServerResponse& Response);
void ParseSplitSensorResponse(FDTFluxServerResponse& Response);
EDTFluxResponseStatus ProcessPushMessage(FDTFluxServerResponse& Response);
void Parse(FDTFluxServerResponse& Response);
void OnWebSocketMessageEvent_Subsystem(const FString& MessageString);
void OnWebSocketMessageSentEvent_Subsystem(const FString& MessageSent);
// === GESTION DES REQUÊTES TRACKÉES ===
UFUNCTION()
void OnRequestTimedOut_Internal(const FDTFluxQueuedRequest& TimedOutRequest);
bool TryMatchResponseToQueuedRequest(const FDTFluxServerResponse& Response);
void CompleteTrackedRequest(const FGuid& RequestId, const FString& ResponseData, EDTFluxRequestType RequestType);
void FailTrackedRequest(const FGuid& RequestId, const FString& ErrorMessage, EDTFluxRequestType RequestType);
void SendQueuedRequest(const FDTFluxQueuedRequest& QueuedRequest);
// === UTILITAIRES ===
static FString ConstructWsAddress(const FString& Address, const FString& Path, const int& Port);
};