文章目录
- 一、前言
- 二、插件下载安装
- 三、快速入门
-
- 1、启动steam
- [2、添加SteamManager 脚本](#2、添加SteamManager 脚本)
- [3、获取 Steam 用户的显示名称](#3、获取 Steam 用户的显示名称)
- [4、Steam 回调](#4、Steam 回调)
- [5、Steam 调用结果](#5、Steam 调用结果)
- 四、SteamManager
-
- [1、SteamManager 脚本的工作原理](#1、SteamManager 脚本的工作原理)
- 2、样板代码
- [3、持久化 GameObject/单例逻辑](#3、持久化 GameObject/单例逻辑)
- 4、完整性检查
- 5、SteamAPI.RestartAppIfNecessary
- 6、SteamAPI.Init
- 7、SteamAPIWarningMessageHook
- 8、SteamAPI.RunCallbacks
- 9、SteamAPI.Shutdown
- 五、对接自己的应用
- 六、设置Steamwork商店Depot
-
- 1、找到所有应用程序
- 2、找到你在Steam上花100美元申请的AppID的应用程序,点击Steamworks管理员
- 3、找到SteamPipe中的Depot
- 4、添加新的depot,因为我这里已经添加过了因此有一个depot
- [5、添加depot的名称和选中depotID,这个depotid默认是比appid+1的,比如你的appid是480,depotid就应该是481,然后点击保存 ,这里的depot就设置完成了。](#5、添加depot的名称和选中depotID,这个depotid默认是比appid+1的,比如你的appid是480,depotid就应该是481,然后点击保存 ,这里的depot就设置完成了。)
- 七、上传游戏版本
- 八、Steamwork商店配置发布
- 参考
- 专栏推荐
- 完结
一、前言
Steamworks.NET 是 Valve 的 Steamworks API 的 C# 封装,可用于 Unity 或基于 C# 的应用程序。
Steamworks.NET 的设计尽可能接近原始 C++ API,因此 Valve 提供的文档主要涵盖了 Steamworks.NET 的使用。可以在 Steamworks.NET 之上轻松实现一些便捷功能和 C# 特有的用法。
Steamworks.NET 完全支持 Windows(32 位和 64 位)、OSX 和 Linux。目前基于 Steamworks SDK 1.63 进行构建。
开发文档:https://steamworks.github.io/
二、插件下载安装
https://github.com/rlabrecque/Steamworks.NET/releases/tag/2025.162.1

示例:https://github.com/rlabrecque/Steamworks.NET-Example
三、快速入门
1、启动steam
注意:后续测试都要记得要先启动steam再运行,不然可能会报错:[Steamworks.NET] SteamAPI_Init() failed. Refer to Valve's documentation or the comment above this line for more information.UnityEngine.Debug:LogError (object,UnityEngine.Object) SteamManager:Awake () (at Assets/Scripts/Steamworks.NET/SteamManager.cs:124)
安装steam地址:https://store.steampowered.com/about/
2、添加SteamManager 脚本
SteamManager 脚本为您的项目提供了理想的起点,我强烈建议使用它,这将大大减少上手所需的时间。
只需在第一个场景中创建一个新的空 GameObject 并将 SteamManager 脚本附加到它上面。

现在,当您启动游戏时,Steam 应该会显示您正处于游戏中。

3、获取 Steam 用户的显示名称
接下来,在确认基本功能工作后,我建议尝试一个简单的 SteamAPI 方法调用。
创建一个名为 SteamScript.cs 的新脚本:
csharp
using Steamworks;
using UnityEngine;
public class SteamScript : MonoBehaviour
{
void Start() {
if(SteamManager.Initialized) {
// 获取 Steam 用户的显示名称
string name = SteamFriends.GetPersonaName();
Debug.Log(name);
}
}
}
请注意:在调用任何 Steamworks 函数之前,我们必须始终通过检查
SteamManager.Initialized来确保Steam 已初始化。
现在只需将此脚本添加到一个 GameObject 上并尝试运行!应该会打印出你的steam名字


如果遇到任何问题,请查看 常见问题解答 ,看看是否已有解决方案!
4、Steam 回调
回调是 Steamworks 最重要的方面,它们允许您从 Steam 异步获取数据,而不会锁定您的游戏。
您很可能希望使用的一个回调是 GameOverlayActivated_t。顾名思义,每当 Steam 覆盖层被激活或停用时,它都会向您发送一个回调。
我们将继续使用之前的脚本来演示如何使用它。
要在 Steamworks.NET 中使用回调,首先必须在类作用域内声明一个受保护的 Callback<> 作为成员变量。
csharp
public class SteamScript : MonoBehaviour {
protected Callback<GameOverlayActivated_t> m_GameOverlayActivated;
}
然后,我们通过调用 Callback<>.Create() 来创建回调,并将其分配给 m_GameOverlayActivated。这可以防止回调被垃圾回收。
我们通常在 OnEnable 中执行此操作,因为这允许我们在 Unity 重新加载程序集后重新创建回调。
csharp
public class SteamScript : MonoBehaviour {
protected Callback<GameOverlayActivated_t> m_GameOverlayActivated;
private void OnEnable() {
if (SteamManager.Initialized) {
m_GameOverlayActivated = Callback<GameOverlayActivated_t>.Create(OnGameOverlayActivated);
}
}
}
最后一块拼图是 OnGameOverlayActivated 函数。
csharp
using Steamworks;
using UnityEngine;
public class SteamScript : MonoBehaviour {
protected Callback<GameOverlayActivated_t> m_GameOverlayActivated;
private void OnEnable() {
if (SteamManager.Initialized) {
m_GameOverlayActivated = Callback<GameOverlayActivated_t>.Create(OnGameOverlayActivated);
}
}
private void OnGameOverlayActivated(GameOverlayActivated_t pCallback) {
if(pCallback.m_bActive != 0) {
Debug.Log("Steam 覆盖层已被激活");
}
else {
Debug.Log("Steam 覆盖层已被关闭");
}
}
}
搞定!
GameOverlayActivated 回调一个流行且推荐的用例是:当覆盖层打开时暂停游戏。比如打开背包,打开设置面板等等。
5、Steam 调用结果
调用结果与回调非常相似,但它们是特定函数调用的异步结果,而不是像回调那样的全局事件接收器。
您可以通过检查函数的返回值来识别提供调用结果的函数。如果它返回 SteamAPICall_t,那么您必须设置一个调用结果。
在 Steamworks.NET 中,设置调用结果与回调几乎相同!
比如我们获取正在玩您游戏的玩家数量
csharp
using Steamworks;
using UnityEngine;
public class SteamScript : MonoBehaviour {
private CallResult<NumberOfCurrentPlayers_t> m_NumberOfCurrentPlayers;
//在 OnEnable 中执行此操作,以便每次 Unity 重新加载程序集时都会重新创建它。
private void OnEnable() {
if (SteamManager.Initialized) {
//创建调用结果
m_NumberOfCurrentPlayers = CallResult<NumberOfCurrentPlayers_t>.Create(OnNumberOfCurrentPlayers);
}
}
private void Update() {
// 我们需要调用一个返回调用结果的函数,然后将其返回的 SteamAPICall_t 句柄与我们的调用结果关联起来。
if(Input.GetKeyDown(KeyCode.Space)) {
SteamAPICall_t handle = SteamUserStats.GetNumberOfCurrentPlayers();
m_NumberOfCurrentPlayers.Set(handle);
Debug.Log("已调用 GetNumberOfCurrentPlayers()");
}
}
//创建异步调用的函数,调用结果的函数签名与回调略有不同,增加了 bool bIOFailure 参数。
private void OnNumberOfCurrentPlayers(NumberOfCurrentPlayers_t pCallback, bool bIOFailure) {
if (pCallback.m_bSuccess != 1 || bIOFailure) {
Debug.Log("检索玩家数量时出错。");
}
else {
Debug.Log("正在玩您游戏的玩家数量: " + pCallback.m_cPlayers);
}
}
}
运行,按空格,查看结果

对于回调和调用结果,您都必须定期调用 SteamAPI.RunCallbacks。当然这在 SteamManager 中已经帮你完成。
现在您已经熟悉了 Steamworks 的基础构建模块,请查看 Steamworks.NET 示例应用程序,了解 Steamworks 统计和成就的工业级实现!
Steamworks.NET-Test 项目对于了解如何在 Steamworks.NET 中完成各种任务非常有价值。
还有一个 Steamworks.NET-GameServerTest 项目可用,它实现了 Steamworks 游戏服务器接口的一些基本功能。
四、SteamManager
1、SteamManager 脚本的工作原理
SteamManager 脚本是我们认为的 Steamworks "用户模式"端。它提供了一些基本逻辑来设置和维护与 Steam 的连接,并为您提供了一个良好的起点以供构建。
您很可能需要自行修改 SteamManager 脚本,了解其工作原理是全面掌握 Steamworks 的重要一步。
或者,如果您已经拥有平台抽象层,可以编写自己的实现。
您可以在 GitHub 上找到最新版本的 SteamManager 脚本:https://github.com/rlabrecque/Steamworks.NET-SteamManager/blob/master/SteamManager.cs
请注意:如果不使用类似 SteamManager 的脚本,Steamworks.NET 将完全无法工作。
2、样板代码
以下所有代码都包装在一个 MonoBehavior 类中,以便可以添加到 GameObject 上。
csharp
using UnityEngine;
using System.Collections;
using Steamworks;
class SteamManager : MonoBehaviour {
}
3、持久化 GameObject/单例逻辑
SteamManager 脚本依赖于创建一次并在整个游戏过程中持续存在。这涉及到一些相当复杂的逻辑来与 Unity 的 GameObject 系统集成。
我们使用"自创建持久单例"模式来实现这一点。
通过此模式,您可以从游戏中的任何场景使用 SteamManager,而无需在每个场景中手动放置 SteamManager GameObject。与往常一样,请避免在其他脚本的 Awake() 或 OnDestroy() 中与 SteamManager 交互,因为执行顺序无法保证。
如果您的游戏中已经有维护全局状态的方法,您可能希望用您自己的方法替换此逻辑,以确保以正确的顺序设置。
csharp
private static SteamManager s_instance;
private static SteamManager Instance {
get {
return s_instance ?? new GameObject("SteamManager").AddComponent<SteamManager>();
}
}
private void Awake() {
if (s_instance != null) {
Destroy(gameObject);
return;
}
s_instance = this;
DontDestroyOnLoad(gameObject);
}
private void OnEnable() {
if (s_instance == null) {
s_instance = this;
}
}
private void OnDestroy() {
if (s_instance != this) {
return;
}
s_instance = null;
}
4、完整性检查
Steamworks.NET 提供了几个非必需的完整性检查,以确保正确使用 Steamworks.NET。
Packsize.Test() 确保 Steamworks.NET 在正确的平台下运行。在 Unity 正常操作下,这永远不会返回 false。
DllCheck.Test() 检查确保 Steamworks 可再发行二进制文件版本正确。这在您升级 Steamworks.NET 时特别有用,尤其是在不使用 Steamworks.NET 编辑器脚本的情况下。使用错误的 steam_api.dll 运行 Steamworks.NET 可能会导致问题。(当前仅检查 steam_api[64].dll)
csharp
if (!Packsize.Test()) {
Debug.LogError("[Steamworks.NET] Packsize 测试返回 false,此平台上正在运行错误版本的 Steamworks.NET。", this);
}
if (!DllCheck.Test()) {
Debug.LogError("[Steamworks.NET] DllCheck 测试返回 false,一个或多个 Steamworks 二进制文件版本错误。", this);
}
5、SteamAPI.RestartAppIfNecessary
脚本调用的第一个 Steamworks 函数是 SteamAPI.RestartAppIfNecessary((AppId)480)。请将 480 替换为您自己的 AppId。
SteamAPI.RestartAppIfNecessary() 检查 Steam 客户端是否正在运行,如果没有则启动它。
如果返回 true,则会在需要时启动 Steam 客户端并通过它重新启动您的游戏,然后您应尽快手动关闭应用程序。这实际上是运行 steam://run/[AppId],因此可能不会重新启动调用它的确切可执行文件。
如果返回 false,则表示您的游戏是由 Steam 客户端启动的,正常继续执行。
如果当前工作目录中存在 steam_appid.txt 文件,则 SteamAPI_RestartAppIfNecessary() 将返回 false。这允许您进行开发而无需每次都通过 Steam 重新启动。
由于这是调用的第一个 Steamworks 函数,因此是确保 steam_api.dll 确实可以加载的理想位置。这是通过将此函数调用包装在 try..catch 块中以捕获 DllNotFoundException 来实现的。
csharp
private void Awake() {
try {
if (SteamAPI.RestartAppIfNecessary((AppId)480)) {
Application.Quit();
return;
}
}
catch (System.DllNotFoundException e) {
Debug.LogError("[Steamworks.NET] 无法加载 [lib]steam_api.dll/so/dylib。它可能不在正确的位置。有关更多详细信息,请参阅 README。\n" + e, this);
Application.Quit();
return;
}
}
6、SteamAPI.Init
应该调用的第二个 Steamworks 函数是 SteamAPI.Init(),这会启动 SteamAPI,并且必须在调用任何其他 Steamworks 函数之前调用。
如果 SteamAPI.Init() 返回 true,则表示已设置好一切以继续使用 Steamworks.NET。
否则,返回值为 false 由以下三个问题之一引起:
- Steam 客户端未运行。需要运行的 Steam 客户端来提供各种 Steamworks 接口的实现。
- Steam 客户端无法确定游戏的 AppID。确保游戏目录中有
steam_appid.txt。当通过 Steam 下载启动游戏时,这永远不会发生,因为SteamAPI.RestartAppIfNecessary()将通过 Steam 重新启动它。 - 确保您的应用程序在与 Steam 客户端相同的用户上下文(包括管理员权限)下运行。
如果遇到 Init 问题,请尝试在启动前运行 Microsoft 的 DbgView 以获取 Steam 的内部输出。
SteamManager 公开了 Initialized 属性,您可以从其他脚本中使用它来确保在调用任何 Steamworks 函数之前 SteamAPI 已初始化。
csharp
private bool m_bInitialized;
public static bool Initialized {
get {
return Instance.m_bInitialized;
}
}
private void Awake() {
m_bInitialized = SteamAPI.Init();
if (!m_bInitialized) {
Debug.LogError("[Steamworks.NET] SteamAPI_Init() 失败。有关更多信息,请参阅 Valve 的文档或此行上方的注释。", this);
return;
}
}
7、SteamAPIWarningMessageHook
通过使用函数委托调用 SteamClient.SetWarningMessageHook(),我们可以在某些情况下拦截来自 Steam 的警告消息。
请注意,在调用任何 Steamworks 函数之前,我们确保 Steam API 已初始化。
我们在 OnEnable 中调用此函数,以便在 Unity 执行程序集重新加载(例如重新编译脚本时)后重新创建它。
要从 Steam 接收警告消息,您必须在启动参数中使用 -debug_steamapi 启动游戏。
csharp
private SteamAPIWarningMessageHook_t m_SteamAPIWarningMessageHook;
private static void SteamAPIDebugTextHook(int nSeverity, System.Text.StringBuilder pchDebugText) {
Debug.LogWarning(pchDebugText);
}
private void OnEnable() {
if (!m_bInitialized) {
return;
}
if (m_SteamAPIWarningMessageHook == null) {
m_SteamAPIWarningMessageHook = new SteamAPIWarningMessageHook_t(SteamAPIDebugTextHook);
SteamClient.SetWarningMessageHook(m_SteamAPIWarningMessageHook);
}
}
8、SteamAPI.RunCallbacks
要使回调和调用结果系统能够分发事件,必须频繁调用 SteamAPI.RunCallbacks()。调用之间的时间越长,从 Steam API 接收事件或结果的潜在延迟就越大。
如果通过将 Time.timeScale 设置为 0 来暂停游戏,则 Update() 函数将不再运行。您需要考虑替代方案,以确保即使游戏暂停时 SteamAPI.RunCallbacks() 也在运行。协程可能是一个不错的选择。
请注意,在调用任何 Steamworks 函数之前,我们确保 Steam API 已初始化。
csharp
private void Update() {
if (!m_bInitialized) {
return;
}
// 运行 Steam 客户端回调
SteamAPI.RunCallbacks();
}
9、SteamAPI.Shutdown
SteamManager 将进行的最终调用是 SteamAPI.Shutdown(),它会清理 SteamAPI 并让 Steam 知道您正在准备关闭。
使用 OnDestroy,因为这是关闭时最后调用的内容。
由于 SteamManager 应该是持久化的且永远不会被禁用或销毁,我们可以使用 OnDestroy 来关闭 SteamAPI。
csharp
private void OnDestroy() {
if (!m_bInitialized) {
return;
}
SteamAPI.Shutdown();
}
五、对接自己的应用
前面测试你会发现我们都没有设置自己的游戏信息,默认使用的都是480测试appid
要修改成自己的,我们需要
-
找到工程目录中的
steam_appid.txt文件,默认是480,是UnitySpaceWar的id,把480改成你自己的appid(appid在Steamworks 创建应用的时候会分配)

-
找到SteamManager.cs 中的SteamAPI.RestartAppIfNecessary并修改为SteamAPI.RestartAppIfNecessary(new AppId_t(你的appid))

-
保存,
重启unity -
我们可以打印AppID测试一下,看看对不对
csharpusing Steamworks; using UnityEngine; public class SteamScript : MonoBehaviour { void Start() { if (SteamManager.Initialized) { // 获取当前运行的AppID AppId_t currentAppId = SteamUtils.GetAppID(); uint appIdValue = currentAppId.m_AppId; Debug.Log($"当前AppID: {appIdValue}"); } } }
六、设置Steamwork商店Depot
生成分支和Depot到底是啥?咋上传不同语言?可以参考:https://www.bilibili.com/video/BV1xamnYbED6/
简单来说,Depot可以理解为你的游戏不同版本
1、找到所有应用程序

2、找到你在Steam上花100美元申请的AppID的应用程序,点击Steamworks管理员

3、找到SteamPipe中的Depot

4、添加新的depot,因为我这里已经添加过了因此有一个depot

5、添加depot的名称和选中depotID,这个depotid默认是比appid+1的,比如你的appid是480,depotid就应该是481,然后点击保存 ,这里的depot就设置完成了。

七、上传游戏版本
1、下载SteamworkSDK
Steamwork的网址将SDK下载下来,解压到一个最好是英文的目录中

2、\sdk\tools\ContentBuilder\scripts里面默认有4个文件,我们首先打开第一个app_build_1000这个文件
注意文件名要跟着改

3、将自己的游戏打包出来,将整个打包的游戏文件拷贝到sdk/tools/ContentBuilder/content下面
注意查看steam_appid.txt文件,是否填好正确的appid

4、编辑depot_build_1001文件

5、然后就通过SteamPipeGUI工具将自己的exe包进行上传了

出现success,则成功了,如果你是第一次上传会需要邮箱进行验证,等待验证成功即可

如果上传失败,检测刚刚那两个文件的参数是否正确,可以在output文件夹中看到错误输出日志

这里一个坑,Steam有一个命令行工具,run_build这个工具也能成功上传,但是虽然显示成功,但提示是preview,要修改
run_build里面的账号密码为自己的,再双击运行,可以把末尾的quit删掉,命令行界面就不会自动关闭了
八、Steamwork商店配置发布
1、找到Steamworks管理员,然后找到SteamPile,点击生成版本,我们可以看到刚刚上传然后生成的版本,这里已经上传过很多次了,因此你第一次上传的话应该是只有一个的,点击default分支,点击预览更改

2、立即将生成版本设置上线

3、设置通用安装文件夹以及启动项

4、点击发布

5、之前没有上线过的等待审核,审核通过了的界面就是这样的,可以安装自己的游戏测试

参考
https://blog.csdn.net/qq_41884036/article/details/134667607
专栏推荐
完结
好了,我是向宇,博客地址:https://xiangyu.blog.csdn.net,如果学习过程中遇到任何问题,也欢迎你评论私信找我。
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

