Beispiel #1
0
void ClientReliableWrite_Float(client_t *cl, float f)
{
	if (cl->num_backbuf) {
		MSG_WriteFloat(&cl->backbuf, f);
		ClientReliable_FinishWrite(cl);
	} else
		MSG_WriteFloat(&cl->netchan.message, f);
}
Beispiel #2
0
// 2000-04-30 NVS HANDSHAKE SRV<->CL/QC<->CL by Maddes
void Host_NVS_Request_f (void)
{
	float	value;

	if (cmd_source == src_command)	// this a client remote only command
	{
		Con_Printf("%s is not valid from the console\n", Cmd_Argv(0));
		return;
	}

	if (Cmd_Argc() < 2)		// not enough arguments
	{
		SV_ClientPrintf("%s: not enough arguments\n", Cmd_Argv(0));
		SV_ClientPrintf("Syntax: %s <version>\n", Cmd_Argv(0));
		return;
	}

	Con_DPrintf("Server received NVS client version %s from client %i\n", Cmd_Argv(1), NUM_FOR_EDICT(host_client->edict));

// 2001-12-24 Keeping full backwards compatibility by Maddes  start
	if (sv_compatibility->value)	// do not reply, like the original Quake executable
	{
		return;
	}
// 2001-12-24 Keeping full backwards compatibility by Maddes  end

	// get and check value
	value = Q_atof(Cmd_Argv(1));
	if (value < 0)
	{
		SV_ClientPrintf ("Only positive NVS versions are accepted.\n");
		return;
	}

	// determine and store client NVS versions
	host_client->nvs_cmax = value;
	host_client->nvs_cclc = (value < MAX_NVS_VERSION) ? value : MAX_NVS_VERSION;
	host_client->nvs_csvc = (value < nvs_current_ssvc->value) ? value : nvs_current_ssvc->value;

	// check client against required version
	if (NVS_RejectClient())
	{
		return;
	}

	// tell client the NVS versions, only when necessary or when client changes during a running game
	// NECESSARY (GOOD) HACK: This is a special case were not the client's SVC is of importance
	if (host_client->nvs_cclc || nvs_current_ssvc->value || host_client->spawned)
	{
		MSG_WriteByte (&host_client->message, svc_extra_version);
		MSG_WriteByte (&host_client->message, VERSION_NVS);
		MSG_WriteFloat (&host_client->message, nvs_current_ssvc->value);
		MSG_WriteFloat (&host_client->message, host_client->nvs_csvc);
		MSG_WriteFloat (&host_client->message, host_client->nvs_cclc);

		Con_DPrintf("Server sends NVS versions SSVC %1.2f CSVC %1.2f CCLC %1.2f to client %i\n", nvs_current_ssvc->value, host_client->nvs_csvc, host_client->nvs_cclc, NUM_FOR_EDICT(host_client->edict));
	}
}
Beispiel #3
0
// 2000-05-02 NVS SVC by Maddes
void NVS_WriteFloat (int dest, float f, sizebuf_t *sb)
{
	int	i;

	switch (dest)
	{
	case MSG_INIT:
		if (sv.nvs_msgsignon->conversion_tab[sv.nvs_msgserver->numwrites-sv.nvs_msgwrites])
		{
			if (sb)				// special signon
			{
				MSG_WriteFloat(sb, f);
			}
			else
			{
				MSG_WriteFloat (&sv.signon, f);
			}
		}
		break;

	case MSG_ONE:
	case MSG_ALL:
	case MSG_BROADCAST:
		for (i=0 ; i<svs.maxclients ; i++)
		{
			if (NVS_CheckClient(&svs.clients[i]))
			{
				if (dest == MSG_BROADCAST)	// unreliable
				{
					MSG_WriteFloat (&svs.clients[i].datagram, f);
				}
				else if (dest == MSG_ONE && sb)	// special reliable MSG_ONE
				{
					MSG_WriteFloat (sb, f);
				}
				else				// reliable MSG_ONE, MSG_ALL
				{
					MSG_WriteFloat (&svs.clients[i].message, f);
				}
			}
		}
		break;

	default:
		Host_Error ("NVS_WriteFloat: bad destination");
		break;
	}

	NVS_CheckCounter();
}
void SV_FullClientUpdate (client_t *client, sizebuf_t *buf)
{
	int		i;
	char	info[MAX_INFO_STRING];

//	Con_Printf("%s\n", __thisfunc__);
	i = client - svs.clients;

//	Sys_Printf("%s:  Updated frags for client %d\n", __thisfunc__, i);

	MSG_WriteByte (buf, svc_updatedminfo);
	MSG_WriteByte (buf, i);
	MSG_WriteShort (buf, client->old_frags);
	MSG_WriteByte (buf, (client->playerclass<<5)|((int)client->edict->v.level&31));

	if (dmMode.integer == DM_SIEGE)
	{
		MSG_WriteByte (buf, svc_updatesiegeinfo);
		MSG_WriteByte (buf, (int)ceil(timelimit.value));
		MSG_WriteByte (buf, (int)ceil(fraglimit.value));

		MSG_WriteByte (buf, svc_updatesiegeteam);
		MSG_WriteByte (buf, i);
		MSG_WriteByte (buf, client->siege_team);

		MSG_WriteByte (buf, svc_updatesiegelosses);
		MSG_WriteByte (buf, PR_GLOBAL_STRUCT(defLosses));
		MSG_WriteByte (buf, PR_GLOBAL_STRUCT(attLosses));

		MSG_WriteByte (buf, svc_time);//send server time upon connection
		MSG_WriteFloat (buf, sv.time);
	}

	MSG_WriteByte (buf, svc_updateping);
	MSG_WriteByte (buf, i);
	MSG_WriteShort (buf, SV_CalcPing (client));

	MSG_WriteByte (buf, svc_updateentertime);
	MSG_WriteByte (buf, i);
	MSG_WriteFloat (buf, realtime - client->connection_started);

	strcpy (info, client->userinfo);
	Info_RemovePrefixedKeys (info, '_');	// server passwords, etc

	MSG_WriteByte (buf, svc_updateuserinfo);
	MSG_WriteByte (buf, i);
	MSG_WriteLong (buf, client->userid);
	MSG_WriteString (buf, info);
}
void Particle(MathVector3f_t org, MathVector3f_t dir,float scale,char *texture,int count)
{
	int	i,v;

	if(sv.datagram.cursize > MAX_DATAGRAM-16)
		return;

	MSG_WriteByte(&sv.datagram,SVC_PARTICLE);

	for(i = 0; i < 3; i++)
		MSG_WriteCoord(&sv.datagram,org[i]);

	for(i=0 ; i<3 ; i++)
	{
		v = dir[i]*16;
		if (v > 127)
			v = 127;
		else if (v < -128)
			v = -128;

		MSG_WriteChar(&sv.datagram,v);
	}

	MSG_WriteFloat(&sv.datagram,scale);

	for(i = 0; i < MAX_EFFECTS; i++)
		if(gEffectTexture[i])
		{
			if(!strcmp(texture,gEffectTexture[i]->name))
			{
				MSG_WriteByte(&sv.datagram,i);
				break;
			}
		}
		else
		{
			// Otherwise give the texture the initial slot (this points to the notexture).
			MSG_WriteByte(&sv.datagram,0);
			break;
		}

	MSG_WriteByte(&sv.datagram,count);
}
Beispiel #6
0
/*
===================
SV_FullClientUpdate

Writes all update values to a sizebuf
===================
*/
void SV_FullClientUpdate (client_t *client, sizebuf_t *buf)
{
	int		i;
	char	info[MAX_INFO_STRING];

	i = client - svs.clients;

	if (client->state == cs_free && sv_fastconnect.value)
		return;

	MSG_WriteByte (buf, svc_updatefrags);
	MSG_WriteByte (buf, i);
	MSG_WriteShort (buf, client->old_frags);
	
	MSG_WriteByte (buf, svc_updateping);
	MSG_WriteByte (buf, i);
	MSG_WriteShort (buf, SV_CalcPing (client));
	
	MSG_WriteByte (buf, svc_updatepl);
	MSG_WriteByte (buf, i);
	MSG_WriteByte (buf, client->lossage);
	
	MSG_WriteByte (buf, svc_updateentertime);
	MSG_WriteByte (buf, i);
	MSG_WriteFloat (buf, svs.realtime - client->connection_started);

	strcpy (info, client->userinfo);
	Info_RemovePrefixedKeys (info, '_');	// server passwords, etc
	Info_RemoveKey (info, "pmodel");
	Info_RemoveKey (info, "emodel");

	MSG_WriteByte (buf, svc_updateuserinfo);
	MSG_WriteByte (buf, i);
	MSG_WriteLong (buf, client->userid);
	MSG_WriteString (buf, info);
}
Beispiel #7
0
// All changes need to be in SV_SendEffect(), SV_ParseEffect(),
// SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect()
void SV_SendEffect(sizebuf_t *sb, int index)
{
	qboolean	DoTest;
	vec3_t		TestO;
	int			TestDistance;
	int			i;

	if (sv_ce_scale.value > 0)
		DoTest = true;
	else
		DoTest = false;

	VectorCopy(vec3_origin, TestO);

	switch(sv.Effects[index].type)
	{
		case CE_HWSHEEPINATOR:
		case CE_HWXBOWSHOOT:
			VectorCopy(sv.Effects[index].Xbow.origin[5], TestO);
			TestDistance = 900;
			break;
		case CE_SCARABCHAIN:
			VectorCopy(sv.Effects[index].Chain.origin, TestO);
			TestDistance = 900;
			break;

		case CE_TRIPMINE:
			VectorCopy(sv.Effects[index].Chain.origin, TestO);
//			DoTest = false;
			break;

			//ACHTUNG!!!!!!! setting DoTest to false here does not insure that effect will be sent to everyone!
		case CE_TRIPMINESTILL:
			TestDistance = 10000;
			DoTest = false;
			break;

		case CE_RAIN:
			TestDistance = 10000;
			DoTest = false;
			break;

		case CE_FOUNTAIN:
			TestDistance = 10000;
			DoTest = false;
			break;

		case CE_QUAKE:
			VectorCopy(sv.Effects[index].Quake.origin, TestO);
			TestDistance = 700;
			break;

		case CE_WHITE_SMOKE:
		case CE_GREEN_SMOKE:
		case CE_GREY_SMOKE:
		case CE_RED_SMOKE:
		case CE_SLOW_WHITE_SMOKE:
		case CE_TELESMK1:
		case CE_TELESMK2:
		case CE_GHOST:
		case CE_REDCLOUD:
		case CE_FLAMESTREAM:
		case CE_ACID_MUZZFL:
		case CE_FLAMEWALL:
		case CE_FLAMEWALL2:
		case CE_ONFIRE:
		case CE_RIPPLE:
			VectorCopy(sv.Effects[index].Smoke.origin, TestO);
			TestDistance = 250;
			break;

		case CE_SM_WHITE_FLASH:
		case CE_YELLOWRED_FLASH:
		case CE_BLUESPARK:
		case CE_YELLOWSPARK:
		case CE_SM_CIRCLE_EXP:
		case CE_BG_CIRCLE_EXP:
		case CE_SM_EXPLOSION:
		case CE_SM_EXPLOSION2:
		case CE_BG_EXPLOSION:
		case CE_FLOOR_EXPLOSION:
		case CE_BLUE_EXPLOSION:
		case CE_REDSPARK:
		case CE_GREENSPARK:
		case CE_ICEHIT:
		case CE_MEDUSA_HIT:
		case CE_MEZZO_REFLECT:
		case CE_FLOOR_EXPLOSION2:
		case CE_XBOW_EXPLOSION:
		case CE_NEW_EXPLOSION:
		case CE_MAGIC_MISSILE_EXPLOSION:
		case CE_BONE_EXPLOSION:
		case CE_BLDRN_EXPL:
		case CE_ACID_HIT:
		case CE_LBALL_EXPL:
		case CE_FIREWALL_SMALL:
		case CE_FIREWALL_MEDIUM:
		case CE_FIREWALL_LARGE:
		case CE_ACID_SPLAT:
		case CE_ACID_EXPL:
		case CE_FBOOM:
		case CE_BRN_BOUNCE:
		case CE_LSHOCK:
		case CE_BOMB:
		case CE_FLOOR_EXPLOSION3:
			VectorCopy(sv.Effects[index].Smoke.origin, TestO);
			TestDistance = 250;
			break;

		case CE_WHITE_FLASH:
		case CE_BLUE_FLASH:
		case CE_SM_BLUE_FLASH:
		case CE_HWSPLITFLASH:
		case CE_RED_FLASH:
			VectorCopy(sv.Effects[index].Smoke.origin, TestO);
			TestDistance = 250;
			break;


		case CE_RIDER_DEATH:
			DoTest = false;
			break;

		case CE_TELEPORTERPUFFS:
			VectorCopy(sv.Effects[index].Teleporter.origin, TestO);
			TestDistance = 350;
			break;

		case CE_TELEPORTERBODY:
			VectorCopy(sv.Effects[index].Teleporter.origin, TestO);
			TestDistance = 350;
			break;

		case CE_DEATHBUBBLES:
			if (sv.Effects[index].Bubble.owner < 0 || sv.Effects[index].Bubble.owner >= sv.num_edicts)
			{
				return;
			}
			VectorCopy(PROG_TO_EDICT(sv.Effects[index].Bubble.owner)->v.origin, TestO);
			TestDistance = 400;
			break;

		case CE_HWDRILLA:
		case CE_BONESHARD:
		case CE_BONESHRAPNEL:
		case CE_HWBONEBALL:
		case CE_HWRAVENSTAFF:
		case CE_HWRAVENPOWER:

			VectorCopy(sv.Effects[index].Missile.origin, TestO);
			TestDistance = 900;
			break;

		case CE_HWMISSILESTAR:
		case CE_HWEIDOLONSTAR:
			VectorCopy(sv.Effects[index].Missile.origin, TestO);
			TestDistance = 600;
			break;
		default:
//			Sys_Error ("SV_SendEffect: bad type");
			PR_RunError ("SV_SendEffect: bad type");
			break;
	}

	MSG_WriteByte (&sv.multicast, svc_start_effect);
	MSG_WriteByte (&sv.multicast, index);
	MSG_WriteByte (&sv.multicast, sv.Effects[index].type);

	switch(sv.Effects[index].type)
	{
		case CE_RAIN:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[2]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[2]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[2]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[2]);
			MSG_WriteShort(&sv.multicast, sv.Effects[index].Rain.color);
			MSG_WriteShort(&sv.multicast, sv.Effects[index].Rain.count);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Rain.wait);
			break;

		case CE_FOUNTAIN:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[2]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[0]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[1]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[2]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[2]);
			MSG_WriteShort(&sv.multicast, sv.Effects[index].Fountain.color);
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Fountain.cnt);
			break;

		case CE_QUAKE:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Quake.radius);
			break;

		case CE_WHITE_SMOKE:
		case CE_GREEN_SMOKE:
		case CE_GREY_SMOKE:
		case CE_RED_SMOKE:
		case CE_SLOW_WHITE_SMOKE:
		case CE_TELESMK1:
		case CE_TELESMK2:
		case CE_GHOST:
		case CE_REDCLOUD:
		case CE_FLAMESTREAM:
		case CE_ACID_MUZZFL:
		case CE_FLAMEWALL:
		case CE_FLAMEWALL2:
		case CE_ONFIRE:
		case CE_RIPPLE:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.framelength);
			break;

		case CE_SM_WHITE_FLASH:
		case CE_YELLOWRED_FLASH:
		case CE_BLUESPARK:
		case CE_YELLOWSPARK:
		case CE_SM_CIRCLE_EXP:
		case CE_BG_CIRCLE_EXP:
		case CE_SM_EXPLOSION:
		case CE_SM_EXPLOSION2:
		case CE_BG_EXPLOSION:
		case CE_FLOOR_EXPLOSION:
		case CE_BLUE_EXPLOSION:
		case CE_REDSPARK:
		case CE_GREENSPARK:
		case CE_ICEHIT:
		case CE_MEDUSA_HIT:
		case CE_MEZZO_REFLECT:
		case CE_FLOOR_EXPLOSION2:
		case CE_XBOW_EXPLOSION:
		case CE_NEW_EXPLOSION:
		case CE_MAGIC_MISSILE_EXPLOSION:
		case CE_BONE_EXPLOSION:
		case CE_BLDRN_EXPL:
		case CE_ACID_HIT:
		case CE_ACID_SPLAT:
		case CE_ACID_EXPL:
		case CE_LBALL_EXPL:	
		case CE_FIREWALL_SMALL:
		case CE_FIREWALL_MEDIUM:
		case CE_FIREWALL_LARGE:
		case CE_FBOOM:
		case CE_BOMB:
		case CE_BRN_BOUNCE:
		case CE_LSHOCK:

			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]);
			break;

		case CE_WHITE_FLASH:
		case CE_BLUE_FLASH:
		case CE_SM_BLUE_FLASH:			
		case CE_HWSPLITFLASH:
		case CE_RED_FLASH:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]);
			break;


		case CE_RIDER_DEATH:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[2]);
			break;

		case CE_TELEPORTERPUFFS:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[2]);
			break;

		case CE_TELEPORTERBODY:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.skinnum);
			break;
		case CE_BONESHRAPNEL:
		case CE_HWBONEBALL:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[2]);

			break;
		case CE_BONESHARD:
		case CE_HWRAVENSTAFF:
		case CE_HWMISSILESTAR:
		case CE_HWEIDOLONSTAR:
		case CE_HWRAVENPOWER:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[2]);
			break;
		case CE_HWDRILLA:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[index].Missile.angle[0]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[index].Missile.angle[1]);
			MSG_WriteShort(&sv.multicast, sv.Effects[index].Missile.speed);
			break;
		case CE_DEATHBUBBLES:
			MSG_WriteShort(&sv.multicast, sv.Effects[index].Bubble.owner);
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[0]);
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[1]);
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[2]);
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.count);
			break;
		case CE_SCARABCHAIN:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[2]);
			MSG_WriteShort(&sv.multicast, sv.Effects[index].Chain.owner+sv.Effects[index].Chain.material);
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Chain.tag);
			break;
		case CE_TRIPMINESTILL:
		case CE_TRIPMINE:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[2]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[0]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[1]);
			MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[2]);
			break;
		case CE_HWSHEEPINATOR:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][2]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[0]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[1]);

			//now send the guys that have turned
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.turnedbolts);
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.activebolts);
			for (i=0;i<5;i++)
			{
				if ((1<<i)&sv.Effects[index].Xbow.turnedbolts)
				{
					MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][0]);
					MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][1]);
					MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][2]);
					MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][0]);
					MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][1]);
				}
			}
			break;
		case CE_HWXBOWSHOOT:
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][0]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][1]);
			MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][2]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[0]);
			MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[1]);
