无所属单位

主页 文献与帮助
Steamworks 文献库
Steamworks API 概览

概览

通过 Steamworks API ,您的游戏可最大限度地利用该 API 提供的 Steam 基础系统,包括开启 Steam 界面时暂停游戏、邀请好友加入游戏、解锁 Steam 成就并在 Steam 排行榜上 互相较量,以及更多丰富的功能。

Steamworks API 偏好 中分类并纪录了 API 支持的所有接口、函数、回调和类型信息。

将产品上架 Steam 时,不要求必须整合 Steamworks API,但我们强烈建议整合,因为其中包含了许多 Steam 用户期待的互动功能。

入门指南

备注:Steamworks API 正式支持 Microsoft Windows 上 Visual Studio 2008+ 的 C++ ,以及 macOS 和 SteamOS / Linux 上的 GCC 4.6 + 以及 Clang 3.0+。如果您使用的是 C++ 以外的第三方引擎或编程语言,请先参阅对商业引擎和非 C++ 语言的支持,了解您所选的引擎或语言是否有特别需要采取的步骤。在某些情况下,可省略许多步骤。

  • 如果尚未下载,请先下载 Steamworks SDK 并解压缩文件。
  • 将 Steamworks API 标头文件夹 public/steam 复制至您的应用程序来源树中适当的位置。
  • 将下列其中一个头文件引入您的 C++ 项目中。
    • steam_api.h – 引入所有 Steamworks 标头,以及提供初始化 Steamworks API 所需的进入点。
    • steam_gameserver.h – 只有在使用 Steam 游戏服务器 API 时才需要引入此文件。由于内部已引入了 steam_api.h,所以不需要引入两份。
  • redistributable_bin 复制相关的可再发行文件至您的项目文件夹中的适当位置。
    • Windows
      您须将 steam_api[64].lib 链接至您的 Visual Studio 项目。可链接至主要可执行文件或使用 Steam 的模块。您便可使用 steam_api[64].dll 中以 Steamworks API 标头公开访问的功能。相关文章请参阅:将可执行文件链接至 DLL(MSDN)一文。

      另外,您必须将 steam_api[64].dll 放入运行时目录中(在程序可执行文件旁边,或是在 dll 搜索路径中)才能发行程序。
    • macOS
      libsteam_api.dylib 提供了 x86 和 x64 两种版本的 Steam API。您须将此文件链接至 XCode 项目,并与可执行文件一同推出。
      相关文章请参阅: 使用动态库(Using Dynamic Libraries)
    • Linux
      您必须同时将 libsteam_api.so 链接至您的可执行文件,并一同推出。

初始化与关闭

SteamAPI_Init

在您的项目内设置好 Steamworks API 后,便可开始调用 SteamAPI_Init 函数来初始化 API 了。这将建立全局状态并填入接口指针,然后便可通过与接口名称相同的全局函数访问。要使用任何 Steamworks 接口之前,必须先调用该函数并成功返回!

若 Steamwork API 不知道您游戏的 App ID ,便无法初始化。如果是从 Steam 本身启动应用程序,便会自动取得有效的 App ID。开发过程中,您将需要用文本文件向 Steam 提示这一点。请在您的可执行文件旁边创建一个名为 steam_appid.txt 的文本文件,其中除了 App ID 以外不要输入任何文字。这将重写 Steam 所提供的值。请确保不要将此文件与生成版本一同推出。文件示例:
480

如果返回 False 则代表发生了下列其中一种状况:
  • Steam 客户端不在运行中。必须运行 Steam 才可实现各种 Steamworks 接口。
  • Steam 客户端无法确定游戏的 App ID。如果您是直接从可执行文件或调试程序启动应用程序,则必须在游戏目录中可执行文件旁边放置一个 steam_appid.txt,其中除了 App ID 以外不要输入任何文字。Steam 将从目前执行的目录中寻找此文件。如果您是从别的目录开启可执行文件,可能也需要移动 steam_appid.txt 文件。
  • 应用程序所执行的操作系统用户内容与 Steam 客户端不相符,例如不同的用户或管理员访问权限。
  • 请确定您的当前有效 Steam 帐户中持有该 App ID 的许可。您的游戏必须出现于 Steam 库中。
  • 您的 App ID 并未设置完全,也就是说尚处于发行状态:不可用阶段,或是缺失了默认程序包。
