Compare commits

...

7 Commits

8 changed files with 151 additions and 13 deletions

View File

@ -23,7 +23,7 @@ public class DTFluxProjectSettings : ModuleRules
"DeveloperSettings", "DeveloperSettings",
"DTFluxCore", "DTFluxCore",
"Settings", "Settings",
"DeveloperSettings" "DeveloperSettings","AvalancheMedia"
} }
); );

View File

@ -2,6 +2,7 @@
#include "DTFluxGeneralSettings.h" #include "DTFluxGeneralSettings.h"
#include "Assets/DTFluxModelAsset.h"
#include "DTFluxProjectSettingsModule.h" #include "DTFluxProjectSettingsModule.h"
@ -14,3 +15,17 @@ UDTFluxGeneralSettings::UDTFluxGeneralSettings()
UE_LOG(logDTFluxProjectSettings, Log, TEXT("Category Name -> %s"), *GetCategoryName().ToString()); UE_LOG(logDTFluxProjectSettings, Log, TEXT("Category Name -> %s"), *GetCategoryName().ToString());
} }
void UDTFluxGeneralSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
if (PropertyChangedEvent.Property &&
PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UDTFluxGeneralSettings, RemoteTargetRundown))
{
UE_LOG(LogTemp, Log, TEXT("RemoteTargetRundown property changed to: %s"),
RemoteTargetRundown.IsNull() ? TEXT("None") : *RemoteTargetRundown.ToString());
OnRemoteRundownChanged.Broadcast(RemoteTargetRundown);
}
}

View File

@ -3,10 +3,11 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Assets/DTFluxModelAsset.h"
#include "Engine/DeveloperSettings.h" #include "Engine/DeveloperSettings.h"
#include "DTFluxGeneralSettings.generated.h" #include "DTFluxGeneralSettings.generated.h"
class UAvaRundown;
class UDTFluxModelAsset;
/** /**
* *
*/ */
@ -20,5 +21,14 @@ public:
UDTFluxGeneralSettings(); UDTFluxGeneralSettings();
UPROPERTY(Category="General", Config, EditAnywhere, BlueprintReadOnly, DisplayName="Datastorage File") UPROPERTY(Category="General", Config, EditAnywhere, BlueprintReadOnly, DisplayName="Datastorage File")
TSoftObjectPtr<UDTFluxModelAsset> ModelAsset; TSoftObjectPtr<UDTFluxModelAsset> ModelAsset;
UPROPERTY(Category="General|Remote HTTP", Config, EditAnywhere, BlueprintReadOnly, DisplayName="Rundown Remote Target")
TSoftObjectPtr<UAvaRundown> RemoteTargetRundown;
#if WITH_EDITOR
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
DECLARE_MULTICAST_DELEGATE_OneParam(FOnRemoteRundownChanged, const TSoftObjectPtr<UAvaRundown>& );
FOnRemoteRundownChanged OnRemoteRundownChanged;
#endif
}; };

View File

@ -23,6 +23,8 @@ public class DTFluxRemote : ModuleRules
"HttpServer", "HttpServer",
"JsonUtilities", "JsonUtilities",
"Json", "Json",
"DTFluxProjectSettings",
"AvalancheMedia"
} }
); );
} }

View File