//				MSG_WriteFloat(&sv.multicast, sv.Effects[index].Xbow.angle[2]);
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.bolts);
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.randseed);

			//now send the guys that have turned
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.turnedbolts);
			MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.activebolts);
			for (i=0;i<5;i++)
			{
				if ((1<<i)&sv.Effects[index].Xbow.turnedbolts)
				{
					MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][0]);
					MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][1]);
					MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][2]);
					MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][0]);
					MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][1]);
				}
			}
			break;
		default:
//			Sys_Error ("SV_SendEffect: bad type");
			PR_RunError ("SV_SendEffect: bad type");
			break;
	}

	if (sb)
	{
		SZ_Write (sb, sv.multicast.data, sv.multicast.cursize);
		SZ_Clear (&sv.multicast);
	}
	else
	{
		if (DoTest)
		{
			SV_Multicast (TestO, MULTICAST_PVS_R);
		}
		else
		{
			SV_Multicast (TestO, MULTICAST_ALL_R);
		}
		sv.Effects[index].client_list = clients_multicast;
	}
}
Beispiel #8
0
/*
==============
CL_SendMove
==============
*/
void CL_SendMove (usercmd_t *cmd)
{
	int		i;
	int		bits;
	sizebuf_t	buf;
	byte	data[128];
	
	buf.maxsize = 128;
	buf.cursize = 0;
	buf.data = data;
	
	cl.cmd = *cmd;

//
// send the movement message
//
    MSG_WriteByte (&buf, clc_move);

	MSG_WriteFloat (&buf, cl.mtime[0]);	// so server can get ping times

	for (i=0 ; i<3 ; i++)
		MSG_WriteAngle (&buf, cl.viewangles[i]);
	
    MSG_WriteShort (&buf, cmd->forwardmove);
    MSG_WriteShort (&buf, cmd->sidemove);
    MSG_WriteShort (&buf, cmd->upmove);

//
// send button bits
//
	bits = 0;
	
	if ( in_attack.state & 3 )
		bits |= 1;
	in_attack.state &= ~2;
	
	if (in_jump.state & 3)
		bits |= 2;
	in_jump.state &= ~2;
	
    MSG_WriteByte (&buf, bits);

    MSG_WriteByte (&buf, in_impulse);
	in_impulse = 0;

//
// deliver the message
//
	if (cls.demoplayback)
		return;

//
// allways dump the first two message, because it may contain leftover inputs
// from the last level
//
	if (++cl.movemessages <= 2)
		return;
	
	if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)
	{
		Con_Printf ("CL_SendMove: lost server connection\n");
		CL_Disconnect ();
	}
}
Beispiel #9
0
static qbool SV_MVD_Record (mvddest_t *dest)
{
	sizebuf_t	buf;
	byte buf_data[MAX_MSGLEN];
	int n, i;
	char *s, info[MAX_INFO_STRING];
	client_t *player;
	char *gamedir;

	if (!dest)
		return false;

	DestFlush(true);

	if (!sv.mvdrecording)
	{
		memset(&demo, 0, sizeof(demo));
		for (i = 0; i < UPDATE_BACKUP; i++)
		{
			demo.recorder.frames[i] = demo_frames[i];
			demo.recorder.frames[i].entities.entities = demo_entities[i];
		}

		MVDBuffer_Init(&demo.dbuffer, demo.buffer, sizeof(demo.buffer));
		MVDSetMsgBuf(NULL, &demo.frames[0].buf);

		demo.datagram.maxsize = sizeof(demo.datagram_data);
		demo.datagram.data = demo.datagram_data;

		sv.mvdrecording = true;
	}
//	else
//		SV_WriteRecordMVDMessage(&buf);

	demo.pingtime = demo.time = sv.time;

	dest->nextdest = demo.dest;
	demo.dest = dest;

	singledest = dest;

/*-------------------------------------------------*/

// serverdata
	// send the info about the new client to all connected clients
	SZ_Init (&buf, buf_data, sizeof(buf_data));

// send the serverdata

	gamedir = Info_ValueForKey (svs.info, "*gamedir");
	if (!gamedir[0])
		gamedir = "qw";

	MSG_WriteByte (&buf, svc_serverdata);

	MSG_WriteLong (&buf, PROTOCOL_VERSION);
	MSG_WriteLong (&buf, svs.spawncount);
	MSG_WriteString (&buf, gamedir);

	MSG_WriteFloat (&buf, sv.time);

	// send full levelname
	MSG_WriteString (&buf, sv.mapname);

	// send the movevars
	MSG_WriteFloat(&buf, sv.movevars.gravity);
	MSG_WriteFloat(&buf, sv.movevars.stopspeed);
	MSG_WriteFloat(&buf, sv.movevars.maxspeed);
	MSG_WriteFloat(&buf, sv.movevars.spectatormaxspeed);
	MSG_WriteFloat(&buf, sv.movevars.accelerate);
	MSG_WriteFloat(&buf, sv.movevars.airaccelerate);
	MSG_WriteFloat(&buf, sv.movevars.wateraccelerate);
	MSG_WriteFloat(&buf, sv.movevars.friction);
	MSG_WriteFloat(&buf, sv.movevars.waterfriction);
	MSG_WriteFloat(&buf, sv.movevars.entgravity);

	// send music
	MSG_WriteByte (&buf, svc_cdtrack);
	MSG_WriteByte (&buf, 0); // none in demos

	// send server info string
	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", svs.info) );

	// flush packet
	SV_WriteRecordMVDMessage (&buf);
	SZ_Clear (&buf);

// soundlist
	MSG_WriteByte (&buf, svc_soundlist);
	MSG_WriteByte (&buf, 0);

	n = 0;
	s = sv.sound_name[n+1];
	while (s)
	{
		MSG_WriteString (&buf, s);
		if (buf.cursize > MAX_MSGLEN/2)
		{
			MSG_WriteByte (&buf, 0);
			MSG_WriteByte (&buf, n);
			SV_WriteRecordMVDMessage (&buf);
			SZ_Clear (&buf);
			MSG_WriteByte (&buf, svc_soundlist);
			MSG_WriteByte (&buf, n + 1);
		}
		n++;
		s = sv.sound_name[n+1];
	}

	if (buf.cursize)
	{
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, 0);
		SV_WriteRecordMVDMessage (&buf);
		SZ_Clear (&buf);
	}

