Compare commits

..

5 Commits

16 changed files with 130 additions and 745 deletions

View File

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 512 512"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:export-filename="RaceResult.icone16x16.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
sodipodi:docname="RaceResult.icone16x16.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="px" /><defs
id="defs1" /><g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(3.0517578e-5)"><rect
style="fill:#e22c2b;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
id="rect1"
width="512"
height="512"
x="-3.0517578e-05"
y="0" /><path
style="fill:none;stroke:#ffffff;stroke-width:15;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
d="m 154.64305,277.08769 -1.3605,-151.92206 146.48007,103.3977 v 184.12046 l 54.87334,-50.79185 V 199.53942 L 215.41187,92.967228 V 328.78654 Z"
id="path1" /></g></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -31,6 +31,7 @@ public class DTFluxAPIStatus : ModuleRules
"DTFluxCoreSubsystem", "DTFluxCoreSubsystem",
"InputCore", "InputCore",
"OutputLog", "OutputLog",
"ToolMenus",
} }
); );
} }

View File

@ -14,9 +14,9 @@ FText DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::StatusTabDisplayName = FText::
void DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::StartupModule() void DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::StartupModule()
{ {
FDTFluxStatusStyle::RegisterStyle();
InitMenuExtension(); InitMenuExtension();
RegisterStatusTab(); RegisterStatusTab();
FDTFluxStatusStyle::RegisterStyle();
} }
@ -25,45 +25,109 @@ void DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::StartupModule()
void DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::InitMenuExtension() void DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::InitMenuExtension()
{ {
FLevelEditorModule& LevelEditorModule = // FLevelEditorModule& LevelEditorModule =
FModuleManager::LoadModuleChecked<FLevelEditorModule>(TEXT("LevelEditor")); // FModuleManager::LoadModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
// FDTFluxAPIModule& DTFluxApi = // // FDTFluxAPIModule& DTFluxApi =
// FModuleManager::LoadModuleChecked<FDTFluxAPIModule>(TEXT("DTFluxAPI")); // // FModuleManager::LoadModuleChecked<FDTFluxAPIModule>(TEXT("DTFluxAPI"));
const TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender()); // const TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());
//
// MenuExtender->AddMenuBarExtension(
// "Help",
// EExtensionHook::Before,
// nullptr,
// FMenuBarExtensionDelegate::CreateRaw(this, &FDTFluxAPIStatusModule::AddMenu)
// );
// LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
MenuExtender->AddMenuBarExtension( UToolMenus::RegisterStartupCallback(
"Help", FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FDTFluxAPIStatusModule::RegisterMenus)
EExtensionHook::Before,
nullptr,
FMenuBarExtensionDelegate::CreateRaw(this, &FDTFluxAPIStatusModule::AddMenu)
); );
LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
} }
void DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::AddMenu(FMenuBarBuilder& MenuBarBuilder) void FDTFluxAPIStatusModule::RegisterMenus()
{ {
MenuBarBuilder.AddPullDownMenu( UE_LOG(logDTFluxStatus, Warning, TEXT("Creating DTFlux menu"));
// 1. Enregistrer le menu DTFlux
UToolMenu* DTFluxMenu = UToolMenus::Get()->RegisterMenu("DTFlux.MainMenu");
if (DTFluxMenu)
{
CreateSubmenu(DTFluxMenu);
}
// 2. Ajouter ce menu à la barre principale
if (UToolMenu* MainMenu = UToolMenus::Get()->ExtendMenu("MainFrame.MainMenu"))
{
FToolMenuSection& DTFluxMenuSection = MainMenu->FindOrAddSection("DTFlux");
DTFluxMenuSection.Label = FText::FromString("DTFlux");
DTFluxMenuSection.AddSubMenu(
"DTFluxSubmenu",
FText::FromString("DTFlux"), FText::FromString("DTFlux"),
FText::FromString("DTFlux API Tools"), FText::FromString("DTFlux API Tools"),
FNewMenuDelegate::CreateRaw(this, &FDTFluxAPIStatusModule::FillMenu) FNewToolMenuDelegate::CreateLambda([](UToolMenu* Menu)
{
// Référencer le menu enregistré
if (UToolMenu* RegisteredMenu = UToolMenus::Get()->FindMenu("DTFlux.MainMenu"))
{
// Copier la structure du menu enregistré
for (const FToolMenuSection& Section : RegisteredMenu->Sections)
{
Menu->Sections.Add(Section);
}
}
}),
false,
FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.Tab.Icon")
); );
}
} }
void DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::FillMenu(FMenuBuilder& MenuBuilder) void FDTFluxAPIStatusModule::CreateSubmenu(UToolMenu* Menu)
{ {
MenuBuilder.BeginSection(NAME_None, FText::FromString("DTFlux API")); FToolMenuSection& DTFluxAPISection = Menu->FindOrAddSection("DTFluxAPI");
MenuBuilder.AddMenuEntry( DTFluxAPISection.Label = FText::FromString("DTFlux API");
FText::FromString("Status"), // Cette section est vide pour le moment, prête pour de futurs boutons
FText::FromString("Launch DTFlux Status"),
FSlateIcon(FDTFluxStatusStyle::GetStyleSetName(), "LevelEditor.Tab.Icon"),
FExecuteAction::CreateRaw(this, &FDTFluxAPIStatusModule::OnButtonClicked)
);
MenuBuilder.EndSection();
// Section 2 : Tools
FToolMenuSection& ToolsSection = Menu->FindOrAddSection("Tools");
ToolsSection.Label = FText::FromString("Tools");
// Ajouter le bouton Status dans la section Tools
DTFluxAPISection.AddMenuEntry(
"DTFluxStatus",
FText::FromString("DTFlux Status"),
FText::FromString("Launch DTFlux Status Control Panel"),
FSlateIcon(FDTFluxStatusStyle::GetStyleSetName(), "LevelEditor.Tab.Icon"),
FUIAction(FExecuteAction::CreateRaw(this, &FDTFluxAPIStatusModule::OnButtonClicked))
);
} }
// void DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::AddMenu(FMenuBarBuilder& MenuBarBuilder)
// {
// MenuBarBuilder.AddPullDownMenu(
// FText::FromString("DTFlux"),
// FText::FromString("DTFlux API Tools"),
// FNewMenuDelegate::CreateRaw(this, &FDTFluxAPIStatusModule::FillMenu)
// );
// }
// void DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::FillMenu(FMenuBuilder& MenuBuilder)
// {
// MenuBuilder.BeginSection(NAME_None, FText::FromString("DTFlux API"));
// MenuBuilder.AddMenuEntry(
// FText::FromString("Status"),
// FText::FromString("Launch DTFlux Status"),
// FSlateIcon(FDTFluxStatusStyle::GetStyleSetName(), "LevelEditor.Tab.Icon"),
// FExecuteAction::CreateRaw(this, &FDTFluxAPIStatusModule::OnButtonClicked)
// );
// MenuBuilder.EndSection();
// }
void DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::OnButtonClicked() void DTFLUXAPISTATUS_API FDTFluxAPIStatusModule::OnButtonClicked()
{ {
FGlobalTabmanager::Get()->TryInvokeTab(StatusTabId); FGlobalTabmanager::Get()->TryInvokeTab(StatusTabId);

View File

@ -13,10 +13,11 @@ public:
#pragma region MenuExtention #pragma region MenuExtention
void InitMenuExtension(); void InitMenuExtension();
void AddMenu(FMenuBarBuilder& MenuBarBuilder); void RegisterMenus();
void FillMenu(FMenuBuilder& MenuBuilder); void CreateSubmenu(UToolMenu* Menu);
// void AddMenu(FMenuBarBuilder& MenuBarBuilder);
// void FillMenu(FMenuBuilder& MenuBuilder);
void OnButtonClicked(); void OnButtonClicked();
// void OnWsEvent(TEnumAsByte<EDTFluxWsStatus> WsResponseEvent) const;
#pragma endregion #pragma endregion
#pragma region EditorTab #pragma region EditorTab
@ -25,7 +26,6 @@ public:
private: private:
static FName StatusTabId; static FName StatusTabId;
static FText StatusTabDisplayName; static FText StatusTabDisplayName;
TSharedPtr<class SDTFluxStatusWidget> StatusWidget; TSharedPtr<class SDTFluxStatusWidget> StatusWidget;
#pragma endregion #pragma endregion
}; };

