Steamworks 文獻庫
Steamworks API 概覽

概覽

Steamworks API 讓您的遊戲得以透過 API 存取所有底層系統,以充分利用 Steam 能帶來的優勢。 這包含在使用者開啟 Steam 內嵌介面時暫停遊戲、邀請好友同樂、讓玩家解鎖 Steam 成就、供玩家在 Steam 排行榜上競爭在內等許多功能。

Steamworks API 索引中分類並記錄了 API 所有支援的介面、函式、回呼和型別。

在 Steam 上發行產品並不需要整合 Steamworks API,但我們強烈建議將其整合在內,如此才能做出多種 Steam 使用者預期會出現的互動。

初步指南

備註: Steamworks API 正式支援 C++,以及 Microsoft Windows 上的 Microsoft Visual Studio 2008 以上版本、macOS 與 SteamOS / Linux 上的 GCC 4.6 及 Clang 3.0 以上版本。 若使用第三方的引擎或 C++ 以外的程式語言,請先查閱對商用引擎和 C++ 以外語言的支援了解您選用的引擎或語言是否有更具體的初步設定說明。 部分情況下,或許能省略掉以下許多步驟。

  • 如果尚未進行此步驟,請下載 Steamworks SDK 並解壓縮
  • 將 Steamworks API 標頭資料夾 public/steam 複製到應用程式來源樹中的適當位置
  • 將 redistributable_bin 中相關的可轉散發檔案複製到專案資料夾中的適當位置
    • Windows
      您必須將 steam_api[64].lib 與您的 Visual Studio 專案連結, 連結標的為主要執行檔或使用 Steam 的模組皆可。 如此一來才能存取 steam_api [64] .dll 中透過 Steamworks API 標頭公開提供的功能。 額外閱讀資料:將可執行檔連結至 DLL

      您也必須將 steam_api[64].dll 放入執行目錄(位於程式執行檔旁或在 DLL 搜尋路徑中)一同釋出
    • macOS
      libsteam_api.dylib 提供 x64 和 arm64 兩種版本的 Steam API。 您必須在 Xcode 專案中包含此連結,並將其增添至 Build Phase(組建階段)中 Copy Files(複製檔案)下 Destination (目標位址)內的「Executables」(執行檔),以便複製到應用程式組合包中。 詳情請見 Xcode 文獻。
    • Linux
      libsteam_api.so 您必須將其與執行檔連結,並一同釋出

初始化和關閉

SteamAPI_Init

在專案中完成對 Steamworks API 的初步設定後,即可呼叫 SteamAPI_Init 函式來初始化 API 並開始使用。 這將進行全域狀態的設定,並產生介面指標,透過與介面名稱相同的全域函式存取。 必須先呼叫該函式並收到傳回的成功,才能存取 Steamworks 介面!

如果 Steamworks 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 偵錯,了解 Steamworks API 的各種偵錯方法。

SteamAPI_RestartAppIfNecessary

SteamAPI_RestartAppIfNecessary 會檢查您的執行檔是否透過 Steam 啟動,若不是則重新透過 Steam 啟動。

這並非必要項目,但強烈建議使用,因為如果使用者直接啟動執行檔,與應用程式關聯的 Steam 脈絡(包括 App ID)將不會受到設定。 若發生這種情況,SteamAPI_Init 將失敗,而無法使用 Steamworks API。
若選擇使用此項目,則應置於 SteamAPI_Init 之前,為您第一個呼叫的 Steamworks 函式。

如果回傳 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 使用完畢後,應呼叫 steam_api:: SteamAPI_Shutdown 以釋放您的應用程式在 Steam 內部使用的資源。 您應該盡可能在程序關閉期間呼叫此函式。

這不會將 Steam 內嵌介面從您的遊戲解除掛勾,因為您的彩現 API 不見得已停止使用它。

Steamworks 介面

Steamworks API 由多個介面組成,每個介面皆公開提供特定有限數量的功能。

成功初始化 Steamworks 之後,您就可以透過其全域函式存取介面。 函式一定會與介面名稱相符。 也就是說,您可以透過 SteamApps() 存取 ISteamApps,或透過 SteamFriends() 存取 ISteamFriends。

介面能用來進行呼叫,如下所示:
// 取得目前使用者的 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\n" ); else printf( "Steam overlay now inactive\n" ); }

ISteamFriends::GameOverlayActivated_t 一個常見且建議的使用情況為在開啟內嵌介面時暫停遊戲。

呼叫結果

許多 Steamworks 方法使用呼叫結果來傳回異步的函式呼叫結果,而非回呼。 回呼和呼叫結果的差異在於回呼會廣播給所有的監聽器,而呼叫結果只會針對特定的監聽器。 與回呼類似的是,您的遊戲需要呼叫 SteamAPI_RunCallbacks 才能將呼叫結果發派至其監聽器。