// modellist
	MSG_WriteByte (&buf, svc_modellist);
	MSG_WriteByte (&buf, 0);

	n = 0;
	s = sv.model_name[n+1];
	while (s)
	{
		MSG_WriteString (&buf, s);
		if (buf.cursize > MAX_MSGLEN/2)
		{
			MSG_WriteByte (&buf, 0);
			MSG_WriteByte (&buf, n);
			SV_WriteRecordMVDMessage (&buf);
			SZ_Clear (&buf);
			MSG_WriteByte (&buf, svc_modellist);
			MSG_WriteByte (&buf, n + 1);
		}
		n++;
		s = sv.model_name[n+1];
	}
	if (buf.cursize)
	{
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, 0);
		SV_WriteRecordMVDMessage (&buf);
		SZ_Clear (&buf);
	}

// baselines
	{
		entity_state_t from;
		edict_t *ent;
		entity_state_t *state;

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

		for (n = 0; n < sv.num_edicts; n++)
		{
			ent = EDICT_NUM(n);
			state = &ent->baseline;

			if (!state->number || !state->modelindex)
			{	//ent doesn't have a baseline
				continue;
			}

			if (!ent)
			{
				MSG_WriteByte(&buf, svc_spawnbaseline);

				MSG_WriteShort (&buf, n);

				MSG_WriteByte (&buf, 0);

				MSG_WriteByte (&buf, 0);
				MSG_WriteByte (&buf, 0);
				MSG_WriteByte (&buf, 0);
				for (i=0 ; i<3 ; i++)
				{
					MSG_WriteCoord(&buf, 0);
					MSG_WriteAngle(&buf, 0);
				}
			}
			else
			{
				MSG_WriteByte(&buf, svc_spawnbaseline);

				MSG_WriteShort (&buf, n);

				MSG_WriteByte (&buf, state->modelindex&255);

				MSG_WriteByte (&buf, state->frame);
				MSG_WriteByte (&buf, (int)state->colormap);
				MSG_WriteByte (&buf, (int)state->skinnum);
				for (i=0 ; i<3 ; i++)
				{
					MSG_WriteCoord(&buf, state->s_origin[i]);
					MSG_WriteAngle(&buf, state->s_angles[i]);
				}
			}
			if (buf.cursize > MAX_MSGLEN/2)
			{
				SV_WriteRecordMVDMessage (&buf);
				SZ_Clear (&buf);
			}
		}
	}

	//prespawn

	for (n = 0; n < sv.num_signon_buffers; n++)
	{
		if (buf.cursize+sv.signon_buffer_size[n] > MAX_MSGLEN/2)
		{
			SV_WriteRecordMVDMessage (&buf);
			SZ_Clear (&buf);
		}
		SZ_Write (&buf, sv.signon_buffers[n], sv.signon_buffer_size[n]);
	}

	if (buf.cursize > MAX_MSGLEN/2)
	{
		SV_WriteRecordMVDMessage (&buf);
		SZ_Clear (&buf);
	}

	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("cmd spawn %i\n",svs.spawncount) );

	if (buf.cursize)
	{
		SV_WriteRecordMVDMessage (&buf);
		SZ_Clear (&buf);
	}