@ -3,10 +3,13 @@
#include "DTFluxRemoteSubsystem.h" #include "DTFluxRemoteSubsystem.h"
#include "DTFluxRemoteSubsystem.h" #include "DTFluxRemoteSubsystem.h"
#include "DTFluxGeneralSettings.h"
#include "DTFluxRemoteModule.h" #include "DTFluxRemoteModule.h"
#include "DTFluxRemoteModule.h" #include "DTFluxRemoteModule.h"
#include "HttpServerModule.h" #include "HttpServerModule.h"
#include "IHttpRouter.h" #include "IHttpRouter.h"
#include "Rundown/AvaRundown.h"
#include "Json.h" #include "Json.h"
#include "Engine/Engine.h" #include "Engine/Engine.h"
#include "Misc/DateTime.h" #include "Misc/DateTime.h"
@ -18,6 +21,16 @@ void UDTFluxRemoteSubsystem::Initialize(FSubsystemCollectionBase& Collection)
UE_LOG(logDTFluxRemote, Log, TEXT("DTFlux API Subsystem Initialized")); UE_LOG(logDTFluxRemote, Log, TEXT("DTFlux API Subsystem Initialized"));
#if WITH_EDITOR
// S'abonner aux changements de settings
if (UDTFluxGeneralSettings* Settings = GetMutableDefault<UDTFluxGeneralSettings>())
{
SettingsRundownChangedHandle = Settings->OnRemoteRundownChanged.AddUObject(
this, &UDTFluxRemoteSubsystem::OnSettingsRundownChanged
);
}
#endif
LoadRundownFromSettings();
// Auto-start server (optionnel) // Auto-start server (optionnel)
StartHTTPServer(63350); StartHTTPServer(63350);
} }
@ -26,6 +39,21 @@ void UDTFluxRemoteSubsystem::Deinitialize()
{ {
StopHTTPServer(); StopHTTPServer();
#if WITH_EDITOR
// Se désabonner du delegate
if (UDTFluxGeneralSettings* Settings = GetMutableDefault<UDTFluxGeneralSettings>())
{
if (SettingsRundownChangedHandle.IsValid())
{
Settings->OnRemoteRundownChanged.Remove(SettingsRundownChangedHandle);
SettingsRundownChangedHandle.Reset();
}
}
#endif
// Décharger proprement le rundown
UnloadCurrentRundown();
UE_LOG(logDTFluxRemote, Log, TEXT("DTFlux API Subsystem Deinitialized")); UE_LOG(logDTFluxRemote, Log, TEXT("DTFlux API Subsystem Deinitialized"));
Super::Deinitialize(); Super::Deinitialize();
@ -64,9 +92,9 @@ bool UDTFluxRemoteSubsystem::StartHTTPServer(int32 Port)
UE_LOG(logDTFluxRemote, Log, TEXT("DTFlux HTTP API Server started on port %d"), ServerPort); UE_LOG(logDTFluxRemote, Log, TEXT("DTFlux HTTP API Server started on port %d"), ServerPort);
UE_LOG(logDTFluxRemote, Log, TEXT("Base URL: http://localhost:%d/dtflux/api/v1"), ServerPort); UE_LOG(logDTFluxRemote, Log, TEXT("Base URL: http://localhost:%d/dtflux/api/v1"), ServerPort);
UE_LOG(logDTFluxRemote, Log, TEXT("Available routes:")); UE_LOG(logDTFluxRemote, Log, TEXT("Available routes:"));
UE_LOG(logDTFluxRemote, Log, TEXT(" POST /dtflux/api/v1/title")); UE_LOG(logDTFluxRemote, Log, TEXT(" PUT /dtflux/api/v1/title"));
UE_LOG(logDTFluxRemote, Log, TEXT(" POST /dtflux/api/v1/title-bib")); UE_LOG(logDTFluxRemote, Log, TEXT(" PUT /dtflux/api/v1/title-bib"));
UE_LOG(logDTFluxRemote, Log, TEXT(" POST /dtflux/api/v1/commands")); UE_LOG(logDTFluxRemote, Log, TEXT(" PUT /dtflux/api/v1/commands"));
return true; return true;
} }
@ -111,21 +139,21 @@ void UDTFluxRemoteSubsystem::SetupRoutes()
// Route: POST /dtflux/api/v1/title // Route: POST /dtflux/api/v1/title
TitleRouteHandle = HttpRouter->BindRoute( TitleRouteHandle = HttpRouter->BindRoute(
FHttpPath(TEXT("/dtflux/api/v1/title")), FHttpPath(TEXT("/dtflux/api/v1/title")),
EHttpServerRequestVerbs::VERB_GET, EHttpServerRequestVerbs::VERB_PUT,
FHttpRequestHandler::CreateUObject(this, &UDTFluxRemoteSubsystem::HandleTitleRequest) FHttpRequestHandler::CreateUObject(this, &UDTFluxRemoteSubsystem::HandleTitleRequest)
); );
// Route: POST /dtflux/api/v1/title-bib // Route: POST /dtflux/api/v1/title-bib
TitleBibRouteHandle = HttpRouter->BindRoute( TitleBibRouteHandle = HttpRouter->BindRoute(
FHttpPath(TEXT("/dtflux/api/v1/title-bib")), FHttpPath(TEXT("/dtflux/api/v1/title-bib")),
EHttpServerRequestVerbs::VERB_GET, EHttpServerRequestVerbs::VERB_PUT,
FHttpRequestHandler::CreateUObject(this, &UDTFluxRemoteSubsystem::HandleTitleBibRequest) FHttpRequestHandler::CreateUObject(this, &UDTFluxRemoteSubsystem::HandleTitleBibRequest)
); );
// Route: POST /dtflux/api/v1/commands // Route: POST /dtflux/api/v1/commands
CommandsRouteHandle = HttpRouter->BindRoute( CommandsRouteHandle = HttpRouter->BindRoute(
FHttpPath(TEXT("/dtflux/api/v1/commands")), FHttpPath(TEXT("/dtflux/api/v1/commands")),
EHttpServerRequestVerbs::VERB_GET, EHttpServerRequestVerbs::VERB_PUT,
FHttpRequestHandler::CreateUObject(this, &UDTFluxRemoteSubsystem::HandleCommandsRequest) FHttpRequestHandler::CreateUObject(this, &UDTFluxRemoteSubsystem::HandleCommandsRequest)
); );
@ -316,6 +344,56 @@ bool UDTFluxRemoteSubsystem::ParseCommandData(const TSharedPtr<FJsonObject>& Jso
return true; return true;
} }
void UDTFluxRemoteSubsystem::UnloadCurrentRundown()
{
}
void UDTFluxRemoteSubsystem::LoadRundownFromSettings()
{
const UDTFluxGeneralSettings* Settings = GetDefault<UDTFluxGeneralSettings>();
if (!Settings)
{
UE_LOG(logDTFluxRemote, Warning, TEXT("Cannot access DTFlux settings"));
return;
}
TSoftObjectPtr<UAvaRundown> RundownAsset = Settings->RemoteTargetRundown;
if (RundownAsset.IsNull())
{
UE_LOG(logDTFluxRemote, Log, TEXT("No rundown specified in settings"));
UnloadCurrentRundown();
return;
}
// Si c'est le même rundown, pas besoin de recharger
if (RemotedRundown && RemotedRundown == RundownAsset.LoadSynchronous())
{
UE_LOG(logDTFluxRemote, Log, TEXT("Rundown already loaded: %s"), *RundownAsset.ToString());
return;
}
// Décharger l'ancien rundown d'abord
UnloadCurrentRundown();
RundownAsset = RundownAsset.LoadSynchronous();
// Charger le nouveau rundown
if ( RundownAsset.IsValid())
{
UE_LOG(logDTFluxRemote, Log, TEXT("Successfully loaded rundown from settings: %s"), *RundownAsset.ToString());
}
else
{
UE_LOG(logDTFluxRemote, Error, TEXT("Failed to load rundown from settings: %s"), *RundownAsset.ToString());
}
}
#if WITH_EDITOR
void UDTFluxRemoteSubsystem::OnSettingsRundownChanged(const TSoftObjectPtr<UAvaRundown>& NewRundown)
{
}
#endif
// Manual processing functions for testing // Manual processing functions for testing
bool UDTFluxRemoteSubsystem::ProcessTitleData(const FString& JsonString) bool UDTFluxRemoteSubsystem::ProcessTitleData(const FString& JsonString)
{ {
@ -374,3 +452,6 @@ bool UDTFluxRemoteSubsystem::ProcessCommandData(const FString& JsonString)
return false; return false;
} }