您可以檢查傳回的值來辨識提供呼叫結果的函式;如果傳回 steamapicall_t 並具有 CALL_RESULT () 屬性,則必須進行註冊才能接收呼叫結果。 請注意,註冊到 CCallResult 的回呼只會針對其設置的最新 steam_api:: 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\n" ); SteamAPICall_t hSteamAPICall = SteamUserStats()->GetNumberOfCurrentPlayers(); m_NumberOfCurrentPlayersCallResult.Set( hSteamAPICall, this, &CGameManager::OnGetNumberOfCurrentPlayers ); } // 於呼叫 SteamAPI_RunCallbacks() 之後,在異步接收到 SteamUserStats()->GetNumberOfCurrentPlayers() 的回傳時進行呼叫 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 ); }

備註: 若無法使用 CCallResult 系統,那麼或許可以使用 ISteamUtils::IsAPICallCompleted、ISteamUtils::GetAPICallResult 和 ISteamUtils::GetAPICallFailureReason 來追蹤呼叫結果的狀態。

手動回呼發派

用於註冊回呼的類別和巨集在 C ++ 程式碼中使用起來相當方便, 但還有一個較低層級的機制在處理回呼。 此機制的運行方式更類似於 Windows 的事件迴圈, 即為在迴圈中取得下一個可用的回呼,然後用您希望的任何機制進行發派,而非使用單一函式將所有回呼和呼叫結果發派給作用中的監聽器。 手動發派模式對於將 Steamworks SDK 公開提供給 C++ 以外語言的繫結層特別有用。 更多資訊請見 steam_api.h 中的 SteamAPI_ManualDispatch_Init()。

Steam 遊戲伺服器

Steamworks API 支援遊戲伺服器及一般用戶端的運作。 在 Steamworks API 的術語中,遊戲伺服器是系統中供一般使用者連線來進行多人遊戲的一個實體。 可以是透過網路連線到遠端的遊戲伺服器,或從區域網路連線至與用戶端處於相同處理程序的遊戲伺服器。 遊戲伺服器有自己的一套 API 函式,以及可供其他使用者參照的獨特 Steam ID。

要使用 Steam 遊戲伺服器 API,您必須首先納入 steam_gameserver.h,而非 steam_api.h。

遊戲伺服器的初始化和使用與一般的 API 很相似:

初始化遊戲伺服器後,便可以存取兩個遊戲伺服器專用的介面:ISteamGameServer 和 ISteamGameServerStats。

另也可以從遊戲伺服器存取以下一般介面:
  • ISteamClient,透過全域介面 SteamGameServerClient() 存取
  • ISteamUtils,透過全域介面 SteamGameServerUtils() 存取
  • ISteamNetworking,透過全域介面 SteamGameServerNetworking() 存取
  • ISteamHTTP,透過全域介面 SteamGameServerHTTP() 存取
  • ISteamUGC,透過全域介面 SteamGameServerUGC() 存取
  • ISteamApps,透過全域介面 SteamGameServerApps() 存取

若使用的是專用遊戲伺服器(沒有用戶端元件),則只需初始化遊戲伺服器 API,無需初始化普通使用者的 API。

架構完整的遊戲伺服器使用範例請見 Steamworks API 範例應用程式(SpaceWar)。

與遊戲不同,專用伺服器通常會在沒有安裝 Steam 用戶端的環境中執行,來提供最新的 Steamworks 二進位檔案。 為了讓專用伺服器擁有最新的 Steam 二進位檔案,您需要將專用伺服器的可轉散發檔案包含在您的應用程式中。 請登入 partner.steamgames.com 並前往應用程式的技術設定, 查看「安裝 / 可轉散發檔案」並勾選下方的「Dedicated Server Redistributables」(專用伺服器可轉散發檔案)。

對商用引擎和 C++ 以外語言的支援

若您使用商用的遊戲引擎或 C/C++ 以外的語言,最好先了解 Steamworks API 對它們支援的程度。
部分引擎自己便有提供內建支援,有些則可能需要第三方的解決方案。

如果您的引擎並不提供原生支援,則可以使用 Steam Web API 來存取 Steam 支援的許多功能。

無論 Steamworks API 是如何實作於您的引擎中,您都需要最新版本的 Steamworks SDK 才能將應用程式上傳至 Steam。

備註: 如果您在 Steam 上推出的軟體部分能透過限制性的開源授權取得,那麼請見在 Steam 上分發開源應用程式。

