diff --git a/Source/HarmonyLink/HarmonyLink.Build.cs b/Source/HarmonyLink/HarmonyLink.Build.cs index 725ae7e..ce895e9 100644 --- a/Source/HarmonyLink/HarmonyLink.Build.cs +++ b/Source/HarmonyLink/HarmonyLink.Build.cs @@ -52,23 +52,22 @@ public class HarmonyLink : ModuleRules } ); - // Platform-specific settings - if (Target.Platform == UnrealTargetPlatform.Win64) - { - PublicAdditionalLibraries.Add(Path.Combine(PluginDirectory, "Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.lib")); - RuntimeDependencies.Add("$(BinaryOutputDir)/HarmonyLinkLib.dll", Path.Combine(PluginDirectory, "Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.dll")); - } - else if (Target.Platform == UnrealTargetPlatform.Linux) - { - PublicAdditionalLibraries.Add(Path.Combine(PluginDirectory, "Source/ThirdParty/HarmonyLinkLib/bin/Linux/libHarmonyLinkLib.so")); - RuntimeDependencies.Add("$(BinaryOutputDir)/libHarmonyLinkLib.so", Path.Combine(PluginDirectory, "Source/ThirdParty/HarmonyLinkLib/bin/Linux/libHarmonyLinkLib.so")); - } - + // Platform-specific settings for static libraries + if (Target.Platform == UnrealTargetPlatform.Win64) + { + PublicAdditionalLibraries.Add(Path.Combine(PluginDirectory, "Source/ThirdParty/HarmonyLinkLib/lib/Win64/HarmonyLinkLibStatic.lib")); + PublicDefinitions.Add("HARMONYLINKLIB_STATIC=1"); + } + else if (Target.Platform == UnrealTargetPlatform.Linux) + { + PublicAdditionalLibraries.Add(Path.Combine(PluginDirectory, "Source/ThirdParty/HarmonyLinkLib/lib/Linux/libHarmonyLinkLibStatic.a")); + PublicDefinitions.Add("HARMONYLINKLIB_STATIC=1"); + } // I shall include this if anyone wishes to provide Mac binaries of HarmonyLink but these are not included by default as I don't own one. - else if (Target.Platform == UnrealTargetPlatform.Mac) - { - PublicAdditionalLibraries.Add(Path.Combine(PluginDirectory, "Source/ThirdParty/HarmonyLinkLib/bin/Mac/HarmonyLinkLib.dylib")); - RuntimeDependencies.Add("$(BinaryOutputDir)/HarmonyLinkLib.dylib", Path.Combine(PluginDirectory, "Source/ThirdParty/HarmonyLinkLib/bin/Mac/HarmonyLinkLib.dylib")); - } + else if (Target.Platform == UnrealTargetPlatform.Mac) + { + PublicAdditionalLibraries.Add(Path.Combine(PluginDirectory, "Source/ThirdParty/HarmonyLinkLib/lib/Mac/libHarmonyLinkLibStatic.a")); + PublicDefinitions.Add("HARMONYLINKLIB_STATIC=1"); + } } } diff --git a/Source/HarmonyLink/Private/HarmonyLinkLibrary.cpp b/Source/HarmonyLink/Private/HarmonyLinkLibrary.cpp index ed3f0d9..ac55833 100644 --- a/Source/HarmonyLink/Private/HarmonyLinkLibrary.cpp +++ b/Source/HarmonyLink/Private/HarmonyLinkLibrary.cpp @@ -11,13 +11,7 @@ bool UHarmonyLinkLibrary::IsWine() bool UHarmonyLinkLibrary::IsLinux() { -#if PLATFORM_WINDOWS - return IsWine(); -#elif PLATFORM_LINUX - return true; -#else - return false; -#endif + return HarmonyLinkLib::get_is_linux(); } bool UHarmonyLinkLibrary::IsSteamDeck() diff --git a/Source/HarmonyLink/Private/Objects/HarmonyLinkGraphics.cpp b/Source/HarmonyLink/Private/Objects/HarmonyLinkGraphics.cpp index 33832a6..3f05b62 100644 --- a/Source/HarmonyLink/Private/Objects/HarmonyLinkGraphics.cpp +++ b/Source/HarmonyLink/Private/Objects/HarmonyLinkGraphics.cpp @@ -9,7 +9,20 @@ UHarmonyLinkGraphics* UHarmonyLinkGraphics::_INSTANCE = nullptr; int32 UHarmonyLinkGraphics::_TickRate = 1; +FTimerHandle UHarmonyLinkGraphics::_TickTimerHandle = FTimerHandle(); +/** + * @brief Default graphics settings for different power states in HarmonyLink. + * + * This map defines the default configuration values for various graphics settings based on the power state of the device. + * The outer map's key is the power state (e.g., "Battery", "Charging", "Docked"). + * The inner map contains key-value pairs where the key is the setting name and the value is the corresponding configuration value. + * + * Power States: + * - "Battery": Settings for when the device is running on battery power. + * - "Charging": Settings for when the device is charging. + * - "Docked": Settings for when the device is docked. + */ TMap> UHarmonyLinkGraphics::_DefaultSettings = { { "Battery", { { TEXT("r.ReflectionMethod"), FHLConfigValue(0) }, @@ -34,8 +47,7 @@ TMap> UHarmonyLinkGraphics::_DefaultSettings UHarmonyLinkGraphics::UHarmonyLinkGraphics() { UE_LOG(LogHarmonyLink, Warning, TEXT("HarmonyLinkGraphics initialized.")); - - _bAutomaticSwitch = true; + FWorldDelegates::OnPostWorldInitialization.AddUObject(this, &UHarmonyLinkGraphics::OnPostWorldInitialization); FWorldDelegates::OnPreWorldFinishDestroy.AddUObject(this, &UHarmonyLinkGraphics::OnWorldEnd); } @@ -50,25 +62,29 @@ void UHarmonyLinkGraphics::LoadConfig(const bool bForceReload) QUICK_SCOPE_CYCLE_COUNTER(HarmonyLinkGraphics_LoadSettings); // Load the settings into the map - if (!LoadSettingsFromConfig()) + if (!LoadSettingsFromConfig(false)) { - // Retry 2nd time - LoadSettingsFromConfig(); + if (!LoadSettingsFromConfig(true)) + { + CreateDefaultConfigFile(); + // Retry 2nd time + LoadSettingsFromConfig(true); + } } DebugPrintProfiles(); } -bool UHarmonyLinkGraphics::LoadSettingsFromConfig() +bool UHarmonyLinkGraphics::LoadSettingsFromConfig(const bool bLoadDefaults) { // Load the configuration from the INI file FConfigFile ConfigFile; - const FString Filename = GetConfigDirectoryFile(); + const FString Filename = GetConfigDirectoryFile(bLoadDefaults); if (!GConfig) { - UE_LOG(LogHarmonyLink, Error, TEXT("Failed to access GConfig!")) + UE_LOG(LogHarmonyLink, Error, TEXT("Failed to access GConfig!")); return false; } @@ -77,6 +93,20 @@ bool UHarmonyLinkGraphics::LoadSettingsFromConfig() // Load each profile section bool bLoaded = true; + // Load the _bAutomaticSwitch variable + const FString SectionName = TEXT("HarmonyLink"); + const FString KeyName = TEXT("AutomaticProfileSwitch"); + + if (!GConfig->GetBool(*SectionName, *KeyName, _bAutomaticSwitch, Filename)) + { + UE_LOG(LogHarmonyLink, Error, TEXT("Failed to load bAutomaticSwitch from config")); + bLoaded = false; + } + else + { + UE_LOG(LogHarmonyLink, Log, TEXT("Loaded bAutomaticSwitch: %s"), _bAutomaticSwitch ? TEXT("true") : TEXT("false")); + } + for (const TPair& Profile : _ProfileNames) { if (!LoadSection(ConfigFile, Profile)) @@ -86,7 +116,7 @@ bool UHarmonyLinkGraphics::LoadSettingsFromConfig() } } - // Check if all profiles were loaded successfully + // Check if all profiles and settings were loaded successfully if (bLoaded) { UE_LOG(LogHarmonyLink, Log, TEXT("Successfully loaded config file: %s"), *Filename); @@ -95,7 +125,6 @@ bool UHarmonyLinkGraphics::LoadSettingsFromConfig() } UE_LOG(LogHarmonyLink, Error, TEXT("Failed to load config file: %s"), *Filename); - CreateDefaultConfigFile(); return false; } @@ -151,20 +180,17 @@ bool UHarmonyLinkGraphics::LoadSection(const FConfigFile& ConfigFile, const TPai void UHarmonyLinkGraphics::SaveConfig() const { - QUICK_SCOPE_CYCLE_COUNTER(HarmonyLinkGraphics_SaveConfig); - - for (TPair Profile : _Profiles) - { - SaveSection(Profile.Value); - } - - const FString Filename = GetConfigDirectoryFile(); - UE_LOG(LogHarmonyLink, Log, TEXT("Flushing file: '%s'"), *Filename); - GConfig->Flush(false, Filename); + Intermal_SaveConfig(false); } void UHarmonyLinkGraphics::SetSetting(const EProfile Profile, const FName Setting, const FHLConfigValue Value) { + // Ignore if HarmonyLinkSettings is disabled + if (Profile == EProfile::NONE) + { + return; + } + // Find the profile name associated with the given EProfile const FName* ProfileName = _ProfileNames.Find(Profile); @@ -230,6 +256,12 @@ UHarmonyLinkGraphics* UHarmonyLinkGraphics::GetSettings() FSettingsProfile UHarmonyLinkGraphics::GetSettingProfile(const EProfile Profile) { + // Ignore if HarmonyLinkSettings is disabled + if (Profile == EProfile::NONE) + { + return FSettingsProfile(); + } + // Find the profile name associated with the given EProfile const FName* ProfileName = _ProfileNames.Find(Profile); @@ -249,7 +281,6 @@ FSettingsProfile UHarmonyLinkGraphics::GetSettingProfile(const EProfile Profile) } return *SettingsProfile; - } EProfile UHarmonyLinkGraphics::GetActiveProfile() const @@ -286,16 +317,35 @@ void UHarmonyLinkGraphics::Init() LoadConfig(); const FBattery BatteryStatus = UHarmonyLinkLibrary::GetBatteryStatus(); - - // Enabled for development testing - // At some point I need to implement the ability to fake and emulate these settings to make it easier to test - // BUG: Remove this before release! - if (!BatteryStatus.HasBattery) + + if (BatteryStatus.HasBattery) { ApplyProfileInternal(EProfile::BATTERY); } } +void UHarmonyLinkGraphics::Intermal_SaveConfig(const bool bDefaultConfig) const +{ + QUICK_SCOPE_CYCLE_COUNTER(HarmonyLinkGraphics_SaveConfig); + + const FString Filename = GetConfigDirectoryFile(bDefaultConfig); + const FString SectionName = TEXT("HarmonyLink"); + const FString KeyName = TEXT("AutomaticProfileSwitch"); + + // Save the _bAutomaticSwitch variable + GConfig->SetBool(*SectionName, *KeyName, _bAutomaticSwitch, Filename); + + UE_LOG(LogHarmonyLink, Log, TEXT("Saving bAutomaticSwitch: %s"), _bAutomaticSwitch ? TEXT("true") : TEXT("false")); + + for (const TPair& Profile : _Profiles) + { + SaveSection(Profile.Value, bDefaultConfig); + } + + UE_LOG(LogHarmonyLink, Log, TEXT("Flushing file: '%s'"), *Filename); + GConfig->Flush(true, Filename); +} + void UHarmonyLinkGraphics::Tick() { Async(EAsyncExecution::Thread, [this]() @@ -347,27 +397,23 @@ void UHarmonyLinkGraphics::CreateDefaultConfigFile() UE_LOG(LogHarmonyLink, Log, TEXT("Creating default config file.")); LoadDefaults(); - SaveConfig(); + Intermal_SaveConfig(true); UE_LOG(LogHarmonyLink, Log, TEXT("Default config file created.")); } -FString UHarmonyLinkGraphics::GetConfigDirectoryFile() +FString UHarmonyLinkGraphics::GetConfigDirectoryFile(const bool bDefaultFolder) { - FString ConfigFileName = "HarmonyLink.ini"; // Replace with your actual config file name + FString ConfigFileName = bDefaultFolder? "DefaultHarmonyLink.ini" : "HarmonyLink.ini"; // Replace with your actual config file name -#if WITH_EDITOR - return FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("Config"), ConfigFileName); -#else - return FPaths::Combine(FPaths::ProjectConfigDir(), ConfigFileName); -#endif + return FPaths::Combine(bDefaultFolder ? FPaths::ProjectConfigDir() : FPaths::GeneratedConfigDir(), ConfigFileName); } -void UHarmonyLinkGraphics::SaveSection(FSettingsProfile& SettingsProfile, const bool bFlush) +void UHarmonyLinkGraphics::SaveSection(const FSettingsProfile& SettingsProfile, const bool bDefaultConfig, const bool bFlush) { if (GConfig) { - const FString Filename = GetConfigDirectoryFile(); + const FString Filename = GetConfigDirectoryFile(bDefaultConfig); for (const auto& Setting : SettingsProfile.Settings) { FString TypeString; @@ -490,7 +536,7 @@ bool UHarmonyLinkGraphics::ApplyProfileInternal(const EProfile Profile) void UHarmonyLinkGraphics::OnPostWorldInitialization(UWorld* World, UWorld::InitializationValues IVS) { - if (!World) + if (!World || !World->IsValidLowLevel()) { UE_LOG(LogHarmonyLink, Error, TEXT("Failed to Hook into World Initialisation!")) return; @@ -498,18 +544,29 @@ void UHarmonyLinkGraphics::OnPostWorldInitialization(UWorld* World, UWorld::Init if (World->IsGameWorld()) { - if (UHarmonyLinkGraphics* Settings = GetSettings()) + if (_INSTANCE) { - if (World->IsPlayInEditor()) + FTimerManager* TimerManager = &World->GetTimerManager(); + if (!TimerManager) { - Settings->LoadConfig(true); + UE_LOG(LogHarmonyLink, Error, TEXT("Failed get TimerManager!")) + return; } - - if (!World->GetTimerManager().TimerExists(Settings->_TickTimerHandle) || !World->GetTimerManager().IsTimerActive(Settings->_TickTimerHandle)) + + if (!TimerManager->TimerExists(_INSTANCE->_TickTimerHandle) || !TimerManager->IsTimerActive(_INSTANCE->_TickTimerHandle)) { - World->GetTimerManager().SetTimer(Settings->_TickTimerHandle, [Settings] + World->GetTimerManager().SetTimer(_INSTANCE->_TickTimerHandle, [&, TimerManager] { - Settings->Tick(); + if (!this) + { + UE_LOG(LogHarmonyLink, Error, TEXT("'This' is destroyed, Clearing timer.")) + if (TimerManager) + { + TimerManager->ClearTimer(_TickTimerHandle); + } + return; + } + Tick(); }, _TickRate, true); } } @@ -518,7 +575,7 @@ void UHarmonyLinkGraphics::OnPostWorldInitialization(UWorld* World, UWorld::Init void UHarmonyLinkGraphics::OnWorldEnd(UWorld* World) { - if (!World) + if (!World || !World->IsValidLowLevel()) { UE_LOG(LogHarmonyLink, Error, TEXT("World Already destroyed")) return; @@ -533,10 +590,10 @@ void UHarmonyLinkGraphics::OnWorldEnd(UWorld* World) DestroySettings(); } -bool UHarmonyLinkGraphics::ApplyProfile(const EProfile Profile, const bool bDisableAuto) +bool UHarmonyLinkGraphics::ApplyProfile(const EProfile Profile, const bool bDisableAutomaticSwitch) { // Manual profile change, turn off automatic switching - if (bDisableAuto) + if (bDisableAutomaticSwitch) { _bAutomaticSwitch = false; } diff --git a/Source/HarmonyLink/Public/Enums/Platform.h b/Source/HarmonyLink/Public/Enums/Platform.h index 2ffb255..9ab89dc 100644 --- a/Source/HarmonyLink/Public/Enums/Platform.h +++ b/Source/HarmonyLink/Public/Enums/Platform.h @@ -5,6 +5,9 @@ #include "CoreMinimal.h" #include "Platform.generated.h" +// Undefine the LINUX macro to avoid conflicts with the enum definition. +#undef LINUX + /* * Enum representing different operating system platforms. */ diff --git a/Source/HarmonyLink/Public/Objects/HarmonyLinkGraphics.h b/Source/HarmonyLink/Public/Objects/HarmonyLinkGraphics.h index e9a486e..3b0836e 100644 --- a/Source/HarmonyLink/Public/Objects/HarmonyLinkGraphics.h +++ b/Source/HarmonyLink/Public/Objects/HarmonyLinkGraphics.h @@ -33,81 +33,468 @@ public: UPROPERTY(BlueprintAssignable) FOnBatteryLevelChanged OnBatteryLevelChanged; - + + /** + * @brief Loads the graphics configuration settings. + * + * This function loads the graphics settings into the appropriate map. If the initial loading attempt fails, + * it retries a second time. The settings are loaded using the `LoadSettingsFromConfig` method. + * After loading the settings, the function prints debug information about the profiles. + * + * @param bForceReload Indicates whether to force reload the settings. Defaults to false. + * + * @note This function uses the QUICK_SCOPE_CYCLE_COUNTER macro for performance profiling. + */ UFUNCTION(BlueprintCallable, Category="HarmonyLink Settings") void LoadConfig(const bool bForceReload = false); + /** + * @brief Saves the current graphics configuration settings to the configuration file. + * + * This function iterates through all profiles and saves their settings to the configuration file. + * Additionally, it saves the `_bAutomaticSwitch` variable to the configuration file and flushes the changes. + * + * @details + * - Uses the QUICK_SCOPE_CYCLE_COUNTER macro for performance profiling. + * - Iterates through the `_Profiles` map and calls `SaveSection` for each profile to save its settings. + * - Saves the `_bAutomaticSwitch` variable under the "HarmonyLink" section with the key "AutomaticProfileSwitch". + * - Logs the status of `_bAutomaticSwitch` and flushes the configuration file to ensure all changes are written. + * + * @note Uses UE_LOG for logging the save process and status messages. + */ UFUNCTION(BlueprintCallable, Category="HarmonyLink Settings") void SaveConfig() const; + /** + * @brief Sets a specific configuration value for a given profile. + * + * This function updates a setting for a specified profile with a new value. It handles various data types (int, float, bool, string) + * and logs the process. If the profile or settings cannot be found, it logs an error message. + * + * @param Profile The profile identifier for which the setting is to be updated. + * @param Setting The name of the setting to update. + * @param Value The new value to set for the specified setting. + * + * @details + * - Finds the profile name associated with the given `EProfile`. + * - Determines the type of the value and converts it to a string. + * - Logs the application of the setting with its value and type. + * - Finds the settings profile associated with the given profile. + * - Updates the setting with the new value or adds it if it does not exist. + * + * @note Uses UE_LOG for logging the update process and any errors. + */ UFUNCTION(BlueprintCallable, Category="HarmonyLink Settings") void SetSetting(EProfile Profile, FName Setting, FHLConfigValue Value); + /** + * @brief Applies the specified graphics profile. + * + * This function applies the given graphics profile. If automatic profile switching is enabled, it can be disabled by setting the `bDisableAutomaticSwitch` parameter to true. + * + * @param Profile The profile to apply. + * @param bDisableAutomaticSwitch Indicates whether to disable automatic profile switching. Defaults to true. + * @return bool Returns true if the profile was successfully applied; false otherwise. + * + * @details + * - If `bDisableAutomaticSwitch` is true, sets `_bAutomaticSwitch` to false to disable automatic profile switching. + * - Calls `ApplyProfileInternal` to apply the specified profile. + * - Returns the result of `ApplyProfileInternal`. + */ UFUNCTION(BlueprintCallable, Category="HarmonyLink Settings") - bool ApplyProfile(EProfile Profile, const bool bDisableAuto = true); + bool ApplyProfile(EProfile Profile, const bool bDisableAutomaticSwitch = true); - /** Returns the game local machine settings (resolution, windowing mode, scalability settings, etc...) */ + /** + * @brief Retrieves the singleton instance of the UHarmonyLinkGraphics settings. + * + * This function returns the singleton instance of the `UHarmonyLinkGraphics` class. If the instance has not been + * initialized, it creates a new instance, adds it to the root to prevent garbage collection, initializes it, and + * then returns the instance. + * + * @return UHarmonyLinkGraphics* The singleton instance of the `UHarmonyLinkGraphics` class. + * + * @details + * - Checks if the singleton instance (`_INSTANCE`) is already initialized. + * - If not, creates a new instance using `NewObject`. + * - Adds the new instance to the root to prevent it from being garbage collected. + * - Calls the `Init` function on the new instance to perform any necessary initialization. + * - Returns the singleton instance. + */ UFUNCTION(BlueprintCallable, Category="HarmonyLink Settings") static UHarmonyLinkGraphics* GetSettings(); + /** + * @brief Retrieves the settings profile for a specified profile. + * + * This function returns the settings profile associated with the given `EProfile`. If the profile name or the settings + * cannot be found, it logs an error message and returns an empty `FSettingsProfile`. + * + * @param Profile The profile identifier for which the settings profile is to be retrieved. + * @return FSettingsProfile The settings profile associated with the specified profile. If the profile is not found, returns an empty `FSettingsProfile`. + * + * @details + * - Finds the profile name associated with the given `EProfile`. + * - Logs an error and returns an empty `FSettingsProfile` if the profile name is not found. + * - Finds the settings profile associated with the profile. + * - Logs an error and returns an empty `FSettingsProfile` if the settings profile is not found. + * - Returns the settings profile if found. + * + * @note Uses UE_LOG for logging errors. + */ UFUNCTION(BlueprintCallable, BlueprintPure, Category="HarmonyLink Settings") FSettingsProfile GetSettingProfile(const EProfile Profile); + /** + * @brief Retrieves the currently active profile. + * + * This function returns the currently active profile of the `UHarmonyLinkGraphics` settings. + * + * @return EProfile The currently active profile. + */ UFUNCTION(BlueprintCallable, BlueprintPure, Category="HarmonyLink Settings") EProfile GetActiveProfile() const; + /** + * @brief Sets the automatic profile switching state. + * + * This function updates the automatic profile switching setting and broadcasts the change. + * + * @param bAutomaticSwitch Indicates whether automatic profile switching should be enabled (true) or disabled (false). + * + * @details + * - Updates the `_bAutomaticSwitch` member variable with the new value. + * - Broadcasts the change to any listeners using the `OnAutomaticSwitchChanged` delegate. + */ UFUNCTION(BlueprintCallable, Category="HarmonyLink Settings") void SetAutomaticSwitching(const bool bAutomaticSwitch); + /** + * @brief Retrieves the current state of automatic profile switching. + * + * This function returns the state of the automatic profile switching setting. + * + * @return bool True if automatic profile switching is enabled; false otherwise. + */ UFUNCTION(BlueprintCallable, BlueprintPure, Category="HarmonyLink Settings") bool GetAutomaticSwitching() const; + /** + * @brief Destroys the singleton instance of the UHarmonyLinkGraphics settings. + * + * This function safely destroys the singleton instance of the `UHarmonyLinkGraphics` class by removing it from root, + * marking it as garbage for cleanup, and setting the instance pointer to null. + * + * @details + * - Checks if the singleton instance (`_INSTANCE`) exists. + * - Logs the destruction of the `UHarmonyLinkGraphics` instance. + * - Removes all delegate bindings from `_INSTANCE`. + * - Removes `_INSTANCE` from the root to allow garbage collection. + * - Marks `_INSTANCE` as garbage to enable cleanup. + * - Sets `_INSTANCE` to null. + * + * @note Uses UE_LOG for logging the destruction process. + */ static void DestroySettings(); private: + /** + * @brief Initializes the UHarmonyLinkGraphics settings. + * + * This function initializes the `UHarmonyLinkGraphics` settings by loading the configuration and applying the + * appropriate profile based on the battery status. + * + * @details + * - Calls `LoadConfig` to load the configuration settings. + * - Retrieves the current battery status using `UHarmonyLinkLibrary::GetBatteryStatus`. + * - If the device has a battery, applies the `BATTERY` profile by calling `ApplyProfileInternal`. + */ void Init(); + + void Intermal_SaveConfig(const bool bDefaultConfig) const; + + /** + * @brief Periodically checks and updates the battery status and profile settings. + * + * This function is executed based on a timer determined by `_TickRate`. It asynchronously checks the current battery status + * and updates the battery percentage and profile settings as needed. If the battery percentage has changed, it broadcasts + * this change. If automatic profile switching is enabled, it applies the appropriate profile based on the AC connection status. + * + * @details + * - Runs asynchronously on a separate thread to fetch the current battery status using `UHarmonyLinkLibrary::GetBatteryStatus`. + * - If the battery percentage has changed, broadcasts the new battery percentage in a thread-safe manner. + * - If automatic profile switching (`_bAutomaticSwitch`) is disabled, exits the function. + * - If the device has a battery: + * - Checks the AC connection status and applies the `CHARGING` profile if connected to AC. + * - Applies the `BATTERY` profile if not connected to AC. + * - Ensures all profile applications and broadcasts are executed on the main thread for thread safety. + * + * @note Uses UE_LOG for logging and `Async` for asynchronous execution. + */ void Tick(); + + /** + * @brief Creates a default configuration file. + * + * This function creates a default configuration file by loading the default settings and then saving them to the config file. + * + * @details + * - Logs the start of the default configuration file creation process. + * - Calls `LoadDefaults` to load the default settings into the configuration. + * - Calls `SaveConfig` to save the default settings to the configuration file. + * - Logs the completion of the default configuration file creation process. + * + * @note Uses UE_LOG for logging the creation process. + */ void CreateDefaultConfigFile(); - static FString GetConfigDirectoryFile(); - bool LoadSettingsFromConfig(); + + /** + * @brief Retrieves the path to the configuration file. + * + * This function constructs and returns the full path to the configuration file used by the `UHarmonyLinkGraphics` settings. + * + * @return FString The full path to the configuration file. + * + * @details + * - Defines the configuration file name as "HarmonyLink.ini". + * - Combines the generated config directory path with the configuration file name to form the full path. + * - Returns the full path to the configuration file. + */ + static FString GetConfigDirectoryFile(const bool bDefaultFolder); + + /** + * @brief Loads the settings from the configuration file. + * + * This function loads the graphics settings from an INI configuration file into the appropriate structures. + * It attempts to load each profile section and the automatic switch setting. If any section fails to load, + * it logs an error message and indicates failure. If loading is successful, it logs a success message. + * + * @return true if the settings were successfully loaded; false otherwise. + * + * @details + * - Loads the configuration file specified by `GetConfigDirectoryFile`. + * - Iterates over the `_ProfileNames` to load each profile section. + * - Loads the `_bAutomaticSwitch` variable from the config. + * - If loading fails, it attempts to create a default configuration file. + * + * @note Uses UE_LOG for logging errors and success messages. + */ + bool LoadSettingsFromConfig(const bool bLoadDefaults); + + /** + * @brief Loads a specific section from the configuration file into a settings profile. + * + * This function extracts settings from a specified section of the configuration file and stores them in the corresponding profile. + * It handles different data types (int, float, bool, string) and parses them accordingly. If the section is found and loaded successfully, + * the settings are added to the profile's settings map. + * + * @param ConfigFile The configuration file from which to load the section. + * @param Profile The profile key-value pair containing the profile enum and the section name. + * @return true if the section was found and loaded successfully; false otherwise. + * + * @details + * - Finds the section in the configuration file using the section name from the profile. + * - Clears any previous settings in the profile. + * - Iterates through the settings in the section, parsing the value and type, and adds them to the profile's settings map. + * + * @note The function handles settings of types int, float, bool, and string. + */ bool LoadSection(const FConfigFile& ConfigFile, const TPair Profile); - static void SaveSection(FSettingsProfile& SettingsProfile, const bool bFlush = false); + + + /** + * @brief Saves the settings of a given profile section to the configuration file. + * + * This function saves the settings of a specified profile section to the configuration file. It handles various data types + * (int, float, bool, string) and formats them accordingly before saving. If the `bFlush` parameter is true, the configuration + * file is flushed to ensure all changes are written to disk. + * + * @param SettingsProfile The settings profile to be saved. + * @param bFlush Indicates whether to flush the configuration file after saving. Defaults to false. + * + * @details + * - Checks if the global configuration object (`GConfig`) is available. + * - Constructs the full path to the configuration file using `GetConfigDirectoryFile`. + * - Iterates through the settings in the provided `SettingsProfile`. + * - Determines the type and value of each setting and formats them as strings. + * - Sets the formatted string in the configuration file for each setting. + * - Logs the save operation. + * - If `bFlush` is true, flushes the configuration file to ensure all changes are written. + * + * @note Uses UE_LOG for logging the save and flush operations. + */ + static void SaveSection(const FSettingsProfile& SettingsProfile, const bool bDefaultConfig, const bool bFlush = false); + + /** + * @brief Loads the default settings into the profiles. + * + * This function resets the current profiles and loads the default settings into the profiles. It iterates over the profile names + * and assigns the default settings to each profile. + * + * @details + * - Logs the start of the `LoadDefaults` process. + * - Resets the `_Profiles` map to clear any existing settings. + * - Iterates over `_ProfileNames` to create default settings for each profile. + * - For each profile, initializes a `FSettingsProfile` with the section name. + * - If default settings are found for the profile in `_DefaultSettings`, assigns these settings to the profile. + * - Adds the newly created profile settings to `_Profiles`. + * + * @note Uses UE_LOG for logging the start of the default settings loading process. + */ void LoadDefaults(); + + /** + * @brief Applies the specified graphics profile internally. + * + * This function applies the given graphics profile by either reverting to the original user game settings or + * applying the settings associated with the specified profile. + * + * @param Profile The profile to apply. If the profile is `EProfile::NONE`, the function reverts to the original user game settings. + * @return bool Returns true if the profile was successfully applied; false otherwise. + * + * @details + * - If the `Profile` is `EProfile::NONE`: + * - Logs a message indicating reversion to original user game settings. + * - Retrieves the user game settings and applies them. + * - Sets `_ActiveProfile` to `EProfile::NONE` and broadcasts the profile change. + * - Returns true if successful, false otherwise. + * - Finds the profile name associated with the given `EProfile`. + * - Logs an error and returns false if the profile name is not found. + * - Logs a message indicating the profile being applied. + * - Finds the settings associated with the profile. + * - Logs a warning and returns false if the settings profile is not found. + * - Creates a render state context for applying settings. + * - Iterates through each setting in the profile and applies it using `ApplySetting`. + * - Sets `_ActiveProfile` to the specified profile and broadcasts the profile change. + * - Returns true indicating the profile was successfully applied. + * + * @note Uses UE_LOG for logging messages, warnings, and errors. Uses `OnProfileChanged` to broadcast profile changes. + */ bool ApplyProfileInternal(EProfile Profile); + /** + * @brief Handles actions to be performed after the world initialization. + * + * This function hooks into the world initialization process to set up the `UHarmonyLinkGraphics` settings. + * It checks if the world is valid and is a game world, then initializes or reloads the settings as necessary and sets up a timer for periodic updates. + * + * @param World The world that has just been initialized. + * @param IVS Initialization values for the world. + * + * @details + * - Checks if the `World` pointer is valid. Logs an error and returns if the world is invalid. + * - If the world is a game world: + * - Retrieves the singleton settings instance using `GetSettings`. + * - If the world is a play-in-editor world, reloads the settings configuration by calling `LoadConfig` with `bForceReload` set to true. + * - Checks if the tick timer is already set or active. If not, sets a timer to call the `Tick` function at intervals specified by `_TickRate`. + * + * @note Uses UE_LOG for logging errors and informational messages. + */ void OnPostWorldInitialization(UWorld* World, UWorld::InitializationValues IVS); + + /** + * @brief Handles actions to be performed when the world ends. + * + * This function is called when the world is about to be destroyed. It clears the tick timer and safely destroys the singleton instance of the `UHarmonyLinkGraphics` settings. + * + * @param World The world that is ending. + * + * @details + * - Checks if the `World` pointer is valid. Logs an error and returns if the world is already destroyed. + * - If the tick timer exists, clears the timer using the world's timer manager. + * - Calls `DestroySettings` to safely destroy the singleton instance of `UHarmonyLinkGraphics`. + * + * @note Uses UE_LOG for logging errors and informational messages. + */ void OnWorldEnd(UWorld* World); + /** + * @brief Resets the singleton instance of the UHarmonyLinkGraphics settings. + * + * This function resets the singleton instance by destroying the current instance and creating a new one. + * + * @details + * - Calls `DestroySettings` on the current instance to safely destroy it. + * - Calls `GetSettings` to create and initialize a new singleton instance. + */ static void ResetInstance(); - // Note: Turning off HarmonyLink Settings requires game restart + /** + * @brief Applies a specific configuration setting to the console variable. + * + * This function applies the given configuration setting to the corresponding console variable (CVar) based on its key. It supports different data types such as bool, float, and int. + * + * @param Setting The key-value pair representing the setting to apply. The key is the name of the console variable, and the value is the configuration value. + * + * @details + * - Uses the console manager to find the console variable associated with the given setting key. + * - Depending on the type of the configuration value, sets the console variable to the corresponding value. + * - If the console variable is not found, logs a warning message. + * - If the value type is unsupported, logs a warning message. + * + * @note Uses UE_LOG for logging warnings about unsupported value types or missing console variables. + */ static void ApplySetting(const TPair& Setting); - // Debugging + /** + * @brief Prints debug information for all profiles. + * + * This function logs the debug information for all profiles stored in `_Profiles`. It iterates through each profile and calls `PrintDebugSection` to print the details. + * + * @details + * - Logs the start of the `DebugPrintProfiles` process. + * - Iterates over each profile in the `_Profiles` map. + * - Calls `PrintDebugSection` for each profile to print its details. + * - Logs the completion of the `DebugPrintProfiles` process. + * + * @note Uses UE_LOG for logging the start and completion of the debug print process. + */ void DebugPrintProfiles() const; + + /** + * @brief Prints debug information for a specific settings profile. + * + * This function logs the debug information for a given settings profile, including the section name and each setting's key, value, and type. + * + * @param SettingsProfile The settings profile to print debug information for. + * + * @details + * - Logs the section name of the `SettingsProfile`. + * - Iterates through each setting in the `SettingsProfile`. + * - Depending on the type of each setting, converts the value to a string and logs the key, value, and type. + * + * @note Uses UE_LOG for logging the section name and settings details. + */ static void PrintDebugSection(FSettingsProfile& SettingsProfile); - uint8 _bAutomaticSwitch :1; + // Indicates whether automatic profile switching is enabled. + bool _bAutomaticSwitch = false; + // Stores the last recorded battery percentage. int32 _LastBatteryPercentage = 0; - // How many times to query HarmonyLinkLib for hardware info + // The rate at which to query HarmonyLinkLib for hardware info. static int32 _TickRate; - FTimerHandle _TickTimerHandle; + // Timer handle for managing the periodic tick function. + static FTimerHandle _TickTimerHandle; + // The currently active profile. EProfile _ActiveProfile = EProfile::NONE; + // Maps profile enums to their corresponding names. TMap _ProfileNames = { {EProfile::BATTERY, "Battery"}, {EProfile::CHARGING, "Charging"}, {EProfile::DOCKED, "Docked"}, }; + // Stores the settings profiles. TMap _Profiles; + // The default settings for profiles. static TMap> _DefaultSettings; + // Singleton instance of UHarmonyLinkGraphics. static UHarmonyLinkGraphics* _INSTANCE; }; diff --git a/Source/ThirdParty/HarmonyLinkLib/bin/Linux/libHarmonyLinkLib.so b/Source/ThirdParty/HarmonyLinkLib/bin/Linux/libHarmonyLinkLib.so deleted file mode 100644 index a48fb6f..0000000 --- a/Source/ThirdParty/HarmonyLinkLib/bin/Linux/libHarmonyLinkLib.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3934d762dd9c3c6fcd29b5bf76687770f2572296f1820cbd39ff4093135ad907 -size 278088 diff --git a/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.dll b/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.dll deleted file mode 100644 index 860a335..0000000 --- a/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.dll +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6a94fca6083b966762b2640dc4fed71c4556c5169e6853c092638c9b80923ad3 -size 193536 diff --git a/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.lib b/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.lib deleted file mode 100644 index 233a4d6..0000000 --- a/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.lib +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6a815d7263dfec62f077eed620f0f08763031b3b58e3bf816a305d3ed0271167 -size 11026 diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Core.h b/Source/ThirdParty/HarmonyLinkLib/include/Core.h index ec6ef9d..94a32d2 100644 --- a/Source/ThirdParty/HarmonyLinkLib/include/Core.h +++ b/Source/ThirdParty/HarmonyLinkLib/include/Core.h @@ -16,10 +16,14 @@ // Use a preprocessor definition to switch between export and import declarations #ifdef _WIN32 - #ifdef HARMONYLINKLIB_EXPORTS - #define HARMONYLINKLIB_API __declspec(dllexport) + #ifdef HARMONYLINKLIB_STATIC + #define HARMONYLINKLIB_API #else - #define HARMONYLINKLIB_API __declspec(dllimport) + #ifdef HARMONYLINKLIB_SHARED + #define HARMONYLINKLIB_API __declspec(dllexport) + #else + #define HARMONYLINKLIB_API __declspec(dllimport) + #endif #endif #else #define HARMONYLINKLIB_API diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Enums/EDevice.h b/Source/ThirdParty/HarmonyLinkLib/include/Enums/EDevice.h index f49c7ec..c11919d 100644 --- a/Source/ThirdParty/HarmonyLinkLib/include/Enums/EDevice.h +++ b/Source/ThirdParty/HarmonyLinkLib/include/Enums/EDevice.h @@ -14,6 +14,9 @@ #pragma once +// Undefine the LINUX macro to avoid conflicts with the enum definition. +#undef LINUX + #include // Enum class for representing different types of devices diff --git a/Source/ThirdParty/HarmonyLinkLib/lib/Linux/libHarmonyLinkLibStatic.a b/Source/ThirdParty/HarmonyLinkLib/lib/Linux/libHarmonyLinkLibStatic.a new file mode 100644 index 0000000..a68f717 --- /dev/null +++ b/Source/ThirdParty/HarmonyLinkLib/lib/Linux/libHarmonyLinkLibStatic.a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:662848d6802035c1d74a131316d676e256a65c1537644e787e39c0b3c58209df +size 398236 diff --git a/Source/ThirdParty/HarmonyLinkLib/lib/Win64/HarmonyLinkLibStatic.lib b/Source/ThirdParty/HarmonyLinkLib/lib/Win64/HarmonyLinkLibStatic.lib new file mode 100644 index 0000000..d011ea4 --- /dev/null +++ b/Source/ThirdParty/HarmonyLinkLib/lib/Win64/HarmonyLinkLibStatic.lib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b400a97666909a2c7c4dd063f65d5bdfe404dda51e31c9d37546e1961f97a3c3 +size 1355050