diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..884087a
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,39 @@
+* text=auto
+
+# Sources
+*.c text diff=cpp
+*.cc text diff=cpp
+*.cxx text diff=cpp
+*.cpp text diff=cpp
+*.cpi text diff=cpp
+*.c++ text diff=cpp
+*.hpp text diff=cpp
+*.h text diff=cpp
+*.h++ text diff=cpp
+*.hh text diff=cpp
+
+# Compiled Object files
+*.slo binary filter=lfs diff=lfs merge=lfs
+*.lo binary filter=lfs diff=lfs merge=lfs
+*.o binary filter=lfs diff=lfs merge=lfs
+*.obj binary filter=lfs diff=lfs merge=lfs
+
+# Precompiled Headers
+*.gch binary filter=lfs diff=lfs merge=lfs
+*.pch binary filter=lfs diff=lfs merge=lfs
+
+# Compiled Dynamic libraries
+*.so binary filter=lfs diff=lfs merge=lfs
+*.dylib binary filter=lfs diff=lfs merge=lfs
+*.dll binary filter=lfs diff=lfs merge=lfs
+
+# Compiled Static libraries
+*.lai binary filter=lfs diff=lfs merge=lfs
+*.la binary filter=lfs diff=lfs merge=lfs
+*.a binary filter=lfs diff=lfs merge=lfs
+*.lib binary filter=lfs diff=lfs merge=lfs
+
+# Executables
+*.exe binary filter=lfs diff=lfs merge=lfs
+*.out binary filter=lfs diff=lfs merge=lfs
+*.app binary filter=lfs diff=lfs merge=lfs
diff --git a/Config/FilterPlugin.ini b/Config/FilterPlugin.ini
new file mode 100644
index 0000000..ccebca2
--- /dev/null
+++ b/Config/FilterPlugin.ini
@@ -0,0 +1,8 @@
+[FilterPlugin]
+; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and
+; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively.
+;
+; Examples:
+; /README.txt
+; /Extras/...
+; /Binaries/ThirdParty/*.dll
diff --git a/HarmonyLink.uplugin b/HarmonyLink.uplugin
deleted file mode 100644
index c69226e..0000000
--- a/HarmonyLink.uplugin
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "FileVersion": 3,
- "Version": 1,
- "VersionName": "1.0",
- "FriendlyName": "HarmonyLink",
- "Description": "",
- "Category": "Other",
- "CreatedBy": "Jordon Brooks",
- "CreatedByURL": "https://jordongamedev.co.uk",
- "DocsURL": "",
- "MarketplaceURL": "",
- "SupportURL": "",
- "CanContainContent": true,
- "IsBetaVersion": true,
- "IsExperimentalVersion": true,
- "Installed": false,
- "Modules": [
- {
- "Name": "HarmonyLink",
- "Type": "Runtime",
- "LoadingPhase": "Default"
- }
- ]
-}
diff --git a/HarmonyLinkUE.uplugin b/HarmonyLinkUE.uplugin
new file mode 100644
index 0000000..a62990f
--- /dev/null
+++ b/HarmonyLinkUE.uplugin
@@ -0,0 +1,33 @@
+{
+ "FileVersion": 3,
+ "Version": 1,
+ "VersionName": "1.1.0",
+ "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",
+ "CreatedByURL": "https://bbgames.dev",
+ "DocsURL": "https://github.com/Jordonbc/HarmonyLink",
+ "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/92fd511971274d1f955abb7197485041",
+ "SupportURL": "",
+ "CanContainContent": false,
+ "IsBetaVersion": false,
+ "IsExperimentalVersion": false,
+ "Installed": false,
+ "Modules": [
+ {
+ "Name": "HarmonyLinkUE",
+ "Type": "Runtime",
+ "LoadingPhase": "PreDefault",
+ "WhitelistPlatforms": [
+ "Win64",
+ "Linux"
+ ]
+ },
+ {
+ "Name": "HarmonyLinkSettings",
+ "Type": "Runtime",
+ "LoadingPhase": "Default"
+ }
+ ]
+}
diff --git a/README.md b/README.md
index b3ce6e0..00a0f8c 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,11 @@
This repository hosts the Unreal Engine 5 plugin for HarmonyLink, designed to provide real-time device metrics for handheld gaming, enhancing both gameplay and immersion.
+
+
+ Download the Marketplace plugin here
+
+
## Features
- **Intelligent Hardware Recognition**: HarmonyLink 2.0 can accurately identify specific devices like the Steam Deck without relying on manual environment variables or command line arguments.
@@ -27,7 +32,11 @@ This repository hosts the Unreal Engine 5 plugin for HarmonyLink, designed to pr
Watch the HarmonyLink Plugin in action, demonstrating its impact on gameplay through a Minecraft mod example:
-
+
+
+
+
+
diff --git a/Source/HarmonyLink/Private/HarmonyLink.cpp b/Source/HarmonyLink/Private/HarmonyLink.cpp
deleted file mode 100644
index da94234..0000000
--- a/Source/HarmonyLink/Private/HarmonyLink.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#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 e2de5d4..0000000
--- a/Source/HarmonyLink/Private/HarmonyLinkLibrary.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (C) 2023 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 9a3df81..0000000
--- a/Source/HarmonyLink/Public/HarmonyLinkLibrary.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2023 Jordon Brooks
-
-#pragma once
-
-#include "CoreMinimal.h"
-#include "Kismet/BlueprintFunctionLibrary.h"
-#include "Structs/Battery.h"
-#include "Structs/CPUInfo.h"
-#include "Structs/Device.h"
-#include "Structs/OSVerInfo.h"
-#include "HarmonyLinkLibrary.generated.h"
-
-/**
- *
- */
-UCLASS()
-class HARMONYLINK_API UHarmonyLinkLibrary : public UBlueprintFunctionLibrary
-{
- GENERATED_BODY()
-
- UFUNCTION(BlueprintCallable, Category="HarmonyLink")
- static bool IsWine();
-
- UFUNCTION(BlueprintCallable, Category="HarmonyLink")
- static bool IsLinux();
-
- UFUNCTION(BlueprintCallable, Category="HarmonyLink")
- static bool IsSteamDeck();
-
- UFUNCTION(BlueprintCallable, Category="HarmonyLink")
- static FCPUInfo GetCPUInfo();
-
- UFUNCTION(BlueprintCallable, Category="HarmonyLink")
- static FDevice GetDeviceInfo();
-
- UFUNCTION(BlueprintCallable, Category="HarmonyLink")
- static FOSVerInfo GetOSInfo();
-
- UFUNCTION(BlueprintCallable, Category="HarmonyLink")
- static FBattery GetBatteryStatus();
-};
diff --git a/Source/HarmonyLink/Public/Structs/Battery.h b/Source/HarmonyLink/Public/Structs/Battery.h
deleted file mode 100644
index fd4c278..0000000
--- a/Source/HarmonyLink/Public/Structs/Battery.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2023 Jordon Brooks
-#pragma once
-
-#include
-
-#include "CoreMinimal.h"
-#include "Battery.generated.h"
-
-/**
- *
- */
-USTRUCT(BlueprintType)
-struct FBattery
-{
- GENERATED_BODY()
-
- FBattery() {}
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- bool HasBattery = false;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- bool IsACConnected = false;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- int32 BatteryPercent = 0;
-
- FBattery(HarmonyLinkLib::FBattery* battery);
-};
diff --git a/Source/HarmonyLink/Public/Structs/CPUInfo.h b/Source/HarmonyLink/Public/Structs/CPUInfo.h
deleted file mode 100644
index 97d0f95..0000000
--- a/Source/HarmonyLink/Public/Structs/CPUInfo.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (C) 2023 Jordon Brooks
-
-#pragma once
-
-#include
-
-#include "CoreMinimal.h"
-#include "CPUInfo.generated.h"
-
-/**
- *
- */
-USTRUCT(BlueprintType)
-struct FCPUInfo
-{
- GENERATED_BODY()
-
- FCPUInfo() {}
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- FString VendorID;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- FString ModelName;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- int32 PhysicalCores = 0;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- int32 LogicalCores = 0;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- TSet Flags;
-
- FCPUInfo(HarmonyLinkLib::FCPUInfo* cpu_info);
-};
diff --git a/Source/HarmonyLink/Public/Structs/Device.h b/Source/HarmonyLink/Public/Structs/Device.h
deleted file mode 100644
index 00c7ad2..0000000
--- a/Source/HarmonyLink/Public/Structs/Device.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "Enums/DeviceEnum.h"
-#include "Enums/Platform.h"
-#include
-
-#include "Device.generated.h"
-
-/**
- *
- */
-USTRUCT(BlueprintType)
-struct FDevice
-{
- GENERATED_BODY()
-
- FDevice() {}
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- EPlatform Platform = EPlatform::WINDOWS;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- EDeviceEnum Device = EDeviceEnum::DESKTOP;
-
- FDevice(HarmonyLinkLib::FDevice* oldDevice);
-
- static EDeviceEnum Convert(HarmonyLinkLib::EDevice Device);
- static EPlatform Convert(HarmonyLinkLib::EPlatform Platform);
-};
diff --git a/Source/HarmonyLink/Public/Structs/OSVerInfo.h b/Source/HarmonyLink/Public/Structs/OSVerInfo.h
deleted file mode 100644
index 9d4474f..0000000
--- a/Source/HarmonyLink/Public/Structs/OSVerInfo.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (C) 2023 Jordon Brooks
-#pragma once
-
-#include
-
-#include "CoreMinimal.h"
-
-#include "OSVerInfo.generated.h"
-
-/**
- *
- */
-USTRUCT(BlueprintType)
-struct FOSVerInfo
-{
- GENERATED_BODY()
-
- FOSVerInfo() {}
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- FString Name;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- int32 Version = 0;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- FString ID;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- FString VersionID;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- FString VersionCodename;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- FString PrettyName;
-
- UPROPERTY(BlueprintReadWrite, EditAnywhere)
- FString VariantID;
-
- FOSVerInfo(HarmonyLinkLib::FOSVerInfo* oldInfo);
-};
diff --git a/Source/HarmonyLinkSettings/HarmonyLinkSettings.Build.cs b/Source/HarmonyLinkSettings/HarmonyLinkSettings.Build.cs
new file mode 100644
index 0000000..e4912ff
--- /dev/null
+++ b/Source/HarmonyLinkSettings/HarmonyLinkSettings.Build.cs
@@ -0,0 +1,28 @@
+// Copyright (C) 2024 Jordon Brooks
+
+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..6f4680e
--- /dev/null
+++ b/Source/HarmonyLinkSettings/Private/HarmonyLinkSettings.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2024 Jordon Brooks
+
+#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..6626493
--- /dev/null
+++ b/Source/HarmonyLinkSettings/Public/HarmonyLinkSettings.h
@@ -0,0 +1,15 @@
+// Copyright (C) 2024 Jordon Brooks
+
+#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/HarmonyLink/HarmonyLink.Build.cs b/Source/HarmonyLinkUE/HarmonyLinkUE.Build.cs
similarity index 52%
rename from Source/HarmonyLink/HarmonyLink.Build.cs
rename to Source/HarmonyLinkUE/HarmonyLinkUE.Build.cs
index ede23b2..56b5629 100644
--- a/Source/HarmonyLink/HarmonyLink.Build.cs
+++ b/Source/HarmonyLinkUE/HarmonyLinkUE.Build.cs
@@ -1,13 +1,15 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
+// Copyright (C) 2024 Jordon Brooks
using UnrealBuildTool;
using System.IO;
-public class HarmonyLink : ModuleRules
+public class HarmonyLinkUE : ModuleRules
{
- public HarmonyLink(ReadOnlyTargetRules Target) : base(Target)
+ public HarmonyLinkUE(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
+
+ //IWYUSupport = IWYUSupport.Full;
PublicIncludePaths.AddRange(
new string[] {
@@ -19,7 +21,6 @@ public class HarmonyLink : ModuleRules
PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
- "ThirdParty/HarmonyLinkLib/include"
}
);
@@ -30,7 +31,8 @@ public class HarmonyLink : ModuleRules
"Core",
"CoreUObject",
"Engine",
- "Projects"
+
+ "HarmonyLinkLib",
// ... add other public dependencies that you statically link with here ...
}
);
@@ -39,21 +41,9 @@ public class HarmonyLink : ModuleRules
PrivateDependencyModuleNames.AddRange(
new string[]
{
- // ... add private dependencies that you statically link with here ...
+ // ... add private dependencies that you statically link with here ...
}
);
-
-
- DynamicallyLoadedModuleNames.AddRange(
- new string[]
- {
- // ... add any modules that your module loads dynamically here ...
- }
- );
-
- 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"));
}
}
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 90%
rename from Source/HarmonyLink/Private/Structs/Battery.cpp
rename to Source/HarmonyLinkUE/Private/Structs/Battery.cpp
index 3978e75..0b23e6d 100644
--- a/Source/HarmonyLink/Private/Structs/Battery.cpp
+++ b/Source/HarmonyLinkUE/Private/Structs/Battery.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2023 Jordon Brooks
+// Copyright (C) 2024 Jordon Brooks
#include "Structs/Battery.h"
diff --git a/Source/HarmonyLink/Private/Structs/CPUInfo.cpp b/Source/HarmonyLinkUE/Private/Structs/CPUInfo.cpp
similarity index 73%
rename from Source/HarmonyLink/Private/Structs/CPUInfo.cpp
rename to Source/HarmonyLinkUE/Private/Structs/CPUInfo.cpp
index f075203..8b70135 100644
--- a/Source/HarmonyLink/Private/Structs/CPUInfo.cpp
+++ b/Source/HarmonyLinkUE/Private/Structs/CPUInfo.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2023 Jordon Brooks
+// Copyright (C) 2024 Jordon Brooks
#include "Structs/CPUInfo.h"
@@ -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 77%
rename from Source/HarmonyLink/Private/Structs/Device.cpp
rename to Source/HarmonyLinkUE/Private/Structs/Device.cpp
index 1e2845a..794e914 100644
--- a/Source/HarmonyLink/Private/Structs/Device.cpp
+++ b/Source/HarmonyLinkUE/Private/Structs/Device.cpp
@@ -1,4 +1,6 @@
-#include "Structs/Device.h"
+// Copyright (C) 2024 Jordon Brooks
+
+#include "Structs/Device.h"
#include
@@ -17,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 82%
rename from Source/HarmonyLink/Private/Structs/OSVerInfo.cpp
rename to Source/HarmonyLinkUE/Private/Structs/OSVerInfo.cpp
index 1d502bb..36f3671 100644
--- a/Source/HarmonyLink/Private/Structs/OSVerInfo.cpp
+++ b/Source/HarmonyLinkUE/Private/Structs/OSVerInfo.cpp
@@ -1,4 +1,6 @@
-#include "Structs/OSVerInfo.h"
+// Copyright (C) 2024 Jordon Brooks
+
+#include "Structs/OSVerInfo.h"
FOSVerInfo::FOSVerInfo(HarmonyLinkLib::FOSVerInfo* oldInfo)
{
diff --git a/Source/HarmonyLink/Public/Enums/DeviceEnum.h b/Source/HarmonyLinkUE/Public/Enums/DeviceEnum.h
similarity index 65%
rename from Source/HarmonyLink/Public/Enums/DeviceEnum.h
rename to Source/HarmonyLinkUE/Public/Enums/DeviceEnum.h
index fe3aa8e..fb7bb44 100644
--- a/Source/HarmonyLink/Public/Enums/DeviceEnum.h
+++ b/Source/HarmonyLinkUE/Public/Enums/DeviceEnum.h
@@ -1,13 +1,15 @@
-#pragma once
+// Copyright (C) 2024 Jordon Brooks
+
+#pragma once
#include "CoreMinimal.h"
#include "DeviceEnum.generated.h"
-/**
- *
+/*
+ * 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 57%
rename from Source/HarmonyLink/Public/Enums/Platform.h
rename to Source/HarmonyLinkUE/Public/Enums/Platform.h
index 492c31b..9ab89dc 100644
--- a/Source/HarmonyLink/Public/Enums/Platform.h
+++ b/Source/HarmonyLinkUE/Public/Enums/Platform.h
@@ -1,10 +1,15 @@
-#pragma once
+// Copyright (C) 2024 Jordon Brooks
+
+#pragma once
#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.
*/
UENUM(BlueprintType)
enum class EPlatform : uint8
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 56%
rename from Source/HarmonyLink/Public/HarmonyLink.h
rename to Source/HarmonyLinkUE/Public/HarmonyLinkUE.h
index 116fad0..b88bb95 100644
--- a/Source/HarmonyLink/Public/HarmonyLink.h
+++ b/Source/HarmonyLinkUE/Public/HarmonyLinkUE.h
@@ -1,10 +1,12 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
+// Copyright (C) 2024 Jordon Brooks
#pragma once
#include "Modules/ModuleManager.h"
-class FHarmonyLinkModule : public IModuleInterface
+DECLARE_LOG_CATEGORY_EXTERN(LogHarmonyLink, All, All);
+
+class FHarmonyLinkUEModule : public IModuleInterface
{
public:
diff --git a/Source/HarmonyLinkUE/Public/Structs/Battery.h b/Source/HarmonyLinkUE/Public/Structs/Battery.h
new file mode 100644
index 0000000..bd2793b
--- /dev/null
+++ b/Source/HarmonyLinkUE/Public/Structs/Battery.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2024 Jordon Brooks
+#pragma once
+
+#include "CoreMinimal.h"
+
+#include "Structs/FBattery.h"
+
+#include "Battery.generated.h"
+
+/*
+ * Represents the battery status and information of a device.
+ */
+USTRUCT(BlueprintType)
+struct FBattery
+{
+ GENERATED_BODY()
+
+ FBattery() {}
+
+ // Indicates whether the device has a battery.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ bool HasBattery = false;
+
+ // Indicates whether the device is connected to AC power.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ bool IsACConnected = false;
+
+ // The current battery percentage of the device.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ int32 BatteryPercent = 0;
+
+ // Constructor that initializes the struct with information from an external battery source.
+ // @param battery Pointer to an external FBattery structure to copy data from.
+ FBattery(HarmonyLinkLib::FBattery* battery);
+};
diff --git a/Source/HarmonyLinkUE/Public/Structs/CPUInfo.h b/Source/HarmonyLinkUE/Public/Structs/CPUInfo.h
new file mode 100644
index 0000000..353c3e5
--- /dev/null
+++ b/Source/HarmonyLinkUE/Public/Structs/CPUInfo.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2024 Jordon Brooks
+
+#pragma once
+
+#include "CoreMinimal.h"
+
+#include "Structs/FCPUInfo.h"
+
+#include "CPUInfo.generated.h"
+
+/*
+ * Represents information about the CPU of a device.
+ */
+USTRUCT(BlueprintType)
+struct FCPUInfo
+{
+ GENERATED_BODY()
+
+ FCPUInfo() {}
+
+ // The vendor identifier for the CPU.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ FString VendorID;
+
+ // The model name of the CPU.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ FString ModelName;
+
+ // The number of physical cores in the CPU.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ int32 PhysicalCores = 0;
+
+ // The number of logical cores in the CPU (may be different from physical cores).
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ int32 LogicalCores = 0;
+
+ // 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/HarmonyLinkUE/Public/Structs/Device.h b/Source/HarmonyLinkUE/Public/Structs/Device.h
new file mode 100644
index 0000000..fd009bd
--- /dev/null
+++ b/Source/HarmonyLinkUE/Public/Structs/Device.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2024 Jordon Brooks
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Enums/DeviceEnum.h"
+#include "Enums/Platform.h"
+
+#include "Structs/FDevice.h"
+
+#include "Device.generated.h"
+
+// Represents information about a specific device.
+USTRUCT(BlueprintType)
+struct FDevice
+{
+ GENERATED_BODY()
+
+ FDevice() {}
+
+ // The platform on which the device operates. Note: This can differ from the build platform.
+ // For example, if the device is identified as running on Wine, this will show Linux,
+ // regardless of the build being an executable for Windows.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ EPlatform Platform = EPlatform::WINDOWS;
+
+ // The type of the device.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ 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.
+ FDevice(HarmonyLinkLib::FDevice* oldDevice);
+
+private:
+ // Converts an external device enum to the internal EDeviceEnum type.
+ // @param Device External device enum to convert.
+ // @returns Converted EDeviceEnum value.
+ static EDevice Convert(HarmonyLinkLib::EDevice Device);
+
+ // Converts an external platform enum to the internal EPlatform type.
+ // @param Platform External platform enum to convert.
+ // @returns Converted EPlatform value.
+ static EPlatform Convert(HarmonyLinkLib::EPlatform Platform);
+};
diff --git a/Source/HarmonyLinkUE/Public/Structs/OSVerInfo.h b/Source/HarmonyLinkUE/Public/Structs/OSVerInfo.h
new file mode 100644
index 0000000..e423cc0
--- /dev/null
+++ b/Source/HarmonyLinkUE/Public/Structs/OSVerInfo.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2024 Jordon Brooks
+#pragma once
+
+#include "CoreMinimal.h"
+
+#include "Structs/FOSVerInfo.h"
+
+#include "OSVerInfo.generated.h"
+
+// Represents information about an operating system version.
+USTRUCT(BlueprintType)
+struct FOSVerInfo
+{
+ GENERATED_BODY()
+
+ FOSVerInfo() {}
+
+ // The name of the operating system.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ FString Name;
+
+ // Numerical version of the operating system.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ int32 Version = 0;
+
+ // Unique identifier for the operating system.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ FString ID;
+
+ // Identifier for the specific version of the operating system.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ FString VersionID;
+
+ // Codename for the operating system version.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ FString VersionCodename;
+
+ // User-friendly name for the operating system version.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ FString PrettyName;
+
+ // Variant identifier of the operating system.
+ UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="HarmonyLink")
+ FString VariantID;
+
+ // Constructor that initializes the struct with information from an external source.
+ // @param oldInfo Pointer to an external FOSVerInfo structure to copy data from.
+ FOSVerInfo(HarmonyLinkLib::FOSVerInfo* oldInfo);
+};
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 0daf6e2..0000000
Binary files a/Source/ThirdParty/HarmonyLinkLib/bin/Linux/libHarmonyLinkLib.so and /dev/null differ
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 c020eef..0000000
Binary files a/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.dll and /dev/null differ
diff --git a/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.lib b/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.lib
deleted file mode 100644
index ce48844..0000000
Binary files a/Source/ThirdParty/HarmonyLinkLib/bin/Win64/HarmonyLinkLib.lib and /dev/null differ
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 90d63b4..90babed 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/Core.h
+++ b/Source/ThirdParty/HarmonyLinkLib/include/Core.h
@@ -1,14 +1,38 @@
-// Copyright (C) 2023 Jordon Brooks
+// 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
// 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 75d3cc5..c11919d 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/Enums/EDevice.h
+++ b/Source/ThirdParty/HarmonyLinkLib/include/Enums/EDevice.h
@@ -1,5 +1,22 @@
+// 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
+// Undefine the LINUX macro to avoid conflicts with the enum definition.
+#undef LINUX
+
#include
// Enum class for representing different types of devices
@@ -7,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 c050ca3..ffa2be7 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/Enums/EPlatform.h
+++ b/Source/ThirdParty/HarmonyLinkLib/include/Enums/EPlatform.h
@@ -1,3 +1,17 @@
+// 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
@@ -7,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/FString.h b/Source/ThirdParty/HarmonyLinkLib/include/FString.h
index 3f23dc1..68ae766 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/FString.h
+++ b/Source/ThirdParty/HarmonyLinkLib/include/FString.h
@@ -1,4 +1,16 @@
-// Copyright (C) 2024 Jordon Brooks
+// 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
diff --git a/Source/ThirdParty/HarmonyLinkLib/include/HarmonyLinkLib.h b/Source/ThirdParty/HarmonyLinkLib/include/HarmonyLinkLib.h
index 94f07ed..0298e2d 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/HarmonyLinkLib.h
+++ b/Source/ThirdParty/HarmonyLinkLib/include/HarmonyLinkLib.h
@@ -1,4 +1,35 @@
-// Copyright (C) 2023 Jordon Brooks
+// 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.
+
+
+/**
+ * IMPORTANT REMINDER:
+ * Do NOT use standard output functions like std::cout and printf anywhere in this codebase.
+ *
+ * Reason:
+ * Unreal Engine 5's packaging tool encounters issues with these functions, leading to
+ * packaging failures. The engine sets stdout to UTF-8, which can cause conflicts with
+ * these standard functions, resulting in a "SECURE CRT: Invalid parameter detected" error
+ * during packaging.
+ *
+ * This issue once required an extensive debugging effort that lasted over 8 hours.
+ * To prevent similar issues in the future and ensure smooth packaging, always use
+ * wide-character versions of these functions, such as wprintf and std::wcout, when working
+ * within the DLL. These functions are compatible with the UTF-8 setting in Unreal Engine 5.
+ *
+ */
+
#pragma once
@@ -13,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/HarmonyLinkStruct.h b/Source/ThirdParty/HarmonyLinkLib/include/HarmonyLinkStruct.h
index aa4497d..362750b 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/HarmonyLinkStruct.h
+++ b/Source/ThirdParty/HarmonyLinkLib/include/HarmonyLinkStruct.h
@@ -1,3 +1,17 @@
+// 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
struct HarmonyLinkStruct
diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Structs/FBattery.h b/Source/ThirdParty/HarmonyLinkLib/include/Structs/FBattery.h
index 6c41595..3a40095 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/Structs/FBattery.h
+++ b/Source/ThirdParty/HarmonyLinkLib/include/Structs/FBattery.h
@@ -1,4 +1,18 @@
-#pragma once
+// 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
#include
diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Structs/FCPUInfo.h b/Source/ThirdParty/HarmonyLinkLib/include/Structs/FCPUInfo.h
index 8694e6a..827bc40 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/Structs/FCPUInfo.h
+++ b/Source/ThirdParty/HarmonyLinkLib/include/Structs/FCPUInfo.h
@@ -1,3 +1,17 @@
+// 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
diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Structs/FDevice.h b/Source/ThirdParty/HarmonyLinkLib/include/Structs/FDevice.h
index 204a5da..b574d6a 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/Structs/FDevice.h
+++ b/Source/ThirdParty/HarmonyLinkLib/include/Structs/FDevice.h
@@ -1,16 +1,32 @@
+// 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
#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/include/Structs/FOSVerInfo.h b/Source/ThirdParty/HarmonyLinkLib/include/Structs/FOSVerInfo.h
index 6b62db3..a308a22 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/Structs/FOSVerInfo.h
+++ b/Source/ThirdParty/HarmonyLinkLib/include/Structs/FOSVerInfo.h
@@ -1,4 +1,18 @@
-#pragma once
+// 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 "FString.h"
#include "HarmonyLinkStruct.h"
diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Version.h b/Source/ThirdParty/HarmonyLinkLib/include/Version.h
index 61d6e3f..dcc9d33 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/Version.h
+++ b/Source/ThirdParty/HarmonyLinkLib/include/Version.h
@@ -1,4 +1,17 @@
-// Copyright (C) 2024 Jordon Brooks
+// 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 "Core.h"
diff --git a/Source/ThirdParty/HarmonyLinkLib/include/Version.h.in b/Source/ThirdParty/HarmonyLinkLib/include/Version.h.in
index 4081f8d..08881c5 100644
--- a/Source/ThirdParty/HarmonyLinkLib/include/Version.h.in
+++ b/Source/ThirdParty/HarmonyLinkLib/include/Version.h.in
@@ -1,3 +1,17 @@
+// 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.
+
// Version.h.in
#pragma once
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