以下為一些經常用於在 Steam 上推出遊戲的引擎,以及有關如何進行 Steamworks SDK 初步設定的相關資料。

備註: Valve 不為以下引擎或第三方解決方案提供任何形式的背書或支持。 此列表純粹按名稱排序,並不完整,也僅作為入門指南之用。 只有包含原生支援,或具有符合指南的第三方解決方案的引擎,才會被列於此處。 第三方解決方案僅在其版本於合理範圍內保持與 Steamworks SDK 的更新相容、均有允許免費使用的授權(請見:在 Steam 上分發開源應用程式),並在 Steamworks 討論區中有相關討論串時才會列出。 我們建議您諮詢社群,了解哪個選項最適合您的特定設置情況。

引擎:

引擎原生支援?資訊
CRYENGINE ✔️
GameMaker Studio 2 ✔️ 配合 Steamworks SDK 使用 GameMaker: Studio
Godot ❌ 第三方:GodotSteam - Steamworks 開發者討論區客服討論串
Haxe ❌ 第三方:SteamWrap - Steamworks 開發者討論區客服討論串
Leadwerks Game Engine ✔️ Leadwerks API 參考檔案 › Steamworks
RPG Maker MV ❌ 第三方:Greenworks - Steamworks 開發者討論區客服討論串
Source 2013 ✔️ 發佈 Source 引擎遊戲 / 模組
Unity ❌ 第三方:Facepunch.Steamworks - Steamworks 開發者討論區客服討論串
第三方:http://steamworks.github.io - Steamworks 開發者討論區客服討論串
Unreal Engine 4 ✔️ Steam 線上子系統
Visionaire Studio ✔️ 在 Steam 上發佈

語言:

用於繫結其它語言的平面介面

SDK 有一些功能,能用來建立連接其它語言的繫結層。

  • steam_api_flat.h 宣告一組「平面」函式,能以相同於 SDK 中的介面函式的功能來使用。 這並非純粹的 C 語言程式碼,但連結與呼叫相等的函式時是以純 C 語言進行,因此容易與其它語言互通。 這些函式由 steam_api[64][.dll/.so/dylib] 匯出
  • steam_api.json 描述 SDK 中(幾乎所有)的介面、型別和函式。 用途是供自動化程序用來產生繫結層。 我們希望這樣能讓 95% 的工作內容自動化,但仍然有一些特殊情況需要手動處理。 特別是 CSteamID 和 CGameID 可能需要您的繫結層進行特殊處理才能提高效率

技術細節

Steam 使用多種技術來將功能公開給您的應用程式使用。 完全了解 Steamworks API 的運作方式並非至關重要,但其原理相當簡單,而且您在制訂遊戲的編寫計畫時若也考量到與 Steam 的整合,即可派上用場。

連結至 steam_api[64][.dll/.so/dylib] 後,便可以存取以 S_API 巨集為前綴、由 steam_api.h 和 steam_gameserver.h 公開提供的少量 C 語言函式。 steam_api 本身相當小,僅公開提供用於初始化和關閉 Steamworks API 的基礎功能。

Steamworks API 初始化時,它會找到正在執行的 Steam 用戶端處理程序,並從其路徑載入 steamclient.dll。 steamclient.dll 相當於是 Steam 用戶端的核心引擎, 包含並維護著執行 Steam 必要的資訊。 Steam 用戶端 UI 使用與此處公開使用類似的一組函式來存取 steamclient.dll 提供的資料。 由於資料存在於 Steam 處理程序中,所有 Steam API 呼叫將透明地被結集並透過 RPC/IPC 機制傳送 (跨處理程序的管道,ISteamClient::HSteamPipe)。

從 steamclient.dll 而來的 Steam 處理程序會與 Steam 後端伺服器持續保持連線。 所有的驗證、遊戲配對、好友列表、VAC 通訊都會透過它的連線進行。 如果使用者的網路出現問題,或連線的 Steam 伺服器受到更新,則連線可能中斷。 連線中斷或重新連線時,回呼將發送給所有正在執行的應用程式。 Steam 用戶端會自動嘗試重新連線,以正在執行應用程式的用戶端為優先,因此重新連線的時間一般不會超過 10 秒,但在一些罕見情況下,最多可能長達 5 分鐘。

Steamworks API 透過類似 COM 的機制進行版本管理,而字串名稱和介面版本會被傳送到 steamclient.dll,然後將正確版本的介面傳回給呼叫者。 steamclient.dll 包含一組適用於所有發行版本介面的轉接器,會以適用於最新介面的方式重新導向至或重新詮釋舊式的呼叫。 轉接器位於 Steam 用戶端內,因此如果出現任何問題,可以輕鬆進行更新。