paavohtl Claude Opus 4.6 commited on
Commit
de224ec
·
1 Parent(s): 9ad30f2

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: param_4
24
- pub _param_008: *mut u8,
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-0x98B7: Remaining fields
 
 
 
 
 
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 _unknown_8144: [u8; 0x98B8 - 0x8144],
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::CGameTask;
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 *mut u8;
378
- let game_task = task_ptr as *const CGameTask;
379
 
380
- // Early exit if trail not visible (set by InitWormTrail when Bungee is used)
381
- if *(task.add(0xBC) as *const i32) == 0 {
382
  return;
383
  }
384
 
385
- let ddgame = &*((*game_task).base.ddgame as *const DDGame);
386
  let rq = &mut *ddgame.render_queue;
387
 
388
- let seg_data = *(task.add(0xE4) as *const *const u8);
389
  if seg_data.is_null() {
390
  return;
391
  }
392
 
393
- let segment_count = *(task.add(0xD0) as *const i32);
394
  if segment_count <= 0 {
395
  return;
396
  }
397
 
398
- let mut x = *(task.add(0xC0) as *const i32);
399
- let mut y = *(task.add(0xC4) as *const i32);
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] = [(*game_task).pos_x.0, (*game_task).pos_y.0, 0];
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 u8;
503
- let game_task = task_ptr as *const CGameTask;
504
 
505
- // Early exit if aiming not active (derived class field)
506
- if *(task.add(0x258) as *const i32) == 0 {
507
  return;
508
  }
509
 
510
- let ddgame_ptr = (*game_task).base.ddgame as *const u8;
511
- let ddgame = &*(ddgame_ptr as *const DDGame);
512
  let rq = &mut *ddgame.render_queue;
513
 
514
- let start_x = (*game_task).pos_x.0;
515
- let start_y = (*game_task).pos_y.0;
516
 
517
- let angle = *(task.add(0x264) as *const u32);
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[CROSSHAIR_SCALE], 0x140000) + task[0x324]
526
- let ddgame_scale = *(ddgame_ptr.add(dg::CROSSHAIR_SCALE) as *const i32);
527
- let scale = fixed_mul(ddgame_scale, 0x14_0000)
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, offsets, SoundQueueEntry};
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
- // sound_enabled is at DDGame+0x008, mapped as _param_008 (pointer-sized).
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];