Skip to content

suggesting an updated SteamManager #773

@u-an-i

Description

@u-an-i
// The SteamManager is designed to work with Steamworks.NET
// This file is released into the public domain.
// Where that dedication is not recognized you are granted a perpetual,
// irrevocable license to copy and modify this file as you see fit.
//
// Version: 1.0.13

// allow SteamManager for any target
#if !DISABLESTEAMWORKS

using Steamworks;
using UnityEngine;


// The SteamManager provides a base implementation of Steamworks.NET on which you can build upon.
// It handles the basics of starting up and shutting down the SteamAPI for you to use.
//
// Calling a base class method from a derived class cannot be guaranteed.
// You can use Steamworks(.NET) API (wrapper) in your own classes at your own leisure after this
// class initialised the Steamworks API.
//
// let Update run early in the frame, see there
[DefaultExecutionOrder(-31998)]
[DisallowMultipleComponent]
public sealed class SteamManager : MonoBehaviour
{
	// slider size is likely not more than 100px
	public int numberOfFramesToWaitBetweenCallsToSteamworksAPI
	{
		get => numberFramesToWait;
		set => numberFramesToWait = Unity.Mathematics.math.clamp(value, 0, 99);
    }
    [Range(0, 99)]
    [SerializeField]
    private int numberFramesToWait = 59;
    private int numberFramesPassed;

    private static SteamManager first = null;
	private static int countObjectsOfSelf = 0;
	private static bool steamAPIRunning = false;

	private bool doRegisterToNotDestroy = true;
    private bool quitRequested = false;


	[AOT.MonoPInvokeCallback(typeof(SteamAPIWarningMessageHook_t))]
	private static void SteamAPIDebugTextHook(int nSeverity, System.Text.StringBuilder pchDebugText) {
		Debug.LogWarning(pchDebugText);
	}

	private static string note()
	{
		return "[Steamworks.NET] Steamworks API may not be initialised twice. Do not have a second SteamManager for it. \nThe name of the GameObject the existing SteamManager is attached to is \"" + first.gameObject.name + "\" without quotation marks around it. \nIt resides in scene and path \"" + UnityEditor.Search.SearchUtils.GetHierarchyPath(first.gameObject, includeScene: true) + "\" without quotation marks around it. \nUse SteamManager.getSteamManager() to get the existing SteamManager -- it will create one if none exists -- during runtime.";
    }

    public SteamManager()
	{
		if(first == null)
            first = this;
		++countObjectsOfSelf;
    }
	~SteamManager()
	{
		if(--countObjectsOfSelf == 0)
		{
			first = null;
		}
    }

	// no use case exists for this for now except creating SteamManager during runtime
	// SteamManager does not have public methods except this one
	public static SteamManager getSteamManager()
	{
        if (countObjectsOfSelf > 0)
        {
            return first;
        }
		else
		{
			return new GameObject("SteamManager").AddComponent<SteamManager>();
		}
	}

    void Awake()
    {
        if (first != this)
        {
            Debug.LogWarning(note(), this);
            return;
        }

        if (doRegisterToNotDestroy)
		{
			doRegisterToNotDestroy = false;
            // We want our SteamManager Instance to persist across scenes.
            DontDestroyOnLoad(gameObject);
		}

        // Initializes the Steamworks API.
        // If this returns false then this indicates one of the following conditions:
        // [*] The Steam client isn't running. A running Steam client is required to provide implementations of the various Steamworks interfaces.
        // [*] The Steam client couldn't determine the App ID of game. If you're running your application from the executable or debugger directly then you must have a [code-inline]steam_appid.txt[/code-inline] in your game directory next to the executable, with your app ID in it and nothing else. Steam will look for this file in the current working directory. If you are running your executable from a different directory you may need to relocate the [code-inline]steam_appid.txt[/code-inline] file.
        // [*] Your application is not running under the same OS user context as the Steam client, such as a different user or administration access level.
        // [*] Ensure that you own a license for the App ID on the currently active Steam account. Your game must show up in your Steam library.
        // [*] Your App ID is not completely set up, i.e. in Release State: Unavailable, or it's missing default packages.
        // Valve's documentation for this is located here:
        // https://partner.steamgames.com/doc/sdk/api#initialization_and_shutdown
        steamAPIRunning = SteamAPI.Init();
        if (!steamAPIRunning) {
			Debug.LogWarning("[Steamworks.NET] SteamAPI_Init() failed. Refer to Valve's documentation or the comment above this line for more information.", this);
		} else {
            // Set up our callback to receive warning messages from Steam.
            // You must launch with "-debug_steamapi" in the launch args to receive warnings.
            SteamClient.SetWarningMessageHook(new SteamAPIWarningMessageHook_t(SteamAPIDebugTextHook));
		}

        enabled = steamAPIRunning;
	}

	void OnEnable()
	{
		if (!steamAPIRunning)
		{
			Awake();
        }
	}

    void Start()
    {
		numberFramesPassed = numberFramesToWait - 1;
    }

    // OnApplicationQuit gets called too early to shutdown the SteamAPI.
    void OnApplicationQuit()
	{
		quitRequested = true;
    }

    // Because the SteamManager should be persistent and never disabled or destroyed we shutdown the SteamAPI only when application about to quit.
    void OnDestroy()
	{
		if (quitRequested && steamAPIRunning)
        {
            SteamAPI.Shutdown();
			steamAPIRunning = false;		// be nice
        }
	}

	void Update()
	{
		if(++numberFramesPassed >= numberFramesToWait)
        {
            // collect
            SteamAPI.RunCallbacks();
        }
    }

    void LateUpdate()
    {
        if (numberFramesPassed >= numberFramesToWait)
        {
            numberFramesPassed = -1;
			if (numberFramesToWait > 0)
			{
				// dispatch
				SteamAPI.RunCallbacks();
			}
        }
    }
}
#endif

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions