Anti-Crash Functions!


Most of you probably have my set of helper functions from my previous
tutorials (I've pasted them at the bottom if you don't). Well, the
G_EntExists() and G_ClientInGame() functions can (and preferably should)
be used in many locations throughout the entire source where references
are made to a client. Typically, at the tops of each of these functions
you'll find a statement like

if (!ent->client) return;

which is testing to see if this is a real 'player' client before letting
the function's source get executed (most likely to prevent crashes).

If reference is made to the client (ie, ent->client) and the ent
does not exist for whatever the reason then CRASH!. Similarly, if
the client is de-referenced and the client does not exist such as
ent->client->silencer_shots (from PlayerNoise), then CRASH!

What I've done below is show which of the many functions I've placed
my G_EntExists() function at the very top of by simply replacing the
if statement tests (if any) with a single function call.

Another thing, you'll see these at the bottom below, is a check to make
sure that the player is actually in the game. You'll see where I've
used the G_ClientInGame() function (on console commands) that you
don't want the player to be able to execute if they are not presently
actively in the game. If they are sitting connected but not playing then,
for instance, you may not want them to drop inventory.

Putting in all of these 'safety' checks in your code should only take a
few minutes with a good editor and some cut-n-paste.. Anyway, this
is all a matter of choice... Your choice.. This is more of a 'heads-up'
then anything else.

Add in the blue code and take out any pink code.

Okay, let's get started..



