Steam 云同步机制解析

文章发布时间:

最后更新时间:

文章总字数:
6.8k

页面浏览: 加载中...

本文重点解析了 Steam Cloud 的两种同步机制(API vs Auto-Cloud)、Root ID 映射原理、Auto-Cloud 存档“删不掉”的底层原因,以及通过 UFS 注入和 API 调用实现的实用解决方案。文中部分结论是基于观察和推断得出的,并不一定百分之百准确,如有错误,欢迎指正。

由于 Steam 官方的 Remote Storage 网页端(客户端路径:帮助 -> Steam 客服 -> 我的账户 -> 您 Steam 帐户的相关数据 -> 上传的内容 - Steam 云)仅支持查看和下载,不提供删除等管理操作,若要深度管理云存档就必须调用底层接口。

然而官方 API 文档对云同步内部机制的描述十分匮乏。在开发 Steam Cloud File Manager(以下简称云存档管理器)的过程中,我深入研究并梳理了 Steam 云的底层同步逻辑。

Steam 云的工作逻辑

Steam 的云同步架构其实分为三层:

  1. 游戏本地存档根目录(Root Path):游戏在本地文件系统中读写存档的基准位置(比如 我的文档/My Games/AppData/Local/ 等)。
  2. Steam Userdata 远程缓存目录Steam/userdata/<UserID>/<AppID>/remote/
  3. Steam 云端:Valve 的服务器。

Steam 客户端主要维护的是Steam Userdata 远程缓存目录云端的一致性。至于存档如何进入这个目录并同步到云端,可以分为两种机制。

两种同步机制

Steam 云主要通过两种方式实现同步。根据 Steamworks 文献库 的描述,这两种方式可以独立使用,也可以同时配置。而游戏具体使用了哪种方式,直接决定了存档同步是由游戏程序主动控制,还是交由 Steam 客户端根据预设规则自动同步。

Steam Cloud API (ISteamRemoteStorage)

游戏代码直接调用 Steam 提供的 ISteamRemoteStorage 接口来管理云端文件。文件的读写、删除操作都通过 API 完成,而不是直接操作文件系统。它的特点是相对可控,开发者明确知道哪些文件需要同步。

官方文档中对关键 API 有明确定义:

FileWrite: 创建一个新文件,将字节写入文件,再关闭文件。 目标文件若已存在,将被覆盖。
FileDelete: 从本地磁盘中删除一个文件,并将该删除传播到云端。

因为是游戏明确发出的删除指令,Steam 会直接执行同步,不会像自动云那样尝试重新下载已经在本地被手动删除的文件。

场景一:写入存档 (FileWrite)

当游戏调用 FileWrite API 时,Steam 优先处理本地操作:立即将数据写入硬盘,并在本地云缓存索引文件 remotecache.vdf(以下简称”云缓存”)中更新元数据(大小、哈希值等),同时将 syncstate(同步状态)标记为待上传。API 立即返回成功,实际的网络上传由 Steam 客户端在后台异步完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
sequenceDiagram
autonumber

box "用户电脑 (Local)"
participant Game as 游戏程序
participant API as Steam 客户端
participant Disk as 本地磁盘
participant VDF as remotecache.vdf
end

box "Valve 服务器 (Remote)"
participant Cloud as Steam Cloud
end

Game->>API: FileWrite(fileName, data)
API->>Disk: 创建/覆盖目标文件
API->>VDF: 更新云缓存,同步状态标记为待上传
API-->>Game: 立即返回成功
Note right of API: 本地写操作完成,不阻塞游戏进程

Note over API, Cloud: 后台异步阶段 (基于 VDF 状态驱动)
API->>VDF: 后台检测到待上传的同步状态
API->>Cloud: 上传文件数据块
Cloud-->>API: 确认上传完成
API->>VDF: 同步状态更新为已同步

场景二:删除存档 (FileDelete)

