เอกสาร Steamworks
Steamworks API Overview

Overview

The Steamworks API allows your game to take full advantage of Steam by accessing all of the underlying systems provided through the API. This includes things such as pausing your game when the user opens the Steam Overlay, inviting friends to play, allowing players to unlock Steam Achievements, letting players compete on the Steam Leaderboards and much more.

The Steamworks API Reference catalogs and documents every interface, function, callback, and type supported in the API.

Integration with the Steamworks API is never required to ship your product on Steam, but it is highly recommended as it allows you to accomplish many interactions that Steam users expect.

Getting Started

NOTE: The Steamworks API officially supports C++, using Microsoft Visual Studio 2008+ on Microsoft Windows, GCC 4.6+ and Clang 3.0+ on macOS and SteamOS / Linux. If you're using a third party engine or a programming language other than C++ then you should first look at Commercial engine and non-C++ language support to see if there are more specific instructions to get started with your engine or language of choice. In some cases you may be able to skip many of these steps.

  • If you haven't already, download the Steamworks SDK and unzip it.
  • Copy the Steamworks API headers folder public/steam into an appropriate place in your applications source tree.
  • Copy the relevant redistributable files from redistributable_bin into an appropriate place in your project folder.
    • Windows
      You must have steam_api[64].lib linking in your visual studio project. This can be linked to either the primary executable or a module that uses Steam. This allows you to access the functionality contained in steam_api[64].dll which is exposed via the Steamworks API headers. Additional Reading: Linking an Executable to a DLL (MSDN)

      You must also ship the steam_api[64].dll in your run-time directory (next to your programs executable, or in your dll search path).
    • macOS
      libsteam_api.dylib provides both the x86 and x64 version of the Steam API. You must link to this in your Xcode project and you must ship this along side your executable.
      Additional Reading: Using Dynamic Libraries
    • Linux
      libsteam_api.so You must both link to and ship this along side your executable.

Initialization and Shutdown

SteamAPI_Init

After you have the Steamworks API set up within your project you can start using it by calling SteamAPI_Init function to initialize the API. This will set up the global state and populate the interface pointers which are accessible via the global functions which match the name of the interface. This MUST be called and return successfully prior to accessing any of the Steamworks Interfaces!

The Steamworks API will not initialize if it does not know the App ID of your game. When you launch your app from Steam itself then it will automatically have the App ID available. While developing you will need to hint this to Steam with a text file. Create the a text file called steam_appid.txt next to your executable containing just the App ID and nothing else. This overrides the value that Steam provides. You should not ship this with your builds. Example:
480

A return of false 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 steam_appid.txt 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 steam_appid.txt 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.
If you're running into initialization issues then see the Debugging the Steamworks API documentation to learn about the various methods of debugging the Steamworks API.

SteamAPI_RestartAppIfNecessary

SteamAPI_RestartAppIfNecessary checks if your executable was launched through Steam and relaunches it through Steam if it wasn't.

This is optional but highly recommended as the Steam context associated with your application (including your App ID) will not be set up if the user launches the executable directly. If this occurs then SteamAPI_Init will fail and you will be unable to use the Steamworks API.
If you choose to use this then it should be the first Steamworks function call you make, right before SteamAPI_Init.

If this returns true then it starts the Steam client if required and launches your game again through it, and you should quit your process as soon as possible. This effectively runs steam://run/<AppID> so it may not relaunch the exact executable that called this function (for example, if you were running from your debugger). It will always relaunch from the version installed in your Steam library folder.

Otherwise, if it returns false, then your game was launched by the Steam client and no action needs to be taken. One exception is if a steam_appid.txt file is present then this will return false regardless. This allows you to develop and test without launching your game through the Steam client. Make sure to remove the steam_appid.txt file when uploading the game to your Steam depot!

NOTE: If you use the Steam DRM wrapper on your primary executable file, this check is unnecessary as the DRM wrapper will perform this internally.

SteamAPI_Shutdown

When you are done using the Steamworks API you should call SteamAPI_Shutdown to release the resources used by your application internally within Steam. You should call this during process shutdown if possible.

