- Status
- Offline
- Joined
- Mar 3, 2026
- Messages
- 805
- Reaction score
- 457
Spent some quality time reversing the Frostbite engine to get a proper silent aim working in BF4. If you've tried writing to variables externally and failed, it's because you're fighting a losing battle against the engine's internal update loop. Here is the breakdown of how to handle it correctly via an internal hook.
The Frostbite ShootSpace Mechanics
In BF4, bullet direction isn't a simple vector you can just poke. The game uses a ShootSpace 4x4 column-major matrix located inside ClientWeapon at offset
When a bullet is spawned, the game takes
Because the camera and crosshair rely on AimingSim, while bullets rely on ShootSpace, we can manipulate the latter to achieve perfect silent aim with zero visual snapping or flicker.
ShootSpace Matrix Layout (ClientWeapon + 0x40):
The Hook: Overcoming Race Conditions
You cannot write to ShootSpace from a separate thread reliably. The game's matrix copy function will either overwrite your changes before the bullet spawns, or you'll write too late. To win, you have to hook the matrix copy function directly at
Pointer Chain & Offsets
Global ClientGameContext:
Implementation Snippet
Reversing Notes & Safety
Curious if anyone has experimented with modifying the ShotConfigData velocity vectors directly to handle high-velocity offsets without hitting the matrix—thoughts?
The Frostbite ShootSpace Mechanics
In BF4, bullet direction isn't a simple vector you can just poke. The game uses a ShootSpace 4x4 column-major matrix located inside ClientWeapon at offset
+0x40. Every frame, the engine rebuilds this matrix from your AimingSim angles (Yaw/Pitch) and copies it over.When a bullet is spawned, the game takes
ShotConfigData::m_Direction (which is always a static 0, 0, 1, 0) and multiplies it by this ShootSpace matrix. Effectively, the bullet's world-space direction is just Column 2 of that matrix.Because the camera and crosshair rely on AimingSim, while bullets rely on ShootSpace, we can manipulate the latter to achieve perfect silent aim with zero visual snapping or flicker.
ShootSpace Matrix Layout (ClientWeapon + 0x40):
- Column 0: Right Vector
- Column 1: Up Vector
- Column 2: Forward Vector (Bullet Direction)
- Column 3: Translation (Muzzle Position)
The Hook: Overcoming Race Conditions
You cannot write to ShootSpace from a separate thread reliably. The game's matrix copy function will either overwrite your changes before the bullet spawns, or you'll write too late. To win, you have to hook the matrix copy function directly at
bf4.exe+0x1473B0.This function is roughly 33 bytes. It takes the source matrix in RDX and copies it to RCX+0x40.
By intercepting this and modifying Column 2 in the source matrix before the copy completes, you ensure the bullet spawns with your calculated trajectory.
Code:
0x1401473B0: 0F 28 02 movaps xmm0, [rdx] ; Source Col 0
0x1401473B3: 0F 29 41 40 movaps [rcx+0x40], xmm0 ; To ShootSpace
0x1401473BF: 0F 28 42 20 movaps xmm0, [rdx+0x20] ; Source Col 2 (Bullet Dir)
0x1401473C3: 0F 29 41 60 movaps [rcx+0x60], xmm0 ; Modify this
Pointer Chain & Offsets
Global ClientGameContext:
0x142670D80- ClientGameContext + 0x60 -> PlayerManager
- PlayerManager + 0x540 -> LocalPlayer
- LocalPlayer + 0x14B0 -> Soldier (Double deref, result - 8)
- Soldier + 0x570 -> WeaponsComponent
- WeaponsComponent + 0x890 -> WeaponHandler
- SoldierWeapon + 0x49A8 -> ClientWeapon
- SoldierWeapon + 0x49C0 -> WeaponFiring
- WeaponFiring + 0x1AC -> IsNotFiring (uint8, 0 = Active Shooting)
Implementation Snippet
Code:
static void __fastcall Hook_CopyShootSpace(uintptr_t dest, float* src) {
__try {
if (s_silentAimActive && dest == (uintptr_t)s_silentClientWeapon) {
uintptr_t wf = (uintptr_t)s_silentWeaponFiring;
if (wf && IsValidPtr(wf)) {
if (Read<uint8_t>(wf + 0x1AC) == 0) {
// Overwrite source matrix column 2
src[8] = s_silentDirX;
src[9] = s_silentDirY;
src[10] = s_silentDirZ;
}
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {}
g_origCopyShootSpace(dest, src);
}
Reversing Notes & Safety
- Writing to
ClientWeapon + 0x10(m_Direction) will cause an immediate crash; it holds pointers, not floats. - The hook is safe from flicker because it doesn't touch the AimingSim.
- Always verify the IsNotFiring byte to avoid weird tracers when you aren't pulling the trigger.
- FairFight might look at your view-to-shot angle delta if you go too blatant. Punkbuster is effectively a non-issue here.
Curious if anyone has experimented with modifying the ShotConfigData velocity vectors directly to handle high-velocity offsets without hitting the matrix—thoughts?