From 77828d626d0b67c5eb26e4e21fde57c64750b9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Skyler=20M=C3=A4ntysaari?= Date: Sat, 24 Jan 2026 06:09:16 +0200 Subject: [PATCH 1/3] Move config initialization to it's own subsystem away from beginPlay --- .../Private/FRMConfigInitSubsystem.cpp | 50 ++++++++++++++ .../Private/FicsitRemoteMonitoring.cpp | 66 ++++++++++--------- .../Public/FRMConfigInitSubsystem.h | 33 ++++++++++ .../Public/FicsitRemoteMonitoring.h | 5 ++ .../FicsitRemoteMonitoringServer.build.cs | 4 +- 5 files changed, 126 insertions(+), 32 deletions(-) create mode 100644 Source/FicsitRemoteMonitoring/Private/FRMConfigInitSubsystem.cpp create mode 100644 Source/FicsitRemoteMonitoring/Public/FRMConfigInitSubsystem.h diff --git a/Source/FicsitRemoteMonitoring/Private/FRMConfigInitSubsystem.cpp b/Source/FicsitRemoteMonitoring/Private/FRMConfigInitSubsystem.cpp new file mode 100644 index 00000000..27f5cc9b --- /dev/null +++ b/Source/FicsitRemoteMonitoring/Private/FRMConfigInitSubsystem.cpp @@ -0,0 +1,50 @@ +#include "FRMConfigInitSubsystem.h" +#include "Configuration/ConfigManager.h" +#include "Engine/Engine.h" + +void UFRMConfigInitSubsystem::Initialize(FSubsystemCollectionBase& Collection) +{ + Super::Initialize(Collection); + + UConfigManager* ConfigManager = GetGameInstance()->GetSubsystem(); + if (!ConfigManager) + { + UE_LOG(LogTemp, Error, TEXT("[FRMConfigInitSubsystem] ConfigManager missing.")); + return; + } + + ConfigManager->ReloadModConfigurations(); + + // Now config is loaded and safe to read/write + HttpConfig = FConfig_HTTPStruct::GetActiveConfig(this); + SerialConfig = FConfig_SerialStruct::GetActiveConfig(this); + FactoryConfig = FConfig_FactoryStruct::GetActiveConfig(this); + + if (HttpConfig.Authentication_Token.IsEmpty()) + { + HttpConfig.Authentication_Token = GenerateAuthToken(32); + HttpConfig.Save(GetWorld()); + + UE_LOG(LogTemp, Log, TEXT("[FRMConfigInitSubsystem] Generated and saved new token: %s"), *HttpConfig.Authentication_Token); + } + else + { + UE_LOG(LogTemp, Log, TEXT("[FRMConfigInitSubsystem] Token already exists.")); + } + + AuthenticationToken = HttpConfig.Authentication_Token; +} + +FString UFRMConfigInitSubsystem::GenerateAuthToken(const int32 Length) +{ + const FString Characters = TEXT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + const int32 CharactersCount = Characters.Len(); + + FString RandomString; + for (int32 i = 0; i < Length; ++i) + { + RandomString.AppendChar(Characters[FMath::RandRange(0, CharactersCount - 1)]); + } + + return RandomString; +} diff --git a/Source/FicsitRemoteMonitoring/Private/FicsitRemoteMonitoring.cpp b/Source/FicsitRemoteMonitoring/Private/FicsitRemoteMonitoring.cpp index 34a44246..51e840f3 100644 --- a/Source/FicsitRemoteMonitoring/Private/FicsitRemoteMonitoring.cpp +++ b/Source/FicsitRemoteMonitoring/Private/FicsitRemoteMonitoring.cpp @@ -10,6 +10,7 @@ #include "EventsLibrary.h" #include "FactoryLibrary.h" #include "FicsitRemoteMonitoringModule.h" +#include "FRMConfigInitSubsystem.h" #include "Async/Async.h" #include "FRM_Request.h" #include "Hypertubes.h" @@ -59,46 +60,46 @@ void AFicsitRemoteMonitoring::BeginPlay() { Super::BeginPlay(); - // Load FRM's API Endpoints - InitAPIRegistry(); + // Load FRM's API Endpoints + InitAPIRegistry(); - // get config structs - auto HttpConfig = FConfig_HTTPStruct::GetActiveConfig(GetWorld()); - auto SerialConfig = FConfig_SerialStruct::GetActiveConfig(GetWorld()); - - if (HttpConfig.Web_Autostart) { StartWebSocketServer(); } - if (SerialConfig.COM_Autostart) { InitSerialDevice(); } - - UWorld* World = GetWorld(); + // Get our config subsystem + auto ConfigSubsystem = GetGameInstance()->GetSubsystem(); + if (ConfigSubsystem) + { + SetAuthToken(ConfigSubsystem->GetAuthenticationToken()); + } - // generate new authentication token if no token is available - if (HttpConfig.Authentication_Token.IsEmpty()) + if (!ConfigSubsystem) { - HttpConfig.Authentication_Token = GenerateAuthToken(32); - UE_LOG(LogHttpServer, Warning, TEXT("Authentication Token not set, generated a new token: %s"), *HttpConfig.Authentication_Token); - HttpConfig.Save(World); + UE_LOG(LogTemp, Error, TEXT("[AFicsitRemoteMonitoring] Config subsystem missing!")); + return; } - - // store JSONDebugMode into a local property to prevent crash while access to GetActiveConfig while the EndPlay process - const auto FactoryConfig = FConfig_FactoryStruct::GetActiveConfig(World); - JSONDebugMode = FactoryConfig.JSONDebugMode; - // Register the callback to ensure WebSocket is stopped on crash/exit - FCoreDelegates::OnExit.AddUObject(this, &AFicsitRemoteMonitoring::StopWebSocketServer); -} + // Use cached config values from the subsystem + const auto& HttpConfig = ConfigSubsystem->GetHttpConfig(); + const auto& SerialConfig = ConfigSubsystem->GetSerialConfig(); + const auto& FactoryConfig = ConfigSubsystem->GetFactoryConfig(); -FString AFicsitRemoteMonitoring::GenerateAuthToken(const int32 Length) -{ - const FString Characters = TEXT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); - const int32 CharactersCount = Characters.Len(); + // Save locally + JSONDebugMode = FactoryConfig.JSONDebugMode; - FString RandomString; - for (int32 i = 0; i < Length; ++i) + // Start services based on config + if (HttpConfig.Web_Autostart) { - RandomString.AppendChar(Characters[FMath::RandRange(0, CharactersCount - 1)]); + StartWebSocketServer(); } - return RandomString; + if (SerialConfig.COM_Autostart) + { + InitSerialDevice(); + } + + // Store token for use in auth checks + SetAuthToken(ConfigSubsystem->GetAuthenticationToken()); + + // Register the callback to ensure WebSocket is stopped on crash/exit + FCoreDelegates::OnExit.AddUObject(this, &AFicsitRemoteMonitoring::StopWebSocketServer); } void AFicsitRemoteMonitoring::StartWebSocketPushDataLoop() @@ -1082,4 +1083,9 @@ void AFicsitRemoteMonitoring::HandleEndpoint(FString InEndpoint, FRequestData Re TSharedPtr FirstJsonObject = JsonValues[0]->AsObject(); Out_Data = UFRM_RequestLibrary::JsonObjectToString(FirstJsonObject, JSONDebugMode); } +} + +void AFicsitRemoteMonitoring::SetAuthToken(const FString& Token) +{ + AuthenticationToken = Token; } \ No newline at end of file diff --git a/Source/FicsitRemoteMonitoring/Public/FRMConfigInitSubsystem.h b/Source/FicsitRemoteMonitoring/Public/FRMConfigInitSubsystem.h new file mode 100644 index 00000000..73efc6fb --- /dev/null +++ b/Source/FicsitRemoteMonitoring/Public/FRMConfigInitSubsystem.h @@ -0,0 +1,33 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Subsystems/GameInstanceSubsystem.h" +#include "Config_HTTPStruct.h" +#include "Config_SerialStruct.h" +#include "Config_FactoryStruct.h" +#include "FRMConfigInitSubsystem.generated.h" + +UCLASS() +class FICSITREMOTEMONITORING_API UFRMConfigInitSubsystem : public UGameInstanceSubsystem +{ + GENERATED_BODY() + +public: + virtual void Initialize(FSubsystemCollectionBase& Collection) override; + + UFUNCTION(BlueprintCallable, Category = "RemoteMonitoring") + FString GetAuthenticationToken() const { return AuthenticationToken; } + + const FConfig_HTTPStruct& GetHttpConfig() const { return HttpConfig; } + const FConfig_SerialStruct& GetSerialConfig() const { return SerialConfig; } + const FConfig_FactoryStruct& GetFactoryConfig() const { return FactoryConfig; } + +private: + FString AuthenticationToken; + + FConfig_HTTPStruct HttpConfig; + FConfig_SerialStruct SerialConfig; + FConfig_FactoryStruct FactoryConfig; + + FString GenerateAuthToken(int32 Length); +}; diff --git a/Source/FicsitRemoteMonitoring/Public/FicsitRemoteMonitoring.h b/Source/FicsitRemoteMonitoring/Public/FicsitRemoteMonitoring.h index 74d6fb4d..b6f927c1 100644 --- a/Source/FicsitRemoteMonitoring/Public/FicsitRemoteMonitoring.h +++ b/Source/FicsitRemoteMonitoring/Public/FicsitRemoteMonitoring.h @@ -104,6 +104,8 @@ class FICSITREMOTEMONITORING_API AFicsitRemoteMonitoring : public AModSubsystem bool JSONDebugMode = false; bool bShouldStop = false; bool bHasRunningPushDataLoop = false; + + FString AuthenticationToken; friend class UFGPowerCircuitGroup; @@ -112,6 +114,9 @@ class FICSITREMOTEMONITORING_API AFicsitRemoteMonitoring : public AModSubsystem AFicsitRemoteMonitoring(); virtual ~AFicsitRemoteMonitoring(); + void SetAuthToken(const FString& Token); + FString GetAuthToken() const { return AuthenticationToken; } + friend class UFGServerSubsystem; friend class UFGServerAPIManager; diff --git a/Source/FicsitRemoteMonitoringServer/FicsitRemoteMonitoringServer.build.cs b/Source/FicsitRemoteMonitoringServer/FicsitRemoteMonitoringServer.build.cs index e61d8e51..5976b616 100644 --- a/Source/FicsitRemoteMonitoringServer/FicsitRemoteMonitoringServer.build.cs +++ b/Source/FicsitRemoteMonitoringServer/FicsitRemoteMonitoringServer.build.cs @@ -42,9 +42,9 @@ public FicsitRemoteMonitoringServer(ReadOnlyTargetRules Target) : base(Target) public void ApplySMLPatch() { + // Example ModuleDirectory: C:\Modding\Satisfactory\SatisfactoryModLoader\Mods\FicsitRemoteMonitoring\Source\FicsitRemoteMonitoring string patchPath = Path.Combine(ModuleDirectory, "..", "..", "Patches", "FGServerAPIManager-FRM-04162025.patch"); - string headerPath = Path.Combine(ModuleDirectory, "..", "..", "FactoryGame", "Source", "FactoryDedicatedServer", - "Public", "Networking", "FGServerAPIManager.h"); + string headerPath = Path.Combine(ModuleDirectory, "..", "..", "..", "..", "Source", "FactoryDedicatedServer", "Public", "Networking", "FGServerAPIManager.h"); // Check if the target line is still 'private:' before patching bool needsPatch = false; From 389886f056df71af0e57fd5aa38562f8d8136016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Skyler=20M=C3=A4ntysaari?= Date: Fri, 13 Feb 2026 13:46:27 +0200 Subject: [PATCH 2/3] fix: The build configuration for ThirdParty deps Sometimes it would not copy the ThirdParty dependencies to the packaged mod --- Source/FicsitRemoteMonitoring/FicsitRemoteMonitoring.build.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/FicsitRemoteMonitoring/FicsitRemoteMonitoring.build.cs b/Source/FicsitRemoteMonitoring/FicsitRemoteMonitoring.build.cs index da6f245f..8ab4880f 100644 --- a/Source/FicsitRemoteMonitoring/FicsitRemoteMonitoring.build.cs +++ b/Source/FicsitRemoteMonitoring/FicsitRemoteMonitoring.build.cs @@ -97,8 +97,8 @@ public bool LoaduWebSockets(ReadOnlyTargetRules Target) }); } - RuntimeDependencies.Add(Path.Combine(LibrariesPath, "zlib1.dll")); - RuntimeDependencies.Add(Path.Combine(LibrariesPath, "uv.dll")); + RuntimeDependencies.Add("$(BinaryOutputDir)/uv.dll", Path.Combine(LibrariesPath, "uv.dll")); + RuntimeDependencies.Add("$(BinaryOutputDir)/zlib1.dll", Path.Combine(LibrariesPath, "zlib1.dll")); CopyToBinaries(Path.Combine(LibrariesPath, "zlib1.dll"), Target); CopyToBinaries(Path.Combine(LibrariesPath, "uv.dll"), Target); From b8e4302bebc65639502630abdeed8820d1416259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Skyler=20M=C3=A4ntysaari?= Date: Fri, 13 Feb 2026 13:47:33 +0200 Subject: [PATCH 3/3] fix: move the saving of config to config subsystem This keeps the concerns seperate, as the struct is now just a data struct. --- .../Private/FRMConfigInitSubsystem.cpp | 27 +++++++++++++++++-- .../Public/Configs/Config_HTTPStruct.h | 14 ---------- .../Public/FRMConfigInitSubsystem.h | 3 +++ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Source/FicsitRemoteMonitoring/Private/FRMConfigInitSubsystem.cpp b/Source/FicsitRemoteMonitoring/Private/FRMConfigInitSubsystem.cpp index 27f5cc9b..bf878887 100644 --- a/Source/FicsitRemoteMonitoring/Private/FRMConfigInitSubsystem.cpp +++ b/Source/FicsitRemoteMonitoring/Private/FRMConfigInitSubsystem.cpp @@ -1,5 +1,6 @@ #include "FRMConfigInitSubsystem.h" #include "Configuration/ConfigManager.h" +#include "ConfigPropertyString.h" #include "Engine/Engine.h" void UFRMConfigInitSubsystem::Initialize(FSubsystemCollectionBase& Collection) @@ -23,7 +24,7 @@ void UFRMConfigInitSubsystem::Initialize(FSubsystemCollectionBase& Collection) if (HttpConfig.Authentication_Token.IsEmpty()) { HttpConfig.Authentication_Token = GenerateAuthToken(32); - HttpConfig.Save(GetWorld()); + SaveHttpAuthToken(ConfigManager); UE_LOG(LogTemp, Log, TEXT("[FRMConfigInitSubsystem] Generated and saved new token: %s"), *HttpConfig.Authentication_Token); } @@ -35,6 +36,28 @@ void UFRMConfigInitSubsystem::Initialize(FSubsystemCollectionBase& Collection) AuthenticationToken = HttpConfig.Authentication_Token; } +void UFRMConfigInitSubsystem::SaveHttpAuthToken(UConfigManager* ConfigManager) +{ + FConfigId ConfigId{ "FicsitRemoteMonitoring", "WebServer" }; + + UConfigPropertySection* ConfigurationRootSection = ConfigManager->GetConfigurationRootSection(ConfigId); + if (!ConfigurationRootSection) + { + UE_LOG(LogTemp, Warning, TEXT("[FRMConfigInitSubsystem] ConfigurationRootSection is null.")); + return; + } + + if (ConfigurationRootSection->SectionProperties.Contains("Authentication_Token")) + { + if (UConfigPropertyString* AuthTokenProperty = Cast(ConfigurationRootSection->SectionProperties["Authentication_Token"])) + { + AuthTokenProperty->Value = HttpConfig.Authentication_Token; + } + } + + ConfigManager->MarkConfigurationDirty(ConfigId); +} + FString UFRMConfigInitSubsystem::GenerateAuthToken(const int32 Length) { const FString Characters = TEXT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); @@ -47,4 +70,4 @@ FString UFRMConfigInitSubsystem::GenerateAuthToken(const int32 Length) } return RandomString; -} +} \ No newline at end of file diff --git a/Source/FicsitRemoteMonitoring/Public/Configs/Config_HTTPStruct.h b/Source/FicsitRemoteMonitoring/Public/Configs/Config_HTTPStruct.h index 3a685671..04a1bcf1 100644 --- a/Source/FicsitRemoteMonitoring/Public/Configs/Config_HTTPStruct.h +++ b/Source/FicsitRemoteMonitoring/Public/Configs/Config_HTTPStruct.h @@ -35,19 +35,5 @@ struct FConfig_HTTPStruct { } return ConfigStruct; } - - void Save(UWorld* World) - { - FConfigId ConfigId{"FicsitRemoteMonitoring", "WebServer"}; - UConfigManager* ConfigManager = World->GetGameInstance()->GetSubsystem(); - UConfigPropertySection* ConfigurationRootSection = ConfigManager->GetConfigurationRootSection(ConfigId); - - if (ConfigurationRootSection->SectionProperties.Contains("Authentication_Token")) - { - Cast(ConfigurationRootSection->SectionProperties["Authentication_Token"])->Value = Authentication_Token; - } - - ConfigManager->MarkConfigurationDirty(ConfigId); - } }; diff --git a/Source/FicsitRemoteMonitoring/Public/FRMConfigInitSubsystem.h b/Source/FicsitRemoteMonitoring/Public/FRMConfigInitSubsystem.h index 73efc6fb..053045b7 100644 --- a/Source/FicsitRemoteMonitoring/Public/FRMConfigInitSubsystem.h +++ b/Source/FicsitRemoteMonitoring/Public/FRMConfigInitSubsystem.h @@ -7,6 +7,8 @@ #include "Config_FactoryStruct.h" #include "FRMConfigInitSubsystem.generated.h" +class UConfigManager; + UCLASS() class FICSITREMOTEMONITORING_API UFRMConfigInitSubsystem : public UGameInstanceSubsystem { @@ -30,4 +32,5 @@ class FICSITREMOTEMONITORING_API UFRMConfigInitSubsystem : public UGameInstanceS FConfig_FactoryStruct FactoryConfig; FString GenerateAuthToken(int32 Length); + void SaveHttpAuthToken(UConfigManager* ConfigManager); };