// send current status of all other players

	for (i = 0; i < MAX_CLIENTS; i++)
	{
		player = svs.clients + i;

		MSG_WriteByte (&buf, svc_updatefrags);
		MSG_WriteByte (&buf, i);
		MSG_WriteShort (&buf, player->old_frags);

		MSG_WriteByte (&buf, svc_updateping);
		MSG_WriteByte (&buf, i);
		MSG_WriteShort (&buf, SV_CalcPing(player));

		MSG_WriteByte (&buf, svc_updatepl);
		MSG_WriteByte (&buf, i);
		MSG_WriteByte (&buf, player->lossage);

		MSG_WriteByte (&buf, svc_updateentertime);
		MSG_WriteByte (&buf, i);
		MSG_WriteFloat (&buf, svs.realtime - player->connection_started);

		Q_strncpyz (info, player->userinfo, MAX_INFO_STRING);
		Info_RemovePrefixedKeys (info, '_');	// server passwords, etc

		MSG_WriteByte (&buf, svc_updateuserinfo);
		MSG_WriteByte (&buf, i);
		MSG_WriteLong (&buf, player->userid);
		MSG_WriteString (&buf, info);

		if (buf.cursize > MAX_MSGLEN/2)
		{
			SV_WriteRecordMVDMessage (&buf);
			SZ_Clear (&buf);
		}
	}

// send all current light styles
	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
	{
		MSG_WriteByte (&buf, svc_lightstyle);
		MSG_WriteByte (&buf, (char)i);
		MSG_WriteString (&buf, sv.lightstyles[i]);
	}

	// get the client to check and download skins
	// when that is completed, a begin command will be issued
	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, "skins\n");

	SV_WriteRecordMVDMessage (&buf);

	SV_WriteSetMVDMessage();

	singledest = NULL;

	// done
	return true;
}
Beispiel #10
0
void EXT_FUNC MSG_WriteFloat_api(sizebuf_t *sb, float f) {
	MSG_WriteFloat(sb, f);
}
Beispiel #11
0
void SV_New_f (void)
{
	char		*gamedir;
	int			playernum;

	if (host_client->state == cs_spawned)
		return;

	host_client->state = cs_connected;
	host_client->connection_started = realtime;

	// send the info about the new client to all connected clients
//	SV_FullClientUpdate (host_client, &sv.reliable_datagram);
//	host_client->sendinfo = true;

	gamedir = Info_ValueForKey (svs.info, "*gamedir");
	if (!gamedir[0])
		gamedir = "qw";

//NOTE:  This doesn't go through ClientReliableWrite since it's before the user
//spawns.  These functions are written to not overflow
	if (host_client->num_backbuf) {
		Con_Printf("WARNING %s: [SV_New] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize); 
		host_client->num_backbuf = 0;
		SZ_Clear(&host_client->netchan.message);
	}

	// send the serverdata
	MSG_WriteByte (&host_client->netchan.message, svc_serverdata);
	MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION);
	MSG_WriteLong (&host_client->netchan.message, svs.spawncount);
	MSG_WriteString (&host_client->netchan.message, gamedir);

	playernum = NUM_FOR_EDICT(host_client->edict)-1;
	if (host_client->spectator)
		playernum |= 128;
	MSG_WriteByte (&host_client->netchan.message, playernum);

	// send full levelname
	MSG_WriteString (&host_client->netchan.message, PR_GetString(sv.edicts->v.message));

	// send the movevars
	MSG_WriteFloat(&host_client->netchan.message, movevars.gravity);
	MSG_WriteFloat(&host_client->netchan.message, movevars.stopspeed);
	MSG_WriteFloat(&host_client->netchan.message, movevars.maxspeed);
	MSG_WriteFloat(&host_client->netchan.message, movevars.spectatormaxspeed);
	MSG_WriteFloat(&host_client->netchan.message, movevars.accelerate);
	MSG_WriteFloat(&host_client->netchan.message, movevars.airaccelerate);
	MSG_WriteFloat(&host_client->netchan.message, movevars.wateraccelerate);
	MSG_WriteFloat(&host_client->netchan.message, movevars.friction);
	MSG_WriteFloat(&host_client->netchan.message, movevars.waterfriction);
	MSG_WriteFloat(&host_client->netchan.message, movevars.entgravity);

	// send music
	MSG_WriteByte (&host_client->netchan.message, svc_cdtrack);
	MSG_WriteByte (&host_client->netchan.message, sv.edicts->v.sounds);

	// send server info string
	MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
	MSG_WriteString (&host_client->netchan.message, va("fullserverinfo \"%s\"\n", svs.info) );
}
Beispiel #12
0
/*
====================
CL_Record

Called by CL_Record_f and CL_EasyRecord_f
====================
*/
static void CL_Record (void)
{
	sizebuf_t	buf;
	byte	buf_data[MAX_MSGLEN];
	int n, i, j;
	char *s;
	entity_t *ent;
	entity_state_t *es, blankes;
	player_info_t *player;
	int seq = 1;

#ifdef MVDPLAY
	if (cls.mvdplayback) {
		Com_Printf ("Can't record while playing MVD demo.\n");
		return;
	}
#endif
	cls.demorecording = true;

/*-------------------------------------------------*/

// serverdata
	// send the info about the new client to all connected clients
	SZ_Init (&buf, buf_data, sizeof(buf_data));

// send the serverdata
	MSG_WriteByte (&buf, svc_serverdata);
	MSG_WriteLong (&buf, PROTOCOL_VERSION);
	MSG_WriteLong (&buf, cl.servercount);
	MSG_WriteString (&buf, cls.gamedirfile);

	if (cl.spectator)
		MSG_WriteByte (&buf, cl.playernum | 128);
	else
		MSG_WriteByte (&buf, cl.playernum);

	// send full levelname
	MSG_WriteString (&buf, cl.levelname);

	// send the movevars
	MSG_WriteFloat(&buf, movevars.gravity);
	MSG_WriteFloat(&buf, movevars.stopspeed);
	MSG_WriteFloat(&buf, cl.maxspeed);
	MSG_WriteFloat(&buf, movevars.spectatormaxspeed);
	MSG_WriteFloat(&buf, movevars.accelerate);
	MSG_WriteFloat(&buf, movevars.airaccelerate);
	MSG_WriteFloat(&buf, movevars.wateraccelerate);
	MSG_WriteFloat(&buf, movevars.friction);
	MSG_WriteFloat(&buf, movevars.waterfriction);
	MSG_WriteFloat(&buf, cl.entgravity);

	// send music
	MSG_WriteByte (&buf, svc_cdtrack);
	MSG_WriteByte (&buf, 0); // none in demos

	// send server info string
	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", cl.serverinfo) );

	// flush packet
	CL_WriteRecordDemoMessage (&buf, seq++);
	SZ_Clear (&buf); 

// soundlist
	MSG_WriteByte (&buf, svc_soundlist);
	MSG_WriteByte (&buf, 0);

	n = 0;
	s = cl.sound_name[n+1];
	while (*s) {
		MSG_WriteString (&buf, s);
		if (buf.cursize > MAX_MSGLEN/2) {
			MSG_WriteByte (&buf, 0);
			MSG_WriteByte (&buf, n);
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
			MSG_WriteByte (&buf, svc_soundlist);
			MSG_WriteByte (&buf, n + 1);
		}
		n++;
		s = cl.sound_name[n+1];
	}
	if (buf.cursize) {
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, 0);
		CL_WriteRecordDemoMessage (&buf, seq++);
		SZ_Clear (&buf); 
	}

#ifdef VWEP_TEST
// vwep modellist
	if ((cl.z_ext & Z_EXT_VWEP) && cl.vw_model_name[0][0]) {
		// send VWep precaches
		// pray we don't overflow
		for (i = 0; i < MAX_VWEP_MODELS; i++) {
			s = cl.vw_model_name[i];
			if (!*s)
				continue;
			MSG_WriteByte (&buf, svc_serverinfo);
			MSG_WriteString (&buf, "#vw");
			MSG_WriteString (&buf, va("%i %s", i, TrimModelName(s)));
		}
		// send end-of-list messsage
		MSG_WriteByte (&buf, svc_serverinfo);
		MSG_WriteString (&buf, "#vw");
		MSG_WriteString (&buf, "");
	}
	// don't bother flushing, the vwep list is not that large (I hope)
#endif

// modellist
	MSG_WriteByte (&buf, svc_modellist);
	MSG_WriteByte (&buf, 0);

	n = 0;
	s = cl.model_name[n+1];
	while (*s) {
		MSG_WriteString (&buf, s);
		if (buf.cursize > MAX_MSGLEN/2) {
			MSG_WriteByte (&buf, 0);
			MSG_WriteByte (&buf, n);
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
			MSG_WriteByte (&buf, svc_modellist);
			MSG_WriteByte (&buf, n + 1);
		}
		n++;
		s = cl.model_name[n+1];
	}
	if (buf.cursize) {
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, 0);
		CL_WriteRecordDemoMessage (&buf, seq++);
		SZ_Clear (&buf); 
	}

// spawnstatic

	for (i = 0; i < cl.num_statics; i++) {
		ent = cl_static_entities + i;

		MSG_WriteByte (&buf, svc_spawnstatic);

		for (j = 1; j < MAX_MODELS; j++)
			if (ent->model == cl.model_precache[j])
				break;
		if (j == MAX_MODELS)
			MSG_WriteByte (&buf, 0);
		else
			MSG_WriteByte (&buf, j);

		MSG_WriteByte (&buf, ent->frame);
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, ent->skinnum);
		for (j=0 ; j<3 ; j++)
		{
			MSG_WriteCoord (&buf, ent->origin[j]);
			MSG_WriteAngle (&buf, ent->angles[j]);
		}

		if (buf.cursize > MAX_MSGLEN/2) {
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
		}
	}