View File

@ -366,3 +366,12 @@ void UDTFluxCoreSubsystem::LaunchPursuitSequenceFor(const TArray<int> ContestIds
} }
} }
} }
FOnPursuitSequenceReady& UDTFluxCoreSubsystem::InitPursuit(const TArray<FDTFluxContest> Contests)
{
if (PursuitManager)
{
PursuitManager->LaunchPursuitSequenceFor(Contests);
}
return PursuitManager->OnPursuitSequenceReady;
}

View File

@ -18,7 +18,7 @@ class UDTFluxPursuitManager;
/** /**
* *
*/ */
UCLASS() UCLASS(Blueprintable, BlueprintType)
class DTFLUXCORESUBSYSTEM_API UDTFluxCoreSubsystem : public UEngineSubsystem class DTFLUXCORESUBSYSTEM_API UDTFluxCoreSubsystem : public UEngineSubsystem
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@ -102,7 +102,7 @@ public:
UPROPERTY() UPROPERTY()
int CurrentIndex = -1; int CurrentIndex = -1;
UPROPERTY(BlueprintCallable, Category="DTFlux|Pursuit") UPROPERTY(BlueprintAssignable, Category="DTFlux|Pursuit")
FOnPursuitSequenceReady OnPursuitSequenceReady; FOnPursuitSequenceReady OnPursuitSequenceReady;

View File

