Steam manifest 文件详解
appmanifest_*.acf 文件是什么、里面有什么、为什么 SteamTools 需要它,以及怎么在文本编辑器里读懂它。
最近更新: 2026-07-05
每次 SteamTools 解锁都需要两个文件。本页讲第一个 —— appmanifest_<APPID>.acf —— 讲到你可以在文本编辑器里读它、明白每一行在做什么。Lua 文件是简单那一半(只是个短脚本,告诉 SteamTools 加载哪些 depot),manifest 才是让人困惑的部分。我们也会把所有常见的错误和边界情况都过一遍,让你在野外再看到一个 manifest 时能清楚知道该怎么处理。
这个文件是什么
manifest 是 Valve "ACF"(Application Configuration File,应用程序配置文件)格式的小文本文件。ACF 是带 section 头的键值格式,类似 INI。Steam 在 steamapps 目录里为每个你装过的 app 写一份。命名约定是 appmanifest_<APPID>.acf,其中 <APPID> 是该游戏的 App ID。
要让 SteamTools 跑起来,你需要一份这样的文件(或一份指向正确 depot 和 build 的副本)放在 SteamTools 监听的目录里,通常是 <SteamTools>/depotcache/。manifest 不需要是 Steam 给你安装的那份原文 —— 它只需要描述正确的 app 的正确的 build。SteamTools 读 manifest 知道要拉哪个 depot 的哪个 build,读 Lua 文件(第二个下载)知道用哪个解密密钥。
里面有什么
一份真实的 appmanifest_400.acf(Portal)长这样:
"AppState"
{
"appid" "400"
"name" "Portal"
"installdir" "Portal"
"StateFlags" "4"
"UpdateLocalTime" "Wed Jan 1 12:34:56 2025"
"buildid" "1234567"
"LastOwner" "12345678901234567"
"BytesToDownload" "0"
"BytesDownloaded" "0"
"AutoUpdateBehavior" "0"
"UserConfig"
{
"language" "english"
}
"MountedDepots"
{
"400" "2345678"
}
}
一旦知道该看哪,这些字段大多数都自解释。对 SteamTools 真正重要的是两个:
appid—— App ID。必须与文件名一致。SteamTools 实际不查文件名,但 Steam 在文件名不以appmanifest_<appid>.acf开头时会拒绝加载。所以两边必须匹配。MountedDepots—— depot ID 到该 depot build ID 的映射。SteamTools 用这个知道每个 depot 要下载哪个 build。MountedDepots是空或错了的话,SteamTools 找不到正确的 build,游戏就起不来。
其它字段(UpdateLocalTime、UserConfig、LastOwner 等)是 Steam 自己的账本。SteamTools 忽略它们。生成器也不会带它们 —— 复制别人的 LastOwner 就会指向别人的 Steam 安装而不是你的,既是隐私问题也是正确性问题。
生成器给你的到底是什么
从本站请求一份 manifest 时,你拿到的是一份只含 SteamTools 需要的字段的小文本文件。具体是:
appidname(请求时从appdetails解析出来)installdir(Steam 的安装目录约定,小写)buildid(最新的公开 build,或者你指定的分支的 build)MountedDepots,app 上的每个 depot 一条
我们不带 UpdateLocalTime、UserConfig 或 LastOwner,因为 SteamTools 不读它们,复制别人的 manifest 还会把 LastOwner 指向别人的 Steam 安装而不是你的。
生成器出的 manifest 一般在 200–600 字节,取决于 depot 数量。相比之下 Steam 自己的完整 manifest 可以到 2–4 KB。
Lua 文件 60 秒讲完
Lua 文件(你下的第二个文件)是个很小的脚本,告诉 SteamTools 这个 app 要加载哪些 depot。一份典型的 400_public.lua 大概是:
addappid(400, 1, "abcdef0123456789abcdef0123456789")
setmanifest("2345678", "1234567890abcdef1234567890abcdef")
addappid(<appid>, 1, <depot_key>)注册这个 app 并提供它主 depot 的解密密钥。setmanifest(<depot_id>, <manifest_id>)让 SteamTools 指向该 depot 的特定 build。
生成器从 Steam 公开数据里推导出 depot 密钥和 manifest ID。没有任何秘密。depot 密钥就是那个 depot 的解密密钥 —— Steam 公开的 32 字符 hex 串。manifest ID 是该 depot 的 manifest 文件的 SHA-1,也是公开的。
为什么 SteamTools 两个文件都要
这个拆分是有意为之的:
- manifest 告诉 SteamTools 要加载 app 的哪个 build。
- Lua 文件告诉 SteamTools 怎么加载(哪些 depot、哪个解密密钥)。
只拿到 manifest 的话,SteamTools 不知道怎么解密 depot。只拿到 Lua 的话,SteamTools 不知道要抓哪个 build。两个文件都必需,而且它们对 App ID 的描述必须一致。
.acf manifest .lua script
│ │
│ "我要 app 400 的 │ "对 app 400 用 depot key X,
│ build 1234567, │ 对 depot 2345678
│ depot 400 → 2345678" │ 指向 manifest Y"
│ │
└──────────┬───────────────────┘
▼
SteamTools
(桌面客户端)
│
▼
游戏以正确的
解密 build 启动
分支说明
有些游戏除了 public 之外还有 beta 或 ptb 分支。生成器在 UI 上有一个 "Branch" 字段;填了之后返回的 manifest 和 Lua 指向那个分支的 build 而不是 public。默认是 public。
分支名必须与 Steam 显示的完全一致。常见值有 public、beta、beta_1、ptb、experimental。不确定要哪个分支就把字段留空,会拿到 public build。
要查某个 app 有哪些分支,去 SteamDB 的 branches 页。SteamDB 是分支名和每个分支的 buildid 的权威来源。
常见边界情况
这些是"把文件丢进 depotcache"这条基本流程覆盖不到的情况。
没有公开 depot 的 app
有些 app 在 Steam 目录里存在但没有发布过 build。它们在搜索里有、有一个 App ID,但 appdetails 返回的 depot 列表是空的。生成器会返回 0 字节的 manifest,或只带 AppState 头。how-it-works 页对这种情况有专门的错误。
加密 vs 非加密 depot
Steam 上的每个 depot 都是加密的,不管这个游戏是否号称"无 DRM"。加密作用在 depot chunk 上、不是游戏文件本身 —— 拿到 depot 密钥后,SteamTools 把 chunk 解出来,游戏文件就是解密后的。这正是为什么 Lua 文件是强制的,即使对"无 DRM"的广告游戏也一样。DRM 在 Steam-workshop 层(没有 Steam 账号拥有这个游戏),不在 depot 层(depot chunk 在传输时仍然是 AES 加密的)。
soundtrack 和 DLC
DLC 和 soundtrack 是普通的 Steam app。它们有自己的 App ID、自己的 manifest、自己的 Lua 文件。要解锁一份 DLC 或 soundtrack,生成 DLC 自己的 App ID 的 manifest + Lua,不是基础游戏的。常见 DLC 像"原声大碟"(App ID 在 20 多万)、"季票"(App ID 不固定)。
如果你想解锁一个基础游戏 + DLC 的组合,需要两对 manifest/Lua:一份给基础游戏的 App ID,一份给 DLC 的 App ID。两对都放进同一个 depotcache 和 scripts 文件夹。
跨区 depot
有些游戏会为不同区(CN、EU、US、ASIA)发布独立的 depot。生成器会挑与你 Steam 客户端区域匹配的 depot。改了区的话要重新生成 manifest —— MountedDepots 映射会不一样。
工具类(Proton、Steamworks、Source SDK)
Proton、Source SDK、Steamworks Common Redistributables 这些工具都是普通的 Steam app。解锁方式一样。App ID 是已知的(Proton 是 858280;Steamworks 是 243750)。
下架 app 说明
如果一个游戏已经从 Steam 下架,生成器里可能还有 manifest 和 Lua,但它们用不了。SteamTools 上游也拿不到下架 app 的可用 build,SteamDB 同样不能。没有绕过办法 —— 想要继续用下架 app,唯一的办法是在它下架前装一份并且永远别卸载。
部分下架 app 在下架后几周内 Steam 的 appdetails 接口仍然可达。在那个窗口期内,生成器会返回可用的 manifest。窗口关闭后就会返回 404,我们这边什么都做不了。
怎么验证 manifest 是对的
把 manifest 丢进 depotcache 之前,过一下这个清单:
- 文件名匹配
appid。文件应该是appmanifest_<APPID>.acf,里面的appid字段要一致。不匹配的话 SteamTools 会拒绝。 name是你预期的游戏名。name 错了说明 App ID 错了。MountedDepots非空。MountedDepots块为空说明该 app 没有公开 build。buildid看着合理。Steam 的 build ID 是整数,一般 7–8 位,随时间递增。buildid是1或0就是错的。
四条都过了 manifest 就是好的。丢进 depotcache、Lua 丢进 scripts、重启 SteamTools。
故障排查:"文件都放进去了但 SteamTools 还显示游戏锁着"
十有八九是这六个之一:
- manifest 放错目录了。必须在 SteamTools 根目录的
depotcache文件夹,不能放在子目录里。 - Lua 放错目录了。必须在 SteamTools 根目录的
scripts文件夹,不能放在depotcache里。 - 没重启 SteamTools。文件是 SteamTools 启动时读的。运行中复制进去不会生效。
- manifest 里的 build 比 Steam 提供的老。重新生成一次 manifest,新那份的 buildid 就是最新的公开 build。
- Lua 里的分支与 manifest 里的分支不一致。Branch 字段填了
beta但 Lua 是按public生成的,两边就对不上。重新生成时分支填一样的(生成器默认就是这样)。 - Lua 里的 depot 密钥错了。这种情况很少见 —— 说明该 depot 重新分发了密钥。生成器下次请求时会拿到新密钥。
SteamTools.games manifest vs Steam 原始 manifest vs GreenLuma manifest
格式一样,内容不同。
| 来源 | 有 appid | MountedDepots 正确 | 有 LastOwner | SteamTools 能用吗 |
|---|---|---|---|---|
| 本生成器 | 有 | 有(最新公开 build) | 无(省略) | 能 |
| Steam 原始 manifest(你自己安装的) | 有 | 有(你装的 build) | 有(你的 Steam ID) | 能,但 LastOwner 是你自己的 ID,没问题 |
| 朋友分享的 manifest | 有 | 有(他装的 build) | 有(他的 Steam ID) | 能,SteamTools 忽略 LastOwner |
| GreenLuma manifest | 有 | 有时候 | 无 | 有时候 —— GreenLuma 的 manifest 格式是子集,可能不含 MountedDepots |
简单说:任何来源的 manifest 只要 appid 和 MountedDepots 对了,SteamTools 就能用。其它字段对 SteamTools 来说是噪音。
进一步阅读
- SteamTools.games 是怎么工作的 —— 产出 manifest 的四步流程
- 生成器错误排查指南 —— 生成器能返回的四种错误及修法
- SteamTools 上游文档 —— 解释 SteamTools 在你把 manifest 和 Lua 放好之后做什么
- SteamDB app 页 ——
buildid和 depot 列表的权威来源 - 如何找 Steam App ID —— 当你有游戏名但没有 App ID 时
另见
- 什么是 Steam manifest 文件,怎么配合 SteamTools 使用? —— 完整的前门指南;本页是其中一个部分的深入展开。