如果您在初始化时遇到了问题,请参见 Steamworks API 调试 一文,了解有关各种调试方法的信息。

SteamAPI_RestartAppIfNecessary

SteamAPI_RestartAppIfNecessary 将检查您的可执行文件是否由 Steam 启动,若不是,则会从 Steam 重新启动。

虽然此项为可选,但我们强烈建议这么做,因为如果用户直接从可执行文件启动,便无法设置应用程序相关的 Steam 内容(包括 App ID)。如此一来,SteamAPI_Init 便会失败,也就无法使用 Steamworks API。
若您决定要检查,您需要首先调用此 Steamworks 函数,然后调用 SteamAPI_Init

如果返回了 True,必要情况下,便会开启 Steam 客户端,并通过客户端再次启动游戏,您则必须尽快退出进程。此函数有效利用了 steam://run/< AppID> ,所以并不一定会再次启动调用它的可执行文件(例如说,如果从调试程序启动)。此函数永远会重新启动 Steam 库文件夹中的版本。

相反地,如果返回了 False,则表示您的游戏是从 Steam 客户端启动的,无须采取任何操作。例外的情况是,如果 steam_appid.txt 文件存在,那么无论如何都会返回 False。如此一来,开发和测试游戏时便不需要从 Steam 客户端启动游戏。将游戏上传至 Steam Depot 时,请记得移除 steam_appid.txt

备注:如果您在主要可执行文件上使用了Steam DRM 包装器,此检查便无需进行,因为 DRM 的包装器会在内部进行检查。

SteamAPI_Shutdown

使用完 Steamworks API 后,您应调用 SteamAPI_Shutdown 来释放您的应用程序在 Steam 内部所使用的资源。如果可能的话,您应在关闭过程中调用此函数。

此举并不会解除您的游戏与 Steam 界面 的挂钩,因为无法保证您的渲染 API 不再需要该界面。

Steamworks 接口

Steamworks API 是由多个接口所组成,各个接口皆具有数量有限且特定的功能。

Steamworks 成功初始化后,便可通过各自的全局函数访问 Steamworks 接口。而全局函数永远会与其接口名称相符。例如,您可通过 SteamApps() 访问器访问 ISteamApps,并通过 SteamFriends() 访问 [ api]ISteamFriends[/api]。

您可利用这些接口,进行如下调用:
// 获取当前用户的 Steam 名称。 const char *name = SteamFriends()-> GetPersonaName();

如需接口的完整列表,请参阅 Steamworks API 偏好,或查阅 Steamworks API 的头文件。

回调

回调是 Steamworks 中极其重要的一部份,能在不锁定游戏的状况下,以异步的方式从 Steam 取得数据。回调的目的是用来提供一个简易、轻量、类型安全且线程安全的方式,向任何作为侦听程序的对象发起异步事件。

回调通常是由 Steam 上的事件触发,例如好友登录或注销,或是从 API 函数传来的异步结果。每个回调都由包含一个唯一识别符和一小组数据的结构组成。回调结构会在 ISteam*.h 头文件中声明,与最相近的接口组成一组。