This will not unhook the Steam Overlay from your game as there's no guarantee that your rendering API is done using it.

Steamworks Interfaces

The Steamworks API is composed of multiple interfaces which all expose a limited, specific amount of functionality.

After Steamworks has successfully initialized you can then access the interfaces via their global functions. The functions always match the name of their interface. As such you can access ISteamApps through the SteamApps() accessor and ISteamFriends through SteamFriends().

You can use these interfaces to make calls like so:
// Get the current users Steam name. const char *name = SteamFriends()->GetPersonaName();

You can view the complete list of interfaces on the Steamworks API Reference or by diving into the Steamworks API header files.

Callbacks

Callbacks are one of the most important aspect of Steamworks, they allow you to retrieve data asynchronously from Steam without locking up your game. The goal of the callbacks are to provide a simple, light-weight, type-safe, thread-safe method of raising asynchronous events to any object registered as a listener.

Callbacks are usually triggered via an event that happens from Steam such as when ever a friend logs on or off, or the asynchronous result of some API functions. Each callback consists of a struct containing a unique identifier and a small set of data. The callbacks are declared in the ISteam*.h header files, grouped with the interface that it most closely belongs to.

To listen for a callback, a struct or class must use the macro STEAM_CALLBACK( :classname, :functionname, :callbackname ) in it's declaration.
  • :classname must be the name of the struct or class where you are defining this. (eg. CGameManager)
  • :functionname will be the name of the function that receives this callback. (eg. OnGameOverlayActivated)
  • :callbackname is the name of the callback. (eg. GameOverlayActivated_t)
This defines a local member function for that class which is automatically prototyped as void :functionname( :callbackname *pCallback ). Creating a new instance of the object will cause this member function to register itself as a listener with the Steamworks API; destruction of the object will cause it to de-register.

NOTE: You should ensure that Steam has been initialized before creating objects that listen for callbacks.

For callbacks to dispatch to registered listeners you must call the SteamAPI_RunCallbacks. It's best to call this frequently, as the more time between calls, the more latency between receiving events or results from the Steamworks API. Most games call this once per render-frame, it's highly recommended that you call this at least once a second. All registered listener functions will be invoked during this call, in the thread context where SteamAPI_RunCallbacks was called from.

Example

One callback that you will likely wish to use is ISteamFriends::GameOverlayActivated_t. As the name implies it sends you a callback every time the user activates or deactivates the Steam Overlay.

class CGameManager { private: STEAM_CALLBACK( CGameManager, OnGameOverlayActivated, GameOverlayActivated_t ); }; void CGameManager::OnGameOverlayActivated( GameOverlayActivated_t* pCallback ) { if ( pCallback->m_bActive ) printf( "Steam overlay now active\n" ); else printf( "Steam overlay now inactive\n" ); }

One popular and recommended use case for the ISteamFriends::GameOverlayActivated_t callback is to pause the game when the overlay opens.

CallResults

Many Steamworks methods use call results instead of a callback to asynchronously return results from a function call. The difference between a callback and call results is that callbacks are broadcast to all listeners, where-as call results only target a specific listener. Like callbacks, your game will need to call SteamAPI_RunCallbacks to dispatch call results to their listener.

You can identify a function that provides a call result by inspecting it's return value; if it returns a SteamAPICall_t and has a CALL_RESULT() attribute then you must register to receive the call result.

NOTE: Callbacks and call results are not interchangeable. An event will only come through one or the other, not both. You must make sure that you are registering for the right type of event!

Call results must be created as a member in a struct/class using the CCallResult type and you will also need to create the member function that will receive the callback.
void func( :callresultname *pCallback, bool bIOFailure ); CCallResult< :classname, :callresultname > m_callresultname;
  • :classname must be the name of the struct or class where you are defining this. (eg. CGameManager)
  • :callresultname is the name of the callback. (eg. NumberOfCurrentPlayers_t)

Feel free to name the function, function parameters, and CCallResult type anything you want.

Example