// spawnstaticsound

	for (i = 0; i < cl.num_static_sounds; i++) {
		static_sound_t *ss = &cl.static_sounds[i];
		MSG_WriteByte (&buf, svc_spawnstaticsound);
		for (j = 0; j < 3; j++)
			MSG_WriteCoord (&buf, ss->org[j]);
		MSG_WriteByte (&buf, ss->sound_num);
		MSG_WriteByte (&buf, ss->vol);
		MSG_WriteByte (&buf, ss->atten);

		if (buf.cursize > MAX_MSGLEN/2) {
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
		}
	}

// baselines

	memset(&blankes, 0, sizeof(blankes));
	for (i = 0; i < MAX_CL_EDICTS; i++) {
		es = &cl_entities[i].baseline;

		if (memcmp(es, &blankes, sizeof(blankes))) {
			MSG_WriteByte (&buf,svc_spawnbaseline);		
			MSG_WriteShort (&buf, i);

			MSG_WriteByte (&buf, es->modelindex);
			MSG_WriteByte (&buf, es->frame);
			MSG_WriteByte (&buf, es->colormap);
			MSG_WriteByte (&buf, es->skinnum);
			for (j=0 ; j<3 ; j++)
			{
				MSG_WriteShort (&buf, es->s_origin[j]);
				MSG_WriteByte (&buf, es->s_angles[j]);
			}

			if (buf.cursize > MAX_MSGLEN/2) {
				CL_WriteRecordDemoMessage (&buf, seq++);
				SZ_Clear (&buf); 
			}
		}
	}

	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("cmd spawn %i 0\n", cl.servercount) );

	if (buf.cursize) {
		CL_WriteRecordDemoMessage (&buf, seq++);
		SZ_Clear (&buf); 
	}

// send current status of all other players

	for (i = 0; i < MAX_CLIENTS; i++) {
		player = cl.players + i;

		MSG_WriteByte (&buf, svc_updatefrags);
		MSG_WriteByte (&buf, i);
		MSG_WriteShort (&buf, player->frags);
		
		MSG_WriteByte (&buf, svc_updateping);
		MSG_WriteByte (&buf, i);
		MSG_WriteShort (&buf, player->ping);
		
		MSG_WriteByte (&buf, svc_updatepl);
		MSG_WriteByte (&buf, i);
		MSG_WriteByte (&buf, player->pl);
		
		MSG_WriteByte (&buf, svc_updateentertime);
		MSG_WriteByte (&buf, i);
		MSG_WriteFloat (&buf, cls.realtime - player->entertime);

		MSG_WriteByte (&buf, svc_updateuserinfo);
		MSG_WriteByte (&buf, i);
		MSG_WriteLong (&buf, player->userid);
		MSG_WriteString (&buf, player->userinfo);

		if (buf.cursize > MAX_MSGLEN/2) {
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
		}
	}
	
// send all current light styles
	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
	{
		if (!cl_lightstyle[i].length)
			continue;		// don't send empty lightstyle strings
		MSG_WriteByte (&buf, svc_lightstyle);
		MSG_WriteByte (&buf, (char)i);
		MSG_WriteString (&buf, cl_lightstyle[i].map);
	}

	for (i = 0; i < MAX_CL_STATS; i++) {
		if (!cl.stats[i])
			continue;		// no need to send zero values
		if (cl.stats[i] >= 0 && cl.stats[i] <= 255) {
			MSG_WriteByte (&buf, svc_updatestat);
			MSG_WriteByte (&buf, i);
			MSG_WriteByte (&buf, cl.stats[i]);
		} else {
			MSG_WriteByte (&buf, svc_updatestatlong);
			MSG_WriteByte (&buf, i);
			MSG_WriteLong (&buf, cl.stats[i]);
		}
		if (buf.cursize > MAX_MSGLEN/2) {
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
		}
	}

	// get the client to check and download skins
	// when that is completed, a begin command will be issued
	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("skins\n") );

	CL_WriteRecordDemoMessage (&buf, seq++);

	CL_WriteSetDemoMessage();

	// done
}
Beispiel #13
0
void ClientReliableWrite_Float (float f)
{
	assert (backbuf_write_started);
	MSG_WriteFloat (&backbuf, f);
}
/*
================
SV_New_f

Sends the first message from the server to a connected client.
This will be sent on the initial connection and upon each server load.
================
*/
static void SV_New_f (void)
{
	const char	*gamedir;
	int		playernum;

	if (host_client->state == cs_spawned)
		return;

	host_client->state = cs_connected;
	host_client->connection_started = realtime;

	// send the info about the new client to all connected clients
//	SV_FullClientUpdate (host_client, &sv.reliable_datagram);
	host_client->sendinfo = true;

	gamedir = Info_ValueForKey (svs.info, "*gamedir");
	if (!gamedir[0])
		gamedir = "hw";

	// send the serverdata
	MSG_WriteByte (&host_client->netchan.message, svc_serverdata);
	MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION);
	MSG_WriteLong (&host_client->netchan.message, svs.spawncount);
	MSG_WriteString (&host_client->netchan.message, gamedir);

	playernum = NUM_FOR_EDICT(host_client->edict)-1;
	if (host_client->spectator)
		playernum |= 128;
	MSG_WriteByte (&host_client->netchan.message, playernum);

	// send full levelname
	if (sv.edicts->v.message > 0 && sv.edicts->v.message <= pr_string_count)
	{
		MSG_WriteString (&host_client->netchan.message,&pr_global_strings[pr_string_index[(int)sv.edicts->v.message-1]]);
	}
	else 
	{
	// Use netname on map if there is one, so they don't have to edit strings.txt
	//	MSG_WriteString(&host_client->netchan.message,"");
		MSG_WriteString(&host_client->netchan.message, PR_GetString(sv.edicts->v.netname));
	}

	// send the movevars
	MSG_WriteFloat(&host_client->netchan.message, movevars.gravity);
	MSG_WriteFloat(&host_client->netchan.message, movevars.stopspeed);
	MSG_WriteFloat(&host_client->netchan.message, movevars.maxspeed);
	MSG_WriteFloat(&host_client->netchan.message, movevars.spectatormaxspeed);
	MSG_WriteFloat(&host_client->netchan.message, movevars.accelerate);
	MSG_WriteFloat(&host_client->netchan.message, movevars.airaccelerate);
	MSG_WriteFloat(&host_client->netchan.message, movevars.wateraccelerate);
	MSG_WriteFloat(&host_client->netchan.message, movevars.friction);
	MSG_WriteFloat(&host_client->netchan.message, movevars.waterfriction);
	MSG_WriteFloat(&host_client->netchan.message, movevars.entgravity);

	// send music
	MSG_WriteByte (&host_client->netchan.message, svc_cdtrack);
