Example #1
0
/*
==============
CL_ParseMuzzleFlash2
==============
*/
void CL_ParseMuzzleFlash2(void){
	int	ent;
	vec3_t	origin;
	int	flash_number;
	cdlight_t	*dl;
	vec3_t	forward, right;
	char	soundname[64];
	
	ent = MSG_ReadShort(&net_message);
	if(ent < 1 || ent >= MAX_EDICTS)
		Com_Error(ERR_DROP, "CL_ParseMuzzleFlash2: bad entity");
		
	flash_number = MSG_ReadByte(&net_message);
	
	// locate the origin
	AngleVectors(cl_entities[ent].current.angles, forward, right, NULL);
	origin[0] = cl_entities[ent].current.origin[0] + forward[0] * monster_flash_offset[flash_number][0] + right[0] * monster_flash_offset[flash_number][1];
	origin[1] = cl_entities[ent].current.origin[1] + forward[1] * monster_flash_offset[flash_number][0] + right[1] * monster_flash_offset[flash_number][1];
	origin[2] = cl_entities[ent].current.origin[2] + forward[2] * monster_flash_offset[flash_number][0] + right[2] * monster_flash_offset[flash_number][1] + monster_flash_offset[flash_number][2];
	
	dl = CL_AllocDlight(ent);
	VectorCopy(origin, dl->origin);
	dl->radius = 200 +(rand() & 31);
	dl->minlight = 32;
	dl->die = cl.time;	// + 0.1;
	
	switch(flash_number){
		case MZ2_INFANTRY_MACHINEGUN_1:
		case MZ2_INFANTRY_MACHINEGUN_2:
		case MZ2_INFANTRY_MACHINEGUN_3:
		case MZ2_INFANTRY_MACHINEGUN_4:
		case MZ2_INFANTRY_MACHINEGUN_5:
		case MZ2_INFANTRY_MACHINEGUN_6:
		case MZ2_INFANTRY_MACHINEGUN_7:
		case MZ2_INFANTRY_MACHINEGUN_8:
		case MZ2_INFANTRY_MACHINEGUN_9:
		case MZ2_INFANTRY_MACHINEGUN_10:
		case MZ2_INFANTRY_MACHINEGUN_11:
		case MZ2_INFANTRY_MACHINEGUN_12:
		case MZ2_INFANTRY_MACHINEGUN_13:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			CL_ParticleEffect(origin, vec3_origin, 0, 40);
			CL_SmokeAndFlash(origin);
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_SOLDIER_MACHINEGUN_1:
		case MZ2_SOLDIER_MACHINEGUN_2:
		case MZ2_SOLDIER_MACHINEGUN_3:
		case MZ2_SOLDIER_MACHINEGUN_4:
		case MZ2_SOLDIER_MACHINEGUN_5:
		case MZ2_SOLDIER_MACHINEGUN_6:
		case MZ2_SOLDIER_MACHINEGUN_7:
		case MZ2_SOLDIER_MACHINEGUN_8:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			CL_ParticleEffect(origin, vec3_origin, 0, 40);
			CL_SmokeAndFlash(origin);
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_GUNNER_MACHINEGUN_1:
		case MZ2_GUNNER_MACHINEGUN_2:
		case MZ2_GUNNER_MACHINEGUN_3:
		case MZ2_GUNNER_MACHINEGUN_4:
		case MZ2_GUNNER_MACHINEGUN_5:
		case MZ2_GUNNER_MACHINEGUN_6:
		case MZ2_GUNNER_MACHINEGUN_7:
		case MZ2_GUNNER_MACHINEGUN_8:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			CL_ParticleEffect(origin, vec3_origin, 0, 40);
			CL_SmokeAndFlash(origin);
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_ACTOR_MACHINEGUN_1:
		case MZ2_SUPERTANK_MACHINEGUN_1:
		case MZ2_SUPERTANK_MACHINEGUN_2:
		case MZ2_SUPERTANK_MACHINEGUN_3:
		case MZ2_SUPERTANK_MACHINEGUN_4:
		case MZ2_SUPERTANK_MACHINEGUN_5:
		case MZ2_SUPERTANK_MACHINEGUN_6:
		case MZ2_TURRET_MACHINEGUN: 			// PGM
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			
			CL_ParticleEffect(origin, vec3_origin, 0, 40);
			CL_SmokeAndFlash(origin);
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_BOSS2_MACHINEGUN_L1:
		case MZ2_BOSS2_MACHINEGUN_L2:
		case MZ2_BOSS2_MACHINEGUN_L3:
		case MZ2_BOSS2_MACHINEGUN_L4:
		case MZ2_BOSS2_MACHINEGUN_L5:
		case MZ2_CARRIER_MACHINEGUN_L1: 		// PMM
		case MZ2_CARRIER_MACHINEGUN_L2: 		// PMM
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			
			CL_ParticleEffect(origin, vec3_origin, 0, 40);
			CL_SmokeAndFlash(origin);
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0);
			break;
			
		case MZ2_SOLDIER_BLASTER_1:
		case MZ2_SOLDIER_BLASTER_2:
		case MZ2_SOLDIER_BLASTER_3:
		case MZ2_SOLDIER_BLASTER_4:
		case MZ2_SOLDIER_BLASTER_5:
		case MZ2_SOLDIER_BLASTER_6:
		case MZ2_SOLDIER_BLASTER_7:
		case MZ2_SOLDIER_BLASTER_8:
		case MZ2_TURRET_BLASTER: 			// PGM
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_FLYER_BLASTER_1:
		case MZ2_FLYER_BLASTER_2:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_MEDIC_BLASTER_1:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_HOVER_BLASTER_1:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_FLOAT_BLASTER_1:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_SOLDIER_SHOTGUN_1:
		case MZ2_SOLDIER_SHOTGUN_2:
		case MZ2_SOLDIER_SHOTGUN_3:
		case MZ2_SOLDIER_SHOTGUN_4:
		case MZ2_SOLDIER_SHOTGUN_5:
		case MZ2_SOLDIER_SHOTGUN_6:
		case MZ2_SOLDIER_SHOTGUN_7:
		case MZ2_SOLDIER_SHOTGUN_8:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			CL_SmokeAndFlash(origin);
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_TANK_BLASTER_1:
		case MZ2_TANK_BLASTER_2:
		case MZ2_TANK_BLASTER_3:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_TANK_MACHINEGUN_1:
		case MZ2_TANK_MACHINEGUN_2:
		case MZ2_TANK_MACHINEGUN_3:
		case MZ2_TANK_MACHINEGUN_4:
		case MZ2_TANK_MACHINEGUN_5:
		case MZ2_TANK_MACHINEGUN_6:
		case MZ2_TANK_MACHINEGUN_7:
		case MZ2_TANK_MACHINEGUN_8:
		case MZ2_TANK_MACHINEGUN_9:
		case MZ2_TANK_MACHINEGUN_10:
		case MZ2_TANK_MACHINEGUN_11:
		case MZ2_TANK_MACHINEGUN_12:
		case MZ2_TANK_MACHINEGUN_13:
		case MZ2_TANK_MACHINEGUN_14:
		case MZ2_TANK_MACHINEGUN_15:
		case MZ2_TANK_MACHINEGUN_16:
		case MZ2_TANK_MACHINEGUN_17:
		case MZ2_TANK_MACHINEGUN_18:
		case MZ2_TANK_MACHINEGUN_19:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			CL_ParticleEffect(origin, vec3_origin, 0, 40);
			CL_SmokeAndFlash(origin);
			Com_sprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + rand() % 5);
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound(soundname), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_CHICK_ROCKET_1:
		case MZ2_TURRET_ROCKET: 			// PGM
			dl->color[0] = 1;
			dl->color[1] = 0.5;
			dl->color[2] = 0.2;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_TANK_ROCKET_1:
		case MZ2_TANK_ROCKET_2:
		case MZ2_TANK_ROCKET_3:
			dl->color[0] = 1;
			dl->color[1] = 0.5;
			dl->color[2] = 0.2;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_SUPERTANK_ROCKET_1:
		case MZ2_SUPERTANK_ROCKET_2:
		case MZ2_SUPERTANK_ROCKET_3:
		case MZ2_BOSS2_ROCKET_1:
		case MZ2_BOSS2_ROCKET_2:
		case MZ2_BOSS2_ROCKET_3:
		case MZ2_BOSS2_ROCKET_4:
		case MZ2_CARRIER_ROCKET_1:
			//	case MZ2_CARRIER_ROCKET_2:
			//	case MZ2_CARRIER_ROCKET_3:
			//	case MZ2_CARRIER_ROCKET_4:
			dl->color[0] = 1;
			dl->color[1] = 0.5;
			dl->color[2] = 0.2;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_GUNNER_GRENADE_1:
		case MZ2_GUNNER_GRENADE_2:
		case MZ2_GUNNER_GRENADE_3:
		case MZ2_GUNNER_GRENADE_4:
			dl->color[0] = 1;
			dl->color[1] = 0.5;
			dl->color[2] = 0;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_GLADIATOR_RAILGUN_1:
			// PMM
		case MZ2_CARRIER_RAILGUN:
		case MZ2_WIDOW_RAIL:
			// pmm
			dl->color[0] = 0.5;
			dl->color[1] = 0.5;
			dl->color[2] = 1.0;
			break;
			
			// --- Xian's shit starts ---
		case MZ2_MAKRON_BFG:
			dl->color[0] = 0.5;
			dl->color[1] = 1;
			dl->color[2] = 0.5;
			//S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_MAKRON_BLASTER_1:
		case MZ2_MAKRON_BLASTER_2:
		case MZ2_MAKRON_BLASTER_3:
		case MZ2_MAKRON_BLASTER_4:
		case MZ2_MAKRON_BLASTER_5:
		case MZ2_MAKRON_BLASTER_6:
		case MZ2_MAKRON_BLASTER_7:
		case MZ2_MAKRON_BLASTER_8:
		case MZ2_MAKRON_BLASTER_9:
		case MZ2_MAKRON_BLASTER_10:
		case MZ2_MAKRON_BLASTER_11:
		case MZ2_MAKRON_BLASTER_12:
		case MZ2_MAKRON_BLASTER_13:
		case MZ2_MAKRON_BLASTER_14:
		case MZ2_MAKRON_BLASTER_15:
		case MZ2_MAKRON_BLASTER_16:
		case MZ2_MAKRON_BLASTER_17:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_JORG_MACHINEGUN_L1:
		case MZ2_JORG_MACHINEGUN_L2:
		case MZ2_JORG_MACHINEGUN_L3:
		case MZ2_JORG_MACHINEGUN_L4:
		case MZ2_JORG_MACHINEGUN_L5:
		case MZ2_JORG_MACHINEGUN_L6:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			CL_ParticleEffect(origin, vec3_origin, 0, 40);
			CL_SmokeAndFlash(origin);
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_JORG_MACHINEGUN_R1:
		case MZ2_JORG_MACHINEGUN_R2:
		case MZ2_JORG_MACHINEGUN_R3:
		case MZ2_JORG_MACHINEGUN_R4:
		case MZ2_JORG_MACHINEGUN_R5:
		case MZ2_JORG_MACHINEGUN_R6:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			CL_ParticleEffect(origin, vec3_origin, 0, 40);
			CL_SmokeAndFlash(origin);
			break;
			
		case MZ2_JORG_BFG_1:
			dl->color[0] = 0.5;
			dl->color[1] = 1;
			dl->color[2] = 0.5;
			break;
			
		case MZ2_BOSS2_MACHINEGUN_R1:
		case MZ2_BOSS2_MACHINEGUN_R2:
		case MZ2_BOSS2_MACHINEGUN_R3:
		case MZ2_BOSS2_MACHINEGUN_R4:
		case MZ2_BOSS2_MACHINEGUN_R5:
		case MZ2_CARRIER_MACHINEGUN_R1: 			// PMM
		case MZ2_CARRIER_MACHINEGUN_R2: 			// PMM
		
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			
			CL_ParticleEffect(origin, vec3_origin, 0, 40);
			CL_SmokeAndFlash(origin);
			break;
			
			// ======
			// ROGUE
		case MZ2_STALKER_BLASTER:
		case MZ2_DAEDALUS_BLASTER:
		case MZ2_MEDIC_BLASTER_2:
		case MZ2_WIDOW_BLASTER:
		case MZ2_WIDOW_BLASTER_SWEEP1:
		case MZ2_WIDOW_BLASTER_SWEEP2:
		case MZ2_WIDOW_BLASTER_SWEEP3:
		case MZ2_WIDOW_BLASTER_SWEEP4:
		case MZ2_WIDOW_BLASTER_SWEEP5:
		case MZ2_WIDOW_BLASTER_SWEEP6:
		case MZ2_WIDOW_BLASTER_SWEEP7:
		case MZ2_WIDOW_BLASTER_SWEEP8:
		case MZ2_WIDOW_BLASTER_SWEEP9:
		case MZ2_WIDOW_BLASTER_100:
		case MZ2_WIDOW_BLASTER_90:
		case MZ2_WIDOW_BLASTER_80:
		case MZ2_WIDOW_BLASTER_70:
		case MZ2_WIDOW_BLASTER_60:
		case MZ2_WIDOW_BLASTER_50:
		case MZ2_WIDOW_BLASTER_40:
		case MZ2_WIDOW_BLASTER_30:
		case MZ2_WIDOW_BLASTER_20:
		case MZ2_WIDOW_BLASTER_10:
		case MZ2_WIDOW_BLASTER_0:
		case MZ2_WIDOW_BLASTER_10L:
		case MZ2_WIDOW_BLASTER_20L:
		case MZ2_WIDOW_BLASTER_30L:
		case MZ2_WIDOW_BLASTER_40L:
		case MZ2_WIDOW_BLASTER_50L:
		case MZ2_WIDOW_BLASTER_60L:
		case MZ2_WIDOW_BLASTER_70L:
		case MZ2_WIDOW_RUN_1:
		case MZ2_WIDOW_RUN_2:
		case MZ2_WIDOW_RUN_3:
		case MZ2_WIDOW_RUN_4:
		case MZ2_WIDOW_RUN_5:
		case MZ2_WIDOW_RUN_6:
		case MZ2_WIDOW_RUN_7:
		case MZ2_WIDOW_RUN_8:
			dl->color[0] = 0;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_WIDOW_DISRUPTOR:
			dl->color[0] = -1;
			dl->color[1] = -1;
			dl->color[2] = -1;
			S_StartSound(NULL, ent, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0);
			break;
			
		case MZ2_WIDOW_PLASMABEAM:
		case MZ2_WIDOW2_BEAMER_1:
		case MZ2_WIDOW2_BEAMER_2:
		case MZ2_WIDOW2_BEAMER_3:
		case MZ2_WIDOW2_BEAMER_4:
		case MZ2_WIDOW2_BEAMER_5:
		case MZ2_WIDOW2_BEAM_SWEEP_1:
		case MZ2_WIDOW2_BEAM_SWEEP_2:
		case MZ2_WIDOW2_BEAM_SWEEP_3:
		case MZ2_WIDOW2_BEAM_SWEEP_4:
		case MZ2_WIDOW2_BEAM_SWEEP_5:
		case MZ2_WIDOW2_BEAM_SWEEP_6:
		case MZ2_WIDOW2_BEAM_SWEEP_7:
		case MZ2_WIDOW2_BEAM_SWEEP_8:
		case MZ2_WIDOW2_BEAM_SWEEP_9:
		case MZ2_WIDOW2_BEAM_SWEEP_10:
		case MZ2_WIDOW2_BEAM_SWEEP_11:
			dl->radius = 300 +(rand() & 100);
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			dl->die = cl.time + 200;
			break;
			// ROGUE
			// ======
			
			// --- Xian's shit ends ---
			
	}
}
Example #2
0
/*
=====================
CL_ParseVoip

A VoIP message has been received from the server
=====================
*/
static
void CL_ParseVoip ( msg_t *msg ) {
	static short decoded[4096];  // !!! FIXME: don't hardcode.

	const int sender = MSG_ReadShort(msg);
	const int generation = MSG_ReadByte(msg);
	const int sequence = MSG_ReadLong(msg);
	const int frames = MSG_ReadByte(msg);
	const int packetsize = MSG_ReadShort(msg);
	const int flags = MSG_ReadBits(msg, VOIP_FLAGCNT);
	char encoded[1024];
	int seqdiff;
	int written = 0;
	int i;

	Com_DPrintf("VoIP: %d-byte packet from client %d\n", packetsize, sender);

	if (sender < 0)
		return;   // short/invalid packet, bail.
	else if (generation < 0)
		return;   // short/invalid packet, bail.
	else if (sequence < 0)
		return;   // short/invalid packet, bail.
	else if (frames < 0)
		return;   // short/invalid packet, bail.
	else if (packetsize < 0)
		return;   // short/invalid packet, bail.

	if (packetsize > sizeof (encoded)) {  // overlarge packet?
		int bytesleft = packetsize;
		while (bytesleft) {
			int br = bytesleft;
			if (br > sizeof (encoded))
				br = sizeof (encoded);
			MSG_ReadData(msg, encoded, br);
			bytesleft -= br;
		}
		return;   // overlarge packet, bail.
	}

	if (!clc.speexInitialized) {
		MSG_ReadData(msg, encoded, packetsize);  // skip payload.
		return;   // can't handle VoIP without libspeex!
	} else if (sender >= MAX_CLIENTS) {
		MSG_ReadData(msg, encoded, packetsize);  // skip payload.
		return;   // bogus sender.
	} else if (CL_ShouldIgnoreVoipSender(sender)) {
		MSG_ReadData(msg, encoded, packetsize);  // skip payload.
		return;   // Channel is muted, bail.
	}

	// !!! FIXME: make sure data is narrowband? Does decoder handle this?

	Com_DPrintf("VoIP: packet accepted!\n");

	seqdiff = sequence - clc.voipIncomingSequence[sender];

	// This is a new "generation" ... a new recording started, reset the bits.
	if (generation != clc.voipIncomingGeneration[sender]) {
		Com_DPrintf("VoIP: new generation %d!\n", generation);
		speex_bits_reset(&clc.speexDecoderBits[sender]);
		clc.voipIncomingGeneration[sender] = generation;
		seqdiff = 0;
	} else if (seqdiff < 0) {   // we're ahead of the sequence?!
		// This shouldn't happen unless the packet is corrupted or something.
		Com_DPrintf("VoIP: misordered sequence! %d < %d!\n",
		            sequence, clc.voipIncomingSequence[sender]);
		// reset the bits just in case.
		speex_bits_reset(&clc.speexDecoderBits[sender]);
		seqdiff = 0;
	} else if (seqdiff * clc.speexFrameSize * 2 >= sizeof (decoded)) { // dropped more than we can handle?
		// just start over.
		Com_DPrintf("VoIP: Dropped way too many (%d) frames from client #%d\n",
		            seqdiff, sender);
		speex_bits_reset(&clc.speexDecoderBits[sender]);
		seqdiff = 0;
	}

	if (seqdiff != 0) {
		Com_DPrintf("VoIP: Dropped %d frames from client #%d\n",
		            seqdiff, sender);
		// tell speex that we're missing frames...
		for (i = 0; i < seqdiff; i++) {
			assert((written + clc.speexFrameSize) * 2 < sizeof (decoded));
			speex_decode_int(clc.speexDecoder[sender], NULL, decoded + written);
			written += clc.speexFrameSize;
		}
	}

	for (i = 0; i < frames; i++) {
		const int len = MSG_ReadByte(msg);
		if (len < 0) {
			Com_DPrintf("VoIP: Short packet!\n");
			break;
		}
		MSG_ReadData(msg, encoded, len);

		// shouldn't happen, but just in case...
		if ((written + clc.speexFrameSize) * 2 > sizeof (decoded)) {
			Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
			            written * 2, written, i);
			
			CL_PlayVoip(sender, written, (const byte *) decoded, flags);
			written = 0;
		}

		speex_bits_read_from(&clc.speexDecoderBits[sender], encoded, len);
		speex_decode_int(clc.speexDecoder[sender],
		                 &clc.speexDecoderBits[sender], decoded + written);

		#if 0
		static FILE *encio = NULL;
		if (encio == NULL) encio = fopen("voip-incoming-encoded.bin", "wb");
		if (encio != NULL) { fwrite(encoded, len, 1, encio); fflush(encio); }
		static FILE *decio = NULL;
		if (decio == NULL) decio = fopen("voip-incoming-decoded.bin", "wb");
		if (decio != NULL) { fwrite(decoded+written, clc.speexFrameSize*2, 1, decio); fflush(decio); }
		#endif

		written += clc.speexFrameSize;
	}

	Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
	            written * 2, written, i);

	if(written > 0)
		CL_PlayVoip(sender, written, (const byte *) decoded, flags);

	clc.voipIncomingSequence[sender] = sequence + frames;
}
Example #3
0
/*
=====================
CL_ParseServerMessage
=====================
*/
void CL_ParseServerMessage( msg_t *msg ) {
	int			cmd;

	if ( cl_shownet->integer == 1 ) {
		Com_Printf ("%i ",msg->cursize);
	} else if ( cl_shownet->integer >= 2 ) {
		Com_Printf ("------------------\n");
	}

	MSG_Bitstream(msg);

	// get the reliable sequence acknowledge number
	clc.reliableAcknowledge = MSG_ReadLong( msg );
	// 
	if ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) {
		clc.reliableAcknowledge = clc.reliableSequence;
	}

	//
	// parse the message
	//
	while ( 1 ) {
		if ( msg->readcount > msg->cursize ) {
			Com_Error (ERR_DROP,"CL_ParseServerMessage: read past end of server message");
			break;
		}

		cmd = MSG_ReadByte( msg );

		if ( cmd == svc_EOF) {
			SHOWNET( msg, "END OF MESSAGE" );
			break;
		}

		if ( cl_shownet->integer >= 2 ) {
			if ( !svc_strings[cmd] ) {
				Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd );
			} else {
				SHOWNET( msg, svc_strings[cmd] );
			}
		}
	
	// other commands
		switch ( cmd ) {
		default:
			Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
			break;			
		case svc_nop:
			break;
		case svc_serverCommand:
			CL_ParseCommandString( msg );
			break;
		case svc_gamestate:
			CL_ParseGamestate( msg );
			break;
		case svc_snapshot:
			CL_ParseSnapshot( msg );
			break;
		case svc_download:
			CL_ParseDownload( msg );
			break;
		case svc_mapchange:
			if (cgvm)
			{
				VM_Call( cgvm, CG_MAP_CHANGE );
			}
			break;
		}
	}
}
Example #4
0
File: save.c Project: jdolan/q2pro
static int read_server_file(void)
{
    char        name[MAX_OSPATH], string[MAX_STRING_CHARS];
    mapcmd_t    cmd;
    size_t      len;

    // errors like missing file, bad version, etc are
    // non-fatal and just return to the command handler
    if (read_binary_file("save/" SAVE_CURRENT "/server.ssv"))
        return -1;

    if (MSG_ReadLong() != SAVE_MAGIC1)
        return -1;

    if (MSG_ReadLong() != SAVE_VERSION)
        return -1;

    memset(&cmd, 0, sizeof(cmd));

    // read the comment field
    MSG_ReadLong();
    MSG_ReadLong();
    if (MSG_ReadByte())
        cmd.loadgame = 2;   // autosave
    else
        cmd.loadgame = 1;   // regular savegame
    MSG_ReadString(NULL, 0);

    // read the mapcmd
    len = MSG_ReadString(cmd.buffer, sizeof(cmd.buffer));
    if (len >= sizeof(cmd.buffer))
        return -1;

    // now try to load the map
    if (!SV_ParseMapCmd(&cmd))
        return -1;

    // save pending CM to be freed later if ERR_DROP is thrown
    Com_AbortFunc(abort_func, &cmd.cm);

    // any error will drop from this point
    SV_Shutdown("Server restarted\n", ERR_RECONNECT);

    // the rest can't underflow
    msg_read.allowunderflow = qfalse;

    // read all CVAR_LATCH cvars
    // these will be things like coop, skill, deathmatch, etc
    while (1) {
        len = MSG_ReadString(name, MAX_QPATH);
        if (!len)
            break;
        if (len >= MAX_QPATH)
            Com_Error(ERR_DROP, "Savegame cvar name too long");

        len = MSG_ReadString(string, sizeof(string));
        if (len >= sizeof(string))
            Com_Error(ERR_DROP, "Savegame cvar value too long");

        Cvar_UserSet(name, string);
    }

    // start a new game fresh with new cvars
    SV_InitGame(MVD_SPAWN_DISABLED);

    // error out immediately if game doesn't support safe savegames
    if (!(g_features->integer & GMF_ENHANCED_SAVEGAMES))
        Com_Error(ERR_DROP, "Game does not support enhanced savegames");

    // read game state
    len = Q_snprintf(name, MAX_OSPATH,
                     "%s/save/" SAVE_CURRENT "/game.ssv", fs_gamedir);
    if (len >= MAX_OSPATH)
        Com_Error(ERR_DROP, "Savegame path too long");

    ge->ReadGame(name);

    // clear pending CM
    Com_AbortFunc(NULL, NULL);

    // go to the map
    SV_SpawnServer(&cmd);
    return 0;
}
Example #5
0
/*
=====================
CL_ParseServerMessage
=====================
*/
void CL_ParseServerMessage( msg_t *msg ) {
	int			cmd;

	if ( cl_shownet->integer == 1 ) {
		Com_Printf ("%i ",msg->cursize);
	} else if ( cl_shownet->integer >= 2 ) {
		Com_Printf ("------------------\n");
	}

	#ifdef ELITEFORCE
	if(!msg->compat)
	{
	#endif
		MSG_Bitstream(msg);

		// get the reliable sequence acknowledge number
		clc.reliableAcknowledge = MSG_ReadLong( msg );
		// 
		if ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) {
			clc.reliableAcknowledge = clc.reliableSequence;
		}
	#ifdef ELITEFORCE
	}
	#endif
	
	//
	// parse the message
	//
	while ( 1 ) {
		if ( msg->readcount > msg->cursize ) {
			Com_Error (ERR_DROP,"CL_ParseServerMessage: read past end of server message");
			break;
		}

		cmd = MSG_ReadByte( msg );

		#ifdef ELITEFORCE
		if ( cmd == svc_EOF || ( msg->compat && cmd == -1 ) )
		#else
		if ( cmd == svc_EOF)
		#endif
		{
			SHOWNET( msg, "END OF MESSAGE" );
			break;
		}

		if ( cl_shownet->integer >= 2 ) {
			if ( (cmd < 0) || (!svc_strings[cmd]) ) {
				Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd );
			} else {
				SHOWNET( msg, svc_strings[cmd] );
			}
		}
	
	// other commands
		switch ( cmd ) {
		default:
			Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message");
			break;			
		case svc_nop:
			break;
		case svc_serverCommand:
			CL_ParseCommandString( msg );
			break;
		case svc_gamestate:
			CL_ParseGamestate( msg );
			break;
		case svc_snapshot:
			CL_ParseSnapshot( msg );
			break;
		case svc_download:
			CL_ParseDownload( msg );
			break;
		case svc_voip:
#ifdef USE_VOIP
			CL_ParseVoip( msg );
#endif
			break;
		}
	}
}
/*
=================
CL_ParseTEnt
=================
*/
void CL_ParseTEnt (void)
{
	int		type;
	vec3_t	pos;
	dlight_t	*dl;
	int		rnd;
	int		colorStart, colorLength;

	type = MSG_ReadByte ();
	switch (type)
	{
	case TE_WIZSPIKE:			// spike hitting wall
		pos[0] = MSG_ReadCoord ();
		pos[1] = MSG_ReadCoord ();
		pos[2] = MSG_ReadCoord ();
		R_RunParticleEffect (pos, vec3_origin, 20, 30);
#ifdef SUPPORTS_SOFTWARE_FTESTAIN
		R_AddStain(pos, -20, 11); //qbism ftestain
#endif
		S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);
		break;

	case TE_KNIGHTSPIKE:			// spike hitting wall
		pos[0] = MSG_ReadCoord ();
		pos[1] = MSG_ReadCoord ();
		pos[2] = MSG_ReadCoord ();
		R_RunParticleEffect (pos, vec3_origin, 226, 20);
#ifdef SUPPORTS_SOFTWARE_FTESTAIN
		R_AddStain(pos, -20, 15); //qbism ftestain
#endif
		S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);
		break;

	case TE_SPIKE:			// spike hitting wall
		pos[0] = MSG_ReadCoord ();
		pos[1] = MSG_ReadCoord ();
		pos[2] = MSG_ReadCoord ();

		R_RunParticleEffect (pos, vec3_origin, 0, 10);