当游戏调用 FileDelete API 时,Steam 删除本地物理文件,但保留云缓存中的记录并将同步状态标记为待删除——后台同步程序需要依据该记录才能通知服务器删除对应文件。待云端确认删除后,这条记录才被最终清除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
sequenceDiagram
autonumber

box "用户电脑 (Local)"
participant Game as 游戏程序
participant API as Steam 客户端
participant Disk as 本地磁盘
participant VDF as remotecache.vdf
end

box "Valve 服务器 (Remote)"
participant Cloud as Steam Cloud
end

Game->>API: FileDelete(fileName)
API->>Disk: 删除本地物理文件
API->>VDF: 保留记录,同步状态标记为待删除
API-->>Game: 立即返回成功
Note right of API: 本地文件已移除,游戏侧视为删除成功

Note over API, Cloud: 后台异步阶段 (基于 VDF 状态驱动)
API->>VDF: 后台检测到待删除的同步状态
API->>Cloud: 向云端发送永久删除指令
Cloud-->>API: 云端确认删除完成
API->>VDF: 彻底从索引中抹除该文件记录

VDF 的容错校验机制

一个自然的疑问是:如果用户手动删除了云缓存中的记录(而非通过 API),Steam 会怎么处理?

为了验证这一点,我做了一组实验:在游戏关闭后,手动从 VDF 中删除了几条 root=0 的文件记录,然后用云存档管理器短暂连接 API 再断开,触发一次同步。结果发现:被我删掉的 VDF 记录全部自动恢复了。

查阅 Steam 客户端的 cloud_log.txt,可以清晰地看到整个容错校验的过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// ① Steam 触发同步,开始执行 Auto-Cloud 退出检查
[2026-02-25 23:41:50] [AppID 48700] Starting sync (up,AC Exit,)
[2026-02-25 23:41:50] [AppID 48700] AutoCloud complete

// ② ValidateCache 校验:发现本地物理文件的 SHA 与缓存记录不匹配(因为我手动删了 VDF 记录)
[2026-02-25 23:41:50] [AppID 48700] (ValidateCache) File
'.../roottest233/.DS_Store' SHA mismatch with cache - setting local changes

// ③ 检测到本地版本号被重置为 0,与服务器的 40 产生巨大差异,触发完整同步
[2026-02-25 23:41:51] [AppID 48700] Attempting to sync from
local change number '0' to global change number '40' (full)

// ④ 基于校验结果,自动重建 VDF 记录并标记为待上传
[2026-02-25 23:41:51] [AppID 48700] Need to upload file roottest233/.DS_Store
[2026-02-25 23:41:51] [AppID 48700] Successfully synced to ChangeNumber 40

// ⑤ 发起上传批次,版本号从 40 递增到 41
[2026-02-25 23:41:51] [AppID 48700] Upload batch initiated,
ID: 2174408134322121558, ChangeNumber: 41
[2026-02-25 23:41:53] [AppID 48700] Upload OK for file roottest233/.DS_Store
[2026-02-25 23:41:53] [AppID 48700] Upload complete, result OK

// ⑥ 修复后的 VDF 被写回磁盘,校验修复完成
[2026-02-25 23:41:54] [AppID 48700] YldWriteCacheDirectoryToFile
- saved to '.../48700/remotecache.vdf'

这段日志揭示了 Steam 的两层容错机制:

  1. ChangeNumber 版本追踪:每次云端同步都会递增一个全局版本号(ChangeNumber)。手动清空 VDF 后,本地版本号被重置为 0,而服务器端仍为 40。Steam 检测到版本差异,触发了一次 full 完整同步。

  2. ValidateCache 校验:同步过程中,Steam 会逐一比对本地物理文件的 SHA 与缓存记录。由于我只删除了 VDF 记录而没有删除物理文件,校验发现 SHA mismatch with cache(本地文件存在但缓存记录缺失),于是执行 setting local changes——根据本地物理文件重建 VDF 记录,并标记为待上传。