//	MSG_WriteByte (&host_client->netchan.message, sv.edicts->v.soundtype);
	MSG_WriteByte (&host_client->netchan.message, sv.cd_track);

	MSG_WriteByte (&host_client->netchan.message, svc_midi_name);
	MSG_WriteString (&host_client->netchan.message, sv.midi_name);

	// send server info string
	MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
	MSG_WriteString (&host_client->netchan.message, va("fullserverinfo \"%s\"\n", svs.info) );
}
Beispiel #15
0
static void
Host_Spawn_f (void)
{
	int         i;
	client_t   *client;
	edict_t    *ent;
	float      *sendangles;

	if (cmd_source == src_command) {
		Sys_Printf ("spawn is not valid from the console\n");
		return;
	}

	if (host_client->spawned) {
		Sys_Printf ("Spawn not valid -- already spawned\n");
		return;
	}
	// run the entrance script
	if (sv.loadgame) {				// loaded games are fully inited already
		// if this is the last client to be connected, unpause
		sv.paused = false;
	} else {
		// set up the edict
		ent = host_client->edict;
		memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4);
		SVfloat (ent, colormap) = NUM_FOR_EDICT (&sv_pr_state, ent);
		SVfloat (ent, team) = (host_client->colors & 15) + 1;
		SVstring (ent, netname) = PR_SetString (&sv_pr_state,
												host_client->name);

		// copy spawn parms out of the client_t
		for (i = 0; i < NUM_SPAWN_PARMS; i++)
			sv_globals.parms[i] = host_client->spawn_parms[i];

		// call the spawn function
		*sv_globals.time = sv.time;
		*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
		PR_ExecuteProgram (&sv_pr_state, sv_funcs.ClientConnect);
		if ((Sys_DoubleTime () - host_client->netconnection->connecttime) <=
			sv.time) Sys_Printf ("%s entered the game\n", host_client->name);
		PR_ExecuteProgram (&sv_pr_state, sv_funcs.PutClientInServer);
	}

	// send all current names, colors, and frag counts
	SZ_Clear (&host_client->message);

	// send time of update
	MSG_WriteByte (&host_client->message, svc_time);
	MSG_WriteFloat (&host_client->message, sv.time);

	for (i = 0, client = svs.clients; i < svs.maxclients; i++, client++) {
		MSG_WriteByte (&host_client->message, svc_updatename);
		MSG_WriteByte (&host_client->message, i);
		MSG_WriteString (&host_client->message, client->name);
		MSG_WriteByte (&host_client->message, svc_updatefrags);
		MSG_WriteByte (&host_client->message, i);
		MSG_WriteShort (&host_client->message, client->old_frags);
		MSG_WriteByte (&host_client->message, svc_updatecolors);
		MSG_WriteByte (&host_client->message, i);
		MSG_WriteByte (&host_client->message, client->colors);
	}

	// send all current light styles
	for (i = 0; i < MAX_LIGHTSTYLES; i++) {
		MSG_WriteByte (&host_client->message, svc_lightstyle);
		MSG_WriteByte (&host_client->message, (char) i);
		MSG_WriteString (&host_client->message, sv.lightstyles[i]);
	}

	// send some stats
	MSG_WriteByte (&host_client->message, svc_updatestat);
	MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS);
	MSG_WriteLong (&host_client->message,
				   *sv_globals.total_secrets);

	MSG_WriteByte (&host_client->message, svc_updatestat);
	MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS);
	MSG_WriteLong (&host_client->message,
				   *sv_globals.total_monsters);

	MSG_WriteByte (&host_client->message, svc_updatestat);
	MSG_WriteByte (&host_client->message, STAT_SECRETS);
	MSG_WriteLong (&host_client->message,
				   *sv_globals.found_secrets);

	MSG_WriteByte (&host_client->message, svc_updatestat);
	MSG_WriteByte (&host_client->message, STAT_MONSTERS);
	MSG_WriteLong (&host_client->message,
				   *sv_globals.killed_monsters);

	// send a fixangle
	// Never send a roll angle, because savegames can catch the server
	// in a state where it is expecting the client to correct the angle
	// and it won't happen if the game was just loaded, so you wind up
	// with a permanent head tilt
	ent = EDICT_NUM (&sv_pr_state, 1 + (host_client - svs.clients));
	MSG_WriteByte (&host_client->message, svc_setangle);
	sendangles = sv.loadgame ? SVvector (ent, v_angle): SVvector (ent, angles);
	MSG_WriteAngle (&host_client->message, sendangles[0]);
	MSG_WriteAngle (&host_client->message, sendangles[1]);
	MSG_WriteAngle (&host_client->message, 0);

	SV_WriteClientdataToMessage (sv_player, &host_client->message);

	MSG_WriteByte (&host_client->message, svc_signonnum);
	MSG_WriteByte (&host_client->message, 3);
	host_client->sendsignon = true;
}
Beispiel #16
0
// All changes need to be in SV_SendEffect(), SV_ParseEffect(),
// SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect()
static void SV_SendEffect (sizebuf_t *sb, int idx)
{
	qboolean	DoTest;
	vec3_t		TestO1, Diff;
	float		Size, TestDistance;
	int		i, count;

	if (sb == &sv.reliable_datagram && sv_ce_scale.value > 0)
		DoTest = true;
	else
		DoTest = false;

	VectorClear(TestO1);
	TestDistance = 0;

	switch (sv.Effects[idx].type)
	{
	case CE_RAIN:
	case CE_SNOW:
		DoTest = false;
		break;

	case CE_FOUNTAIN:
		DoTest = false;
		break;

	case CE_QUAKE:
		VectorCopy(sv.Effects[idx].ef.Quake.origin, TestO1);
		TestDistance = 700;
		break;

	case CE_WHITE_SMOKE:
	case CE_GREEN_SMOKE:
	case CE_GREY_SMOKE:
	case CE_RED_SMOKE:
	case CE_SLOW_WHITE_SMOKE:
	case CE_TELESMK1:
	case CE_TELESMK2:
	case CE_GHOST:
	case CE_REDCLOUD:
	case CE_FLAMESTREAM:
	case CE_ACID_MUZZFL:
	case CE_FLAMEWALL:
	case CE_FLAMEWALL2:
	case CE_ONFIRE:
		VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1);
		TestDistance = 250;
		break;

	case CE_SM_WHITE_FLASH:
	case CE_YELLOWRED_FLASH:
	case CE_BLUESPARK:
	case CE_YELLOWSPARK:
	case CE_SM_CIRCLE_EXP:
	case CE_BG_CIRCLE_EXP:
	case CE_SM_EXPLOSION:
	case CE_LG_EXPLOSION:
	case CE_FLOOR_EXPLOSION:
	case CE_BLUE_EXPLOSION:
	case CE_REDSPARK:
	case CE_GREENSPARK:
	case CE_ICEHIT:
	case CE_MEDUSA_HIT:
	case CE_MEZZO_REFLECT:
	case CE_FLOOR_EXPLOSION2:
	case CE_XBOW_EXPLOSION:
	case CE_NEW_EXPLOSION:
	case CE_MAGIC_MISSILE_EXPLOSION:
	case CE_BONE_EXPLOSION:
	case CE_BLDRN_EXPL:
	case CE_ACID_HIT:
	case CE_LBALL_EXPL:
	case CE_FIREWALL_SMALL:
	case CE_FIREWALL_MEDIUM:
	case CE_FIREWALL_LARGE:
	case CE_ACID_SPLAT:
	case CE_ACID_EXPL:
	case CE_FBOOM:
	case CE_BRN_BOUNCE:
	case CE_LSHOCK:
	case CE_BOMB:
	case CE_FLOOR_EXPLOSION3:
		VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1);
		TestDistance = 250;
		break;

	case CE_WHITE_FLASH:
	case CE_BLUE_FLASH:
	case CE_SM_BLUE_FLASH:
	case CE_RED_FLASH:
		VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1);
		TestDistance = 250;
		break;

	case CE_RIDER_DEATH:
		DoTest = false;
		break;

	case CE_GRAVITYWELL:
		DoTest = false;
		break;

	case CE_TELEPORTERPUFFS:
		VectorCopy(sv.Effects[idx].ef.Teleporter.origin, TestO1);
		TestDistance = 350;
		break;

	case CE_TELEPORTERBODY:
		VectorCopy(sv.Effects[idx].ef.Teleporter.origin, TestO1);
		TestDistance = 350;
		break;

	case CE_BONESHARD:
	case CE_BONESHRAPNEL:
		VectorCopy(sv.Effects[idx].ef.Missile.origin, TestO1);
		TestDistance = 600;
		break;

	case CE_CHUNK:
		VectorCopy(sv.Effects[idx].ef.Chunk.origin, TestO1);
		TestDistance = 600;
		break;

	default:
		PR_RunError ("%s: bad type", __thisfunc__);
		break;
	}

	if (!DoTest)
		count = 1;
	else
	{
		count = svs.maxclients;
		TestDistance = (float)TestDistance * sv_ce_scale.value;
		TestDistance *= TestDistance;
	}

	for (i = 0 ; i < count ; i++)
	{
		if (DoTest)
		{
			if (svs.clients[i].active)
			{
				sb = &svs.clients[i].datagram;
				VectorSubtract(svs.clients[i].edict->v.origin, TestO1, Diff);
				Size = (Diff[0]*Diff[0]) + (Diff[1]*Diff[1]) + (Diff[2]*Diff[2]);

				if (Size > TestDistance)
					continue;

				if (sv_ce_max_size.value > 0 && sb->cursize > sv_ce_max_size.value)
					continue;
			}
			else
				continue;
		}

		MSG_WriteByte (sb, svc_start_effect);
		MSG_WriteByte (sb, idx);
		MSG_WriteByte (sb, sv.Effects[idx].type);

		switch (sv.Effects[idx].type)
		{
		case CE_RAIN:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[2]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[2]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[2]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[2]);
			MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.color);
			MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.count);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Rain.wait);
			break;

		case CE_SNOW:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[2]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[2]);
			MSG_WriteByte(sb, sv.Effects[idx].ef.Rain.flags);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[2]);
			MSG_WriteByte(sb, sv.Effects[idx].ef.Rain.count);
			//MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.veer);
			break;

		case CE_FOUNTAIN:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[2]);
			MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[0]);
			MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[1]);
			MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[2]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[2]);
			MSG_WriteShort(sb, sv.Effects[idx].ef.Fountain.color);
			MSG_WriteByte(sb, sv.Effects[idx].ef.Fountain.cnt);
			break;

		case CE_QUAKE:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[2]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Quake.radius);
			break;

		case CE_WHITE_SMOKE:
		case CE_GREEN_SMOKE:
		case CE_GREY_SMOKE:
		case CE_RED_SMOKE:
		case CE_SLOW_WHITE_SMOKE:
		case CE_TELESMK1:
		case CE_TELESMK2:
		case CE_GHOST:
		case CE_REDCLOUD:
		case CE_FLAMESTREAM:
		case CE_ACID_MUZZFL:
		case CE_FLAMEWALL:
		case CE_FLAMEWALL2:
		case CE_ONFIRE:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[0]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[1]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[2]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.framelength);
			/* smoke frame is a mission pack thing only. */
			if (sv_protocol > PROTOCOL_RAVEN_111)
				MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.frame);
			break;

		case CE_SM_WHITE_FLASH:
		case CE_YELLOWRED_FLASH:
		case CE_BLUESPARK:
		case CE_YELLOWSPARK:
		case CE_SM_CIRCLE_EXP:
		case CE_BG_CIRCLE_EXP:
		case CE_SM_EXPLOSION:
		case CE_LG_EXPLOSION:
		case CE_FLOOR_EXPLOSION:
		case CE_FLOOR_EXPLOSION3:
		case CE_BLUE_EXPLOSION:
		case CE_REDSPARK:
		case CE_GREENSPARK:
		case CE_ICEHIT:
		case CE_MEDUSA_HIT:
		case CE_MEZZO_REFLECT:
		case CE_FLOOR_EXPLOSION2:
		case CE_XBOW_EXPLOSION:
		case CE_NEW_EXPLOSION:
		case CE_MAGIC_MISSILE_EXPLOSION:
		case CE_BONE_EXPLOSION:
		case CE_BLDRN_EXPL:
		case CE_ACID_HIT:
		case CE_ACID_SPLAT:
		case CE_ACID_EXPL:
		case CE_LBALL_EXPL:
		case CE_FIREWALL_SMALL:
		case CE_FIREWALL_MEDIUM:
		case CE_FIREWALL_LARGE:
		case CE_FBOOM:
		case CE_BOMB:
		case CE_BRN_BOUNCE:
		case CE_LSHOCK:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]);
			break;

		case CE_WHITE_FLASH:
		case CE_BLUE_FLASH:
		case CE_SM_BLUE_FLASH:
		case CE_RED_FLASH:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]);
			break;

		case CE_RIDER_DEATH:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[2]);
			break;

		case CE_TELEPORTERPUFFS:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[2]);
			break;

		case CE_TELEPORTERBODY:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[2]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][0]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][1]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][2]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.skinnum);
			break;

		case CE_BONESHARD:
		case CE_BONESHRAPNEL:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[2]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[0]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[1]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[2]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[0]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[1]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[2]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[0]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[1]);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[2]);
			break;

		case CE_GRAVITYWELL:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[2]);
			MSG_WriteShort(sb, sv.Effects[idx].ef.RD.color);
			MSG_WriteFloat(sb, sv.Effects[idx].ef.RD.lifetime);
			break;

		case CE_CHUNK:
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[2]);
			MSG_WriteByte (sb, sv.Effects[idx].ef.Chunk.type);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[0]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[1]);
			MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[2]);
			MSG_WriteByte (sb, sv.Effects[idx].ef.Chunk.numChunks);
		//	Con_Printf ("Adding %d chunks on server...\n", sv.Effects[idx].Chunk.numChunks);
			break;

		default:
			PR_RunError ("%s: bad type", __thisfunc__);
			break;
		}
	}
}
Beispiel #17
0
/*
====================
CL_Record_f

record <demoname> <server>
====================
*/
void CL_Record_f (void)
{
	int		c;
	char	name[MAX_OSPATH];
	sizebuf_t	buf;
	char	buf_data[MAX_MSGLEN];
	int n, i, j;
	char *s;
	entity_t *ent;
	entity_state_t *es, blankes;
	player_info_t *player;
	extern	char gamedirfile[];
	int seq = 1;

	c = Cmd_Argc();
	if (c != 2)
	{
		Con_Printf ("record <demoname>\n");
		return;
	}

	if (cls.state != ca_active) {
		Con_Printf ("You must be connected to record.\n");
		return;
	}

	if (cls.demorecording)
		CL_Stop_f();
  
	sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));