View File

@ -9,6 +9,7 @@
#include "IHttpRouter.h" #include "IHttpRouter.h"
#include "DTFluxRemoteSubsystem.generated.h" #include "DTFluxRemoteSubsystem.generated.h"
class UAvaRundown;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTitleReceived, const FDTFluxRemoteTitleData&, TitleData); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTitleReceived, const FDTFluxRemoteTitleData&, TitleData);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTitleBibReceived, const FDTFluxRemoteBibData&, TitleBibData); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTitleBibReceived, const FDTFluxRemoteBibData&, TitleBibData);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCommandReceived, const FDTFluxRemoteCommandData&, CommandData); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCommandReceived, const FDTFluxRemoteCommandData&, CommandData);
@ -73,10 +74,25 @@ private:
private: private:
TSharedPtr<IHttpRouter> HttpRouter; TSharedPtr<IHttpRouter> HttpRouter;
TSoftObjectPtr<UAvaRundown> RemotedRundown;
int32 ServerPort = 63350; int32 ServerPort = 63350;
bool bServerRunning = false; bool bServerRunning = false;
FHttpRouteHandle TitleRouteHandle; FHttpRouteHandle TitleRouteHandle;
FHttpRouteHandle TitleBibRouteHandle; FHttpRouteHandle TitleBibRouteHandle;
FHttpRouteHandle CommandsRouteHandle; FHttpRouteHandle CommandsRouteHandle;
void UnloadCurrentRundown();
void LoadRundownFromSettings();
#if WITH_EDITOR
FDelegateHandle SettingsRundownChangedHandle;
#endif
#if WITH_EDITOR
// Callback pour les changements de settings
UFUNCTION()
void OnSettingsRundownChanged(const TSoftObjectPtr<UAvaRundown>& NewRundown);
#endif
}; };

