paavohtl Claude Opus 4.6 (1M context) commited on
Commit
94f0eda
·
1 Parent(s): c6d4e73

feat: add Task trait for ergonomic CTask base access

Browse files

Add unsafe trait Task with default methods:
- task() / task_mut() — reference to CTask base
- as_task_ptr() / as_task_ptr_mut() — raw pointers
- ddgame() — direct DDGame pointer access

Implemented for all CTask subclasses (CTaskWorm, CTaskTeam,
CTaskMissile, CTaskArrow, CTaskMine, etc.) via unsafe impls.

Replace all .base.base chains in weapon.rs with trait methods:
- (*worm).base.base.ddgame → (*worm).ddgame()
- &(*worm).base.base as *const _ as *const CTask → (*worm).as_task_ptr()
- SharedDataTable::from_task(task as *const _ as ...) → from_task((*worm).as_task_ptr())

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

crates/openwa-core/src/task/base.rs CHANGED
@@ -141,6 +141,44 @@ pub struct CTask<V: 'static = *const core::ffi::c_void> {
141
 
142
  const _: () = assert!(core::mem::size_of::<CTask>() == 0x30);
143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  // ---------------------------------------------------------------------------
145
  // Shared-data entity registry
146
  // ---------------------------------------------------------------------------
 
141
 
142
  const _: () = assert!(core::mem::size_of::<CTask>() == 0x30);
143
 
144
+ /// Trait for all task types in the CTask hierarchy.
145
+ ///
146
+ /// Provides safe access to the underlying CTask fields regardless of
147
+ /// inheritance depth. Avoids repetitive `.base.base` chains.
148
+ ///
149
+ /// # Safety
150
+ /// Implementors must be `#[repr(C)]` structs where a `CTask` (with any
151
+ /// vtable type parameter) is at offset 0.
152
+ pub unsafe trait Task {
153
+ /// Get a shared reference to the underlying CTask (default vtable type).
154
+ fn task(&self) -> &CTask {
155
+ unsafe { &*(self as *const Self as *const CTask) }
156
+ }
157
+
158
+ /// Get a mutable reference to the underlying CTask.
159
+ fn task_mut(&mut self) -> &mut CTask {
160
+ unsafe { &mut *(self as *mut Self as *mut CTask) }
161
+ }
162
+
163
+ /// Get a raw const pointer to the CTask base.
164
+ fn as_task_ptr(&self) -> *const CTask {
165
+ self as *const Self as *const CTask
166
+ }
167
+
168
+ /// Get a raw mutable pointer to the CTask base.
169
+ fn as_task_ptr_mut(&mut self) -> *mut CTask {
170
+ self as *mut Self as *mut CTask
171
+ }
172
+
173
+ /// Get the DDGame pointer from the CTask base.
174
+ fn ddgame(&self) -> *mut DDGame {
175
+ self.task().ddgame
176
+ }
177
+ }
178
+
179
+ // Blanket impl for any CTask<V>
180
+ unsafe impl<V: 'static> Task for CTask<V> {}
181
+
182
  // ---------------------------------------------------------------------------
183
  // Shared-data entity registry
184
  // ---------------------------------------------------------------------------
crates/openwa-core/src/task/mod.rs CHANGED
@@ -14,7 +14,7 @@ pub mod turn_game;
14
  pub mod worm;
15
 
16
  pub use arrow::{CTaskArrow, CTaskArrowVTable};
17
- pub use base::{CTask, CTaskBfsIter, SharedDataIter, SharedDataNode, SharedDataTable};
18
  pub use cloud::{CTaskCloud, CTaskCloudVTable};
19
  pub use filter::{CTaskFilter, CTaskFilterVTable};
20
  pub use fire::{CTaskFire, CTaskFireVTable};
@@ -26,3 +26,18 @@ pub use supply_crate::{CTaskCrate, CTaskCrateVTable};
26
  pub use team::{CTaskTeam, CTaskTeamVTable};
27
  pub use turn_game::{CTaskTurnGame, CTaskTurnGameVTable, TurnGameCtx};
28
  pub use worm::{CTaskWorm, CTaskWormVTable};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  pub mod worm;
15
 
16
  pub use arrow::{CTaskArrow, CTaskArrowVTable};
