updated SteamWorks library
This commit is contained in:
@@ -5,11 +5,13 @@ using OmegaLeo.HelperLib.Shared.Attributes;
|
||||
|
||||
namespace OmegaLeo.HelperLib.Steamworks
|
||||
{
|
||||
[Documentation(nameof(SteamManager), "Manages Steamworks initialization, callback polling, and shutdown for applications using the Steam API.", null,
|
||||
[Documentation(nameof(SteamManager), "Manages Steamworks initialization, callback dispatch, and shutdown for applications using the Steam API.", null,
|
||||
@"```csharp
|
||||
SteamManager.ConfigureLogger(logger);
|
||||
SteamManager.ConfigureAppId(480);
|
||||
SteamManager.ConfigureLibraryPath(pluginFolder);
|
||||
if (SteamManager.RestartAppIfNecessary(480)) { Quit(); return; }
|
||||
var steam = SteamManager.Instance;
|
||||
steam.OverlayActivated += overlay => Pause(overlay.Active);
|
||||
steam.Update();
|
||||
```")]
|
||||
public class SteamManager
|
||||
@@ -17,6 +19,8 @@ steam.Update();
|
||||
private static SteamManager _instance;
|
||||
private static uint? _configuredAppId;
|
||||
private static ILogger _logger = NullLogger.Instance;
|
||||
private static readonly SteamCallbackDispatcher CallbackDispatcher = new SteamCallbackDispatcher();
|
||||
private static readonly SteamAppsManager AppsManager = new SteamAppsManager();
|
||||
private static readonly SteamUgcManager UgcManager = new SteamUgcManager();
|
||||
private static readonly SteamRemotePlayManager RemotePlayManager = new SteamRemotePlayManager();
|
||||
private static readonly SteamControllerManager ControllerManager = new SteamControllerManager();
|
||||
@@ -41,14 +45,76 @@ steam.Update();
|
||||
|
||||
internal static ILogger Logger => _logger;
|
||||
|
||||
internal static SteamCallbackDispatcher Dispatcher => CallbackDispatcher;
|
||||
|
||||
[Documentation(nameof(ConfigureLogger), "Configures the logger used by Steamworks helper classes.", new[] { "logger: ILogger instance to receive Steamworks logs." }, null)]
|
||||
public static void ConfigureLogger(ILogger logger)
|
||||
{
|
||||
_logger = logger ?? NullLogger.Instance;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ConfigureAppId), "Configures the Steam AppId used during initialization. Must be called before accessing the singleton instance.", new[] { "appId: Steam application identifier." }, null)]
|
||||
[Documentation(nameof(ConfigureLibraryPath), "Adds a folder (or full file path) to search first for the Steam API native library (steam_api64.dll / libsteam_api.so / libsteam_api.dylib). Can be called several times; paths are tried in order, then the default locations. Must be called before Instance or RestartAppIfNecessary. Returns false when the library is already loaded.", new[] { "directoryOrFile: Folder containing the native library, or the full path to it." },
|
||||
@"```csharp
|
||||
SteamManager.ConfigureLibraryPath(Path.Combine(gameDataFolder, ""Plugins"", ""x86_64""));
|
||||
```")]
|
||||
public static bool ConfigureLibraryPath(string directoryOrFile)
|
||||
{
|
||||
if (!SteamNativeApi.AddLibrarySearchPath(directoryOrFile))
|
||||
{
|
||||
_logger.LogWarning("ConfigureLibraryPath ignored for '{SteamLibraryPath}': the path is empty or the Steam API library is already loaded.", directoryOrFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ConfigureManualDispatch), "Enables or disables manual callback dispatch (enabled by default). When disabled, Update() uses SteamAPI_RunCallbacks and no callback events or async call results are delivered. Must be called before Instance.", new[] { "enabled: True to use manual dispatch." }, null)]
|
||||
public static bool ConfigureManualDispatch(bool enabled)
|
||||
{
|
||||
return _instance == null && SteamNativeApi.ConfigureManualDispatch(enabled);
|
||||
}
|
||||
|
||||
[Documentation(nameof(RestartAppIfNecessary), "Calls SteamAPI_RestartAppIfNecessary. Returns true when the game was not launched through Steam and Steam is relaunching it: quit immediately in that case. Call it before Instance and before ConfigureAppId (steam_appid.txt, and possibly the SteamAppId environment variable, suppress the relaunch). Returns false when the native library cannot be loaded.", new[] { "appId: Your Steam AppId." },
|
||||
@"```csharp
|
||||
if (SteamManager.RestartAppIfNecessary(480))
|
||||
{
|
||||
Quit();
|
||||
return;
|
||||
}
|
||||
```")]
|
||||
public static bool RestartAppIfNecessary(uint appId)
|
||||
{
|
||||
if (appId == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_configuredAppId.HasValue)
|
||||
{
|
||||
_logger.LogWarning("RestartAppIfNecessary was called after ConfigureAppId; the AppId environment variables or steam_appid.txt may stop Steam from relaunching the game.");
|
||||
}
|
||||
|
||||
var restarting = SteamNativeApi.RestartAppIfNecessary(appId);
|
||||
if (restarting)
|
||||
{
|
||||
_logger.LogInformation("Steam is relaunching the game through the Steam client; the current process should exit.");
|
||||
}
|
||||
|
||||
return restarting;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ConfigureAppId), "Configures the Steam AppId used during initialization by setting the SteamAppId/SteamGameId environment variables. Does not write steam_appid.txt. Must be called before accessing the singleton instance.", new[] { "appId: Steam application identifier." }, null)]
|
||||
public static bool ConfigureAppId(uint appId)
|
||||
{
|
||||
return ConfigureAppId(appId, false);
|
||||
}
|
||||
|
||||
[Documentation(nameof(ConfigureAppId), "Configures the Steam AppId used during initialization. Optionally writes steam_appid.txt next to the executable and in the working directory (useful in editors and development builds; leave false for shipped builds). Must be called before accessing the singleton instance.", new[]
|
||||
{
|
||||
"appId: Steam application identifier.",
|
||||
"writeSteamAppIdFile: True to also write steam_appid.txt."
|
||||
}, null)]
|
||||
public static bool ConfigureAppId(uint appId, bool writeSteamAppIdFile)
|
||||
{
|
||||
if (appId == 0)
|
||||
{
|
||||
@@ -62,13 +128,29 @@ steam.Update();
|
||||
}
|
||||
|
||||
_configuredAppId = appId;
|
||||
SteamNativeApi.ConfigureAppId(appId);
|
||||
SteamNativeApi.ConfigureAppId(appId, writeSteamAppIdFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Documentation(nameof(IsSteamworksInitialized), "Indicates whether Steamworks is initialized and ready for API calls.", null, null)]
|
||||
public bool IsSteamworksInitialized { get; private set; }
|
||||
|
||||
[Documentation(nameof(InitErrorMessage), "The reason initialization failed, as reported by SteamAPI_InitFlat when available. Empty after a successful init.", null, null)]
|
||||
public string InitErrorMessage { get; private set; } = string.Empty;
|
||||
|
||||
[Documentation(nameof(Callbacks), "Provides callback subscriptions and async call results through manual dispatch.", null, null)]
|
||||
public SteamCallbackDispatcher Callbacks => CallbackDispatcher;
|
||||
|
||||
[Documentation(nameof(OverlayActivated), "Raised from Update() when the Steam overlay opens or closes. Same as Callbacks.OverlayActivated.", null, null)]
|
||||
public event Action<SteamOverlayActivated> OverlayActivated
|
||||
{
|
||||
add => CallbackDispatcher.OverlayActivated += value;
|
||||
remove => CallbackDispatcher.OverlayActivated -= value;
|
||||
}
|
||||
|
||||
[Documentation(nameof(Apps), "Provides access to ISteamApps bindings (ownership, DLC, language).", null, null)]
|
||||
public SteamAppsManager Apps => AppsManager;
|
||||
|
||||
[Documentation(nameof(Ugc), "Provides access to Steam Workshop (UGC) helper operations.", null, null)]
|
||||
public SteamUgcManager Ugc => UgcManager;
|
||||
|
||||
@@ -134,11 +216,12 @@ steam.Update();
|
||||
if (SteamNativeApi.Initialize(_configuredAppId))
|
||||
{
|
||||
IsSteamworksInitialized = true;
|
||||
_logger.LogInformation("Steamworks initialized successfully.");
|
||||
_logger.LogInformation("Steamworks initialized successfully (manual callback dispatch: {ManualDispatchActive}).", SteamNativeApi.IsManualDispatchActive);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Steamworks initialization failed. Ensure Steam is running and AppId context is valid.");
|
||||
InitErrorMessage = SteamNativeApi.LastInitErrorMessage;
|
||||
_logger.LogWarning("Steamworks initialization failed: {InitErrorMessage} Ensure Steam is running and AppId context is valid.", InitErrorMessage);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -148,20 +231,30 @@ steam.Update();
|
||||
}
|
||||
|
||||
// This must be called from your game's main loop (e.g., Update in Unity/Godot)
|
||||
[Documentation(nameof(Update), "Executes Steamworks callbacks. Call every frame from your game loop.", null, null)]
|
||||
[Documentation(nameof(Update), "Executes Steamworks callbacks (manual dispatch, or SteamAPI_RunCallbacks when manual dispatch is unavailable) and delivers events and async call results. Call every frame from your game loop's main thread.", null, null)]
|
||||
public void Update()
|
||||
{
|
||||
if (IsSteamworksInitialized)
|
||||
if (!IsSteamworksInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SteamNativeApi.IsManualDispatchActive)
|
||||
{
|
||||
CallbackDispatcher.RunFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
SteamNativeApi.RunCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
[Documentation(nameof(Shutdown), "Shuts down Steamworks and clears the initialized state.", null, null)]
|
||||
[Documentation(nameof(Shutdown), "Shuts down Steamworks and clears the initialized state. Pending async call results complete with IoFailure = true.", null, null)]
|
||||
public void Shutdown()
|
||||
{
|
||||
if (IsSteamworksInitialized)
|
||||
{
|
||||
CallbackDispatcher.FailPendingCallResults();
|
||||
SteamNativeApi.Shutdown();
|
||||
IsSteamworksInitialized = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user