Here's an example of how to use the ISteamUserStats::GetNumberOfCurrentPlayers API which produces a ISteamUserStats::NumberOfCurrentPlayers_t call result.
// In your class definition class CGameManager { public: void GetNumberOfCurrentPlayers(); private: void OnGetNumberOfCurrentPlayers( NumberOfCurrentPlayers_t *pCallback, bool bIOFailure ); CCallResult< CGameManager, NumberOfCurrentPlayers_t > m_NumberOfCurrentPlayersCallResult; }; // Make the asynchronous request to receive the number of current players. void CGameManager::GetNumberOfCurrentPlayers() { printf( "Getting Number of Current Players\n" ); SteamAPICall_t hSteamAPICall = SteamUserStats()->GetNumberOfCurrentPlayers(); m_NumberOfCurrentPlayersCallResult.Set( hSteamAPICall, this, &CGameManager::OnGetNumberOfCurrentPlayers ); } // Called when SteamUserStats()->GetNumberOfCurrentPlayers() returns asynchronously, after a call to SteamAPI_RunCallbacks(). void CGameManager::OnGetNumberOfCurrentPlayers( NumberOfCurrentPlayers_t *pCallback, bool bIOFailure ) { if ( bIOFailure || !pCallback->m_bSuccess ) { printf( "NumberOfCurrentPlayers_t failed!\n" ); return; } printf( "Number of players currently playing: %d\n", pCallback->m_cPlayers ); }

NOTE: If you can't use the CCallResult system, then you may be able to use ISteamUtils::IsAPICallCompleted, ISteamUtils::GetAPICallResult and ISteamUtils::GetAPICallFailureReason to track the status of a call result.

Manual Callback Dispatch

The classes and macros used to register callbacks are convenient in C++ code. But there is also a lower-level mechanism for dealing with callbacks. This mechanism operates more like a windows event loop. Instead of a single function that dispatches all of the callbacks and call results to active listeners, you fetch the next available callback in a loop, and dispatch it using whatever mechanisms you want. The manual dispatch mode is especially useful for binding layers that expose the Steamworks SDK to languages other than C++. See SteamAPI_ManualDispatch_Init() in steam_api.h for more information.

Steam Game Servers

The Steamworks API includes support for running game servers as well as regular clients. A game server, in Steamworks API terms, is an entity in the system that normal users connect to to play multi-player games. This can be connecting over the Internet to a remote game server, or connecting locally to a game server that's in the same process as the client. Game servers have their own set of API functions to use, and their own unique Steam ID for other users to refer to them by.

To use the Steam Game Server API you must first include steam_gameserver.h instead of steam_api.h.

Initializing and using the game server API is very similar to the normal API:

After initializing a game server you have access to the two game server exclusive interfaces ISteamGameServer and ISteamGameServerStats.

You can also access the following regular interfaces from the game server:
  • ISteamClient which you can access via the global interface: SteamGameServerClient()
  • ISteamUtils which you can access via the global interface: SteamGameServerUtils()
  • ISteamNetworking which you can access via the global interface: SteamGameServerNetworking()
  • ISteamHTTP which you can access via the global interface: SteamGameServerHTTP()
  • ISteamUGC which you can access via the global interface: SteamGameServerUGC()
  • ISteamApps which you can access via the global interface: SteamGameServerApps()

If you're running a dedicated game server (one which has no client component), you only have to initialize the game server API's, you don't have to initialize the normal user API.

See Steamworks API Example Application (SpaceWar) for a fully loaded example of using the game server API.

Unlike a game, a dedicated server will usually be run in an environment where there is no Steam Client installed to provide the latest steamworks binaries. In order for the dedicated server to have the latest steam binaries, you will need to include the Dedicated Server Redistributables with your app. Log into partner.steamgames.com and navigate to the technical settings for your app. Then look under "Installation / Redistributables" and check "Dedicated Server Redistributables"

Commercial engine and non-C++ language support

If you're using a commercial game engine or a language other than C or C++ you will want to see what level of support for the Steamworks API is provided for it.
In some engines they provide native built-in support, for others you may need a third-party solution.

If your engine does not have native support you can use the Steam Web API to access many features that Steam supports.

Regardless of how the Steamworks SDK is implemented in your engine you will need to have the latest Steamworks SDK to upload your application to Steam.

