bssth/sacred-sdk
GitHub: bssth/sacred-sdk
SacredSDK 是一个基于 Lua 的 Sacred Gold 游戏模组开发框架,通过将脚本编译为原生字节码实现无需修改 EXE 的游戏内容自定义。
Stars: 5 | Forks: 2
# SacredSDK
一个专为 **Sacred Gold** (Ascaron, 2004) 打造的现代 mod 工具包 —— 使用 **Lua** 编写 mod,且无需修改任何原始游戏文件。
[]()
[]()
[]()

## 这是什么
SacredSDK 是一个会在启动时被 Sacred 加载的 DLL(通过 `ijl15.dll`
代理槽位 —— 无需对 `Sacred.exe` 打补丁)。加载后,它会:
1. **将 Lua mod 编译** 将 `custom/lua/**/*.lua` 编译为 Sacred 的原生
字节码(即游戏中的每个任务、对话和生物所使用的 `FunkCode.bin` 格式)。
2. **修补资源查找**,使得 Sacred 打开的任何文件都可以被透明地替换为
`custom/`。
3. **挂钩资源解析器**,使得 Lua mod 能够对游戏运行时事件(NPC 对话、击杀横幅、任务进度)作出反应,并修改英雄状态(金币、物品栏)。
Steam 安装文件保持分毫未改 —— mod 完全存放在
`/custom/` 目录下。卸载 = 删除该目录。
## 目前你可以做到的
| 功能 | 状态 | 备注 |
|---|---|---|
| **重新包装任意原版任务的文本** | ✅ 稳定 | `T.named("HQ_3_2_1_Log_Title", "My new title")` |
| **内联字符串 mod** | ✅ 稳定 | `T"Some text"` 会自动注册到 `global.res` 中 |
| **基于职业的启动脚本** | ✅ 稳定 | 在英雄生成时设定 qbits 和变量 |
| **使用 Lua 创建对话场景** | ✅ 稳定 | `d.trigger / d.line / d.emit` 构建器 |
| **原生 `has_item` 断言** | ✅ 稳定 | 字节码级别的物品栏检查 |
| **原生 `give_gold` 操作码** | ✅ 稳定 | 编译时的金币操作 |
| **运行时回调** (`sacred.on_trigger`) | ✅ 运行中 | 在资源查询时触发 |
| 处理程序中的 **`ctx:give_gold(N)`** | ✅ 运行中 | 事件总线,播放金币掉落声 + 浮动文字 |
| **`ctx:has_item(N)`** (装备) | ✅ 运行中 | 扫描 18 个穿戴槽位 |
| **`ctx:notify(text)`** | ✅ 运行中 | 屏幕顶部的 Toast 横幅 |
| **游戏内覆盖层** | ✅ 运行中 | F11 捕获 / F12 隐藏 / F10 快照 |
| `ctx:has_item` (背包) | 🟡 待办 | 需要对背包数组进行逆向工程 |
| `ctx:set_qbit` 运行时 | 🟡 存根 | 编译时版本可用 |
| 原生引擎横幅 | 🟡 待办 | 目前为 ImGui 覆盖层 Toast |
| 生成时创建全新任务 | ❌ 受阻 | 需要对任务书进行逆向工程 |
请参阅 [docs/community-refs.md](docs/community-refs.md) 获取包含工作量预估的完整
需求清单。
## 快速开始
```
-- save as: /custom/lua/bin/TYPE_NPC_SERAPHIM/FunkCode.lua
local T = require "text"
local v = require "vanilla"
-- Re-skin the Seraphim main quest into a custom narrative.
T.named("HQ_3_2_1_Log_Title", "The Lost Tome of Ancaria")
T.named("HQ_3_2_1_Log_Header", "Chapter 1 — A Curious Heist")
T.named("HQ_3_2_1_Log_Qstart",
"A young monk runs up to you in Bellevue, breathless. " ..
"An ancient tome was stolen from the monastery library...")
return v.load "bin/TYPE_NPC_SERAPHIM/FunkCode"
```
启动 Sacred → 创建一个新的 Seraphim → 接受 Leandra 的任务 → 打开
日志。你会看到原版中原本显示为“River Pirates”的地方变成了你设定的新标题和文本。
完整的参考文档位于 **[docs/MODDING_GUIDE.md](docs/MODDING_GUIDE.md)** ——
请先阅读该文档。
## 结构剖析
```
/
├── ijl15.dll ← SacredSDK proxy (replaces stock)
├── ijl15_real.dll ← original, renamed
├── bin/, scripts/, … ← vanilla, never touched
└── custom/
├── lua/
│ ├── lib/ ← stdlib (quest / dialog / text / events / …)
│ ├── examples/ ← copy-paste starters (01..07)
│ └── bin/ ← YOUR mods live here, mirror of bin/
│ └── TYPE_NPC_*/
│ ├── QuestCode.lua
│ └── FunkCode.lua
└── bin/ ← auto-generated .bin files (served to Sacred)
```
这里有三个创作层级(从高到低):
1. **高层** —— `lib/quest.lua`、`lib/dialog.lua`、`lib/text.lua`。
每个任务原语只需编写一行 Lua 代码。
2. **中层** —— `lib/funkcode.lua`、`lib/raw.lua`。通过操作码名称直接进行字节码构建。
3. **底层** —— `lib/unsafe.lua`、`raw.hex"…"`。原始字节数据字面量。
对于 132/132 个原版 `.bin` 文件,其往返转换在字节级别上是完全一致的。
## 示例 (位于 `custom/lua/examples/`)
| 文件 | 演示内容 |
|---|---|
| `01_hello.lua` | 声明状态的最小化 mod |
| `02_text_swap.lua` | 通过 `gsub` 批量重写原版内容 |
| `03_dialog_block.lua` | 从零编写一个对话场景 |
| `04_full_quest.lua` | 小型独立任务 |
| `05_conditional_dialog.lua` | 原生 Sacred 分支结构骨架 |
| `06_sidequest.lua` | **从这里开始** —— 完整的支线任务模板 |
| `07_runtime_triggers.lua` | `sacred.on_trigger` 模式 |
## 项目状态
**Alpha 阶段。** 核心流程(Lua → 编译 → 字节一致的 bytecode)已被
验证且稳定。运行时挂钩可以正常工作,但需要了解
在你所关注的事件期间 Sacred 会查询哪些资源 ID
(发现过程是迭代的;请参阅 `docs/MODDING_GUIDE.md` 中的“运行时
触发器挂钩”部分)。
公开接口是 **`docs/MODDING_GUIDE.md`** 和 `custom/lua/lib/`
模块。C++ 端(DLL 实现、挂钩、RE 脚本)位于
同一个 SCM 仓库中,但进行了单独的权限控制 —— 请参阅下文的“仓库
内容”部分。
## 仓库内容
```
sdk/
├── README.md ← you are here
├── docs/
│ ├── MODDING_GUIDE.md ← READ THIS FIRST
│ ├── README.md ← guide to the rest of the doc set
│ ├── 01..22-*.md ← RE journey (historical, technical)
│ ├── community-refs.md ← mined intel from community RE tools
│ └── roadmap.md ← where we are, where we're going
└── tools/
├── README.md ← walkthrough: "I want to X → run Y"
├── *.py ← FunkCode pipeline, globalres edits, quest
│ dumpers, sacred_hash, balance_diff, …
├── hash_names.csv ← 23 123-entry hash dictionary
├── smoke_test_proxy.bat
└── ghidra/ ← Java scripts for headless Ghidra RE
└── README.md
```
**DLL 源码** (C++) 以及**打包进 DLL 的 Lua 标准库**
将通过单独的分发渠道(二进制发布)提供,并将在
后续推送中,当公开 API 接口趋于稳定时予以开放。
如果你现在只想运行 mod,二进制版本已经内置了所有
运行时组件 —— 只有当你想要阅读、贡献或扩展文档和 Python 工具时,才需要克隆此仓库。
## 已验证环境
Steam 版 Sacred Gold,版本号 **2.0.2.28** (2006-10-13)。该 DLL 不会
进行版本检测;其他版本可能可以运行,但尚未经过
测试。如果你尝试了其他版本,请提交一个 issue。
## 非目标
- 多人模式 mod 脚本(Sacred LAN 协议的逆向工程在
愿望清单上,但尚未开始)。
- 资源替换(贴图、模型、声音) —— 这些是
`.pak`/Granny 格式;请参阅 `docs/community-refs.md` 了解
处理它们社区工具。
- “ReBorn HD”风格的 EXE 补丁 —— SacredSDK 仅是一个运行时 DLL,
而不是补丁。
## 致谢
- **Thorium**(2007 非官方补丁 2.29) —— 恢复了 global.res
加载器 detour 以及我们移植到运行时的 focus-busy-wait 修复。
- **SonicMouse** (SacredGameTools) —— 存档文件格式,
`TINCAT2.DLL` 网络布局。
- **The Resacred remake 项目** —— pak/keyx 格式逆向
工程,物品/瓦片结构。
- 更广泛的 Sacred mod 社区,感谢他们二十年来积累的
逆向工程笔记。
## 许可证
MIT。请参阅 `LICENSE`(或退回到标准的 MIT 条款 —— 这
纯属粉丝制作 mod 的工作;不分发任何 Ascaron/Encore 的 IP)。
标签:DLL注入, Lua, rizin, 字节码工具链, 封包Hook, 流量审计, 游戏模组, 游戏逆向工程, 逆向工具