//
// open the demo file
//
	COM_DefaultExtension (name, ".qwd");

	cls.demofile = fopen (name, "wb");
	if (!cls.demofile)
	{
		Con_Printf ("ERROR: couldn't open.\n");
		return;
	}

	Con_Printf ("recording to %s.\n", name);
	cls.demorecording = true;

/*-------------------------------------------------*/

// serverdata
	// send the info about the new client to all connected clients
	memset(&buf, 0, sizeof(buf));
	buf.data = buf_data;
	buf.maxsize = sizeof(buf_data);

// send the serverdata
	MSG_WriteByte (&buf, svc_serverdata);
	MSG_WriteLong (&buf, PROTOCOL_VERSION);
	MSG_WriteLong (&buf, cl.servercount);
	MSG_WriteString (&buf, gamedirfile);

	if (cl.spectator)
		MSG_WriteByte (&buf, cl.playernum | 128);
	else
		MSG_WriteByte (&buf, cl.playernum);

	// send full levelname
	MSG_WriteString (&buf, cl.levelname);

	// send the movevars
	MSG_WriteFloat(&buf, movevars.gravity);
	MSG_WriteFloat(&buf, movevars.stopspeed);
	MSG_WriteFloat(&buf, movevars.maxspeed);
	MSG_WriteFloat(&buf, movevars.spectatormaxspeed);
	MSG_WriteFloat(&buf, movevars.accelerate);
	MSG_WriteFloat(&buf, movevars.airaccelerate);
	MSG_WriteFloat(&buf, movevars.wateraccelerate);
	MSG_WriteFloat(&buf, movevars.friction);
	MSG_WriteFloat(&buf, movevars.waterfriction);
	MSG_WriteFloat(&buf, movevars.entgravity);

	// send music
	MSG_WriteByte (&buf, svc_cdtrack);
	MSG_WriteByte (&buf, 0); // none in demos

	// send server info string
	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", cl.serverinfo) );

	// flush packet
	CL_WriteRecordDemoMessage (&buf, seq++);
	SZ_Clear (&buf); 

// soundlist
	MSG_WriteByte (&buf, svc_soundlist);
	MSG_WriteByte (&buf, 0);

	n = 0;
	s = cl.sound_name[n+1];
	while (*s) {
		MSG_WriteString (&buf, s);
		if (buf.cursize > MAX_MSGLEN/2) {
			MSG_WriteByte (&buf, 0);
			MSG_WriteByte (&buf, n);
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
			MSG_WriteByte (&buf, svc_soundlist);
			MSG_WriteByte (&buf, n + 1);
		}
		n++;
		s = cl.sound_name[n+1];
	}
	if (buf.cursize) {
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, 0);
		CL_WriteRecordDemoMessage (&buf, seq++);
		SZ_Clear (&buf); 
	}

// modellist
	MSG_WriteByte (&buf, svc_modellist);
	MSG_WriteByte (&buf, 0);

	n = 0;
	s = cl.model_name[n+1];
	while (*s) {
		MSG_WriteString (&buf, s);
		if (buf.cursize > MAX_MSGLEN/2) {
			MSG_WriteByte (&buf, 0);
			MSG_WriteByte (&buf, n);
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
			MSG_WriteByte (&buf, svc_modellist);
			MSG_WriteByte (&buf, n + 1);
		}
		n++;
		s = cl.model_name[n+1];
	}
	if (buf.cursize) {
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, 0);
		CL_WriteRecordDemoMessage (&buf, seq++);
		SZ_Clear (&buf); 
	}

// spawnstatic

	for (i = 0; i < cl.num_statics; i++) {
		ent = cl_static_entities + i;

		MSG_WriteByte (&buf, svc_spawnstatic);

		for (j = 1; j < MAX_MODELS; j++)
			if (ent->model == cl.model_precache[j])
				break;
		if (j == MAX_MODELS)
			MSG_WriteByte (&buf, 0);
		else
			MSG_WriteByte (&buf, j);

		MSG_WriteByte (&buf, ent->frame);
		MSG_WriteByte (&buf, 0);
		MSG_WriteByte (&buf, ent->skinnum);
		for (j=0 ; j<3 ; j++)
		{
			MSG_WriteCoord (&buf, ent->origin[j]);
			MSG_WriteAngle (&buf, ent->angles[j]);
		}

		if (buf.cursize > MAX_MSGLEN/2) {
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
		}
	}

// spawnstaticsound
	// static sounds are skipped in demos, life is hard

// baselines

	memset(&blankes, 0, sizeof(blankes));
	for (i = 0; i < MAX_EDICTS; i++) {
		es = cl_baselines + i;

		if (memcmp(es, &blankes, sizeof(blankes))) {
			MSG_WriteByte (&buf,svc_spawnbaseline);		
			MSG_WriteShort (&buf, i);

			MSG_WriteByte (&buf, es->modelindex);
			MSG_WriteByte (&buf, es->frame);
			MSG_WriteByte (&buf, es->colormap);
			MSG_WriteByte (&buf, es->skinnum);
			for (j=0 ; j<3 ; j++)
			{
				MSG_WriteCoord(&buf, es->origin[j]);
				MSG_WriteAngle(&buf, es->angles[j]);
			}

			if (buf.cursize > MAX_MSGLEN/2) {
				CL_WriteRecordDemoMessage (&buf, seq++);
				SZ_Clear (&buf); 
			}
		}
	}

	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("cmd spawn %i 0\n", cl.servercount) );

	if (buf.cursize) {
		CL_WriteRecordDemoMessage (&buf, seq++);
		SZ_Clear (&buf); 
	}

// send current status of all other players

	for (i = 0; i < MAX_CLIENTS; i++) {
		player = cl.players + i;

		MSG_WriteByte (&buf, svc_updatefrags);
		MSG_WriteByte (&buf, i);
		MSG_WriteShort (&buf, player->frags);
		
		MSG_WriteByte (&buf, svc_updateping);
		MSG_WriteByte (&buf, i);
		MSG_WriteShort (&buf, player->ping);
		
		MSG_WriteByte (&buf, svc_updatepl);
		MSG_WriteByte (&buf, i);
		MSG_WriteByte (&buf, player->pl);
		
		MSG_WriteByte (&buf, svc_updateentertime);
		MSG_WriteByte (&buf, i);
		MSG_WriteFloat (&buf, player->entertime);

		MSG_WriteByte (&buf, svc_updateuserinfo);
		MSG_WriteByte (&buf, i);
		MSG_WriteLong (&buf, player->userid);
		MSG_WriteString (&buf, player->userinfo);

		if (buf.cursize > MAX_MSGLEN/2) {
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
		}
	}
	
// send all current light styles
	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
	{
		MSG_WriteByte (&buf, svc_lightstyle);
		MSG_WriteByte (&buf, (char)i);
		MSG_WriteString (&buf, cl_lightstyle[i].map);
	}

	for (i = 0; i < MAX_CL_STATS; i++) {
		MSG_WriteByte (&buf, svc_updatestatlong);
		MSG_WriteByte (&buf, i);
		MSG_WriteLong (&buf, cl.stats[i]);
		if (buf.cursize > MAX_MSGLEN/2) {
			CL_WriteRecordDemoMessage (&buf, seq++);
			SZ_Clear (&buf); 
		}
	}

#if 0
	MSG_WriteByte (&buf, svc_updatestatlong);
	MSG_WriteByte (&buf, STAT_TOTALMONSTERS);
	MSG_WriteLong (&buf, cl.stats[STAT_TOTALMONSTERS]);

	MSG_WriteByte (&buf, svc_updatestatlong);
	MSG_WriteByte (&buf, STAT_SECRETS);
	MSG_WriteLong (&buf, cl.stats[STAT_SECRETS]);

	MSG_WriteByte (&buf, svc_updatestatlong);
	MSG_WriteByte (&buf, STAT_MONSTERS);
	MSG_WriteLong (&buf, cl.stats[STAT_MONSTERS]);
