Framework for Sacred 2 Gold, game log mirror, borderless fullscreen
Ported from sacredK with module-relative addresses, hooks by exported name and a SHA-256 check of the six game modules (Community Patch 2.65.1). Borderless windowed at monitor size replaces exclusive fullscreen, whose focus loss during loading made the game quit and crash on exit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
8a7bdfd99f
44 files changed
+2505
No files matched your search
@@ -0,0 +1,113 @@
|
||||
# sacred2K
|
||||
|
||||
An incremental reimplementation of **Sacred 2 Gold** (Sacred 2: Fallen Angel +
|
||||
Ice & Blood, 2009) with Community Patch 2.65.1. Sister project of sacredK
|
||||
(Sacred Gold).
|
||||
|
||||
`sacred2K.dll` is injected into the original game at startup and replaces
|
||||
game functions with rewritten C++ one by one. Everything not yet rewritten
|
||||
keeps running as original machine code, so the game stays playable at every
|
||||
step and each rewrite can be tested in-game immediately.
|
||||
|
||||
No game assets or original code are included; you need your own installed copy
|
||||
of Sacred 2 Gold.
|
||||
|
||||
## Supported build
|
||||
|
||||
Sacred 2 Gold (Steam, app 225640) with Community Patch 2.65.1. The game is
|
||||
split into an executable and several DLLs; hook addresses are specific to
|
||||
these files:
|
||||
|
||||
| File (in `system\`) | Size | SHA-256 |
|
||||
|---|---|---|
|
||||
| `sacred2.exe` | 2,825,728 | `37b6d077ce9ff7c1b539e9e17db5351cb3a22c02827b36cc327b1f5fc0900090` |
|
||||
| `orcSystem.dll` | 935,560 | `43b34c8c5a825f6f485f8cf8122054faff4075a33f44554901d8de167c7389b3` |
|
||||
| `s2core.dll` | 1,406,088 | `2b9b8e05746f7a6f439746c3e26919a983ec794bae6bbcfe25f54cf0d05c13ec` |
|
||||
| `s2logic.dll` | 3,754,120 | `9370aa81d3b1ca10f603a0758d2520bf42c20f8f5605966aab046fd236d5ed1b` |
|
||||
| `s2logicai.dll` | 1,918,600 | `26b41eaa9e306ba9e9b51a1d33d011d6df7934e14bf21c289876516b393ebe6e` |
|
||||
| `s2render.dll` | 3,711,624 | `09bd4975a2b01816f9a20db4a9365ee944611a78612e72a6abfae125c2723d75` |
|
||||
|
||||
The Community Patch kept the original PE timestamps, so the DLL hashes every
|
||||
module at startup and leaves any other build unpatched.
|
||||
|
||||
## Building
|
||||
|
||||
Requirements: Visual Studio 2022 Build Tools ("Desktop development with C++",
|
||||
MSVC x86 + Windows SDK), CMake ≥ 3.24, Ninja, git (Detours is fetched at
|
||||
configure time).
|
||||
|
||||
```powershell
|
||||
.\build.ps1 # x86-debug -> build\x86-debug\
|
||||
.\build.ps1 x86-release # x86-release -> build\x86-release\
|
||||
```
|
||||
|
||||
Everything is 32-bit x86: the code runs inside the 32-bit game process.
|
||||
|
||||
## Running
|
||||
|
||||
Tell the launcher the Sacred 2 Gold folder (the one containing `system\`) once:
|
||||
|
||||
```powershell
|
||||
build\x86-debug\sacred2K.exe --game-dir "<Sacred 2 Gold folder>" # first run; remembered in sacred2K.ini
|
||||
build\x86-debug\sacred2K.exe # later runs; extra args go to the game
|
||||
```
|
||||
|
||||
The folder is stored as `[paths] GameDir` in `sacred2K.ini` next to the
|
||||
launcher (one per build preset, not tracked by git). The game is started from
|
||||
its `system` folder, as Steam does.
|
||||
|
||||
`sacred2K.log` (next to the DLL) records the module check, what was hooked,
|
||||
and every message the game passes to its logger (`Orc::Log`).
|
||||
|
||||
Hooks can be switched off individually in `sacred2K.ini`:
|
||||
|
||||
```ini
|
||||
[hooks]
|
||||
LogMessage=0
|
||||
```
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
src/re/ hook framework, module addresses, startup, logging, config, crash reports
|
||||
src/launcher/ sacred2K.exe — starts sacred2.exe with sacred2K.dll injected
|
||||
src/game/ rewritten game code and original-layout structs, by module/subsystem
|
||||
src/mods/ behaviour changes on top of the original
|
||||
docs/ reverse-engineering notes; function-map.md tracks progress
|
||||
tools/ disassembler, export index, RTTI, Ghidra scripts
|
||||
```
|
||||
|
||||
## Addresses
|
||||
|
||||
The game's DLLs all prefer image base 0x10000000 and are relocated when
|
||||
loaded, so an address is always a module plus a VA at the module's preferred
|
||||
base, exactly as Ghidra shows it (`docs/modules.md`):
|
||||
|
||||
```cpp
|
||||
constexpr re::Address kSomething{re::Module::S2Logic, 0x10123450};
|
||||
```
|
||||
|
||||
Exported functions (the DLLs export most of their classes) are hooked by
|
||||
decorated name instead:
|
||||
|
||||
```cpp
|
||||
namespace orc {
|
||||
void __fastcall LogMessage(Log* self, void* edx, const String& message, int level);
|
||||
RE_HOOK_EXPORT(re::Module::OrcSystem, "?logMessage@Log@Orc@@UAEXABVString@2@W4LogMessageLevel@2@@Z", LogMessage);
|
||||
void __fastcall LogMessage(Log* self, void* edx, const String& message, int level) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
The signature and calling convention must match the original exactly. Add the
|
||||
file to `CMakeLists.txt` and a row to `docs/function-map.md`.
|
||||
|
||||
## Portability rules (for an eventual 64-bit build)
|
||||
|
||||
The game is 32-bit and must stay so while we hook into it, but new code should
|
||||
not make that permanent:
|
||||
|
||||
- use fixed-width types (`uint32_t`, not `long`/`DWORD`) for anything with a
|
||||
fixed layout;
|
||||
- never store pointers in, or cast pointers to, 32-bit integers;
|
||||
- keep file and network formats behind explicit serialization code instead of
|
||||
`fwrite`-ing structs.
|
||||
Reference in new issue
Block a user