#ifdef SUPPORTS_SOFTWARE_FTESTAIN
		R_AddStain(pos, -30, 10); //qbism ftestain
#endif

		if ( rand() % 5 )
		{
			S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
		}
		else
		{
			rnd = rand() & 3;
			if (rnd == 1)
				S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
			else if (rnd == 2)
				S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
			else
				S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
		}
		break;

	case TE_SUPERSPIKE:			// super spike hitting wall
		pos[0] = MSG_ReadCoord ();
		pos[1] = MSG_ReadCoord ();
		pos[2] = MSG_ReadCoord ();
		R_RunParticleEffect (pos, vec3_origin, 0, 20);
#ifdef SUPPORTS_SOFTWARE_FTESTAIN
		R_AddStain(pos, -30, 10); //qbism ftestain
#endif

		if ( rand() % 5 )
		{
			S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);
		}
		else
		{
			rnd = rand() & 3;
			if (rnd == 1)
				S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);
			else if (rnd == 2)
				S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);
			else
				S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);
		}
		break;

	case TE_GUNSHOT:			// bullet hitting wall
		pos[0] = MSG_ReadCoord ();
		pos[1] = MSG_ReadCoord ();
		pos[2] = MSG_ReadCoord ();
#ifdef SUPPORTS_KUROK
		if (!kurok)
#endif
		{
			R_RunParticleEffect (pos, vec3_origin, 0, 20);
#ifdef SUPPORTS_SOFTWARE_FTESTAIN
			R_AddStain(pos, -40, 12); //qbism ftestain
#endif
		}
		break;

	case TE_EXPLOSION:			// rocket explosion
		pos[0] = MSG_ReadCoord ();
		pos[1] = MSG_ReadCoord ();
		pos[2] = MSG_ReadCoord ();
		R_ParticleExplosion (pos);
		dl = CL_AllocDlight (0);
		VectorCopy (pos, dl->origin);
		dl->radius = 350;
		dl->die = cl.time + 0.5;
		dl->decay = 300;
#ifdef SUPPORTS_KUROK
		if(kurok)
		{
        	dl->color[0] = MSG_ReadCoord ();
			dl->color[1] = MSG_ReadCoord ();
			dl->color[2] = MSG_ReadCoord ();
		}
#endif
#ifdef SUPPORTS_SOFTWARE_FTESTAIN
		R_AddStain(pos, -30, 45); //qbism ftestain
#endif
		S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
		break;

	case TE_TAREXPLOSION:			// tarbaby explosion
		pos[0] = MSG_ReadCoord ();
		pos[1] = MSG_ReadCoord ();
		pos[2] = MSG_ReadCoord ();
		R_BlobExplosion (pos);
#ifdef SUPPORTS_KUROK
		if(kurok)
		{
			dl = CL_AllocDlight (0);
			VectorCopy (pos, dl->origin);
			dl->radius = 150;
			dl->die = cl.time + 0.75;
			dl->decay = 200;
        	dl->color[0] = MSG_ReadCoord ();
			dl->color[1] = MSG_ReadCoord ();
			dl->color[2] = MSG_ReadCoord ();
		}
#endif
#ifdef SUPPORTS_SOFTWARE_FTESTAIN
		R_AddStain(pos, -20, 60); //qbism ftestain
#endif
		S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
		break;

	case TE_LIGHTNING1:				// lightning bolts
		CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true));
		break;

	case TE_LIGHTNING2:				// lightning bolts
		CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true));
		break;

	case TE_LIGHTNING3:				// lightning bolts
		CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true));
		break;

// PGM 01/21/97
	case TE_BEAM:				// grappling hook beam
		CL_ParseBeam (Mod_ForName("progs/beam.mdl", true));
		break;
// PGM 01/21/97

	case TE_LAVASPLASH:
		pos[0] = MSG_ReadCoord ();
		pos[1] = MSG_ReadCoord ();
		pos[2] = MSG_ReadCoord ();
		R_LavaSplash (pos);
		break;

	case TE_TELEPORT:
		pos[0] = MSG_ReadCoord ();
		pos[1] = MSG_ReadCoord ();
		pos[2] = MSG_ReadCoord ();
		R_TeleportSplash (pos);
		break;

	case TE_EXPLOSION2:				// color mapped explosion
		pos[0] = MSG_ReadCoord ();
		pos[1] = MSG_ReadCoord ();
		pos[2] = MSG_ReadCoord ();
		colorStart = MSG_ReadByte ();
		colorLength = MSG_ReadByte ();
		R_ParticleExplosion2 (pos, colorStart, colorLength);
		dl = CL_AllocDlight (0);
		VectorCopy (pos, dl->origin);
		dl->radius = 350;
		dl->die = cl.time + 0.5;
		dl->decay = 300;
#ifdef SUPPORTS_SOFTWARE_FTESTAIN
		R_AddStain(pos, -30, 50); //qbism ftestain
