updated SteamWorks library

This commit is contained in:
2026-10-24 11:38:40 +01:00
parent 91cdba0fef
commit c745fb18bd
8 changed files with 1485 additions and 33 deletions
+487 -19
View File
@@ -2,18 +2,70 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging;
namespace OmegaLeo.HelperLib.Steamworks
{
internal readonly struct SteamNativeCallbackMessage
{
public SteamNativeCallbackMessage(int steamUser, int callbackId, IntPtr param, int paramSize)
{
SteamUser = steamUser;
CallbackId = callbackId;
Param = param;
ParamSize = paramSize;
}
public int SteamUser { get; }
public int CallbackId { get; }
public IntPtr Param { get; }
public int ParamSize { get; }
}
internal static class SteamNativeApi
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
private delegate bool SteamApiInitDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int SteamApiInitFlatDelegate(IntPtr errorMessage);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
private delegate bool SteamApiRestartAppIfNecessaryDelegate(uint appId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SteamApiVoidDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int SteamApiGetHSteamPipeDelegate();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SteamApiManualDispatchPipeDelegate(int steamPipe);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
private delegate bool SteamApiManualDispatchGetNextCallbackDelegate(int steamPipe, IntPtr callbackMessage);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
private delegate bool SteamApiManualDispatchGetApiCallResultDelegate(int steamPipe, ulong apiCall, IntPtr callbackBuffer, int callbackSize, int callbackExpected, [MarshalAs(UnmanagedType.I1)] out bool failed);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
private delegate bool SteamAppsBoolDelegate(IntPtr steamApps);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
private delegate bool SteamAppsAppIdBoolDelegate(IntPtr steamApps, uint appId);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr SteamAppsStringDelegate(IntPtr steamApps);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int SteamAppsGetAppBuildIdDelegate(IntPtr steamApps);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr SteamFriendsAccessorDelegate();
@@ -289,13 +341,41 @@ namespace OmegaLeo.HelperLib.Steamworks
private static readonly object SyncRoot = new object();
// SteamErrMsg is a char[1024] buffer in steam_api_common.h.
private const int SteamErrMsgSize = 1024;
// Large enough for CallbackMsg_t on 32-bit and 64-bit (24 bytes on x64).
private const int CallbackMessageBufferSize = 64;
private static IntPtr _libraryHandle;
private static bool _libraryLoaded;
private static bool _loadFailureLogged;
private static bool _initialized;
private static bool _manualDispatchEnabled = true;
private static bool _manualDispatchActive;
private static int _steamPipe;
private static IntPtr _callbackMessageBuffer;
private static readonly List<string> CustomLibraryPaths = new List<string>();
private static SteamApiInitFlatDelegate _steamApiInitFlat;
private static SteamApiInitDelegate _steamApiInit;
private static SteamApiRestartAppIfNecessaryDelegate _steamApiRestartAppIfNecessary;
private static SteamApiVoidDelegate _steamApiShutdown;
private static SteamApiVoidDelegate _steamApiRunCallbacks;
private static SteamApiGetHSteamPipeDelegate _steamApiGetHSteamPipe;
private static SteamApiVoidDelegate _steamApiManualDispatchInit;
private static SteamApiManualDispatchPipeDelegate _steamApiManualDispatchRunFrame;
private static SteamApiManualDispatchGetNextCallbackDelegate _steamApiManualDispatchGetNextCallback;
private static SteamApiManualDispatchPipeDelegate _steamApiManualDispatchFreeLastCallback;
private static SteamApiManualDispatchGetApiCallResultDelegate _steamApiManualDispatchGetApiCallResult;
private static SteamAppsBoolDelegate _steamAppsIsSubscribed;
private static SteamAppsAppIdBoolDelegate _steamAppsIsSubscribedApp;
private static SteamAppsAppIdBoolDelegate _steamAppsIsDlcInstalled;
private static SteamAppsAppIdBoolDelegate _steamAppsIsAppInstalled;
private static SteamAppsStringDelegate _steamAppsGetCurrentGameLanguage;
private static SteamAppsStringDelegate _steamAppsGetAvailableGameLanguages;
private static SteamAppsGetAppBuildIdDelegate _steamAppsGetAppBuildId;
private static SteamFriendsAccessorDelegate _steamFriendsAccessor;
private static SteamUserStatsAccessorDelegate _steamUserStatsAccessor;
private static SteamUgcAccessorDelegate _steamUgcAccessor;
@@ -385,6 +465,7 @@ namespace OmegaLeo.HelperLib.Steamworks
private static readonly Dictionary<string, SteamInterfaceAccessorDelegate> AdditionalInterfaceAccessors = new Dictionary<string, SteamInterfaceAccessorDelegate>();
private static readonly Dictionary<string, IntPtr> AdditionalInterfacePointers = new Dictionary<string, IntPtr>();
private const string InterfaceSteamApps = "SteamApps";
private const string InterfaceSteamController = "SteamController";
private const string InterfaceSteamGameCoordinator = "SteamGameCoordinator";
private const string InterfaceSteamGameServer = "SteamGameServer";
@@ -403,13 +484,53 @@ namespace OmegaLeo.HelperLib.Steamworks
public static bool IsAvailable => EnsureLoaded();
public static bool IsManualDispatchActive => _manualDispatchActive;
public static string LastInitErrorMessage { get; private set; } = string.Empty;
private static ILogger Logger => SteamManager.Logger;
public static bool AddLibrarySearchPath(string directoryOrFile)
{
if (string.IsNullOrWhiteSpace(directoryOrFile))
{
return false;
}
lock (SyncRoot)
{
if (_libraryLoaded)
{
return false;
}
CustomLibraryPaths.Add(directoryOrFile);
_loadFailureLogged = false;
return true;
}
}
public static bool ConfigureManualDispatch(bool enabled)
{
lock (SyncRoot)
{
if (_initialized)
{
return false;
}
_manualDispatchEnabled = enabled;
return true;
}
}
public static bool Initialize(uint? appId = null)
{
lock (SyncRoot)
{
if (appId.HasValue && appId.Value > 0)
{
ConfigureAppId(appId.Value);
ApplyAppIdEnvironment(appId.Value);
}
if (_initialized)
@@ -419,25 +540,39 @@ namespace OmegaLeo.HelperLib.Steamworks
if (!EnsureLoaded())
{
LastInitErrorMessage = "The Steam API native library could not be loaded.";
return false;
}
if (_steamApiInit == null)
{
return false;
}
_initialized = _steamApiInit();
_initialized = InvokeSteamApiInit();
if (_initialized)
{
CacheInterfaces();
TryEnableManualDispatch();
}
return _initialized;
}
}
public static void ConfigureAppId(uint appId)
public static bool RestartAppIfNecessary(uint appId)
{
if (!EnsureLoaded())
{
Logger.LogError("SteamAPI_RestartAppIfNecessary skipped: the Steam API native library could not be loaded.");
return false;
}
if (_steamApiRestartAppIfNecessary == null)
{
Logger.LogWarning("SteamAPI_RestartAppIfNecessary export not found in the loaded Steam API library.");
return false;
}
return _steamApiRestartAppIfNecessary(appId);
}
public static void ConfigureAppId(uint appId, bool writeSteamAppIdFile)
{
if (appId == 0)
{
@@ -447,7 +582,10 @@ namespace OmegaLeo.HelperLib.Steamworks
lock (SyncRoot)
{
ApplyAppIdEnvironment(appId);
TryWriteSteamAppIdFile(appId);
if (writeSteamAppIdFile)
{
TryWriteSteamAppIdFile(appId);
}
}
}
@@ -462,6 +600,14 @@ namespace OmegaLeo.HelperLib.Steamworks
_steamApiShutdown?.Invoke();
_initialized = false;
_manualDispatchActive = false;
_steamPipe = 0;
if (_callbackMessageBuffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(_callbackMessageBuffer);
_callbackMessageBuffer = IntPtr.Zero;
}
_steamFriends = IntPtr.Zero;
_steamUserStats = IntPtr.Zero;
_steamUgc = IntPtr.Zero;
@@ -472,7 +618,8 @@ namespace OmegaLeo.HelperLib.Steamworks
public static void RunCallbacks()
{
if (!_initialized)
// SteamAPI_RunCallbacks must never run once manual dispatch is in use.
if (!_initialized || _manualDispatchActive)
{
return;
}
@@ -480,6 +627,152 @@ namespace OmegaLeo.HelperLib.Steamworks
_steamApiRunCallbacks?.Invoke();
}
public static void ManualDispatchRunFrame()
{
if (!_manualDispatchActive)
{
return;
}
_steamApiManualDispatchRunFrame(_steamPipe);
}
public static bool ManualDispatchGetNextCallback(out SteamNativeCallbackMessage message)
{
message = default;
if (!_manualDispatchActive || !_steamApiManualDispatchGetNextCallback(_steamPipe, _callbackMessageBuffer))
{
return false;
}
// CallbackMsg_t { HSteamUser m_hSteamUser; int m_iCallback; uint8 *m_pubParam; int m_cubParam; }
// The pointer lands on offset 8 under both pack 4 and pack 8, so the layout is the same on every platform.
message = new SteamNativeCallbackMessage(
Marshal.ReadInt32(_callbackMessageBuffer, 0),
Marshal.ReadInt32(_callbackMessageBuffer, 4),
Marshal.ReadIntPtr(_callbackMessageBuffer, 8),
Marshal.ReadInt32(_callbackMessageBuffer, 8 + IntPtr.Size));
return true;
}
public static void ManualDispatchFreeLastCallback()
{
if (!_manualDispatchActive)
{
return;
}
_steamApiManualDispatchFreeLastCallback(_steamPipe);
}
public static bool ManualDispatchGetApiCallResult(ulong apiCall, IntPtr callbackBuffer, int callbackSize, int callbackExpected, out bool failed)
{
failed = true;
if (!_manualDispatchActive)
{
return false;
}
return _steamApiManualDispatchGetApiCallResult(_steamPipe, apiCall, callbackBuffer, callbackSize, callbackExpected, out failed);
}
private static bool InvokeSteamApiInit()
{
LastInitErrorMessage = string.Empty;
if (_steamApiInitFlat != null)
{
var errorBuffer = Marshal.AllocHGlobal(SteamErrMsgSize);
try
{
Marshal.WriteByte(errorBuffer, 0, 0);
var result = _steamApiInitFlat(errorBuffer);
if (result == 0)
{
Logger.LogDebug("Steamworks initialized through SteamAPI_InitFlat.");
return true;
}
var message = Marshal.PtrToStringAnsi(errorBuffer) ?? string.Empty;
LastInitErrorMessage = string.IsNullOrWhiteSpace(message) ? DescribeInitResult(result) : message;
Logger.LogWarning("SteamAPI_InitFlat failed with {InitResult} ({InitResultName}): {InitErrorMessage}", result, DescribeInitResult(result), LastInitErrorMessage);
return false;
}
finally
{
Marshal.FreeHGlobal(errorBuffer);
}
}
if (_steamApiInit != null)
{
if (_steamApiInit())
{
Logger.LogDebug("Steamworks initialized through the legacy SteamAPI_Init export.");
return true;
}
LastInitErrorMessage = "SteamAPI_Init returned false (this SDK version does not report a reason).";
return false;
}
LastInitErrorMessage = "No SteamAPI_InitFlat, SteamAPI_Init or SteamAPI_InitSafe export was found.";
Logger.LogError(LastInitErrorMessage);
return false;
}
private static string DescribeInitResult(int result)
{
// ESteamAPIInitResult
switch (result)
{
case 0: return "OK";
case 1: return "FailedGeneric";
case 2: return "NoSteamClient";
case 3: return "VersionMismatch";
default: return "Unknown";
}
}
private static void TryEnableManualDispatch()
{
if (!_manualDispatchEnabled)
{
Logger.LogInformation("Manual callback dispatch disabled; using SteamAPI_RunCallbacks.");
return;
}
if (_steamApiGetHSteamPipe == null ||
_steamApiManualDispatchInit == null ||
_steamApiManualDispatchRunFrame == null ||
_steamApiManualDispatchGetNextCallback == null ||
_steamApiManualDispatchFreeLastCallback == null ||
_steamApiManualDispatchGetApiCallResult == null)
{
Logger.LogWarning("Steam manual dispatch exports not found; falling back to SteamAPI_RunCallbacks. Callback events and async call results will not be delivered.");
return;
}
var steamPipe = _steamApiGetHSteamPipe();
if (steamPipe == 0)
{
Logger.LogWarning("SteamAPI_GetHSteamPipe returned an invalid pipe; falling back to SteamAPI_RunCallbacks.");
return;
}
_steamApiManualDispatchInit();
_steamPipe = steamPipe;
if (_callbackMessageBuffer == IntPtr.Zero)
{
_callbackMessageBuffer = Marshal.AllocHGlobal(CallbackMessageBufferSize);
}
_manualDispatchActive = true;
Logger.LogDebug("Steam manual callback dispatch enabled.");
}
public static string GetPersonaName()
{
if (!EnsureReady())
@@ -784,6 +1077,8 @@ namespace OmegaLeo.HelperLib.Steamworks
return _steamRemotePlayGetSessionClientResolution?.Invoke(_steamRemotePlay, sessionId, out resolutionX, out resolutionY) ?? false;
}
public static bool IsSteamAppsAvailable() => EnsureAdditionalInterfaceReady(InterfaceSteamApps);
public static bool IsSteamControllerAvailable() => EnsureAdditionalInterfaceReady(InterfaceSteamController);
public static bool IsSteamFriendsAvailable() => EnsureFriendsReady();
@@ -928,6 +1223,85 @@ namespace OmegaLeo.HelperLib.Steamworks
return _steamUtilsIsOverlayEnabled?.Invoke(steamUtils) ?? false;
}
public static bool AppsIsSubscribed()
{
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
{
return false;
}
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
return _steamAppsIsSubscribed?.Invoke(steamApps) ?? false;
}
public static bool AppsIsSubscribedApp(uint appId)
{
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
{
return false;
}
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
return _steamAppsIsSubscribedApp?.Invoke(steamApps, appId) ?? false;
}
public static bool AppsIsDlcInstalled(uint appId)
{
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
{
return false;
}
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
return _steamAppsIsDlcInstalled?.Invoke(steamApps, appId) ?? false;
}
public static bool AppsIsAppInstalled(uint appId)
{
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
{
return false;
}
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
return _steamAppsIsAppInstalled?.Invoke(steamApps, appId) ?? false;
}
public static string AppsGetCurrentGameLanguage()
{
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
{
return string.Empty;
}
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
var languagePtr = _steamAppsGetCurrentGameLanguage?.Invoke(steamApps) ?? IntPtr.Zero;
return languagePtr == IntPtr.Zero ? string.Empty : Marshal.PtrToStringAnsi(languagePtr) ?? string.Empty;
}
public static string AppsGetAvailableGameLanguages()
{
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
{
return string.Empty;
}
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
var languagesPtr = _steamAppsGetAvailableGameLanguages?.Invoke(steamApps) ?? IntPtr.Zero;
return languagesPtr == IntPtr.Zero ? string.Empty : Marshal.PtrToStringAnsi(languagesPtr) ?? string.Empty;
}
public static int AppsGetAppBuildId()
{
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
{
return 0;
}
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
return _steamAppsGetAppBuildId?.Invoke(steamApps) ?? 0;
}
public static bool RemoteStorageFileExists(string fileName)
{
if (!EnsureAdditionalInterfaceReady(InterfaceSteamRemoteStorage))
@@ -1486,35 +1860,66 @@ namespace OmegaLeo.HelperLib.Steamworks
return true;
}
var failures = new List<string>();
foreach (var candidate in GetLibraryCandidates())
{
try
{
_libraryHandle = LoadUnmanagedLibrary(candidate);
_libraryLoaded = _libraryHandle != IntPtr.Zero;
if (_libraryLoaded)
var handle = LoadUnmanagedLibrary(candidate);
if (handle != IntPtr.Zero)
{
_libraryHandle = handle;
_libraryLoaded = true;
BindDelegates();
Logger.LogInformation("Loaded Steam API native library from '{SteamLibraryPath}'.", candidate);
return true;
}
failures.Add($"{candidate} ({GetLastLoadError()})");
}
catch
catch (Exception e)
{
// Try the next candidate.
failures.Add($"{candidate} ({e.GetType().Name}: {e.Message})");
}
}
if (!_loadFailureLogged)
{
_loadFailureLogged = true;
Logger.LogError(
"Could not load the Steam API native library '{SteamLibraryName}'. Call SteamManager.ConfigureLibraryPath with the folder that contains it. Tried: {SteamLibraryCandidates}",
GetLibraryFileName(),
string.Join("; ", failures));
}
return false;
}
}
private static void BindDelegates()
{
// SDK 1.58+ exposes SteamAPI_InitFlat (with an error message); older SDKs only have SteamAPI_Init/InitSafe.
_steamApiInitFlat = Bind<SteamApiInitFlatDelegate>("SteamAPI_InitFlat");
_steamApiInit =
Bind<SteamApiInitDelegate>("SteamAPI_Init")
?? Bind<SteamApiInitDelegate>("SteamAPI_InitSafe");
_steamApiRestartAppIfNecessary = Bind<SteamApiRestartAppIfNecessaryDelegate>("SteamAPI_RestartAppIfNecessary");
_steamApiShutdown = Bind<SteamApiVoidDelegate>("SteamAPI_Shutdown");
_steamApiRunCallbacks = Bind<SteamApiVoidDelegate>("SteamAPI_RunCallbacks");
_steamApiGetHSteamPipe = Bind<SteamApiGetHSteamPipeDelegate>("SteamAPI_GetHSteamPipe");
_steamApiManualDispatchInit = Bind<SteamApiVoidDelegate>("SteamAPI_ManualDispatch_Init");
_steamApiManualDispatchRunFrame = Bind<SteamApiManualDispatchPipeDelegate>("SteamAPI_ManualDispatch_RunFrame");
_steamApiManualDispatchGetNextCallback = Bind<SteamApiManualDispatchGetNextCallbackDelegate>("SteamAPI_ManualDispatch_GetNextCallback");
_steamApiManualDispatchFreeLastCallback = Bind<SteamApiManualDispatchPipeDelegate>("SteamAPI_ManualDispatch_FreeLastCallback");
_steamApiManualDispatchGetApiCallResult = Bind<SteamApiManualDispatchGetApiCallResultDelegate>("SteamAPI_ManualDispatch_GetAPICallResult");
_steamAppsIsSubscribed = Bind<SteamAppsBoolDelegate>("SteamAPI_ISteamApps_BIsSubscribed");
_steamAppsIsSubscribedApp = Bind<SteamAppsAppIdBoolDelegate>("SteamAPI_ISteamApps_BIsSubscribedApp");
_steamAppsIsDlcInstalled = Bind<SteamAppsAppIdBoolDelegate>("SteamAPI_ISteamApps_BIsDlcInstalled");
_steamAppsIsAppInstalled = Bind<SteamAppsAppIdBoolDelegate>("SteamAPI_ISteamApps_BIsAppInstalled");
_steamAppsGetCurrentGameLanguage = Bind<SteamAppsStringDelegate>("SteamAPI_ISteamApps_GetCurrentGameLanguage");
_steamAppsGetAvailableGameLanguages = Bind<SteamAppsStringDelegate>("SteamAPI_ISteamApps_GetAvailableGameLanguages");
_steamAppsGetAppBuildId = Bind<SteamAppsGetAppBuildIdDelegate>("SteamAPI_ISteamApps_GetAppBuildId");
_steamFriendsAccessor = BindInterfaceAccessor<SteamFriendsAccessorDelegate>("SteamFriends", "ISteamFriends");
_steamUserStatsAccessor = BindInterfaceAccessor<SteamUserStatsAccessorDelegate>("SteamUserStats", "ISteamUserStats");
_steamUgcAccessor = BindInterfaceAccessor<SteamUgcAccessorDelegate>("SteamUGC", "ISteamUGC");
@@ -1597,6 +2002,7 @@ namespace OmegaLeo.HelperLib.Steamworks
_steamUserStatsSetStatInt32 = Bind<SteamUserStatsSetStatInt32Delegate>("SteamAPI_ISteamUserStats_SetStatInt32");
// Additional interface accessors requested for broad API coverage.
BindAdditionalInterfaceAccessor(InterfaceSteamApps, "SteamApps", "ISteamApps");
BindAdditionalInterfaceAccessor(InterfaceSteamController, "SteamController", "ISteamController");
BindAdditionalInterfaceAccessor(InterfaceSteamGameCoordinator, "SteamGameCoordinator", "ISteamGameCoordinator");
BindAdditionalInterfaceAccessor(InterfaceSteamGameServer, "SteamGameServer", "ISteamGameServer");
@@ -1735,13 +2141,38 @@ namespace OmegaLeo.HelperLib.Steamworks
{
var libraryName = GetLibraryFileName();
var runtimeIdentifier = GetRuntimeIdentifier();
var candidates = new List<string>();
return new[]
// Paths from SteamManager.ConfigureLibraryPath are tried first, in the order they were added.
foreach (var customPath in CustomLibraryPaths)
{
Path.Combine(AppContext.BaseDirectory, "runtimes", runtimeIdentifier, "native", libraryName),
Path.Combine(AppContext.BaseDirectory, libraryName),
libraryName
};
var isFile = File.Exists(customPath) ||
string.Equals(Path.GetFileName(customPath), libraryName, StringComparison.OrdinalIgnoreCase);
candidates.Add(isFile ? customPath : Path.Combine(customPath, libraryName));
}
candidates.Add(Path.Combine(AppContext.BaseDirectory, "runtimes", runtimeIdentifier, "native", libraryName));
candidates.Add(Path.Combine(AppContext.BaseDirectory, libraryName));
candidates.Add(libraryName);
return candidates.ToArray();
}
private static string GetLastLoadError()
{
try
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()).Message;
}
var errorPtr = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? DlerrorMac() : DlerrorLinux();
return errorPtr == IntPtr.Zero ? "unknown error" : Marshal.PtrToStringAnsi(errorPtr) ?? "unknown error";
}
catch (Exception e)
{
return e.Message;
}
}
private static string GetRuntimeIdentifier()
@@ -1779,6 +2210,31 @@ namespace OmegaLeo.HelperLib.Steamworks
var appIdValue = appId.ToString();
Environment.SetEnvironmentVariable("SteamAppId", appIdValue);
Environment.SetEnvironmentVariable("SteamGameId", appIdValue);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return;
}
// Some runtimes keep Environment.SetEnvironmentVariable managed-only on Unix,
// so mirror the values into the native environment that steam_api reads.
try
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
SetEnvMac("SteamAppId", appIdValue, 1);
SetEnvMac("SteamGameId", appIdValue, 1);
}
else
{
SetEnvLinux("SteamAppId", appIdValue, 1);
SetEnvLinux("SteamGameId", appIdValue, 1);
}
}
catch (Exception e)
{
Logger.LogDebug(e, "Could not set the native SteamAppId environment variables.");
}
}
private static void TryWriteSteamAppIdFile(uint appId)
@@ -1856,6 +2312,18 @@ namespace OmegaLeo.HelperLib.Steamworks
[DllImport("libSystem.B.dylib", EntryPoint = "dlsym")]
private static extern IntPtr DlsymMac(IntPtr handle, string symbol);
[DllImport("libdl.so.2", EntryPoint = "dlerror")]
private static extern IntPtr DlerrorLinux();
[DllImport("libSystem.B.dylib", EntryPoint = "dlerror")]
private static extern IntPtr DlerrorMac();
[DllImport("libc.so.6", EntryPoint = "setenv")]
private static extern int SetEnvLinux(string name, string value, int overwrite);
[DllImport("libSystem.B.dylib", EntryPoint = "setenv")]
private static extern int SetEnvMac(string name, string value, int overwrite);
private const int RtldNow = 2;
}