The game's ANSI file API calls are hooked; paths under save\ and Settings.cfg are redirected to Documents\Sacred\save and Documents\Sacred\config, copied there once from the game folder. The shared chest uses the same save folder. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
56 lines
2.7 KiB
Markdown
56 lines
2.7 KiB
Markdown
# User folders (Documents\Sacred)
|
|
|
|
Request (2026-10-19): the game keeps its save games and settings in the
|
|
user's Documents folder instead of the game folder:
|
|
|
|
| Folder | Contents |
|
|
|---|---|
|
|
| `Documents\Sacred\save\` | `GAMEnn.PAK` (save rows), `Heronn.pax` (exported heroes), `shared_chest.json` (sacredK) |
|
|
| `Documents\Sacred\config\` | `Settings.cfg` (the game's options) |
|
|
|
|
`sacredK.ini` (key bindings, loot filter, game folder) stays next to the DLL.
|
|
|
|
## Measured
|
|
|
|
Vanilla keeps everything inside the game folder: no AppData, Documents or
|
|
registry use (the `Ascaron Entertainment` folders there belong to Sacred 2).
|
|
`sacred.exe` names the files with paths relative to the working directory
|
|
(the game folder), from 37 code sites:
|
|
|
|
| String | Address | Users |
|
|
|---|---|---|
|
|
| `./SAVE/GAME%.2d.PAK` | 0x95c530 | 0x60b58b, 0x60c0d3, 0x60e38f, 0x60e645, 0x71cda7 |
|
|
| `SAVE/GAME%.2d.PAK` | 0x95c884 | 0x60e35a, 0x60e60a, 0x619c38 |
|
|
| `./SAVE/GAMEF%d.PAK` | 0x95c870 | 0x60e3b9, 0x60e674 |
|
|
| `./SAVE/SAVE02.PAK` | 0x95c85c | 0x60dc2c |
|
|
| `Save\Hero%.2d.pax` | 0x95c4ec | 0x60bf16, 0x614ceb, 0x70d96c, 0x70dd8d, 0x70df1b, 0x70e091 |
|
|
| `.\Save`, `Save` | 0x95d5f4, 0x95d5ec | 0x619cd4/ec, 0x61cdc0/d1 |
|
|
| `SAVE\` | 0x9e15a0 | 0x70bf07 |
|
|
| `Settings.cfg` | 0xa18dc4 | 0x7ed6a2..0x7eeab3 (13), WinMain 0x816dc0..0x816dd6 |
|
|
|
|
All file access goes through kernel32's ANSI functions: `CreateFileA`,
|
|
`DeleteFileA`, `FindFirstFileA`, `GetFileAttributes(Ex)A`,
|
|
`SetFileAttributesA`, `CreateDirectoryA`, `CopyFileA` (no `MoveFile*`, no
|
|
`SetCurrentDirectory`).
|
|
|
|
## How the mod works (`src/mods/userfolders.cpp`)
|
|
|
|
- Those eight functions are hooked (`RE_HOOK_API`). A path is rewritten when,
|
|
after an optional game-folder prefix and `.\`/`./`, its first component is
|
|
`save` (any case) or it is exactly `Settings.cfg`; every other path passes
|
|
unchanged. One choke point instead of 37 patched operands, and no long
|
|
absolute path in the game's fixed-size buffers.
|
|
- The Documents folder comes from `SHGetKnownFolderPath(FOLDERID_Documents)`
|
|
(follows OneDrive/redirected Documents), looked up on the first redirected
|
|
path: the hooks are installed under the loader lock, where shell calls must
|
|
not run. If it is unusable (lookup fails, or a character outside the ANSI
|
|
code page), the game folder stays in use.
|
|
- Migration: when `save\` or `config\` does not exist yet, the game folder's
|
|
save files / `Settings.cfg` are copied there once with the wide file
|
|
functions (not hooked). The originals stay in the game folder.
|
|
- `mods::userfolders::SaveDir()` gives sacredK's own files the same folder
|
|
(shared chest).
|
|
|
|
Not covered: `Config.exe` and `gameserver.exe` (`GameServer.cfg`) are
|
|
separate programs without the DLL and still use the game folder.
|