fix: read weapon ID from CTaskWorm in FireWeapon logger
Browse filesThe stack param to FireWeapon is the CTaskWorm pointer (pushed by
WeaponRelease as EDI=EAX from its usercall convention). Read
selected_weapon at CTaskWorm+0x170 for accurate weapon names.
Previous version read from wrong offset in weapon context, producing
garbage (Skunk, SheepStrike, None). Now correctly shows:
Bazooka(27), Uzi(10), Grenade(9), Teleport(4), etc.
Also reveals dispatch table correction: Bazooka uses sub38=3
(CreateWeaponProjectile), not sub38=2 (FireWeapon__Projectile).
Verified: headless PASS, headful 133+3 / 0 FAIL.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-wormkit/src/replacements/weapon.rs
CHANGED
|
@@ -137,32 +137,42 @@ usercall_trampoline!(fn trampoline_count_alive_worms; impl_fn = count_alive_worm
|
|
| 137 |
|
| 138 |
static ORIG_FIRE_WEAPON: AtomicU32 = AtomicU32::new(0);
|
| 139 |
|
| 140 |
-
/// Logger called from the naked passthrough.
|
| 141 |
-
///
|
| 142 |
-
///
|
| 143 |
-
unsafe extern "cdecl" fn fire_weapon_log(weapon_ctx: u32) {
|
| 144 |
let ctx = weapon_ctx as *const u8;
|
| 145 |
let weapon_type = *(ctx.add(0x30) as *const i32);
|
| 146 |
let subtype_34 = *(ctx.add(0x34) as *const i32);
|
| 147 |
let subtype_38 = *(ctx.add(0x38) as *const i32);
|
| 148 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
let _ = log_line(&format!(
|
| 150 |
-
"[Weapon] FireWeapon: type={} sub34={} sub38={}",
|
| 151 |
-
weapon_type, subtype_34, subtype_38
|
| 152 |
));
|
| 153 |
}
|
| 154 |
|
| 155 |
/// Naked passthrough: save regs → call logger → restore → jmp original.
|
|
|
|
|
|
|
| 156 |
#[unsafe(naked)]
|
| 157 |
unsafe extern "C" fn trampoline_fire_weapon() {
|
| 158 |
core::arch::naked_asm!(
|
| 159 |
"push eax",
|
| 160 |
"push ecx",
|
| 161 |
"push edx",
|
| 162 |
-
// call logger
|
|
|
|
|
|
|
| 163 |
"push eax",
|
| 164 |
"call {log_fn}",
|
| 165 |
-
"add esp,
|
| 166 |
"pop edx",
|
| 167 |
"pop ecx",
|
| 168 |
"pop eax",
|
|
|
|
| 137 |
|
| 138 |
static ORIG_FIRE_WEAPON: AtomicU32 = AtomicU32::new(0);
|
| 139 |
|
| 140 |
+
/// Logger called from the naked passthrough.
|
| 141 |
+
/// `weapon_ctx` = EAX = pointer to weapon data (from CTaskWorm+0x36C).
|
| 142 |
+
/// `worm_ptr` = stack param = CTaskWorm pointer (pushed by WeaponRelease).
|
| 143 |
+
unsafe extern "cdecl" fn fire_weapon_log(weapon_ctx: u32, worm_ptr: u32) {
|
| 144 |
let ctx = weapon_ctx as *const u8;
|
| 145 |
let weapon_type = *(ctx.add(0x30) as *const i32);
|
| 146 |
let subtype_34 = *(ctx.add(0x34) as *const i32);
|
| 147 |
let subtype_38 = *(ctx.add(0x38) as *const i32);
|
| 148 |
|
| 149 |
+
// Read selected weapon from CTaskWorm+0x170
|
| 150 |
+
let weapon_id = *((worm_ptr as *const u8).add(0x170) as *const u32);
|
| 151 |
+
let weapon_name = Weapon::try_from(weapon_id)
|
| 152 |
+
.map(|w| format!("{:?}", w))
|
| 153 |
+
.unwrap_or_else(|id| format!("Unknown({})", id));
|
| 154 |
+
|
| 155 |
let _ = log_line(&format!(
|
| 156 |
+
"[Weapon] FireWeapon: {} (id={}) type={} sub34={} sub38={}",
|
| 157 |
+
weapon_name, weapon_id, weapon_type, subtype_34, subtype_38
|
| 158 |
));
|
| 159 |
}
|
| 160 |
|
| 161 |
/// Naked passthrough: save regs → call logger → restore → jmp original.
|
| 162 |
+
/// Stack layout at entry: [ret_addr] [wrapper_param]
|
| 163 |
+
/// We read wrapper_param to pass to the logger as the worm pointer.
|
| 164 |
#[unsafe(naked)]
|
| 165 |
unsafe extern "C" fn trampoline_fire_weapon() {
|
| 166 |
core::arch::naked_asm!(
|
| 167 |
"push eax",
|
| 168 |
"push ecx",
|
| 169 |
"push edx",
|
| 170 |
+
// call logger(weapon_ctx=EAX, worm_ptr=[ESP+16])
|
| 171 |
+
// ESP+16 because: 3 pushes (12 bytes) + ret_addr (4) = 16 to stack param
|
| 172 |
+
"push [esp+16]",
|
| 173 |
"push eax",
|
| 174 |
"call {log_fn}",
|
| 175 |
+
"add esp, 8",
|
| 176 |
"pop edx",
|
| 177 |
"pop ecx",
|
| 178 |
"pop eax",
|