diff --git a/HarmonyLink.uplugin b/HarmonyLinkUE.uplugin similarity index 71% rename from HarmonyLink.uplugin rename to HarmonyLinkUE.uplugin index b083076..450dc53 100644 --- a/HarmonyLink.uplugin +++ b/HarmonyLinkUE.uplugin @@ -2,7 +2,7 @@ "FileVersion": 3, "Version": 1, "VersionName": "1.0", - "FriendlyName": "HarmonyLink", + "FriendlyName": "HarmonyLinkUE", "Description": "Revolutionize handheld gaming with adaptive game settings. Optimize graphics and gameplay experience based on real-time system metrics. Open-source project empowering developers to enhance games on portable devices", "Category": "Handheld", "CreatedBy": "Jordon Brooks", @@ -10,16 +10,24 @@ "DocsURL": "https://github.com/Jordonbc/HarmonyLink", "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/92fd511971274d1f955abb7197485041", "SupportURL": "", - "CanContainContent": true, + "CanContainContent": false, "IsBetaVersion": false, "IsExperimentalVersion": false, "Installed": false, "Modules": [ { - "Name": "HarmonyLink", + "Name": "HarmonyLinkUE", "Type": "Runtime", - "LoadingPhase": "Default", - "WhitelistPlatforms": ["Win64", "Linux"] + "LoadingPhase": "PreDefault", + "WhitelistPlatforms": [ + "Win64", + "Linux" + ] + }, + { + "Name": "HarmonyLinkSettings", + "Type": "Runtime", + "LoadingPhase": "Default" } ] } diff --git a/Source/HarmonyLink/HarmonyLink.Build.cs b/Source/HarmonyLink/HarmonyLink.Build.cs deleted file mode 100644 index 75e3165..0000000 --- a/Source/HarmonyLink/HarmonyLink.Build.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (C) 2024 Jordon Brooks - -using UnrealBuildTool; -using System.IO; - -public class HarmonyLink : ModuleRules -{ - public HarmonyLink(ReadOnlyTargetRules Target) : base(Target) - { - PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; - - PublicIncludePaths.AddRange( - new string[] { - // ... add public include paths required here ... - } - ); - - - PrivateIncludePaths.AddRange( - new string[] { - // ... add other private include paths required here ... - "ThirdParty/HarmonyLinkLib/include" - } - ); - - - PublicDependencyModuleNames.AddRange( - new string[] - { - "Core", - "CoreUObject", - "Engine", - // ... add other public dependencies that you statically link with here ... - } - ); - - - PrivateDependencyModuleNames.AddRange( - new string[] - { - // ... add private dependencies that you statically link with here ... - } - ); - - - DynamicallyLoadedModuleNames.AddRange( - new string[] - { - // ... add any modules that your module loads dynamically here ... - } - ); - - // 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")); - } - - // 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")); - } - } -} diff --git a/Source/HarmonyLink/Private/HarmonyLink.cpp b/Source/HarmonyLink/Private/HarmonyLink.cpp deleted file mode 100644 index 88e7005..0000000 --- a/Source/HarmonyLink/Private/HarmonyLink.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2024 Jordon Brooks - -#include "HarmonyLink.h" -#include "Modules/ModuleManager.h" - -#define LOCTEXT_NAMESPACE "FHarmonyLinkModule" - -void FHarmonyLinkModule::StartupModule() -{ -} - -void FHarmonyLinkModule::ShutdownModule() -{ -} - -#undef LOCTEXT_NAMESPACE - -IMPLEMENT_MODULE(FHarmonyLinkModule, HarmonyLink) diff --git a/Source/HarmonyLink/Private/HarmonyLinkLibrary.cpp b/Source/HarmonyLink/Private/HarmonyLinkLibrary.cpp deleted file mode 100644 index ed3f0d9..0000000 --- a/Source/HarmonyLink/Private/HarmonyLinkLibrary.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2024 Jordon Brooks - -#include "HarmonyLinkLibrary.h" - -#include - -bool UHarmonyLinkLibrary::IsWine() -{ - return HarmonyLinkLib::get_is_wine(); -} - -bool UHarmonyLinkLibrary::IsLinux() -{ -#if PLATFORM_WINDOWS - return IsWine(); -#elif PLATFORM_LINUX - return true; -#else - return false; -#endif -} - -bool UHarmonyLinkLibrary::IsSteamDeck() -{ - return GetDeviceInfo().Device == EDeviceEnum::STEAM_DECK; -} - -FCPUInfo UHarmonyLinkLibrary::GetCPUInfo() -{ - return FCPUInfo(HarmonyLinkLib::get_cpu_info()); -} - -FDevice UHarmonyLinkLibrary::GetDeviceInfo() -{ - return FDevice(HarmonyLinkLib::get_device_info()); -} - -FOSVerInfo UHarmonyLinkLibrary::GetOSInfo() -{ - return FOSVerInfo(HarmonyLinkLib::get_os_version()); -} - -FBattery UHarmonyLinkLibrary::GetBatteryStatus() -{ - return FBattery(HarmonyLinkLib::get_battery_status()); -} diff --git a/Source/HarmonyLink/Public/HarmonyLinkLibrary.h b/Source/HarmonyLink/Public/HarmonyLinkLibrary.h deleted file mode 100644 index 4a809e2..0000000 --- a/Source/HarmonyLink/Public/HarmonyLinkLibrary.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2024 Jordon Brooks - -#pragma once - -#include "CoreMinimal.h" - -#include "Structs/Battery.h" -#include "Structs/CPUInfo.h" -#include "Structs/Device.h" -#include "Structs/OSVerInfo.h" - -#include "Kismet/BlueprintFunctionLibrary.h" -#include "HarmonyLinkLibrary.generated.h" - -/** - * Library of static functions for accessing various system information, particularly for the HarmonyLink project. - */ -UCLASS() -class HARMONYLINK_API UHarmonyLinkLibrary : public UBlueprintFunctionLibrary -{ - GENERATED_BODY() - -public: - // Checks if the game is running under Wine. - UFUNCTION(BlueprintCallable, Category="HarmonyLink") - static bool IsWine(); - - // Checks if the operating system is Linux. - UFUNCTION(BlueprintCallable, Category="HarmonyLink") - static bool IsLinux(); - - // Checks if the game is running on a Steam Deck. - UFUNCTION(BlueprintCallable, Category="HarmonyLink") - static bool IsSteamDeck(); - - // Retrieves information about the CPU of the current device. - UFUNCTION(BlueprintCallable, Category="HarmonyLink") - static FCPUInfo GetCPUInfo(); - - // Retrieves information about the current device. - UFUNCTION(BlueprintCallable, Category="HarmonyLink") - static FDevice GetDeviceInfo(); - - // Retrieves information about the operating system of the current device. - UFUNCTION(BlueprintCallable, Category="HarmonyLink") - static FOSVerInfo GetOSInfo(); - - // Retrieves the current battery status of the device. - UFUNCTION(BlueprintCallable, Category="HarmonyLink") - static FBattery GetBatteryStatus(); -}; diff --git a/Source/HarmonyLinkSettings/HarmonyLinkSettings.Build.cs b/Source/HarmonyLinkSettings/HarmonyLinkSettings.Build.cs new file mode 100644 index 0000000..e630ffb --- /dev/null +++ b/Source/HarmonyLinkSettings/HarmonyLinkSettings.Build.cs @@ -0,0 +1,26 @@ +using UnrealBuildTool; + +public class HarmonyLinkSettings : ModuleRules +{ + public HarmonyLinkSettings(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + } + ); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + + "HarmonyLinkUE" + } + ); + } +} diff --git a/Source/HarmonyLinkSettings/Private/HarmonyLinkSettings.cpp b/Source/HarmonyLinkSettings/Private/HarmonyLinkSettings.cpp new file mode 100644 index 0000000..b2ea795 --- /dev/null +++ b/Source/HarmonyLinkSettings/Private/HarmonyLinkSettings.cpp @@ -0,0 +1,22 @@ +#include "HarmonyLinkSettings.h" + +#include "Objects/HarmonyLinkGraphics.h" + +#define LOCTEXT_NAMESPACE "FHarmonyLinkSettingsModule" + +DEFINE_LOG_CATEGORY(LogHarmonyLinkSettings); + +void FHarmonyLinkSettingsModule::StartupModule() +{ + +} + +void FHarmonyLinkSettingsModule::ShutdownModule() +{ + // Ensure we safely destroy our singleton instance + UHarmonyLinkGraphics::DestroySettings(); +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FHarmonyLinkSettingsModule, HarmonyLinkSettings) diff --git a/Source/HarmonyLinkSettings/Private/Objects/HarmonyLinkGraphics.cpp b/Source/HarmonyLinkSettings/Private/Objects/HarmonyLinkGraphics.cpp new file mode 100644 index 0000000..fafa023 --- /dev/null +++ b/Source/HarmonyLinkSettings/Private/Objects/HarmonyLinkGraphics.cpp @@ -0,0 +1,798 @@ +// Copyright (C) 2024 Jordon Brooks + + +#include "Objects/HarmonyLinkGraphics.h" +#include "ComponentRecreateRenderStateContext.h" +#include "HarmonyLinkSettings.h" +#include "HarmonyLinkLibrary.h" +#include "GameFramework/GameUserSettings.h" +#include "Kismet/GameplayStatics.h" + +UHarmonyLinkGraphics* UHarmonyLinkGraphics::_INSTANCE = nullptr; +int32 UHarmonyLinkGraphics::_TickRate = 1; +FTimerHandle UHarmonyLinkGraphics::_TickTimerHandle = FTimerHandle(); +TSharedPtr UHarmonyLinkGraphics::_ConfigFile = nullptr; +bool UHarmonyLinkGraphics::_bAutomaticSwitch = false; +int32 UHarmonyLinkGraphics::_LastBatteryPercentage = 0; +EProfile UHarmonyLinkGraphics::_ActiveProfile = EProfile::NONE; +TMap UHarmonyLinkGraphics::_Profiles = TMap(); + +TMap UHarmonyLinkGraphics::_ProfileNames = +{ + {EProfile::BATTERY, "Battery"}, + {EProfile::CHARGING, "Charging"}, + {EProfile::DOCKED, "Docked"}, +}; + +/** + * @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) }, +// { TEXT("r.DynamicGlobalIlluminationMethod"), FHLConfigValue(2) }, +// { TEXT("r.Shadow.Virtual.Enable"), FHLConfigValue(0) }, +// { TEXT("r.ScreenPercentage"), FHLConfigValue(50) }, + }}, + { "Charging", { +// { TEXT("r.ReflectionMethod"), FHLConfigValue(2) }, +// { TEXT("r.DynamicGlobalIlluminationMethod"), FHLConfigValue(2) }, +// { TEXT("r.Shadow.Virtual.Enable"), FHLConfigValue(1) }, +// { TEXT("r.ScreenPercentage"), FHLConfigValue(100) }, + }}, + { "Docked", { +// { TEXT("r.ReflectionMethod"), FHLConfigValue(2) }, +// { TEXT("r.DynamicGlobalIlluminationMethod"), FHLConfigValue(2) }, +// { TEXT("r.Shadow.Virtual.Enable"), FHLConfigValue(1) }, +// { TEXT("r.ScreenPercentage"), FHLConfigValue(100) }, + }} +}; + +UHarmonyLinkGraphics::~UHarmonyLinkGraphics() +{ + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("~UHarmonyLinkGraphics called.")); + FWorldDelegates::OnPostWorldInitialization.RemoveAll(this); + FWorldDelegates::OnPreWorldFinishDestroy.RemoveAll(this); +} + +void UHarmonyLinkGraphics::LoadConfig(const bool bForceReload) +{ + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("LoadConfig called.")); + QUICK_SCOPE_CYCLE_COUNTER(HarmonyLinkGraphics_LoadSettings); + + // Load the settings into the map + FConfigFile* _ = GetConfig(); + + DebugPrintProfiles(); +} + +bool UHarmonyLinkGraphics::LoadSettingsFromConfig(FConfigFile* ConfigFile) const +{ + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("LoadSettingsFromConfig called.")); + //const FString Filename = "HarmonyLink"; //GetConfigDirectoryFile(bLoadDefaults); + + // Load each profile section + bool bLoaded = true; + + // Load the _bAutomaticSwitch variable + const FString SectionName = TEXT("HarmonyLink"); + const FString KeyName = TEXT("AutomaticProfileSwitch"); + + if (!ConfigFile->GetBool(*SectionName, *KeyName, _bAutomaticSwitch)) + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("Failed to load bAutomaticSwitch from config")); + bLoaded = false; + } + else + { + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Loaded bAutomaticSwitch: %s"), _bAutomaticSwitch ? TEXT("true") : TEXT("false")); + } + + for (const TPair& Profile : _ProfileNames) + { + if (!LoadSection(ConfigFile, Profile)) + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("Failed to load section: '%s'"), *Profile.Value.ToString()); + bLoaded = false; + } + } + + // Check if all profiles and settings were loaded successfully + if (bLoaded) + { + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Successfully loaded config.")); + return true; + } + + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("Failed to load config file.")); + return false; +} + +bool UHarmonyLinkGraphics::LoadSection(FConfigFile* ConfigFile, const TPair Profile) +{ + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("LoadSection called.")); + if (!ensureMsgf(ConfigFile, TEXT("ConfigFile is nullptr!"))) return false; + + const FName& SectionName = Profile.Value; + const EProfile ProfileKey = Profile.Key; + + const FConfigSection* Section = nullptr; + + +#if (ENGINE_MAJOR_VERSION >= 5) + Section = ConfigFile->FindSection(*SectionName.ToString()); +#elif (ENGINE_MAJOR_VERSION == 4) && (ENGINE_MINOR_VERSION >= 27) + Section = ConfigFile->FindOrAddSection(*SectionName.ToString()); +#else + #error "Unsupported Unreal Engine version" +#endif + + if (Section) + { + FSettingsProfile& SettingsProfile = _Profiles.FindOrAdd(ProfileKey); + SettingsProfile.SectionName = SectionName; + SettingsProfile.Settings.Empty(); // Clear previous settings + + for (const auto& ValueIt : *Section) + { + FString ValueString = ValueIt.Value.GetValue(); + FString Value, Type; + + // Parse the Value and Type from the string + if (ValueString.Split(TEXT(", Type="), &Value, &Type)) + { + Value = Value.RightChop(7); // Remove "(Value=" prefix + Type = Type.LeftChop(1); // Remove ")" suffix + + if (Type == "int") + { + const int32 IntValue = FCString::Atoi(*Value); + SettingsProfile.Settings.Add(ValueIt.Key, FHLConfigValue(IntValue)); + } + else if (Type == "float") + { + const float FloatValue = FCString::Atof(*Value); + SettingsProfile.Settings.Add(ValueIt.Key, FHLConfigValue(FloatValue)); + } + else if (Type == "bool") + { + const bool BoolValue = Value == "true"; + SettingsProfile.Settings.Add(ValueIt.Key, FHLConfigValue(BoolValue)); + } + else if (Type == "string") + { + SettingsProfile.Settings.Add(ValueIt.Key, FHLConfigValue(Value)); + } + } + } + + return true; + } + + return false; +} + +void UHarmonyLinkGraphics::SaveConfig() const +{ + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("SaveConfig called.")); + Intermal_SaveConfig(false); +} + +void UHarmonyLinkGraphics::SetSetting(const EProfile Profile, const FName Setting, const FHLConfigValue& Value) +{ + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("SetSetting called.")); + // 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); + + if (!ProfileName) + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("Profile not found.")); + return; + } + + FString TypeString; + FString ValueString; + + switch (Value.GetType()) + { + case EConfigValueType::Int: + ValueString = FString::FromInt(Value.GetValue()); + TypeString = TEXT("int"); + break; + case EConfigValueType::Float: + ValueString = FString::SanitizeFloat(Value.GetValue()); + TypeString = TEXT("float"); + break; + case EConfigValueType::Bool: + ValueString = Value.GetValue() ? TEXT("True") : TEXT("False"); + TypeString = TEXT("bool"); + break; + case EConfigValueType::String: + ValueString = Value.GetValue(); + TypeString = TEXT("string"); + break; + } + + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Applying '%s': Value='%s', Type='%s' to profile '%s'."), *Setting.ToString(), *TypeString, *ValueString, *ProfileName->ToString()); + + // Find the settings associated with the profile + FSettingsProfile* SettingsProfile = _Profiles.Find(Profile); + + if (!SettingsProfile) + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("No settings found for profile %s."), *ProfileName->ToString()); + return; + } + + SettingsProfile->Settings.FindOrAdd(Setting) = Value; +} + + +UHarmonyLinkGraphics* UHarmonyLinkGraphics::GetSettings() +{ + UE_LOG(LogHarmonyLinkSettings, VeryVerbose, TEXT("GetSettings called.")); + // Check if we already initialised + if (_INSTANCE) + { + return _INSTANCE; + } + + // Proceed to create a new singleton instance + _INSTANCE = NewObject(); + _INSTANCE->Init(); + + return _INSTANCE; +} + +FSettingsProfile UHarmonyLinkGraphics::GetSettingProfile(const EProfile Profile) +{ + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("GetSettingProfile called.")); + // 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); + + if (!ProfileName) + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("Profile not found.")); + return FSettingsProfile(); + } + + // Find the settings associated with the profile + FSettingsProfile* SettingsProfile = _Profiles.Find(Profile); + + if (!SettingsProfile) + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("No settings found for profile %s."), *ProfileName->ToString()); + return FSettingsProfile(); + } + + return *SettingsProfile; +} + +EProfile UHarmonyLinkGraphics::GetActiveProfile() const +{ + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("GetActiveProfile called.")); + return _ActiveProfile; +} + +void UHarmonyLinkGraphics::SetAutomaticSwitching(const bool bAutomaticSwitch) +{ + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("SetAutomaticSwitching called.")); + _bAutomaticSwitch = bAutomaticSwitch; + OnAutomaticSwitchChanged.Broadcast(_bAutomaticSwitch); +} + +bool UHarmonyLinkGraphics::GetAutomaticSwitching() const +{ + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("GetAutomaticSwitching called.")); + return _bAutomaticSwitch; +} + +void UHarmonyLinkGraphics::DestroySettings() +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("DestroySettings called.")); + if (_INSTANCE) + { + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Destroying UHarmonyLinkGraphics.")) + FWorldDelegates::OnPostWorldInitialization.RemoveAll(_INSTANCE); + FWorldDelegates::OnPreWorldFinishDestroy.RemoveAll(_INSTANCE); + _INSTANCE->RemoveFromRoot(); + +#if (ENGINE_MAJOR_VERSION >= 5) + _INSTANCE->MarkAsGarbage(); // For UE 5.0 and above +#elif (ENGINE_MAJOR_VERSION == 4) && (ENGINE_MINOR_VERSION >= 27) + _INSTANCE->MarkPendingKill(); // For UE 4.27 and above +#else +#error "Unsupported Unreal Engine version" +#endif + + _INSTANCE = nullptr; + } +} + +void UHarmonyLinkGraphics::Init() +{ + UE_LOG(LogHarmonyLinkSettings, Warning, TEXT("HarmonyLinkGraphics initialized.")); + if (_INSTANCE != this) + { + if (_INSTANCE) + { + DestroySettings(); + } + + _INSTANCE = this; + } + + AddToRoot(); + + FWorldDelegates::OnPostWorldInitialization.AddStatic(&UHarmonyLinkGraphics::OnPostWorldInitialization); + FWorldDelegates::OnPreWorldFinishDestroy.AddStatic(&UHarmonyLinkGraphics::OnWorldEnd); + + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Init called.")); + + if (!UHarmonyLinkLibrary::IsInitialised()) + { + UE_LOG(LogHarmonyLinkSettings, Fatal, TEXT("Failed to initialise HarmonyLinkLib!")); + return; + } + + LoadConfig(); + + const FBattery BatteryStatus = UHarmonyLinkLibrary::GetBatteryStatus(); + + if (BatteryStatus.HasBattery) + { + if (BatteryStatus.IsACConnected) + { + ApplyProfileInternal(EProfile::BATTERY); + } + else + { + ApplyProfileInternal(EProfile::CHARGING); + } + } +} + +void UHarmonyLinkGraphics::Intermal_SaveConfig(const bool bDefaultConfig) const +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Intermal_SaveConfig called.")); + 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(LogHarmonyLinkSettings, Log, TEXT("Saving bAutomaticSwitch: %s"), _bAutomaticSwitch ? TEXT("true") : TEXT("false")); + + for (const TPair& Profile : _Profiles) + { + SaveSection(Profile.Value, bDefaultConfig); + } + + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Flushing file: '%s'"), *Filename); + GetConfig()->Dirty = true; + // You'd think that Write would actually write something but for some + // reason even if it outputs a success the file doesn't actually get created. + // For this reason, Flush seems to work for now. + //GetConfig()->Write(Filename); + GConfig->Flush(true, Filename); +} + +void UHarmonyLinkGraphics::Tick() +{ + UE_LOG(LogHarmonyLinkSettings, VeryVerbose, TEXT("Tick called.")); + const FBattery BatteryStatus = UHarmonyLinkLibrary::GetBatteryStatus(); + + if (BatteryStatus.BatteryPercent != _LastBatteryPercentage) + { + // Ensure thread-safe broadcasting + OnBatteryLevelChanged.Broadcast(BatteryStatus.BatteryPercent); + } + + if (!_bAutomaticSwitch) + { + return; + } + + if (BatteryStatus.HasBattery) + { + if (BatteryStatus.IsACConnected) + { + if (_ActiveProfile != EProfile::CHARGING) + { + ApplyProfileInternal(EProfile::CHARGING); + } + } + else + { + if (_ActiveProfile != EProfile::BATTERY) + { + ApplyProfileInternal(EProfile::BATTERY); + } + } + } +} + +void UHarmonyLinkGraphics::CreateDefaultConfigFile() const +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("CreateDefaultConfigFile called.")); + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Creating default config file.")); + + LoadDefaults(); + Intermal_SaveConfig(true); + + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Default config file created.")); +} + +FString UHarmonyLinkGraphics::GetConfigDirectoryFile(const bool bDefaultFolder) +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("GetConfigDirectoryFile called.")); + FString ConfigFileName = bDefaultFolder ? TEXT("DefaultHarmonyLink.ini") : TEXT("HarmonyLink.ini"); + + FString ConfigDirectory = bDefaultFolder ? FPaths::ProjectConfigDir() : FPaths::Combine(FPaths::GeneratedConfigDir(), UGameplayStatics::GetPlatformName()); + + return FPaths::Combine(ConfigDirectory, ConfigFileName); +} + +void UHarmonyLinkGraphics::SaveSection(const FSettingsProfile& SettingsProfile, const bool bDefaultConfig, const bool bFlush) const +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("SaveSection called.")); + if (GConfig) + { + const FString Filename = GetConfigDirectoryFile(bDefaultConfig); + for (const auto& Setting : SettingsProfile.Settings) + { + FString TypeString; + FString ValueString; + + switch (Setting.Value.GetType()) + { + case EConfigValueType::Int: + ValueString = FString::FromInt(Setting.Value.GetValue()); + TypeString = TEXT("int"); + break; + case EConfigValueType::Float: + ValueString = FString::SanitizeFloat(Setting.Value.GetValue()); + TypeString = TEXT("float"); + break; + case EConfigValueType::Bool: + ValueString = Setting.Value.GetValue() ? TEXT("True") : TEXT("False"); + TypeString = TEXT("bool"); + break; + case EConfigValueType::String: + ValueString = Setting.Value.GetValue(); + TypeString = TEXT("string"); + break; + } + + const FString ConfigValue = FString::Printf(TEXT("(Value=%s, Type=%s)"), *ValueString, *TypeString); + GConfig->SetString(*SettingsProfile.SectionName.ToString(), *Setting.Key.ToString(), *ConfigValue, Filename); + } + + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Saving config file: '%s'"), *Filename); + if (bFlush) + { + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Flushing file: '%s'"), *Filename); + GConfig->Flush(false, Filename); + } + } +} + +void UHarmonyLinkGraphics::LoadDefaults() const +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("LoadDefaults called.")); + + _Profiles.Reset(); + + // Iterate over ProfileNames to create default settings + for (const TPair& Profile : _ProfileNames) + { + FSettingsProfile NewProfileSettings; + NewProfileSettings.SectionName = Profile.Value; + + if (const TMap* Settings = _DefaultSettings.Find(Profile.Value)) + { + NewProfileSettings.Settings = *Settings; + } + + _Profiles.Add(Profile.Key, NewProfileSettings); + } +} + +bool UHarmonyLinkGraphics::ApplyProfileInternal(const EProfile Profile) +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("ApplyProfileInternal called.")); + // If the profile is None, revert to the original user game settings + if (Profile == EProfile::NONE) + { + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Reverting to original user game settings.")); + + if (UGameUserSettings* UserSettings = GEngine->GetGameUserSettings()) + { + UserSettings->LoadSettings(true); + UserSettings->ApplySettings(true); + _ActiveProfile = EProfile::NONE; + OnProfileChanged.Broadcast(_ActiveProfile); + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Original user game settings applied.")); + return true; + } + + UE_LOG(LogHarmonyLinkSettings, Warning, TEXT("Failed to get user game settings.")); + return false; + } + + + // Find the profile name associated with the given EProfile + const FName* ProfileName = _ProfileNames.Find(Profile); + + if (!ProfileName) + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("Profile not found.")); + return false; + } + + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Applying profile %s."), *ProfileName->ToString()); + + // Find the settings associated with the profile + FSettingsProfile* SettingsProfile = _Profiles.Find(Profile); + + if (!SettingsProfile) + { + UE_LOG(LogHarmonyLinkSettings, Warning, TEXT("No settings found for profile %s."), *ProfileName->ToString()); + return false; + } + + { + FGlobalComponentRecreateRenderStateContext Context; + + // Example of applying settings (actual application depends on your implementation) + for (const TPair& Setting : SettingsProfile->Settings) + { + // Example of logging each setting being applied + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Patching CVar override: %s = %s"), + *Setting.Key.ToString(), *Setting.Value.ToString()); + + ApplySetting(Setting); + } + } + + _ActiveProfile = Profile; + OnProfileChanged.Broadcast(_ActiveProfile); + return true; +} + +void UHarmonyLinkGraphics::OnPostWorldInitialization(UWorld* World, UWorld::InitializationValues IVS) +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("OnPostWorldInitialization called.")); + if (!World || !World->IsValidLowLevel()) + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("Failed to Hook into World Initialisation!")) + return; + } + + if (World->IsGameWorld()) + { + if (IsValid(GetSettings())) + { + FTimerManager* TimerManager = &World->GetTimerManager(); + if (!TimerManager) + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("Failed get TimerManager!")) + return; + } + + if (!TimerManager->TimerExists(_TickTimerHandle) || !TimerManager->IsTimerActive(_TickTimerHandle)) + { + + World->GetTimerManager().SetTimer(_TickTimerHandle, [TimerManager] + { + if (!GetSettings()) + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("'This' is destroyed, Clearing timer.")) + if (TimerManager) + { + TimerManager->ClearTimer(_TickTimerHandle); + } + return; + } + GetSettings()->Tick(); + }, _TickRate, true); + } + else + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("Error: Timer already exists.")); + } + } + else + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("'This' is nullptr!")); + } + } + else + { + //UE_LOG(LogHarmonyLink, Error, TEXT("Failed to bring up tick!")); + } +} + +void UHarmonyLinkGraphics::OnWorldEnd(UWorld* World) +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("OnWorldEnd(UWorld* World) called.")); + if (!World) + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("World Already destroyed")) + return; + } + + if (!World->IsGameWorld()) + { + return; + } + + if(World->GetTimerManager().TimerExists(_TickTimerHandle)) + { + World->GetTimerManager().ClearTimer(_TickTimerHandle); + } + + // Ensure we safely destroy our singleton instance + DestroySettings(); +} + +bool UHarmonyLinkGraphics::ApplyProfile(const EProfile Profile, const bool bDisableAutomaticSwitch) +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Applying Profile.")); + // Manual profile change, turn off automatic switching + if (bDisableAutomaticSwitch) + { + _bAutomaticSwitch = false; + } + + return ApplyProfileInternal(Profile); +} + +void UHarmonyLinkGraphics::ApplySetting(const TPair& Setting) +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Applying settings.")); + // Apply the setting based on the key (CVar) + IConsoleManager& ConsoleManager = IConsoleManager::Get(); + IConsoleVariable* CVar = ConsoleManager.FindConsoleVariable(*Setting.Key.ToString()); + + if (CVar) + { + switch (Setting.Value.GetType()) + { + case EConfigValueType::Bool: + CVar->Set(Setting.Value.GetValue(), ECVF_SetByGameSetting); + break; + + case EConfigValueType::Float: + CVar->Set(Setting.Value.GetValue(), ECVF_SetByGameSetting); + break; + + case EConfigValueType::Int: + CVar->Set(Setting.Value.GetValue(), ECVF_SetByGameSetting); + break; + + default: + UE_LOG(LogHarmonyLinkSettings, Warning, TEXT("Unsupported value type for setting: %s"), *Setting.Key.ToString()); + break; + } + } + else + { + UE_LOG(LogHarmonyLinkSettings, Warning, TEXT("Console variable not found: %s"), *Setting.Key.ToString()); + } +} + +void UHarmonyLinkGraphics::DebugPrintProfiles() const +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("DebugPrintProfiles started.")); + + for (TPair Profile : _Profiles) + { + PrintDebugSection(Profile.Value); + } + + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("DebugPrintProfiles completed.")); +} + +FConfigFile* UHarmonyLinkGraphics::GetConfig() const +{ + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("GetConfig Called.")); + if (_ConfigFile) + { + return _ConfigFile.Get(); + } + + FConfigFile* ConfigFile = GConfig->Find(GetConfigDirectoryFile(false), false); + + if (!ConfigFile) + { + UE_LOG(LogHarmonyLinkSettings, Warning, TEXT("Config file not found, attempting to read DefaultHarmonyLink.ini.")); + // Look in ProjectFolder->Config->DefaultHarmonyLink.ini + ConfigFile = GConfig->Find(GetConfigDirectoryFile(true), true); + } + + /*if (!ConfigFile) + { + CreateDefaultConfigFile(); + ConfigFile = GConfig->Find(GetConfigDirectoryFile(true), true); + }*/ + + if (ConfigFile) + { + UE_LOG(LogHarmonyLinkSettings, Verbose, TEXT("Setting up config.")); + ConfigFile->Name = "HarmonyLink"; + LoadSettingsFromConfig(ConfigFile); + _ConfigFile = MakeShareable(ConfigFile); + } + else + { + UE_LOG(LogHarmonyLinkSettings, Error, TEXT("Failed to make config variable!")) + return nullptr; + } + + return _ConfigFile.Get(); +} + +void UHarmonyLinkGraphics::PrintDebugSection(FSettingsProfile& SettingsProfile) +{ + UE_LOG(LogHarmonyLinkSettings, Warning, TEXT("[%s]"), *SettingsProfile.SectionName.ToString()); + + for (const auto& Setting : SettingsProfile.Settings) + { + FString ValueString; + FString TypeString; + + switch (Setting.Value.GetType()) + { + case EConfigValueType::Int: + ValueString = FString::FromInt(Setting.Value.GetValue()); + TypeString = TEXT("int"); + break; + case EConfigValueType::Float: + ValueString = FString::SanitizeFloat(Setting.Value.GetValue()); + TypeString = TEXT("float"); + break; + case EConfigValueType::Bool: + ValueString = Setting.Value.GetValue() ? TEXT("true") : TEXT("false"); + TypeString = TEXT("bool"); + break; + case EConfigValueType::String: + ValueString = Setting.Value.GetValue(); + TypeString = TEXT("string"); + break; + } + + UE_LOG(LogHarmonyLinkSettings, Warning, TEXT("Key: %s = V=%s, T=%s "), *Setting.Key.ToString(), *ValueString, *TypeString); + } +} + +void UHarmonyLinkGraphics::ResetInstance() +{ + UE_LOG(LogHarmonyLinkSettings, Log, TEXT("Resetting instance.")); + _INSTANCE->DestroySettings(); + GetSettings(); +} diff --git a/Source/HarmonyLinkSettings/Private/Structs/HLConfigValue.cpp b/Source/HarmonyLinkSettings/Private/Structs/HLConfigValue.cpp new file mode 100644 index 0000000..16f5699 --- /dev/null +++ b/Source/HarmonyLinkSettings/Private/Structs/HLConfigValue.cpp @@ -0,0 +1,3 @@ +// Copyright (C) 2024 Jordon Brooks + +#include "Structs/HLConfigValue.h" diff --git a/Source/HarmonyLinkSettings/Public/Enums/Profile.h b/Source/HarmonyLinkSettings/Public/Enums/Profile.h new file mode 100644 index 0000000..16c48cd --- /dev/null +++ b/Source/HarmonyLinkSettings/Public/Enums/Profile.h @@ -0,0 +1,18 @@ +// Copyright (C) 2024 Jordon Brooks + +#pragma once + +#include "CoreMinimal.h" +#include "Profile.generated.h" + +/* + * Enum representing different operating system platforms. + */ +UENUM(BlueprintType) +enum class EProfile : uint8 +{ + NONE = 0 UMETA(DisplayName = "NONE"), + BATTERY UMETA(DisplayName = "BATTERY"), + CHARGING UMETA(DisplayName = "CHARGING"), + DOCKED UMETA(DisplayName = "DOCKED"), +}; diff --git a/Source/HarmonyLinkSettings/Public/HarmonyLinkSettings.h b/Source/HarmonyLinkSettings/Public/HarmonyLinkSettings.h new file mode 100644 index 0000000..a51a458 --- /dev/null +++ b/Source/HarmonyLinkSettings/Public/HarmonyLinkSettings.h @@ -0,0 +1,13 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleManager.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogHarmonyLinkSettings, Log, All); + +class FHarmonyLinkSettingsModule : public IModuleInterface +{ +public: + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; diff --git a/Source/HarmonyLinkSettings/Public/Objects/HarmonyLinkGraphics.h b/Source/HarmonyLinkSettings/Public/Objects/HarmonyLinkGraphics.h new file mode 100644 index 0000000..782fb98 --- /dev/null +++ b/Source/HarmonyLinkSettings/Public/Objects/HarmonyLinkGraphics.h @@ -0,0 +1,499 @@ +// Copyright (C) 2024 Jordon Brooks + +#pragma once + +#include "CoreMinimal.h" +#include "Enums/Profile.h" +#include "Structs/SettingsProfile.h" + +#include "Kismet/BlueprintFunctionLibrary.h" +#include "HarmonyLinkGraphics.generated.h" + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnProfileChanged, EProfile, Profile); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAutomaticSwitchChanged, bool, bAutomaticSwich); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnBatteryLevelChanged, int32, BatteryPercent); + +/** + * + */ +UCLASS(Blueprintable, config="HarmonyLink") +class HARMONYLINKSETTINGS_API UHarmonyLinkGraphics : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + virtual ~UHarmonyLinkGraphics() override; + + UPROPERTY(BlueprintAssignable) + FOnProfileChanged OnProfileChanged; + + UPROPERTY(BlueprintAssignable) + FOnAutomaticSwitchChanged OnAutomaticSwitchChanged; + + 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, const 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 bDisableAutomaticSwitch = true); + + /** + * @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, BlueprintPure, 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, 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() const; + + /** + * @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(FConfigFile* ConfigFile) const; + + /** + * @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. + */ + static bool LoadSection(FConfigFile* ConfigFile, const TPair Profile); + + + /** + * @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. + */ + void SaveSection(const FSettingsProfile& SettingsProfile, const bool bDefaultConfig, const bool bFlush = false) const; + + /** + * @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() const; + + /** + * @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. + */ + static 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. + */ + static 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(); + + /** + * @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); + + /** + * @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; + + FConfigFile* GetConfig() 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); + + // Indicates whether automatic profile switching is enabled. + static bool _bAutomaticSwitch; + + // Stores the last recorded battery percentage. + static int32 _LastBatteryPercentage; + + // The rate at which to query HarmonyLinkLib for hardware info. + static int32 _TickRate; + + // Timer handle for managing the periodic tick function. + static FTimerHandle _TickTimerHandle; + + // The currently active profile. + static EProfile _ActiveProfile; + + // Maps profile enums to their corresponding names. + static TMap _ProfileNames; + + // Stores the settings profiles. + static TMap _Profiles; + + static TSharedPtr _ConfigFile; + + // The default settings for profiles. + static TMap> _DefaultSettings; + + // Singleton instance of UHarmonyLinkGraphics. + static UHarmonyLinkGraphics* _INSTANCE; +}; diff --git a/Source/HarmonyLinkSettings/Public/Structs/HLConfigValue.h b/Source/HarmonyLinkSettings/Public/Structs/HLConfigValue.h new file mode 100644 index 0000000..2ce69f3 --- /dev/null +++ b/Source/HarmonyLinkSettings/Public/Structs/HLConfigValue.h @@ -0,0 +1,158 @@ +// Copyright (C) 2024 Jordon Brooks + +#pragma once + +#include "CoreMinimal.h" +#include "HLConfigValue.generated.h" + +UENUM(BlueprintType) +enum class EConfigValueType : uint8 +{ + Int, + Float, + Bool, + String +}; + +/** + * Note: In Blueprints, all values will be visible, but only the value corresponding to the 'Type' will be used. + */ +USTRUCT(BlueprintType) +struct FHLConfigValue +{ + GENERATED_BODY() + +private: + // Allow Blueprint access to these private variables + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ConfigValue", meta = (AllowPrivateAccess = "true")) + EConfigValueType Type; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ConfigValue", meta = (AllowPrivateAccess = "true", EditCondition = "Type == EConfigValueType::Int", EditConditionHides)) + int32 IntValue; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ConfigValue", meta = (AllowPrivateAccess = "true", EditCondition = "Type == EConfigValueType::Float", EditConditionHides)) + float FloatValue; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ConfigValue", meta = (AllowPrivateAccess = "true", EditCondition = "Type == EConfigValueType::Bool", EditConditionHides)) + bool BoolValue; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ConfigValue", meta = (AllowPrivateAccess = "true", EditCondition = "Type == EConfigValueType::String", EditConditionHides)) + FString StringValue; + +public: + FHLConfigValue() : Type(EConfigValueType::String), IntValue(0), FloatValue(0.0f), BoolValue(false), StringValue(TEXT("")) {} + + FHLConfigValue(int32 Value) : Type(EConfigValueType::Int), IntValue(Value), FloatValue(0.0f), BoolValue(false), StringValue(TEXT("")) {} + + FHLConfigValue(float Value) : Type(EConfigValueType::Float), IntValue(0), FloatValue(Value), BoolValue(false), StringValue(TEXT("")) {} + + FHLConfigValue(bool Value) : Type(EConfigValueType::Bool), IntValue(0), FloatValue(0.0f), BoolValue(Value), StringValue(TEXT("")) {} + + FHLConfigValue(const FString& Value) : Type(EConfigValueType::String), IntValue(0), FloatValue(0.0f), BoolValue(false), StringValue(Value) {} + + FString ToString() const + { + switch (Type) + { + case EConfigValueType::Int: + return FString::Printf(TEXT("Int: %d"), IntValue); + case EConfigValueType::Float: + return FString::Printf(TEXT("Float: %f"), FloatValue); + case EConfigValueType::Bool: + return BoolValue ? TEXT("Bool: true") : TEXT("Bool: false"); + case EConfigValueType::String: + return FString::Printf(TEXT("String: %s"), *StringValue); + default: + return TEXT("Unknown Type"); + } + } + + EConfigValueType GetType() const + { + return Type; + } + + template + T GetValue() const; + + // Equality operators + bool operator==(const FHLConfigValue& Other) const + { + if (Type != Other.Type) + { + return false; + } + + switch (Type) + { + case EConfigValueType::Int: + return IntValue == Other.IntValue; + case EConfigValueType::Float: + return FloatValue == Other.FloatValue; + case EConfigValueType::Bool: + return BoolValue == Other.BoolValue; + case EConfigValueType::String: + return StringValue == Other.StringValue; + default: + return false; + } + } + + bool operator!=(const FHLConfigValue& Other) const + { + return !(*this == Other); + } +}; + +// Specializations of the templated getter +template<> +inline int32 FHLConfigValue::GetValue() const +{ + ensure(Type == EConfigValueType::Int); + return IntValue; +} + +template<> +inline float FHLConfigValue::GetValue() const +{ + ensure(Type == EConfigValueType::Float); + return FloatValue; +} + +template<> +inline bool FHLConfigValue::GetValue() const +{ + ensure(Type == EConfigValueType::Bool); + return BoolValue; +} + +template<> +inline FString FHLConfigValue::GetValue() const +{ + ensure(Type == EConfigValueType::String); + return StringValue; +} + +// Hash function +FORCEINLINE uint32 GetTypeHash(const FHLConfigValue& Value) +{ + uint32 Hash = GetTypeHash(Value.GetType()); + + switch (Value.GetType()) + { + case EConfigValueType::Int: + Hash = HashCombine(Hash, GetTypeHash(Value.GetValue())); + break; + case EConfigValueType::Float: + Hash = HashCombine(Hash, GetTypeHash(Value.GetValue())); + break; + case EConfigValueType::Bool: + Hash = HashCombine(Hash, GetTypeHash(Value.GetValue())); + break; + case EConfigValueType::String: + Hash = HashCombine(Hash, GetTypeHash(Value.GetValue())); + break; + } + + return Hash; +} diff --git a/Source/HarmonyLinkSettings/Public/Structs/SettingsProfile.h b/Source/HarmonyLinkSettings/Public/Structs/SettingsProfile.h new file mode 100644 index 0000000..7d12c33 --- /dev/null +++ b/Source/HarmonyLinkSettings/Public/Structs/SettingsProfile.h @@ -0,0 +1,45 @@ +// Copyright (C) 2024 Jordon Brooks + +#pragma once + +#include "CoreMinimal.h" +#include "HLConfigValue.h" + +#include "SettingsProfile.generated.h" + +USTRUCT(BlueprintType) +struct FSettingsProfile +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Settings") + FName SectionName; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Settings") + TMap Settings; + + // Equality operators + bool operator==(const FSettingsProfile& Other) const + { + return SectionName == Other.SectionName && Settings.OrderIndependentCompareEqual(Other.Settings); + } + + bool operator!=(const FSettingsProfile& Other) const + { + return !(*this == Other); + } +}; + +// Hash function +FORCEINLINE uint32 GetTypeHash(const FSettingsProfile& Profile) +{ + uint32 Hash = GetTypeHash(Profile.SectionName); + + for (const auto& Pair : Profile.Settings) + { + Hash = HashCombine(Hash, GetTypeHash(Pair.Key)); + Hash = HashCombine(Hash, GetTypeHash(Pair.Value)); + } + + return Hash; +} diff --git a/Source/HarmonyLinkUE/HarmonyLinkUE.Build.cs b/Source/HarmonyLinkUE/HarmonyLinkUE.Build.cs new file mode 100644 index 0000000..56b5629 --- /dev/null +++ b/Source/HarmonyLinkUE/HarmonyLinkUE.Build.cs @@ -0,0 +1,49 @@ +// Copyright (C) 2024 Jordon Brooks + +using UnrealBuildTool; +using System.IO; + +public class HarmonyLinkUE : ModuleRules +{ + public HarmonyLinkUE(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + //IWYUSupport = IWYUSupport.Full; + + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "Engine", + + "HarmonyLinkLib", + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + // ... add private dependencies that you statically link with here ... + } + ); + + } +} diff --git a/Source/HarmonyLinkUE/Private/HarmonyLinkLibrary.cpp b/Source/HarmonyLinkUE/Private/HarmonyLinkLibrary.cpp new file mode 100644 index 0000000..bddd3af --- /dev/null +++ b/Source/HarmonyLinkUE/Private/HarmonyLinkLibrary.cpp @@ -0,0 +1,107 @@ +// Copyright (C) 2024 Jordon Brooks + +#include "HarmonyLinkLibrary.h" +#include "HarmonyLinkUE.h" + +#include "HarmonyLinkLib.h" + +bool UHarmonyLinkLibrary::bIsWineCached = false; +bool UHarmonyLinkLibrary::bIsLinuxCached = false; +bool UHarmonyLinkLibrary::bIsSteamDeckCached = false; +bool UHarmonyLinkLibrary::bCPUInfoCached = false; +bool UHarmonyLinkLibrary::bDeviceInfoCached = false; +bool UHarmonyLinkLibrary::bOSInfoCached = false; + +bool UHarmonyLinkLibrary::bIsWine = false; +bool UHarmonyLinkLibrary::bIsLinux = false; +bool UHarmonyLinkLibrary::bIsSteamDeck = false; + +FCPUInfo UHarmonyLinkLibrary::CachedCPUInfo = FCPUInfo(); +FDevice UHarmonyLinkLibrary::CachedDeviceInfo = FDevice(); +FOSVerInfo UHarmonyLinkLibrary::CachedOSInfo = FOSVerInfo(); + +bool UHarmonyLinkLibrary::bIsInitialised = false; + +UHarmonyLinkLibrary::UHarmonyLinkLibrary() +{ + bIsInitialised = HarmonyLinkLib::HL_Init(); + + if (!bIsInitialised) + { + UE_LOG(LogHarmonyLink, Fatal, TEXT("Failed to initialise HarmonyLinkLib!")); + return; + } + + UE_LOG(LogHarmonyLink, Log, TEXT("HarmonyLinkLib Initialised!")); +} + +bool UHarmonyLinkLibrary::IsInitialised() +{ + return bIsInitialised; +} + +bool UHarmonyLinkLibrary::IsWine(bool bForce) +{ + if (!bIsWineCached || bForce) + { + bIsWine = HarmonyLinkLib::get_is_wine(); + bIsWineCached = true; + } + return bIsWine; +} + +bool UHarmonyLinkLibrary::IsLinux(bool bForce) +{ + if (!bIsLinuxCached || bForce) + { + bIsLinux = HarmonyLinkLib::get_is_linux(); + bIsLinuxCached = true; + } + return bIsLinux; +} + +bool UHarmonyLinkLibrary::IsSteamDeck(bool bForce) +{ + if (!bIsSteamDeckCached || bForce) + { + bIsSteamDeck = GetDeviceInfo().Device == EDevice::STEAM_DECK; + bIsSteamDeckCached = true; + } + return bIsSteamDeck; +} + +FCPUInfo UHarmonyLinkLibrary::GetCPUInfo(bool bForce) +{ + if (!bCPUInfoCached || bForce) + { + CachedCPUInfo = FCPUInfo(HarmonyLinkLib::get_cpu_info()); + bCPUInfoCached = true; + } + + return CachedCPUInfo; +} + +FDevice UHarmonyLinkLibrary::GetDeviceInfo(bool bForce) +{ + if (!bDeviceInfoCached || bForce) + { + CachedDeviceInfo = FDevice(HarmonyLinkLib::get_device_info()); + bDeviceInfoCached = true; + } + return CachedDeviceInfo; +} + +FOSVerInfo UHarmonyLinkLibrary::GetOSInfo(bool bForce) +{ + if (!bOSInfoCached || bForce) + { + CachedOSInfo = FOSVerInfo(HarmonyLinkLib::get_os_version()); + bOSInfoCached = true; + } + return CachedOSInfo; +} + +FBattery UHarmonyLinkLibrary::GetBatteryStatus() +{ + return FBattery(HarmonyLinkLib::get_battery_status()); +} diff --git a/Source/HarmonyLinkUE/Private/HarmonyLinkUE.cpp b/Source/HarmonyLinkUE/Private/HarmonyLinkUE.cpp new file mode 100644 index 0000000..29c33e1 --- /dev/null +++ b/Source/HarmonyLinkUE/Private/HarmonyLinkUE.cpp @@ -0,0 +1,22 @@ +// Copyright (C) 2024 Jordon Brooks + +#include "HarmonyLinkUE.h" +#include "Modules/ModuleManager.h" + +#define LOCTEXT_NAMESPACE "FHarmonyLinkUEModule" + +DEFINE_LOG_CATEGORY(LogHarmonyLink); + +void FHarmonyLinkUEModule::StartupModule() +{ + +} + +void FHarmonyLinkUEModule::ShutdownModule() +{ + +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FHarmonyLinkUEModule, HarmonyLinkUE) diff --git a/Source/HarmonyLink/Private/Structs/Battery.cpp b/Source/HarmonyLinkUE/Private/Structs/Battery.cpp similarity index 100% rename from Source/HarmonyLink/Private/Structs/Battery.cpp rename to Source/HarmonyLinkUE/Private/Structs/Battery.cpp diff --git a/Source/HarmonyLink/Private/Structs/CPUInfo.cpp b/Source/HarmonyLinkUE/Private/Structs/CPUInfo.cpp similarity index 80% rename from Source/HarmonyLink/Private/Structs/CPUInfo.cpp rename to Source/HarmonyLinkUE/Private/Structs/CPUInfo.cpp index c13d94d..8b70135 100644 --- a/Source/HarmonyLink/Private/Structs/CPUInfo.cpp +++ b/Source/HarmonyLinkUE/Private/Structs/CPUInfo.cpp @@ -11,11 +11,6 @@ FCPUInfo::FCPUInfo(HarmonyLinkLib::FCPUInfo* cpu_info) PhysicalCores = cpu_info->Physical_Cores; LogicalCores = cpu_info->Logical_Cores; - for (const HarmonyLinkLib::FString& Flag : cpu_info->Flags) - { - Flags.Add(Flag.c_str()); - } - cpu_info->free(); } else diff --git a/Source/HarmonyLink/Private/Structs/Device.cpp b/Source/HarmonyLinkUE/Private/Structs/Device.cpp similarity index 81% rename from Source/HarmonyLink/Private/Structs/Device.cpp rename to Source/HarmonyLinkUE/Private/Structs/Device.cpp index a52de5f..794e914 100644 --- a/Source/HarmonyLink/Private/Structs/Device.cpp +++ b/Source/HarmonyLinkUE/Private/Structs/Device.cpp @@ -19,20 +19,20 @@ FDevice::FDevice(HarmonyLinkLib::FDevice* oldDevice) } } -EDeviceEnum FDevice::Convert(HarmonyLinkLib::EDevice Device) +EDevice FDevice::Convert(HarmonyLinkLib::EDevice Device) { switch (Device) { case HarmonyLinkLib::EDevice::DESKTOP: - return EDeviceEnum::DESKTOP; + return EDevice::DESKTOP; case HarmonyLinkLib::EDevice::LAPTOP: - return EDeviceEnum::LAPTOP; + return EDevice::LAPTOP; case HarmonyLinkLib::EDevice::HANDHELD: - return EDeviceEnum::HANDHELD; + return EDevice::HANDHELD; case HarmonyLinkLib::EDevice::STEAM_DECK: - return EDeviceEnum::STEAM_DECK; + return EDevice::STEAM_DECK; default: - return EDeviceEnum::DESKTOP; + return EDevice::DESKTOP; } } diff --git a/Source/HarmonyLink/Private/Structs/OSVerInfo.cpp b/Source/HarmonyLinkUE/Private/Structs/OSVerInfo.cpp similarity index 100% rename from Source/HarmonyLink/Private/Structs/OSVerInfo.cpp rename to Source/HarmonyLinkUE/Private/Structs/OSVerInfo.cpp diff --git a/Source/HarmonyLink/Public/Enums/DeviceEnum.h b/Source/HarmonyLinkUE/Public/Enums/DeviceEnum.h similarity index 92% rename from Source/HarmonyLink/Public/Enums/DeviceEnum.h rename to Source/HarmonyLinkUE/Public/Enums/DeviceEnum.h index 64320c8..fb7bb44 100644 --- a/Source/HarmonyLink/Public/Enums/DeviceEnum.h +++ b/Source/HarmonyLinkUE/Public/Enums/DeviceEnum.h @@ -9,7 +9,7 @@ * Enum representing different operating system platforms. */ UENUM(BlueprintType) -enum class EDeviceEnum : uint8 +enum class EDevice : uint8 { DESKTOP UMETA(DisplayName = "Desktop"), LAPTOP UMETA(DisplayName = "Laptop"), diff --git a/Source/HarmonyLink/Public/Enums/Platform.h b/Source/HarmonyLinkUE/Public/Enums/Platform.h similarity index 81% rename from Source/HarmonyLink/Public/Enums/Platform.h rename to Source/HarmonyLinkUE/Public/Enums/Platform.h index 2ffb255..9ab89dc 100644 --- a/Source/HarmonyLink/Public/Enums/Platform.h +++ b/Source/HarmonyLinkUE/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/HarmonyLinkUE/Public/HarmonyLinkLibrary.h b/Source/HarmonyLinkUE/Public/HarmonyLinkLibrary.h new file mode 100644 index 0000000..a55db5f --- /dev/null +++ b/Source/HarmonyLinkUE/Public/HarmonyLinkLibrary.h @@ -0,0 +1,75 @@ +// Copyright (C) 2024 Jordon Brooks + +#pragma once + +#include "CoreMinimal.h" + +#include "Structs/Battery.h" +#include "Structs/CPUInfo.h" +#include "Structs/Device.h" +#include "Structs/OSVerInfo.h" + +#include "Kismet/BlueprintFunctionLibrary.h" +#include "HarmonyLinkLibrary.generated.h" + +/** + * Library of static functions for accessing various system information, particularly for the HarmonyLink project. + */ +UCLASS() +class HARMONYLINKUE_API UHarmonyLinkLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + UHarmonyLinkLibrary(); + + // IsInitialised + UFUNCTION(BlueprintCallable, BlueprintPure, Category="HarmonyLink") + static bool IsInitialised(); + + // Checks if the game is running under Wine. + UFUNCTION(BlueprintCallable, BlueprintPure, Category="HarmonyLink") + static bool IsWine(bool bForce = false); + + // Checks if the operating system is Linux. + UFUNCTION(BlueprintCallable, BlueprintPure, Category="HarmonyLink") + static bool IsLinux(bool bForce = false); + + // Checks if the game is running on a Steam Deck. + UFUNCTION(BlueprintCallable, BlueprintPure, Category="HarmonyLink") + static bool IsSteamDeck(bool bForce = false); + + // Retrieves information about the CPU of the current device. + UFUNCTION(BlueprintCallable, BlueprintPure, Category="HarmonyLink") + static FCPUInfo GetCPUInfo(bool bForce = false); + + // Retrieves information about the current device. + UFUNCTION(BlueprintCallable, BlueprintPure, Category="HarmonyLink") + static FDevice GetDeviceInfo(bool bForce = false); + + // Retrieves information about the operating system of the current device. + UFUNCTION(BlueprintCallable, BlueprintPure, Category="HarmonyLink") + static FOSVerInfo GetOSInfo(bool bForce = false); + + // Retrieves the current battery status of the device. + UFUNCTION(BlueprintCallable, BlueprintPure, Category="HarmonyLink") + static FBattery GetBatteryStatus(); + +private: + static bool bIsWineCached; + static bool bIsWine; + static bool bIsLinuxCached; + static bool bIsLinux; + static bool bIsSteamDeckCached; + static bool bIsSteamDeck; + + static bool bCPUInfoCached; + static bool bDeviceInfoCached; + static bool bOSInfoCached; + + static FCPUInfo CachedCPUInfo; + static FDevice CachedDeviceInfo; + static FOSVerInfo CachedOSInfo; + + static bool bIsInitialised; +}; diff --git a/Source/HarmonyLink/Public/HarmonyLink.h b/Source/HarmonyLinkUE/Public/HarmonyLinkUE.h similarity index 67% rename from Source/HarmonyLink/Public/HarmonyLink.h rename to Source/HarmonyLinkUE/Public/HarmonyLinkUE.h index 9ee5be3..b88bb95 100644 --- a/Source/HarmonyLink/Public/HarmonyLink.h +++ b/Source/HarmonyLinkUE/Public/HarmonyLinkUE.h @@ -4,7 +4,9 @@ #include "Modules/ModuleManager.h" -class FHarmonyLinkModule : public IModuleInterface +DECLARE_LOG_CATEGORY_EXTERN(LogHarmonyLink, All, All); + +class FHarmonyLinkUEModule : public IModuleInterface { public: diff --git a/Source/HarmonyLink/Public/Structs/Battery.h b/Source/HarmonyLinkUE/Public/Structs/Battery.h similarity index 96% rename from Source/HarmonyLink/Public/Structs/Battery.h rename to Source/HarmonyLinkUE/Public/Structs/Battery.h index 6b8ec43..bd2793b 100644 --- a/Source/HarmonyLink/Public/Structs/Battery.h +++ b/Source/HarmonyLinkUE/Public/Structs/Battery.h @@ -1,9 +1,10 @@ // Copyright (C) 2024 Jordon Brooks #pragma once -#include - #include "CoreMinimal.h" + +#include "Structs/FBattery.h" + #include "Battery.generated.h" /* diff --git a/Source/HarmonyLink/Public/Structs/CPUInfo.h b/Source/HarmonyLinkUE/Public/Structs/CPUInfo.h similarity index 84% rename from Source/HarmonyLink/Public/Structs/CPUInfo.h rename to Source/HarmonyLinkUE/Public/Structs/CPUInfo.h index e6cbd9d..353c3e5 100644 --- a/Source/HarmonyLink/Public/Structs/CPUInfo.h +++ b/Source/HarmonyLinkUE/Public/Structs/CPUInfo.h @@ -2,9 +2,10 @@ #pragma once -#include - #include "CoreMinimal.h" + +#include "Structs/FCPUInfo.h" + #include "CPUInfo.generated.h" /* @@ -33,10 +34,6 @@ struct FCPUInfo UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink") int32 LogicalCores = 0; - // A set of flags representing various features or capabilities of the CPU. - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink") - TSet Flags; - // Constructor that initializes the struct with information from an external CPU info source. // @param cpu_info Pointer to an external FCPUInfo structure to copy data from. FCPUInfo(HarmonyLinkLib::FCPUInfo* cpu_info); diff --git a/Source/HarmonyLink/Public/Structs/Device.h b/Source/HarmonyLinkUE/Public/Structs/Device.h similarity index 91% rename from Source/HarmonyLink/Public/Structs/Device.h rename to Source/HarmonyLinkUE/Public/Structs/Device.h index 071d13c..fd009bd 100644 --- a/Source/HarmonyLink/Public/Structs/Device.h +++ b/Source/HarmonyLinkUE/Public/Structs/Device.h @@ -5,7 +5,8 @@ #include "CoreMinimal.h" #include "Enums/DeviceEnum.h" #include "Enums/Platform.h" -#include + +#include "Structs/FDevice.h" #include "Device.generated.h" @@ -25,7 +26,7 @@ struct FDevice // The type of the device. UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink") - EDeviceEnum Device = EDeviceEnum::DESKTOP; + EDevice Device = EDevice::DESKTOP; // Constructor that initializes the struct with information from an external source. // @param oldDevice Pointer to an external FDevice structure to copy data from. @@ -35,7 +36,7 @@ private: // Converts an external device enum to the internal EDeviceEnum type. // @param Device External device enum to convert. // @returns Converted EDeviceEnum value. - static EDeviceEnum Convert(HarmonyLinkLib::EDevice Device); + static EDevice Convert(HarmonyLinkLib::EDevice Device); // Converts an external platform enum to the internal EPlatform type. // @param Platform External platform enum to convert. diff --git a/Source/HarmonyLink/Public/Structs/OSVerInfo.h b/Source/HarmonyLinkUE/Public/Structs/OSVerInfo.h similarity index 97% rename from Source/HarmonyLink/Public/Structs/OSVerInfo.h rename to Source/HarmonyLinkUE/Public/Structs/OSVerInfo.h index ea380c8..e423cc0 100644 --- a/Source/HarmonyLink/Public/Structs/OSVerInfo.h +++ b/Source/HarmonyLinkUE/Public/Structs/OSVerInfo.h @@ -2,7 +2,8 @@ #pragma once #include "CoreMinimal.h" -#include + +#include "Structs/FOSVerInfo.h" #include "OSVerInfo.generated.h" diff --git a/Source/ThirdParty/HarmonyLinkLib/HarmonyLinkLib.Build.cs b/Source/ThirdParty/HarmonyLinkLib/HarmonyLinkLib.Build.cs new file mode 100644 index 0000000..2ce9175 --- /dev/null +++ b/Source/ThirdParty/HarmonyLinkLib/HarmonyLinkLib.Build.cs @@ -0,0 +1,72 @@ +// Copyright (C) 2024 Jordon Brooks + +using UnrealBuildTool; +using System.IO; +using Internal; + +public class HarmonyLinkLib : ModuleRules +{ + public HarmonyLinkLib(ReadOnlyTargetRules Target) : base(Target) + { + //Console.WriteLine("Building HarmonyLinkLib"); + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + Type = ModuleType.External; + + // Add the standard library + //bUseRTTI = true; + //bEnableExceptions = true; + + // Optionally, if you need C++17 features + //CppStandard = CppStandardVersion.Cpp17; + + string includePath = Path.Combine(ModuleDirectory, "include"); + //Console.WriteLine("Include Path: " + includePath); + PublicIncludePaths.Add(includePath); + + string platformString = Target.Platform.ToString(); + if (Target.Platform == UnrealTargetPlatform.Win64) + { + PublicDefinitions.Add("HARMONYLINKLIB_STATIC=1"); + PublicDefinitions.Add("BUILD_WINDOWS=1"); + string libpath = Path.Combine(ModuleDirectory, "lib", platformString, "HarmonyLinkLibStatic.lib"); + + PublicAdditionalLibraries.Add(libpath); + + //string dllPath = Path.Combine(ModuleDirectory, "bin", platformString, "HarmonyLinkLibShared.dll"); + //string dllTargetPath = "$(TargetOutputDir)/HarmonyLinkLibShared.dll"; + + //Console.WriteLine("DLL Path: " + dllPath); + //RuntimeDependencies.Add(dllTargetPath, dllPath); + + //PublicDelayLoadDLLs.Add("HarmonyLinkLibShared.dll"); + } + else if (Target.Platform == UnrealTargetPlatform.Linux) + { + PublicDefinitions.Add("HARMONYLINKLIB_STATIC=1"); + //Console.WriteLine("Building Linux"); + PublicDefinitions.Add("BUILD_LINUX=1"); + string dllPath = Path.Combine(ModuleDirectory, "lib", platformString, "libHarmonyLinkLibStatic_clang++.a"); + //string dllTargetPath = "$(TargetOutputDir)/libHarmonyLinkLibShared.so"; + //Console.WriteLine("Library Path: " + libPath); + PublicAdditionalLibraries.Add(dllPath); + + // Ensure the proper linking of standard C++ libraries + //PublicSystemLibraries.Add("stdc++"); + //PublicSystemLibraries.Add("c++abi"); + //PublicSystemLibraries.Add("m"); // Math library + //PublicSystemLibraries.Add("pthread"); // POSIX threads library + + // Add the C++ standard library explicitly if needed + PublicSystemLibraries.Add("c++"); + + // Ensure linking with libc and other necessary libraries + //PublicSystemLibraries.Add("dl"); // Dynamic linking loader + //PublicSystemLibraries.Add("rt"); // Real-time library + + // Add any other libraries that might be needed + //PublicSystemLibraries.Add("gcc_s"); // GCC support library + //PublicSystemLibraries.Add("gcc"); // GCC compiler support library + } + } +} diff --git a/Source/ThirdParty/HarmonyLinkLib/bin/Linux/libHarmonyLinkLib.so b/Source/ThirdParty/HarmonyLinkLib/bin/Linux/libHarmonyLinkLib.so deleted file mode 100644 index 7725901..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:d81f286a40562f70ff49c7c185e94e3cd9344208583bc2f2ebac8febe2b022e0 -size 454760 diff --git a/Source/ThirdParty/HarmonyLinkLib/bin/Linux/libHarmonyLinkLibShared.so b/Source/ThirdParty/HarmonyLinkLib/bin/Linux/libHarmonyLinkLibShared.so new file mode 100644 index 0000000..7f4480a --- /dev/null +++ b/Source/ThirdParty/HarmonyLinkLib/bin/Linux/libHarmonyLinkLibShared.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4a3966f9c7018d84e684baf61183d07758e13633decea1bd84daa44cf2b8ca1 +size 813728 diff --git a/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.dll b/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.dll deleted file mode 100644 index ad74163..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:ed05fbfae236188e483ecea23adaca7a7f8e2b1c9fc89d949c42fef3bbbdcf50 -size 95744 diff --git a/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.lib b/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.lib deleted file mode 100644 index 297581c..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:9008f30839f9b72aa8fe679a80aad5d2e6a12d1c46e33029a7a580ed7c87f19c -size 10636 diff --git a/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLibShared.dll b/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLibShared.dll new file mode 100644 index 0000000..a98cee4 --- /dev/null +++ b/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLibShared.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db0796fdd07c54a25cf0b1d77015f8c7af7b7a73ded92c123521dcc9a01e9b40 +size 731136 diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Core.h b/Source/ThirdParty/HarmonyLinkLib/include/Core.h index ec6ef9d..90babed 100644 --- a/Source/ThirdParty/HarmonyLinkLib/include/Core.h +++ b/Source/ThirdParty/HarmonyLinkLib/include/Core.h @@ -15,12 +15,24 @@ #pragma once // Use a preprocessor definition to switch between export and import declarations -#ifdef _WIN32 - #ifdef HARMONYLINKLIB_EXPORTS - #define HARMONYLINKLIB_API __declspec(dllexport) +#ifdef BUILD_WINDOWS + #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 + #ifdef HARMONYLINKLIB_SHARED + #ifdef __clang__ + #define HARMONYLINKLIB_API __attribute__((visibility("default"))) + #else + #define HARMONYLINKLIB_API + #endif + #else + #define HARMONYLINKLIB_API + #endif #endif diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Enums/EDevice.h b/Source/ThirdParty/HarmonyLinkLib/include/Enums/EDevice.h index 31f9bfe..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 @@ -21,6 +24,7 @@ namespace HarmonyLinkLib { enum class EDevice : uint8_t { + UNKNOWN, DESKTOP, LAPTOP, HANDHELD, diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Enums/EPlatform.h b/Source/ThirdParty/HarmonyLinkLib/include/Enums/EPlatform.h index 66697ee..ffa2be7 100644 --- a/Source/ThirdParty/HarmonyLinkLib/include/Enums/EPlatform.h +++ b/Source/ThirdParty/HarmonyLinkLib/include/Enums/EPlatform.h @@ -21,6 +21,7 @@ namespace HarmonyLinkLib { enum class EPlatform : uint8_t { + UNKNOWN, WINDOWS, LINUX, MAC, diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Enums/ESteamDeck.h b/Source/ThirdParty/HarmonyLinkLib/include/Enums/ESteamDeck.h new file mode 100644 index 0000000..9fbad64 --- /dev/null +++ b/Source/ThirdParty/HarmonyLinkLib/include/Enums/ESteamDeck.h @@ -0,0 +1,29 @@ +// Copyright (c) 2024 Jordon Brooks +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +// Enum class for representing different types of devices +namespace HarmonyLinkLib +{ + enum class ESteamDeck : uint8_t + { + NONE, // Device is not a steam deck + UNKNOWN, // Device is a steam deck but model cannot be determined + LCD, + OLED, + }; +} diff --git a/Source/ThirdParty/HarmonyLinkLib/include/HarmonyLinkLib.h b/Source/ThirdParty/HarmonyLinkLib/include/HarmonyLinkLib.h index aaa1887..0298e2d 100644 --- a/Source/ThirdParty/HarmonyLinkLib/include/HarmonyLinkLib.h +++ b/Source/ThirdParty/HarmonyLinkLib/include/HarmonyLinkLib.h @@ -44,13 +44,19 @@ class IPlatformUtilities; namespace HarmonyLinkLib { - extern "C" HARMONYLINKLIB_API bool get_is_wine(); + HARMONYLINKLIB_API bool HL_Init(); - extern "C" HARMONYLINKLIB_API FCPUInfo* get_cpu_info(); + HARMONYLINKLIB_API bool get_is_wine(); - extern "C" HARMONYLINKLIB_API FDevice* get_device_info(); + HARMONYLINKLIB_API bool get_is_linux(); - extern "C" HARMONYLINKLIB_API FOSVerInfo* get_os_version(); + HARMONYLINKLIB_API bool get_is_docked(); + + HARMONYLINKLIB_API FCPUInfo* get_cpu_info(); + + HARMONYLINKLIB_API FDevice* get_device_info(); + + HARMONYLINKLIB_API FOSVerInfo* get_os_version(); - extern "C" HARMONYLINKLIB_API FBattery* get_battery_status(); + HARMONYLINKLIB_API FBattery* get_battery_status(); } diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Structs/FDevice.h b/Source/ThirdParty/HarmonyLinkLib/include/Structs/FDevice.h index 50a1a5c..b574d6a 100644 --- a/Source/ThirdParty/HarmonyLinkLib/include/Structs/FDevice.h +++ b/Source/ThirdParty/HarmonyLinkLib/include/Structs/FDevice.h @@ -18,13 +18,15 @@ #include "Enums/EDevice.h" #include "Enums/EPlatform.h" +#include "Enums/ESteamDeck.h" namespace HarmonyLinkLib { // Struct to represent a specific device with both platform and device type struct FDevice : HarmonyLinkStruct { - EPlatform platform; - EDevice device; + EPlatform platform = EPlatform::UNKNOWN; + EDevice device = EDevice::UNKNOWN; + ESteamDeck steam_deck_model = ESteamDeck::NONE; }; } 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/Linux/libHarmonyLinkLibStatic_clang++.a b/Source/ThirdParty/HarmonyLinkLib/lib/Linux/libHarmonyLinkLibStatic_clang++.a new file mode 100644 index 0000000..27b9163 --- /dev/null +++ b/Source/ThirdParty/HarmonyLinkLib/lib/Linux/libHarmonyLinkLibStatic_clang++.a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6977100139b596b50b1b46bb91fb1979b43c3fc991ddcf5b6f4e4f4de1c992db +size 1775982 diff --git a/Source/ThirdParty/HarmonyLinkLib/lib/Win64/HarmonyLinkLibStatic.lib b/Source/ThirdParty/HarmonyLinkLib/lib/Win64/HarmonyLinkLibStatic.lib new file mode 100644 index 0000000..b820888 --- /dev/null +++ b/Source/ThirdParty/HarmonyLinkLib/lib/Win64/HarmonyLinkLibStatic.lib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ef8d92a66b36b8899e5fc2fe2e51e0753d11e7b161790013ee3c9a5c804fefa7 +size 1425358