#endif
		S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
		break;

	default:
		Sys_Error ("CL_ParseTEnt: bad type");
	}
}
Example #7
0
/*
==================
SV_UserMove

The message usually contains all the movement commands
that were in the last three packets, so that the information
in dropped packets can be recovered.

On very fast clients, there may be multiple usercmd packed into
each of the backup packets.
==================
*/
static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) {
	int			i, key;
	int			cmdCount;
	usercmd_t	nullcmd;
	usercmd_t	cmds[MAX_PACKET_USERCMDS];
	usercmd_t	*cmd, *oldcmd;

	if ( delta ) {
		cl->deltaMessage = cl->messageAcknowledge;
	} else {
		cl->deltaMessage = -1;
	}

	cmdCount = MSG_ReadByte( msg );

	if ( cmdCount < 1 ) {
		Com_Printf( "cmdCount < 1\n" );
		return;
	}

	if ( cmdCount > MAX_PACKET_USERCMDS ) {
		Com_Printf( "cmdCount > MAX_PACKET_USERCMDS\n" );
		return;
	}

	// use the checksum feed in the key
	key = sv.checksumFeed;
	// also use the message acknowledge
	key ^= cl->messageAcknowledge;
	// also use the last acknowledged server command in the key
	key ^= Com_HashKey(cl->reliableCommands[ cl->reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ], 32);

	Com_Memset( &nullcmd, 0, sizeof(nullcmd) );
	oldcmd = &nullcmd;
	for ( i = 0 ; i < cmdCount ; i++ ) {
		cmd = &cmds[i];
		MSG_ReadDeltaUsercmdKey( msg, key, oldcmd, cmd );
		oldcmd = cmd;
	}

	// save time for ping calculation
	// With sv_pingFix enabled we store the time of the first acknowledge, instead of the last. And we use a time value that is not limited by sv_fps.
	if ( !sv_pingFix->integer || cl->frames[ cl->messageAcknowledge & PACKET_MASK ].messageAcked == -1 )
		cl->frames[ cl->messageAcknowledge & PACKET_MASK ].messageAcked = (sv_pingFix->integer ? Sys_Milliseconds() : svs.time);

	// if this is the first usercmd we have received
	// this gamestate, put the client into the world
	if ( cl->state == CS_PRIMED ) {
		SV_SendServerCommand(cl, "print \"^1[ ^7This server is running JK2MV ^1v^7" JK2MV_VERSION " ^1| ^7http://jk2mv.org ^1]\n\"");

		SV_ClientEnterWorld( cl, &cmds[0] );
		// the moves can be processed normaly
	}
	//
	if (sv_pure->integer != 0 && cl->pureAuthentic == 0) {
		SV_DropClient( cl, "Cannot validate pure client!");
		return;
	}

	if ( cl->state != CS_ACTIVE ) {
		cl->deltaMessage = -1;
		return;
	}

	// usually, the first couple commands will be duplicates
	// of ones we have previously received, but the servertimes
	// in the commands will cause them to be immediately discarded
	for ( i =  0 ; i < cmdCount ; i++ ) {
		// if this is a cmd from before a map_restart ignore it
		if ( cmds[i].serverTime > cmds[cmdCount-1].serverTime ) {
			continue;
		}
		// extremely lagged or cmd from before a map_restart
		//if ( cmds[i].serverTime > sv.time + 3000 ) {
		//	continue;
		//}
		// don't execute if this is an old cmd which is already executed
		// these old cmds are included when cl_packetdup > 0
		if ( cmds[i].serverTime <= cl->lastUsercmd.serverTime ) {
			continue;
		}
		SV_ClientThink (cl - svs.clients, &cmds[ i ]);
	}
}
Example #8
0
static void _Datagram_SearchForHosts(qboolean xmit)
{
    int		ret;
    int		n;
    int		i;
    struct qsockaddr readaddr;
    struct qsockaddr myaddr;
    int		control;

    dfunc.GetSocketAddr(dfunc.controlSock, &myaddr);
    if (xmit) {
        SZ_Clear(&net_message);
        // save space for the header, filled in later
        MSG_WriteLong(&net_message, 0);
        MSG_WriteByte(&net_message, CCREQ_SERVER_INFO);
        MSG_WriteString(&net_message, "QUAKE");
        MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
        *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
        dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize);
        SZ_Clear(&net_message);
    }

    while ((ret = dfunc.Read(dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0) {
        if (ret < sizeof(int)) {
            continue;
        }
        net_message.cursize = ret;

        // don't answer our own query
        if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0) {
            continue;
        }

        // is the cache full?
        if (hostCacheCount == HOSTCACHESIZE) {
            continue;
        }

        MSG_BeginReading();
        control = BigLong(*((int *)net_message.data));
        MSG_ReadLong();
        if (control == -1) {
            continue;
        }
        if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL) {
            continue;
        }
        if ((control & NETFLAG_LENGTH_MASK) != ret) {
            continue;
        }

        if (MSG_ReadByte() != CCREP_SERVER_INFO) {
            continue;
        }

        dfunc.GetAddrFromName(MSG_ReadString(), &readaddr);
        // search the cache for this server
        for (n = 0; n < hostCacheCount; n++)
            if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0) {
                break;
            }

        // is it already there?
        if (n < hostCacheCount) {
            continue;
        }

        // add it
        hostCacheCount++;
        Q_strcpy(hostcache[n].name, MSG_ReadString());
        Q_strcpy(hostcache[n].map, MSG_ReadString());
        hostcache[n].users = MSG_ReadByte();
        hostcache[n].maxusers = MSG_ReadByte();
        if (MSG_ReadByte() != NET_PROTOCOL_VERSION) {
            Q_strcpy(hostcache[n].cname, hostcache[n].name);
            hostcache[n].cname[14] = 0;
            Q_strcpy(hostcache[n].name, "*");
            Q_strcat(hostcache[n].name, hostcache[n].cname);
        }
        Q_memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr));
        hostcache[n].driver = net_driverlevel;
        hostcache[n].ldriver = net_landriverlevel;
        Q_strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr));

        // check for a name conflict
        for (i = 0; i < hostCacheCount; i++) {
            if (i == n) {
                continue;
            }
            if (Q_strcasecmp(hostcache[n].name, hostcache[i].name) == 0) {
                i = Q_strlen(hostcache[n].name);
                if (i < 15 && hostcache[n].name[i-1] > '8') {
                    hostcache[n].name[i] = '0';
                    hostcache[n].name[i+1] = 0;
                } else {
                    hostcache[n].name[i-1]++;
                }
                i = -1;
            }
        }
    }
}
Example #9
0
static qsocket_t *_Datagram_Connect(char *host)
{
    struct qsockaddr sendaddr;
    struct qsockaddr readaddr;
    qsocket_t	*sock;
    int			newsock;
    int			ret;
    int			reps;
    double		start_time;
    int			control;
    char		*reason;

    // see if we can resolve the host name
    if (dfunc.GetAddrFromName(host, &sendaddr) == -1) {
        return NULL;
    }

    newsock = dfunc.OpenSocket(0);
    if (newsock == -1) {
        return NULL;
    }

    sock = NET_NewQSocket();
    if (sock == NULL) {
        goto ErrorReturn2;
    }
    sock->socket = newsock;
    sock->landriver = net_landriverlevel;

    // connect to the host
    if (dfunc.Connect(newsock, &sendaddr) == -1) {
        goto ErrorReturn;
    }

    // send the connection request
    Con_Printf("trying...\n");
    SCR_UpdateScreen();
    start_time = net_time;

    for (reps = 0; reps < 3; reps++) {
        SZ_Clear(&net_message);
        // save space for the header, filled in later
        MSG_WriteLong(&net_message, 0);
        MSG_WriteByte(&net_message, CCREQ_CONNECT);
        MSG_WriteString(&net_message, "QUAKE");
        MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
        *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
        dfunc.Write(newsock, net_message.data, net_message.cursize, &sendaddr);
        SZ_Clear(&net_message);
        do {
            ret = dfunc.Read(newsock, net_message.data, net_message.maxsize, &readaddr);
            // if we got something, validate it
            if (ret > 0) {
                // is it from the right place?
                if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0) {
#ifdef DEBUG
                    Con_Printf("wrong reply address\n");
                    Con_Printf("Expected: %s\n", StrAddr(&sendaddr));
                    Con_Printf("Received: %s\n", StrAddr(&readaddr));
                    SCR_UpdateScreen();
#endif
                    ret = 0;
                    continue;
                }

                if (ret < sizeof(int)) {
                    ret = 0;
                    continue;
                }

                net_message.cursize = ret;
                MSG_BeginReading();

                control = BigLong(*((int *)net_message.data));
                MSG_ReadLong();
                if (control == -1) {
                    ret = 0;
                    continue;
                }
                if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL) {
                    ret = 0;
                    continue;
                }
                if ((control & NETFLAG_LENGTH_MASK) != ret) {
                    ret = 0;
                    continue;
                }
            }
        } while (ret == 0 && (SetNetTime() - start_time) < 2.5);
        if (ret) {
            break;
        }
        Con_Printf("still trying...\n");
        SCR_UpdateScreen();
        start_time = SetNetTime();
    }

    if (ret == 0) {
        reason = "No Response";
        Con_Printf("%s\n", reason);
        Q_strcpy(m_return_reason, reason);
        goto ErrorReturn;
    }

    if (ret == -1) {
        reason = "Network Error";
        Con_Printf("%s\n", reason);
        Q_strcpy(m_return_reason, reason);
        goto ErrorReturn;
    }

    ret = MSG_ReadByte();
    if (ret == CCREP_REJECT) {
        reason = MSG_ReadString();
        Con_Printf(reason);
        Q_strncpy(m_return_reason, reason, 31);
        goto ErrorReturn;
    }

    if (ret == CCREP_ACCEPT) {
        Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr));
        dfunc.SetSocketPort(&sock->addr, MSG_ReadLong());
    } else {
        reason = "Bad Response";
        Con_Printf("%s\n", reason);
        Q_strcpy(m_return_reason, reason);
        goto ErrorReturn;
    }

    dfunc.GetNameFromAddr(&sendaddr, sock->address);

    Con_Printf("Connection accepted\n");
    sock->lastMessageTime = SetNetTime();

    // switch the connection to the specified address
    if (dfunc.Connect(newsock, &sock->addr) == -1) {
        reason = "Connect to Game failed";
        Con_Printf("%s\n", reason);
        Q_strcpy(m_return_reason, reason);
        goto ErrorReturn;
    }

    m_return_onerror = false;
    return sock;

ErrorReturn:
    NET_FreeQSocket(sock);
