Add DDGame engine architecture structs and subsystem types
Browse filesDefine DDGame (0x98B8), DDGameWrapper, PCLandscape, DSSound, and
OpenGLState repr(C) structs with compile-time size assertions.
Add 9 subsystem vtable addresses to address.rs. Document the
engine initialization chain and update memory map with DDGame layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- crates/openwa-types/src/address.rs +18 -0
- crates/openwa-types/src/ddgame.rs +103 -0
- crates/openwa-types/src/ddgame_wrapper.rs +45 -0
- crates/openwa-types/src/dssound.rs +44 -0
- crates/openwa-types/src/landscape.rs +61 -0
- crates/openwa-types/src/lib.rs +5 -0
- crates/openwa-types/src/opengl.rs +33 -0
- docs/re-notes/engine-init.md +74 -0
- docs/re-notes/memory-map.md +36 -2
crates/openwa-types/src/address.rs
CHANGED
|
@@ -26,6 +26,24 @@ pub mod va {
|
|
| 26 |
pub const CGAMETASK_VTABLE: u32 = 0x0066_41F8;
|
| 27 |
/// CGameTask secondary vtable (at object offset 0xE8)
|
| 28 |
pub const CGAMETASK_VTABLE2: u32 = 0x0066_9CF8;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
// === CTask vtable methods (at CTask__vtable) ===
|
| 31 |
|
|
|
|
| 26 |
pub const CGAMETASK_VTABLE: u32 = 0x0066_41F8;
|
| 27 |
/// CGameTask secondary vtable (at object offset 0xE8)
|
| 28 |
pub const CGAMETASK_VTABLE2: u32 = 0x0066_9CF8;
|
| 29 |
+
/// DDGameWrapper vtable
|
| 30 |
+
pub const DDGAME_WRAPPER_VTABLE: u32 = 0x0066_A30C;
|
| 31 |
+
/// GfxHandler vtable (0x19C-byte objects)
|
| 32 |
+
pub const GFX_HANDLER_VTABLE: u32 = 0x0066_B280;
|
| 33 |
+
/// DisplayGfx vtable
|
| 34 |
+
pub const DISPLAY_GFX_VTABLE: u32 = 0x0066_4144;
|
| 35 |
+
/// PCLandscape vtable
|
| 36 |
+
pub const PC_LANDSCAPE_VTABLE: u32 = 0x0066_B208;
|
| 37 |
+
/// LandscapeShader vtable
|
| 38 |
+
pub const LANDSCAPE_SHADER_VTABLE: u32 = 0x0066_B1DC;
|
| 39 |
+
/// DSSound vtable
|
| 40 |
+
pub const DS_SOUND_VTABLE: u32 = 0x0066_AF20;
|
| 41 |
+
/// TaskStateMachine vtable
|
| 42 |
+
pub const TASK_STATE_MACHINE_VTABLE: u32 = 0x0066_4118;
|
| 43 |
+
/// OpenGLCPU vtable (0x48-byte object)
|
| 44 |
+
pub const OPENGL_CPU_VTABLE: u32 = 0x0067_74C0;
|
| 45 |
+
/// WaterEffect vtable (0xBC-byte object)
|
| 46 |
+
pub const WATER_EFFECT_VTABLE: u32 = 0x0066_B268;
|
| 47 |
|
| 48 |
// === CTask vtable methods (at CTask__vtable) ===
|
| 49 |
|
crates/openwa-types/src/ddgame.rs
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use crate::task::Ptr32;
|
| 2 |
+
|
| 3 |
+
/// DDGame β the main game engine object.
|
| 4 |
+
///
|
| 5 |
+
/// This is a massive ~39KB struct (0x98B8 bytes) that owns all major subsystems:
|
| 6 |
+
/// display, landscape, sound, graphics handlers, and task state machines.
|
| 7 |
+
///
|
| 8 |
+
/// Allocated in DDGame__Constructor (0x56E220).
|
| 9 |
+
/// Vtable set via DDGameWrapper at 0x66A30C.
|
| 10 |
+
///
|
| 11 |
+
/// PARTIAL: Only landmark offsets are defined. The vast majority of fields
|
| 12 |
+
/// are unknown. Use the offset constants below for field access.
|
| 13 |
+
///
|
| 14 |
+
/// Note: Ghidra decompiles DDGame constructor with DWORD-indexed offsets
|
| 15 |
+
/// (param_2[0x122] etc.), but these are byte offsets in the struct below.
|
| 16 |
+
/// Conversion: dword_index * 4 = byte_offset.
|
| 17 |
+
#[repr(C)]
|
| 18 |
+
pub struct DDGame {
|
| 19 |
+
/// 0x0000-0x0023: Header region
|
| 20 |
+
pub _header: [u8; 0x24],
|
| 21 |
+
/// 0x0024: Game state pointer
|
| 22 |
+
pub game_state: Ptr32,
|
| 23 |
+
/// 0x0028: Unknown parameter from constructor
|
| 24 |
+
pub _param_28: Ptr32,
|
| 25 |
+
/// 0x002C-0x11AF: Unknown fields
|
| 26 |
+
pub _unknown_002c: [u8; 0x1184],
|
| 27 |
+
/// 0x11B0-0x11BF: Task objects region (5 state machine pointers)
|
| 28 |
+
/// Ghidra: param[0x46C..0x47C] (dword-indexed)
|
| 29 |
+
pub task_ptrs: [Ptr32; 5],
|
| 30 |
+
/// 0x11C4-0x1217: Unknown
|
| 31 |
+
pub _unknown_11c4: [u8; 0x54],
|
| 32 |
+
/// 0x1218-0x1223: Game global / WormKit-known offsets area
|
| 33 |
+
/// Note: WormKit documents DDGame+0x488 as game_global, but that's
|
| 34 |
+
/// relative to the DDGame ptr held in DDGameWrapper[0x122].
|
| 35 |
+
/// Since DDGameWrapper[0x122] points to THIS struct at offset 0,
|
| 36 |
+
/// these WormKit offsets map directly.
|
| 37 |
+
pub _unknown_1218: [u8; 0x270],
|
| 38 |
+
/// 0x1488-0x3547: Unknown fields
|
| 39 |
+
pub _unknown_1488: [u8; 0x20C0],
|
| 40 |
+
/// 0x3548: Display mode pointer
|
| 41 |
+
pub display_mode: Ptr32,
|
| 42 |
+
/// 0x354C: Display width
|
| 43 |
+
pub display_width: u32,
|
| 44 |
+
/// 0x3550: Display param (init 0)
|
| 45 |
+
pub _display_3550: u32,
|
| 46 |
+
/// 0x3554: Display param (init 0)
|
| 47 |
+
pub _display_3554: u32,
|
| 48 |
+
/// 0x3558-0x355F: Unknown
|
| 49 |
+
pub _unknown_3558: [u8; 8],
|
| 50 |
+
/// 0x3560: Display center X (width / 2)
|
| 51 |
+
pub display_center_x: u32,
|
| 52 |
+
/// 0x3564: Display center Y (height / 2)
|
| 53 |
+
pub display_center_y: u32,
|
| 54 |
+
/// 0x3568-0x3577: Unknown
|
| 55 |
+
pub _unknown_3568: [u8; 0x10],
|
| 56 |
+
/// 0x3578: Window handle (HWND)
|
| 57 |
+
pub hwnd: Ptr32,
|
| 58 |
+
/// 0x357C-0x358C: Unknown
|
| 59 |
+
pub _unknown_357c: [u8; 0x11],
|
| 60 |
+
/// 0x358D-0x398C: Palette entries (0x100 * 4 = 1024 bytes)
|
| 61 |
+
pub palette: [u8; 0x400],
|
| 62 |
+
/// 0x398D-0x3D8F: Unknown display fields
|
| 63 |
+
pub _unknown_398d: [u8; 0x403],
|
| 64 |
+
/// 0x3D90: Graphics constant (init 0x100)
|
| 65 |
+
pub _gfx_3d90: u32,
|
| 66 |
+
/// 0x3D94: Graphics constant (init 0xFFFFFFFF)
|
| 67 |
+
pub _gfx_3d94: u32,
|
| 68 |
+
/// 0x3D98: Graphics object pointers (4 entries)
|
| 69 |
+
pub gfx_objects: [Ptr32; 4],
|
| 70 |
+
/// 0x3DA8-0x98B7: Remaining fields
|
| 71 |
+
pub _unknown_3da8: [u8; 0x5B10],
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
const _: () = assert!(core::mem::size_of::<DDGame>() == 0x98B8);
|
| 75 |
+
|
| 76 |
+
/// Well-known byte offsets into DDGame, for use with raw pointer access.
|
| 77 |
+
///
|
| 78 |
+
/// These are sourced from WormKit, wkJellyWorm, and Ghidra decompilation.
|
| 79 |
+
/// WormKit documents offsets relative to DDGameWrapper[0x122] which points
|
| 80 |
+
/// to the DDGame allocation.
|
| 81 |
+
pub mod offsets {
|
| 82 |
+
/// Game state pointer
|
| 83 |
+
pub const GAME_STATE: usize = 0x0024;
|
| 84 |
+
|
| 85 |
+
/// Task state machine pointers (5 entries, each Ptr32)
|
| 86 |
+
pub const TASK_PTRS: usize = 0x11B0;
|
| 87 |
+
|
| 88 |
+
/// Display mode pointer
|
| 89 |
+
pub const DISPLAY_MODE: usize = 0x3548;
|
| 90 |
+
/// Display width
|
| 91 |
+
pub const DISPLAY_WIDTH: usize = 0x354C;
|
| 92 |
+
/// Display center X
|
| 93 |
+
pub const DISPLAY_CENTER_X: usize = 0x3560;
|
| 94 |
+
/// Display center Y
|
| 95 |
+
pub const DISPLAY_CENTER_Y: usize = 0x3564;
|
| 96 |
+
/// Window handle (HWND)
|
| 97 |
+
pub const HWND: usize = 0x3578;
|
| 98 |
+
/// Palette start (0x400 bytes)
|
| 99 |
+
pub const PALETTE: usize = 0x358D;
|
| 100 |
+
|
| 101 |
+
/// Graphics object pointers (from DDDisplay__Init)
|
| 102 |
+
pub const GFX_OBJECTS: usize = 0x3D98;
|
| 103 |
+
}
|
crates/openwa-types/src/ddgame_wrapper.rs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use crate::task::Ptr32;
|
| 2 |
+
|
| 3 |
+
/// DDGameWrapper β thin wrapper around DDGame.
|
| 4 |
+
///
|
| 5 |
+
/// This is the top-level object created by DDGameWrapper__Constructor (0x56DEF0).
|
| 6 |
+
/// It holds a pointer to the DDGame allocation and graphics handler references.
|
| 7 |
+
///
|
| 8 |
+
/// Vtable: 0x66A30C
|
| 9 |
+
///
|
| 10 |
+
/// Note: Ghidra shows DWORD-indexed offsets (param_1[0x122] etc.).
|
| 11 |
+
/// Byte offset = dword_index * 4.
|
| 12 |
+
///
|
| 13 |
+
/// PARTIAL: Only confirmed fields from the constructor are defined.
|
| 14 |
+
#[repr(C)]
|
| 15 |
+
pub struct DDGameWrapper {
|
| 16 |
+
/// 0x000: Vtable pointer (0x66A30C)
|
| 17 |
+
pub vtable: Ptr32,
|
| 18 |
+
/// 0x004-0x487: Unknown fields
|
| 19 |
+
pub _unknown_004: [u8; 0x484],
|
| 20 |
+
/// 0x488: Pointer to DDGame allocation
|
| 21 |
+
pub ddgame: Ptr32,
|
| 22 |
+
/// 0x48C: Secondary DDGame struct pointer (0x2C bytes, conditional)
|
| 23 |
+
pub ddgame_secondary: Ptr32,
|
| 24 |
+
/// 0x490-0x4BF: Unknown
|
| 25 |
+
pub _unknown_490: [u8; 0x30],
|
| 26 |
+
/// 0x4C0: Graphics handler 0 pointer (0x19C bytes, vtable 0x66B280)
|
| 27 |
+
pub gfx_handler_0: Ptr32,
|
| 28 |
+
/// 0x4C4: Graphics handler 1 pointer (optional)
|
| 29 |
+
pub gfx_handler_1: Ptr32,
|
| 30 |
+
/// 0x4C8: Graphics mode flag
|
| 31 |
+
pub gfx_mode: u32,
|
| 32 |
+
/// 0x4CC: PCLandscape object pointer
|
| 33 |
+
pub landscape: Ptr32,
|
| 34 |
+
/// 0x4D0: Constructor param_2
|
| 35 |
+
pub _param_4d0: u32,
|
| 36 |
+
/// 0x4D4: Constructor param_3
|
| 37 |
+
pub _param_4d4: u32,
|
| 38 |
+
/// 0x4D8-end: Unknown trailing fields
|
| 39 |
+
/// Size uncertain β DDGameWrapper total size not yet determined
|
| 40 |
+
pub _unknown_4d8: [u8; 0x28],
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
// DDGameWrapper total size is uncertain. This is a minimum based on known fields.
|
| 44 |
+
// Remove or update this assertion when the true size is determined.
|
| 45 |
+
const _: () = assert!(core::mem::size_of::<DDGameWrapper>() == 0x500);
|
crates/openwa-types/src/dssound.rs
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use crate::fixed::Fixed;
|
| 2 |
+
use crate::task::Ptr32;
|
| 3 |
+
|
| 4 |
+
/// DSSound β DirectSound audio subsystem.
|
| 5 |
+
///
|
| 6 |
+
/// Created by DSSound__Constructor (0x573D50).
|
| 7 |
+
/// Vtable: 0x66AF20
|
| 8 |
+
///
|
| 9 |
+
/// Manages sound playback through DirectSound.
|
| 10 |
+
/// Has 500 sound channel slots and a master volume control.
|
| 11 |
+
///
|
| 12 |
+
/// PARTIAL: Only constructor-confirmed fields.
|
| 13 |
+
/// Ghidra uses DWORD-indexed offsets.
|
| 14 |
+
#[repr(C)]
|
| 15 |
+
pub struct DSSound {
|
| 16 |
+
/// 0x000: Vtable pointer (0x66AF20)
|
| 17 |
+
pub vtable: Ptr32,
|
| 18 |
+
/// 0x004: Unknown
|
| 19 |
+
pub _unknown_004: [u8; 4],
|
| 20 |
+
/// 0x008: Init field (set to 0)
|
| 21 |
+
pub _field_008: u32,
|
| 22 |
+
/// 0x00C: Init field (set to 0)
|
| 23 |
+
pub _field_00c: u32,
|
| 24 |
+
/// 0x010: Init field (set to 0)
|
| 25 |
+
pub _field_010: u32,
|
| 26 |
+
/// 0x014-0x8A3: Unknown fields
|
| 27 |
+
pub _unknown_014: [u8; 0x890],
|
| 28 |
+
/// 0x8A4: Master volume (Fixed, init 0x10000 = 1.0)
|
| 29 |
+
pub volume: Fixed,
|
| 30 |
+
/// 0x8A8-0xBB3: Unknown (includes 500-entry channel slot table)
|
| 31 |
+
pub _unknown_8a8: [u8; 0x30C],
|
| 32 |
+
/// 0xBB4: Status flag 1 (init 1)
|
| 33 |
+
pub status_1: u32,
|
| 34 |
+
/// 0xBB8: Status flag 2 (init 1)
|
| 35 |
+
pub status_2: u32,
|
| 36 |
+
/// 0xBBC: Status flag 3 (init 0)
|
| 37 |
+
pub status_3: u32,
|
| 38 |
+
/// 0xBC0-end: Unknown trailing fields
|
| 39 |
+
pub _unknown_bc0: [u8; 0x10],
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
// Total size uncertain β this is an estimate based on constructor analysis.
|
| 43 |
+
// The 500 dword channel table starts around offset 0xD4+ but exact layout unclear.
|
| 44 |
+
const _: () = assert!(core::mem::size_of::<DSSound>() == 0xBD0);
|
crates/openwa-types/src/landscape.rs
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use crate::task::Ptr32;
|
| 2 |
+
|
| 3 |
+
/// PCLandscape β terrain/landscape subsystem.
|
| 4 |
+
///
|
| 5 |
+
/// Created by PCLandscape__Constructor (0x57ACB0).
|
| 6 |
+
/// Vtable: 0x66B208
|
| 7 |
+
///
|
| 8 |
+
/// Manages terrain data, water effects, and level graphics.
|
| 9 |
+
/// Loads Water.dir and Level.dir from `data\Gfx\`.
|
| 10 |
+
/// Allocates a 384KB (0x60000) terrain buffer.
|
| 11 |
+
///
|
| 12 |
+
/// PARTIAL: Only constructor-confirmed fields are defined.
|
| 13 |
+
/// Ghidra uses DWORD-indexed offsets (param_1[0x240] etc.).
|
| 14 |
+
/// Byte offset = dword_index * 4.
|
| 15 |
+
#[repr(C)]
|
| 16 |
+
pub struct PCLandscape {
|
| 17 |
+
/// 0x000: Vtable pointer (0x66B208)
|
| 18 |
+
pub vtable: Ptr32,
|
| 19 |
+
/// 0x004: Parent DDGame pointer
|
| 20 |
+
pub ddgame: Ptr32,
|
| 21 |
+
/// 0x008-0x0C7: Unknown
|
| 22 |
+
pub _unknown_008: [u8; 0xC0],
|
| 23 |
+
/// 0x0C8: Water effect object pointer (0xBC bytes, vtable 0x66B268)
|
| 24 |
+
pub water_effect: Ptr32,
|
| 25 |
+
/// 0x0CC-0x8E7: Unknown fields (terrain metadata, dimensions, etc.)
|
| 26 |
+
pub _unknown_0cc: [u8; 0x81C],
|
| 27 |
+
/// 0x8E8: Terrain buffer pointer (0x60000 bytes allocated)
|
| 28 |
+
pub terrain_buffer: Ptr32,
|
| 29 |
+
/// 0x8EC-0x8EF: Buffer size (0x60000)
|
| 30 |
+
pub _terrain_size: [u8; 4],
|
| 31 |
+
/// 0x8F0-0x90F: Unknown
|
| 32 |
+
pub _unknown_8f0: [u8; 0x20],
|
| 33 |
+
/// 0x910-0x913: Terrain handler pointer
|
| 34 |
+
pub terrain_handler: Ptr32,
|
| 35 |
+
/// 0x914: Initialized flag (set to 1)
|
| 36 |
+
pub initialized: u32,
|
| 37 |
+
/// 0x918-0x92F: Terrain directory path pointers
|
| 38 |
+
pub _dir_paths: [u8; 0x18],
|
| 39 |
+
/// 0x930: Splash buffer pointer (0x4C bytes)
|
| 40 |
+
pub splash_buffer: Ptr32,
|
| 41 |
+
/// 0x934: Terrain data pointer
|
| 42 |
+
pub terrain_data: Ptr32,
|
| 43 |
+
/// 0x938: Palette pointer
|
| 44 |
+
pub palette: Ptr32,
|
| 45 |
+
/// 0x93C: Shader object pointer (vtable 0x66B1DC)
|
| 46 |
+
pub shader: Ptr32,
|
| 47 |
+
/// 0x940-0x947: Surface texture buffer pointers
|
| 48 |
+
pub surface_textures: [Ptr32; 2],
|
| 49 |
+
/// 0x948-0x94B: Unknown
|
| 50 |
+
pub _unknown_948: [u8; 4],
|
| 51 |
+
/// 0x94C-0xB33: Unknown
|
| 52 |
+
pub _unknown_94c: [u8; 0x1E8],
|
| 53 |
+
/// 0xB34: Water .dir file handle
|
| 54 |
+
pub water_dir_handle: Ptr32,
|
| 55 |
+
/// 0xB38: Level .dir file handle
|
| 56 |
+
pub level_dir_handle: Ptr32,
|
| 57 |
+
/// 0xB3C-0xB3F: Trailing padding
|
| 58 |
+
pub _unknown_b3c: [u8; 4],
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
const _: () = assert!(core::mem::size_of::<PCLandscape>() == 0xB40);
|
crates/openwa-types/src/lib.rs
CHANGED
|
@@ -5,4 +5,9 @@ pub mod sound;
|
|
| 5 |
pub mod sprite;
|
| 6 |
pub mod fixed;
|
| 7 |
pub mod task;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
pub mod address;
|
|
|
|
| 5 |
pub mod sprite;
|
| 6 |
pub mod fixed;
|
| 7 |
pub mod task;
|
| 8 |
+
pub mod ddgame;
|
| 9 |
+
pub mod ddgame_wrapper;
|
| 10 |
+
pub mod landscape;
|
| 11 |
+
pub mod dssound;
|
| 12 |
+
pub mod opengl;
|
| 13 |
pub mod address;
|
crates/openwa-types/src/opengl.rs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
use crate::task::Ptr32;
|
| 2 |
+
|
| 3 |
+
/// OpenGLState β CPU-side OpenGL state object.
|
| 4 |
+
///
|
| 5 |
+
/// Created by OpenGLCPU__Constructor (0x5A0850).
|
| 6 |
+
/// Vtable: 0x6774C0
|
| 7 |
+
///
|
| 8 |
+
/// Small object (0x48 bytes) holding OpenGL rendering state.
|
| 9 |
+
/// The actual OpenGL context (HDC, HGLRC) is stored in DDDisplay
|
| 10 |
+
/// fields during OpenGL__Init (0x59F000).
|
| 11 |
+
#[repr(C)]
|
| 12 |
+
pub struct OpenGLState {
|
| 13 |
+
/// 0x00: Vtable pointer (0x6774C0)
|
| 14 |
+
pub vtable: Ptr32,
|
| 15 |
+
/// 0x04-0x0F: Unknown
|
| 16 |
+
pub _unknown_04: [u8; 0x0C],
|
| 17 |
+
/// 0x10: Width
|
| 18 |
+
pub width: u32,
|
| 19 |
+
/// 0x14: Unknown (init 0)
|
| 20 |
+
pub _field_14: u32,
|
| 21 |
+
/// 0x18-0x23: Unknown (init 0)
|
| 22 |
+
pub _unknown_18: [u8; 0x0C],
|
| 23 |
+
/// 0x24: Height
|
| 24 |
+
pub height: u32,
|
| 25 |
+
/// 0x28-0x3F: Unknown
|
| 26 |
+
pub _unknown_28: [u8; 0x18],
|
| 27 |
+
/// 0x40: Unknown (init 0)
|
| 28 |
+
pub _field_40: u32,
|
| 29 |
+
/// 0x44: Unknown (init 0)
|
| 30 |
+
pub _field_44: u32,
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
const _: () = assert!(core::mem::size_of::<OpenGLState>() == 0x48);
|
docs/re-notes/engine-init.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Engine Initialization Chain
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
|
| 5 |
+
WA.exe initializes the engine through a chain of constructor calls that build
|
| 6 |
+
the DDGame monolith and its subsystems. The top-level entry is
|
| 7 |
+
`ConstructDDGameWrapper` which allocates DDGame and wires up all subsystems.
|
| 8 |
+
|
| 9 |
+
## Call Chain
|
| 10 |
+
|
| 11 |
+
```
|
| 12 |
+
WinMain / CRT startup (0x5D8B6C)
|
| 13 |
+
ββ ConstructDDGameWrapper (0x56DEF0)
|
| 14 |
+
ββ Allocates DDGameWrapper (vtable 0x66A30C)
|
| 15 |
+
ββ DDGame__Constructor (0x56E220)
|
| 16 |
+
β ββ Allocates 0x98B8 bytes for DDGame
|
| 17 |
+
β ββ DDDisplay__Init (0x569D00)
|
| 18 |
+
β β ββ Sets display mode, dimensions, palette, HWND
|
| 19 |
+
β ββ GfxHandler x2 (vtable 0x66B280, 0x19C bytes each)
|
| 20 |
+
β ββ Task state machines x5 (vtable 0x664118)
|
| 21 |
+
β ββ Game state pointer at DDGame+0x24
|
| 22 |
+
ββ PCLandscape__Constructor (0x57ACB0)
|
| 23 |
+
β ββ vtable 0x66B208, parent = DDGame
|
| 24 |
+
β ββ Allocates terrain buffer (0x60000 bytes) at +0x8E8
|
| 25 |
+
β ββ Creates WaterEffect object (vtable 0x66B268) at +0xC8
|
| 26 |
+
β ββ Creates LandscapeShader (vtable 0x66B1DC) at +0x93C
|
| 27 |
+
β ββ Loads Water.dir, Level.dir from data\Gfx\
|
| 28 |
+
ββ DSSound__Constructor (0x573D50)
|
| 29 |
+
β ββ vtable 0x66AF20
|
| 30 |
+
β ββ Master volume = Fixed(0x10000) = 1.0 at +0x8A4
|
| 31 |
+
β ββ 500 sound channel slots
|
| 32 |
+
ββ OpenGLCPU__Constructor (0x5A0850) [conditional]
|
| 33 |
+
ββ vtable 0x6774C0, 0x48 bytes
|
| 34 |
+
ββ Width at +0x10, Height at +0x24
|
| 35 |
+
ββ OpenGL__Init (0x59F000) stores HDC/HGLRC in DDDisplay
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
## DDGameWrapper Layout
|
| 39 |
+
|
| 40 |
+
DDGameWrapper is a thin wrapper (~0x500 bytes) around DDGame:
|
| 41 |
+
|
| 42 |
+
| Offset | Field | Notes |
|
| 43 |
+
|--------|--------------------|------------------------------------|
|
| 44 |
+
| 0x000 | vtable | 0x66A30C |
|
| 45 |
+
| 0x488 | DDGame ptr | Allocated 0x98B8-byte object |
|
| 46 |
+
| 0x48C | DDGame secondary | Optional 0x2C-byte struct |
|
| 47 |
+
| 0x4C0 | GfxHandler 0 | 0x19C bytes, vtable 0x66B280 |
|
| 48 |
+
| 0x4C4 | GfxHandler 1 | Optional |
|
| 49 |
+
| 0x4C8 | GfxMode | Graphics mode flag |
|
| 50 |
+
| 0x4CC | PCLandscape | Pointer to landscape subsystem |
|
| 51 |
+
|
| 52 |
+
## DDGame Key Offsets
|
| 53 |
+
|
| 54 |
+
DDGame is a ~39KB (0x98B8 bytes) monolithic object. Known landmark fields:
|
| 55 |
+
|
| 56 |
+
| Offset | Field | Notes |
|
| 57 |
+
|--------|--------------------|------------------------------------|
|
| 58 |
+
| 0x0024 | game_state | Global game state pointer |
|
| 59 |
+
| 0x0028 | param | Constructor parameter |
|
| 60 |
+
| 0x11B0 | task_ptrs[5] | 5 task state machine pointers |
|
| 61 |
+
| 0x3548 | display_mode | Display mode pointer |
|
| 62 |
+
| 0x354C | display_width | Screen width |
|
| 63 |
+
| 0x3560 | display_center_x | Screen center X |
|
| 64 |
+
| 0x3564 | display_center_y | Screen center Y |
|
| 65 |
+
| 0x3578 | hwnd | Window handle |
|
| 66 |
+
| 0x358D | palette | 256-color palette (0x400 bytes) |
|
| 67 |
+
| 0x3D98 | gfx_objects[4] | Graphics object pointers |
|
| 68 |
+
|
| 69 |
+
## Ghidra Offset Convention
|
| 70 |
+
|
| 71 |
+
Ghidra's decompiler shows DWORD-indexed offsets for struct access:
|
| 72 |
+
- `param_1[0x122]` β byte offset 0x122 * 4 = **0x488**
|
| 73 |
+
- `param_1[0x133]` β byte offset 0x133 * 4 = **0x4CC**
|
| 74 |
+
- Always multiply DWORD index by 4 to get the true byte offset.
|
docs/re-notes/memory-map.md
CHANGED
|
@@ -21,14 +21,48 @@
|
|
| 21 |
|
| 22 |
## DDGame structure access
|
| 23 |
|
| 24 |
-
The main game state is
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
- DDGame+0x08 β TurnGame object
|
| 27 |
- DDGame+0x488 β Game global state
|
| 28 |
- DDGame+0x4CC β PC_Landscape
|
| 29 |
- DDGame+0x510 β Weapon table
|
| 30 |
- DDGame+0x548 β Weapon panel
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
## Fixed-point convention
|
| 33 |
|
| 34 |
All coordinates, velocities, and physics values use 16.16 fixed-point:
|
|
|
|
| 21 |
|
| 22 |
## DDGame structure access
|
| 23 |
|
| 24 |
+
The main game state is a 0x98B8-byte (39KB) monolithic object allocated by
|
| 25 |
+
`DDGame__Constructor` (0x56E220). It is wrapped by DDGameWrapper (0x56DEF0).
|
| 26 |
+
|
| 27 |
+
### DDGameWrapper offsets (from wrapper base)
|
| 28 |
+
- +0x488 β DDGame pointer (the allocated 0x98B8-byte object)
|
| 29 |
+
- +0x4C0 β GfxHandler 0 (vtable 0x66B280)
|
| 30 |
+
- +0x4CC β PCLandscape pointer
|
| 31 |
+
|
| 32 |
+
### DDGame offsets (from DDGame base)
|
| 33 |
+
- +0x0024 β Game state pointer
|
| 34 |
+
- +0x0028 β Constructor param
|
| 35 |
+
- +0x11B0 β Task state machine pointers (5 entries)
|
| 36 |
+
- +0x3548 β Display mode
|
| 37 |
+
- +0x354C β Display width
|
| 38 |
+
- +0x3560 β Display center X
|
| 39 |
+
- +0x3564 β Display center Y
|
| 40 |
+
- +0x3578 β HWND
|
| 41 |
+
- +0x358D β Palette (0x400 bytes)
|
| 42 |
+
- +0x3D98 β Gfx object pointers (4 entries)
|
| 43 |
+
|
| 44 |
+
### WormKit-convention offsets (DWORD-indexed)
|
| 45 |
+
These offsets are from the DDGameWrapper base, as used by WormKit mods:
|
| 46 |
- DDGame+0x08 β TurnGame object
|
| 47 |
- DDGame+0x488 β Game global state
|
| 48 |
- DDGame+0x4CC β PC_Landscape
|
| 49 |
- DDGame+0x510 β Weapon table
|
| 50 |
- DDGame+0x548 β Weapon panel
|
| 51 |
|
| 52 |
+
## Subsystem vtables
|
| 53 |
+
|
| 54 |
+
| Address | Object | Size | Notes |
|
| 55 |
+
|------------|-----------------|--------|---------------------------|
|
| 56 |
+
| 0x66A30C | DDGameWrapper | ~0x500 | Top-level wrapper |
|
| 57 |
+
| 0x66B280 | GfxHandler | 0x19C | 2 instances |
|
| 58 |
+
| 0x664144 | DisplayGfx | β | |
|
| 59 |
+
| 0x66B208 | PCLandscape | 0xB40 | Terrain, water, level |
|
| 60 |
+
| 0x66B1DC | LandscapeShader | β | Used by PCLandscape |
|
| 61 |
+
| 0x66B268 | WaterEffect | 0xBC | Created by PCLandscape |
|
| 62 |
+
| 0x66AF20 | DSSound | ~0xBD0 | DirectSound, 500 channels |
|
| 63 |
+
| 0x664118 | TaskStateMachine| β | 5 instances in DDGame |
|
| 64 |
+
| 0x6774C0 | OpenGLCPU | 0x48 | Optional, conditional |
|
| 65 |
+
|
| 66 |
## Fixed-point convention
|
| 67 |
|
| 68 |
All coordinates, velocities, and physics values use 16.16 fixed-point:
|