@ -104,7 +104,6 @@ FGuid UDTFluxNetworkSubsystem::SendTrackedRequestWithCallback(
PendingErrorCallbacks.Add(RequestId, OnError.GetValue()); PendingErrorCallbacks.Add(RequestId, OnError.GetValue());
} }
} }
return RequestId; return RequestId;
} }
@ -592,8 +591,6 @@ void UDTFluxNetworkSubsystem::Parse(FDTFluxServerResponse& Response)
void UDTFluxNetworkSubsystem::OnWebSocketMessageEvent_Subsystem(const FString& MessageString) void UDTFluxNetworkSubsystem::OnWebSocketMessageEvent_Subsystem(const FString& MessageString)
{ {
// UE_LOG(logDTFluxNetwork, Warning, TEXT("Client %s :\nMessage Received : %s"), *WsClient->GetAddress(), *MessageString);
//Do Something With the message
EDTFluxResponseStatus ResponseStatus; EDTFluxResponseStatus ResponseStatus;
FDTFluxServerResponse Response(MessageString, ResponseStatus); FDTFluxServerResponse Response(MessageString, ResponseStatus);
if (!TryMatchResponseToQueuedRequest(Response)) if (!TryMatchResponseToQueuedRequest(Response))
@ -680,6 +677,7 @@ bool UDTFluxNetworkSubsystem::TryMatchResponseToQueuedRequest(FDTFluxServerRespo
TEXT("Matched response to queued request: Type=%s, Contest=%d, Stage=%d, Split=%d"), TEXT("Matched response to queued request: Type=%s, Contest=%d, Stage=%d, Split=%d"),
*UEnum::GetValueAsString(Response.GetResponseType()), Response.ContestID, Response.StageID, *UEnum::GetValueAsString(Response.GetResponseType()), Response.ContestID, Response.StageID,
Response.SplitID); Response.SplitID);
if (PendingCallbacks.Contains(FoundRequestId)) if (PendingCallbacks.Contains(FoundRequestId))
{ {
FOnDTFluxTrackedRequestResponse* SuccessCallback = PendingCallbacks.Find(FoundRequestId); FOnDTFluxTrackedRequestResponse* SuccessCallback = PendingCallbacks.Find(FoundRequestId);
@ -689,7 +687,6 @@ bool UDTFluxNetworkSubsystem::TryMatchResponseToQueuedRequest(FDTFluxServerRespo
} }
return QueueManager->MarkRequestAsResponded(FoundRequestId); return QueueManager->MarkRequestAsResponded(FoundRequestId);
} }
return false; return false;
} }

View File