ErrorReturn2:
    dfunc.CloseSocket(newsock);
    if (m_return_onerror) {
        key_dest = key_menu;
        m_state = m_return_state;
        m_return_onerror = false;
    }
    return NULL;
}
Example #10
0
static void CL_ParseDemoSnapShotSimple(msg_t *msg)
{
	int          len;
	clSnapshot_t *old;
	clSnapshot_t newSnap;
	int          deltaNum;
	int          oldMessageNum;
	int          i, packetNum;

	memset(&newSnap, 0, sizeof(newSnap));
	newSnap.serverCommandNum = clc.serverCommandSequence;
	newSnap.serverTime       = MSG_ReadLong(msg);
	newSnap.messageNum       = clc.serverMessageSequence;
	deltaNum                 = MSG_ReadByte(msg);
	if (!deltaNum)
	{
		newSnap.deltaNum = -1;
	}
	else
	{
		newSnap.deltaNum = newSnap.messageNum - deltaNum;
	}
	newSnap.snapFlags = MSG_ReadByte(msg);

	if (newSnap.deltaNum <= 0)
	{
		newSnap.valid = qtrue;      // uncompressed frame
		old           = NULL;
	}
	else
	{
		old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK];
		if (!old->valid)
		{
			// should never happen
			Com_FuncPrinf("Delta from invalid frame (not supposed to happen!).\n");
		}
		else if (old->messageNum != newSnap.deltaNum)
		{
			// The frame that the server did the delta from
			// is too old, so we can't reconstruct it properly.
			Com_FuncDPrinf("Delta frame too old.\n");
		}
		else if (cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES - 128)
		{
			Com_FuncDPrinf("Delta parseEntitiesNum too old.\n");
		}
		else
		{
			newSnap.valid = qtrue;  // valid delta parse
		}
	}

	// read areamask
	len = MSG_ReadByte(msg);

	if (len > sizeof(newSnap.areamask))
	{
		Com_FuncDrop("Invalid size %d for areamask.", len);
		return;
	}

	MSG_ReadData(msg, &newSnap.areamask, len);

	if (old)
	{
		MSG_ReadDeltaPlayerstate(msg, &old->ps, &newSnap.ps);
	}
	else
	{
		MSG_ReadDeltaPlayerstate(msg, NULL, &newSnap.ps);
	}

	// read packet entities
	CL_ParsePacketEntities(msg, old, &newSnap);

	// if not valid, dump the entire thing now that it has
	// been properly read
	if (!newSnap.valid)
	{
		return;
	}

	// clear the valid flags of any snapshots between the last
	// received and this one, so if there was a dropped packet
	// it won't look like something valid to delta from next
	// time we wrap around in the buffer
	oldMessageNum = cl.snap.messageNum + 1;

	if (newSnap.messageNum - oldMessageNum >= PACKET_BACKUP)
	{
		oldMessageNum = newSnap.messageNum - (PACKET_BACKUP - 1);
	}
	for (; oldMessageNum < newSnap.messageNum; oldMessageNum++)
	{
		cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse;
	}

	// copy to the current good spot
	cl.snap      = newSnap;
	cl.snap.ping = 999;
	// calculate ping time
	for (i = 0; i < PACKET_BACKUP; i++)
	{
		packetNum = (clc.netchan.outgoingSequence - 1 - i) & PACKET_MASK;
		if (cl.snap.ps.commandTime >= cl.outPackets[packetNum].p_serverTime)
		{
			cl.snap.ping = cls.realtime - cl.outPackets[packetNum].p_realtime;
			break;
		}
	}
	// save the frame off in the backup array for later delta comparisons
	cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap;
	cl.newSnapshots                                = qtrue;
}
Example #11
0
// Do very shallow parse of the demo (could be extended) just to get times and snapshot count
static void CL_ParseDemo(void)
{
	int tstart   = 0;
	int demofile = 0;

	// Reset our demo data
	memset(&di, 0, sizeof(di));

	// Parse start
	di.gameStartTime = -1;
	di.gameEndTime   = -1;
	FS_Seek(clc.demofile, 0, FS_SEEK_SET);
	tstart = Sys_Milliseconds();

	while (qtrue)
	{
		int   r;
		msg_t buf;
		msg_t *msg;
		byte  bufData[MAX_MSGLEN];
		int   s;
		int   cmd;

		di.demoPos = FS_FTell(clc.demofile);

		// get the sequence number
		r = FS_Read(&s, 4, clc.demofile);
		if (r != 4)
		{
			CL_DemoCompleted();
			return;
		}

		clc.serverMessageSequence = LittleLong(s);

		// init the message
		MSG_Init(&buf, bufData, sizeof(bufData));

		// get the length
		r = FS_Read(&buf.cursize, 4, clc.demofile);

		if (r != 4)
		{
			break;
		}

		buf.cursize = LittleLong(buf.cursize);
		if (buf.cursize == -1)
		{
			break;
		}

		if (buf.cursize > buf.maxsize)
		{
			Com_FuncDPrinf("demoMsglen > MAX_MSGLEN");
			break;
		}

		r = FS_Read(buf.data, buf.cursize, clc.demofile);
		if (r != buf.cursize)
		{
			Com_FuncDPrinf("Demo file was truncated.\n");
			break;
		}

		clc.lastPacketTime = cls.realtime;
		buf.readcount      = 0;

		// parse
		msg = &buf;
		MSG_Bitstream(msg);

		// get the reliable sequence acknowledge number
		clc.reliableAcknowledge = MSG_ReadLong(msg);

		if (clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS)
		{
			clc.reliableAcknowledge = clc.reliableSequence;
		}

		// parse the message
		while (qtrue)
		{
			if (msg->readcount > msg->cursize)
			{
				Com_FuncDrop("read past end of server message");
				break;
			}

			cmd = MSG_ReadByte(msg);

			if (cmd == svc_EOF)
			{
				break;
			}

			// other commands
			switch (cmd)
			{
			default:
				Com_FuncDrop("Illegible server message %d", cmd);
				break;
			case svc_nop:
				break;
			case svc_serverCommand:
				MSG_ReadLong(msg);
				MSG_ReadString(msg);
				break;
			case svc_gamestate:
				clc.serverCommandSequence = MSG_ReadLong(msg);
				cl.gameState.dataCount    = 1;
				while (qtrue)
				{
					int cmd2 = MSG_ReadByte(msg);
					if (cmd2 == svc_EOF)
					{
						break;
					}
					if (cmd2 == svc_configstring)
					{
						MSG_ReadShort(msg);
						MSG_ReadBigString(msg);
					}
					else if (cmd2 == svc_baseline)
					{
						entityState_t s1, s2;
						memset(&s1, 0, sizeof(s1));
						memset(&s2, 0, sizeof(s2));
						MSG_ReadBits(msg, GENTITYNUM_BITS);
						MSG_ReadDeltaEntity(msg, &s1, &s2, 0);
					}
					else
					{
						Com_FuncDrop("bad command byte");
					}
				}
				MSG_ReadLong(msg);
				MSG_ReadLong(msg);
				break;
			case svc_snapshot:
				CL_ParseDemoSnapShotSimple(msg);
				break;
			case svc_download:
				MSG_ReadShort(msg);

				break;
			}
		}

		if (!cl.snap.valid)
		{
			Com_FuncDPrinf("!cl.snap.valid\n");
			continue;
		}

		if (cl.snap.serverTime < cl.oldFrameServerTime)
		{
			// ignore snapshots that don't have entities
			if (cl.snap.snapFlags & SNAPFLAG_NOT_ACTIVE)
			{
				continue;
			}
			cls.state = CA_ACTIVE;

			// set the timedelta so we are exactly on this first frame
			cl.serverTimeDelta = cl.snap.serverTime - cls.realtime;
			cl.oldServerTime   = cl.snap.serverTime;

			clc.timeDemoBaseTime = cl.snap.serverTime;
		}
		cl.oldFrameServerTime = cl.snap.serverTime;

		if (cl.newSnapshots)
		{
			CL_AdjustTimeDelta();
		}

		di.lastServerTime = cl.snap.serverTime;
		if (di.firstServerTime == 0)
		{
			di.firstServerTime = cl.snap.serverTime;
			Com_FuncPrinf("firstServerTime %d\n", di.firstServerTime);
		}

		di.snapsInDemo++;
	}

	Com_FuncDPrinf("Snaps in demo: %i\n", di.snapsInDemo);
	Com_FuncDPrinf("last serverTime %d   total %f minutes\n", cl.snap.serverTime, (cl.snap.serverTime - di.firstServerTime) / 1000.0 / 60.0);
	Com_FuncDPrinf("parse time %f seconds\n", (float)(Sys_Milliseconds() - tstart) / 1000.0);
	FS_Seek(clc.demofile, 0, FS_SEEK_SET);
	clc.demoplaying = qfalse;
	demofile        = clc.demofile;
	CL_ClearState();
	Com_Memset(&clc, 0, sizeof(clc));
	clc.demofile             = demofile;
	cls.state                = CA_DISCONNECTED;
	cl_connectedToPureServer = qfalse;

	dpi.firstTime = di.firstServerTime;
	dpi.lastTime  = di.lastServerTime;
}
Example #12
0
qboolean CL_PeekSnapshot(int snapshotNumber, snapshot_t *snapshot)
{
	clSnapshot_t *clSnap;
	clSnapshot_t csn;
	int          i, count;
	int          origPosition;
	int          cmd;
	//char         *s;
	char     buffer[16];
	qboolean success = qfalse;
	int      r;
	msg_t    buf;
	byte     bufData[MAX_MSGLEN];
	int      j;
	int      lastPacketTimeOrig;
	int      parseEntitiesNumOrig;
	int      currentSnapNum;
	//int      serverMessageSequence;

	clSnap = &csn;

	if (!clc.demoplaying)
	{
		return qfalse;
	}

	if (snapshotNumber <= cl.snap.messageNum)
	{
		success = CL_GetSnapshot(snapshotNumber, snapshot);
		if (!success)
		{
			Com_FuncDPrinf("snapshot number outside of backup buffer\n");
			return qfalse;
		}
		return qtrue;
	}

	if (snapshotNumber > cl.snap.messageNum + 1)
	{
		Com_FuncDPrinf("FIXME CL_PeekSnapshot  %d >  cl.snap.messageNum + 1 (%d)\n", snapshotNumber, cl.snap.messageNum);
		//return qfalse;
	}

	parseEntitiesNumOrig = cl.parseEntitiesNum;
	lastPacketTimeOrig   = clc.lastPacketTime;
	// CL_ReadDemoMessage()
	origPosition = FS_FTell(clc.demofile);

	currentSnapNum = cl.snap.messageNum;

	for (j = 0; j < snapshotNumber - currentSnapNum; j++)
	{
		// get the sequence number
		memset(buffer, 0, sizeof(buffer));
		r = FS_Read(&buffer, 4, clc.demofile);
		if (r != 4)
		{
			Com_FuncDPrinf("couldn't read sequence number\n");
			FS_Seek(clc.demofile, origPosition, FS_SEEK_SET);
			clc.lastPacketTime  = lastPacketTimeOrig;
			cl.parseEntitiesNum = parseEntitiesNumOrig;
			return qfalse;
		}
		//serverMessageSequence = LittleLong(*((int *)buffer));

		// init the message
		memset(&buf, 0, sizeof(msg_t));
		MSG_Init(&buf, bufData, sizeof(bufData));

		// get the length
		r = FS_Read(&buf.cursize, 4, clc.demofile);
		if (r != 4)
		{
			Com_FuncDPrinf("couldn't get length\n");
			FS_Seek(clc.demofile, origPosition, FS_SEEK_SET);
			clc.lastPacketTime  = lastPacketTimeOrig;
			cl.parseEntitiesNum = parseEntitiesNumOrig;
			return qfalse;
		}

		buf.cursize = LittleLong(buf.cursize);
		if (buf.cursize == -1)
		{
			Com_FuncDPrinf("buf.cursize == -1\n");
			FS_Seek(clc.demofile, origPosition, FS_SEEK_SET);
			clc.lastPacketTime  = lastPacketTimeOrig;
			cl.parseEntitiesNum = parseEntitiesNumOrig;
			return qfalse;
		}

		if (buf.cursize > buf.maxsize)
		{
			Com_FuncDrop("demoMsglen > MAX_MSGLEN");
		}

		r = FS_Read(buf.data, buf.cursize, clc.demofile);
		if (r != buf.cursize)
		{
			Com_FuncDPrinf("Demo file was truncated.\n");
			FS_Seek(clc.demofile, origPosition, FS_SEEK_SET);
			clc.lastPacketTime  = lastPacketTimeOrig;
			cl.parseEntitiesNum = parseEntitiesNumOrig;
			return qfalse;
		}

		clc.lastPacketTime = cls.realtime;
		buf.readcount      = 0;

		MSG_Bitstream(&buf);
		// get the reliable sequence acknowledge number
		MSG_ReadLong(&buf);

		// parse the message
		while (qtrue)
		{
			if (buf.readcount > buf.cursize)
			{
				Com_FuncDrop("read past end of server message");
				break;
			}

			cmd = MSG_ReadByte(&buf);

			if (cmd == svc_EOF)
			{
				break;
			}
			success = qfalse;

			switch (cmd)
			{
			default:
				Com_FuncDrop("Illegible server message");
				break;
			case svc_nop:
				break;
			case svc_serverCommand:
				MSG_ReadLong(&buf);  // seq
				//s = MSG_ReadString(&buf);
				MSG_ReadString(&buf);
				break;
			case svc_gamestate:
				Com_FuncDPrinf("FIXME gamestate\n");
				goto alldone;
				break;
			case svc_snapshot:
				// TODO: changed this check if it works
				CL_ParseSnapshot(&buf);
				if (cl.snap.valid)
				{
					success = qtrue;
				}
				break;
			case svc_download:
				Com_FuncDPrinf("FIXME download\n");
				goto alldone;
				break;
			}
		}

alldone:

		if (!success)
		{
			Com_FuncDPrinf("failed\n");
			FS_Seek(clc.demofile, origPosition, FS_SEEK_SET);
			clc.lastPacketTime  = lastPacketTimeOrig;
			cl.parseEntitiesNum = parseEntitiesNumOrig;
			return success;
		}

		// FIXME other ents not supported yet

		// if the entities in the frame have fallen out of their
		// circular buffer, we can't return it
		if (cl.parseEntitiesNum - clSnap->parseEntitiesNum >= MAX_PARSE_ENTITIES)
		{
			Com_FuncDPrinf("cl.parseEntitiesNum - clSnap->parseEntitiesNum >= MAX_PARSE_ENTITIES");
			FS_Seek(clc.demofile, origPosition, FS_SEEK_SET);
			clc.lastPacketTime  = lastPacketTimeOrig;
			cl.parseEntitiesNum = parseEntitiesNumOrig;
			return qtrue;  // FIXME if you fix other ents
		}

		// write the snapshot
		snapshot->snapFlags             = clSnap->snapFlags;
		snapshot->serverCommandSequence = clSnap->serverCommandNum;
		snapshot->ping                  = clSnap->ping;
		snapshot->serverTime            = clSnap->serverTime;
		Com_Memcpy(snapshot->areamask, clSnap->areamask, sizeof(snapshot->areamask));
		snapshot->ps = clSnap->ps;
		count        = clSnap->numEntities;

		if (count > MAX_ENTITIES_IN_SNAPSHOT)
		{
			Com_FuncDPrinf("truncated %i entities to %i\n", count, MAX_ENTITIES_IN_SNAPSHOT);
			count = MAX_ENTITIES_IN_SNAPSHOT;
		}

		snapshot->numEntities = count;
		for (i = 0; i < count; i++)
		{
			snapshot->entities[i] = cl.parseEntities[(clSnap->parseEntitiesNum + i) & (MAX_PARSE_ENTITIES - 1)];
		}

	}

	FS_Seek(clc.demofile, origPosition, FS_SEEK_SET);
	clc.lastPacketTime  = lastPacketTimeOrig;
	cl.parseEntitiesNum = parseEntitiesNumOrig;
	// TODO: configstring changes and server commands!!!

	return qtrue;
}
Example #13
0
/*
=====================
CL_ParseServerMessage
=====================
*/
void CL_ParseServerMessage(msg_t *msg)
{
	int cmd;

	if (cl_shownet->integer == 1)
	{
		Com_Printf("%i ", msg->cursize);
	}
	else if (cl_shownet->integer >= 2)
	{
		Com_Printf("------------------\n");
	}

	MSG_Bitstream(msg);

	// get the reliable sequence acknowledge number
	clc.reliableAcknowledge = MSG_ReadLong(msg);

	if (clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS)
	{
		clc.reliableAcknowledge = clc.reliableSequence;
	}

	// parse the message
	while (1)
	{
		if (msg->readcount > msg->cursize)
		{
			Com_Error(ERR_DROP, "CL_ParseServerMessage: read past end of server message");
			break;
		}

		cmd = MSG_ReadByte(msg);

		if (cmd == svc_EOF)
		{
			SHOWNET(msg, "END OF MESSAGE");
			break;
		}

		if (cl_shownet->integer >= 2)
		{
			if (cmd < 0 || cmd > svc_EOF) // MSG_ReadByte might return -1 and we can't access our svc_strings array ...
			{
				Com_Printf("%3i:BAD BYTE %i\n", msg->readcount - 1, cmd); // -> ERR_DROP
			}
			else
			{
				if (!svc_strings[cmd])
				{
					Com_Printf("%3i:BAD CMD %i\n", msg->readcount - 1, cmd);
				}
				else
				{
					SHOWNET(msg, svc_strings[cmd]);
				}
			}
		}

		// other commands
		switch (cmd)
		{
		default:
			Com_Error(ERR_DROP, "CL_ParseServerMessage: Illegible server message %d", cmd);
			break;
		case svc_nop:
			break;
		case svc_serverCommand:
			CL_ParseCommandString(msg);
			break;
		case svc_gamestate:
			CL_ParseGamestate(msg);
			break;
		case svc_snapshot:
			CL_ParseSnapshot(msg);
			break;
		case svc_download:
			CL_ParseDownload(msg);
			break;
		}
	}

	CL_ParseBinaryMessage(msg);
}
Example #14
0
/*
==================
CL_ParseGamestate
==================
*/
void CL_ParseGamestate(msg_t *msg)
{
	int           i;
	entityState_t *es;
	int           newnum;
	entityState_t nullstate;
	int           cmd;
	char          *s;

	// Con_Close();

	clc.connectPacketCount = 0;

	// wipe local client state
	CL_ClearState();

	// a gamestate always marks a server command sequence
	clc.serverCommandSequence = MSG_ReadLong(msg);

	// parse all the configstrings and baselines
	cl.gameState.dataCount = 1; // leave a 0 at the beginning for uninitialized configstrings
	while (1)
	{
		cmd = MSG_ReadByte(msg);

		if (cmd == svc_EOF)
		{
			break;
		}

		if (cmd == svc_configstring)
		{
			int len;

			i = MSG_ReadShort(msg);
			if (i < 0 || i >= MAX_CONFIGSTRINGS)
			{
				Com_Error(ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
			}
			s   = MSG_ReadBigString(msg);
			len = strlen(s);

			if (len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS)
			{
				Com_Error(ERR_DROP, "MAX_GAMESTATE_CHARS exceeded");
			}

			// append it to the gameState string buffer
			cl.gameState.stringOffsets[i] = cl.gameState.dataCount;
			memcpy(cl.gameState.stringData + cl.gameState.dataCount, s, len + 1);
			cl.gameState.dataCount += len + 1;
		}
		else if (cmd == svc_baseline)
		{
			newnum = MSG_ReadBits(msg, GENTITYNUM_BITS);
			if (newnum < 0 || newnum >= MAX_GENTITIES)
			{
				Com_Error(ERR_DROP, "Baseline number out of range: %i", newnum);
			}
			memset(&nullstate, 0, sizeof(nullstate));
			es = &cl.entityBaselines[newnum];
			MSG_ReadDeltaEntity(msg, &nullstate, es, newnum);
		}
		else
		{
			Com_Error(ERR_DROP, "CL_ParseGamestate: bad command byte");
		}
	}

	clc.clientNum = MSG_ReadLong(msg);
	// read the checksum feed
	clc.checksumFeed = MSG_ReadLong(msg);

	// parse serverId and other cvars
	CL_SystemInfoChanged();

	// Verify if we have all official pakfiles. As we won't
	// be downloading them, we should be kicked for not having them.
	if (cl_connectedToPureServer && !FS_VerifyOfficialPaks())
	{
		Com_Error(ERR_DROP, "Couldn't load an official pak file; verify your installation and make sure it has been updated to the latest version.");
	}

	// reinitialize the filesystem if the game directory has changed
	FS_ConditionalRestart(clc.checksumFeed);

	// This used to call CL_StartHunkUsers, but now we enter the download state before loading the
	// cgame
	Com_InitDownloads();

	// make sure the game starts
	Cvar_Set("cl_paused", "0");
}
Example #15
0
static void demoFrameUnpack( msg_t *msg, demoFrame_t *oldFrame, demoFrame_t *newFrame ) {
	int last;
	qboolean isDelta = MSG_ReadBits( msg, 1 ) ? qfalse : qtrue;
	if (!isDelta)
		oldFrame = 0;

	newFrame->serverTime = MSG_ReadLong( msg );
	/* Read config strings */
	newFrame->string.data[0] = 0;
	newFrame->string.used = 1;
	last = 0;
	/* Extract config strings */
	while ( 1 ) {
		int i, num = MSG_ReadShort( msg );
		if (!isDelta ) {
			for (i = last;i<num;i++)
				newFrame->string.offsets[i] = 0;
		} else {
			for (i = last;i<num;i++)
				demoFrameAddString( &newFrame->string, i, oldFrame->string.data + oldFrame->string.offsets[i] );
		}
		if (num < MAX_CONFIGSTRINGS) {
			demoFrameAddString( &newFrame->string, num, MSG_ReadBigString( msg ) );
		} else {
			break;
		}
		last = num + 1;
	}
    /* Extract player states */
	Com_Memset( newFrame->clientData, 0, sizeof( newFrame->clientData ));
	last = MSG_ReadByte( msg );
	while (last < MAX_CLIENTS) {
		playerState_t *oldPlayer, *newPlayer;
		newFrame->clientData[last] = 1;
		oldPlayer = isDelta && oldFrame->clientData[last] ? &oldFrame->clients[last] : &demoNullPlayerState;
		newPlayer = &newFrame->clients[last];
		MSG_ReadDeltaPlayerstate( msg, oldPlayer, newPlayer );
		last = MSG_ReadByte( msg );
	}
	/* Extract entity states */
	last = 0;
	while ( 1 ) {
		int i, num = MSG_ReadBits( msg, GENTITYNUM_BITS );
		entityState_t *oldEntity, *newEntity;	
		if ( isDelta ) {
			for (i = last;i<num;i++)
				if (oldFrame->entities[i].number == i)
					newFrame->entities[i] = oldFrame->entities[i];
				else
					newFrame->entities[i].number = MAX_GENTITIES - 1;
		} else {
			for (i = last;i<num;i++)
				newFrame->entities[i].number = MAX_GENTITIES - 1;
		}
		if (num < MAX_GENTITIES - 1) {
			if (isDelta) {
				oldEntity = &oldFrame->entities[num];
				if (oldEntity->number != num)
					oldEntity = &demoNullEntityState;
			} else {
				oldEntity = &demoNullEntityState;
			}
			newEntity = &newFrame->entities[i];
			MSG_ReadDeltaEntity( msg, oldEntity, newEntity, num );
		} else
			break;
		last = num + 1;
	}
	/* Read the area mask */
	newFrame->areaUsed = MSG_ReadByte( msg );
	MSG_ReadData( msg, newFrame->areamask, newFrame->areaUsed );
	/* Read the command string data */
	newFrame->commandUsed = MSG_ReadLong( msg );
	MSG_ReadData( msg, newFrame->commandData, newFrame->commandUsed );
}
Example #16
0
static void Test2_Poll(void)
{
    struct qsockaddr clientaddr;
    int		control;
    int		len;
    char	name[256];
    char	value[256];

    net_landriverlevel = test2Driver;
    name[0] = 0;

    len = dfunc.Read(test2Socket, net_message.data, net_message.maxsize, &clientaddr);
    if (len < sizeof(int)) {
        goto Reschedule;
    }

    net_message.cursize = len;

    MSG_BeginReading();
    control = BigLong(*((int *)net_message.data));
    MSG_ReadLong();
    if (control == -1) {
        goto Error;
    }
    if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL) {
        goto Error;
    }
    if ((control & NETFLAG_LENGTH_MASK) != len) {
        goto Error;
    }

    if (MSG_ReadByte() != CCREP_RULE_INFO) {
        goto Error;
    }

    Q_strcpy(name, MSG_ReadString());
    if (name[0] == 0) {
        goto Done;
    }
    Q_strcpy(value, MSG_ReadString());

    Con_Printf("%-16.16s  %-16.16s\n", name, value);

    SZ_Clear(&net_message);
    // save space for the header, filled in later
    MSG_WriteLong(&net_message, 0);
    MSG_WriteByte(&net_message, CCREQ_RULE_INFO);
    MSG_WriteString(&net_message, name);
    *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
    dfunc.Write(test2Socket, net_message.data, net_message.cursize, &clientaddr);
    SZ_Clear(&net_message);

Reschedule:
    SchedulePollProcedure(&test2PollProcedure, 0.05);
    return;

Error:
    Con_Printf("Unexpected repsonse to Rule Info request\n");
Done:
    dfunc.CloseSocket(test2Socket);
    test2InProgress = false;
    return;
}
Example #17
0
/*
=================
CL_ParseTEnt
=================
*/
void
CL_ParseTEnt(void)
{
    int type;
    vec3_t pos;
    dlight_t *dl;
    int rnd;
    explosion_t *ex;
    int cnt;

    type = MSG_ReadByte();
    switch (type) {
    case TE_WIZSPIKE:		// spike hitting wall
	pos[0] = MSG_ReadCoord();
	pos[1] = MSG_ReadCoord();
	pos[2] = MSG_ReadCoord();
	R_RunParticleEffect(pos, vec3_origin, 20, 30);
	S_StartSound(-1, 0, cl_sfx_wizhit, pos, 1, 1);
	break;

    case TE_KNIGHTSPIKE:	// spike hitting wall
	pos[0] = MSG_ReadCoord();
	pos[1] = MSG_ReadCoord();
	pos[2] = MSG_ReadCoord();
	R_RunParticleEffect(pos, vec3_origin, 226, 20);
	S_StartSound(-1, 0, cl_sfx_knighthit, pos, 1, 1);
	break;

    case TE_SPIKE:		// spike hitting wall
	pos[0] = MSG_ReadCoord();
	pos[1] = MSG_ReadCoord();
	pos[2] = MSG_ReadCoord();
	R_RunParticleEffect(pos, vec3_origin, 0, 10);

	if (rand() % 5)
	    S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
	else {
	    rnd = rand() & 3;
	    if (rnd == 1)
		S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
	    else if (rnd == 2)
		S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
	    else
		S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
	}
	break;
    case TE_SUPERSPIKE:	// super spike hitting wall
	pos[0] = MSG_ReadCoord();
	pos[1] = MSG_ReadCoord();
	pos[2] = MSG_ReadCoord();
	R_RunParticleEffect(pos, vec3_origin, 0, 20);

	if (rand() % 5)
	    S_StartSound(-1, 0, cl_sfx_tink1, pos, 1, 1);
	else {
	    rnd = rand() & 3;
	    if (rnd == 1)
		S_StartSound(-1, 0, cl_sfx_ric1, pos, 1, 1);
	    else if (rnd == 2)
		S_StartSound(-1, 0, cl_sfx_ric2, pos, 1, 1);
	    else
		S_StartSound(-1, 0, cl_sfx_ric3, pos, 1, 1);
	}
	break;

    case TE_EXPLOSION:		// rocket explosion
	// particles
	pos[0] = MSG_ReadCoord();
	pos[1] = MSG_ReadCoord();
	pos[2] = MSG_ReadCoord();
	R_ParticleExplosion(pos);

	// light
	dl = CL_AllocDlight(0);
	VectorCopy(pos, dl->origin);
	dl->radius = 350;
	dl->die = cl.time + 0.5;
	dl->decay = 300;
	dl->color = dl_colors[DLIGHT_FLASH];

	// sound
	S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);

	// sprite
	ex = CL_AllocExplosion();
	VectorCopy(pos, ex->origin);
	ex->start = cl.time;
	ex->model = Mod_ForName("progs/s_explod.spr", true);
	break;

    case TE_TAREXPLOSION:	// tarbaby explosion
	pos[0] = MSG_ReadCoord();
	pos[1] = MSG_ReadCoord();
	pos[2] = MSG_ReadCoord();
	R_BlobExplosion(pos);

	S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
	break;

    case TE_LIGHTNING1:	// lightning bolts
	CL_ParseBeam(Mod_ForName("progs/bolt.mdl", true));
	break;

    case TE_LIGHTNING2:	// lightning bolts
	CL_ParseBeam(Mod_ForName("progs/bolt2.mdl", true));
	break;

    case TE_LIGHTNING3:	// lightning bolts
	CL_ParseBeam(Mod_ForName("progs/bolt3.mdl", true));
	break;

    case TE_LAVASPLASH:
	pos[0] = MSG_ReadCoord();
	pos[1] = MSG_ReadCoord();
	pos[2] = MSG_ReadCoord();
	R_LavaSplash(pos);
	break;

    case TE_TELEPORT:
	pos[0] = MSG_ReadCoord();
	pos[1] = MSG_ReadCoord();
	pos[2] = MSG_ReadCoord();
	R_TeleportSplash(pos);
	break;

    case TE_GUNSHOT:		// bullet hitting wall
	cnt = MSG_ReadByte();
	pos[0] = MSG_ReadCoord();
	pos[1] = MSG_ReadCoord();
	pos[2] = MSG_ReadCoord();
	R_RunParticleEffect(pos, vec3_origin, 0, 20 * cnt);
	break;

    case TE_BLOOD:		// bullets hitting body
	cnt = MSG_ReadByte();
	pos[0] = MSG_ReadCoord();
	pos[1] = MSG_ReadCoord();
	pos[2] = MSG_ReadCoord();
	R_RunParticleEffect(pos, vec3_origin, 73, 20 * cnt);
	break;

    case TE_LIGHTNINGBLOOD:	// lightning hitting body
	pos[0] = MSG_ReadCoord();
	pos[1] = MSG_ReadCoord();
	pos[2] = MSG_ReadCoord();
	R_RunParticleEffect(pos, vec3_origin, 225, 50);
	break;

    default:
	Sys_Error("%s: bad type", __func__);
    }
}
Example #18
0
static qsocket_t *_Datagram_CheckNewConnections(void)
{
    struct qsockaddr clientaddr;
    struct qsockaddr newaddr;
    int			newsock;
    int			acceptsock;
    qsocket_t	*sock;
    qsocket_t	*s;
    int			len;
    int			command;
    int			control;
    int			ret;

    acceptsock = dfunc.CheckNewConnections();
    if (acceptsock == -1) {
        return NULL;
    }

    SZ_Clear(&net_message);

    len = dfunc.Read(acceptsock, net_message.data, net_message.maxsize, &clientaddr);
    if (len < sizeof(int)) {
        return NULL;
    }
    net_message.cursize = len;

    MSG_BeginReading();
    control = BigLong(*((int *)net_message.data));
    MSG_ReadLong();
    if (control == -1) {
        return NULL;
    }
    if ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL) {
        return NULL;
    }
    if ((control & NETFLAG_LENGTH_MASK) != len) {
        return NULL;
    }

    command = MSG_ReadByte();
    if (command == CCREQ_SERVER_INFO) {
        if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) {
            return NULL;
        }

        SZ_Clear(&net_message);
        // save space for the header, filled in later
        MSG_WriteLong(&net_message, 0);
        MSG_WriteByte(&net_message, CCREP_SERVER_INFO);
        dfunc.GetSocketAddr(acceptsock, &newaddr);
        MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
        MSG_WriteString(&net_message, hostname.string);
        MSG_WriteString(&net_message, sv.name);
        MSG_WriteByte(&net_message, net_activeconnections);
        MSG_WriteByte(&net_message, svs.maxclients);
        MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);
        *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
        dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr);
        SZ_Clear(&net_message);
        return NULL;
    }

    if (command == CCREQ_PLAYER_INFO) {
        int			playerNumber;
        int			activeNumber;
        int			clientNumber;
        client_t	*client;

        playerNumber = MSG_ReadByte();
        activeNumber = -1;
        for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++) {
            if (client->active) {
                activeNumber++;
                if (activeNumber == playerNumber) {
                    break;
                }
            }
        }
        if (clientNumber == svs.maxclients) {
            return NULL;
        }

        SZ_Clear(&net_message);
        // save space for the header, filled in later
        MSG_WriteLong(&net_message, 0);
        MSG_WriteByte(&net_message, CCREP_PLAYER_INFO);
        MSG_WriteByte(&net_message, playerNumber);
        MSG_WriteString(&net_message, client->name);
        MSG_WriteLong(&net_message, client->colors);
        MSG_WriteLong(&net_message, (int)client->edict->v.frags);
        MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
        MSG_WriteString(&net_message, client->netconnection->address);
        *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
        dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr);
        SZ_Clear(&net_message);

        return NULL;
    }

    if (command == CCREQ_RULE_INFO) {
        char	*prevCvarName;
        cvar_t	*var;

        // find the search start location
        prevCvarName = MSG_ReadString();
        if (*prevCvarName) {
            var = Cvar_FindVar(prevCvarName);
            if (!var) {
                return NULL;
            }
            var = var->next;
        } else {
            var = cvar_vars;
        }

        // search for the next server cvar
        while (var) {
            if (var->server) {
                break;
            }
            var = var->next;
        }

        // send the response

        SZ_Clear(&net_message);
        // save space for the header, filled in later
        MSG_WriteLong(&net_message, 0);
        MSG_WriteByte(&net_message, CCREP_RULE_INFO);
        if (var) {
            MSG_WriteString(&net_message, var->name);
            MSG_WriteString(&net_message, var->string);
        }
        *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
        dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr);
        SZ_Clear(&net_message);

        return NULL;
    }

    if (command != CCREQ_CONNECT) {
        return NULL;
    }

    if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) {
        return NULL;
    }

    if (MSG_ReadByte() != NET_PROTOCOL_VERSION) {
        SZ_Clear(&net_message);
        // save space for the header, filled in later
        MSG_WriteLong(&net_message, 0);
        MSG_WriteByte(&net_message, CCREP_REJECT);
        MSG_WriteString(&net_message, "Incompatible version.\n");
        *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
        dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr);
        SZ_Clear(&net_message);
        return NULL;
    }

