Ejemplo n.º 1
0
/* DESCRIPTION: ED_Alloc
// LOCATION: pr_edict.c
// PATH: lots
//
// Allocates a new edict.  And by 'allocates' I mean it picks one of
// the already allocated edicts.  QW's picking was much more involved,
// which makes sense as there are plenty of ways to screw with a mod
// here due to the memory reuse.
*/
edict_t * ED_Alloc() {

   unsigned int i;
   edict_t * e;

   for(i = global_svs.allocated_client_slots + 1; i < global_sv.num_edicts; i++) {

      e = &(global_sv.edicts[i]);

      if(e->free && (e->freetime < 2 || global_sv.time0c - e->freetime > 0.5 )) { //0.5 was originally zero, I trust QW to be smarter.

         ED_ClearEdict(e);
         return(e);
      }
   }

   if(i < global_sv.max_edicts) {

      global_sv.num_edicts++;
      e = &(global_sv.edicts[i]);
      ED_ClearEdict(e);
      return(e);
   }

   Sys_Error("%s: No edicts available.", __FUNCTION__);
}
Ejemplo n.º 2
0
/*
=================
ED_Alloc
 
Either finds a free edict, or allocates a new one.
Try to avoid reusing an entity that was recently freed, because it
can cause the client to think the entity morphed into something else
instead of being removed and recreated, which can cause interpolated
angles and bad trails.
=================
*/
edict_t *ED_Alloc (void)
{
	int			i;
	edict_t		*e;

	for ( i=MAX_CLIENTS+1 ; i<sv.num_edicts ; i++)
	{
		e = EDICT_NUM(i);
		// the first couple seconds of server time can involve a lot of
		// freeing and allocating, so relax the replacement policy
		if (e->e->free && ( e->e->freetime < 2 || sv.time - e->e->freetime > 0.5 ) )
		{
			ED_ClearEdict (e);
			return e;
		}
	}

	if (i == MAX_EDICTS)
	{
		Con_Printf ("WARNING: ED_Alloc: no free edicts\n");
		// step on whatever is the last edict
		e = EDICT_NUM(--i);
		SV_UnlinkEdict(e);
	}
	else
		sv.num_edicts++;
	e = EDICT_NUM(i);
	ED_ClearEdict (e);

	return e;
}
Ejemplo n.º 3
0
/*
=================
ED_Alloc

Either finds a free edict, or allocates a new_ptr one.
Try to avoid reusing an entity that was recently freed, because it
can cause the client to think the entity morphed into something else
instead of being removed and recreated, which can cause interpolated
angles and bad trails.
=================
*/
edict_t *ED_Alloc (void)
{
	int			i;
	edict_t		*e;

	for ( i=svs.maxclients+1 ; i<sv.num_edicts ; i++)
	{
		e = EDICT_NUM(i);
		// the first couple seconds of server time can involve a lot of
		// freeing and allocating, so relax the replacement policy
		if (e->free && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )
		{
			ED_ClearEdict (e);
			return e;
		}
	}
	
	if (i == MAX_EDICTS)
		Sys_Error ("ED_Alloc: no free edicts");
		
	sv.num_edicts++;
	e = EDICT_NUM(i);
	ED_ClearEdict (e);

	return e;
}
Ejemplo n.º 4
0
edict_t *ED_Alloc( int iForceEdictIndex )
{
	if ( iForceEdictIndex >= 0 )
	{
		if ( iForceEdictIndex >= sv.num_edicts )
		{
			Warning( "ED_Alloc( %d ) - invalid edict index specified.", iForceEdictIndex );
			return NULL;
		}
		
		edict_t *e = &sv.edicts[iForceEdictIndex];
		if ( e->IsFree() )
		{
			ED_ClearEdict( e );
			return e;
		}
		else
		{
			return NULL;
		}
	}

	// Check the free list first.
	edict_t *pEdict = sv.edicts + sv.GetMaxClients() + 1;

	for ( int i=sv.GetMaxClients()+1; i < sv.num_edicts; i++ )
	{
		if ( pEdict->IsFree() && (pEdict->freetime < 2 || sv.GetTime() - pEdict->freetime >= EDICT_FREETIME) )
		{
			// If we have no freetime, we've had AllowImmediateReuse() called. We need
			// to explicitly delete this old entity.
			if ( pEdict->freetime == 0 && sv_useexplicitdelete.GetBool() )
			{
				//Warning("ADDING SLOT to snapshot: %d\n", i );
				framesnapshotmanager->AddExplicitDelete( i );
			}

			ED_ClearEdict( pEdict );
			return pEdict;
		}

		pEdict++;
	}
	
	// Allocate a new edict.
	if ( sv.num_edicts >= sv.max_edicts )
	{
		AssertMsg( 0, "Can't allocate edict" );
		if ( sv.max_edicts == 0 )
			Sys_Error( "ED_Alloc: No edicts yet" );
		Sys_Error ("ED_Alloc: no free edicts");
	}

	// Do this before clearing since clear now needs to call back into the edict to deduce the index so can get the changeinfo data in the parallel structure
	sv.num_edicts++;

	ED_ClearEdict( pEdict );
	
	return pEdict;
}
Ejemplo n.º 5
0
/*
=================
ED_Alloc

Either finds a free edict, or allocates a new one.
Try to avoid reusing an entity that was recently freed, because it
can cause the client to think the entity morphed into something else
instead of being removed and recreated, which can cause interpolated
angles and bad trails.
=================
*/
edict_t *ED_Alloc (void)
{
	int			i;
	edict_t		*e;

	for (i = svs.maxclients + 1; i < sv.num_edicts; i++)
	{
		e = EDICT_NUM(i);
		// the first couple seconds of server time can involve a lot of
		// freeing and allocating, so relax the replacement policy
		if (e->free && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )
		{
			ED_ClearEdict (e);
			return e;
		}
	}

	if (i == sv.max_edicts) //johnfitz -- use sv.max_edicts instead of MAX_EDICTS
		Host_Error ("ED_Alloc: no free edicts (max_edicts is %i)", sv.max_edicts);

	sv.num_edicts++;
	e = EDICT_NUM(i);
	memset(e, 0, pr_edict_size); // ericw -- switched sv.edicts to malloc(), so we are accessing uninitialized memory and must fully zero it, not just ED_ClearEdict

	return e;
}
Ejemplo n.º 6
0
/*
==================
SVC_DirectConnect

A connection request that did not come from the master
==================
*/
static void SVC_DirectConnect (void)
{
	char		userinfo[1024];
	static		int	userid;
	netadr_t	adr;
	int			i;
	client_t	*cl, *newcl;
	client_t	temp;
	edict_t		*ent;
	int			edictnum;
	const char		*s;
	int			clients, spectators;
	qboolean	spectator;

	q_strlcpy (userinfo, Cmd_Argv(2), sizeof(userinfo));

	// check for password or spectator_password
	s = Info_ValueForKey (userinfo, "spectator");
	if (s[0] && strcmp(s, "0"))
	{
		if (spectator_password.string[0] && 
			q_strcasecmp(spectator_password.string, "none") &&
			strcmp(spectator_password.string, s) )
		{	// failed
			Con_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from));
			Netchan_OutOfBandPrint (net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT);
			return;
		}
		Info_SetValueForStarKey (userinfo, "*spectator", "1", MAX_INFO_STRING);
		spectator = true;
		Info_RemoveKey (userinfo, "spectator"); // remove passwd
	}
	else
	{
		s = Info_ValueForKey (userinfo, "password");
		if (password.string[0] && 
			q_strcasecmp(password.string, "none") &&
			strcmp(password.string, s) )
		{
			Con_Printf ("%s:password failed\n", NET_AdrToString (net_from));
			Netchan_OutOfBandPrint (net_from, "%c\nserver requires a password\n\n", A2C_PRINT);
			return;
		}
		spectator = false;
		Info_RemoveKey (userinfo, "password"); // remove passwd
	}

	adr = net_from;
	userid++;	// so every client gets a unique id

	newcl = &temp;
	memset (newcl, 0, sizeof(client_t));

	newcl->userid = userid;
	newcl->portals = atoi(Cmd_Argv(1));

	// works properly
	if (!sv_highchars.integer)
	{
		byte	*p, *q;

		for (p = (byte *)newcl->userinfo, q = (byte *)userinfo;
			*q && p < (byte *)newcl->userinfo + sizeof(newcl->userinfo)-1; q++)
		{
			if (*q > 31 && *q <= 127)
				*p++ = *q;
		}
	}
	else
	{
		q_strlcpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo));
	}

	// if there is already a slot for this ip, drop it
	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
	{
		if (cl->state == cs_free)
			continue;
		if (NET_CompareAdr (adr, cl->netchan.remote_address))
		{
			Con_Printf ("%s:reconnect\n", NET_AdrToString (adr));
			SV_DropClient (cl);
			break;
		}
	}

	// count up the clients and spectators
	clients = 0;
	spectators = 0;
	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
	{
		if (cl->state == cs_free)
			continue;
		if (cl->spectator)
			spectators++;
		else
			clients++;
	}

	// if at server limits, refuse connection
	if (maxclients.integer > MAX_CLIENTS)
		Cvar_SetValue ("maxclients", MAX_CLIENTS);
	if (maxspectators.integer > MAX_CLIENTS)
		Cvar_SetValue ("maxspectators", MAX_CLIENTS);
	if (maxspectators.integer + maxclients.integer > MAX_CLIENTS)
		Cvar_SetValue ("maxspectators", MAX_CLIENTS - maxspectators.integer + maxclients.integer);
	if ( (spectator && spectators >= maxspectators.integer)
		|| (!spectator && clients >= maxclients.integer) )
	{
		Con_Printf ("%s:full connect\n", NET_AdrToString (adr));
		Netchan_OutOfBandPrint (adr, "%c\nserver is full\n\n", A2C_PRINT);
		return;
	}

	// find a client slot
	newcl = NULL;
	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
	{
		if (cl->state == cs_free)
		{
			newcl = cl;
			break;
		}
	}
	if (!newcl)
	{
		Con_Printf ("WARNING: miscounted available clients\n");
		return;
	}

	// build a new connection
	// accept the new client
	// this is the only place a client_t is ever initialized
	*newcl = temp;

	Netchan_OutOfBandPrint (adr, "%c", S2C_CONNECTION );

	edictnum = (newcl-svs.clients)+1;

	Netchan_Setup (&newcl->netchan, adr);

	newcl->state = cs_connected;

	SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf));
	newcl->datagram.allowoverflow = true;

	// spectator mode can ONLY be set at join time
	newcl->spectator = spectator;

	ent = EDICT_NUM(edictnum);
	newcl->edict = ent;
	ED_ClearEdict (ent);

	// parse some info from the info strings
	SV_ExtractFromUserinfo (newcl);

	// JACK: Init the floodprot stuff.
	for (i = 0; i < 10; i++)
		newcl->whensaid[i] = 0.0;
	newcl->whensaidhead = 0;
	newcl->lockedtill = 0;

	// call the progs to get default spawn parms for the new client
	PR_ExecuteProgram (pr_global_struct->SetNewParms);
	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		newcl->spawn_parms[i] = (&pr_global_struct->parm1)[i];

	if (newcl->spectator)
		Con_Printf ("Spectator %s connected\n", newcl->name);
	else
		Con_DPrintf ("Client %s connected\n", newcl->name);
}
Ejemplo n.º 7
0
void SV_LoadGame_f (void) {
	extern cvar_t sv_progtype;
	char name[MAX_OSPATH], mapname[MAX_QPATH], str[32 * 1024], *start;
	FILE *f;
	float time, tfloat, spawn_parms[NUM_SPAWN_PARMS];
	edict_t *ent;
	int entnum, version, r;
	unsigned int i;

	if (Cmd_Argc() != 2) {
		Con_Printf ("Usage: %s <savename> : load a game\n", Cmd_Argv(0));
		return;
	}

	snprintf (name, sizeof (name), "%s/save/%s", fs_gamedir, Cmd_Argv(1));
	COM_DefaultExtension (name, ".sav");

	Con_Printf ("Loading game from %s...\n", name);
	if (!(f = fopen (name, "rb"))) {
		Con_Printf ("ERROR: couldn't open.\n");
		return;
	}

	if (fscanf (f, "%i\n", &version) != 1) {
		fclose (f);
		Con_Printf ("Error reading savegame data\n");
		return;
	}

	if (version != SAVEGAME_VERSION) {
		fclose (f);
		Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
		return;
	}

	if (fscanf (f, "%s\n", str) != 1) {
		fclose (f);
		Con_Printf ("Error reading savegame data\n");
		return;
	}
	for (i = 0; i < NUM_SPAWN_PARMS; i++) {
		if (fscanf (f, "%f\n", &spawn_parms[i]) != 1) {
			fclose (f);
			Con_Printf ("Error reading savegame data\n");
			return;
		}
	}

	// this silliness is so we can load 1.06 save files, which have float skill values
	if (fscanf (f, "%f\n", &tfloat) != 1) {
		fclose (f);
		Con_Printf ("Error reading savegame data\n");
		return;
	}
	current_skill = (int)(tfloat + 0.1);
	Cvar_Set (&skill, va("%i", current_skill));

	Cvar_SetValue (&deathmatch, 0);
	Cvar_SetValue (&coop, 0);
	Cvar_SetValue (&teamplay, 0);
	Cvar_SetValue (&maxclients, 1);

	Cvar_Set (&sv_progsname, "spprogs"); // force progsname
#ifdef USE_PR2
	Cvar_Set (&sv_progtype, "0"); // force .dat
#endif

	if (fscanf (f, "%s\n", mapname) != 1) {
		fclose (f);
		Con_Printf ("Error reading savegame data\n");
		return;
	}
	if (fscanf (f, "%f\n", &time) != 1) {
		fclose (f);
		Con_Printf ("Error reading savegame data\n");
		return;
	}

#ifndef SERVERONLY
	Host_EndGame();
	CL_BeginLocalConnection ();
#endif

	SV_SpawnServer (mapname, false);

	if (sv.state != ss_active) {
		Con_Printf ("Couldn't load map\n");
		fclose (f);
		return;
	}

	// load the light styles
	for (i = 0; i < MAX_LIGHTSTYLES; i++) {
		if (fscanf (f, "%s\n", str) != 1) {
			Con_Printf("Couldn't read lightstyles\n");
			fclose (f);
			return;
		}
		sv.lightstyles[i] = (char *) Hunk_Alloc (strlen(str) + 1);
		strlcpy (sv.lightstyles[i], str, strlen(str) + 1);
	}

	// pause until all clients connect
	if (!(sv.paused & 1))
		SV_TogglePause (NULL, 1);

	sv.loadgame = true;

	// load the edicts out of the savegame file
	entnum = -1;		// -1 is the globals
	while (!feof(f)) {
		for (i = 0; i < sizeof(str) - 1; i++) {
			r = fgetc (f);
			if (r == EOF || !r)
				break;
			str[i] = r;
			if (r == '}') {
				i++;
				break;
			}
		}
		if (i == sizeof(str)-1)
			Host_Error ("Loadgame buffer overflow");
		str[i] = 0;
		start = str;
		start = COM_Parse(str);
		if (!com_token[0])
			break;		// end of file

		if (strcmp(com_token,"{"))
			Host_Error ("First token isn't a brace");

		if (entnum == -1) {	
			// parse the global vars
			ED_ParseGlobals (start);
		} else {	
			// parse an edict
			ent = EDICT_NUM(entnum);
			ED_ClearEdict (ent); // FIXME: we also clear world edict here, is it OK?
			ED_ParseEdict (start, ent);
	
			// link it into the bsp tree
			if (!ent->e->free)
				SV_LinkEdict (ent, false);
		}
		entnum++;
	}

	sv.num_edicts = entnum;
	sv.time = time;

	fclose (f);

	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		svs.clients->spawn_parms[i] = spawn_parms[i];
}