@ -128,14 +128,14 @@ public:
// === REQUÊTES AVEC QUEUE ET TRACKING === // === REQUÊTES AVEC QUEUE ET TRACKING ===
UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests") UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests")
FGuid SendTrackedRequest(EDTFluxApiDataType RequestType, int32 ContestId = -1, int32 StageId = -1, FGuid SendTrackedRequest(EDTFluxApiDataType RequestType, int32 ContestId = -1, int32 StageId = -1,
int32 SplitId = -1, float TimeoutSeconds = 30.0f); int32 SplitId = -1, float TimeoutSeconds = 5.0f);
FGuid SendTrackedRequestWithCallback(EDTFluxApiDataType RequestType, int32 ContestId, int32 StageId, int32 SplitId, FGuid SendTrackedRequestWithCallback(EDTFluxApiDataType RequestType, int32 ContestId, int32 StageId, int32 SplitId,
FOnDTFluxTrackedRequestResponse OnCompleted, FOnDTFluxTrackedRequestResponse OnCompleted,
FOnDTFluxTrackedRequestTimeout OnTimeout, FOnDTFluxTrackedRequestTimeout OnTimeout,
TOptional<FOnDTFluxRequestResponseError> OnError = TOptional< TOptional<FOnDTFluxRequestResponseError> OnError = TOptional<
FOnDTFluxRequestResponseError>(), FOnDTFluxRequestResponseError>(),
float TimeoutSeconds = 30.0f); float TimeoutSeconds = 5.0f);
UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests") UFUNCTION(BlueprintCallable, Category="DTFlux|Tracked Requests")
bool GetTrackedRequest(const FGuid& RequestId, FDTFluxQueuedRequest& OutRequest) const; bool GetTrackedRequest(const FGuid& RequestId, FDTFluxQueuedRequest& OutRequest) const;
@ -192,28 +192,30 @@ private:
// === MÉTHODES DE CONFIGURATION === // === MÉTHODES DE CONFIGURATION ===
UFUNCTION() UFUNCTION()
void WsSettingsChanged(const FDTFluxWsSettings& NewWsSettings); void WsSettingsChanged(const FDTFluxWsSettings& NewWsSettings);
void ReconnectWs(const FName WsClientId);
UFUNCTION() UFUNCTION()
void HttpSettingsChanged(const FDTFluxHttpSettings& NewHttpSettings); void HttpSettingsChanged(const FDTFluxHttpSettings& NewHttpSettings);
void ReconnectWs(const FName WsClientId);
void ReconnectHttp(const FName WsClientId); void ReconnectHttp(const FName WsClientId);
// === GESTION DES ÉVÉNEMENTS HTTP ===
void RegisterHttpEvents();
void UnregisterHttpEvents();
// === GESTION DES ÉVÉNEMENTS WEBSOCKET === // === GESTION DES ÉVÉNEMENTS WEBSOCKET ===
void RegisterWebSocketEvents(); void RegisterWebSocketEvents();
void UnregisterWebSocketEvents(); void UnregisterWebSocketEvents();
void OnWebSocketConnected_Subsystem(); void OnWebSocketConnected_Subsystem();
void OnWebSocketConnectionError_Subsystem(const FString& Error); void OnWebSocketConnectionError_Subsystem(const FString& Error);
void OnWebSocketClosedEvent_Subsystem(int32 StatusCode, const FString& Reason, bool bWasClean); void OnWebSocketClosedEvent_Subsystem(int32 StatusCode, const FString& Reason, bool bWasClean);
void OnWebSocketMessageEvent_Subsystem(const FString& MessageString);
void OnWebSocketMessageSentEvent_Subsystem(const FString& MessageSent);
FDelegateHandle OnWsConnectedEventDelegateHandle; FDelegateHandle OnWsConnectedEventDelegateHandle;
FDelegateHandle OnWsConnectionErrorEventDelegateHandle; FDelegateHandle OnWsConnectionErrorEventDelegateHandle;
FDelegateHandle OnWsClosedEventDelegateHandle; FDelegateHandle OnWsClosedEventDelegateHandle;
FDelegateHandle OnWsMessageEventDelegateHandle; FDelegateHandle OnWsMessageEventDelegateHandle;
FDelegateHandle OnWsMessageSentEventDelegateHandle; FDelegateHandle OnWsMessageSentEventDelegateHandle;
// === GESTION DES ÉVÉNEMENTS HTTP ===
void RegisterHttpEvents();
void UnregisterHttpEvents();
// === PARSING DES RÉPONSES === // === PARSING DES RÉPONSES ===
void ParseTeamListResponse(FDTFluxServerResponse& ServerResponse); void ParseTeamListResponse(FDTFluxServerResponse& ServerResponse);
@ -224,10 +226,9 @@ private:
void ParseStatusUpdateResponse(FDTFluxServerResponse& Response); void ParseStatusUpdateResponse(FDTFluxServerResponse& Response);
void ParseSplitSensorResponse(FDTFluxServerResponse& Response); void ParseSplitSensorResponse(FDTFluxServerResponse& Response);
EDTFluxResponseStatus ProcessPushMessage(FDTFluxServerResponse& Response); EDTFluxResponseStatus ProcessPushMessage(FDTFluxServerResponse& Response);
void Parse(FDTFluxServerResponse& Response); void Parse(FDTFluxServerResponse& Response);
void OnWebSocketMessageEvent_Subsystem(const FString& MessageString);
void OnWebSocketMessageSentEvent_Subsystem(const FString& MessageSent);
bool CleanRequestCallbacks(const FGuid& RequestId); bool CleanRequestCallbacks(const FGuid& RequestId);
// === GESTION DES REQUÊTES TRACKÉES === // === GESTION DES REQUÊTES TRACKÉES ===

View File

@ -1,34 +0,0 @@
using UnrealBuildTool;
public class DTFluxRaceResult : ModuleRules
{
public DTFluxRaceResult(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core"
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
"DTFluxProjectSettings",
"UMG",
"WebBrowser",
"Projects",
"ToolMenus",
"HTTP",
"JsonUtilities",
"Json"
}
);
}
}

View File