NOTE: If some of the software you are shipping on steam is available under a restrictive open source license then please see Distributing Open Source Applications on Steam.

Here are some common engines that people routinely use to ship games on Steam and the relevant documentation on how to get started using the Steamworks SDK with them.

NOTE: Valve does not in any way endorse any of these engines or the third-party solutions. This list is sorted exclusively by name, and is in no way comprehensive, it exists solely as a starting guide. Engines will only be listed if they include native support or have a third-party solution that fits the guidelines. Third-party solutions will only be listed if they are kept reasonably up to date with the Steamworks SDK, are freely available under a permissive license (See: Distributing Open Source Applications on Steam), and have a thread on the Steamworks Discussion Board. We recommend that you consult the community to see which option would work best for your specific setup.

Engines:

EngineNative support?Information
CRYENGINE ✔️
GameMaker Studio 2 ✔️ Using The Steamworks SDK With GameMaker: Studio
Godot Third Party: GodotSteam - Steamworks Developer Discussions support thread
Haxe Third Party: SteamWrap - Steamworks Developer Discussions support thread
Leadwerks Game Engine ✔️ Leadwerks API Reference › Steamworks
RPG Maker MV Third party: Greenworks - Steamworks Developer Discussions support thread
Source 2013 ✔️ Distributing Source Engine Games / Mods
Unity Third party: Facepunch.Steamworks - Steamworks Developer Discussions support thread
Third party: http://steamworks.github.io - Steamworks Developer Discussions support thread
Unreal Engine 4 ✔️ Online Subsystem Steam
Visionaire Studio ✔️ Publish on Steam

Languages:

Flat interface for binding to other languages

The SDK has a few features to facilitate the creation of binding layers for other languages.

  • steam_api_flat.h declares a set of "flat" functions that mirror the interface functions in the SDK. This is not pure C code, but it does use plain C linkage and calling conventions, so it is easy to interop with other languages. These functions are exported by steam_api[64][.dll/.so/dylib].
  • steam_api.json describes (almost all of) the interfaces, types, and functions in the SDK. It is intended that this file be used by an automated process to generate binding layer. We hope that this can be used to automate 95% of the work, but there are still a few special cases that need to be handled manually. In particular, CSteamID and CGameID will probably require special handling by your binding layer to make it efficient.

Technical Details

Steam uses a variety of techniques to expose functionality to your application. It's by no means critical to understand exactly how the Steamworks API works but it's fairly simple and can be useful in planning out how to code your game with Steam integration in mind.

When you link to steam_api[64][.dll/.so/dylib] it provides access to a small number of C functions which are prefixed with the S_API macro, these functions are all exposed in steam_api.h and steam_gameserver.h. The steam_api module itself is very small, it only exposes the base functionality to initialize and shutdown the Steamworks API.

When the Steamworks API initializes it finds the actively running steam client process and loads steamclient.dll from that path. steamclient.dll is essentially the core engine of the Steam client. It contains and maintains the information necessary to run Steam. The Steam client UI uses a similar set of functions as exposed here to access the data provided by steamclient.dll. Since this data is in the Steam process, all Steam API calls are transparently marshaled and sent via an RPC/IPC mechanism. (A cross-process pipe, ISteamClient::HSteamPipe).

The Steam process, via steamclient.dll maintains a constant connection to the Steam back-end servers. Through this connection all authentication, matchmaking, friends list and VAC communication occurs. This connection may drop if the user has a network issue, or if the Steam server they are connected to receives an update. Callbacks will be posted to any running app if the connection drops or re-establishes. The Steam client will automatically try to reconnect, and clients running an app receive priority, so the typical reconnect time is under 10 seconds, although in some rare cases may be up to 5 minutes.

The Steamworks API is versioned through a COM-like mechanism, where a string name and version of an interface are passed into steamclient.dll which then returns the correct version of the interface to the caller. steamclient.dll contains a set of adapters for all released versions of an interface which redirect or re-interpret the old calls in the context of the latest interface. The adapters live inside the steam client so that they are easy to update if any issues arise.