#ifdef BAN_TEST
    // check for a ban
    if (clientaddr.sa_family == AF_INET) {
        unsigned long testAddr;
        testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr;
        if ((testAddr & banMask) == banAddr) {
            SZ_Clear(&net_message);
            // save space for the header, filled in later
            MSG_WriteLong(&net_message, 0);
            MSG_WriteByte(&net_message, CCREP_REJECT);
            MSG_WriteString(&net_message, "You have been banned.\n");
            *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
            dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr);
            SZ_Clear(&net_message);
            return NULL;
        }
    }
#endif

    // see if this guy is already connected
    for (s = net_activeSockets; s; s = s->next) {
        if (s->driver != net_driverlevel) {
            continue;
        }
        ret = dfunc.AddrCompare(&clientaddr, &s->addr);
        if (ret >= 0) {
            // is this a duplicate connection reqeust?
            if (ret == 0 && net_time - s->connecttime < 2.0) {
                // yes, so send a duplicate reply
                SZ_Clear(&net_message);
                // save space for the header, filled in later
                MSG_WriteLong(&net_message, 0);
                MSG_WriteByte(&net_message, CCREP_ACCEPT);
                dfunc.GetSocketAddr(s->socket, &newaddr);
                MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
                *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
                dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr);
                SZ_Clear(&net_message);
                return NULL;
            }
            // it's somebody coming back in from a crash/disconnect
            // so close the old qsocket and let their retry get them back in
            NET_Close(s);
            return NULL;
        }
    }

    // allocate a QSocket
    sock = NET_NewQSocket();
    if (sock == NULL) {
        // no room; try to let him know
        SZ_Clear(&net_message);
        // save space for the header, filled in later
        MSG_WriteLong(&net_message, 0);
        MSG_WriteByte(&net_message, CCREP_REJECT);
        MSG_WriteString(&net_message, "Server is full.\n");
        *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
        dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr);
        SZ_Clear(&net_message);
        return NULL;
    }

    // allocate a network socket
    newsock = dfunc.OpenSocket(0);
    if (newsock == -1) {
        NET_FreeQSocket(sock);
        return NULL;
    }

    // connect to the client
    if (dfunc.Connect(newsock, &clientaddr) == -1) {
        dfunc.CloseSocket(newsock);
        NET_FreeQSocket(sock);
        return NULL;
    }

    // everything is allocated, just fill in the details
    sock->socket = newsock;
    sock->landriver = net_landriverlevel;
    sock->addr = clientaddr;
    Q_strcpy(sock->address, dfunc.AddrToString(&clientaddr));

    // send him back the info about the server connection he has been allocated
    SZ_Clear(&net_message);
    // save space for the header, filled in later
    MSG_WriteLong(&net_message, 0);
    MSG_WriteByte(&net_message, CCREP_ACCEPT);
    dfunc.GetSocketAddr(newsock, &newaddr);
    MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
//	MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));
    *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
    dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr);
    SZ_Clear(&net_message);

    return sock;
}
Example #19
0
/*
=====================
CL_ParseServerMessage
=====================
 */