@ -1,161 +0,0 @@
#include "DTFluxRaceResultModule.h"
#include "LevelEditor.h"
#include "Widget/SDTFluxRaceResultWidget.h"
#include "Widget/Style/DTFluxRaceResultStyle.h"
#define LOCTEXT_NAMESPACE "FDTFluxRaceResultModule"
DEFINE_LOG_CATEGORY(logDTFluxRaceResult)
FName DTFLUXRACERESULT_API FDTFluxRaceResult::RaceResultTabId = "DTFluxRaceResult";
FText DTFLUXRACERESULT_API FDTFluxRaceResult::RaceResultTabDisplayName = FText::FromString(TEXT("DTFlux RaceResult"));
void DTFLUXRACERESULT_API FDTFluxRaceResult::StartupModule()
{
UE_LOG(logDTFluxRaceResult, Warning, TEXT("DTFluxRaceResult Module Started"))
FDTFluxRaceResultStyle::RegisterStyle();
InitMenuExtension();
RegisterRaceResultTab();
}
#pragma region MenuExtension
void DTFLUXRACERESULT_API FDTFluxRaceResult::InitMenuExtension()
{
UToolMenus::RegisterStartupCallback(
FSimpleMulticastDelegate::FDelegate::CreateRaw(this,
&FDTFluxRaceResult::RegisterMenuExtensions));
}
void DTFLUXRACERESULT_API FDTFluxRaceResult::RegisterMenuExtensions()
{
// Étendre le menu enregistré
if (UToolMenu* DTFluxMenu = UToolMenus::Get()->ExtendMenu("DTFlux.MainMenu"))
{
FToolMenuSection& ToolsSection = DTFluxMenu->FindOrAddSection("Tools");
ToolsSection.AddMenuEntry(
"DTFluxRaceResult",
FText::FromString("RaceResult"),
FText::FromString("Launch DTFlux RaceResult Control Panel"),
FSlateIcon(FDTFluxRaceResultStyle::GetStyleSetName(), "LevelEditor.Tab.IconRaceResult"),
FUIAction(FExecuteAction::CreateRaw(this, &FDTFluxRaceResult::OnButtonClicked))
);
}
}
void FDTFluxRaceResult::CreateSubmenu(UToolMenu* Menu)
{
// Section 2 : Tools
FToolMenuSection& ToolsSection = Menu->FindOrAddSection("Tools");
ToolsSection.Label = FText::FromString("Tools");
ToolsSection.AddMenuEntry(
"DTFluxRaceResult",
FText::FromString("RaceResult"),
FText::FromString("Launch Race Result WebAdmin Console"),
FSlateIcon(FDTFluxRaceResultStyle::GetStyleSetName(), "LevelEditor.Tab.IconRaceResult"),
// Adaptez selon votre icône
FUIAction(FExecuteAction::CreateRaw(this, &FDTFluxRaceResult::OnButtonClicked))
);
}
void DTFLUXRACERESULT_API FDTFluxRaceResult::OnButtonClicked()
{
FGlobalTabmanager::Get()->TryInvokeTab(RaceResultTabId);
UE_LOG(LogTemp, Log, TEXT("Race Result Launched"))
}
#pragma endregion EditorTab
#pragma region
void DTFLUXRACERESULT_API FDTFluxRaceResult::RegisterRaceResultTab()
{
FTabSpawnerEntry& SpawnerEntry =
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(
RaceResultTabId,
FOnSpawnTab::CreateRaw(this, &FDTFluxRaceResult::OnSpawnTab)
)
.SetDisplayName(RaceResultTabDisplayName)
.SetTooltipText(FText::FromString(TEXT("Race Result Control Panel")));
}
TSharedRef<SDockTab> DTFLUXRACERESULT_API FDTFluxRaceResult::OnSpawnTab(const FSpawnTabArgs& SpawnTabArgs)
{
return
SNew(
SDockTab
)
.TabRole(ETabRole::NomadTab)
// .ShouldAutosize(true)
[
SNew(SDTFluxRaceResultWidget)
];
}
#pragma endregion
void DTFLUXRACERESULT_API FDTFluxRaceResult::ShutdownModule()
{
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(RaceResultTabId);
FDTFluxRaceResultStyle::UnregisterStyle();
}
//
// // Dans votre code de debug
// void DTFLUXRACERESULT_API FDTFluxRaceResult::DebugMenus()
// {
// UToolMenus* ToolMenus = UToolMenus::Get();
// if (ToolMenus)
// {
// TArray<FName> MenuNames;
// ToolMenus->GetAllMenuNames(MenuNames);
//
// UE_LOG(logDTFluxRaceResult, Warning, TEXT("=== ALL AVAILABLE MENUS ==="));
// for (const FName& MenuName : MenuNames)
// {
// UE_LOG(logDTFluxRaceResult, Warning, TEXT("Menu: %s"), *MenuName.ToString());
//
// // Obtenir les sections de chaque menu
// UToolMenu* Menu = ToolMenus->FindMenu(MenuName);
// if (Menu)
// {
// for (const FToolMenuSection& Section : Menu->Sections)
// {
// UE_LOG(logDTFluxRaceResult, Warning, TEXT(" Section: %s"), *Section.Name.ToString());
// }
// }
// }
// UE_LOG(logDTFluxRaceResult, Warning, TEXT("=== END MENU LIST ==="));
// }
// }
// void DTFLUXRACERESULT_API FDTFluxRaceResult::AddMenu(FMenuBarBuilder& MenuBarBuilder)
// {
// MenuBarBuilder.AddPullDownMenu(
// FText::FromString("DTFlux"),
// FText::FromString("DTFlux API Tools"),
// FNewMenuDelegate::CreateRaw(this, &FDTFluxRaceResult::FillMenu)
// );
// }
// void DTFLUXRACERESULT_API FDTFluxRaceResult::FillMenu(FMenuBuilder& MenuBuilder)
// {
// MenuBuilder.AddMenuEntry(
// FText::FromString("RaceResult ControlPanel"),
// FText::FromString("Launch RaceResult Control Panel"),
// FSlateIcon(FDTFluxRaceResultStyle::GetStyleSetName(), "LevelEditor.Tab.IconRaceResult"),
// FExecuteAction::CreateRaw(this, &FDTFluxRaceResult::OnButtonClicked)
// );
// MenuBuilder.EndSection();
// }
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FDTFluxRaceResult, DTFluxRaceResult)

View File