也就是说,remotecache.vdf 虽然是本地核心索引,但并非唯一数据来源。服务器端 ChangeNumber 始终作为校验基准,即使本地 VDF 被篡改或清空,下次同步时 Steam 也会自动修复。这也解释了为什么手动删除 VDF 记录来清除云存档往往无效——服务器端元数据会在下次同步时恢复这些记录。

Steam Auto-Cloud (自动云)

开发者只需在 Steamworks 后台配置好存档文件的路径匹配规则即可。这些配置会被打包进本地的应用配置文件 appinfo.vdf(以下简称”应用配置”)中的 ufs(User File System,用户文件系统,以下简称 UFS)配置节,并下发到玩家的客户端。

Steamworks后台

Steam 客户端根据应用配置中的规则,在游戏启动和退出时对指定目录进行全量扫描,若检测到文件变更则立即在后台自动上传同步。

值得一提的是,在 Auto-Cloud 监控的存档目录下,Steam 会自动放置一个 steam_autocloud.vdf 文件,内容仅包含当前登录账户的 ID:

1
2
3
4
"steam_autocloud.vdf"
{
"accountid" "233333333"
}

该文件用于标识存档目录归属的 Steam 账户,在多账户共用时避免存档混淆,本身不参与同步逻辑。

Steamworks 文献库 中指出,每条自动云路径配置均由 Root(根目录)和 Subdirectory(子目录)组成。Root 是特定操作系统上一组预定义的路径(例如 我的文档/My Games/AppData/Local/),而 Subdirectory 则是相对于 Root 的具体路径。