void CL_ParseServerMessage(msg_t *msg) {
    int cmd;

    if (cl_shownet->integer == 1) {
        Com_Printf("%i ", msg->cursize);
    } else if (cl_shownet->integer >= 2) {
        Com_Printf("------------------\n");
    }

    MSG_Bitstream(msg);

    // get the reliable sequence acknowledge number
    clc.reliableAcknowledge = MSG_ReadLong(msg);
    //
    if (clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS) {
        clc.reliableAcknowledge = clc.reliableSequence;
    }

    //
    // parse the message
    //
    while (1) {
        if (msg->readcount > msg->cursize) {
            Com_Error(ERR_DROP, "CL_ParseServerMessage: read past end of server message");
            break;
        }

        cmd = MSG_ReadByte(msg);

        // See if this is an extension command after the EOF, which means we
        //  got data that a legacy client should ignore.
        if ((cmd == svc_EOF) && (MSG_LookaheadByte(msg) == svc_extension)) {
            SHOWNET(msg, "EXTENSION");
            MSG_ReadByte(msg); // throw the svc_extension byte away.
            cmd = MSG_ReadByte(msg); // something legacy clients can't do!
            // sometimes you get a svc_extension at end of stream...dangling
            //  bits in the huffman decoder giving a bogus value?
            if (cmd == -1) {
                cmd = svc_EOF;
            }
        }

        if (cmd == svc_EOF) {
            SHOWNET(msg, "END OF MESSAGE");
            break;
        }

        if (cl_shownet->integer >= 2) {
            if ((cmd < 0) || (!svc_strings[cmd])) {
                Com_Printf("%3i:BAD CMD %i\n", msg->readcount - 1, cmd);
            } else {
                SHOWNET(msg, svc_strings[cmd]);
            }
        }

        // other commands
        switch (cmd) {
            default:
                Com_Error(ERR_DROP, "CL_ParseServerMessage: Illegible server message\n");
                break;
            case svc_nop:
                break;
            case svc_serverCommand:
                CL_ParseCommandString(msg);
                break;
            case svc_gamestate:
                CL_ParseGamestate(msg);
                break;
            case svc_snapshot:
                CL_ParseSnapshot(msg);
                break;
            case svc_download:
                CL_ParseDownload(msg);
                break;
            case svc_voip:
#ifdef USE_VOIP
                CL_ParseVoip(msg);
#endif
                break;
        }
    }
}
Example #20
0
/*
================
CL_ParseSnapshot

If the snapshot is parsed properly, it will be copied to
cl.snap and saved in cl.snapshots[].  If the snapshot is invalid
for any reason, no changes to the state will be made at all.
================
*/
void CL_ParseSnapshot( msg_t *msg )
{
	int          len;
	clSnapshot_t *old;
	clSnapshot_t newSnap;
	int          deltaNum;
	int          oldMessageNum;
	int          i, packetNum;

	// get the reliable sequence acknowledge number
	// NOTE: now sent with all server to client messages
	//clc.reliableAcknowledge = MSG_ReadLong( msg );

	// read in the new snapshot to a temporary buffer
	// we will only copy to cl.snap if it is valid
	Com_Memset( &newSnap, 0, sizeof( newSnap ) );

	// we will have read any new server commands in this
	// message before we got to svc_snapshot
	newSnap.serverCommandNum = clc.serverCommandSequence;

	newSnap.serverTime = MSG_ReadLong( msg );

	// if we were just unpaused, we can only *now* really let the
	// change come into effect or the client hangs.
	cl_paused->modified = 0;

	newSnap.messageNum = clc.serverMessageSequence;

	deltaNum = MSG_ReadByte( msg );

	if ( !deltaNum )
	{
		newSnap.deltaNum = -1;
	}
	else
	{
		newSnap.deltaNum = newSnap.messageNum - deltaNum;
	}

	newSnap.snapFlags = MSG_ReadByte( msg );

	// If the frame is delta compressed from data that we
	// no longer have available, we must suck up the rest of
	// the frame, but not use it, then ask for a non-compressed
	// message
	if ( newSnap.deltaNum <= 0 )
	{
		newSnap.valid = true; // uncompressed frame
		old = nullptr;

		if ( clc.demorecording )
		{
			clc.demowaiting = false; // we can start recording now
//          if(cl_autorecord->integer) {
//              Cvar_Set( "g_synchronousClients", "0" );
//          }
		}
		else
		{
			if ( cl_autorecord->integer /*&& Cvar_VariableValue( "g_synchronousClients") */ )
			{
				char    name[ 256 ];
				char    mapname[ MAX_QPATH ];
				char    *period;
				qtime_t time;

				Com_RealTime( &time );

				Q_strncpyz( mapname, cl.mapname, MAX_QPATH );

				for ( period = mapname; *period; period++ )
				{
					if ( *period == '.' )
					{
						*period = '\0';
						break;
					}
				}

				for ( period = mapname; *period; period++ )
				{
					if ( *period == '/' )
					{
						break;
					}
				}

				if ( *period )
				{
					period++;
				}

				Com_sprintf( name, sizeof( name ), "demos/%s_%04i-%02i-%02i_%02i%02i%02i.dm_%d", period,
				             1900 + time.tm_year, time.tm_mon + 1, time.tm_mday,
				             time.tm_hour, time.tm_min, time.tm_sec,
				             PROTOCOL_VERSION );

				CL_Record( name );
			}
		}
	}
	else
	{
		old = &cl.snapshots[ newSnap.deltaNum & PACKET_MASK ];

		if ( !old->valid )
		{
			// should never happen
			Com_Printf( "Delta from invalid frame (not supposed to happen!).\n" );
		}
		else if ( old->messageNum != newSnap.deltaNum )
		{
			// The frame that the server did the delta from
			// is too old, so we can't reconstruct it properly.
			Com_DPrintf( "Delta frame too old.\n" );
		}
		else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES - 128 )
		{
			Com_DPrintf( "Delta parseEntitiesNum too old.\n" );
		}
		else
		{
			newSnap.valid = true; // valid delta parse
		}
	}

	// read areamask
	len = MSG_ReadByte( msg );

	if ( len > (int) sizeof( newSnap.areamask ) )
	{
		Com_Error( ERR_DROP, "CL_ParseSnapshot: Invalid size %d for areamask.", len );
	}

	MSG_ReadData( msg, &newSnap.areamask, len );

	// read playerinfo
	SHOWNET( msg, "playerstate" );

	if ( old )
	{
		MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
	}
	else
	{
		MSG_ReadDeltaPlayerstate( msg, nullptr, &newSnap.ps );
	}

	// read packet entities
	SHOWNET( msg, "packet entities" );
	CL_ParsePacketEntities( msg, old, &newSnap );

	// if not valid, dump the entire thing now that it has
	// been properly read
	if ( !newSnap.valid )
	{
		return;
	}

	// clear the valid flags of any snapshots between the last
	// received and this one, so if there was a dropped packet
	// it won't look like something valid to delta from next
	// time we wrap around in the buffer
	oldMessageNum = cl.snap.messageNum + 1;

	if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP )
	{
		oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );
	}

	for ( ; oldMessageNum < newSnap.messageNum; oldMessageNum++ )
	{
		cl.snapshots[ oldMessageNum & PACKET_MASK ].valid = false;
	}

	// copy to the current good spot
	cl.snap = newSnap;
	cl.snap.ping = 999;

	// calculate ping time
	for ( i = 0; i < PACKET_BACKUP; i++ )
	{
		packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;

		if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime )
		{
			cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;
			break;
		}
	}

	// save the frame off in the backup array for later delta comparisons
	cl.snapshots[ cl.snap.messageNum & PACKET_MASK ] = cl.snap;

	if ( cl_shownet->integer == 3 )
	{
		Com_Printf( "   snapshot:%i  delta:%i  ping:%i\n", cl.snap.messageNum, cl.snap.deltaNum, cl.snap.ping );
	}

	cl.newSnapshots = true;
}
Example #21
0
/*
===================
SV_ExecuteClientMessage

Parse a client packet
===================
*/
void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
	int			c;
	int			serverId;

	MSG_Bitstream(msg);

	serverId = MSG_ReadLong( msg );
	cl->messageAcknowledge = MSG_ReadLong( msg );

	if (cl->messageAcknowledge < 0) {
		// usually only hackers create messages like this
		// it is more annoying for them to let them hanging
		//SV_DropClient( cl, "illegible client message" );
		return;
	}

	cl->reliableAcknowledge = MSG_ReadLong( msg );

	// NOTE: when the client message is fux0red the acknowledgement numbers
	// can be out of range, this could cause the server to send thousands of server
	// commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient
	if (cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS) {
		// usually only hackers create messages like this
		// it is more annoying for them to let them hanging
		//SV_DropClient( cl, "illegible client message" );
		cl->reliableAcknowledge = cl->reliableSequence;
		return;
	}
	// if this is a usercmd from a previous gamestate,
	// ignore it or retransmit the current gamestate
	//
	// if the client was downloading, let it stay at whatever serverId and
	// gamestate it was at.  This allows it to keep downloading even when
	// the gamestate changes.  After the download is finished, we'll
	// notice and send it a new game state
	if ( serverId != sv.serverId &&
		!*cl->downloadName ) {
		if ( serverId == sv.restartedServerId ) {
			// they just haven't caught the map_restart yet
			return;
		}
		// if we can tell that the client has dropped the last
		// gamestate we sent them, resend it
		if ( cl->messageAcknowledge > cl->gamestateMessageNum ) {
			Com_DPrintf( "%s : dropped gamestate, resending\n", cl->name );
			SV_SendClientGameState( cl );
		}
		return;
	}

	// this client has acknowledged the new gamestate so it's
	// safe to start sending it the real time again
	if( cl->oldServerTime && serverId == sv.serverId ){
		Com_DPrintf( "%s acknowledged gamestate\n", cl->name );
		cl->oldServerTime = 0;
	}

	// read optional clientCommand strings
	do {
		c = MSG_ReadByte( msg );
		if ( c == clc_EOF ) {
			break;
		}
		if ( c != clc_clientCommand ) {
			break;
		}
		if ( !SV_ClientCommand( cl, msg ) ) {
			return;	// we couldn't execute it because of the flood protection
		}
		if (cl->state == CS_ZOMBIE) {
			return;	// disconnect command
		}
	} while ( 1 );

	// read the usercmd_t
	if ( c == clc_move ) {
		SV_UserMove( cl, msg, qtrue );
	} else if ( c == clc_moveNoDelta ) {
		SV_UserMove( cl, msg, qfalse );
	} else if ( c != clc_EOF ) {
		Com_Printf( "WARNING: bad command byte for client %i\n", (int)(cl - svs.clients) );
	}