#endif

	// get the client to check and download skins
	// when that is completed, a begin command will be issued
	MSG_WriteByte (&buf, svc_stufftext);
	MSG_WriteString (&buf, va("skins\n") );

	CL_WriteRecordDemoMessage (&buf, seq++);

	CL_WriteSetDemoMessage();

	// done
}
Beispiel #18
0
/**
 * Responds to a Steam server query.
 *
 * @param s       query string
 * @param socket  response socket
 * @param address response address
 * @param inmsg   message for arguments
 * @return whether the request was handled as a Steam query
 */
bool SV_SteamServerQuery( const char *s, const socket_t *socket, const netadr_t *address, msg_t *inmsg )
{
#if APP_STEAMID
	if( sv.state < ss_loading || sv.state > ss_game )
		return false; // server not running

	if( ( !sv_public->integer && !NET_IsLANAddress( address ) ) || ( sv_maxclients->integer == 1 ) )
		return false;

	if( !strcmp( s, "i" ) )
	{
		// ping
		const char pingResponse[] = "j00000000000000";
		Netchan_OutOfBand( socket, address, sizeof( pingResponse ), ( const uint8_t * )pingResponse );
		return true;
	}

	if( !strcmp( s, "W" ) || !strcmp( s, "U\xFF\xFF\xFF\xFF" ) )
	{
		// challenge - security feature, but since we don't send multiple packets always return 0
		const uint8_t challengeResponse[] = { 'A', 0, 0, 0, 0 };
		Netchan_OutOfBand( socket, address, sizeof( challengeResponse ), ( const uint8_t * )challengeResponse );
		return true;
	}

	if( !strcmp( s, "TSource Engine Query" ) )
	{
		// server info
		char hostname[MAX_INFO_VALUE];
		char gamedir[MAX_QPATH];
		char gamename[128];
		char version[32];
		char tags[MAX_STEAMQUERY_TAG_STRING];
		int i, players = 0, bots = 0, maxclients = 0;
		int flags = 0x80 | 0x01; // game port | game ID containing app ID
		client_t *cl;
		msg_t msg;
		uint8_t msgbuf[MAX_STEAMQUERY_PACKETLEN - sizeof( int32_t )];

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Info Packet %s\n", NET_AddressToString( address ) );

		Q_strncpyz( hostname, COM_RemoveColorTokens( sv_hostname->string ), sizeof( hostname ) );
		if( !hostname[0] )
			Q_strncpyz( hostname, sv_hostname->dvalue, sizeof( hostname ) );
		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );

		Q_strncpyz( gamename, APPLICATION, sizeof( gamename ) );
		if( Cvar_Value( "g_instagib" ) )
			Q_strncatz( gamename, " IG", sizeof( gamename ) );
		if( sv.configstrings[CS_GAMETYPETITLE][0] || sv.configstrings[CS_GAMETYPENAME][0] )
		{
			Q_strncatz( gamename, " ", sizeof( gamename ) );
			Q_strncatz( gamename,
				sv.configstrings[sv.configstrings[CS_GAMETYPETITLE][0] ? CS_GAMETYPETITLE : CS_GAMETYPENAME],
				sizeof( gamename ) );
		}

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( cl->state >= CS_CONNECTED )
			{
				if( cl->tvclient ) // exclude TV from the max players count
					continue;
				if( cl->edict->r.svflags & SVF_FAKECLIENT )
					bots++;
				players++;
			}
			maxclients++;
		}

		Q_snprintfz( version, sizeof( version ), "%i.%i.0.0", APP_VERSION_MAJOR, APP_VERSION_MINOR );

		SV_GetSteamTags( tags );
		if( tags[0] )
			flags |= 0x20;

		MSG_Init( &msg, msgbuf, sizeof( msgbuf ) );
		MSG_WriteByte( &msg, 'I' );
		MSG_WriteByte( &msg, APP_PROTOCOL_VERSION );
		MSG_WriteString( &msg, hostname );
		MSG_WriteString( &msg, sv.mapname );
		MSG_WriteString( &msg, gamedir );
		MSG_WriteString( &msg, gamename );
		MSG_WriteShort( &msg, 0 ); // app ID specified later
		MSG_WriteByte( &msg, min( players, 99 ) );
		MSG_WriteByte( &msg, min( maxclients, 99 ) );
		MSG_WriteByte( &msg, min( bots, 99 ) );
		MSG_WriteByte( &msg, ( dedicated && dedicated->integer ) ? 'd' : 'l' );
		MSG_WriteByte( &msg, STEAMQUERY_OS );
		MSG_WriteByte( &msg, Cvar_String( "password" )[0] ? 1 : 0 );
		MSG_WriteByte( &msg, 0 ); // VAC insecure
		MSG_WriteString( &msg, version );
		MSG_WriteByte( &msg, flags );
		// port
		MSG_WriteShort( &msg, sv_port->integer );
		// tags
		if( flags & 0x20 )
			MSG_WriteString( &msg, tags );
		// 64-bit game ID - needed to specify app ID
		MSG_WriteLong( &msg, APP_STEAMID & 0xffffff );
		MSG_WriteLong( &msg, 0 );
		Netchan_OutOfBand( socket, address, msg.cursize, msg.data );
		return true;
	}

	if( s[0] == 'U' )
	{
		// players
		msg_t msg;
		uint8_t msgbuf[MAX_STEAMQUERY_PACKETLEN - sizeof( int32_t )];
		int i, players = 0;
		client_t *cl;
		char name[MAX_NAME_BYTES];
		unsigned int time = Sys_Milliseconds();

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Players Packet %s\n", NET_AddressToString( address ) );

		MSG_Init( &msg, msgbuf, sizeof( msgbuf ) );
		MSG_WriteByte( &msg, 'D' );
		MSG_WriteByte( &msg, 0 );

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( ( cl->state < CS_CONNECTED ) || cl->tvclient )
				continue;

			Q_strncpyz( name, COM_RemoveColorTokens( cl->name ), sizeof( name ) );
			if( ( msg.cursize + 10 + strlen( name ) ) > sizeof( msgbuf ) )
				break;

			MSG_WriteByte( &msg, i );
			MSG_WriteString( &msg, name );
			MSG_WriteLong( &msg, cl->edict->r.client->r.frags );
			MSG_WriteFloat( &msg, ( float )( time - cl->lastconnect ) * 0.001f );

			players++;
			if( players == 99 )
				break;
		}

		msgbuf[1] = players;
		Netchan_OutOfBand( socket, address, msg.cursize, msg.data );
		return true;
	}

	if( !strcmp( s, "s" ) )
	{
		// master server query, terminated by \n, followed by the challenge
		int i;
		bool fromMaster = false;
		int challenge;
		char gamedir[MAX_QPATH], basedir[MAX_QPATH], tags[MAX_STEAMQUERY_TAG_STRING];
		int players = 0, bots = 0, maxclients = 0;
		client_t *cl;
		char msg[MAX_STEAMQUERY_PACKETLEN];

		for( i = 0; i < MAX_MASTERS; i++ )
		{
			if( sv_masters[i].steam && NET_CompareAddress( address, &sv_masters[i].address ) )
			{
				fromMaster = true;
				break;
			}
		}
		if( !fromMaster )
			return true;

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Master Server Info Packet %s\n", NET_AddressToString( address ) );

		challenge = MSG_ReadLong( inmsg );

		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );
		Q_strncpyz( basedir, FS_BaseGameDirectory(), sizeof( basedir ) );
		SV_GetSteamTags( tags );

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( cl->state >= CS_CONNECTED )
			{
				if( cl->tvclient ) // exclude TV from the max players count
					continue;
				if( cl->edict->r.svflags & SVF_FAKECLIENT )
					bots++;
				players++;
			}
			maxclients++;
		}

		Q_snprintfz( msg, sizeof( msg ),
			"0\n\\protocol\\7\\challenge\\%i" // protocol must be 7 to match Source
			"\\players\\%i\\max\\%i\\bots\\%i"
			"\\gamedir\\%s\\map\\%s"
			"\\password\\%i\\os\\%c"
			"\\lan\\%i\\region\\255"
			"%s%s"
			"\\type\\%c\\secure\\0"
			"\\version\\%i.%i.0.0"
			"\\product\\%s\n",
			challenge,
			min( players, 99 ), min( maxclients, 99 ), min( bots, 99 ),
			gamedir, sv.mapname,
			Cvar_String( "password" )[0] ? 1 : 0, STEAMQUERY_OS,
			sv_public->integer ? 0 : 1,
			tags[0] ? "\\gametype\\" /* legacy - "gametype", not "tags" */ : "", tags,
			( dedicated && dedicated->integer ) ? 'd' : 'l',
			APP_VERSION_MAJOR, APP_VERSION_MINOR,
			basedir );
		NET_SendPacket( socket, ( const uint8_t * )msg, strlen( msg ), address );

		return true;
	}

	if( s[0] == 'O' )
	{
		// out of date message
		static bool printed = false;
		if( !printed )
		{
			int i;
			for( i = 0; i < MAX_MASTERS; i++ )
			{
				if( sv_masters[i].steam && NET_CompareAddress( address, &sv_masters[i].address ) )
				{
					Com_Printf( "Server is out of date and cannot be added to the Steam master servers.\n" );
					printed = true;
					return true;
				}
			}
		}
		return true;
	}
#endif

	return false;
}