17
+ pub use base::{CTask, CTaskBfsIter, SharedDataIter, SharedDataNode, SharedDataTable, Task};
18
  pub use cloud::{CTaskCloud, CTaskCloudVTable};
19
  pub use filter::{CTaskFilter, CTaskFilterVTable};
20
  pub use fire::{CTaskFire, CTaskFireVTable};
 
26
  pub use team::{CTaskTeam, CTaskTeamVTable};
27
  pub use turn_game::{CTaskTurnGame, CTaskTurnGameVTable, TurnGameCtx};
28
  pub use worm::{CTaskWorm, CTaskWormVTable};
29
+
30
+ // Task trait impls — safe access to CTask base regardless of inheritance depth.
31
+ // CTask<V> impl is in base.rs (blanket impl).
32
+ unsafe impl<V: 'static> Task for CGameTask<V> {}
33
+ unsafe impl Task for CTaskTeam {}
34
+ unsafe impl Task for CTaskTurnGame {}
35
+ unsafe impl Task for CTaskFilter {}
36
+ unsafe impl Task for CTaskCloud {}
37
+ unsafe impl Task for CTaskFire {}
38
+ unsafe impl Task for CTaskWorm {}
39
+ unsafe impl Task for CTaskMissile {}
40
+ unsafe impl Task for CTaskArrow {}
41
+ unsafe impl Task for CTaskMine {}
42
+ unsafe impl Task for CTaskOilDrum {}
43
+ unsafe impl Task for CTaskCrate {}
crates/openwa-wormkit/src/replacements/weapon.rs CHANGED
@@ -20,6 +20,7 @@ use openwa_core::engine::ddgame::{self, TeamArenaRef};
20
  use openwa_core::game::weapon::{WeaponEntry, WeaponFireParams};
21
  use openwa_core::game::Weapon;
22
  use openwa_core::log::log_line;
 
23
  use openwa_core::task::worm::CTaskWorm;
24
 
25
  use crate::hook::{self, usercall_trampoline};