@ -1,283 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Widget/SDTFluxRaceResultWidget.h"
#include "DTFluxRaceResultModule.h"
#include "HttpModule.h"
#include "IWebBrowserCookieManager.h"
#include "IWebBrowserWindow.h"
#include "SlateOptMacros.h"
#include "WebBrowserModule.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SDTFluxRaceResultWidget::Construct(const FArguments& InArgs)
{
FWebBrowserInitSettings browserInitSettings = FWebBrowserInitSettings();
IWebBrowserModule::Get().CustomInitialize(browserInitSettings);
WindowSettings.InitialURL = TEXT("about:blank");
WindowSettings.BrowserFrameRate = 25;
if (IWebBrowserModule::IsAvailable() && IWebBrowserModule::Get().IsWebModuleAvailable())
{
IWebBrowserSingleton* WebBrowserSingleton = IWebBrowserModule::Get().GetSingleton();
Browser = WebBrowserSingleton->CreateBrowserWindow(WindowSettings);
// Browser->OnLoadUrl().BindRaw(this, &SDTFluxRaceResultWidget::OnLoadOverride);
}
ChildSlot
[
SNew(SBox)
.Padding(5.0f)
[
SNew(SBorder)
.BorderImage(FCoreStyle::Get().GetBrush("ToolPanel.GroupBorder"))
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
[
SAssignNew(WebBrowser, SWebBrowser, Browser)
.ShowControls(true)
.SupportsTransparency(true)
.OnUrlChanged(this, &SDTFluxRaceResultWidget::OnUrlChanged)
.OnBeforeNavigation(this, &SDTFluxRaceResultWidget::OnBeforeNavigation)
.OnLoadCompleted(FSimpleDelegate::CreateRaw(this, &SDTFluxRaceResultWidget::OnLoadCompleted))
.OnLoadError(FSimpleDelegate::CreateRaw(this, &SDTFluxRaceResultWidget::OnLoadError))
.OnLoadStarted(FSimpleDelegate::CreateRaw(this, &SDTFluxRaceResultWidget::OnLoadStarted))
.ShowErrorMessage(true)
.ShowAddressBar(true)
]
]
]
];
}
void SDTFluxRaceResultWidget::OnCookieSet(bool bSuccess)
{
}
void SDTFluxRaceResultWidget::LoadContentViaHTTP()
{
UE_LOG(logDTFluxRaceResult, Log, TEXT("Loading initial content via HTTP: %s"), *RaceResultUrl);
LoadSpecificURL(RaceResultUrl);
}
void SDTFluxRaceResultWidget::LoadSpecificURL(const FString& Url)
{
UE_LOG(logDTFluxRaceResult, Log, TEXT("Loading via HTTP: %s"), *Url);
// Créer la requête HTTP
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = FHttpModule::Get().CreateRequest();
// Ajouter l'authentification Basic pour TOUTES les requêtes
FString Credentials = Username + TEXT(":") + Password;
FString EncodedCredentials = FBase64::Encode(Credentials);
Request->SetURL(Url);
Request->SetVerb("GET");
Request->SetHeader("Authorization", "Basic " + EncodedCredentials);
Request->SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
Request->SetHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
Request->SetHeader("Accept-Language", "en-US,en;q=0.5");
Request->SetHeader("Accept-Encoding", "gzip, deflate");
Request->SetHeader("Connection", "keep-alive");
Request->OnProcessRequestComplete().BindRaw(this, &SDTFluxRaceResultWidget::OnHTTPContentLoaded);
Request->ProcessRequest();
UE_LOG(logDTFluxRaceResult, Log, TEXT("HTTP request sent with Basic Auth"));
}
void SDTFluxRaceResultWidget::OnHTTPContentLoaded(TSharedPtr<IHttpRequest> Request,
TSharedPtr<IHttpResponse> HttpResponse, bool bWasSuccessful)
{
if (bWasSuccessful && HttpResponse.IsValid())
{
int32 ResponseCode = HttpResponse->GetResponseCode();
UE_LOG(logDTFluxRaceResult, Log, TEXT("HTTP Response Code: %d"), ResponseCode);
if (ResponseCode == 200)
{
FString Content = HttpResponse->GetContentAsString();
UE_LOG(logDTFluxRaceResult, Log, TEXT("Content loaded successfully, size: %d characters"), Content.Len());
// Traiter le contenu HTML
FString ProcessedContent = ProcessHTMLContent(Content, Request->GetURL());
// Charger le contenu dans le browser via LoadString
if (Browser.IsValid())
{
Browser->LoadString(ProcessedContent, Request->GetURL());
UE_LOG(logDTFluxRaceResult, Log, TEXT("Content loaded into browser"));
}
}
else if (ResponseCode == 401)
{
UE_LOG(logDTFluxRaceResult, Error, TEXT("Authentication failed - 401 Unauthorized. Check your credentials."));
}
else if (ResponseCode == 403)
{
UE_LOG(logDTFluxRaceResult, Error, TEXT("Access forbidden - 403 Forbidden"));
}
else if (ResponseCode == 404)
{
UE_LOG(logDTFluxRaceResult, Error, TEXT("Page not found - 404 Not Found"));
}
else
{
UE_LOG(logDTFluxRaceResult, Error, TEXT("HTTP request failed with code: %d"), ResponseCode);
}
}
else
{
UE_LOG(logDTFluxRaceResult, Error, TEXT("HTTP request failed completely"));
}
}
void SDTFluxRaceResultWidget::OnLoadOverride()
{
}
void SDTFluxRaceResultWidget::OnUrlChanged(const FText& NewUrl)
{
UE_LOG(logDTFluxRaceResult, Log, TEXT("URL changed to: %s"), *NewUrl.ToString());
}
FString SDTFluxRaceResultWidget::ProcessHTMLContent(const FString& Content, const FString& BaseUrl)
{
FString ProcessedContent = Content;
// Extraire le domaine de base
FString BaseDomain = ExtractDomain(BaseUrl);
UE_LOG(logDTFluxRaceResult, Log, TEXT("Processing HTML content, base domain: %s"), *BaseDomain);
// Convertir tous les liens relatifs en liens absolus
ProcessedContent = ProcessedContent.Replace(TEXT("src=\"/"), *FString::Printf(TEXT("src=\"%s/"), *BaseDomain));
ProcessedContent = ProcessedContent.Replace(TEXT("href=\"/"), *FString::Printf(TEXT("href=\"%s/"), *BaseDomain));
ProcessedContent = ProcessedContent.Replace(TEXT("src='/"), *FString::Printf(TEXT("src='%s/"), *BaseDomain));
ProcessedContent = ProcessedContent.Replace(TEXT("href='/"), *FString::Printf(TEXT("href='%s/"), *BaseDomain));
// Gérer les liens relatifs avec ./
ProcessedContent = ProcessedContent.Replace(TEXT("src=\"./"), *FString::Printf(TEXT("src=\"%s/"), *BaseDomain));
ProcessedContent = ProcessedContent.Replace(TEXT("href=\"./"), *FString::Printf(TEXT("href=\"%s/"), *BaseDomain));
// Ajouter une balise base pour aider avec les liens relatifs restants
FString BaseTag = FString::Printf(TEXT("<base href=\"%s/\">"), *BaseDomain);
if (ProcessedContent.Contains(TEXT("<head>")))
{
FString HeadReplacement = TEXT("<head>") + BaseTag;
ProcessedContent = ProcessedContent.Replace(TEXT("<head>"), *HeadReplacement);
}
else if (ProcessedContent.Contains(TEXT("<HEAD>")))
{
FString HeadReplacement = TEXT("<HEAD>") + BaseTag;
ProcessedContent = ProcessedContent.Replace(TEXT("<HEAD>"), *HeadReplacement);
}
UE_LOG(logDTFluxRaceResult, Log, TEXT("HTML content processed"));
return ProcessedContent;
}
FString SDTFluxRaceResultWidget::ExtractDomain(const FString& Url)
{
FString Domain = Url;
// Enlever le protocole
if (Url.StartsWith(TEXT("https://")))
{
Domain = Url.Mid(8);
}
else if (Url.StartsWith(TEXT("http://")))
{
Domain = Url.Mid(7);
}
// Trouver le premier slash (début du path)
int32 SlashIndex;
if (Domain.FindChar(TEXT('/'), SlashIndex))
{
Domain = Url.Left(Url.Len() - (Domain.Len() - SlashIndex));
}
// Enlever le port si présent
FString DomainPart = Domain;
if (Domain.StartsWith(TEXT("https://")))
{
DomainPart = Domain.Mid(8);
}
else if (Domain.StartsWith(TEXT("http://")))
{
DomainPart = Domain.Mid(7);
}
int32 ColonIndex;
if (DomainPart.FindChar(TEXT(':'), ColonIndex))
{
Domain = Domain.Left(Domain.Len() - (DomainPart.Len() - ColonIndex));
}
return Domain;
}
bool SDTFluxRaceResultWidget::OnBeforeNavigation(const FString& Url, const FWebNavigationRequest& Request)
{
UE_LOG(logDTFluxRaceResult, Log, TEXT("Loading via HTTP: %s"), *Url);
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> HTTPRequest = FHttpModule::Get().CreateRequest();
// Authentification pour toutes les requêtes
FString Credentials = Username + TEXT(":") + Password;
FString EncodedCredentials = FBase64::Encode(Credentials);
HTTPRequest->SetURL(RaceResultUrl);
HTTPRequest->SetVerb("GET");
HTTPRequest->SetHeader("Authorization", "Basic " + EncodedCredentials);
HTTPRequest->SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
HTTPRequest->SetHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
HTTPRequest->OnProcessRequestComplete().BindRaw(this, &SDTFluxRaceResultWidget::OnHTTPContentLoaded);
HTTPRequest->ProcessRequest();
return true;
}
void SDTFluxRaceResultWidget::OnLoadCompleted()
{
UE_LOG(logDTFluxRaceResult, Log, TEXT("Load Completed"));
}
void SDTFluxRaceResultWidget::OnLoadStarted()
{
UE_LOG(logDTFluxRaceResult, Log, TEXT("Load Started"));
}
void SDTFluxRaceResultWidget::OnLoadError()
{
UE_LOG(logDTFluxRaceResult, Log, TEXT("Load Error"));
}
void SDTFluxRaceResultWidget::OnBeforeResourceLoad(FString Url, FString ResourceType, FContextRequestHeaders& AdditionalHeaders, const bool AllowUserCredentials)
{
}
void SDTFluxRaceResultWidget::SetupBasicAuth()
{
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -1,47 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Widget/Style/DTFluxRaceResultStyle.h"
#include "Interfaces/IPluginManager.h"
#include "Styling/SlateStyleRegistry.h"
#include "Styling/SlateStyleMacros.h"
#define RootToContentDir Style->RootToContentDir
TSharedPtr<ISlateStyle> FDTFluxRaceResultStyle::StyleSet = nullptr;
void FDTFluxRaceResultStyle::RegisterStyle()
{
if(StyleSet.IsValid()) return;
StyleSet = Create();
FSlateStyleRegistry::RegisterSlateStyle(*StyleSet);
}
void FDTFluxRaceResultStyle::UnregisterStyle()
{
if(StyleSet.IsValid())
{
FSlateStyleRegistry::UnRegisterSlateStyle(*StyleSet);
ensure(StyleSet.IsUnique());
StyleSet.Reset();
}
}
void FDTFluxRaceResultStyle::ReloadTextures()
{
}
TSharedPtr<ISlateStyle> FDTFluxRaceResultStyle::Create()
{
TSharedPtr<FSlateStyleSet> Style = MakeShareable(new FSlateStyleSet("DTFluxRaceResultStyle"));
Style->SetContentRoot(IPluginManager::Get().FindPlugin("DTFluxAPI")->GetBaseDir()/TEXT("Resources"));
Style->Set("LevelEditor.Tab.IconRaceResult", new IMAGE_BRUSH_SVG("DTFluxRaceResult16x16", FVector2d(16)) );
return Style;
}

View File

@ -1,33 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
DTFLUXRACERESULT_API DECLARE_LOG_CATEGORY_EXTERN(logDTFluxRaceResult, All, All);
class DTFLUXRACERESULT_API FDTFluxRaceResult : public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
#pragma region MenuExtention
void RegisterMenuExtensions();
void InitMenuExtension();
void CreateSubmenu(UToolMenu* Menu);
// void AddMenu(FMenuBarBuilder& MenuBarBuilder);
// void FillMenu(FMenuBuilder& MenuBuilder);
void OnButtonClicked();
#pragma endregion
#pragma region EditorTab
void RegisterRaceResultTab();
TSharedRef<SDockTab> OnSpawnTab(const FSpawnTabArgs& SpawnTabArgs);
private:
// static void DebugMenus();
static FName RaceResultTabId;
static FText RaceResultTabDisplayName;
TSharedPtr<class SDTFluxRaceResultWidget> RaceResultWidget;
#pragma endregion
};