//==============================================================
char *ClientTeam(edict_t *ent) {
char *p;
static char value[512];

value[0]=0;

// Make sure ent exists!
if (!G_EntExists(ent)) return value;


//==============================================================
void ClientCommand(edict_t *ent) {
char *cmd=gi.argv(0);

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
static int CheckArmor(edict_t *ent, vec3_t point, vec3_t normal, int damage, int te_sparks, int dflags) {
int save, index;
gitem_t *armor;

// Make sure ent exists!
if (!G_EntExists(ent)) return 0;


//==============================================================
qboolean Add_Ammo(edict_t *ent, gitem_t *item, int count) {
int index, max;

// Make sure ent exists!
if (!G_EntExists(ent)) return false;


//==============================================================
int ArmorIndex(edict_t *ent) {

// Make sure ent exists!
if (!G_EntExists(ent)) return 0;


//==============================================================
int PowerArmorType(edict_t *ent) {

// Make sure ent exists!
if (!G_EntExists(ent))
return POWER_ARMOR_NONE;


//==============================================================
void Touch_Item(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) {
qboolean taken;

// Make sure ent exists!
if (!G_EntExists(other)) return;


//==============================================================
qboolean Pickup_Weapon(edict_t *ent, edict_t *other) {
gitem_t *ammo, *weapon;

// Make sure ent exists!
if (!G_EntExists(other)) return false;


//==============================================================
void Use_Weapon(edict_t *ent, gitem_t *weapon) {
int ammo_index;
gitem_t *ammo_item;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void Drop_Weapon(edict_t *ent, gitem_t *weapon) {

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void PlayerNoise(edict_t *who, vec3_t where, int type) {
edict_t *noise;

// Make sure ent exists!
if (!G_EntExists(who)) return;


//==============================================================
qboolean IsFemale(edict_t *ent) {
char *info;

// Make sure ent exists!
if (!G_EntExists(ent)) return false;


//==============================================================
qboolean IsNeutral(edict_t *ent) {
char *info;

// Make sure ent exists!
if (!G_EntExists(ent)) return false;


//==============================================================
void ClientObituary(edict_t *self, edict_t *inflictor, edict_t *attacker) {
int mod;
char *message=NULL;
char *message2="";
qboolean ff=false;

// If no victim then no obit!
if (!G_EntExists(self)) return;


//==============================================================
void TossClientWeapon(edict_t *self) {
gitem_t *item;
edict_t *drop;
qboolean quad;
float spread;

// Make sure ent exists!
if (!G_EntExists(self)) return;


//==============================================================
void LookAtKiller(edict_t *self, edict_t *inflictor, edict_t *attacker) {
vec3_t dir;

// Make sure ent exists!
if (!G_EntExists(self)) return;


//==============================================================
void player_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) {
int n;
static int i;

// if no-one died, then exit..
if (!G_EntExists(self)) return;


//==============================================================
void FetchClientEntData(edict_t *ent) {

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void ClientDisconnect(edict_t *ent) {
int playernum;

// Safety check...
if (!G_EntExists(ent)) return;


//==============================================================
void ClientThink(edict_t *ent, usercmd_t *ucmd) {
edict_t *other;
int i, j;
pmove_t pm;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void G_SetStats(edict_t *ent) {
gitem_t *item;
int index, cells;
int power_armor_type;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void G_SetSpectatorStats(edict_t *ent) {

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void P_DamageFeedback(edict_t *player) {
float side, realcount, count, kick;
vec3_t v;
static int i;
int r, l;
static vec3_t power_color={0.0, 1.0, 0.0};
static vec3_t acolor={1.0, 1.0, 1.0};
static vec3_t bcolor={1.0, 0.0, 0.0};

// Make sure player exists!
if (!G_EntExists(player)) return;


//==============================================================
void SV_CalcViewOffset(edict_t *ent) {
float *angles, bob, ratio, delta;
vec3_t v;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void SV_CalcGunOffset(edict_t *ent) {
int i;
float delta;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void SV_CalcBlend(edict_t *ent) {
int contents;
vec3_t vieworg;
int remaining;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void P_FallingDamage(edict_t *ent) {
float delta;
int damage;
vec3_t dir;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void G_SetClientEffects(edict_t *ent) {
int pa_type;
int remaining;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void G_SetClientSound(edict_t *ent) {
char *weap;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void G_SetClientFrame(edict_t *ent) {
qboolean duck, run;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void ChangeWeapon(edict_t *ent) {
int i;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void NoAmmoWeaponChange(edict_t *ent) {
int idx;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void Think_Weapon(edict_t *ent) {

// Make sure ent exists!
if (!G_EntExists(ent)) return;


//==============================================================
void Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void(*fire)(edict_t *ent)) {
int n;

// Make sure ent exists!
if (!G_EntExists(ent)) return;


These are the checks to make sure that the Client is in the game..



//==============================================================
void Cmd_InvDrop_f(edict_t *ent) {
gitem_t *it;

// Not available to dead or respawning players!
if (!G_ClientInGame(ent)) return;


//==============================================================
void Cmd_Kill_f(edict_t *ent) {

// Not available to dead or respawning players!
if (!G_ClientInGame(ent)) return;


//==============================================================
void Cmd_Wave_f(edict_t *ent) {
int i;

// Not available to dead or respawning players!
if (!G_ClientInGame(ent)) return;

Here are the functions if you don't have them already..




//======================================================
// True if Ent is valid, has client, and edict_t inuse.
//======================================================
qboolean G_EntExists(edict_t *ent) {
return ((ent) && (ent->client) && (ent->inuse));
}

//======================================================
// True if ent is not DEAD or DEAD or DEAD (and BURIED!)
//======================================================
qboolean G_ClientNotDead(edict_t *ent) {
qboolean buried=true;
qboolean b1=ent->client->ps.pmove.pm_type!=PM_DEAD;
qboolean b2=ent->deadflag != DEAD_DEAD;
qboolean b3=ent->health > 0;
return ((b3 || b2 || b1) && buried);
}

//======================================================
// True if ent is not DEAD and not just did a Respawn.
//======================================================
qboolean G_ClientInGame(edict_t *ent) {
if (!G_EntExists(ent)) return false;
if (!G_ClientNotDead(ent)) return false;
return (ent->client->respawn_time + 5.0 < level.time);
}


That's it!! Now make sure the BASTARD ARE THERE BEFORE YOU KILL THEM!!

Have Fun!

regards,
philip