要侦听回调时,对象需要在其结构或类别声明中使用宏 STEAM_CALLBACK( :classname, :functionname, :callbackname )
  • :classname 须为定义时所在的结构或类别名称。(例:CGameManager
  • :functionname 为接收回调的函数名称。(例:OnGameOverlayActivated
  • :callbackname 为回调的名称。(例:GameOverlayActivated_t
如此便会给该类别定义一个本地成员对象,而原型将被自动设置为 void :functionname( :callbackname *pCallback )。如果创建一个对象的新示例,便会导致此成员函数将自己注册为 Steamworks API 的侦听程序;销毁对象便会导致取消注册。

备注:创建侦听回调的对象前,请先确定 Steam 已初始化。

调用 SteamAPI_RunCallbacks 即可向注册侦听程序发送回调。由于调用的间隔越长,接收事件或来自 Steamworks API 结果的延时就越长,所以最好经常调用。绝大部分游戏是每次渲染一帧便调用一次,而我们强烈建议您至少每秒调用一次。在本次调用期间,所有注册的侦听函数都将在 SteamAPI_RunCallbacks 的线程上下文中被调用。

示例

一个很可能会用到的回调是 ISteamFriends::GameOverlayActivated_t。正如其名,每当用户开启或关闭 Steam 界面时,便会发送一个回调给您。

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

ISteamFriends::GameOverlayActivated_t 常见且推荐的用法是在开启界面时暂停游戏。

CallResults (调用结果)

有些 Steamworks 方法使用调用结果代替回调,从函数调用中异步返回结果。回调与调用结果的区别是,回调向所有侦听程序广播,而调用结果只针对其中一个特定的侦听程序。与回调一样,您的游戏需要调用 SteamAPI_RunCallbacks 向各个侦听程序发送调用结果。

您可通过返回值来判断一个函数提供的是否为调用结果。如果返回的是具有 CALL_RESULT() 属性的 SteamAPICall_t,则必须注册以获取调用结果。

备注:回调与调用结果无法互换。事件只会通过一种方式传来,而不会两种一起使用。您必须确认自己注册了正确的事件类型!

调用结果须使用 CCallResult 类型,创建为某个结构或类别的成员,同时您也需要创建用来接收回调的成员函数。
void func( :callresultname *pCallback, bool bIOFailure ); CCallResult< :classname, :callresultname > m_callresultname;
  • :classname 须为定义时所在的结构或类别名称。(例:CGameManager
  • :callresultname 为回调的名称。(例:NumberOfCurrentPlayers_t

您可依自己的想法任意命名函数、函数参数,以及 CCallResult 类型。

示例

以下为使用 ISteamUserStats::GetNumberOfCurrentPlayers API,产生调用结果 ISteamUserStats::NumberOfCurrentPlayers_t 的示例。
// 在您的类定义中, class CGameManager { public: void GetNumberOfCurrentPlayers(); private: void OnGetNumberOfCurrentPlayers( NumberOfCurrentPlayers_t *pCallback, bool bIOFailure ); CCallResult< CGameManager, NumberOfCurrentPlayers_t > m_NumberOfCurrentPlayersCallResult; }; // 进行异步请求,获得当前玩家数量。 void CGameManager::GetNumberOfCurrentPlayers() { printf( " Getting Number of Current Players\ " ); SteamAPICall_t hSteamAPICall = SteamUserStats()-> GetNumberOfCurrentPlayers(); m_NumberOfCurrentPlayersCallResult.Set( hSteamAPICall, this, & CGameManager::OnGetNumberOfCurrentPlayers ); } // SteamUserStats()-> GetNumberOfCurrentPlayers() 异步返回时调用,此前进行 SteamAPI_RunCallbacks() 调用。 void CGameManager::OnGetNumberOfCurrentPlayers( NumberOfCurrentPlayers_t *pCallback, bool bIOFailure ) { if ( bIOFailure || !pCallback->m_bSuccess ) { printf( " NumberOfCurrentPlayers_t failed!\ " ); return; } printf( " Number of players currently playing: %d\ ", pCallback->m_cPlayers ); }

备注:如果您无法使用 CCallResult 系统,或许可以改用 ISteamUtils::IsAPICallCompletedISteamUtils::GetAPICallResultISteamUtils::GetAPICallFailureReason 来追踪调用结果的状态。

Steam 游戏服务器

Steamworks API 可以像支持普通客户端一样地支持游戏服务器。在Steamworks API 术语中,游戏服务器是系统中的一个实体,一般用户可通过服务器进行多人游戏。它既可以是通过网络远程连接的游戏服务器,也可以是与客户端位于同一进程的本地游戏服务器。游戏服务器使用自己的 API 函数以及唯一的 Steam ID,从而让其他用户参照引用。

要使用 Steam 游戏服务器 API,您须先引入 steam_gameserver.h 而非 steam_api.h

游戏服务器 API 的初始化与使用方法和一般 API 非常相似:

初始化完成后,便可使用两个游戏服务器专用的接口:ISteamGameServerISteamGameServerStats

另外,游戏服务器也可使用下列普通接口:
  • ISteamClient,将使用此全局接口:SteamGameServerClient()
  • ISteamUtils,将使用此全局接口:SteamGameServerUtils()
  • ISteamNetworking,将使用此全局接口:SteamGameServerNetworking()
  • ISteamHTTP,将使用此全局接口:SteamGameServerHTTP()
  • ISteamInventory,将使用此全局接口:SteamGameServerInventory()
  • ISteamUGC,将使用此全局接口:SteamGameServerUGC()
  • ISteamApps,将使用此全局接口:SteamGameServerApps()

如果您运行的是专用游戏服务器(除去客户端组件),则只需要初始化游戏服务器 API ,无需初始化一般的用户 API。

如需游戏服务器 API 的完整示例,请见 Steamworks API 示例应用程序(SpaceWar)

对商业引擎和非 C++ 语言的支持

如果您使用的是商业引擎或 C 或 C ++ 以外的语言,便需要先知道对 Steamworks API 的支持程度。
部分引擎自己便提供了内建支持,另外的则可能需要使用第三方解决方案。

如果您的引擎没有原生支持,可从 Steam Web API 访问 Steam 所支持的功能。

无论您的引擎如何实现 Steamworks SDK,其中都需要有最新版本的 Steamworks SDK,才能将 应用程序上传至 Steam

备注:如果您要上架 Steam 的部分软件适用受限的开源许可条款,请见 在 Steam 上分销开源应用程序 一文。

以下为 Steam 上推出游戏常用的引擎,以及如何在上面使用 Steamworks SDK 的相关文档。

备注: Valve 不会以任何形式替下列任何引擎或第三方解决方案背书。本列表仅依照名称排列,信息并不全面,仅用来当作新手入门的指南。只有带有原生支持或符合规范的第三方解决方案的引擎才会出现在列表中。而第三方解决方案必须与 Steamworks SDK 保持适度更新,并在许可条款下可自由使用(请见:在 Steam 上分销开源应用程序),并且在 Steamworks 讨论区已有跟帖。我们建议您咨询社区,看看哪个选项对您的特定设置最有效。

引擎:

引擎原生支持?信息
CRYENGINE ✔ ️
GameMaker Studio 2 ✔ ️ Using The Steamworks SDK With GameMaker: Studio
Godot第三方:GodotSteam - Steamworks 开发者讨论区支持跟帖
Haxe第三方:SteamWrap - Steamworks 开发者讨论区支持跟帖
Leadwerks Game Engine ✔ ️ Leadwerks API Reference › Steamworks
RPG Maker MV第三方:Greenworks - Steamworks 开发者讨论区支持跟帖
Source 2013 ✔ ️
Unity第三方:Facepunch.Steamworks - Steamworks 开发者讨论区支持跟帖
第三方:Steamworks .NET - Steamworks 开发者讨论区支持跟帖
Unreal Engine 4 ✔ ️ Steam, Using the Steam SDK During Development
Visionaire Studio ✔ ️ Publish on Steam

程序语言:

技术细节

Steam 使用了各种层面的技术让您的应用程序能够接触各式功能。虽然您不必详细了解 Steamworks API 的实际运行方式,但其本身也并不复杂,而在计划如何编写您的游戏并整合 Steam 功能时,也可能派得上用场。

链接至 steam_api[64][.dll/.so/dylib] 便可访问前缀为 S_API 宏的 少数 C 函数 ,它公开于 steam_api.hsteam_gameserver.h 之中。steam_api 模块本身非常小,仅公开了初始和关闭 Steamworks API 的基本功能。

Steamworks API 初始化时会找到正在运行的 Steam 客户端进程并从其路径中加载 steamclient.dllsteamclient.dll 本质上是 Steam 客户端的核心引擎,其中包含并维护运行 Steam 所必需的信息。Steam 客户端用户接口利用类似的方法访问 steamclient.dll 提供的数据。由于该数据位于 Steam 进程中,所有 Steam API 调用皆通过透明封送,并通过 RPC/IPC 机制(跨进程管道 ISteamClient:: HSteamPipe)发送)。

Steam 进程通过 steamclient.dll 与 Steam 后端服务器时刻保持连接。所有身份验证、对战匹配、好友名单,和 VAC 的相关通信都通过此连接实现。当用户本地网络出现问题,或连接的 Steam 服务器更新时,此连接便会中断。如果用户掉线或重新连接时,便会将回调发送给所有运行中的应用程序。 Steam 客户端将自动尝试重新连接,运行游戏的客户端会获得优先权,所以一般重新连接耗时不会超过 10 秒,极个别情况会长达 5 分钟。

Steamworks API 的版本控制通过类似 COM 的机制完成。字符串名称和接口版本会传入 steamclient.dll,随后便会将接口的正确版本传回给调用者。steamclient.dll 内含一组适用于所有已发行版本接口的适配器,可以将旧调用重新定向或解读成符合最新版本接口的形式。适配器位于 Steam 客户端中,因此在发生故障时较容易更新。