Prediction/Sample weapon
This weapon will print data to the console when prediction events occur. Equip it with give weapon_test
.
C++
Include this in both your client and server projects.
#include "cbase.h"
#ifdef CLIENT_DLL
#include "prediction.h"
#define CTestWeapon C_TestWeapon
#endif
class CTestWeapon : public CBaseCombatWeapon
{
public:
DECLARE_CLASS( CTestWeapon, CBaseCombatWeapon );
DECLARE_NETWORKCLASS();
#ifdef CLIENT_DLL
DECLARE_PREDICTABLE();
virtual bool ShouldPredict();
#endif
virtual bool IsPredicted() const { return true; }
CTestWeapon() { SetPredictionEligible(true); iTest = 0; }
void PrimaryAttack();
void SecondaryAttack();
void ShootBullet(bool bRapidFire);
#ifdef GAME_DLL
CNetworkVar( int, iTest );
#elif CLIENT_DLL
int iTest;
#endif
};
LINK_ENTITY_TO_CLASS( weapon_test, CTestWeapon );
PRECACHE_WEAPON_REGISTER( weapon_test );
IMPLEMENT_NETWORKCLASS_ALIASED( TestWeapon, DT_TestWeapon )
#ifdef CLIENT_DLL
BEGIN_PREDICTION_DATA( CTestWeapon )
DEFINE_PRED_FIELD( iTest, FIELD_INTEGER, FTYPEDESC_NOERRORCHECK)
END_PREDICTION_DATA()
bool CTestWeapon::ShouldPredict()
{
if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
else
return BaseClass::ShouldPredict();
}
void RecvProxy_TestWeapon( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
int value = *((unsigned long*)&pData->m_Value.m_Int);
static int oldvalue = 0;
if ( value != oldvalue )
Warning( "Client updated to shot %i\n", value );
oldvalue = value;
*((unsigned long*)pOut) = value;
}
#endif // CLIENT_DLL
BEGIN_NETWORK_TABLE( CTestWeapon, DT_TestWeapon )
#ifdef GAME_DLL
SendPropInt( SENDINFO(iTest) ),
#elif CLIENT_DLL
RecvPropInt( RECVINFO(iTest),-1, RecvProxy_TestWeapon ),
#endif
END_NETWORK_TABLE()
void CTestWeapon::PrimaryAttack()
{
ShootBullet(false);
m_flNextPrimaryAttack = gpGlobals->curtime + 0.75;
}
void CTestWeapon::SecondaryAttack()
{
ShootBullet(true);
m_flNextSecondaryAttack = gpGlobals->curtime + 0.25;
}
void CTestWeapon::ShootBullet(bool bRapidFire)
{
iTest++;
#ifdef CLIENT_DLL
if ( prediction->IsFirstTimePredicted() )
Msg( "Client made shot %i\n", iTest );
else
Msg( "\tClient testing shot %i\n", iTest );
#elif GAME_DLL
Warning("Server received shot %i\n",iTest);
#endif
FireBulletsInfo_t attack;
CBasePlayer* pPlayer = ToBasePlayer( GetOwner() );
if ( pPlayer )
{
pPlayer->RemoveAmmo( attack.m_iShots, m_iPrimaryAmmoType );
pPlayer->DoMuzzleFlash();
pPlayer->SetAnimation( PLAYER_ATTACK1 );
attack.m_vecSrc = pPlayer->Weapon_ShootPosition();
}
else
attack.m_vecSrc = GetOwner()->GetAbsOrigin();
attack.m_flDistance = MAX_TRACE_LENGTH;
attack.m_iAmmoType = m_iPrimaryAmmoType;
attack.m_iTracerFreq = 2;
Vector fwd;
AngleVectors(GetOwner()->GetAbsAngles(),&fwd);
attack.m_vecDirShooting = fwd;
if ( bRapidFire )
{
attack.m_vecSpread = VECTOR_CONE_10DEGREES;
attack.m_bPrimaryAttack = false;
}
GetOwner()->FireBullets( attack );
WeaponSound(SINGLE);
SendWeaponAnim( GetPrimaryAttackActivity() );
}
Script
Save this as mod\scripts\weapon_test.txt
. Remember to change the ammo in use from "pistol" to something your AmmoDef recognises.
WeaponData
{
printname "Prediction test weapon"
viewmodel models/weapons/v_357.mdl
playermodel models/weapons/w_357.mdl
anim_prefix python
bucket 1
bucket_position 1
clip_size -1
clip2_size -1
primary_ammo pistol
secondary_ammo pistol
weight 7
SoundData
{
empty Weapon_Pistol.Empty
single_shot Weapon_357.Single
}
TextureData
{
weapon
{
font WeaponIcons
character e
}
weapon_s
{
font WeaponIconsSelected
character e
}
weapon_small
{
font WeaponIconsSmall
character e
}
ammo
{
font WeaponIconsSmall
character q
}
crosshair
{
font Crosshairs
character Q
}
autoaim
{
file sprites/crosshairs
x 0
y 48
width 24
height 24
}
}
}