From f0ea613a2642674b34f39453b4c86c25ac15cb99 Mon Sep 17 00:00:00 2001 From: "Nuno \"Omega Leo\" Diogo" Date: Mon, 13 Apr 2026 23:30:43 +0100 Subject: [PATCH] Started working on a SteamWorks integration --- .idea/indexLayout.xml | 8 + .idea/projectSettingsUpdater.xml | 7 + .idea/vcs.xml | 6 + .idea/workspace.xml | 73 ++++ .vscode/settings.json | 1 + .../OmegaLeo.HelperLib.ConsoleApp.csproj | 9 +- OmegaLeo.HelperLib.ConsoleApp/Program.cs | 107 +---- OmegaLeo.HelperLib.ConsoleApp/steam_appid.txt | 1 + OmegaLeo.HelperLib.Steamworks/.gitignore | 1 + .../AchievementManager.cs | 27 ++ .../OmegaLeo.HelperLib.Steamworks.csproj | 18 + OmegaLeo.HelperLib.Steamworks/README.md | 49 +++ OmegaLeo.HelperLib.Steamworks/SteamManager.cs | 79 ++++ .../SteamNativeApi.cs | 398 ++++++++++++++++++ OmegaLeo.HelperLib.sln | 92 +++- OmegaLeo.HelperLib.sln.DotSettings.user | 3 + 16 files changed, 787 insertions(+), 92 deletions(-) create mode 100644 .idea/indexLayout.xml create mode 100644 .idea/projectSettingsUpdater.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/workspace.xml create mode 100644 .vscode/settings.json create mode 100644 OmegaLeo.HelperLib.ConsoleApp/steam_appid.txt create mode 100644 OmegaLeo.HelperLib.Steamworks/.gitignore create mode 100644 OmegaLeo.HelperLib.Steamworks/AchievementManager.cs create mode 100644 OmegaLeo.HelperLib.Steamworks/OmegaLeo.HelperLib.Steamworks.csproj create mode 100644 OmegaLeo.HelperLib.Steamworks/README.md create mode 100644 OmegaLeo.HelperLib.Steamworks/SteamManager.cs create mode 100644 OmegaLeo.HelperLib.Steamworks/SteamNativeApi.cs diff --git a/.idea/indexLayout.xml b/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/projectSettingsUpdater.xml b/.idea/projectSettingsUpdater.xml new file mode 100644 index 0000000..64af657 --- /dev/null +++ b/.idea/projectSettingsUpdater.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..a973b1e --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 1776109424996 + + + + + + + + + + + + + \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/OmegaLeo.HelperLib.ConsoleApp/OmegaLeo.HelperLib.ConsoleApp.csproj b/OmegaLeo.HelperLib.ConsoleApp/OmegaLeo.HelperLib.ConsoleApp.csproj index 649c15b..1c1dae4 100755 --- a/OmegaLeo.HelperLib.ConsoleApp/OmegaLeo.HelperLib.ConsoleApp.csproj +++ b/OmegaLeo.HelperLib.ConsoleApp/OmegaLeo.HelperLib.ConsoleApp.csproj @@ -2,14 +2,21 @@ Exe - net8.0 + net9.0 enable enable + + + + Always + + + diff --git a/OmegaLeo.HelperLib.ConsoleApp/Program.cs b/OmegaLeo.HelperLib.ConsoleApp/Program.cs index e56ba62..8b62339 100755 --- a/OmegaLeo.HelperLib.ConsoleApp/Program.cs +++ b/OmegaLeo.HelperLib.ConsoleApp/Program.cs @@ -2,101 +2,28 @@ // /media/omegaleo/Development/Library Dev/HelperLib -using System.Reflection; -using OmegaLeo.HelperLib.Extensions; -using OmegaLeo.HelperLib.Helpers; -using LibGit2Sharp; -using OmegaLeo.HelperLib.Changelog.Tools; -using OmegaLeo.HelperLib.Git; -using OmegaLeo.HelperLib.Git.Models; +using System; +using System.Collections.Generic; +using OmegaLeo.HelperLib.Steamworks; -Console.WriteLine("Insert repo path to check changes:"); -var repo = Console.ReadLine(); - -if (repo.IsNullOrEmpty()) +public class Program { - repo = "/media/omegaleo/Development/Library Dev/HelperLib"; -} - -var git = new GitClient(repo); - -var result = BenchmarkUtility.Record(() => -{ - var changes = git.GetChanges(); - - if (changes.FolderName.IsNotNullOrEmpty()) + public static void Main() { - RecursiveOutput(new List() { changes }); - - var option = 99; - - while (option != 0) + SteamManager.ConfigureAppId(480); // 480 is the AppId for Spacewar, a test app provided by Valve + + var steam = SteamManager.Instance; + if (steam.IsSteamworksInitialized) { - ShowOptions(); - if (option != 99) - { - switch (option) - { - case 1: - Console.WriteLine("Write the commit message"); - var msg = Console.ReadLine(); - - while (msg.IsNullOrEmpty()) - { - Console.WriteLine("Empty message detected, please write a commit message..."); - msg = Console.ReadLine(); - } - - var signature = new Signature("Nuno 'Omega Leo' Diogo", "nunodiogo@omegaleo.pt", - DateTimeOffset.Now); - git.Commit(msg, signature); - - break; - case 2: - git.Push(); - break; - default: - Console.WriteLine("Invalid Option!"); - break; - } - } - - int.TryParse(Console.ReadLine(), out option); - } - } - else - { - Console.WriteLine("No changes found in specified repository"); - } -}); - -Console.WriteLine($"Time for checking for changes: {result} ms"); - -Console.ReadLine(); - - -void RecursiveOutput(List folders, int depth = 0) -{ - foreach (var folder in folders) - { - Console.WriteLine($"{new string('\t', depth)}>{folder.FolderName}"); - if (folder.SubFolders.Any()) - { - RecursiveOutput(folder.SubFolders, depth + 1); + Console.WriteLine($"Welcome {steam.GetSteamName()}"); } - foreach (var change in folder.ChangesInFolder) - { - Console.WriteLine($"{new string('\t', depth + 1)}>{Path.GetFileName(change.Path)} ({change.Status})"); - } - } -} + // Call this in your game loop (Unity Update, Godot _Process, etc.) + steam.Update(); -void ShowOptions() -{ - Console.Clear(); - Console.WriteLine(new string('=', 20)); - Console.WriteLine("What do you want to do in this repository?"); - Console.WriteLine("1. Commit all changes"); - Console.WriteLine("2. Push"); + //var achievements = new AchievementManager(); + //achievements.UnlockAchievement("ACH_FIRST_WIN"); + + steam.Shutdown(); + } } \ No newline at end of file diff --git a/OmegaLeo.HelperLib.ConsoleApp/steam_appid.txt b/OmegaLeo.HelperLib.ConsoleApp/steam_appid.txt new file mode 100644 index 0000000..7ad8022 --- /dev/null +++ b/OmegaLeo.HelperLib.ConsoleApp/steam_appid.txt @@ -0,0 +1 @@ +480 \ No newline at end of file diff --git a/OmegaLeo.HelperLib.Steamworks/.gitignore b/OmegaLeo.HelperLib.Steamworks/.gitignore new file mode 100644 index 0000000..a505c1e --- /dev/null +++ b/OmegaLeo.HelperLib.Steamworks/.gitignore @@ -0,0 +1 @@ +runtimes/ \ No newline at end of file diff --git a/OmegaLeo.HelperLib.Steamworks/AchievementManager.cs b/OmegaLeo.HelperLib.Steamworks/AchievementManager.cs new file mode 100644 index 0000000..3d83ee8 --- /dev/null +++ b/OmegaLeo.HelperLib.Steamworks/AchievementManager.cs @@ -0,0 +1,27 @@ +using System; + +namespace OmegaLeo.HelperLib.Steamworks +{ + public class AchievementManager + { + public void UnlockAchievement(string achievementId) + { + if (SteamManager.Instance.IsSteamworksInitialized) + { + SteamNativeApi.SetAchievement(achievementId); + SteamNativeApi.StoreStats(); // Don't forget to store the stats + Console.WriteLine($"Attempting to unlock achievement: {achievementId}"); + } + } + + public bool IsAchievementUnlocked(string achievementId, out bool unlocked) + { + unlocked = false; + if (SteamManager.Instance.IsSteamworksInitialized) + { + return SteamNativeApi.GetAchievement(achievementId, out unlocked); + } + return false; + } + } +} diff --git a/OmegaLeo.HelperLib.Steamworks/OmegaLeo.HelperLib.Steamworks.csproj b/OmegaLeo.HelperLib.Steamworks/OmegaLeo.HelperLib.Steamworks.csproj new file mode 100644 index 0000000..06aa70d --- /dev/null +++ b/OmegaLeo.HelperLib.Steamworks/OmegaLeo.HelperLib.Steamworks.csproj @@ -0,0 +1,18 @@ + + + + netstandard2.1 + 9 + + + + + + + true + runtimes\%(RecursiveDir)%(Filename)%(Extension) + PreserveNewest + + + + diff --git a/OmegaLeo.HelperLib.Steamworks/README.md b/OmegaLeo.HelperLib.Steamworks/README.md new file mode 100644 index 0000000..af56817 --- /dev/null +++ b/OmegaLeo.HelperLib.Steamworks/README.md @@ -0,0 +1,49 @@ +# OmegaLeo's Helper Library - Steamworks +Lightweight Steamworks helper library for C# game projects. + +This package provides a simple Steam API wrapper for common tasks like initialization, callback processing, player name lookup, and achievements. + +## Features +- Simple Steam initialization via `SteamManager.Instance` +- Per-frame callback runner with `SteamManager.Update()` +- Safe shutdown with `SteamManager.Shutdown()` +- Player persona name access with `SteamManager.GetSteamName()` +- Achievement helpers via `AchievementManager` +- Includes native Steam runtime files in NuGet package `runtimes/` + +## Installation +```bash +dotnet add package OmegaLeo.HelperLib.Steamworks +``` + +## Quick Start +```cs +using OmegaLeo.HelperLib.Steamworks; + +// Optional but recommended for local/editor runs. +SteamManager.ConfigureAppId(480); // Replace with your real AppId. + +var steam = SteamManager.Instance; +if (steam.IsSteamworksInitialized) +{ + Console.WriteLine($"Welcome {steam.GetSteamName()}"); +} + +// Call this in your game loop (Unity Update, Godot _Process, etc.) +steam.Update(); + +var achievements = new AchievementManager(); +achievements.UnlockAchievement("ACH_FIRST_WIN"); + +steam.Shutdown(); +``` + +## Notes +- Steam must be running and your app must be launched in a valid Steam context. +- Configure your AppId before first access to `SteamManager.Instance`. +- `SteamManager.Update()` should be called continuously during runtime. +- If Steam is unavailable, `GetSteamName()` falls back to `"Player"`. + +## License +Open source under the AGPL v3 License. See the repository `LICENSE` for details. + diff --git a/OmegaLeo.HelperLib.Steamworks/SteamManager.cs b/OmegaLeo.HelperLib.Steamworks/SteamManager.cs new file mode 100644 index 0000000..22ba6fb --- /dev/null +++ b/OmegaLeo.HelperLib.Steamworks/SteamManager.cs @@ -0,0 +1,79 @@ +using System; + +namespace OmegaLeo.HelperLib.Steamworks +{ + public class SteamManager + { + private static SteamManager _instance; + private static uint? _configuredAppId; + public static SteamManager Instance => _instance ??= new SteamManager(); + + public static bool ConfigureAppId(uint appId) + { + if (appId == 0) + { + return false; + } + + // AppId must be configured before the singleton is created. + if (_instance != null) + { + return false; + } + + _configuredAppId = appId; + SteamNativeApi.ConfigureAppId(appId); + return true; + } + + public bool IsSteamworksInitialized { get; private set; } + + private SteamManager() + { + try + { + // Attempt to initialize Steamworks + if (SteamNativeApi.Initialize(_configuredAppId)) + { + IsSteamworksInitialized = true; + Console.WriteLine("Steamworks Initialized Successfully!"); + } + else + { + Console.WriteLine("Steamworks Initialization Failed. Is Steam running?"); + } + } + catch (Exception e) + { + Console.WriteLine($"An exception occurred during Steamworks initialization: {e.Message}"); + } + } + + // This must be called from your game's main loop (e.g., Update in Unity/Godot) + public void Update() + { + if (IsSteamworksInitialized) + { + SteamNativeApi.RunCallbacks(); + } + } + + public void Shutdown() + { + if (IsSteamworksInitialized) + { + SteamNativeApi.Shutdown(); + IsSteamworksInitialized = false; + } + } + + public string GetSteamName() + { + if (IsSteamworksInitialized) + { + return SteamNativeApi.GetPersonaName(); + } + return "Player"; + } + } +} diff --git a/OmegaLeo.HelperLib.Steamworks/SteamNativeApi.cs b/OmegaLeo.HelperLib.Steamworks/SteamNativeApi.cs new file mode 100644 index 0000000..1519df1 --- /dev/null +++ b/OmegaLeo.HelperLib.Steamworks/SteamNativeApi.cs @@ -0,0 +1,398 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace OmegaLeo.HelperLib.Steamworks +{ + internal static class SteamNativeApi + { + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool SteamApiInitDelegate(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void SteamApiVoidDelegate(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate IntPtr SteamFriendsAccessorDelegate(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate IntPtr SteamUserStatsAccessorDelegate(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate IntPtr SteamFriendsGetPersonaNameDelegate(IntPtr steamFriends); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool SteamUserStatsSetAchievementDelegate(IntPtr steamUserStats, [MarshalAs(UnmanagedType.LPStr)] string achievementId); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool SteamUserStatsStoreStatsDelegate(IntPtr steamUserStats); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool SteamUserStatsGetAchievementDelegate(IntPtr steamUserStats, [MarshalAs(UnmanagedType.LPStr)] string achievementId, [MarshalAs(UnmanagedType.I1)] out bool achieved); + + private static readonly object SyncRoot = new object(); + + private static IntPtr _libraryHandle; + private static bool _libraryLoaded; + private static bool _initialized; + + private static SteamApiInitDelegate _steamApiInit; + private static SteamApiVoidDelegate _steamApiShutdown; + private static SteamApiVoidDelegate _steamApiRunCallbacks; + private static SteamFriendsAccessorDelegate _steamFriendsAccessor; + private static SteamUserStatsAccessorDelegate _steamUserStatsAccessor; + private static SteamFriendsGetPersonaNameDelegate _steamFriendsGetPersonaName; + private static SteamUserStatsSetAchievementDelegate _steamUserStatsSetAchievement; + private static SteamUserStatsStoreStatsDelegate _steamUserStatsStoreStats; + private static SteamUserStatsGetAchievementDelegate _steamUserStatsGetAchievement; + + private static IntPtr _steamFriends; + private static IntPtr _steamUserStats; + + public static bool IsAvailable => EnsureLoaded(); + + public static bool Initialize(uint? appId = null) + { + lock (SyncRoot) + { + if (appId.HasValue && appId.Value > 0) + { + ConfigureAppId(appId.Value); + } + + if (_initialized) + { + return true; + } + + if (!EnsureLoaded()) + { + return false; + } + + if (_steamApiInit == null) + { + return false; + } + + _initialized = _steamApiInit(); + if (_initialized) + { + CacheInterfaces(); + } + + return _initialized; + } + } + + public static void ConfigureAppId(uint appId) + { + if (appId == 0) + { + return; + } + + lock (SyncRoot) + { + ApplyAppIdEnvironment(appId); + TryWriteSteamAppIdFile(appId); + } + } + + public static void Shutdown() + { + lock (SyncRoot) + { + if (!_initialized) + { + return; + } + + _steamApiShutdown?.Invoke(); + _initialized = false; + _steamFriends = IntPtr.Zero; + _steamUserStats = IntPtr.Zero; + } + } + + public static void RunCallbacks() + { + if (!_initialized) + { + return; + } + + _steamApiRunCallbacks?.Invoke(); + } + + public static string GetPersonaName() + { + if (!EnsureReady()) + { + return string.Empty; + } + + var namePtr = _steamFriendsGetPersonaName?.Invoke(_steamFriends) ?? IntPtr.Zero; + return namePtr == IntPtr.Zero ? string.Empty : Marshal.PtrToStringAnsi(namePtr) ?? string.Empty; + } + + public static bool SetAchievement(string achievementId) + { + if (!EnsureReady()) + { + return false; + } + + return _steamUserStatsSetAchievement?.Invoke(_steamUserStats, achievementId) ?? false; + } + + public static bool StoreStats() + { + if (!EnsureReady()) + { + return false; + } + + return _steamUserStatsStoreStats?.Invoke(_steamUserStats) ?? false; + } + + public static bool GetAchievement(string achievementId, out bool achieved) + { + achieved = false; + + if (!EnsureReady()) + { + return false; + } + + return _steamUserStatsGetAchievement?.Invoke(_steamUserStats, achievementId, out achieved) ?? false; + } + + private static bool EnsureReady() + { + if (!EnsureLoaded()) + { + return false; + } + + if (!_initialized) + { + return false; + } + + if (_steamFriends == IntPtr.Zero || _steamUserStats == IntPtr.Zero) + { + CacheInterfaces(); + } + + return _steamFriends != IntPtr.Zero && _steamUserStats != IntPtr.Zero; + } + + private static bool EnsureLoaded() + { + lock (SyncRoot) + { + if (_libraryLoaded) + { + return true; + } + + foreach (var candidate in GetLibraryCandidates()) + { + try + { + _libraryHandle = LoadUnmanagedLibrary(candidate); + _libraryLoaded = _libraryHandle != IntPtr.Zero; + if (_libraryLoaded) + { + BindDelegates(); + return true; + } + } + catch + { + // Try the next candidate. + } + } + + return false; + } + } + + private static void BindDelegates() + { + _steamApiInit = + Bind("SteamAPI_Init") + ?? Bind("SteamAPI_InitSafe"); + _steamApiShutdown = Bind("SteamAPI_Shutdown"); + _steamApiRunCallbacks = Bind("SteamAPI_RunCallbacks"); + _steamFriendsAccessor = BindInterfaceAccessor("SteamFriends", "ISteamFriends"); + _steamUserStatsAccessor = BindInterfaceAccessor("SteamUserStats", "ISteamUserStats"); + _steamFriendsGetPersonaName = Bind("SteamAPI_ISteamFriends_GetPersonaName"); + _steamUserStatsSetAchievement = Bind("SteamAPI_ISteamUserStats_SetAchievement"); + _steamUserStatsStoreStats = Bind("SteamAPI_ISteamUserStats_StoreStats"); + _steamUserStatsGetAchievement = Bind("SteamAPI_ISteamUserStats_GetAchievement"); + } + + private static T Bind(string exportName) where T : class + { + return TryGetExport(_libraryHandle, exportName, out var export) + ? Marshal.GetDelegateForFunctionPointer(export, typeof(T)) as T + : null; + } + + private static T BindInterfaceAccessor(string friendlyName, string interfaceName) where T : class + { + for (var version = 1; version <= 64; version++) + { + var exportName = $"SteamAPI_{friendlyName}_v{version:000}"; + if (TryGetExport(_libraryHandle, exportName, out var export) || + TryGetExport(_libraryHandle, $"SteamAPI_{interfaceName}_v{version:000}", out export)) + { + return Marshal.GetDelegateForFunctionPointer(export, typeof(T)) as T; + } + } + + return null; + } + + private static void CacheInterfaces() + { + _steamFriends = _steamFriendsAccessor?.Invoke() ?? IntPtr.Zero; + _steamUserStats = _steamUserStatsAccessor?.Invoke() ?? IntPtr.Zero; + } + + private static string[] GetLibraryCandidates() + { + var libraryName = GetLibraryFileName(); + var runtimeIdentifier = GetRuntimeIdentifier(); + + return new[] + { + Path.Combine(AppContext.BaseDirectory, "runtimes", runtimeIdentifier, "native", libraryName), + Path.Combine(AppContext.BaseDirectory, libraryName), + libraryName + }; + } + + private static string GetRuntimeIdentifier() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return Environment.Is64BitProcess ? "win-x64" : "win-x86"; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return Environment.Is64BitProcess ? "osx-x64" : "osx-x86"; + } + + return Environment.Is64BitProcess ? "linux-x64" : "linux-x86"; + } + + private static string GetLibraryFileName() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return Environment.Is64BitProcess ? "steam_api64.dll" : "steam_api.dll"; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return "libsteam_api.dylib"; + } + + return "libsteam_api.so"; + } + + private static void ApplyAppIdEnvironment(uint appId) + { + var appIdValue = appId.ToString(); + Environment.SetEnvironmentVariable("SteamAppId", appIdValue); + Environment.SetEnvironmentVariable("SteamGameId", appIdValue); + } + + private static void TryWriteSteamAppIdFile(uint appId) + { + var appIdValue = appId.ToString(); + var candidatePaths = new[] + { + Path.Combine(AppContext.BaseDirectory, "steam_appid.txt"), + Path.Combine(Directory.GetCurrentDirectory(), "steam_appid.txt") + }; + + foreach (var path in candidatePaths) + { + try + { + File.WriteAllText(path, appIdValue); + } + catch + { + // Ignore write failures and continue with other candidates. + } + } + } + + private static IntPtr LoadUnmanagedLibrary(string path) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return LoadLibraryWindows(path); + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return DlopenMac(path, RtldNow); + } + + return DlopenLinux(path, RtldNow); + } + + private static bool TryGetExport(IntPtr libraryHandle, string exportName, out IntPtr export) + { + if (libraryHandle == IntPtr.Zero) + { + export = IntPtr.Zero; + return false; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + export = GetProcAddressWindows(libraryHandle, exportName); + return export != IntPtr.Zero; + } + + export = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) + ? DlsymMac(libraryHandle, exportName) + : DlsymLinux(libraryHandle, exportName); + return export != IntPtr.Zero; + } + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "LoadLibraryW")] + private static extern IntPtr LoadLibraryWindows(string lpFileName); + + [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true, EntryPoint = "GetProcAddress")] + private static extern IntPtr GetProcAddressWindows(IntPtr hModule, string procName); + + [DllImport("libdl.so.2", EntryPoint = "dlopen")] + private static extern IntPtr DlopenLinux(string fileName, int flags); + + [DllImport("libdl.so.2", EntryPoint = "dlsym")] + private static extern IntPtr DlsymLinux(IntPtr handle, string symbol); + + [DllImport("libSystem.B.dylib", EntryPoint = "dlopen")] + private static extern IntPtr DlopenMac(string fileName, int flags); + + [DllImport("libSystem.B.dylib", EntryPoint = "dlsym")] + private static extern IntPtr DlsymMac(IntPtr handle, string symbol); + + private const int RtldNow = 2; + + } +} + diff --git a/OmegaLeo.HelperLib.sln b/OmegaLeo.HelperLib.sln index 68544d6..6bd1af1 100755 --- a/OmegaLeo.HelperLib.sln +++ b/OmegaLeo.HelperLib.sln @@ -25,47 +25,137 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "actions", "actions", "{750F .github\workflows\dotnet.yml = .github\workflows\dotnet.yml .github\workflows\nuget-publish.yml = .github\workflows\nuget-publish.yml .github\workflows\github-publish.yml = .github\workflows\github-publish.yml - .github\workflows\jetbrains-publish.yml = .github\workflows\jetbrains-publish.yml EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmegaLeo.HelperLib.Documentation", "OmegaLeo.HelperLib.Documentation\OmegaLeo.HelperLib.Documentation.csproj", "{AE69480D-5956-46CB-9028-E4723735E37E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmegaLeo.HelperLib.Shared", "OmegaLeo.HelperLib.Shared\OmegaLeo.HelperLib.Shared.csproj", "{FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmegaLeo.HelperLib.Steamworks", "OmegaLeo.HelperLib.Steamworks\OmegaLeo.HelperLib.Steamworks.csproj", "{23C447DC-3188-4319-8307-E31852EF45C7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmegaLeo.HelperLib.ConsoleApp", "OmegaLeo.HelperLib.ConsoleApp\OmegaLeo.HelperLib.ConsoleApp.csproj", "{C5FD0FDC-0007-48AB-86C7-D8CB05126B86}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Debug|x64.ActiveCfg = Debug|Any CPU + {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Debug|x64.Build.0 = Debug|Any CPU + {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Debug|x86.ActiveCfg = Debug|Any CPU + {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Debug|x86.Build.0 = Debug|Any CPU {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Release|Any CPU.ActiveCfg = Release|Any CPU {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Release|Any CPU.Build.0 = Release|Any CPU + {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Release|x64.ActiveCfg = Release|Any CPU + {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Release|x64.Build.0 = Release|Any CPU + {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Release|x86.ActiveCfg = Release|Any CPU + {A7256931-5D66-46FA-BA50-22B2FA4CD9E9}.Release|x86.Build.0 = Release|Any CPU {378D8125-66B5-42B8-9881-33F951E5E04A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {378D8125-66B5-42B8-9881-33F951E5E04A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {378D8125-66B5-42B8-9881-33F951E5E04A}.Debug|x64.ActiveCfg = Debug|Any CPU + {378D8125-66B5-42B8-9881-33F951E5E04A}.Debug|x64.Build.0 = Debug|Any CPU + {378D8125-66B5-42B8-9881-33F951E5E04A}.Debug|x86.ActiveCfg = Debug|Any CPU + {378D8125-66B5-42B8-9881-33F951E5E04A}.Debug|x86.Build.0 = Debug|Any CPU {378D8125-66B5-42B8-9881-33F951E5E04A}.Release|Any CPU.ActiveCfg = Release|Any CPU {378D8125-66B5-42B8-9881-33F951E5E04A}.Release|Any CPU.Build.0 = Release|Any CPU + {378D8125-66B5-42B8-9881-33F951E5E04A}.Release|x64.ActiveCfg = Release|Any CPU + {378D8125-66B5-42B8-9881-33F951E5E04A}.Release|x64.Build.0 = Release|Any CPU + {378D8125-66B5-42B8-9881-33F951E5E04A}.Release|x86.ActiveCfg = Release|Any CPU + {378D8125-66B5-42B8-9881-33F951E5E04A}.Release|x86.Build.0 = Release|Any CPU {359536F7-02DE-43E9-A383-D83853227B0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {359536F7-02DE-43E9-A383-D83853227B0F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {359536F7-02DE-43E9-A383-D83853227B0F}.Debug|x64.ActiveCfg = Debug|Any CPU + {359536F7-02DE-43E9-A383-D83853227B0F}.Debug|x64.Build.0 = Debug|Any CPU + {359536F7-02DE-43E9-A383-D83853227B0F}.Debug|x86.ActiveCfg = Debug|Any CPU + {359536F7-02DE-43E9-A383-D83853227B0F}.Debug|x86.Build.0 = Debug|Any CPU {359536F7-02DE-43E9-A383-D83853227B0F}.Release|Any CPU.ActiveCfg = Release|Any CPU {359536F7-02DE-43E9-A383-D83853227B0F}.Release|Any CPU.Build.0 = Release|Any CPU + {359536F7-02DE-43E9-A383-D83853227B0F}.Release|x64.ActiveCfg = Release|Any CPU + {359536F7-02DE-43E9-A383-D83853227B0F}.Release|x64.Build.0 = Release|Any CPU + {359536F7-02DE-43E9-A383-D83853227B0F}.Release|x86.ActiveCfg = Release|Any CPU + {359536F7-02DE-43E9-A383-D83853227B0F}.Release|x86.Build.0 = Release|Any CPU {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Debug|x64.ActiveCfg = Debug|Any CPU + {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Debug|x64.Build.0 = Debug|Any CPU + {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Debug|x86.ActiveCfg = Debug|Any CPU + {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Debug|x86.Build.0 = Debug|Any CPU {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Release|Any CPU.ActiveCfg = Release|Any CPU {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Release|Any CPU.Build.0 = Release|Any CPU + {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Release|x64.ActiveCfg = Release|Any CPU + {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Release|x64.Build.0 = Release|Any CPU + {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Release|x86.ActiveCfg = Release|Any CPU + {1EA64C6B-D5D2-47EB-8255-5BAE2EE1385A}.Release|x86.Build.0 = Release|Any CPU {488BC3EA-9B7A-4251-B802-22EB098D6494}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {488BC3EA-9B7A-4251-B802-22EB098D6494}.Debug|Any CPU.Build.0 = Debug|Any CPU + {488BC3EA-9B7A-4251-B802-22EB098D6494}.Debug|x64.ActiveCfg = Debug|Any CPU + {488BC3EA-9B7A-4251-B802-22EB098D6494}.Debug|x64.Build.0 = Debug|Any CPU + {488BC3EA-9B7A-4251-B802-22EB098D6494}.Debug|x86.ActiveCfg = Debug|Any CPU + {488BC3EA-9B7A-4251-B802-22EB098D6494}.Debug|x86.Build.0 = Debug|Any CPU {488BC3EA-9B7A-4251-B802-22EB098D6494}.Release|Any CPU.ActiveCfg = Release|Any CPU {488BC3EA-9B7A-4251-B802-22EB098D6494}.Release|Any CPU.Build.0 = Release|Any CPU + {488BC3EA-9B7A-4251-B802-22EB098D6494}.Release|x64.ActiveCfg = Release|Any CPU + {488BC3EA-9B7A-4251-B802-22EB098D6494}.Release|x64.Build.0 = Release|Any CPU + {488BC3EA-9B7A-4251-B802-22EB098D6494}.Release|x86.ActiveCfg = Release|Any CPU + {488BC3EA-9B7A-4251-B802-22EB098D6494}.Release|x86.Build.0 = Release|Any CPU {AE69480D-5956-46CB-9028-E4723735E37E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AE69480D-5956-46CB-9028-E4723735E37E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE69480D-5956-46CB-9028-E4723735E37E}.Debug|x64.ActiveCfg = Debug|Any CPU + {AE69480D-5956-46CB-9028-E4723735E37E}.Debug|x64.Build.0 = Debug|Any CPU + {AE69480D-5956-46CB-9028-E4723735E37E}.Debug|x86.ActiveCfg = Debug|Any CPU + {AE69480D-5956-46CB-9028-E4723735E37E}.Debug|x86.Build.0 = Debug|Any CPU {AE69480D-5956-46CB-9028-E4723735E37E}.Release|Any CPU.ActiveCfg = Release|Any CPU {AE69480D-5956-46CB-9028-E4723735E37E}.Release|Any CPU.Build.0 = Release|Any CPU + {AE69480D-5956-46CB-9028-E4723735E37E}.Release|x64.ActiveCfg = Release|Any CPU + {AE69480D-5956-46CB-9028-E4723735E37E}.Release|x64.Build.0 = Release|Any CPU + {AE69480D-5956-46CB-9028-E4723735E37E}.Release|x86.ActiveCfg = Release|Any CPU + {AE69480D-5956-46CB-9028-E4723735E37E}.Release|x86.Build.0 = Release|Any CPU {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Debug|x64.ActiveCfg = Debug|Any CPU + {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Debug|x64.Build.0 = Debug|Any CPU + {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Debug|x86.ActiveCfg = Debug|Any CPU + {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Debug|x86.Build.0 = Debug|Any CPU {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Release|Any CPU.ActiveCfg = Release|Any CPU {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Release|Any CPU.Build.0 = Release|Any CPU + {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Release|x64.ActiveCfg = Release|Any CPU + {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Release|x64.Build.0 = Release|Any CPU + {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Release|x86.ActiveCfg = Release|Any CPU + {FE6CA992-8BEB-41DD-A8E4-60FCEF96C59A}.Release|x86.Build.0 = Release|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Debug|x64.ActiveCfg = Debug|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Debug|x64.Build.0 = Debug|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Debug|x86.ActiveCfg = Debug|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Debug|x86.Build.0 = Debug|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Release|Any CPU.Build.0 = Release|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Release|x64.ActiveCfg = Release|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Release|x64.Build.0 = Release|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Release|x86.ActiveCfg = Release|Any CPU + {23C447DC-3188-4319-8307-E31852EF45C7}.Release|x86.Build.0 = Release|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Debug|x64.ActiveCfg = Debug|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Debug|x64.Build.0 = Debug|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Debug|x86.ActiveCfg = Debug|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Debug|x86.Build.0 = Debug|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Release|Any CPU.Build.0 = Release|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Release|x64.ActiveCfg = Release|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Release|x64.Build.0 = Release|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Release|x86.ActiveCfg = Release|Any CPU + {C5FD0FDC-0007-48AB-86C7-D8CB05126B86}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {750F2E9A-2703-4732-98D7-29C658368E48} = {00CF0543-37F3-41DE-B78F-8ADA6DE796ED} diff --git a/OmegaLeo.HelperLib.sln.DotSettings.user b/OmegaLeo.HelperLib.sln.DotSettings.user index b291b2c..6eac453 100755 --- a/OmegaLeo.HelperLib.sln.DotSettings.user +++ b/OmegaLeo.HelperLib.sln.DotSettings.user @@ -1,7 +1,10 @@  + True + True ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded