- Status
- Offline
- Joined
- Mar 3, 2026
- Messages
- 546
- Reaction score
- 7
Warface RMI Logic — Sending SvRequestShootHit without Hardcoded Addresses
If you are still chasing raw offsets for every single action in Warface, you are doing it the hard way. The CryEngine RMI (Remote Method Invocation) system is the backbone of how the client talks to the server about shots and hits. By leveraging the internal InvokeRMI methods, you can trigger shoot events that look completely native to the engine logic without manual assembly hookup or constant pointer updates.
Core Shoot and Hit Structures
Below are the structures required to pack a hit request properly. This includes the hit target, projectile synchronization, and the final shoot-hit packet. This is essential for anyone building a serious internal aimed at silent aim or perfect bullet registration.
The Shoot Wrapper
Implementation via IGameObject
The magic happens in SvRequestShootHit. You populate the shoot position, direction, and a vector of projectiles/hits. Instead of finding a specific function address, you pull the RMI extension from the item proxy.
Prevention and Stability
This is a solid start for a clean internal base. If you can't satisfy the dependencies like the IItem interface or the CRMIBody smart pointers, you probably shouldn't be deep-diving into CryEngine RMIs anyway.
Anyone tested this on the latest patch to see if they added more server-side validation to the physCounter?
If you are still chasing raw offsets for every single action in Warface, you are doing it the hard way. The CryEngine RMI (Remote Method Invocation) system is the backbone of how the client talks to the server about shots and hits. By leveraging the internal InvokeRMI methods, you can trigger shoot events that look completely native to the engine logic without manual assembly hookup or constant pointer updates.
Core Shoot and Hit Structures
Below are the structures required to pack a hit request properly. This includes the hit target, projectile synchronization, and the final shoot-hit packet. This is essential for anyone building a serious internal aimed at silent aim or perfect bullet registration.
Code:
struct SvRequestHit
{
SvRequestHit()
: damageReduction(0)
, physCounter(0)
, targetId(0)
, material(0)
, typeId(0)
, partId(0)
, pos(0)
{
}
void SerializeWith(TSerialize ser)
{
ser.Value(0, targetId, 'eid');
ser.Value(0, material, 'mat');
ser.Value(0, typeId, 'hTyp');
ser.Value(0, partId, 'binv');
ser.Value(0, damageReduction, 'hVal');
ser.Value(0, pos);
ser.Value(0, physCounter, 'ui2');
}
EntityId targetId; // 0x00
int32 material; // 0x04
int32 typeId; // 0x08
int32 partId; // 0x0C
Vec3 pos; // 0x10
f32 damageReduction; // 0x1C
uint8 physCounter; // 0x20
};
struct SvRequestProjectile
{
SvRequestProjectile(EntityId projectileId, const std::vector<SvRequestHit>& hits) : projectileId(projectileId), hits(hits) {}
void SerializeWith(TSerialize ser)
{
ser.Value(0, projectileId, 'deid');
int hitCount = ser.IsReading() ? 0 : (int)hits.size();
ser.Value(0, hitCount, 'stid');
if (ser.IsReading())
{
hits.resize(hitCount);
}
for (int i = 0; i < hitCount; ++i)
{
hits[i].SerializeWith(ser);
}
}
EntityId projectileId;
std::vector<SvRequestHit> hits;
};
The Shoot Wrapper
Code:
struct SvRequestShootHit
{
void SerializeWith(TSerialize ser)
{
ser.Value(0, predictionHandle, 'phdl');
ser.Value(0, dir, 'dir3');
ser.Value(0, shootPos);
ser.Value(0, physCounter, 'ui2');
ser.Value(0, fireCounter, 'ui8');
ser.Value(0, spreadMax, 'sprd');
ser.Value(0, nulled, 'bool');
ser.Value(0, bulletType);
int projCount = ser.IsReading() ? 0 : (int)projectiles.size();
ser.Value(0, projCount, 'stid');
if (ser.IsReading())
{
projectiles.resize(projCount);
}
for (int i = 0; i < projCount; ++i)
{
projectiles[i].SerializeWith(ser);
}
}
Vec3 shootPos; // 0x00
int32 predictionHandle; // 0x0C
Vec3 dir; // 0x10
uint8 physCounter; // 0x1C
std::vector<SvRequestProjectile> projectiles; // 0x20
uint8 fireCounter; // 0x38
f32 spreadMax; // 0x3C
bool nulled; // 0x40
int32 bulletType; // 0x44
};
Implementation via IGameObject
The magic happens in SvRequestShootHit. You populate the shoot position, direction, and a vector of projectiles/hits. Instead of finding a specific function address, you pull the RMI extension from the item proxy.
Code:
void RequestShootHit(IItem* pItem, SvRequestShootHit& request)
{
pItem->GetGameObject()->InvokeRMI(pItem->GetRMIExtension("RMI:CItemProxy:SvRequestShootHit"), request, eRMI_ToServer, -1);
}
Prevention and Stability
- Don't ignore the predictionHandle — CryEngine uses it for desync checks. If you send garbage here, you are asking for a kick.
- Serialization is key. Ensure your bitstream serialization matches the target engine build precisely.
- The string "RMI:CItemProxy:SvRequestShootHit" identifies the function in the RMI table. If the game updates and changes the RMI name, this will break, but it's far more stable than raw addresses.
This is a solid start for a clean internal base. If you can't satisfy the dependencies like the IItem interface or the CRMIBody smart pointers, you probably shouldn't be deep-diving into CryEngine RMIs anyway.
Anyone tested this on the latest patch to see if they added more server-side validation to the physCounter?