paavohtl Claude Opus 4.6 (1M context) commited on
Commit
7b6533e
Β·
1 Parent(s): 8304a79

refactor: add wa_malloc_zeroed, use typed arrays and &raw mut in DDGame ctor

Browse files

Add wa_malloc_zeroed() utility that combines wa_malloc + write_bytes.
Replace 10 malloc+zero pairs in DDGame constructor with single calls.

Type landscape temp buffers as [u32] arrays instead of [u8], enabling
direct indexing for coordinate data. Update wa_pc_landscape_ctor
signature to match (*mut u32 for output params). Use &raw mut for
obtaining raw pointers to DDGame fields.

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

crates/openwa-core/src/engine/ddgame.rs CHANGED
@@ -19,7 +19,7 @@ use crate::render::landscape::PCLandscape;
19
  use crate::render::queue::RenderQueue;
20
  use crate::render::turn_order::TurnOrderWidget;
21
  use crate::task::bit_grid::BitGrid;
22
- use crate::wa_alloc::wa_malloc;
23
 
24
  /// DDGame β€” the main game engine object.
25
  ///
@@ -586,10 +586,10 @@ unsafe fn wa_pc_landscape_ctor(
586
  landscape_path: *const u8,
587
  byte_output: *mut u8,
588
  gfx_mode: u32,
589
- temp_buf: *mut u8,
590
- coord_output: *mut u8,
591
- width_output: *mut u8,
592
- height_output: *mut u8,
593
  ) -> *mut u8 {
594
  let f: unsafe extern "stdcall" fn(
595
  *mut u8,
@@ -599,10 +599,10 @@ unsafe fn wa_pc_landscape_ctor(
599
  *const u8,
600
  *mut u8,
601
  u32,
602
- *mut u8,
603
- *mut u8,
604
- *mut u8,
605
- *mut u8,
606
  ) -> *mut u8 = core::mem::transmute(rb(va::PC_LANDSCAPE_CONSTRUCTOR) as usize);
607
  f(
608
  this,
@@ -680,11 +680,10 @@ pub unsafe fn create_ddgame(
680
  network_ecx: u32, // implicit ECX from caller
681
  ) -> *mut DDGame {
682
  // ── 1. Allocate and zero-fill (matches: memset(piVar3, 0, 0x98B8)) ──
683
- let ddgame = wa_malloc(0x98B8) as *mut DDGame;
684
  if ddgame.is_null() {
685
  return core::ptr::null_mut();
686
  }
687
- core::ptr::write_bytes(ddgame as *mut u8, 0, 0x98B8);
688
 
689
  // Notify watchpoint debugger (if active) so it can arm DR0–DR3.
690
  if let Some(cb) = ON_DDGAME_ALLOC {
@@ -725,8 +724,7 @@ pub unsafe fn create_ddgame(
725
 
726
  // ── 8. Conditional network object (game_version == -2) ──
727
  if (*game_info).game_version == -2 {
728
- let net_obj = wa_malloc(0x2C);
729
- core::ptr::write_bytes(net_obj, 0, 0x2C);
730
  *(net_obj as *mut *mut DDGame) = ddgame;
731
  *net_obj.add(0x28) = (*game_info).net_config_1;
732
  *net_obj.add(0x29) = (*game_info).net_config_2;
@@ -918,8 +916,7 @@ unsafe fn init_graphics_and_resources(
918
 
919
  // ── Secondary GfxDir object (DDGame+0x2C, conditional) ──
920
  if !(*wrapper).secondary_gfx_dir.is_null() {
921
- let gfxdir2 = wa_malloc(0x70C);
922
- core::ptr::write_bytes(gfxdir2, 0, 0x70C);
923
  *(gfxdir2 as *mut u16) = 1;
924
  *(gfxdir2.add(2) as *mut u16) = 0x5A;
925
  // FUN_5411A0: usercall(EAX=gfxdir2), plain RET
@@ -967,8 +964,7 @@ unsafe fn init_graphics_and_resources(
967
  let gfx_resource: *mut u8;
968
  {
969
  let gfx_dir = (*wrapper).primary_gfx_dir;
970
- let out_buf = wa_malloc(0x900);
971
- core::ptr::write_bytes(out_buf, 0, 0x900);
972
  gfx_resource =
973
  gfx_resource_create(gfx_dir, rb(va::STR_MASKS_IMG) as *const c_char, out_buf);
974
  }
@@ -976,13 +972,12 @@ unsafe fn init_graphics_and_resources(
976
  // ── PCLandscape (alloc 0xB44, stdcall 11 params) ──
977
  // Temporary output buffers for landscape coordinate data (used later for coord_list).
978
  // These were stack locals in the original code (aiStack_978, iStack_11f9).
979
- let mut landscape_coords_buf = [0u8; 0x1000]; // 4KB for coord output
980
  let mut landscape_byte_buf = [0u8; 0x100]; // byte output
981
- let mut landscape_temp = [0u8; 0x1000]; // coord count + temp data
982
 
983
  let landscape = {
984
- let alloc = wa_malloc(0xB44);
985
- core::ptr::write_bytes(alloc, 0, 0xB44);
986
  if !alloc.is_null() {
987
  let result = wa_pc_landscape_ctor(
988
  alloc,
@@ -994,8 +989,8 @@ unsafe fn init_graphics_and_resources(
994
  (*wrapper).gfx_mode,
995
  landscape_temp.as_mut_ptr(),
996
  landscape_coords_buf.as_mut_ptr(),
997
- &mut (*ddgame).level_width_raw as *mut u32 as *mut u8,
998
- &mut (*ddgame).level_height_raw as *mut u32 as *mut u8,
999
  );
1000
  (*wrapper).landscape = result as *mut PCLandscape;
1001
  (*ddgame).landscape = result as *mut PCLandscape;
@@ -1039,8 +1034,7 @@ unsafe fn init_graphics_and_resources(
1039
  ];
1040
 
1041
  for &(offset, ecx, edx, p2, p3, p4, p5, p6) in &regions {
1042
- let alloc = wa_malloc(0x9C);
1043
- core::ptr::write_bytes(alloc, 0, 0x9C);
1044
  let result = if !alloc.is_null() {
1045
  call_sprite_region_ctor(alloc, ecx, edx, p2, p3, p4, p5, p6)
1046
  } else {
@@ -1106,8 +1100,7 @@ unsafe fn init_graphics_and_resources(
1106
  let half_h = (sprite_h / 2 - 10).max(0);
1107
 
1108
  // Create SpriteRegion for collision
1109
- let alloc = wa_malloc(0x9C);
1110
- core::ptr::write_bytes(alloc, 0, 0x9C);
1111
  let region = if !alloc.is_null() {
1112
  // SpriteRegion params: ECX, EDX, this, p2, p3, p4, p5, p6
1113
  // this[3] = p4 - p2 (width), this[4] = EDX - p3 (height)
@@ -1162,8 +1155,7 @@ unsafe fn init_graphics_and_resources(
1162
  let cl = wa_malloc(12) as *mut u32;
1163
  *cl = 0; // count
1164
  *cl.add(1) = 600; // capacity
1165
- let data = wa_malloc(0x12C0);
1166
- core::ptr::write_bytes(data, 0, 0x12C0);
1167
  *cl.add(2) = data as u32;
1168
  (*ddgame).coord_list = cl as *mut u8;
1169
 
@@ -1171,12 +1163,11 @@ unsafe fn init_graphics_and_resources(
1171
  // landscape_temp[0] = coordinate count, landscape_coords_buf = pairs of (x, y).
1172
  // Original packs as: coord = x * 0x10000 + y (Fixed-point).
1173
  // Each coord_list entry is 8 bytes: [coord_value, 1]. Duplicates are skipped.
1174
- let coord_count = *(landscape_temp.as_ptr() as *const u32);
1175
- let coords_src = landscape_coords_buf.as_ptr() as *const u32;
1176
  let data_ptr = data as *mut u32;
1177
  for j in 0..coord_count as usize {
1178
- let x = *coords_src.add(j * 2);
1179
- let y = *coords_src.add(j * 2 + 1);
1180
  let coord_val = x.wrapping_mul(0x10000).wrapping_add(y);
1181
  let cur_count = *cl as usize;
1182
  if cur_count >= 600 {
@@ -1325,9 +1316,8 @@ unsafe fn init_graphics_and_resources(
1325
  // ── Gradient image stub (DDGame+0x30) ──
1326
  // Minimal stub: [6]=0 (zero-width) so CTaskLand skips the gradient column loop.
1327
  if (*ddgame).gradient_image.is_null() {
1328
- let obj = wa_malloc(core::mem::size_of::<BitGrid>() as u32) as *mut BitGrid;
1329
  if !obj.is_null() {
1330
- core::ptr::write_bytes(obj as *mut u8, 0, core::mem::size_of::<BitGrid>());
1331
  (*obj).vtable = rb(va::BIT_GRID_VTABLE);
1332
  // height = 0 β†’ CTaskLand skips the gradient column loop
1333
  (*ddgame).gradient_image = obj as *mut u8;
 
19
  use crate::render::queue::RenderQueue;
20
  use crate::render::turn_order::TurnOrderWidget;
21
  use crate::task::bit_grid::BitGrid;
22
+ use crate::wa_alloc::{wa_malloc, wa_malloc_zeroed};
23
 
24
  /// DDGame β€” the main game engine object.
25
  ///
 
586
  landscape_path: *const u8,
587
  byte_output: *mut u8,
588
  gfx_mode: u32,
589
+ temp_buf: *mut u32,
590
+ coord_output: *mut u32,
591
+ width_output: *mut u32,
592
+ height_output: *mut u32,
593
  ) -> *mut u8 {
594
  let f: unsafe extern "stdcall" fn(
595
  *mut u8,
 
599
  *const u8,
600
  *mut u8,
601
  u32,
602
+ *mut u32,
603
+ *mut u32,
604
+ *mut u32,
605
+ *mut u32,
606
  ) -> *mut u8 = core::mem::transmute(rb(va::PC_LANDSCAPE_CONSTRUCTOR) as usize);
607
  f(
608
  this,
 
680
  network_ecx: u32, // implicit ECX from caller
681
  ) -> *mut DDGame {
682
  // ── 1. Allocate and zero-fill (matches: memset(piVar3, 0, 0x98B8)) ──
683
+ let ddgame = wa_malloc_zeroed(0x98B8) as *mut DDGame;
684
  if ddgame.is_null() {
685
  return core::ptr::null_mut();
686
  }
 
687
 
688
  // Notify watchpoint debugger (if active) so it can arm DR0–DR3.
689
  if let Some(cb) = ON_DDGAME_ALLOC {
 
724
 
725
  // ── 8. Conditional network object (game_version == -2) ──
726
  if (*game_info).game_version == -2 {
727
+ let net_obj = wa_malloc_zeroed(0x2C);
 
728
  *(net_obj as *mut *mut DDGame) = ddgame;
729
  *net_obj.add(0x28) = (*game_info).net_config_1;
730
  *net_obj.add(0x29) = (*game_info).net_config_2;
 
916
 
917
  // ── Secondary GfxDir object (DDGame+0x2C, conditional) ──
918
  if !(*wrapper).secondary_gfx_dir.is_null() {
919
+ let gfxdir2 = wa_malloc_zeroed(0x70C);
 
920
  *(gfxdir2 as *mut u16) = 1;
921
  *(gfxdir2.add(2) as *mut u16) = 0x5A;
922
  // FUN_5411A0: usercall(EAX=gfxdir2), plain RET
 
964
  let gfx_resource: *mut u8;
965
  {
966
  let gfx_dir = (*wrapper).primary_gfx_dir;
967
+ let out_buf = wa_malloc_zeroed(0x900);
 
968
  gfx_resource =
969
  gfx_resource_create(gfx_dir, rb(va::STR_MASKS_IMG) as *const c_char, out_buf);
970
  }
 
972
  // ── PCLandscape (alloc 0xB44, stdcall 11 params) ──
973
  // Temporary output buffers for landscape coordinate data (used later for coord_list).
974
  // These were stack locals in the original code (aiStack_978, iStack_11f9).
975
+ let mut landscape_coords_buf = [0u32; 0x400]; // coord output: pairs of (x, y)
976
  let mut landscape_byte_buf = [0u8; 0x100]; // byte output
977
+ let mut landscape_temp = [0u32; 0x400]; // [0] = coord count, rest = temp data
978
 
979
  let landscape = {
980
+ let alloc = wa_malloc_zeroed(0xB44);
 
981
  if !alloc.is_null() {
982
  let result = wa_pc_landscape_ctor(
983
  alloc,
 
989
  (*wrapper).gfx_mode,
990
  landscape_temp.as_mut_ptr(),
991
  landscape_coords_buf.as_mut_ptr(),
992
+ &raw mut (*ddgame).level_width_raw,
993
+ &raw mut (*ddgame).level_height_raw,
994
  );
995
  (*wrapper).landscape = result as *mut PCLandscape;
996
  (*ddgame).landscape = result as *mut PCLandscape;
 
1034
  ];
1035
 
1036
  for &(offset, ecx, edx, p2, p3, p4, p5, p6) in &regions {
1037
+ let alloc = wa_malloc_zeroed(0x9C);
 
1038
  let result = if !alloc.is_null() {
1039
  call_sprite_region_ctor(alloc, ecx, edx, p2, p3, p4, p5, p6)
1040
  } else {
 
1100
  let half_h = (sprite_h / 2 - 10).max(0);
1101
 
1102
  // Create SpriteRegion for collision
1103
+ let alloc = wa_malloc_zeroed(0x9C);
 
1104
  let region = if !alloc.is_null() {
1105
  // SpriteRegion params: ECX, EDX, this, p2, p3, p4, p5, p6
1106
  // this[3] = p4 - p2 (width), this[4] = EDX - p3 (height)
 
1155
  let cl = wa_malloc(12) as *mut u32;
1156
  *cl = 0; // count
1157
  *cl.add(1) = 600; // capacity
1158
+ let data = wa_malloc_zeroed(0x12C0);
 
1159
  *cl.add(2) = data as u32;
1160
  (*ddgame).coord_list = cl as *mut u8;
1161
 
 
1163
  // landscape_temp[0] = coordinate count, landscape_coords_buf = pairs of (x, y).
1164
  // Original packs as: coord = x * 0x10000 + y (Fixed-point).
1165
  // Each coord_list entry is 8 bytes: [coord_value, 1]. Duplicates are skipped.
1166
+ let coord_count = landscape_temp[0];
 
1167
  let data_ptr = data as *mut u32;
1168
  for j in 0..coord_count as usize {
1169
+ let x = landscape_coords_buf[j * 2];
1170
+ let y = landscape_coords_buf[j * 2 + 1];
1171
  let coord_val = x.wrapping_mul(0x10000).wrapping_add(y);
1172
  let cur_count = *cl as usize;
1173
  if cur_count >= 600 {
 
1316
  // ── Gradient image stub (DDGame+0x30) ──
1317
  // Minimal stub: [6]=0 (zero-width) so CTaskLand skips the gradient column loop.
1318
  if (*ddgame).gradient_image.is_null() {
1319
+ let obj = wa_malloc_zeroed(core::mem::size_of::<BitGrid>() as u32) as *mut BitGrid;
1320
  if !obj.is_null() {
 
1321
  (*obj).vtable = rb(va::BIT_GRID_VTABLE);
1322
  // height = 0 β†’ CTaskLand skips the gradient column loop
1323
  (*ddgame).gradient_image = obj as *mut u8;
crates/openwa-core/src/wa_alloc.rs CHANGED
@@ -13,6 +13,20 @@ pub unsafe fn wa_malloc(size: u32) -> *mut u8 {
13
  f(size)
14
  }
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  /// Free a pointer allocated by [`wa_malloc`] (WA's statically-linked CRT `free`).
17
  ///
18
  /// # Safety
 
13
  f(size)
14
  }
15
 
16
+ /// Allocate `size` bytes from WA's CRT heap and zero-initialize them.
17
+ ///
18
+ /// Equivalent to `wa_malloc(size)` followed by `write_bytes(ptr, 0, size)`.
19
+ ///
20
+ /// # Safety
21
+ /// Must only be called from within the WA.exe process.
22
+ pub unsafe fn wa_malloc_zeroed(size: u32) -> *mut u8 {
23
+ let ptr = wa_malloc(size);
24
+ if !ptr.is_null() {
25
+ core::ptr::write_bytes(ptr, 0, size as usize);
26
+ }
27
+ ptr
28
+ }
29
+
30
  /// Free a pointer allocated by [`wa_malloc`] (WA's statically-linked CRT `free`).
31
  ///
32
  /// # Safety