refactor: replace raw DDGame pointers with typed *mut DDGame
Browse filesChange CTask.ddgame, DDGameWrapper.ddgame, and PCLandscape.ddgame from
*mut u8 to *mut DDGame. Add named struct fields for crosshair line
params (0x7324/0x732C), fill_pixel (0x7338), and level dimensions
(0x77C0-0x77C8). Remove redundant casts and raw pointer arithmetic
in sound.rs, render.rs, input.rs, and validation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- crates/openwa-types/src/ddgame.rs +31 -13
- crates/openwa-types/src/ddgame_wrapper.rs +3 -1
- crates/openwa-types/src/landscape.rs +3 -1
- crates/openwa-types/src/task.rs +2 -1
- crates/openwa-wormkit/src/replacements/input.rs +5 -4
- crates/openwa-wormkit/src/replacements/render.rs +4 -6
- crates/openwa-wormkit/src/replacements/sound.rs +2 -2
- crates/openwa-wormkit/src/validation/mod.rs +4 -7
crates/openwa-types/src/ddgame.rs
CHANGED
|
@@ -76,20 +76,44 @@ pub struct DDGame {
|
|
| 76 |
pub _unknown_528: [u8; 0x20],
|
| 77 |
/// 0x548: Weapon panel pointer
|
| 78 |
pub weapon_panel: *mut u8,
|
| 79 |
-
/// 0x54C-
|
| 80 |
///
|
| 81 |
/// Known landmarks:
|
| 82 |
/// - 0x64D8: cleared by init
|
| 83 |
/// - 0x72A4: cleared by init
|
| 84 |
-
/// - 0x730C-
|
| 85 |
-
/// - 0x7338: fill pixel value
|
| 86 |
-
/// - 0x77C4: display-related value
|
| 87 |
-
/// - 0x7EF8: flag from game_state+0xF914
|
| 88 |
-
/// - 0x7EFC: init 1
|
| 89 |
///
|
| 90 |
/// Also includes FUN_00526120 zeroed offsets at stride 0x194:
|
| 91 |
/// 0x379C, 0x3930, 0x3AC4, 0x3C58, 0x3DEC, 0x3F80, 0x4114, 0x42A8, 0x443C, 0x45D0
|
| 92 |
-
pub _unknown_54c: [u8;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
|
| 94 |
// === Sound queue (0x7F00-0x8143) ===
|
| 95 |
/// 0x7F00: Sound queue (16 entries, stride 0x24). Appended by PlaySoundGlobal.
|
|
@@ -178,12 +202,6 @@ pub mod offsets {
|
|
| 178 |
pub const FIELD_64D8: usize = 0x64D8;
|
| 179 |
pub const FIELD_72A4: usize = 0x72A4;
|
| 180 |
pub const GFX_COLOR_ENTRIES: usize = 0x730C;
|
| 181 |
-
/// Crosshair line color param (DrawPolygon param_2). Part of GfxDir color entries.
|
| 182 |
-
pub const CROSSHAIR_LINE_PARAM_2: usize = 0x7324;
|
| 183 |
-
/// Crosshair line style param (DrawPolygon param_1). Part of GfxDir color entries.
|
| 184 |
-
pub const CROSSHAIR_LINE_PARAM_1: usize = 0x732C;
|
| 185 |
-
pub const FILL_PIXEL: usize = 0x7338;
|
| 186 |
-
pub const DISPLAY_77C4: usize = 0x77C4;
|
| 187 |
pub const FLAG_7EF8: usize = 0x7EF8;
|
| 188 |
pub const FIELD_7EFC: usize = 0x7EFC;
|
| 189 |
/// Scale factor used by DrawCrosshairLine (multiplied by 0x140000).
|
|
|
|
| 76 |
pub _unknown_528: [u8; 0x20],
|
| 77 |
/// 0x548: Weapon panel pointer
|
| 78 |
pub weapon_panel: *mut u8,
|
| 79 |
+
/// 0x54C-0x7323: Sparse fields (see offsets module)
|
| 80 |
///
|
| 81 |
/// Known landmarks:
|
| 82 |
/// - 0x64D8: cleared by init
|
| 83 |
/// - 0x72A4: cleared by init
|
| 84 |
+
/// - 0x730C-0x731C: 5 GfxDir color entries
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
///
|
| 86 |
/// Also includes FUN_00526120 zeroed offsets at stride 0x194:
|
| 87 |
/// 0x379C, 0x3930, 0x3AC4, 0x3C58, 0x3DEC, 0x3F80, 0x4114, 0x42A8, 0x443C, 0x45D0
|
| 88 |
+
pub _unknown_54c: [u8; 0x7324 - 0x54C],
|
| 89 |
+
|
| 90 |
+
/// 0x7324: Crosshair line color param (DrawPolygon param_2).
|
| 91 |
+
/// Part of GfxDir color entries at 0x730C.
|
| 92 |
+
pub crosshair_line_color: u32,
|
| 93 |
+
/// 0x7328: Unknown (between crosshair params)
|
| 94 |
+
pub _unknown_7328: [u8; 4],
|
| 95 |
+
/// 0x732C: Crosshair line style param (DrawPolygon param_1).
|
| 96 |
+
pub crosshair_line_style: u32,
|
| 97 |
+
/// 0x7330-0x7337: Unknown
|
| 98 |
+
pub _unknown_7330: [u8; 8],
|
| 99 |
+
/// 0x7338: Fill pixel value
|
| 100 |
+
pub fill_pixel: u32,
|
| 101 |
+
/// 0x733C-0x77BF: Unknown
|
| 102 |
+
pub _unknown_733c: [u8; 0x77C0 - 0x733C],
|
| 103 |
+
|
| 104 |
+
/// 0x77C0: Level width in pixels (set by PCLandscape constructor).
|
| 105 |
+
pub level_width: u32,
|
| 106 |
+
/// 0x77C4: Level height in pixels (set by PCLandscape constructor).
|
| 107 |
+
pub level_height: u32,
|
| 108 |
+
/// 0x77C8: Total pixels (width × height).
|
| 109 |
+
pub level_total_pixels: u32,
|
| 110 |
+
|
| 111 |
+
/// 0x77CC-0x7EFF: Unknown
|
| 112 |
+
///
|
| 113 |
+
/// Known landmarks:
|
| 114 |
+
/// - 0x7EF8: flag from game_state+0xF914
|
| 115 |
+
/// - 0x7EFC: init 1
|
| 116 |
+
pub _unknown_77cc: [u8; 0x7F00 - 0x77CC],
|
| 117 |
|
| 118 |
// === Sound queue (0x7F00-0x8143) ===
|
| 119 |
/// 0x7F00: Sound queue (16 entries, stride 0x24). Appended by PlaySoundGlobal.
|
|
|
|
| 202 |
pub const FIELD_64D8: usize = 0x64D8;
|
| 203 |
pub const FIELD_72A4: usize = 0x72A4;
|
| 204 |
pub const GFX_COLOR_ENTRIES: usize = 0x730C;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
pub const FLAG_7EF8: usize = 0x7EF8;
|
| 206 |
pub const FIELD_7EFC: usize = 0x7EFC;
|
| 207 |
/// Scale factor used by DrawCrosshairLine (multiplied by 0x140000).
|
crates/openwa-types/src/ddgame_wrapper.rs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
|
|
|
|
|
| 1 |
/// DDGameWrapper — large wrapper around DDGame.
|
| 2 |
///
|
| 3 |
/// Created by DDGameWrapper__Constructor (0x56DEF0).
|
|
@@ -20,7 +22,7 @@ pub struct DDGameWrapper {
|
|
| 20 |
/// 0x004-0x487: Unknown fields
|
| 21 |
pub _unknown_004: [u8; 0x484],
|
| 22 |
/// 0x488: Pointer to DDGame allocation (DWORD index 0x122)
|
| 23 |
-
pub ddgame: *mut
|
| 24 |
/// 0x48C: Secondary DDGame struct pointer (0x2C bytes, conditional)
|
| 25 |
pub ddgame_secondary: *mut u8,
|
| 26 |
/// 0x490-0x4BF: Unknown
|
|
|
|
| 1 |
+
use crate::ddgame::DDGame;
|
| 2 |
+
|
| 3 |
/// DDGameWrapper — large wrapper around DDGame.
|
| 4 |
///
|
| 5 |
/// Created by DDGameWrapper__Constructor (0x56DEF0).
|
|
|
|
| 22 |
/// 0x004-0x487: Unknown fields
|
| 23 |
pub _unknown_004: [u8; 0x484],
|
| 24 |
/// 0x488: Pointer to DDGame allocation (DWORD index 0x122)
|
| 25 |
+
pub ddgame: *mut DDGame,
|
| 26 |
/// 0x48C: Secondary DDGame struct pointer (0x2C bytes, conditional)
|
| 27 |
pub ddgame_secondary: *mut u8,
|
| 28 |
/// 0x490-0x4BF: Unknown
|
crates/openwa-types/src/landscape.rs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
|
|
|
|
|
| 1 |
/// PCLandscape — terrain/landscape subsystem (0xB40 bytes).
|
| 2 |
///
|
| 3 |
/// Created by `PCLandscape__Constructor` (0x57ACB0). Vtable: 0x66B208 (32 slots).
|
|
@@ -24,7 +26,7 @@ pub struct PCLandscape {
|
|
| 24 |
/// 0x000: Vtable pointer (0x66B208)
|
| 25 |
pub vtable: *mut u8,
|
| 26 |
/// 0x004: Parent DDGame pointer (param_1[1])
|
| 27 |
-
pub ddgame: *mut
|
| 28 |
/// 0x008-0x0CB: Pre-rendered crater sprites for 15 explosion sizes.
|
| 29 |
/// param_1[2..17]: crater image ptrs, param_1[18..33]: secondary ptrs.
|
| 30 |
/// Indexed by `explosion_size * 15 / 100`.
|
|
|
|
| 1 |
+
use crate::ddgame::DDGame;
|
| 2 |
+
|
| 3 |
/// PCLandscape — terrain/landscape subsystem (0xB40 bytes).
|
| 4 |
///
|
| 5 |
/// Created by `PCLandscape__Constructor` (0x57ACB0). Vtable: 0x66B208 (32 slots).
|
|
|
|
| 26 |
/// 0x000: Vtable pointer (0x66B208)
|
| 27 |
pub vtable: *mut u8,
|
| 28 |
/// 0x004: Parent DDGame pointer (param_1[1])
|
| 29 |
+
pub ddgame: *mut DDGame,
|
| 30 |
/// 0x008-0x0CB: Pre-rendered crater sprites for 15 explosion sizes.
|
| 31 |
/// param_1[2..17]: crater image ptrs, param_1[18..33]: secondary ptrs.
|
| 32 |
/// Indexed by `explosion_size * 15 / 100`.
|
crates/openwa-types/src/task.rs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
use crate::class_type::ClassType;
|
|
|
|
| 2 |
use crate::fixed::Fixed;
|
| 3 |
|
| 4 |
/// Base task class in WA's entity hierarchy.
|
|
@@ -44,7 +45,7 @@ pub struct CTask {
|
|
| 44 |
/// 0x28: 1 if this task owns shared_data (root), 0 if inherited from parent
|
| 45 |
pub owns_shared_data: u32,
|
| 46 |
/// 0x2C: DDGame pointer (3rd param to CTask::Constructor, stored at this+0x2C)
|
| 47 |
-
pub ddgame: *mut
|
| 48 |
}
|
| 49 |
|
| 50 |
const _: () = assert!(core::mem::size_of::<CTask>() == 0x30);
|
|
|
|
| 1 |
use crate::class_type::ClassType;
|
| 2 |
+
use crate::ddgame::DDGame;
|
| 3 |
use crate::fixed::Fixed;
|
| 4 |
|
| 5 |
/// Base task class in WA's entity hierarchy.
|
|
|
|
| 45 |
/// 0x28: 1 if this task owns shared_data (root), 0 if inherited from parent
|
| 46 |
pub owns_shared_data: u32,
|
| 47 |
/// 0x2C: DDGame pointer (3rd param to CTask::Constructor, stored at this+0x2C)
|
| 48 |
+
pub ddgame: *mut DDGame,
|
| 49 |
}
|
| 50 |
|
| 51 |
const _: () = assert!(core::mem::size_of::<CTask>() == 0x30);
|
crates/openwa-wormkit/src/replacements/input.rs
CHANGED
|
@@ -17,22 +17,23 @@ use crate::log_line;
|
|
| 17 |
use openwa_lib::rebase::rb;
|
| 18 |
use openwa_types::address::va;
|
| 19 |
use openwa_types::ddgame::DDGame;
|
|
|
|
| 20 |
|
| 21 |
/// Trampoline to the original TurnManager_ProcessFrame.
|
| 22 |
static ORIG_TURN_MANAGER: AtomicU32 = AtomicU32::new(0);
|
| 23 |
|
| 24 |
-
/// Get the DDGame pointer (session+0xA0 → DDGameWrapper
|
| 25 |
#[inline]
|
| 26 |
unsafe fn get_ddgame() -> *mut DDGame {
|
| 27 |
let session = *(rb(va::G_GAME_SESSION) as *const u32);
|
| 28 |
if session == 0 {
|
| 29 |
return core::ptr::null_mut();
|
| 30 |
}
|
| 31 |
-
let
|
| 32 |
-
if
|
| 33 |
return core::ptr::null_mut();
|
| 34 |
}
|
| 35 |
-
|
| 36 |
}
|
| 37 |
|
| 38 |
/// Hook for TurnManager_ProcessFrame (stdcall, 1 param = TurnGame*).
|
|
|
|
| 17 |
use openwa_lib::rebase::rb;
|
| 18 |
use openwa_types::address::va;
|
| 19 |
use openwa_types::ddgame::DDGame;
|
| 20 |
+
use openwa_types::ddgame_wrapper::DDGameWrapper;
|
| 21 |
|
| 22 |
/// Trampoline to the original TurnManager_ProcessFrame.
|
| 23 |
static ORIG_TURN_MANAGER: AtomicU32 = AtomicU32::new(0);
|
| 24 |
|
| 25 |
+
/// Get the DDGame pointer (session+0xA0 → DDGameWrapper.ddgame).
|
| 26 |
#[inline]
|
| 27 |
unsafe fn get_ddgame() -> *mut DDGame {
|
| 28 |
let session = *(rb(va::G_GAME_SESSION) as *const u32);
|
| 29 |
if session == 0 {
|
| 30 |
return core::ptr::null_mut();
|
| 31 |
}
|
| 32 |
+
let wrapper_ptr = *((session + 0xA0) as *const *const DDGameWrapper);
|
| 33 |
+
if wrapper_ptr.is_null() {
|
| 34 |
return core::ptr::null_mut();
|
| 35 |
}
|
| 36 |
+
(*wrapper_ptr).ddgame
|
| 37 |
}
|
| 38 |
|
| 39 |
/// Hook for TurnManager_ProcessFrame (stdcall, 1 param = TurnGame*).
|
crates/openwa-wormkit/src/replacements/render.rs
CHANGED
|
@@ -5,7 +5,6 @@
|
|
| 5 |
|
| 6 |
use openwa_lib::rebase::rb;
|
| 7 |
use openwa_types::address::va;
|
| 8 |
-
use openwa_types::ddgame::{offsets as dg, DDGame};
|
| 9 |
use openwa_types::render::*;
|
| 10 |
use openwa_types::task::{BungeeTrailTask, WeaponAimTask};
|
| 11 |
|
|
@@ -380,7 +379,7 @@ unsafe extern "stdcall" fn draw_bungee_trail_impl(
|
|
| 380 |
return;
|
| 381 |
}
|
| 382 |
|
| 383 |
-
let ddgame = &*
|
| 384 |
let rq = &mut *ddgame.render_queue;
|
| 385 |
|
| 386 |
let seg_data = task.segment_data;
|
|
@@ -504,7 +503,7 @@ unsafe extern "cdecl" fn draw_crosshair_line_impl(task_ptr: u32) {
|
|
| 504 |
return;
|
| 505 |
}
|
| 506 |
|
| 507 |
-
let ddgame = &*
|
| 508 |
let rq = &mut *ddgame.render_queue;
|
| 509 |
|
| 510 |
let start_x = gt.pos_x.0;
|
|
@@ -554,9 +553,8 @@ unsafe extern "cdecl" fn draw_crosshair_line_impl(task_ptr: u32) {
|
|
| 554 |
}
|
| 555 |
|
| 556 |
// Enqueue polygon line (2 vertices)
|
| 557 |
-
let
|
| 558 |
-
let
|
| 559 |
-
let poly_param_2 = *(ddgame_ptr.add(dg::CROSSHAIR_LINE_PARAM_2) as *const u32);
|
| 560 |
let verts: [[i32; 3]; 2] = [
|
| 561 |
[start_x, start_y, 0],
|
| 562 |
[endpoint_x, endpoint_y, 0],
|
|
|
|
| 5 |
|
| 6 |
use openwa_lib::rebase::rb;
|
| 7 |
use openwa_types::address::va;
|
|
|
|
| 8 |
use openwa_types::render::*;
|
| 9 |
use openwa_types::task::{BungeeTrailTask, WeaponAimTask};
|
| 10 |
|
|
|
|
| 379 |
return;
|
| 380 |
}
|
| 381 |
|
| 382 |
+
let ddgame = &*task.base.ddgame;
|
| 383 |
let rq = &mut *ddgame.render_queue;
|
| 384 |
|
| 385 |
let seg_data = task.segment_data;
|
|
|
|
| 503 |
return;
|
| 504 |
}
|
| 505 |
|
| 506 |
+
let ddgame = &*gt.base.ddgame;
|
| 507 |
let rq = &mut *ddgame.render_queue;
|
| 508 |
|
| 509 |
let start_x = gt.pos_x.0;
|
|
|
|
| 553 |
}
|
| 554 |
|
| 555 |
// Enqueue polygon line (2 vertices)
|
| 556 |
+
let poly_param_1 = ddgame.crosshair_line_style;
|
| 557 |
+
let poly_param_2 = ddgame.crosshair_line_color;
|
|
|
|
| 558 |
let verts: [[i32; 3]; 2] = [
|
| 559 |
[start_x, start_y, 0],
|
| 560 |
[endpoint_x, endpoint_y, 0],
|
crates/openwa-wormkit/src/replacements/sound.rs
CHANGED
|
@@ -80,7 +80,7 @@ unsafe extern "thiscall" fn hook_play_sound_global(
|
|
| 80 |
}
|
| 81 |
|
| 82 |
let task = &*(this as *const CGameTask);
|
| 83 |
-
queue_sound(task.base.ddgame
|
| 84 |
}
|
| 85 |
|
| 86 |
// ============================================================
|
|
@@ -110,7 +110,7 @@ unsafe extern "cdecl" fn play_sound_local_impl(
|
|
| 110 |
}
|
| 111 |
|
| 112 |
let gt = &*(task as *const CGameTask);
|
| 113 |
-
let ddgame = gt.base.ddgame
|
| 114 |
let entry = match queue_sound(ddgame, sound_id, flags, volume, pitch) {
|
| 115 |
Some(e) => e,
|
| 116 |
None => return 0,
|
|
|
|
| 80 |
}
|
| 81 |
|
| 82 |
let task = &*(this as *const CGameTask);
|
| 83 |
+
queue_sound(task.base.ddgame, sound_id, flags, volume, pitch).is_some() as u32
|
| 84 |
}
|
| 85 |
|
| 86 |
// ============================================================
|
|
|
|
| 110 |
}
|
| 111 |
|
| 112 |
let gt = &*(task as *const CGameTask);
|
| 113 |
+
let ddgame = gt.base.ddgame;
|
| 114 |
let entry = match queue_sound(ddgame, sound_id, flags, volume, pitch) {
|
| 115 |
Some(e) => e,
|
| 116 |
None => return 0,
|
crates/openwa-wormkit/src/validation/mod.rs
CHANGED
|
@@ -617,7 +617,7 @@ fn dump_landscape() {
|
|
| 617 |
let _ = log_validation(&format!(" vtable: 0x{:08X} (expected 0x{:08X}) {}",
|
| 618 |
land.vtable as u32, expected_vt, if vt_ok { "OK" } else { "MISMATCH" }));
|
| 619 |
|
| 620 |
-
let _ = log_validation(&format!(" ddgame: 0x{:08X}", land.ddgame as
|
| 621 |
let _ = log_validation(&format!(" _unknown_900: 0x{:08X}", land._unknown_900 as u32));
|
| 622 |
let _ = log_validation(&format!(" collision_bitmap: 0x{:08X}", land.collision_bitmap as u32));
|
| 623 |
let _ = log_validation(&format!(" initialized: {}", land.initialized));
|
|
@@ -671,13 +671,10 @@ fn dump_landscape() {
|
|
| 671 |
let _ = log_validation(&format!(" level_dir_path: {:?}", level_path));
|
| 672 |
let _ = log_validation(&format!(" theme_dir_path: {:?}", theme_path));
|
| 673 |
|
| 674 |
-
|
| 675 |
-
|
| 676 |
-
let level_w = read_u32(ddgame_ptr + 0x77C0);
|
| 677 |
-
let level_h = read_u32(ddgame_ptr + 0x77C4);
|
| 678 |
-
let level_total = read_u32(ddgame_ptr + 0x77C8);
|
| 679 |
let _ = log_validation(&format!(" DDGame level dims: {}x{} (total={})",
|
| 680 |
-
|
| 681 |
}
|
| 682 |
|
| 683 |
let _ = log_validation(" Vtable slots:");
|
|
|
|
| 617 |
let _ = log_validation(&format!(" vtable: 0x{:08X} (expected 0x{:08X}) {}",
|
| 618 |
land.vtable as u32, expected_vt, if vt_ok { "OK" } else { "MISMATCH" }));
|
| 619 |
|
| 620 |
+
let _ = log_validation(&format!(" ddgame: 0x{:08X}", land.ddgame as usize));
|
| 621 |
let _ = log_validation(&format!(" _unknown_900: 0x{:08X}", land._unknown_900 as u32));
|
| 622 |
let _ = log_validation(&format!(" collision_bitmap: 0x{:08X}", land.collision_bitmap as u32));
|
| 623 |
let _ = log_validation(&format!(" initialized: {}", land.initialized));
|
|
|
|
| 671 |
let _ = log_validation(&format!(" level_dir_path: {:?}", level_path));
|
| 672 |
let _ = log_validation(&format!(" theme_dir_path: {:?}", theme_path));
|
| 673 |
|
| 674 |
+
if !land.ddgame.is_null() {
|
| 675 |
+
let dg = &*land.ddgame;
|
|
|
|
|
|
|
|
|
|
| 676 |
let _ = log_validation(&format!(" DDGame level dims: {}x{} (total={})",
|
| 677 |
+
dg.level_width, dg.level_height, dg.level_total_pixels));
|
| 678 |
}
|
| 679 |
|
| 680 |
let _ = log_validation(" Vtable slots:");
|