最近在搞 Switshot 新版本,同時在弄 Steam Deck 上的伴侶 app 需要提交到 Steamworks,加上最近 Gitea 也推出了 CI/CD 功能,想著乾脆就把能上 CI/CD 的東西全部上一遍好了。但比較可惜的是,中文互聯網上好像對通過 CI/CD 管線提交 Steamworks 的相關問題沒有太多記錄,加上我的開發流程比較 tricky,於是打算先記錄下來,希望可以幫到別人(順便傳教 CI/CD)。
需要注意的是,這篇文章比較注重通過 CI/CD 管線將編譯好的工件提交到 Steamworks 的配置的說明。如果你想了解你開發的遊戲如何通過 CI/CD 編譯,可以搜搜網上其他的資料。
基礎概念 ABC
如果你已經對我上面說的許多名詞有了基礎概念,那麼請直接跳過這一段;否則,這裡是一些簡單的解答。
CI/CD:「持續集成與持續交付(Continuous Integration and Continuous Delivery)」的簡稱。你可以將它視作一種高級的自動化:假設你的遊戲發版需要經過編譯、檢查、測試、分發等一系列流程,你可以將它們集成為一組自動化動作。當你的開發工作完成到一定水平、觸發這個自動化動作之後,機器會自動完成你預設的動作,開始進行編譯和檢查;人工完成測試確定可以發佈之後,還能通過自動化提交至商店進行版本交付。
工件(Artifacts):又譯「產物」,即 CI/CD 流程中產生出來的產品/記錄/文件等等等等。編譯好的軟件包也在其列。
Steamworks:類似於 App Store Connect,專為開發者設置的商店後臺。
Gitea/GitHub Actions:Gitea 是一款自部署的、基於 git 的代碼託管服務器;而 GitHub Actions 是一個代碼自動化工具,可以在代碼提交的時候自動觸發一系列的操作,進而幫助開發者完成 CI/CD 工作。Gitea 1.19.0 版本開始新增與 GitHub Actions 對標的 Gitea Actions 功能,不僅功能相近,同時也可以(幾乎不經修改地)使用 GitHub Actions 的配置文件。最大的區別在於,Gitea Actions 要求自己部署一個運行器(runner)用於編譯或執行其他自動化流程,而 GitHub Actions 提供了許多免費的運行器。由於我的工程的 CI/CD 流程託管在 Gitea,因此會與你在 GitHub 使用的時候會有些出入,但二者的操作幾乎可以等價。
開始編寫流程文件
想讓機器自己學會編譯、交付你的代碼,首先肯定得告訴它該怎麼做。這就是 Actions 流程文件的目的。
首先,來創建第一個流程文件。請在你的代碼根目錄創建一個 .gitea 或 .github 文件夾,然後在新文件夾中再創建 workflows 文件夾。創建一個 YAML 文件,我在這裡就給它起名為 compiling.yaml(編譯.yaml)。
然後,你可以把 GitHub 的官方示例流程代碼,複製到這個新的文件中。
這個配置文件其實不難理解。簡單來說,首先定義這個流程名字是「GitHub Actions Demo」,然後說明中插入你的 GitHub 用戶名,代表這個流程是你寫的,然後設置只要 GitHub 收到所有分支中的代碼推送就觸發這個自動化。接著,創建一個名為「Explore-GitHub-Actions」的工作(job),並在安裝了 Ubuntu 的操作系統的執行器上執行一些操作,包括打印歡迎消息、通過變量輸出一些上下文信息(操作系統、觸發流程的分支)、拉取代碼到當前執行器中、列出目前代碼中的所有文件,等等。
當你提交更改並推送到遠程倉庫之後,你的 GitHub/Gitea 倉庫頁面的 Actions 標籤右邊應該會多出來一個「1」的徽標,代表正在開始自動化流程。你可以隨時在 Actions 頁面檢查自動化執行歷史、正在執行的自動化的進展。
當然,我這個流程是已經改過、用於生產的流程。
編寫自動化流程就是這麼簡單:一個 name 參數,用於備註給人看這個流程是在做什麼;一個 run 參數,代表執行器在這一步應該做什麼。假設你在本地需要使用 make build 終端指令來要求電腦編譯你的代碼,只要你在自動化工作中檢出(check out)了你的代碼,你就可以為 make build 指令添加一個 job steps,並在 run 參數中添加 make build,指示自動化需要執行這個指令,在這裡就是開始編譯的意思。
你可能已經注意到,在編譯步驟之前的步驟,還有一個 uses 的參數。它的意思是使用別人已經編寫好的 Action 的操作。在這裡是將你的代碼檢出(拉取)到執行器的執行環境中。
編譯、打包、留檔
接下來開始實際動手編寫自動化。首先,我需要做的事情是,下載並應用 Node.js 環境,然後檢出代碼。完成後,安裝依賴並開始打包編譯。此時我的 CI/CD 自動化流程是這樣:
由於我需要交由 CI/CD 自動化的產品並不是一款遊戲,而是一款(基於 Electron 的)應用程序,因此直接拿走我的配置文件應該是沒辦法應用到各位的遊戲項目中的(GitHub Marketplace 有許多針對編譯打包遊戲引擎的 Actions 可供選擇);但為了不讓各位太過迷惑,以上信息重點用作背景信息。接下來才是重點。
CI/CD 流程啟動 Electron 打包器後會將我的打包文件放在 dist 目錄下。同樣在 dist 目錄下的還有打包日誌文件 builder-debug.yml,以及被統一放在 linux-unpacked 的針對 Linux 系統的軟件包的一些其他產物。我首先將它們統一打包為 zip,然後上傳到 Cloudflare R2 作為存檔,以便我下載編譯後產物或是檢查歷史編譯文件。
於是我的自動化文件擴充成了這樣。
注意,在這裡我們用到了變量,即使用美金符號和兩個花括號包裹的東西。
首先是 secret 前綴的變量,它代表的是秘密變量/密鑰變量,可以在項目設置中進行人為設定:
- Gitea:進入項目後點擊頁面標籤頁欄右側的「設置」,左側目錄點擊「Actions」-「密鑰」。
- GitHub:進入項目後點擊頁面標籤頁欄的「Settings」,左側目錄點擊「Secrets and variables」-「Actions」。
在裡面新建好你設置的變量之後,在流程中就可以用 secret.YOUR_SECRET_NAME 的方式來訪問了。秘密變量一旦新建,你和你的同事都不能再看見,只能修改,即使將它在 CI/CD 打印出來,也只會顯示三個星號。
然後是 gitea 前綴的變量。這些變量代表是執行環境上下文,包括運行任務的編號等等。這些變量在 GitHub 和 Gitea 中都通用,只是前綴有所差異(即如果你使用 GitHub Actions,你應該使用 github 前綴)。這裡是所有可用的變量列表。
最終,這個步驟的效果是:將所有放置在 dist 文件夾中的工件打包成 dist.zip,並提供 Cloudflare R2 的密鑰,要求執行器在存儲空間中新建以任務編號為名的文件夾,並上傳至這個新文件夾。當然,你不一定也要用 Cloudflare R2,AWS S3、阿里雲 OSS 和騰訊雲 COS 等兼容 S3 接口的存儲服務都有對應的 Actions,在 GitHub Marketplace 中稍加搜索就能找到。
將二進制提交至 Steamworks
接下來,就需要考慮提交軟件包至 Steamworks 的事情了。
首先,經過一番研究,我個人推薦專門註冊一個用於 CI/CD 流程的 Steam 小號。前往 partner.steamgames.com 登錄,選擇「用戶與權限」-「管理用戶」,你會在左側看到「邀請用戶」的按鈕。點擊之後會有一個表單,郵箱地址需要填寫沒有註冊過 Steam 的郵箱地址,名字可以做一下簡單的備註。右側的權限列表勾選「編輯應用元數據」、「在 Steam 上發佈更改」兩個。
接下來,這個新的郵箱會收到一封邀請郵件。通過邀請郵件中的鏈接註冊一個新的小號並接受邀請,然後主號再確認一下,小號就可以用來作為 CI/CD 提交流程工具了。
然後,在自己的電腦上安裝一下 SteamCMD 工具(看這篇文章的應該沒有人沒裝過吧?),再使用命令行的方式來登錄一次,這次登錄會提示需要 SteamGuard 驗證碼——別慌,看看郵箱。
登錄成功之後需要找到配置文件。macOS 上,配置文件存放在下面這個位置。
將這個文件的內容轉換為 Base64,然後打開 Gitea 或 GitHub 的秘密變量配置頁面,添加以下秘密變量:
- STEAM_CONFIG_VDF,將上面的步驟的 Base64 粘貼進來
- STEAM_USERNAME,小號的 Steam 用戶名
如果你在執行這些操作的電腦上有登錄過桌面版 Steam,個人建議你在桌面版 Steam 註銷後重新登錄一下,因為這個配置文件裡可能還有你主號的登錄信息(這個操作不會影響小號)。
下面就是對 CI/CD 編譯後的文件夾做點小手術的時候了:
- 清理不需要的文件
- 修改打包好的二進制文件的名字(以適應 Steam 中「啟動選項」的要求)
- 將 dist 文件夾下的不同工件,按操作系統整理到不同的目錄中
由於我只需要針對 Steam OS 進行開發,因此只需要將二進制包的名字改成統一的名稱,然後將它塞到 dist/SteamOSBinary 文件夾下即可。注意,即使你的遊戲或軟件只面向一個平臺,你也需要多套一個文件夾。
萬事俱備,終於可以要求自動化流程將 depot 交付到 Steamworks 了:
複製我的流程的時候請注意把 appId 參數改成你的 Steamworks 應用的 appId,將 rootPath 參數設置為你的二進制輸出主目錄,主目錄下存放不同操作系統的二進制的目錄填寫到 depot[x]Path 參數中。其他更多參數可以看官方的文檔。
另外,我額外做了一個 if 參數,代表只有當主分支接受了提交之後才執行這一操作(以避免意外地將用於內部測試的二進制交付到 Steam。)我在 buildDescription 中備註了當前工作的序號,這樣在 Steamworks 後臺就可以通過備註輕鬆查找到是由哪一次自動化工作生成的二進制版本。
編寫好後,將你的代碼推送到倉庫中,然後等待大約十分鐘到一小時不等(取決於你的遊戲或者軟件有多大)。接下來,看到所有流程步驟亮起綠燈之後,就可以在 Steamworks 後臺找到剛才由 CI/CD 自動化交付的軟件包了!
如果你需要我的完整的 Actions 配置,可以從這裡找到。限於篇幅和經驗不足的原因,只能為大家詳細講解在 Linux 環境下的配置方法,但其他操作系統下的配置方法也大差不差,舉一反三一下即可通用。也希望這篇文章可以作為拋磚引玉,讓更多大佬再來講解有關其他平臺下自動化編譯、打包、交付遊戲二進制的方法。