View File

@ -1,7 +1,7 @@
// Fill out your copyright notice in the Description page of Project Settings. // Fill out your copyright notice in the Description page of Project Settings.
#include "FTDFluxUtils.h" #include "DTFluxUtils.h"
#include "DTFluxCoreSubsystem.h" #include "DTFluxCoreSubsystem.h"
#include "DTFluxUtilitiesModule.h" #include "DTFluxUtilitiesModule.h"
@ -55,3 +55,13 @@ void UFTDFluxUtils::GetFullName(const int Bib, FText& OutFullName)
} }
UE_LOG(logDTFluxUtilities, Error, TEXT("DTFluxCoreSubsystem not available")); UE_LOG(logDTFluxUtilities, Error, TEXT("DTFluxCoreSubsystem not available"));
} }
TArray<FDTFluxSplitSensorInfo> UFTDFluxUtils::SortSplitRankingsByRank(const TArray<FDTFluxSplitSensorInfo>& Rankings)
{
TArray<FDTFluxSplitSensorInfo> CopyRankings = Rankings;
CopyRankings.Sort([](const FDTFluxSplitSensorInfo& A, const FDTFluxSplitSensorInfo& B)
{
return A.Rank < B.Rank;
});
return CopyRankings;
}

View File

@ -5,8 +5,8 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "DTFluxCore/Public/Types/Struct/DTFluxTeamListStruct.h" #include "DTFluxCore/Public/Types/Struct/DTFluxTeamListStruct.h"
#include "Kismet/BlueprintFunctionLibrary.h" #include "Kismet/BlueprintFunctionLibrary.h"
#include "Types/Struct/DTFluxRankingStructs.h" #include "Types/Struct/DTFluxSplitSensor.h"
#include "FTDFluxUtils.generated.h" #include "DTFluxUtils.generated.h"
/** /**
* *
@ -70,4 +70,8 @@ public:
UFUNCTION(BlueprintCallable, Category="DTFlux|Utils") UFUNCTION(BlueprintCallable, Category="DTFlux|Utils")
static void GetFullName(const int Bib, FText& OutFullName); static void GetFullName(const int Bib, FText& OutFullName);
UFUNCTION(BlueprintCallable, Category="DTFlux|Utils")
static TArray<FDTFluxSplitSensorInfo> SortSplitRankingsByRank(const TArray<FDTFluxSplitSensorInfo>& OutRankings);
}; };