这种基于预定义根文件夹 (Roots) 的设计至关重要。例如,开发者配置的规则通常是:“监控代表‘我的文档’的 WinMyDocuments (根目录) 下的 My Games/GameName/*.sav (子目录)”。

这意味着 Steam 需要在底层维护一套跨平台的根目录映射表,将抽象的变量名(如 WinMyDocuments)动态映射到当前玩家电脑上真实的落地路径(比如解析为你电脑里的 C:\Users\你的用户名\Documents)。这也正是我这项研究的核心 —— 弄清楚这些抽象的 “Root ID” 到底是如何跟实际文件系统挂钩的(详见下文 “Root ID” 章节)。

关于 UFS 注入与 AppInfo

既然规则存在本地文件中,理论上我们就能修改它。云存档管理器正是利用这一点,通过修改本地的应用配置来注入自定义的监控规则(UFS),从而直接改变 Steam Auto-Cloud 的默认扫描策略,使其客户端能够将任意未经官方设定的本地路径纳入自动同步的检测队列中。

这种基于单方面修改本地缓存的注入方案,在实际运作时面临以下局限与风险:

  1. 必须重启 Steam:Steam 仅在启动时加载配置,修改后需重启客户端生效。
  2. 配置重置:每次重启 Steam 客户端都会向服务器重新拉取请求从而覆盖本地应用配置(详见 logs/appinfo_log.txt)。此时自定义 UFS 配置即会失效。
  3. 强制静默删除:注入规则一旦失效,Steam 会在状态对账时发现大量“不受当前规则管辖”的文件。出于保护逻辑,后台会直接静默删除关联根目录下的这批数据以保持一致性。

为了绕开这个自动删除机制,云存档管理器利用了 Steamworks 里本来就支持的一项配置:跨平台路径映射 (Override)。Steam 设计这个配置是为了在不同操作系统的根目录间同步文件。在注入自定义规则时,只要加上 Override 设置,将目标的系统属性指定为 Linux 等其他平台。这样一来,Steam 依然能正常把文件传到云端;而在客户端重启引发规则重置时,当前处于 Windows 的 Steam 客户端就会判定“这些冗余的云端数据属于 Linux 平台,与我无关”,从而顺理成章地跳过针对本地数据的清理判定。

衍生讨论:软链接(Symlink)挂载方案可行性分析

在研究初期我产生过一个想法:既然 Steam 把 API 云存档存储在 userdata/{UID}/{AppID}/remote/ 目录下,那能不能通过 symlink 把外部文件夹挂载到 remote 里面,让 Steam Cloud 把这些文件也同步上去?

围绕 symlink 与 Steam Cloud 的话题,在不同游戏的社区里其实有过不少相关讨论(例如 r/Grimdawn 的讨论Steam 社区的 Dwarf Fortress 指南 甚至玩家在 r/SteamDeck 上分享的 OpenCloudSaves 第三方同步工具 等)。

这些社区方案普遍有个共性:它们都放弃了让 Steam Cloud 主动同步,转而利用第三方云盘。 其本质是向外链接 (remote → 第三方云盘):用云盘挂载点替换本地的 remote 目录,Steam 写入时会被系统透明重定向完成跨设备同步。

而我最初的设想恰好相反,是 向内挂载 (外部文件夹 → remote 内),指望 Steam Cloud 能自动发现并上传它们。

但实测证明,挂载外部文件进 remote 无效,因为 Steam 不会主动扫描目录,只认 remotecache.vdf 的索引。即便我尝试在工具里自动调 API 注册文件,也面临“每次产生新文件都需手动重注册”的致命缺陷。说白了就是没卵用😅,比直接用云盘还折腾,因此最终我还是放弃了该思路(虽然已经写完了😋),全面转向 UFS 注入方案。

Auto-Cloud 存档难删的原因

主要是因为 Auto-Cloud 的策略核心是数据保护。Steam 默认假设:只要云端有文件而本地没有,即视为本地数据丢失,必须立即恢复。

这就导致了经典的“死循环”:用户在本地删除归档 -> 启动游戏 -> Steam 检测缺失 -> 自动从云端下载 -> 存档“复活”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
sequenceDiagram
actor User as 用户
participant Disk as 本地文件系统
participant Steam as Steam 客户端
participant Cloud as Steam Cloud

User->>Disk: 删除 savegame.sav (仅删除本地文件)

Steam->>Steam: 触发状态同步 (如游戏关闭时)
Steam->>Disk: 扫描 UFS 监控目录
Disk-->>Steam: 发现文件缺失

Steam->>Steam: 检查 remotecache.vdf (发现本地索引仍在)
Steam->>Cloud: 请求云端校验
Cloud-->>Steam: 云端存在该文件且版本匹配

Note right of Steam: 判定为本地数据意外丢失
Steam->>Cloud: 发起下载恢复请求
Cloud-->>Steam: 传输文件数据
Steam->>Disk: 重新写入本地路径

Note over User, Disk: 死循环:被删除的归档自动恢复

如何彻底删除?

既然本地删除无效,就需要绕过保护机制强制执行远端移除。

1. 常规手段(制造冲突)

利用冲突解决机制覆盖云端数据是社区较常用的方案(参考 XT’s Steam Guide - 管理云存档):

  1. 关闭云同步(防止自动恢复)。
  2. 删除本地文件userdata 下对应的 remotecache.vdf 索引。
  3. 开启云同步并启动游戏,触发冲突状态。
  4. 出现对话框后选择”上传本地文件”,以当前“空状态”强制覆盖删除云端旧存档。

2. Steam 控制台强制同步法

这是 Reddit - How to permanently delete Steam Cloud saves 给出的最新变通方案,利用 Steam 内置控制台的未公开命令强制上传本地“空状态”:

  1. 在本地磁盘中定位并直接删除该游戏的存档文件
  2. Win + R 键,输入 steam://open/console 唤出 Steam 控制台。
  3. 在控制台输入命令 cloud_sync_up [AppID] (替换为目标游戏的 AppID) 并执行。
  4. 这条指令会强制 Steam 以当前本地的最新状态(无文件)向云端发起全量上传覆盖。当你下次启动游戏时,Steam 便会同步这个“空壳”状态,从而实现清除云存档的目的。

3. 借助第三方工具直接调用 API

由于手动制造冲突费时费力,借助工具直接执行 API 调用是更高效且彻底的解法。

核心误区:实测证明,几乎所有 Auto-Cloud 上传的云端文件依然能被 API 强行删除。API 的真正限制在于写入权限的不对等:你可以用 API 删掉 Auto-Cloud 文件,却无法用 API 将新文件写回到特定的 Auto-Cloud 根目录(Root ≠ 0)。这正是上传非0目录必须依赖 UFS 注入的原因。

这种接口层“允许全局删除、限制定向写入”的割裂权限,加上官方管理面板长期缺失删除按钮,迫使玩家折腾各种偏门手段,也引来了社区无数针对这种极其固执的管理的吐槽(如 Steam 社区长线讨论)。

4. 未安装游戏能否直接调用 API 删除?

在未安装游戏的情况下直接调 API 删存档表现极不稳定:有的能成功连接抹除,有的则失败、无响应或仅能读到极少文件残片。就算换用 Watt ToolkitSteamCloudFileManagerLite 也同样如此。这可能是由于本地缓存残缺、特殊的 Root 属性校验或服务端临时策略限制导致。

因此,如果遇上未安装游戏引发的 API 调用失败,目前最稳妥的保底方案仍是:安装游戏并运行一次 -> 确认同步网络已就绪 -> 使用工具删除 -> 删除成功后卸载游戏

Root ID:通过反向验证建立映射表

为了实现 Auto-Cloud 的跨平台支持,Steam 使用了一套 ID 映射系统(Root ID)。每个 ID 代表一个抽象的系统路径。

问题在于:官方文档及网页管理后台仅公开了 Root 的字符串名称(如 WinMyDocuments),但在本地 remotecache.vdf 索引中记录的却是数字 ID。虽然在 Steamworks SDK 内部可以找到它的底层枚举定义,但缺乏跨平台具体的路径落地说明,很多开发者和玩家并不清楚其映射关系。

验证方法:自定义 UFS 注入

由于官方未公开这两者的对应关系,需要通过逆向实验来推导其映射表。验证思路如下:

  1. 找到一个已有云存储配额但没有配置 UFS savefiles 的现有应用 (即只有云空间配额 quota,但没有配置自动同步规则的游戏,如骑砍1、黑魂系列、戴森球计划、Undertale或者一些工具类的应用)。

  2. 使用 Steam 云存档管理器向该应用注入自定义的 UFS 配置,为每个已知的 Root 类型各创建一条 savefiles 规则。

自定义UFS配置

  1. 每条配置使用不同的 Root 名称 (WinMyDocumentsMacHome 等),并各绑定一个独立的测试文件。

路径映射文件夹

  1. 注入配置后重启 Steam 客户端,通过云存档管理器连接并断开一次触发上传,再次连接即可看到上传成功的数据。

云端上传成功

  1. 读取 remotecache.vdf,将每个测试文件对应的数字 root 值与其 UFS 配置中的字符串名称进行比对。

remotecache.vdf数据

通过这种逐一验证的方法,就能精确地将 字符串名称数字 ID 对应起来。

验证结果

以下是部分常见的 Root ID 映射关系预览:

ID 对应的 Root 名称 路径
0 Default {Steam}/userdata/{UID}/{AppID}/remote/ (仅限 API 调用)
1 GameInstall {Steam}/steamapps/common/{Game}/
2 WinMyDocuments %USERPROFILE%\My Documents\
3 WinAppDataLocal %LOCALAPPDATA%
4 WinAppDataRoaming %APPDATA%
10 WinProgramData %PROGRAMDATA%
11 SteamCloudDocuments 见下方说明
13 MacCaches ~/Library/Caches/
17 AndroidSteamPackageRoot (Android 专用)

数据来源:以上 Root ID 与名称的完整对应关系来自 Steam SDK 内部枚举 ERemoteStorageFileRootOpenSteamworks 镜像),路径映射则通过实际游戏测试和 cloud_log.txt 分析确认。

说来惭愧,这个枚举是在写这篇文章的过程中才找到的。也就是说,前面花了大量精力搞 UFS 注入、逐个游戏交叉对比来反向推导的 Root ID 映射表,人家 SDK 头文件里一直都写得清清楚楚——包括之前一直标为”未知”的 Root 5、10、13、17,全都有现成的命名 🤣

完整的 Root ID 映射表见 GitHub 仓库:ROOT_PATH_MAPPING.md

SteamCloudDocuments (Root 11) 路径说明

SteamCloudDocuments 是 Auto-Cloud 专用的 Root 类型,用于将存档存放在用户文档目录。官方文档中仅给出了”平台特定路径”的笼统描述,并以 Linux 为例提供了一条路径:~/.SteamCloud/[username]/[Game Folder]/,其余平台的路径并未公开。以下 macOS 和 Windows 的路径是通过分析各平台 cloud_log.txt 日志确认的:

平台 SteamCloudDocuments (Root 11) 实际路径
macOS ~/Documents/Steam Cloud/[Steam用户名]/[游戏名]/
Linux ~/.SteamCloud/[Steam用户名]/[游戏名]/
Windows %USERPROFILE%\Documents\Steam Cloud\[Steam用户名]\[游戏名]\

额外发现:Android 支持

在分析 Steam 配置时,还发现 Steamworks 加入了对 Android 平台的云同步支持:

AndroidExternalData

在 Steam 的配置数据 (ufs_raw) 中,可以看到这样一段 Root 定义:

1
2
3
4
5
6
7
8
9
10
11
12
// 摘自 Steam 内部配置 (User File System)
"ufs_raw"
{
// ... 其他 Root 定义 ...
"14" // 注:这里的 "14" 仅为配置序号,并非实际 Root ID
{
"root" "AndroidExternalData"
"path" "test233"
"platforms" { "1" "Android" } // Android 平台支持
"recursive" "1"
}
}

实际上,Android 的支持在 SDK 内部远比公开文档要早得多。在前面提到的 ERemoteStorageFileRoot 枚举中,k_ERemoteStorageFileRootAndroidSteamPackageRoot(Root 17)早在 2019 年 1 月的初始 commit 中就已经被定义了。但 Steamworks 后台 UI 直到最近(2026年2月份)才正式向开发者开放了 Android 平台的 Auto-Cloud 配置项,在官方的 Android APK 上传文档中的 Steam Cloud 配置步骤里,明确要求开发者选择 AndroidExternalData 作为 Root,并设置对应的子目录路径来匹配 Android 上的存档目录。

也就是说,Valve 在底层为 Android 云同步埋了至少五年的桩,才逐步将其暴露到面向开发者的公开接口中。

特殊的 AppID

在折腾和研究 Steam 云存储的过程中,我还在远程存储页面(Remote Storage)里发现了一些特殊的 AppID。

Steam Client AppID 7

起初注意到这个特殊的 AppID,正是因为它在远程存储页面中直接被定名为了 Steam Client

通过 SteamDB (AppID 7) 进一步查证可以得知,它并非某款隐藏或未上架的游戏,而被明确标记为 Config 类型的内置应用。这正是 Steam 客户端专门用于存放账号级全局设定的一块云空间。

SteamDB AppID 7 分析页面

比较离谱的是🤔,明明只是一个用来存配置的“内部应用”,SteamDB 数据显示现在都还有 41 个人保持在线😱,不知道在挂什么神仙卡片😂,可能这 41 个人都是V社的员工

通过访问对应的本地 remote 目录(或利用云存档管理器从云端下载),可以提取出两个核心配置文件:

AppID 7 云端数据

提取这些文件内的 VDF 文本结构进行分析,我大致推断出了这些数据的实际作用(如果有人了解更深层的机制,欢迎讨论和修正):

AppID 7 本地文件

  • serverbrowser_hist.vdf:整个文件由一个根节点 "Filters" 组成,内部包含 "favorites"(收藏)与 "history"(历史)两个子域。以 "history" 为例,它以单调递增的数字作为键,逐条保存了连接过的服务器信息:其中 "address""name" 标明了服务器的 IP 与端口,"LastPlayed" 是最后一次游玩的 UNIX 时间戳。值得注意的是,这些记录中的 "appid""accountid" 字段均为 "0"。结合它的结构,这显然是 Steam 控制面板里调出的那个“服务器浏览器”的公共历史与收藏记录。
  • sharedconfig.vdf:文件由 "UserRoamingConfigStore"(用户漫游配置库)为根节点,用于在不同设备间同步你的各个客户端状态配置:
    • "Software" -> "Valve" -> "Steam" 节点下,存放着类似于 "SurveyDate"(硬件调查日期)以及快捷方式创建选项等参数。
    • 其子节点 "apps",以各个游戏的真实系统 AppID(如 "730""504230")作为键名,分别记录着它们各自是否在本地开启了云同步("cloudenabled" "1")。
    • 下方的 "JSClientStorage" 等节点则偏向于 UI 层的交互状态,比如记录 timeline_intro 这种新特性弹窗是否已经被你阅览过(用 "rtSeen" 时间戳标记)。

实测发现:面对 AppID 7,服务端会直接拒绝基础的 API 连接请求。为了能下载这部分数据,我在代码中增加了拦截逻辑:遇到 AppID 7 直接跳过 API 调用,改用 CDP (Chrome DevTools Protocol) 从网页版抓取(见 src/app_handlers.rs):

1
2
3
4
5
6
// 系统级 App ID(无法初始化 Steam API,改用 CDP 获取列表)
const SYSTEM_APP_IDS: [u32; 1] = [7]; // Steam Client

fn is_system_app_id(app_id: u32) -> bool {
SYSTEM_APP_IDS.contains(&app_id)
}

通过 CDP 虽能顺利读取下载,但在尝试发包删除时,服务端仍会报错拦截。因此对外部而言,这就是个被锁定的只读空间

AppID 744350:聊天的图片缓存

在远程存储页面里,我还看到了一个没有名字的软件:AppID 744350

AppID 744350

虽然网页端完全没有任何描述,但通过 API 连接读取后,可以明确看到它对应的名字其实是“Steam Chat Images”:

API 读取结果

为验证其功能机制,进行了一组针对性的测试:通过 Steam 客户端向好友发送了一张 GIF 动图。

好友聊天界面发送图片

发送动作完成后,回到云存档管理器刷新数据,就能看到刚刚上传的的图片已作为新的文件记录出现在列表中:

云端新增的文件

将其下载后,发现就是刚才发送的图:

下载后的文件预览

相比 AppID 7 那种被严格保护的配置空间,这部分数据的读写权限十分开放,与普通游戏存档一致。这直接验证了前面的猜想:Steam Cloud 在底层的定位不仅是“游戏存档”,它完全可以作为一个标准的云文件存储系统,供 Steam 平台侧的各项内部业务直接复用。

结语

这个项目从去年 9 月断断续续写到现在,中间为理清 Root ID 映射表和 API 逻辑踩了不少坑。文中部分结论基于个人摸索和有限平台的测试,难免疏漏。如果你发现了错误或不同的表现,欢迎交流纠正。

如果本文分析或 SteamCloudFileManager 这个工具对你有帮助,真诚求个 GitHub Star⭐️,感谢!

参考链接

官方文档

SDK 内部结构

社区资源

社区讨论

开源项目

引流