View File

@ -1,54 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "SWebBrowser.h"
#include "Widgets/SCompoundWidget.h"
class IHttpResponse;
class IHttpRequest;
/**
*
*/
class DTFLUXRACERESULT_API SDTFluxRaceResultWidget : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SDTFluxRaceResultWidget)
{
}
SLATE_END_ARGS()
/** Constructs this widget with InArgs */
void Construct(const FArguments& InArgs);
void OnCookieSet(bool bSuccess);
void LoadSpecificURL(const FString& Url);
void LoadContentViaHTTP();
private:
TSharedPtr<SWebBrowser> WebBrowser;
TSharedPtr<IWebBrowserWindow> Browser;
TSharedPtr<IWebBrowserAdapter> BrowserAdapter;
FCreateBrowserWindowSettings WindowSettings;
void OnUrlChanged(const FText& NewUrl);
FString ProcessHTMLContent(const FString& Content, const FString& BaseUrl);
FString ExtractDomain(const FString& Url);
void OnHTTPContentLoaded(TSharedPtr<IHttpRequest> Request, TSharedPtr<IHttpResponse> HttpResponse, bool bWasSuccessful);
bool OnBeforeNavigation(const FString& Url, const FWebNavigationRequest& Request);
void OnLoadCompleted();
void OnLoadStarted();
void OnLoadError();
void OnLoadOverride();
void OnBeforeResourceLoad(FString Url, FString ResourceType, FContextRequestHeaders& AdditionalHeaders, const bool AllowUserCredentials);
FString RaceResultUrl = "https://raceresult.tds-france.com";
FString Username = "sporkrono";
FString Password = "Notre 3ème décennie d'action pour le climat";
void SetupBasicAuth();
};

View File

@ -1,34 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Styling/ISlateStyle.h"
/**
*
*/
class DTFLUXRACERESULT_API FDTFluxRaceResultStyle
{
public:
static void RegisterStyle();
static void UnregisterStyle();
static void ReloadTextures();
static const ISlateStyle& Get()
{
return *StyleSet;
}
static const FName& GetStyleSetName()
{
return StyleSet->GetStyleSetName();
}
private:
static TSharedPtr<ISlateStyle> Create();
static TSharedPtr<ISlateStyle> StyleSet;
};