@@ -406,10 +407,9 @@ unsafe fn fire_weapon_special(
406
  ///
407
  /// Returns null if not found.
408
  unsafe fn lookup_team_task(worm: *const CTaskWorm) -> *mut openwa_core::task::CTaskTeam {
409
- use openwa_core::task::SharedDataTable;
410
 
411
- let task = &(*worm).base.base as *const _ as *const openwa_core::task::CTask;
412
- let table = SharedDataTable::from_task(task);
413
  // CTaskTeam is registered with key (0, 0x14) in SharedData
414
  table.lookup(0, 0x14) as *mut openwa_core::task::CTaskTeam
415
  }
@@ -432,7 +432,7 @@ unsafe fn fire_send_team_message(worm: *mut CTaskWorm, msg_type: u32) {
432
  buf[0..4].copy_from_slice(&team_index.to_ne_bytes());
433
 
434
  (*team).handle_message(
435
- &raw mut (*worm).base.base as *mut openwa_core::task::CTask,
436
  msg_type,
437
  4,
438
  buf.as_ptr(),
@@ -453,7 +453,7 @@ unsafe fn fire_select_worm(worm: *mut CTaskWorm) {
453
  buf[4..8].copy_from_slice(&(*worm).team_index.to_ne_bytes());
454
 
455
  (*team).handle_message(
456
- &raw mut (*worm).base.base as *mut openwa_core::task::CTask,
457
  0x5D,
458
  0x408,
459
  buf.as_ptr(),
@@ -467,9 +467,7 @@ unsafe fn fire_select_worm(worm: *mut CTaskWorm) {
467
  /// In game_version > 0x1C: toggles (set/clear). Otherwise: always sets.
468
  unsafe fn fire_skip_go(worm: *const CTaskWorm, entry: *const WeaponEntry) {
469
  use openwa_core::engine::ddgame::TeamArenaRef;
470
- use openwa_core::engine::DDGame;
471
-
472
- let ddgame = (*worm).base.base.ddgame as *mut DDGame;
473
  let game_version = (*(*ddgame).game_info).game_version;
474
  let team_index = (*worm).team_index as usize;
475
 
@@ -496,7 +494,7 @@ unsafe fn fire_surrender(worm: *mut CTaskWorm) {
496
 
497
  fire_send_team_message(worm, 0x29);
498
 
499
- let ddgame = (*worm).base.base.ddgame;
500
  let arena = TeamArenaRef::from_ptr(&raw mut (*ddgame).team_arena);
501
  let team_index = (*worm).team_index as usize;
502
  let worm_index = (*worm).worm_index as usize;
@@ -518,9 +516,7 @@ unsafe fn fire_surrender(worm: *mut CTaskWorm) {
518
  /// - otherwise: skip
519
  unsafe fn fire_mail_mine_mole(worm: *mut CTaskWorm) {
520
  use openwa_core::engine::ddgame::TeamArenaRef;
521
- use openwa_core::engine::DDGame;
522
-
523
- let ddgame = (*worm).base.base.ddgame as *mut DDGame;
524
  let version = *((ddgame as *const u8).add(0x7E40));
525
  let worm_state = (*worm).state();
526
 
@@ -713,11 +709,10 @@ unsafe extern "cdecl" fn create_weapon_projectile_impl(
713
  worm: *mut CTaskWorm, fire_params: *const WeaponFireParams, local_struct: u32,
714
  ) {
715
  use openwa_core::rebase::rb;
716
- use openwa_core::task::SharedDataTable;
717
  use openwa_core::wa_alloc::wa_malloc;
718
 
719
- let task = &(*worm).base.base;
720
- let ddgame = &mut *task.ddgame;
721
 
722
  // Pool capacity check: pool_count + 7 must be <= 700
723
  if ddgame.object_pool_count + 7 > 700 {
@@ -726,7 +721,7 @@ unsafe extern "cdecl" fn create_weapon_projectile_impl(
726
  }
727
 
728
  // Look up parent CTaskTurnGame via SharedData (key_esi=0, key_edi=0x19)
729
- let table = SharedDataTable::from_task(task as *const _ as *const openwa_core::task::CTask);
730
  let parent = table.lookup(0, 0x19);
731
 
732
  // Allocate CTaskMissile (0x40C bytes)
@@ -807,7 +802,7 @@ unsafe extern "cdecl" fn projectile_fire_impl(
807
  let sin_table = rb(va::SIN_TABLE) as *const i32;
808
  let cos_table = sin_table.add(256); // cos = sin offset by 256 entries (quarter turn)
809
 
810
- let ddgame = &mut *(*worm).base.base.ddgame;
811
 
812
  for _i in 0..shot_count {
813
  // Advance game RNG (same LCG as ADVANCE_GAME_RNG at 0x53F320)
@@ -887,11 +882,10 @@ unsafe extern "cdecl" fn create_arrow_impl(
887
  worm: *mut CTaskWorm, fire_params: *const WeaponFireParams, local_struct: u32,
888
  ) {
889
  use openwa_core::rebase::rb;
890
- use openwa_core::task::SharedDataTable;
891
  use openwa_core::wa_alloc::wa_malloc;
892
 
893
- let task = &(*worm).base.base;
894
- let ddgame = &mut *task.ddgame;
895
 
896
  // Pool capacity check: pool_count + 2 must be <= 700
897
  if ddgame.object_pool_count + 2 > 700 {
@@ -900,7 +894,7 @@ unsafe extern "cdecl" fn create_arrow_impl(
900
  }
901
 
902
  // Look up parent CTaskTurnGame via SharedData (key 0, 0x19)
903
- let table = SharedDataTable::from_task(task as *const _ as *const openwa_core::task::CTask);
904
  let parent = table.lookup(0, 0x19);
905
 
906
  // Allocate CTaskArrow (0x168 bytes)
 
20
  use openwa_core::game::weapon::{WeaponEntry, WeaponFireParams};
21
  use openwa_core::game::Weapon;
22
  use openwa_core::log::log_line;
23
+ use openwa_core::task::Task;
24
  use openwa_core::task::worm::CTaskWorm;
25
 
26
  use crate::hook::{self, usercall_trampoline};
 
407
  ///
408
  /// Returns null if not found.
409
  unsafe fn lookup_team_task(worm: *const CTaskWorm) -> *mut openwa_core::task::CTaskTeam {
410
+ use openwa_core::task::{SharedDataTable, Task};
411
 
412
+ let table = SharedDataTable::from_task((*worm).as_task_ptr());
 
413
  // CTaskTeam is registered with key (0, 0x14) in SharedData
414
  table.lookup(0, 0x14) as *mut openwa_core::task::CTaskTeam
415
  }
 
432
  buf[0..4].copy_from_slice(&team_index.to_ne_bytes());
433
 
434
  (*team).handle_message(
435
+ (*worm).as_task_ptr_mut(),
436
  msg_type,
437
  4,
438
  buf.as_ptr(),
 
453
  buf[4..8].copy_from_slice(&(*worm).team_index.to_ne_bytes());
454
 
455
  (*team).handle_message(
456
+ (*worm).as_task_ptr_mut(),
457
  0x5D,
458
  0x408,
459
  buf.as_ptr(),
 
467
  /// In game_version > 0x1C: toggles (set/clear). Otherwise: always sets.
468
  unsafe fn fire_skip_go(worm: *const CTaskWorm, entry: *const WeaponEntry) {
469
  use openwa_core::engine::ddgame::TeamArenaRef;
470
+ let ddgame = (*worm).ddgame();
 
 
471
  let game_version = (*(*ddgame).game_info).game_version;
472
  let team_index = (*worm).team_index as usize;
473
 
 
494
 
495
  fire_send_team_message(worm, 0x29);
496
 
497
+ let ddgame = (*worm).ddgame();
498
  let arena = TeamArenaRef::from_ptr(&raw mut (*ddgame).team_arena);
499
  let team_index = (*worm).team_index as usize;
500
  let worm_index = (*worm).worm_index as usize;
 
516
  /// - otherwise: skip
517
  unsafe fn fire_mail_mine_mole(worm: *mut CTaskWorm) {
518
  use openwa_core::engine::ddgame::TeamArenaRef;
519
+ let ddgame = (*worm).ddgame();
 
 
520
  let version = *((ddgame as *const u8).add(0x7E40));
521
  let worm_state = (*worm).state();
522
 
 
709
  worm: *mut CTaskWorm, fire_params: *const WeaponFireParams, local_struct: u32,
710
  ) {
711
  use openwa_core::rebase::rb;
712
+ use openwa_core::task::{SharedDataTable, Task};
713
  use openwa_core::wa_alloc::wa_malloc;
714
 
715
+ let ddgame = &mut *(*worm).ddgame();
 
716
 
717
  // Pool capacity check: pool_count + 7 must be <= 700
718
  if ddgame.object_pool_count + 7 > 700 {
 
721
  }
722
 
723
  // Look up parent CTaskTurnGame via SharedData (key_esi=0, key_edi=0x19)
724
+ let table = SharedDataTable::from_task((*worm).as_task_ptr());
725
  let parent = table.lookup(0, 0x19);
726
 
727
  // Allocate CTaskMissile (0x40C bytes)
 
802
  let sin_table = rb(va::SIN_TABLE) as *const i32;
803
  let cos_table = sin_table.add(256); // cos = sin offset by 256 entries (quarter turn)
804
 
805
+ let ddgame = &mut *(*worm).ddgame();
806
 
807
  for _i in 0..shot_count {
808
  // Advance game RNG (same LCG as ADVANCE_GAME_RNG at 0x53F320)
 
882
  worm: *mut CTaskWorm, fire_params: *const WeaponFireParams, local_struct: u32,
883
  ) {
884
  use openwa_core::rebase::rb;
885
+ use openwa_core::task::{SharedDataTable, Task};
886
  use openwa_core::wa_alloc::wa_malloc;
887
 
888
+ let ddgame = &mut *(*worm).ddgame();
 
889
 
890
  // Pool capacity check: pool_count + 2 must be <= 700
891
  if ddgame.object_pool_count + 2 > 700 {
 
894
  }
895
 
896
  // Look up parent CTaskTurnGame via SharedData (key 0, 0x19)
897
+ let table = SharedDataTable::from_task((*worm).as_task_ptr());
898
  let parent = table.lookup(0, 0x19);
899
 
900
  // Allocate CTaskArrow (0x168 bytes)