//	if ( msg->readcount != msg->cursize ) {
//		Com_Printf( "WARNING: Junk at end of packet for client %i\n", cl - svs.clients );
//	}
}
Example #22
0
/*
==================
CL_ParseGamestate
==================
*/
void CL_ParseGamestate( msg_t *msg )
{
	int           i;
	entityState_t *es;
	int           newnum;
	entityState_t nullstate;
	int           cmd;

	Con_Close();

	clc.connectPacketCount = 0;

	// wipe local client state
	CL_ClearState();

	// a gamestate always marks a server command sequence
	clc.serverCommandSequence = MSG_ReadLong( msg );

	// parse all the configstrings and baselines
	while ( 1 )
	{
		cmd = MSG_ReadByte( msg );

		if ( cmd == svc_EOF )
		{
			break;
		}

		if ( cmd == svc_configstring )
		{
			i = MSG_ReadShort( msg );

			if ( i < 0 || i >= MAX_CONFIGSTRINGS )
			{
				Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
			}

            const char* str = MSG_ReadBigString( msg );
            std::string s = str;
			cl.gameState[i] = str;
		}
		else if ( cmd == svc_baseline )
		{
			newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );

			if ( newnum < 0 || newnum >= MAX_GENTITIES )
			{
				Com_Error( ERR_DROP, "Baseline number out of range: %i", newnum );
			}

			memset( &nullstate, 0, sizeof( nullstate ) );
			es = &cl.entityBaselines[ newnum ];
			MSG_ReadDeltaEntity( msg, &nullstate, es, newnum );
		}
		else
		{
			Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte" );
		}
	}

	clc.clientNum = MSG_ReadLong( msg );
	// read the checksum feed
	clc.checksumFeed = MSG_ReadLong( msg );

	// parse serverId and other cvars
	CL_SystemInfoChanged();

	// This used to call CL_StartHunkUsers, but now we enter the download state before loading the
	// cgame
	CL_InitDownloads();

	// make sure the game starts
	Cvar_Set( "cl_paused", "0" );
}
Example #23
0
void CPostFunc::GTH_ProcessMessage_PostSystem_OpenWindow()
{

	
	int	PostIdx = 0;
	int PostCount = -1;
	

	enum tagGCPacket_POSTSYSTEM_OPEN::enumCode code =
		tagGCPacket_POSTSYSTEM_OPEN::enumCode::fail;
	code = static_cast<enum tagGCPacket_POSTSYSTEM_OPEN::enumCode>(MSG_ReadByte());	
	
	
	switch( code ) 
	{
	case tagGCPacket_POSTSYSTEM_OPEN::enumCode::success:
		{
			PostCount = MSG_ReadLong();	

			g_cgv.myCharacterInfo->m_PostMng.InitPostSystem();		
			
			for ( PostIdx = 0;  PostIdx < PostCount; PostIdx++)
			{
				CPostManager::PostPackage_t PostPackage;
				memset(&PostPackage, 0, sizeof(CPostManager::PostPackage_t) );
				
				PostPackage.iPostIdx		= MSG_ReadLong();
				sstrncpy(PostPackage.szFromName, MSG_ReadString(), NAMESTRING);
				PostPackage.szFromName[NAMESTRING] = NULL;
				CTools::Replace_doubleQUOTATIONmark_by_singleQUOTATIONmark(PostPackage.szFromName);
				
				sstrncpy(PostPackage.szPostTitle,  MSG_ReadString(), CPostManager::POST_TITLESIZE);
				PostPackage.szPostTitle[CPostManager::POST_TITLESIZE] = NULL;
				CTools::Replace_doubleQUOTATIONmark_by_singleQUOTATIONmark(PostPackage.szPostTitle);

				
				sstrncpy(PostPackage.szSendPostTime	, MSG_ReadString(), CPostManager::POST_SENDTIME_INFO_STR_LEN);
				PostPackage.szSendPostTime[CPostManager::POST_SENDTIME_INFO_STR_LEN] = NULL;
				


				sstrncpy(PostPackage.szMailStr, MSG_ReadString(), CPostManager::POST_STRSIZE);
				PostPackage.szMailStr[CPostManager::POST_STRSIZE] = NULL;
				CTools::Replace_doubleQUOTATIONmark_by_singleQUOTATIONmark(PostPackage.szMailStr);
				
				int state = MSG_ReadLong();
				
				if ( state == 0)		
					PostPackage.MailState  =  CPostManager::enumPostPackageState::POSTPACKAGE_UNCHECK;
				else
					PostPackage.MailState  =  CPostManager::enumPostPackageState::POSTPACKAGE_CHECK;
				
				
				
				int nak = MSG_ReadLong();
				PostPackage.Nak = nak;

				int SendType = MSG_ReadLong();				
				
				
				PostPackage.iRemainDays = MSG_ReadLong();	


				if ( SendType == 0)
					PostPackage.PostSendType = CPostManager::enumPostSendType::POST_SENDTYPE_WEB;
				else
					PostPackage.PostSendType = CPostManager::enumPostSendType::POST_SENDTYPE_CHAR;
				
				
				
				g_cgv.myCharacterInfo->m_PostMng.AddPostPackage(PostPackage);				
				
			}					
			
			
				g_ifMng->m_PostWin->InitIFPost();
				g_ifMng->m_PostWin->SetDisplayMode(true);				
				g_ifMng->m_chatWin->Enable( false );

				g_ifMng->m_PostWin->Enable(1);
				g_ifMng->SetFocus( g_ifMng->m_PostWin );				

		}
		break;		

	case tagGCPacket_POSTSYSTEM_OPEN::enumCode::fail:
		g_ifMng->SetMessage( g_LPACK.GetMassage(LPACK_TYPE_NORMAL, 322), 
			g_LPACK.GetMassage(LPACK_TYPE_NORMAL2, 226) );		
		break;

	default:
		break;		
	}	
	

}
Example #24
0
/*
==================
SV_UserMove

The message usually contains all the movement commands
that were in the last three packets, so that the information
in dropped packets can be recovered.

On very fast clients, there may be multiple usercmd packed into
each of the backup packets.
==================
*/
static void SV_UserMove( client_t *cl, msg_t *msg, bool delta )
{
	int       i;
	int       cmdCount;
	usercmd_t nullcmd;
	usercmd_t cmds[ MAX_PACKET_USERCMDS ];
	usercmd_t *cmd, *oldcmd;

	if ( delta )
	{
		cl->deltaMessage = cl->messageAcknowledge;
	}
	else
	{
		cl->deltaMessage = -1;
	}

	cmdCount = MSG_ReadByte( msg );

	if ( cmdCount < 1 )
	{
		Log::Notice( "cmdCount < 1\n" );
		return;
	}

	if ( cmdCount > MAX_PACKET_USERCMDS )
	{
		Log::Notice( "cmdCount > MAX_PACKET_USERCMDS\n" );
		return;
	}

	memset( &nullcmd, 0, sizeof( nullcmd ) );
	oldcmd = &nullcmd;

	for ( i = 0; i < cmdCount; i++ )
	{
		cmd = &cmds[ i ];
		MSG_ReadDeltaUsercmd( msg, oldcmd, cmd );
//      MSG_ReadDeltaUsercmd( msg, oldcmd, cmd );
		oldcmd = cmd;
	}

	// save time for ping calculation
	cl->frames[ cl->messageAcknowledge & PACKET_MASK ].messageAcked = svs.time;

	// if this is the first usercmd we have received
	// this gamestate, put the client into the world
	if ( cl->state == clientState_t::CS_PRIMED )
	{
		SV_ClientEnterWorld( cl, &cmds[ 0 ] );
		// the moves can be processed normaly
	}

	if ( cl->state != clientState_t::CS_ACTIVE )
	{
		cl->deltaMessage = -1;
		return;
	}

	// usually, the first couple commands will be duplicates
	// of ones we have previously received, but the servertimes
	// in the commands will cause them to be immediately discarded
	for ( i = 0; i < cmdCount; i++ )
	{
		// if this is a cmd from before a map_restart ignore it
		if ( cmds[ i ].serverTime > cmds[ cmdCount - 1 ].serverTime )
		{
			continue;
		}

		// extremely lagged or cmd from before a map_restart
		if ( cmds[ i ].serverTime <= cl->lastUsercmd.serverTime )
		{
			continue;
		}

		SV_ClientThink( cl, &cmds[ i ] );
	}
}
Example #25
0
/*
==================
CL_ParseGamestate
==================
*/
void CL_ParseGamestate( msg_t *msg ) {
	int				i;
	entityState_t	*es;
	int				newnum;
	entityState_t	nullstate;
	int				cmd;
	char			*s;
	char oldGame[MAX_QPATH];

	Con_Close();

	clc.connectPacketCount = 0;

	// wipe local client state
	CL_ClearState();

	// a gamestate always marks a server command sequence
	clc.serverCommandSequence = MSG_ReadLong( msg );

	// parse all the configstrings and baselines
	cl.gameState.dataCount = 1;	// leave a 0 at the beginning for uninitialized configstrings
	while ( 1 ) {
		cmd = MSG_ReadByte( msg );

		if ( cmd == svc_EOF ) {
			break;
		}
		
		if ( cmd == svc_configstring ) {
			int		len;

			i = MSG_ReadShort( msg );
			if ( i < 0 || i >= MAX_CONFIGSTRINGS ) {
				Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
			}
			s = MSG_ReadBigString( msg );
			len = strlen( s );

			if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
				Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" );
			}

			// append it to the gameState string buffer
			cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
			Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 );
			cl.gameState.dataCount += len + 1;
		} else if ( cmd == svc_baseline ) {
			newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
			if ( newnum < 0 || newnum >= MAX_GENTITIES ) {
				Com_Error( ERR_DROP, "Baseline number out of range: %i", newnum );
			}
			Com_Memset (&nullstate, 0, sizeof(nullstate));
			es = &cl.entityBaselines[ newnum ];
			MSG_ReadDeltaEntity( msg, &nullstate, es, newnum );
		} else {
			Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte" );
		}
	}

	clc.clientNum = MSG_ReadLong(msg);
	// read the checksum feed
	clc.checksumFeed = MSG_ReadLong( msg );

	// save old gamedir
	Cvar_VariableStringBuffer("fs_game", oldGame, sizeof(oldGame));

	// parse useful values out of CS_SERVERINFO
	CL_ParseServerInfo();

	// parse serverId and other cvars
	CL_SystemInfoChanged();

	// stop recording now so the demo won't have an unnecessary level load at the end.
	if(cl_autoRecordDemo->integer && clc.demorecording)
		CL_StopRecord_f();
	
	// reinitialize the filesystem if the game directory has changed
	if(!cl_oldGameSet && (Cvar_Flags("fs_game") & CVAR_MODIFIED))
	{
		cl_oldGameSet = qtrue;
		Q_strncpyz(cl_oldGame, oldGame, sizeof(cl_oldGame));
	}

	FS_ConditionalRestart(clc.checksumFeed, qfalse);

	// This used to call CL_StartHunkUsers, but now we enter the download state before loading the
	// cgame
	CL_InitDownloads();

	// make sure the game starts
	Cvar_Set( "cl_paused", "0" );
}
Example #26
0
/*
===================
SV_ExecuteClientMessage

Parse a client packet
===================
*/
void SV_ExecuteClientMessage( client_t *cl, msg_t *msg )
{
	int c;
	int serverId;

	MSG_Bitstream( msg );

	serverId = MSG_ReadLong( msg );
	cl->messageAcknowledge = MSG_ReadLong( msg );

	if ( cl->messageAcknowledge < 0 )
	{
		// usually only hackers create messages like this
		// it is more annoying for them to let them hanging
#ifndef NDEBUG
		SV_DropClient( cl, "DEBUG: illegible client message" );
#endif
		return;
	}

	cl->reliableAcknowledge = MSG_ReadLong( msg );

	// NOTE: when the client message is fux0red the acknowledgement numbers
	// can be out of range, this could cause the server to send thousands of server
	// commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient
	if ( cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS )
	{
		// usually only hackers create messages like this
		// it is more annoying for them to let them hanging
#ifndef NDEBUG
		SV_DropClient( cl, "DEBUG: illegible client message" );
#endif
		cl->reliableAcknowledge = cl->reliableSequence;
		return;
	}

	// if this is a usercmd from a previous gamestate,
	// ignore it or retransmit the current gamestate
	//
	// if the client was downloading, let it stay at whatever serverId and
	// gamestate it was at.  This allows it to keep downloading even when
	// the gamestate changes.  After the download is finished, we'll
	// notice and send it a new game state
	//
	// show_bug.cgi?id=536
	// don't drop as long as previous command was a nextdl, after a dl is done, downloadName is set back to ""
	// but we still need to read the next message to move to next download or send gamestate
	// I don't like this hack though, it must have been working fine at some point, suspecting the fix is somewhere else
	if ( serverId != sv.serverId && !*cl->downloadName && !strstr( cl->lastClientCommandString, "nextdl" ) )
	{
		if ( serverId >= sv.restartedServerId && serverId < sv.serverId )
		{
			// TTimo - use a comparison here to catch multiple map_restart
			// they just haven't caught the map_restart yet
			Log::Debug( "%s^7: ignoring pre map_restart / outdated client message", cl->name );
			return;
		}

		// if we can tell that the client has dropped the last
		// gamestate we sent them, resend it
		if ( cl->messageAcknowledge > cl->gamestateMessageNum )
		{
			Log::Debug( "%s^7: dropped gamestate, resending", cl->name );
			SV_SendClientGameState( cl );
		}

		// read optional clientCommand strings
		do
		{
			c = MSG_ReadByte( msg );

			if ( c == clc_EOF )
			{
				break;
			}

			if ( c != clc_clientCommand )
			{
				break;
			}

			if ( !SV_ClientCommand( cl, msg, true ) )
			{
				return; // we couldn't execute it because of the flood protection
			}

			if ( cl->state == clientState_t::CS_ZOMBIE )
			{
				return; // disconnect command
			}
		}
		while ( 1 );

		return;
	}

	// read optional clientCommand strings
	do
	{
		c = MSG_ReadByte( msg );

		if ( c == clc_EOF )
		{
			break;
		}

		if ( c != clc_clientCommand )
		{
			break;
		}

		if ( !SV_ClientCommand( cl, msg, false ) )
		{
			return; // we couldn't execute it because of the flood protection
		}

		if ( cl->state == clientState_t::CS_ZOMBIE )
		{
			return; // disconnect command
		}
	}
	while ( 1 );

	// read the usercmd_t
	if ( c == clc_move )
	{
		SV_UserMove( cl, msg, true );
	}
	else if ( c == clc_moveNoDelta )
	{
		SV_UserMove( cl, msg, false );
	}
	else if ( c != clc_EOF )
	{
		Log::Warn( "bad command byte for client %i\n", ( int )( cl - svs.clients ) );
	}

	SV_ParseBinaryMessage( cl, msg );

//  if ( msg->readcount != msg->cursize ) {
//      Log::Notice( "WARNING: Junk at end of packet for client %i\n", cl - svs.clients );
//  }
}
Example #27
0
/*
==================
CL_ParseGamestate
==================
*/
void CL_ParseGamestate( msg_t *msg ) {
	int				i;
	entityState_t	*es;
	int				newnum;
	entityState_t	nullstate;
	int				cmd;
	char			*s;

	Con_Close();

	clc.connectPacketCount = 0;

	// wipe local client state
	CL_ClearState();

#ifdef _DONETPROFILE_
	int startBytes,endBytes;
	startBytes=msg->readcount;
#endif

	// a gamestate always marks a server command sequence
	clc.serverCommandSequence = MSG_ReadLong( msg );

	// parse all the configstrings and baselines
	cl.gameState.dataCount = 1;	// leave a 0 at the beginning for uninitialized configstrings
	while ( 1 ) {
		cmd = MSG_ReadByte( msg );

		if ( cmd == svc_EOF ) {
			break;
		}
		
		if ( cmd == svc_configstring ) {
			int		len;

			i = MSG_ReadShort( msg );
			if ( i < 0 || i >= MAX_CONFIGSTRINGS ) {
				Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
			}
			s = MSG_ReadBigString( msg );
			len = strlen( s );

			if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
				Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" );
			}

			// append it to the gameState string buffer
			cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
			Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 );
			cl.gameState.dataCount += len + 1;
		} else if ( cmd == svc_baseline ) {
			newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
			if ( newnum < 0 || newnum >= MAX_GENTITIES ) {
				Com_Error( ERR_DROP, "Baseline number out of range: %i", newnum );
			}
			Com_Memset (&nullstate, 0, sizeof(nullstate));
			es = &cl.entityBaselines[ newnum ];
			MSG_ReadDeltaEntity( msg, &nullstate, es, newnum );
		} else {
			Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte" );
		}
	}

	clc.clientNum = MSG_ReadLong(msg);
	// read the checksum feed
	clc.checksumFeed = MSG_ReadLong( msg );

#ifdef _DONETPROFILE_
	endBytes=msg->readcount;
//	ClReadProf().AddField("svc_gamestate",endBytes-startBytes);
#endif

	// parse serverId and other cvars
	CL_SystemInfoChanged();

	// reinitialize the filesystem if the game directory has changed
	if( FS_ConditionalRestart( clc.checksumFeed ) ) {
		// don't set to true because we yet have to start downloading
		// enabling this can cause double loading of a map when connecting to
		// a server which has a different game directory set
		//clc.downloadRestart = qtrue;
	}

	// This used to call CL_StartHunkUsers, but now we enter the download state before loading the
	// cgame
	CL_InitDownloads();

	// make sure the game starts
	Cvar_Set( "cl_paused", "0" );
}
Example #28
0
void demoConvert( const char *oldName, const char *newBaseName, qboolean smoothen ) {
	fileHandle_t	oldHandle = 0;
	fileHandle_t	newHandle = 0;
	int				temp;
	int				oldSize;
	int				msgSequence;
	msg_t			oldMsg;
	byte			oldData[ MAX_MSGLEN ];
	int				oldTime, nextTime, fullTime;
	int				clientNum;
	demoFrame_t		*workFrame;
	int				parseEntitiesNum = 0;
	demoConvert_t	*convert;
	char			bigConfigString[BIG_INFO_STRING];
	int				bigConfigNumber;
	const char		*s;
	clSnapshot_t	*oldSnap = 0;
	clSnapshot_t	*newSnap;
	int				levelCount = 0;
	char			newName[MAX_OSPATH];

	oldSize = FS_FOpenFileRead( oldName, &oldHandle, qtrue );
	if (!oldHandle) {
		Com_Printf("Failed to open %s for conversion.", oldName);
		return;
	}
	/* Alloc some memory */
	convert = Z_Malloc( sizeof( demoConvert_t) );
	/* Initialize the first workframe's strings */
	while (oldSize > 0) {
		MSG_Init( &oldMsg, oldData, sizeof( oldData ) );
		/* Read the sequence number */
		if (FS_Read( &convert->messageNum, 4, oldHandle) != 4)
			goto conversionerror;
		convert->messageNum = LittleLong( convert->messageNum );
		oldSize -= 4;
		/* Read the message size */
		if (FS_Read( &oldMsg.cursize,4, oldHandle) != 4)
			goto conversionerror;
		oldSize -= 4;
		oldMsg.cursize = LittleLong( oldMsg.cursize );
		/* Negative size signals end of demo */
		if (oldMsg.cursize < 0)
			break;
		if ( oldMsg.cursize > oldMsg.maxsize ) 
			goto conversionerror;
		/* Read the actual message */
		if (FS_Read( oldMsg.data, oldMsg.cursize, oldHandle ) != oldMsg.cursize)
			goto conversionerror;
		oldSize -= oldMsg.cursize;
		// init the bitstream
		MSG_BeginReading( &oldMsg );
		// Skip the reliable sequence acknowledge number
		MSG_ReadLong( &oldMsg );
		//
		// parse the message
		//
		while ( 1 ) {
			byte cmd;
			if ( oldMsg.readcount > oldMsg.cursize ) {
				Com_Printf ("Demo conversion, read past end of server message.\n");
				goto conversionerror;
			}
            cmd = MSG_ReadByte( &oldMsg );
			if ( cmd == svc_EOF) {
                break;
			}
			workFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES ];
			// other commands
			switch ( cmd ) {
			default:
				Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
				break;			
			case svc_nop:
				break;
			case svc_serverCommand:
				temp = MSG_ReadLong( &oldMsg );
				s = MSG_ReadString( &oldMsg );
				if (temp<=msgSequence)
					break;
//				Com_Printf( " server command %s\n", s );
				msgSequence = temp;
				Cmd_TokenizeString( s );
	
				if ( !Q_stricmp( Cmd_Argv(0), "bcs0" ) ) {
					bigConfigNumber = atoi( Cmd_Argv(1) );
					Q_strncpyz( bigConfigString, Cmd_Argv(2), sizeof( bigConfigString ));
					break;
				}
				if ( !Q_stricmp( Cmd_Argv(0), "bcs1" ) ) {
					Q_strcat( bigConfigString, sizeof( bigConfigString ), Cmd_Argv(2));
					break;
				}
				if ( !Q_stricmp( Cmd_Argv(0), "bcs2" ) ) {
					Q_strcat( bigConfigString, sizeof( bigConfigString ), Cmd_Argv(2));
					demoFrameAddString( &workFrame->string, bigConfigNumber, bigConfigString );
					break;
				}
				if ( !Q_stricmp( Cmd_Argv(0), "cs" ) ) {
					int num = atoi( Cmd_Argv(1) );
					s = Cmd_ArgsFrom( 2 );
					demoFrameAddString( &workFrame->string, num, Cmd_ArgsFrom( 2 ) );
					break;
				}
				if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
					int len = strlen( s ) + 1;
					char *dst;
					if (workFrame->commandUsed + len + 1 > sizeof( workFrame->commandData)) {
						Com_Printf("Overflowed state command data.\n");
						goto conversionerror;
					}
					dst = workFrame->commandData + workFrame->commandUsed;
					*dst = clientNum;
					Com_Memcpy( dst+1, s, len );
					workFrame->commandUsed += len + 1;
				}
				break;
			case svc_gamestate:
				if (newHandle) {
					FS_FCloseFile( newHandle );
					newHandle = 0;
				}
				if (levelCount) {
					Com_sprintf( newName, sizeof( newName ), "%s.%d.mme", newBaseName, levelCount );
				} else {
					Com_sprintf( newName, sizeof( newName ), "%s.mme", newBaseName );
				}
				fullTime = -1;
				clientNum = -1;
				oldTime = -1;
				Com_Memset( convert, 0, sizeof( *convert ));
				convert->frames[0].string.used = 1;
				levelCount++;
				newHandle = FS_FOpenFileWrite( newName );
				if (!newHandle) {
					Com_Printf("Failed to open %s for target conversion target.\n", newName);
					goto conversionerror;
					return;
				} else {
					FS_Write ( demoHeader, strlen( demoHeader ), newHandle );
				}
				Com_sprintf( newName, sizeof( newName ), "%s.txt", newBaseName );
				workFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES ];
				msgSequence = MSG_ReadLong( &oldMsg );
				while( 1 ) {
					cmd = MSG_ReadByte( &oldMsg );
					if (cmd == svc_EOF)
						break;
					if ( cmd == svc_configstring) {
						int		num;
						const char *s;
						num = MSG_ReadShort( &oldMsg );
						s = MSG_ReadBigString( &oldMsg );
						demoFrameAddString( &workFrame->string, num, s );
					} else if ( cmd == svc_baseline ) {
						int num = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS );
						if ( num < 0 || num >= MAX_GENTITIES ) {
							Com_Printf( "Baseline number out of range: %i.\n", num );
							goto conversionerror;
						}
						MSG_ReadDeltaEntity( &oldMsg, &demoNullEntityState, &convert->entityBaselines[num], num );
					} else {
						Com_Printf( "Unknown block while converting demo gamestate.\n" );
						goto conversionerror;
					}
				}
				clientNum = MSG_ReadLong( &oldMsg );
				/* Skip the checksum feed */
				MSG_ReadLong( &oldMsg );
				break;
			case svc_snapshot:
				nextTime = MSG_ReadLong( &oldMsg );
				/* Delta number, not needed */
				newSnap = &convert->snapshots[convert->messageNum & PACKET_MASK];
				Com_Memset (newSnap, 0, sizeof(*newSnap));
				newSnap->deltaNum = MSG_ReadByte( &oldMsg );
				newSnap->messageNum = convert->messageNum;
				if (!newSnap->deltaNum) {
					newSnap->deltaNum = -1;
					newSnap->valid = qtrue;		// uncompressed frame
					oldSnap  = NULL;
				} else {
					newSnap->deltaNum = newSnap->messageNum - newSnap->deltaNum;
					oldSnap = &convert->snapshots[newSnap->deltaNum & PACKET_MASK];
					if (!oldSnap->valid) {
						Com_Printf( "Delta snapshot without base.\n" );
						goto conversionerror;
					} else if (oldSnap->messageNum != newSnap->deltaNum) {
						// The frame that the server did the delta from
						// is too old, so we can't reconstruct it properly.
						Com_Printf ("Delta frame too old.\n");
					} else if ( parseEntitiesNum - oldSnap->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) {
						Com_Printf ("Delta parseEntitiesNum too old.\n");
					} else {
						newSnap->valid = qtrue;	// valid delta parse
					}
				}

				/* Snapflags, not needed */
				newSnap->snapFlags = MSG_ReadByte( &oldMsg );
				// read areamask
				workFrame->areaUsed = MSG_ReadByte( &oldMsg );
				MSG_ReadData( &oldMsg, workFrame->areamask, workFrame->areaUsed );
				if (clientNum <0 || clientNum >= MAX_CLIENTS) {
					Com_Printf("Got snapshot with invalid client.\n");
					goto conversionerror;
				}
				MSG_ReadDeltaPlayerstate( &oldMsg, oldSnap ? &oldSnap->ps : &demoNullPlayerState, &newSnap->ps );
				/* Read the individual entities */
				newSnap->parseEntitiesNum = parseEntitiesNum;
				newSnap->numEntities = 0;
				Com_Memset( workFrame->entityData, 0, sizeof( workFrame->entityData ));

				/* The beast that is entity parsing */
				{
				int			newnum;
				entityState_t	*oldstate, *newstate;
				int			oldindex = 0;
				int			oldnum;
				newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS );
				while ( 1 ) {
					// read the entity index number
					if (oldSnap && oldindex < oldSnap->numEntities) {
						oldstate = &convert->parseEntities[(oldSnap->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
						oldnum = oldstate->number;
					} else {
						oldstate = 0;
						oldnum = 99999;
					}
					newstate = &convert->parseEntities[parseEntitiesNum];
					if ( !oldstate && (newnum == (MAX_GENTITIES-1))) {
						break;
					} else if ( oldnum < newnum ) {
						*newstate = *oldstate;
						oldindex++;
					} else if (oldnum == newnum) {
						oldindex++;
						MSG_ReadDeltaEntity( &oldMsg, oldstate, newstate, newnum );
						if ( newstate->number != MAX_GENTITIES-1)
							workFrame->entityData[ newstate->number ] = 1;
						newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS );
					} else if (oldnum > newnum) {
						MSG_ReadDeltaEntity( &oldMsg, &convert->entityBaselines[newnum], newstate , newnum );
						if ( newstate->number != MAX_GENTITIES-1)
							workFrame->entityData[ newstate->number ] = 1;
						newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS );
					}
					if (newstate->number == MAX_GENTITIES-1)
						continue;
					parseEntitiesNum++;
					parseEntitiesNum &= (MAX_PARSE_ENTITIES-1);
					newSnap->numEntities++;
				}}
				/* Stop processing this further since it's an invalid snap due to lack of delta data */
				if (!newSnap->valid)
					break;

				/* Skipped snapshots will be set invalid in the circular buffer */
				if ( newSnap->messageNum - convert->lastMessageNum >= PACKET_BACKUP ) {
					convert->lastMessageNum = newSnap->messageNum - ( PACKET_BACKUP - 1 );
				}
				for ( ; convert->lastMessageNum < newSnap->messageNum ; convert->lastMessageNum++ ) {
					convert->snapshots[convert->lastMessageNum & PACKET_MASK].valid = qfalse;
				}
				convert->lastMessageNum = newSnap->messageNum + 1;

				/* compress the frame into the new format */
				if (nextTime > oldTime) {
					demoFrame_t *cleanFrame;
					int writeIndex;
					for (temp = 0;temp<newSnap->numEntities;temp++) {
						int p = (newSnap->parseEntitiesNum+temp) & (MAX_PARSE_ENTITIES-1);
						entityState_t *newState = &convert->parseEntities[p];
						workFrame->entities[newState->number] = *newState;
					}
					workFrame->clientData[clientNum] = 1;
					workFrame->clients[clientNum] = newSnap->ps;
					workFrame->serverTime = nextTime;

					/* Which frame from the cache to save */
					writeIndex = convert->frameIndex - (DEMOCONVERTFRAMES/2);
					if (writeIndex >= 0) {
						const demoFrame_t *newFrame;
						msg_t writeMsg;
						// init the message
						MSG_Init( &writeMsg, demoBuffer, sizeof (demoBuffer));
						MSG_Clear( &writeMsg );
						MSG_Bitstream( &writeMsg );
						newFrame = &convert->frames[ writeIndex  % DEMOCONVERTFRAMES];
						if ( smoothen )
							demoFrameInterpolate( convert->frames, DEMOCONVERTFRAMES, writeIndex );
						if ( nextTime > fullTime || writeIndex <= 0 ) {
							/* Plan the next time for a full write */
							fullTime = nextTime + 2000;
							demoFramePack( &writeMsg, newFrame, 0 );
						} else {
							const demoFrame_t *oldFrame = &convert->frames[ ( writeIndex -1 ) % DEMOCONVERTFRAMES];
							demoFramePack( &writeMsg, newFrame, oldFrame );
						}
						/* Write away the new data in the msg queue */
						temp = LittleLong( writeMsg.cursize );
						FS_Write (&temp, 4, newHandle );
						FS_Write ( writeMsg.data , writeMsg.cursize, newHandle );
					}

					/* Clean up the upcoming frame for all new changes */
					convert->frameIndex++;
					cleanFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES];
					cleanFrame->serverTime = 0;
					for (temp = 0;temp<MAX_GENTITIES;temp++)
						cleanFrame->entities[temp].number = MAX_GENTITIES-1;
					Com_Memset( cleanFrame->clientData, 0, sizeof ( cleanFrame->clientData ));
					Com_Memcpy( cleanFrame->string.data, workFrame->string.data, workFrame->string.used );
					Com_Memcpy( cleanFrame->string.offsets, workFrame->string.offsets, sizeof( workFrame->string.offsets ));
					cleanFrame->string.used = workFrame->string.used;
					cleanFrame->commandUsed = 0;
					/* keep track of this last frame's time */
					oldTime = nextTime;
				}
				break;
			case svc_download:
				// read block number
				temp = MSG_ReadShort ( &oldMsg );
				if (!temp)	//0 block, read file size
					MSG_ReadLong( &oldMsg );
				// read block size
				temp = MSG_ReadShort ( &oldMsg );
				// read the data block
				for ( ;temp>0;temp--)
					MSG_ReadByte( &oldMsg );
				break;
			}
		}
	}
