refactor: replace raw pointer arithmetic with typed structs
Browse files- DDGame: rename _param_008 to sound_enabled, expose crosshair_scale at 0x8150
- Add BungeeTrailTask overlay (fields at 0xBC-0xE4 for trail rendering)
- Add WeaponAimTask overlay (fields at 0x258, 0x264, 0x324 for crosshair)
- Update render.rs and sound.rs to use typed field access
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
crates/openwa-types/src/ddgame.rs
CHANGED
|
@@ -20,8 +20,8 @@ pub struct DDGame {
|
|
| 20 |
pub _base_000: *mut u8,
|
| 21 |
/// 0x004: Context pointer (param_3)
|
| 22 |
pub _context: *mut u8,
|
| 23 |
-
/// 0x008:
|
| 24 |
-
pub
|
| 25 |
/// 0x00C: Allocated object (0x608 bytes, conditional)
|
| 26 |
pub _object_00c: *mut u8,
|
| 27 |
/// 0x010: param_6
|
|
@@ -97,12 +97,17 @@ pub struct DDGame {
|
|
| 97 |
/// 0x8140: Number of entries currently in the sound queue (0–16).
|
| 98 |
pub sound_queue_count: i32,
|
| 99 |
|
| 100 |
-
/// 0x8144-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
///
|
| 102 |
/// Known landmarks:
|
| 103 |
/// - 0x8CBC-0x8CF0: 4x 0x10-byte entries (zeroed at +0, +4)
|
| 104 |
/// - 0x9850-0x9884: 4x 0x10-byte entries (zeroed at +0, +4)
|
| 105 |
-
pub
|
| 106 |
}
|
| 107 |
|
| 108 |
const _: () = assert!(core::mem::size_of::<DDGame>() == 0x98B8);
|
|
|
|
| 20 |
pub _base_000: *mut u8,
|
| 21 |
/// 0x004: Context pointer (param_3)
|
| 22 |
pub _context: *mut u8,
|
| 23 |
+
/// 0x008: Sound enabled flag (nonzero = enabled). Checked by PlaySoundGlobal.
|
| 24 |
+
pub sound_enabled: i32,
|
| 25 |
/// 0x00C: Allocated object (0x608 bytes, conditional)
|
| 26 |
pub _object_00c: *mut u8,
|
| 27 |
/// 0x010: param_6
|
|
|
|
| 97 |
/// 0x8140: Number of entries currently in the sound queue (0–16).
|
| 98 |
pub sound_queue_count: i32,
|
| 99 |
|
| 100 |
+
/// 0x8144-0x814F: Unknown
|
| 101 |
+
pub _unknown_8144: [u8; 0x8150 - 0x8144],
|
| 102 |
+
/// 0x8150: Scale factor used by DrawCrosshairLine (multiplied by 0x140000).
|
| 103 |
+
pub crosshair_scale: i32,
|
| 104 |
+
|
| 105 |
+
/// 0x8154-0x98B7: Remaining fields
|
| 106 |
///
|
| 107 |
/// Known landmarks:
|
| 108 |
/// - 0x8CBC-0x8CF0: 4x 0x10-byte entries (zeroed at +0, +4)
|
| 109 |
/// - 0x9850-0x9884: 4x 0x10-byte entries (zeroed at +0, +4)
|
| 110 |
+
pub _unknown_8154: [u8; 0x98B8 - 0x8154],
|
| 111 |
}
|
| 112 |
|
| 113 |
const _: () = assert!(core::mem::size_of::<DDGame>() == 0x98B8);
|
crates/openwa-types/src/task.rs
CHANGED
|
@@ -118,3 +118,71 @@ pub struct SoundEmitterVTable {
|
|
| 118 |
/// [5]-[11]: Inherited CTask base methods
|
| 119 |
pub _base_methods: [*const (); 7],
|
| 120 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
/// [5]-[11]: Inherited CTask base methods
|
| 119 |
pub _base_methods: [*const (); 7],
|
| 120 |
}
|
| 121 |
+
|
| 122 |
+
// ============================================================
|
| 123 |
+
// Derived task overlays — for accessing task-specific fields
|
| 124 |
+
// beyond or within CGameTask that differ per task type.
|
| 125 |
+
// ============================================================
|
| 126 |
+
|
| 127 |
+
/// Bungee trail rendering task fields.
|
| 128 |
+
///
|
| 129 |
+
/// Used by DrawBungeeTrail (0x500720). Fields at 0xBC-0xE4 overlap with
|
| 130 |
+
/// CGameTask's `_unknown_98` region — different task types may use these
|
| 131 |
+
/// offsets for different purposes.
|
| 132 |
+
///
|
| 133 |
+
/// Cast a task pointer to this type when you know it's a bungee trail task.
|
| 134 |
+
#[repr(C)]
|
| 135 |
+
pub struct BungeeTrailTask {
|
| 136 |
+
/// 0x00-0x2F: CTask base
|
| 137 |
+
pub base: CTask,
|
| 138 |
+
/// 0x30-0x83: Unknown
|
| 139 |
+
pub _unknown_30: [u8; 0x54],
|
| 140 |
+
/// 0x84: X position in fixed-point
|
| 141 |
+
pub pos_x: Fixed,
|
| 142 |
+
/// 0x88: Y position in fixed-point
|
| 143 |
+
pub pos_y: Fixed,
|
| 144 |
+
/// 0x8C-0xBB: Unknown
|
| 145 |
+
pub _unknown_8c: [u8; 0x30],
|
| 146 |
+
/// 0xBC: Trail visible flag (set by InitWormTrail when Bungee is used)
|
| 147 |
+
pub trail_visible: i32,
|
| 148 |
+
/// 0xC0: Trail start X position
|
| 149 |
+
pub trail_start_x: i32,
|
| 150 |
+
/// 0xC4: Trail start Y position
|
| 151 |
+
pub trail_start_y: i32,
|
| 152 |
+
/// 0xC8-0xCF: Unknown
|
| 153 |
+
pub _unknown_c8: [u8; 8],
|
| 154 |
+
/// 0xD0: Number of trail segments
|
| 155 |
+
pub segment_count: i32,
|
| 156 |
+
/// 0xD4-0xE3: Unknown
|
| 157 |
+
pub _unknown_d4: [u8; 0x10],
|
| 158 |
+
/// 0xE4: Pointer to segment data array (8 bytes per segment: 4 padding + 4 angle)
|
| 159 |
+
pub segment_data: *const u8,
|
| 160 |
+
/// 0xE8: Sound emitter sub-object
|
| 161 |
+
pub sound_emitter: SoundEmitter,
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
const _: () = assert!(core::mem::size_of::<BungeeTrailTask>() == 0xFC);
|
| 165 |
+
|
| 166 |
+
/// Weapon aiming task fields.
|
| 167 |
+
///
|
| 168 |
+
/// Used by DrawCrosshairLine (0x5197D0). Fields at 0x258+ are in the derived
|
| 169 |
+
/// class region beyond CGameTask (0xFC). The exact class name is unknown.
|
| 170 |
+
///
|
| 171 |
+
/// Cast a task pointer to this type when you know it's a worm/weapon aiming task.
|
| 172 |
+
#[repr(C)]
|
| 173 |
+
pub struct WeaponAimTask {
|
| 174 |
+
/// 0x00-0xFB: CGameTask base
|
| 175 |
+
pub game_task: CGameTask,
|
| 176 |
+
/// 0xFC-0x257: Unknown derived fields
|
| 177 |
+
pub _unknown_fc: [u8; 0x258 - 0xFC],
|
| 178 |
+
/// 0x258: Aiming active flag (nonzero = crosshair visible)
|
| 179 |
+
pub aim_active: i32,
|
| 180 |
+
/// 0x25C-0x263: Unknown
|
| 181 |
+
pub _unknown_25c: [u8; 8],
|
| 182 |
+
/// 0x264: Current aim angle (used for trig lookup)
|
| 183 |
+
pub aim_angle: u32,
|
| 184 |
+
/// 0x268-0x323: Unknown
|
| 185 |
+
pub _unknown_268: [u8; 0x324 - 0x268],
|
| 186 |
+
/// 0x324: Aim range offset (added to DDGame crosshair scale)
|
| 187 |
+
pub aim_range_offset: i32,
|
| 188 |
+
}
|
crates/openwa-wormkit/src/replacements/render.rs
CHANGED
|
@@ -7,7 +7,7 @@ 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::
|
| 11 |
|
| 12 |
use crate::hook::{self, usercall_trampoline};
|
| 13 |
|
|
@@ -374,29 +374,27 @@ unsafe extern "stdcall" fn draw_bungee_trail_impl(
|
|
| 374 |
style: u32,
|
| 375 |
fill: u32,
|
| 376 |
) {
|
| 377 |
-
let task = task_ptr as *
|
| 378 |
-
let game_task = task_ptr as *const CGameTask;
|
| 379 |
|
| 380 |
-
|
| 381 |
-
if *(task.add(0xBC) as *const i32) == 0 {
|
| 382 |
return;
|
| 383 |
}
|
| 384 |
|
| 385 |
-
let ddgame = &*(
|
| 386 |
let rq = &mut *ddgame.render_queue;
|
| 387 |
|
| 388 |
-
let seg_data =
|
| 389 |
if seg_data.is_null() {
|
| 390 |
return;
|
| 391 |
}
|
| 392 |
|
| 393 |
-
let segment_count =
|
| 394 |
if segment_count <= 0 {
|
| 395 |
return;
|
| 396 |
}
|
| 397 |
|
| 398 |
-
let mut x =
|
| 399 |
-
let mut y =
|
| 400 |
|
| 401 |
let first_angle = *(seg_data.add(4) as *const i32);
|
| 402 |
|
|
@@ -443,7 +441,7 @@ unsafe extern "stdcall" fn draw_bungee_trail_impl(
|
|
| 443 |
|
| 444 |
// Final vertex = task position (target)
|
| 445 |
if vert_count < MAX_VERTICES {
|
| 446 |
-
verts[vert_count] = [
|
| 447 |
vert_count += 1;
|
| 448 |
}
|
| 449 |
|
|
@@ -499,22 +497,20 @@ usercall_trampoline!(fn trampoline_draw_crosshair_line; impl_fn = draw_crosshair
|
|
| 499 |
reg = edi);
|
| 500 |
|
| 501 |
unsafe extern "cdecl" fn draw_crosshair_line_impl(task_ptr: u32) {
|
| 502 |
-
let task = task_ptr as *const
|
| 503 |
-
let
|
| 504 |
|
| 505 |
-
|
| 506 |
-
if *(task.add(0x258) as *const i32) == 0 {
|
| 507 |
return;
|
| 508 |
}
|
| 509 |
|
| 510 |
-
let
|
| 511 |
-
let ddgame = &*(ddgame_ptr as *const DDGame);
|
| 512 |
let rq = &mut *ddgame.render_queue;
|
| 513 |
|
| 514 |
-
let start_x =
|
| 515 |
-
let start_y =
|
| 516 |
|
| 517 |
-
let angle =
|
| 518 |
|
| 519 |
// Trig interpolation
|
| 520 |
let sin_table = rb(va::G_SIN_TABLE) as *const i32;
|
|
@@ -522,10 +518,9 @@ unsafe extern "cdecl" fn draw_crosshair_line_impl(task_ptr: u32) {
|
|
| 522 |
let sin_interp = trig_lookup(sin_table, angle);
|
| 523 |
let cos_interp = trig_lookup(cos_table, angle);
|
| 524 |
|
| 525 |
-
// Scale = fixed_mul(DDGame
|
| 526 |
-
let
|
| 527 |
-
|
| 528 |
-
+ *(task.add(0x324) as *const i32);
|
| 529 |
|
| 530 |
// Endpoint = start + direction * scale
|
| 531 |
let mut endpoint_x = fixed_mul(sin_interp, scale).wrapping_add(start_x);
|
|
@@ -559,6 +554,7 @@ unsafe extern "cdecl" fn draw_crosshair_line_impl(task_ptr: u32) {
|
|
| 559 |
}
|
| 560 |
|
| 561 |
// Enqueue polygon line (2 vertices)
|
|
|
|
| 562 |
let poly_param_1 = *(ddgame_ptr.add(dg::CROSSHAIR_LINE_PARAM_1) as *const u32);
|
| 563 |
let poly_param_2 = *(ddgame_ptr.add(dg::CROSSHAIR_LINE_PARAM_2) as *const u32);
|
| 564 |
let verts: [[i32; 3]; 2] = [
|
|
|
|
| 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 |
|
| 12 |
use crate::hook::{self, usercall_trampoline};
|
| 13 |
|
|
|
|
| 374 |
style: u32,
|
| 375 |
fill: u32,
|
| 376 |
) {
|
| 377 |
+
let task = &*(task_ptr as *const BungeeTrailTask);
|
|
|
|
| 378 |
|
| 379 |
+
if task.trail_visible == 0 {
|
|
|
|
| 380 |
return;
|
| 381 |
}
|
| 382 |
|
| 383 |
+
let ddgame = &*(task.base.ddgame as *const DDGame);
|
| 384 |
let rq = &mut *ddgame.render_queue;
|
| 385 |
|
| 386 |
+
let seg_data = task.segment_data;
|
| 387 |
if seg_data.is_null() {
|
| 388 |
return;
|
| 389 |
}
|
| 390 |
|
| 391 |
+
let segment_count = task.segment_count;
|
| 392 |
if segment_count <= 0 {
|
| 393 |
return;
|
| 394 |
}
|
| 395 |
|
| 396 |
+
let mut x = task.trail_start_x;
|
| 397 |
+
let mut y = task.trail_start_y;
|
| 398 |
|
| 399 |
let first_angle = *(seg_data.add(4) as *const i32);
|
| 400 |
|
|
|
|
| 441 |
|
| 442 |
// Final vertex = task position (target)
|
| 443 |
if vert_count < MAX_VERTICES {
|
| 444 |
+
verts[vert_count] = [task.pos_x.0, task.pos_y.0, 0];
|
| 445 |
vert_count += 1;
|
| 446 |
}
|
| 447 |
|
|
|
|
| 497 |
reg = edi);
|
| 498 |
|
| 499 |
unsafe extern "cdecl" fn draw_crosshair_line_impl(task_ptr: u32) {
|
| 500 |
+
let task = &*(task_ptr as *const WeaponAimTask);
|
| 501 |
+
let gt = &task.game_task;
|
| 502 |
|
| 503 |
+
if task.aim_active == 0 {
|
|
|
|
| 504 |
return;
|
| 505 |
}
|
| 506 |
|
| 507 |
+
let ddgame = &*(gt.base.ddgame as *const DDGame);
|
|
|
|
| 508 |
let rq = &mut *ddgame.render_queue;
|
| 509 |
|
| 510 |
+
let start_x = gt.pos_x.0;
|
| 511 |
+
let start_y = gt.pos_y.0;
|
| 512 |
|
| 513 |
+
let angle = task.aim_angle;
|
| 514 |
|
| 515 |
// Trig interpolation
|
| 516 |
let sin_table = rb(va::G_SIN_TABLE) as *const i32;
|
|
|
|
| 518 |
let sin_interp = trig_lookup(sin_table, angle);
|
| 519 |
let cos_interp = trig_lookup(cos_table, angle);
|
| 520 |
|
| 521 |
+
// Scale = fixed_mul(DDGame.crosshair_scale, 0x140000) + task.aim_range_offset
|
| 522 |
+
let scale = fixed_mul(ddgame.crosshair_scale, 0x14_0000)
|
| 523 |
+
+ task.aim_range_offset;
|
|
|
|
| 524 |
|
| 525 |
// Endpoint = start + direction * scale
|
| 526 |
let mut endpoint_x = fixed_mul(sin_interp, scale).wrapping_add(start_x);
|
|
|
|
| 554 |
}
|
| 555 |
|
| 556 |
// Enqueue polygon line (2 vertices)
|
| 557 |
+
let ddgame_ptr = ddgame as *const DDGame as *const u8;
|
| 558 |
let poly_param_1 = *(ddgame_ptr.add(dg::CROSSHAIR_LINE_PARAM_1) as *const u32);
|
| 559 |
let poly_param_2 = *(ddgame_ptr.add(dg::CROSSHAIR_LINE_PARAM_2) as *const u32);
|
| 560 |
let verts: [[i32; 3]; 2] = [
|
crates/openwa-wormkit/src/replacements/sound.rs
CHANGED
|
@@ -10,7 +10,7 @@
|
|
| 10 |
use std::sync::atomic::Ordering;
|
| 11 |
|
| 12 |
use openwa_types::address::va;
|
| 13 |
-
use openwa_types::ddgame::{DDGame,
|
| 14 |
use openwa_types::sound::SoundId;
|
| 15 |
use openwa_types::task::CGameTask;
|
| 16 |
|
|
@@ -37,9 +37,7 @@ unsafe fn queue_sound(
|
|
| 37 |
pitch: u32,
|
| 38 |
) -> Option<*mut SoundQueueEntry> {
|
| 39 |
let g = &mut *ddgame;
|
| 40 |
-
|
| 41 |
-
let sound_enabled = *((ddgame as *const u8).add(offsets::SOUND_ENABLED) as *const i32);
|
| 42 |
-
if g.sound_queue_count >= 16 || sound_enabled == 0 {
|
| 43 |
return None;
|
| 44 |
}
|
| 45 |
let entry = &mut g.sound_queue[g.sound_queue_count as usize];
|
|
|
|
| 10 |
use std::sync::atomic::Ordering;
|
| 11 |
|
| 12 |
use openwa_types::address::va;
|
| 13 |
+
use openwa_types::ddgame::{DDGame, SoundQueueEntry};
|
| 14 |
use openwa_types::sound::SoundId;
|
| 15 |
use openwa_types::task::CGameTask;
|
| 16 |
|
|
|
|
| 37 |
pitch: u32,
|
| 38 |
) -> Option<*mut SoundQueueEntry> {
|
| 39 |
let g = &mut *ddgame;
|
| 40 |
+
if g.sound_queue_count >= 16 || g.sound_enabled == 0 {
|
|
|
|
|
|
|
| 41 |
return None;
|
| 42 |
}
|
| 43 |
let entry = &mut g.sound_queue[g.sound_queue_count as usize];
|