diff --git a/FicsitRemoteMonitoring.uplugin b/FicsitRemoteMonitoring.uplugin index d43aa975..6f9aba98 100644 --- a/FicsitRemoteMonitoring.uplugin +++ b/FicsitRemoteMonitoring.uplugin @@ -1,8 +1,8 @@ { "FileVersion": 3, "Version": 1, - "VersionName": "1.4.7", - "SemVersion": "1.4.7", + "VersionName": "1.4.9", + "SemVersion": "1.4.9", "AcceptsAnyRemoteVersion": true, "FriendlyName": "Ficsit Remote Monitoring", "Description": "Statistical and GeoLocation Monitoring for Satisfactory", 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); diff --git a/Source/FicsitRemoteMonitoring/Private/FRMConfigInitSubsystem.cpp b/Source/FicsitRemoteMonitoring/Private/FRMConfigInitSubsystem.cpp new file mode 100644 index 00000000..bf878887 --- /dev/null +++ b/Source/FicsitRemoteMonitoring/Private/FRMConfigInitSubsystem.cpp @@ -0,0 +1,73 @@ +#include "FRMConfigInitSubsystem.h" +#include "Configuration/ConfigManager.h" +#include "ConfigPropertyString.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); + SaveHttpAuthToken(ConfigManager); + + 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; +} + +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"); + const int32 CharactersCount = Characters.Len(); + + FString RandomString; + for (int32 i = 0; i < Length; ++i) + { + RandomString.AppendChar(Characters[FMath::RandRange(0, CharactersCount - 1)]); + } + + return RandomString; +} \ No newline at end of file diff --git a/Source/FicsitRemoteMonitoring/Private/FicsitRemoteMonitoring.cpp b/Source/FicsitRemoteMonitoring/Private/FicsitRemoteMonitoring.cpp index f66038c1..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() @@ -792,7 +793,7 @@ void AFicsitRemoteMonitoring::InitAPIRegistry() // post/write endpoints RegisterEndpoint(FAPIEndpoint("POST", "setSwitches", &UPower::setSwitches).RequiresAuthentication().RequiresGameThread()); - RegisterEndpoint(FAPIEndpoint("POST", "setEnabled", &UCommunication::setEnabled).RequiresAuthentication()); + RegisterEndpoint(FAPIEndpoint("POST", "setEnabled", &UCommunication::setEnabled).RequiresAuthentication().RequiresGameThread()); RegisterEndpoint(FAPIEndpoint("POST", "sendChatMessage", &UCommunication::sendChatMessage).RequiresAuthentication().RequiresGameThread()); RegisterEndpoint(FAPIEndpoint("POST", "createPing", &UCommunication::createPing).RequiresAuthentication().RequiresGameThread()); RegisterEndpoint(FAPIEndpoint("POST", "setModSetting", &UCommunication::setModSetting).RequiresAuthentication().RequiresGameThread()); @@ -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/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 new file mode 100644 index 00000000..053045b7 --- /dev/null +++ b/Source/FicsitRemoteMonitoring/Public/FRMConfigInitSubsystem.h @@ -0,0 +1,36 @@ +#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" + +class UConfigManager; + +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); + void SaveHttpAuthToken(UConfigManager* ConfigManager); +}; 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;