conversionerror:
	FS_FCloseFile( oldHandle );
	FS_FCloseFile( newHandle );
	Z_Free( convert );
	return;
}
Example #29
0
/*
================
CL_ParseSnapshot

If the snapshot is parsed properly, it will be copied to
cl.snap and saved in cl.snapshots[].  If the snapshot is invalid
for any reason, no changes to the state will be made at all.
================
*/
void CL_ParseSnapshot( msg_t *msg ) {
	int			len;
	clSnapshot_t	*old;
	clSnapshot_t	newSnap;
	int			deltaNum;
	int			oldMessageNum;
	int			i, packetNum;

	// get the reliable sequence acknowledge number
	// NOTE: now sent with all server to client messages
	//clc.reliableAcknowledge = MSG_ReadLong( msg );

	// read in the new snapshot to a temporary buffer
	// we will only copy to cl.snap if it is valid
	Com_Memset (&newSnap, 0, sizeof(newSnap));

	// we will have read any new server commands in this
	// message before we got to svc_snapshot
	newSnap.serverCommandNum = clc.serverCommandSequence;

	newSnap.serverTime = MSG_ReadLong( msg );

	// if we were just unpaused, we can only *now* really let the
	// change come into effect or the client hangs.
	cl_paused->modified = qfalse;

	newSnap.messageNum = clc.serverMessageSequence;

	deltaNum = MSG_ReadByte( msg );
	if ( !deltaNum ) {
		newSnap.deltaNum = -1;
	} else {
		newSnap.deltaNum = newSnap.messageNum - deltaNum;
	}
	newSnap.snapFlags = MSG_ReadByte( msg );

	// If the frame is delta compressed from data that we
	// no longer have available, we must suck up the rest of
	// the frame, but not use it, then ask for a non-compressed
	// message 
	if ( newSnap.deltaNum <= 0 ) {
		newSnap.valid = qtrue;		// uncompressed frame
		old = NULL;
		clc.demowaiting = qfalse;	// we can start recording now
	} else {
		old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK];
		if ( !old->valid ) {
			// should never happen
			Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
		} else if ( old->messageNum != newSnap.deltaNum ) {
			// The frame that the server did the delta from
			// is too old, so we can't reconstruct it properly.
			Com_Printf ("Delta frame too old.\n");
		} else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) {
			Com_DPrintf ("Delta parseEntitiesNum too old.\n");
		} else {
			newSnap.valid = qtrue;	// valid delta parse
		}
	}

	// read areamask
	len = MSG_ReadByte( msg );

	if((unsigned)len > sizeof(newSnap.areamask))
	{
		Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask", len);
		return;
	}

	MSG_ReadData( msg, &newSnap.areamask, len);

	// read playerinfo
	SHOWNET( msg, "playerstate" );
	if ( old ) {
		MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
		if (newSnap.ps.m_iVehicleNum)
		{ //this means we must have written our vehicle's ps too
			MSG_ReadDeltaPlayerstate( msg, &old->vps, &newSnap.vps, qtrue );
		}
	} else {
		MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
		if (newSnap.ps.m_iVehicleNum)
		{ //this means we must have written our vehicle's ps too
			MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.vps, qtrue );			
		}
	}

	// read packet entities
	SHOWNET( msg, "packet entities" );
	CL_ParsePacketEntities( msg, old, &newSnap );

	// if not valid, dump the entire thing now that it has
	// been properly read
	if ( !newSnap.valid ) {
		return;
	}

	// clear the valid flags of any snapshots between the last
	// received and this one, so if there was a dropped packet
	// it won't look like something valid to delta from next
	// time we wrap around in the buffer
	oldMessageNum = cl.snap.messageNum + 1;

	if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) {
		oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );
	}
	for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
		cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse;
	}

	// copy to the current good spot
	cl.snap = newSnap;
	cl.snap.ping = 999;
	// calculate ping time
	for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
		packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
		if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) {
			cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;
			break;
		}
	}
	// save the frame off in the backup array for later delta comparisons
	cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap;

	if (cl_shownet->integer == 3) {
		Com_Printf( "   snapshot:%i  delta:%i  ping:%i\n", cl.snap.messageNum,
		cl.snap.deltaNum, cl.snap.ping );
	}

	cl.newSnapshots = qtrue;
}
Example #30
0
/*
==============
CL_ParseMuzzleFlash
==============
*/
void CL_ParseMuzzleFlash(void){
	vec3_t	fv, rv;
	cdlight_t	*dl;
	int	i, weapon;
	centity_t	*pl;
	int	silenced;
	float	volume;
	char	soundname[64];
	
	i = MSG_ReadShort(&net_message);
	if(i < 1 || i >= MAX_EDICTS)
		Com_Error(ERR_DROP, "CL_ParseMuzzleFlash: bad entity");
		
	weapon = MSG_ReadByte(&net_message);
	silenced = weapon & MZ_SILENCED;
	weapon &= ~MZ_SILENCED;
	
	pl = &cl_entities[i];
	
	dl = CL_AllocDlight(i);
	VectorCopy(pl->current.origin, dl->origin);
	AngleVectors(pl->current.angles, fv, rv, NULL);
	VectorMA(dl->origin, 18, fv, dl->origin);
	VectorMA(dl->origin, 16, rv, dl->origin);
	if(silenced)
		dl->radius = 100 +(rand() & 31);
	else
		dl->radius = 200 +(rand() & 31);
	dl->minlight = 32;
	dl->die = cl.time; // + 0.1;
	
	if(silenced)
		volume = 0.2;
	else
		volume = 1;
		
	switch(weapon){
		case MZ_BLASTER:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
			break;
		case MZ_BLUEHYPERBLASTER:
			dl->color[0] = 0;
			dl->color[1] = 0;
			dl->color[2] = 1;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
			break;
		case MZ_HYPERBLASTER:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
			break;
		case MZ_MACHINEGUN:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav",(rand() % 5) + 1);
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
			break;
		case MZ_SHOTGUN:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0);
			S_StartSound(NULL, i, CHAN_AUTO, S_RegisterSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1);
			break;
		case MZ_SSHOTGUN:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0);
			break;
		case MZ_CHAINGUN1:
			dl->radius = 200 +(rand() & 31);
			dl->color[0] = 1;
			dl->color[1] = 0.25;
			dl->color[2] = 0;
			Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav",(rand() % 5) + 1);
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
			break;
		case MZ_CHAINGUN2:
			dl->radius = 225 +(rand() & 31);
			dl->color[0] = 1;
			dl->color[1] = 0.5;
			dl->color[2] = 0;
			dl->die = cl.time + 0.1;	// long delay
			Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav",(rand() % 5) + 1);
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
			Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav",(rand() % 5) + 1);
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.05);
			break;
		case MZ_CHAINGUN3:
			dl->radius = 250 +(rand() & 31);
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			dl->die = cl.time + 0.1;	// long delay
			Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav",(rand() % 5) + 1);
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0);
			Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav",(rand() % 5) + 1);
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.033);
			Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav",(rand() % 5) + 1);
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.066);
			break;
		case MZ_RAILGUN:
			dl->color[0] = 0.5;
			dl->color[1] = 0.5;
			dl->color[2] = 1.0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0);
			break;
		case MZ_ROCKET:
			dl->color[0] = 1;
			dl->color[1] = 0.5;
			dl->color[2] = 0.2;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0);
			S_StartSound(NULL, i, CHAN_AUTO, S_RegisterSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1);
			break;
		case MZ_GRENADE:
			dl->color[0] = 1;
			dl->color[1] = 0.5;
			dl->color[2] = 0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0);
			S_StartSound(NULL, i, CHAN_AUTO, S_RegisterSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1);
			break;
		case MZ_BFG:
			dl->color[0] = 0;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0);
			break;
			
		case MZ_LOGIN:
			dl->color[0] = 0;
			dl->color[1] = 1;
			dl->color[2] = 0;
			dl->die = cl.time + 1.0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
			CL_LogoutEffect(pl->current.origin, weapon);
			break;
		case MZ_LOGOUT:
			dl->color[0] = 1;
			dl->color[1] = 0;
			dl->color[2] = 0;
			dl->die = cl.time + 1.0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
			CL_LogoutEffect(pl->current.origin, weapon);
			break;
		case MZ_RESPAWN:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			dl->die = cl.time + 1.0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
			CL_LogoutEffect(pl->current.origin, weapon);
			break;
			// RAFAEL
		case MZ_PHALANX:
			dl->color[0] = 1;
			dl->color[1] = 0.5;
			dl->color[2] = 0.5;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0);
			break;
			// RAFAEL
		case MZ_IONRIPPER:
			dl->color[0] = 1;
			dl->color[1] = 0.5;
			dl->color[2] = 0.5;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0);
			break;
			
			// ======================
			// PGM
		case MZ_ETF_RIFLE:
			dl->color[0] = 0.9;
			dl->color[1] = 0.7;
			dl->color[2] = 0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0);
			break;
		case MZ_SHOTGUN2:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0);
			break;
		case MZ_HEATBEAM:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			dl->die = cl.time + 100;
			//		S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0);
			break;
		case MZ_BLASTER2:
			dl->color[0] = 0;
			dl->color[1] = 1;
			dl->color[2] = 0;
			// FIXME - different sound for blaster2 ??
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
			break;
		case MZ_TRACKER:
			// negative flashes handled the same in gl/soft until CL_AddDLights
			dl->color[0] = -1;
			dl->color[1] = -1;
			dl->color[2] = -1;
			S_StartSound(NULL, i, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), volume, ATTN_NORM, 0);
			break;
		case MZ_NUKE1:
			dl->color[0] = 1;
			dl->color[1] = 0;
			dl->color[2] = 0;
			dl->die = cl.time + 100;
			break;
		case MZ_NUKE2:
			dl->color[0] = 1;
			dl->color[1] = 1;
			dl->color[2] = 0;
			dl->die = cl.time + 100;
			break;
		case MZ_NUKE4:
			dl->color[0] = 0;
			dl->color[1] = 0;
			dl->color[2] = 1;
			dl->die = cl.time + 100;
			break;
		case MZ_NUKE8:
			dl->color[0] = 0;
			dl->color[1] = 1;
			dl->color[2] = 1;
			dl->die = cl.time + 100;
			break;
			// PGM
			// ======================
	}
}