OpenJKDF2

最新发行版 | 报告崩溃或错误
OpenJKDF2 是 DF2 的逐函数 C 语言重新实现,支持 Windows 7+、macOS 10.15+ 和 Linux 的 64 位移植。文件组织尽可能贴近原始游戏,基于 Grim Fandango Remaster 的 Android/Linux/macOS 移植版中的符号,以及来自其他各种游戏的零散断言。它还包含用于 COG 脚本解析的 byacc 和 flex 的原始版本。
OpenJKDF2 不包含任何原始游戏资源;需要一份有效的 JKDF2 副本,可从 GOG 或 Steam 购买。推荐 GOG 版本,因为它无 DRM 限制,并且包含 Ogg Vorbis 格式的音轨。如果您想先试用再购买,可以在 https://maxthomas.dev/openjkdf2/ 找到 OpenJKDF2 的 WebAssembly 演示版。
从 Ogg Vorbis 文件播放原始音轨的支持主要针对 GOG 和 Steam 版本的游戏资源。原始光盘音轨也可以从每张光盘音轨的 MUSIC/1/Track<2..8>.ogg 和 MUSIC/2/Track<2..12>.ogg 中加载。如果文件缺失,它将尝试使用 MUSIC/Track<12..32>.ogg 中的 GOG 曲目编号。在 OpenJKDF2 的未来版本中,计划在安装时从光盘转储音轨,但目前尚未实现。
平台
OpenJKDF2 支持以下配置:
| 配置 | 渲染器 | 描述 |
|---|---|---|
| 64-bit Windows/SDL2 | OpenGL 3.3 | 使用 SDL2 和 OpenAL 的 64 位 Windows 编译。DirectX 依赖项已被 SDL2 和 OpenAL 取代。 |
| MacOS x86_64/AArch64 | OpenGL 3.3 | 使用 SDL2 和 OpenAL Soft 的 64 位 MacOS 编译。所有发布包均包含 Intel 和 ARM64 版本。 |
| 64-bit Linux/SDL2 | OpenGL 3.3 | 使用 SDL2 和 OpenAL 的 64 位 Linux 编译。 |
| ARM64 Android | OpenGL ES 3 | 使用 SDL2 和 OpenAL Soft 的 ARMv8 Android 编译。 |
| Nintendo DSi | Custom | 支持硬件渲染和软件音频的 Nintendo DSi 移植版。RAM 极度受限,支持自发光调色板。 |
| Dreamcast | Custom | 基于 KallistiOS+Dreamcast 的移植版,支持基础 3D 渲染(不支持自发光调色板)以及包含原声音乐和过场动画的硬件加速音频。RAM 极度受限。 |
| 32-bit Windows/SDL2 | OpenGL 1.1 | 使用 SDL2 和 OpenAL Soft 的 Windows 编译。DirectX 依赖项已被 SDL2 和 OpenAL 取代。目标平台为 Windows XP 至 Windows 7 |
| Emscripten/WebAssembly | WebGL 2/OpenGL ES 3 | 使用 SDL2 和 OpenAL 的 WebAssembly。在 Web 浏览器中运行。由于 WASM 仅支持 32 位指针,这比 64 位版本可能更少出现错误,但性能较低。 |
以下实现正在进行中或已计划:
| 配置 | 渲染器 | 描述 | 状态 |
|---|---|---|---|
| iOS | Metal? | 不是最高优先级,但最好能实现。 | 未开始 |
| Switch libnx | OpenGL ES 3 | 不是最高优先级,但最好能实现。 | 未开始 |
| 32 位 Windows/SDL2 | OpenGL 3.3 | 使用 SDL2 和 OpenAL 进行 Windows 编译。DirectX 依赖项被替换为 SDL2 和 OpenAL。目标为 Windows XP ~ Windows 7 | 未开始 |
| 32 位 Windows/DirectX | Direct3D 3 | 使用原始 DirectX 绑定/渲染器的忠实反编译。 | 未开始 |
以下配置已弃用:
| 配置 | 渲染器 | 描述 |
|---|---|---|
| x86 Linux/SDL2, mmap blobs | OpenGL 3.3 | 使用 SDL2 和 OpenAL 进行 32 位 Linux 编译。JK.EXE 被内存映射到进程中并用作“二进制 blob”;未实现的函数将回退到 JK.EXE 的实现。 |
| 32 位 Linux/SDL2, blobless | OpenGL 3.3 | 使用 SDL2 和 OpenAL 进行 32 位 Linux 编译。输出的可执行文件是 JK.EXE 的替换版本,但会缺少功能,并在遇到未实现的代码时崩溃。 |
| x86 Win32/MinGW DLL | Software/DirectX | Win32 挂钩构建,JK.EXE 被修补以在 JK.EXE 的 main 函数之前加载 df2_reimpl.dll 并执行 hook_init_win。未实现的函数将回退到 JK.EXE 的实现。df2_reimpl_kvm.dll 用于 KVM 目标 |
Linux 构建在 AArch64/RPi4 上使用 llvmpipe 可以正常工作,但 V3D GLES 在处理调色板时存在问题。
OpenJKDF2 需要来自《Jedi Knight: Dark Forces II》正版副本的游戏数据才能运行;OpenJKDF2 不提供任何游戏资源。在 Linux 上,路径和文件名可能区分大小写。您的目录结构应类似于以下内容:
.
├── JK.EXE
├── MUSIC
│ ├── Track12.ogg
│ ├── Track13.ogg
│ ├── Track14.ogg
│ ├── Track15.ogg
│ ├── Track16.ogg
│ ├── Track17.ogg
│ ├── Track18.ogg
│ ├── Track22.ogg
│ ├── Track23.ogg
│ ├── Track24.ogg
│ ├── Track25.ogg
│ ├── Track26.ogg
│ ├── Track27.ogg
│ ├── Track28.ogg
│ ├── Track29.ogg
│ ├── Track30.ogg
│ ├── Track31.ogg
│ └── Track32.ogg
├── episode
│ ├── JK1.gob
│ ├── JK1CTF.gob
│ └── JK1MP.gob
├── openjkdf2-64
├── player
└── resource
├── Res1hi.gob
├── Res2.gob
├── jk_.cd
└── video
├── 01-02A.SMK
├── 03-04A.SMK
├── 06A.SMK
├── 08-10A.SMK
├── 12A.SMK
├── 16A.SMK
├── 18-19A.SMK
├── 21A.SMK
├── 23A.SMK
├── 25A.SMK
├── 27A.SMK
├── 33-34A.SMK
├── 36A.SMK
├── 38A.SMK
├── 39A.SMK
├── 41-42A.SMK
├── 41DA.SMK
├── 41DSA.SMK
├── 44A.SMK
├── 46A.SMK
├── 48A.SMK
├── 50A.SMK
├── 52-53A.SMK
├── 54A.SMK
└── 57A.SMK
构建
请参阅此处获取说明。
贡献
非常欢迎以代码清理和文档形式进行的贡献。请参阅 CONTRIBUTING.md 了解仍需要完成的清理任务类型的详细信息。OpenJKDF2 目前不接受货币捐赠,但始终欢迎详细的错误和崩溃报告,包括涉及模组(mods)的错误/崩溃。
简而言之:尚未实现的功能
- 在 设置 > 控制 > 选项 中加载配置和保存配置
- 使用加号或减号调整屏幕大小(使用 SDL2 时,分辨率会自动调整为窗口大小)
使用原始 JK.EXE 和 DirectX 通过钩子(hooks)使用
请参阅此处获取说明。
方法论
大部分研究和文档工作在 IDA 中进行。每个函数都已识别到文件前缀(例如 stdHashTable_),并对应一个 .c/.h 文件。RenderDroid(rd*)和 LEC 标准库(std*)函数有 90% 采用了规范命名,基于《Grim Fandango Remastered》中的符号。
逆向工程是结构文档化与功能识别之间的并行工作。一旦结构得到充分文档化,即可使用 Hex-Rays 进行反编译。虽然大多数 Hex-Rays 输出可直接使用,但许多循环和结构需要人工干预。输出通常会被清理和整理,以移除冗余的栈变量或过深的嵌套。sizeof 以及明显的内联和宏也应酌情调整。
引擎变量和尚未反编译的函数分别使用 define 宏和静态函数指针进行引用。当一个文件反编译到某个引擎变量不再被未反编译的代码引用时,可以在各自的 C 文件中声明这些变量。对于仅被未反编译函数引用的已反编译函数,会在 main.c 中添加一个 hook_function 调用,将代码执行从 JK.EXE 重定向到 df2_reimpl.dll。
使用 analyze.py、output.map 和 ida_copypaste_funclist_nostdlib.txt 来跟踪进度:编译 df2_reimpl.dll 后,可以将符号与 .idb 进行比较,以确定原始 .text 中有多少实际在使用,以及有多少已被挂钩并替换。
如果您希望获得我的 IDB 副本以检查尚未反编译的函数(或用于其他用途),请告诉我。
当前进度
使用 analyze.py 生成。某些文件名可能不准确或不完整(请参阅 ida_copypaste_funclist_nostdlib.txt 获取完整的函数名称列表)。
[file] [size] [% of text] [% complete] [decomp / total]
DirectX 0x1e 0.003% 100.000% 5 / 5
jkGob 0x29 0.004% 100.000% 2 / 2
jkGuiDecision 0x45 0.006% 100.000% 3 / 3
sithStrTable 0x5b 0.008% 100.000% 4 / 4
sithCopyright 0x67 0.010% 100.000% 1 / 1
jkStrings 0x89 0.013% 100.000% 5 / 5
jkGuiGeneral 0xc5 0.018% 100.000% 3 / 3
jkSmack 0xee 0.022% 100.000% 4 / 4
rdFace 0xf6 0.023% 100.000% 4 / 4
jkGuiControlOptions 0x105 0.024% 100.000% 3 / 3
stdHashKey 0x107 0.024% 100.000% 10 / 10
rdCanvas 0x113 0.025% 100.000% 4 / 4
jkGuiEsc 0x18f 0.037% 100.000% 3 / 3
rdroid 0x1f6 0.047% 100.000% 27 / 27
sithHeader 0x1f9 0.047% 100.000% 1 / 1
sithTime 0x213 0.049% 100.000% 6 / 6
jkGuiSingleTally 0x21b 0.050% 100.000% 4 / 4
jkGuiSetup 0x240 0.053% 100.000% 4 / 4
jkGuiSound 0x274 0.058% 100.000% 3 / 3
sithItem 0x275 0.058% 100.000% 5 / 5
jkGuiGameplay 0x2b2 0.064% 100.000% 3 / 3
stdMemory 0x2ba 0.065% 100.000% 7 / 7
sithEvent 0x2e3 0.069% 100.000% 9 / 9
stdMci 0x2ef 0.070% 100.000% 7 / 7
jkGuiObjectives 0x308 0.072% 100.000% 4 / 4
jkControl 0x331 0.076% 100.000% 4 / 4
Windows 0x39a 0.085% 100.000% 11 / 11
stdString 0x3b3 0.088% 100.000% 11 / 11
sithRenderSky 0x3c2 0.089% 100.000% 5 / 5
jkGuiDialog 0x3e0 0.092% 100.000% 6 / 6
sithModel 0x3f1 0.094% 100.000% 8 / 8
rdThing 0x42f 0.099% 100.000% 12 / 12
stdGdi 0x430 0.099% 100.000% 10 / 10
jkCutscene 0x443 0.101% 100.000% 7 / 7
sithKeyFrame 0x44e 0.102% 100.000% 5 / 5
stdPcx 0x45e 0.104% 100.000% 2 / 2
sithDSSCog 0x460 0.104% 100.000% 4 / 4
smack 0x466 0.104% 100.000% 6 / 6
sithPlayerActions 0x46f 0.105% 100.000% 3 / 3
rdMath 0x47d 0.107% 100.000% 6 / 6
rdLight 0x49f 0.110% 100.000% 8 / 8
jkGuiMain 0x4b1 0.111% 100.000% 6 / 6
stdFnames 0x4ee 0.117% 100.000% 14 / 14
sithSprite 0x4f1 0.117% 100.000% 6 / 6
jkGui 0x4fb 0.118% 100.000% 10 / 10
jkGuiTitle 0x4fb 0.118% 100.000% 10 / 10
sithMaterial 0x4fd 0.118% 100.000% 9 / 9
wuRegistry 0x5b2 0.135% 100.000% 12 / 12
stdHashTable 0x5d6 0.138% 100.000% 10 / 10
Video 0x5dc 0.139% 100.000% 5 / 5
sithConsole 0x5de 0.139% 100.000% 13 / 13
sithExplosion 0x61d 0.145% 100.000% 4 / 4
sithAIClass 0x689 0.155% 100.000% 7 / 7
rdPrimit2 0x69a 0.157% 100.000% 5 / 5
sithCogScript 0x6ca 0.161% 100.000% 9 / 9
Window 0x6db 0.163% 100.000% 13 / 13
stdGob 0x6dd 0.163% 100.000% 14 / 14
jkAI 0x6e7 0.164% 100.000% 5 / 5
sithMain 0x72b 0.170% 100.000% 16 / 16
jkGuiControlSaveLoad 0x732 0.171% 100.000% 6 / 6
jkGuiPlayer 0x73a 0.171% 100.000% 5 / 5
rdSprite 0x76d 0.176% 100.000% 5 / 5
stdConffile 0x78d 0.179% 100.000% 13 / 13
jkGuiMap 0x793 0.180% 100.000% 8 / 8
sithTemplate 0x79d 0.181% 100.000% 10 / 10
sithParticle 0x7f5 0.189% 100.000% 10 / 10
sithSector 0x806 0.190% 100.000% 13 / 13
sithComm 0x80b 0.191% 100.000% 11 / 11
sithMap 0x814 0.192% 100.000% 6 / 6
Main 0x87b 0.201% 100.000% 4 / 4
jkGuiMultiTally 0x8aa 0.206% 100.000% 7 / 7
jkGuiSingleplayer 0x8d8 0.210% 100.000% 7 / 7
jkCredits 0x8e4 0.211% 100.000% 6 / 6
sithCogFunctionSector 0x93a 0.219% 100.000% 22 / 22
sithCogFunctionAI 0x943 0.220% 100.000% 20 / 20
stdSound 0x9bf 0.231% 100.000% 27 / 27
sithGamesave 0x9bf 0.231% 100.000% 7 / 7
jkGuiForce 0x9dd 0.234% 100.000% 11 / 11
sithSound 0xa00 0.237% 100.000% 13 / 13
rdParticle 0xa0d 0.239% 100.000% 10 / 10
rdMaterial 0xa2d 0.241% 100.000% 9 / 9
sithSoundClass 0xa46 0.244% 100.000% 16 / 16
sithCogFunctionSound 0xa97 0.251% 100.000% 14 / 14
rdKeyframe 0xa99 0.251% 100.000% 8 / 8
rdCamera 0xaa8 0.253% 100.000% 26 / 26
jkGuiSaveLoad 0xb21 0.264% 100.000% 9 / 9
rdPolyLine 0xb42 0.267% 100.000% 6 / 6
jkSaber 0xb54 0.269% 100.000% 8 / 8
jkGuiKeyboard 0xb57 0.269% 100.000% 14 / 14
jkGuiNetHost 0xbc6 0.279% 100.000% 6 / 6
sithOverlayMap 0xbf8 0.284% 100.000% 9 / 9
rdVector 0xd29 0.312% 100.000% 55 / 55
jkGuiMouse 0xdb5 0.325% 100.000% 14 / 14
DirectDraw 0xdd4 0.328% 100.000% 16 / 16
jkEpisode 0xdd9 0.329% 100.000% 10 / 10
sithCogFunctionPlayer 0xdf0 0.331% 100.000% 42 / 42
jkHudInv 0xe43 0.338% 100.000% 9 / 9
sithCogFunctionSurface 0xe92 0.346% 100.000% 38 / 38
sithActor 0xf9c 0.370% 100.000% 13 / 13
stdConsole 0xfff 0.380% 100.000% 20 / 20
jkGuiMultiplayer 0x1097 0.394% 100.000% 13 / 13
DirectPlay 0x10cc 0.399% 100.000% 31 / 31
VBuffer 0x10dc 0.400% 100.000% 4 / 4
jkCog 0x11b8 0.420% 100.000% 40 / 40
stdControl 0x11ec 0.425% 100.000% 22 / 22
sithPuppet 0x1222 0.430% 100.000% 17 / 17
sithCamera 0x124b 0.434% 100.000% 23 / 23
jkGuiDisplay 0x12ff 0.451% 100.000% 11 / 11
jkGuiJoystick 0x13f0 0.473% 100.000% 19 / 19
jkDSS 0x13f6 0.474% 100.000% 32 / 32
sithCogYACC 0x152b 0.502% 100.000% 10 / 10
jkRes 0x15b6 0.515% 100.000% 23 / 23
jkMain 0x16cd 0.541% 100.000% 53 / 53
sithWorld 0x1718 0.548% 100.000% 22 / 22
sithDSS 0x175d 0.554% 100.000% 22 / 22
stdMath 0x182a 0.573% 100.000% 23 / 23
rdActive 0x1a55 0.625% 100.000% 8 / 8
sithCogExec 0x1aec 0.639% 100.000% 31 / 31
sithCogParse 0x1b2a 0.645% 100.000% 26 / 26
jkHud 0x1c9b 0.679% 100.000% 17 / 17
jkDev 0x1fd6 0.755% 100.000% 41 / 41
sithInventory 0x2150 0.791% 100.000% 62 / 62
sithDSSThing 0x22aa 0.823% 100.000% 37 / 37
sithRender 0x23de 0.851% 100.000% 22 / 22
jkGuiBuildMulti 0x258b 0.891% 100.000% 24 / 24
sithSoundMixer 0x2626 0.905% 100.000% 37 / 37
stdDisplay 0x267b 0.913% 100.000% 37 / 37
sithCogFunction 0x26c2 0.920% 100.000% 119 / 119
sithAI 0x2771 0.936% 100.000% 35 / 35
rdModel3 0x2a7e 1.008% 100.000% 23 / 23
std3D 0x2c4a 1.051% 100.000% 39 / 39
rdMatrix 0x2c85 1.056% 100.000% 56 / 56
sithAICmd 0x2cc0 1.062% 100.000% 22 / 22
jkGuiRend 0x2cd7 1.064% 100.000% 68 / 68
jkPlayer 0x2da2 1.083% 100.000% 45 / 45
sithPhysics 0x310b 1.164% 100.000% 13 / 13
sithWeapon 0x32a8 1.202% 100.000% 33 / 33
rdCache 0x331c 1.213% 100.000% 16 / 16
sithCogFunctionThing 0x3a4c 1.383% 100.000% 142 / 142
rdClip 0x81f2 3.084% 100.000% 17 / 17
sithAIAwareness 0x31f 0.074% 90.488% 5 / 6
stdComm 0x53c 0.124% 98.955% 16 / 17
stdFileUtil 0x687 0.155% 54.159% 6 / 11
stdBmp 0x6b8 0.159% 0.000% 0 / 3
sithAnimClass 0x6cc 0.161% 94.080% 4 / 5
stdStrTable 0x7b6 0.183% 82.877% 4 / 6
stdColor 0x97e 0.225% 24.198% 3 / 11
jkGame 0x98f 0.227% 80.384% 12 / 13
stdPalEffects 0xa66 0.247% 85.875% 16 / 21
stdLbm 0xc24 0.288% 0.000% 0 / 3
rdColormap 0xcf4 0.307% 47.738% 7 / 12
stdPlatform 0xdde 0.329% 49.042% 37 / 43
sithPlayer 0xe72 0.343% 95.944% 23 / 27
stdBitmap 0xeb6 0.349% 47.398% 6 / 14
sithTrackThing 0xf9f 0.371% 90.098% 12 / 15
rdPuppet 0x101f 0.383% 97.407% 15 / 19
stdGif 0x1162 0.412% 0.000% 0 / 4
sithCommand 0x11b2 0.420% 91.545% 18 / 20
sithIntersect 0x12a8 0.443% 92.588% 9 / 12
rdPrimit3 0x16e0 0.543% 91.684% 7 / 9
stdFont 0x181a 0.572% 75.284% 12 / 20
sithSurface 0x1c6a 0.674% 96.838% 33 / 35
sithCog 0x1ed3 0.731% 90.686% 21 / 28
sithMulti 0x252a 0.882% 91.423% 29 / 35
sithCollision 0x2827 0.953% 91.954% 19 / 22
sithControl 0x285a 0.958% 99.613% 31 / 33
sithThing 0x338c 1.223% 86.829% 43 / 49
rdRaster 0xf04d 5.702% 0.195% 1 / 89
rdZRaster 0x15fb4 8.346% 0.000% 0 / 73
rdAFRaster 0x1620d 8.402% 0.000% 0 / 122
rdNRaster 0x304d4 18.339% 0.000% 0 / 87
---------------------------------------------------------------------------------
Total completion:
-----------------
56.758% by weight
95.857% by weight excluding rasterizer
2694 / 3169 functions
2694 / 2798 functions excluding rasterizer
Subsystem Breakdown (Not Decomp'd)
----------------------------------
[subsys] [% of text] [TODO / total]
sith 0.542% 40 / 1319
stdPlatform 0.168% 6 / 43
std 1.494% 47 / 376
jkGui 0.000% 0 / 284
rd 0.216% 11 / 345
jk 0.044% 1 / 324
Raster 40.778% 370 / 371
other 0.000% 0 / 107
-----------------------------------------
total 43.242% 475 / 3169
Subsystem Breakdown (Not Decomp'd, Excl Raster)
-----------------------------------------------
[subsys] [% of text] [TODO / total]
sith 0.916% 40 / 1319
stdPlatform 0.283% 6 / 43
std 2.524% 47 / 376
jkGui 0.000% 0 / 284
rd 0.364% 11 / 345
jk 0.075% 1 / 324
other 0.000% 0 / 107
-----------------------------------------
total 4.162% 105 / 2798
另请参阅
- OpenJones3D — 姊妹项目,反编译《印第安纳·琼斯与魔域奇兵》,该项目基于相同的引擎和内部库
- OpenJK — 社区维护的开源引擎,适用于《绝地武士:奥德赛》(单人)和《绝地武士:学院》(单人与多人),它们是《黑暗力量 II》的续作。