예제 #1
0
/*
================
SV_Physics_Client

Player character actions
================
*/
void SV_Physics_Client (edict_t	*ent, int num)
{
	client_t	*cl;
	vec3_t		v;
	qboolean	was_angle_set;
	
	cl = &svs.clients[num-1];
	if (!cl->active)
		return;		// unconnected slot

// call standard client pre-think
	PR_GLOBAL(time) = sv.time;
	PR_GLOBAL(self) = EDICT_TO_PROG(ent);
	PR_ExecuteProgram (PR_GLOBAL(PlayerPreThink));
	
	// for cutscene hack (see below)
	if (isDedicated || (num != 1))
		was_angle_set = false;		// do it on local client only
	else
		was_angle_set = (ent->v.fixangle != 0);
	
// do a move
	SV_CheckVelocity (ent);

// decide which move function to call
	switch ((int)ent->v.movetype)
	{
	case MOVETYPE_NONE:
		if (!SV_RunThink(ent))
			return;
		break;

	case MOVETYPE_WALK:
		if (!SV_RunThink(ent))
			return;
		if (!SV_CheckWater(ent) && !((int)ent->v.flags & FL_WATERJUMP))
			SV_AddGravity (ent);
		SV_CheckStuck (ent);
		SV_WalkMove (ent);

		break;
		
	case MOVETYPE_TOSS:
	case MOVETYPE_BOUNCE:
		SV_Physics_Toss (ent);
		break;

	case MOVETYPE_FLY:
#ifdef HEXEN2_SUPPORT
	case MOVETYPE_SWIM:
#endif
		if (!SV_RunThink(ent))
			return;
		SV_FlyMove (ent, host_frametime, NULL);
		break;
		
	case MOVETYPE_NOCLIP:
		if (!SV_RunThink(ent))
			return;
		VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
		break;
		
	default:
		Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
	}


	// JDH: hack for cutscenes made by Darin McNeil's Cutscene Construction Kit:
	//  (note that the extra precision is noticeable only if the viewangles 
	//  are sent from server to client as 2-byte values; hence the addition 
	//  of the new svc_setpreciseangle message code)

	if (was_angle_set && (ent->v.view_ofs[2] == 0) && host_cutscenehack.value 
		&& !strcmp (pr_strings + ent->v.classname, "camera"))
	{
		// - when camera changes back to player, classname remains "camera" for
		//   1 frame, but movedir is no longer valid.  So as an  additional check, 
		//   I verify that view_ofs[2] is still 0
		// - early version(s?) of Cutscene Construction Kit don't move the camera, 
		//   so movedir is not used.  I determine the version by checking *when* 
		//   the viewangle is set: early version does it in the .think function; 
		//   later ones in PlayerPreThink.	was_angle_set will be true only if
		//   it was changed in PlayerPreThink
		
		//if (!sv_oldprotocol.value)
		{
			v[0] = ent->v.movedir[0] - ent->v.origin[0];
			v[1] = ent->v.movedir[1] - ent->v.origin[1];
			v[2] = ent->v.origin[2] - ent->v.movedir[2];
			//vectoangles (v, ent->v.angles);
			vectoangles (v, cl->cutscene_viewangles);
		}
		
		if (!cl->in_cutscene)
		{
			int i;
			edict_t *ed;
			
			// by this time, the player's viewangles have already been changed.
			// But the dummy entity spawned in place of the player has the values
			
			for (i = 1 ; i < sv.num_edicts ; i++)
			{
			// get the current server version
				ed = EDICT_NUM(i);
				if (ed->free)
					continue;

				if (!strcmp(pr_strings + ed->v.classname, "dummy"))
				{
					VectorCopy (ed->v.angles, cl->prev_viewangles);
					break;
				}
			}

			cl->in_cutscene = true;
		}
		//sv.found_cutscene = true;
	}
	else 
	{
		if (cl->in_cutscene)
		{
		// I'm not sure why, but last viewangle while in_cutscene isn't final angle
			ent->v.fixangle = 1;
			VectorCopy (cl->prev_viewangles, ent->v.angles);
			cl->in_cutscene = false;
		}
	}
	
	SV_LinkEdict (ent, true);
	
	PR_GLOBAL(time) = sv.time;
	PR_GLOBAL(self) = EDICT_TO_PROG(ent);

// JDH: another hack, this time for progs that lack CycleWeaponReverse
	if ((ent->v.impulse == 12.0) && ((sv_imp12hack.value >= 2) || (sv_imp12hack.value && !pr_handles_imp12)) && 
		!ent->v.deadflag && (ent->v.view_ofs[0] || ent->v.view_ofs[1] || ent->v.view_ofs[2]))
	{
		eval_t  *val = GETEDICTFIELD(ent, eval_attack_finished);
		if (val && (sv.time >= val->_float))
		{
			SV_CycleWeaponReverse (ent);
		}
	}

// call standard player post-think
	PR_ExecuteProgram (PR_GLOBAL(PlayerPostThink));
}
예제 #2
0
파일: pr_edict.cpp 프로젝트: luaman/zq
void ED_PrintNum (int ent)
{
	ED_Print (EDICT_NUM(ent));
}
예제 #3
0
파일: pr_edict.cpp 프로젝트: luaman/zq
/*
================
ED_LoadFromFile

The entities are directly placed in the array, rather than allocated with
ED_Alloc, because otherwise an error loading the map would have entity
number references out of order.

Creates a server's entity / program execution context by
parsing textual entity definitions out of an ent file.

Used for both fresh maps and savegame loads.  A fresh map would also need
to call ED_CallSpawnFunctions () to let the objects initialize themselves.
================
*/
void ED_LoadFromFile (char *data)
{	
	edict_t		*ent;
	int			inhibit;
	dfunction_t	*func;
	
	ent = NULL;
	inhibit = 0;
	pr_global_struct->time = sv.time;
	
// parse ents
	while (1)
	{
// parse the opening brace	
		data = COM_Parse (data);
		if (!data)
			break;
		if (com_token[0] != '{')
			Host_Error ("ED_LoadFromFile: found %s when expecting {",com_token);

		if (!ent)
			ent = EDICT_NUM(0);
		else
			ent = ED_Alloc ();
		data = ED_ParseEdict (data, ent);
		
// remove things from different skill levels or deathmatch
		if (deathmatch.value)
		{
			if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
			{
				ED_Free (ent);
				inhibit++;
				continue;
			}
		}
		else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY))
				|| (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM))
				|| (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) )
		{
			ED_Free (ent);
			inhibit++;
			continue;
		}

//
// immediately call spawn function
//
		if (!ent->v.classname)
		{
			Com_Printf ("No classname for:\n");
			ED_Print (ent);
			ED_Free (ent);
			continue;
		}

	// look for the spawn function
		func = ED_FindFunction ( PR_GetString(ent->v.classname) );

		if (!func)
		{
			Com_Printf ("No spawn function for:\n");
			ED_Print (ent);
			ED_Free (ent);
			continue;
		}

		pr_global_struct->self = EDICT_TO_PROG(ent);
		PR_ExecuteProgram (func - pr_functions);
		SV_FlushSignon();
	}	

	Com_DPrintf ("%i entities inhibited\n", inhibit);
}
예제 #4
0
파일: sv_init.c 프로젝트: UCyborg/xash3d
/*
==============
SV_InitGame

A brand new game has been started
==============
*/
void SV_InitGame( void )
{
	edict_t	*ent;
	int	i;
	
	if( svs.initialized )
	{
		// cause any connected clients to reconnect
		Q_strncpy( host.finalmsg, "Server restarted", MAX_STRING );
		SV_Shutdown( true );
	}
	else
	{
		// init game after host error
		if( !svgame.hInstance )
		{
			if( !SV_LoadProgs( GI->game_dll ))
			{
				MsgDev( D_ERROR, "SV_InitGame: can't initialize %s\n", GI->game_dll );
				return; // can't load
			}
			MsgDev( D_INFO, "Server loaded\n" );
		}

		// make sure the client is down
		CL_Drop();
	}

	// now apply latched commands
	Cmd_ExecuteString( "latch\n", src_command );

	if( Cvar_VariableValue( "coop" ) && Cvar_VariableValue ( "deathmatch" ) && Cvar_VariableValue( "teamplay" ))
	{
		MsgDev( D_WARN, "Deathmatch, Teamplay and Coop set, defaulting to Deathmatch\n");
		Cvar_FullSet( "coop", "0",  CVAR_LATCH );
		Cvar_FullSet( "teamplay", "0", CVAR_LATCH );
	}

	// dedicated servers are can't be single player and are usually DM
	// so unless they explicity set coop, force it to deathmatch
	if( host.type == HOST_DEDICATED )
	{
		if( !Cvar_VariableValue( "coop" ) && !Cvar_VariableValue( "teamplay" ))
			Cvar_FullSet( "deathmatch", "1",  CVAR_LATCH );
	}

	// init clients
	if( Cvar_VariableValue( "deathmatch" ) || Cvar_VariableValue( "teamplay" ))
	{
		if( sv_maxclients->integer <= 1 )
			Cvar_FullSet( "maxplayers", "8", CVAR_LATCH );
		else if( sv_maxclients->integer > MAX_CLIENTS )
			Cvar_FullSet( "maxplayers", "32", CVAR_LATCH );
	}
	else if( Cvar_VariableValue( "coop" ))
	{
		if( sv_maxclients->integer <= 1 || sv_maxclients->integer > 4 )
			Cvar_FullSet( "maxplayers", "4", CVAR_LATCH );
	}
	else	
	{
		// non-deathmatch, non-coop is one player
		Cvar_FullSet( "maxplayers", "1", CVAR_LATCH );
	}

	svgame.globals->maxClients = sv_maxclients->integer;
	SV_UPDATE_BACKUP = ( svgame.globals->maxClients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;

	svs.clients = Z_Malloc( sizeof( sv_client_t ) * sv_maxclients->integer );
	svs.num_client_entities = sv_maxclients->integer * SV_UPDATE_BACKUP * 64;
	svs.packet_entities = Z_Malloc( sizeof( entity_state_t ) * svs.num_client_entities );
	svs.baselines = Z_Malloc( sizeof( entity_state_t ) * GI->max_edicts );

	// client frames will be allocated in SV_DirectConnect

	// init network stuff
	NET_Config(( sv_maxclients->integer > 1 ));

	// copy gamemode into svgame.globals
	svgame.globals->deathmatch = Cvar_VariableInteger( "deathmatch" );
	svgame.globals->teamplay = Cvar_VariableInteger( "teamplay" );
	svgame.globals->coop = Cvar_VariableInteger( "coop" );

	// heartbeats will always be sent to the id master
	svs.last_heartbeat = MAX_HEARTBEAT; // send immediately

	// set client fields on player ents
	for( i = 0; i < svgame.globals->maxClients; i++ )
	{
		// setup all the clients
		ent = EDICT_NUM( i + 1 );
		SV_InitEdict( ent );
		svs.clients[i].edict = ent;
	}

	// get actual movevars
	SV_UpdateMovevars( true );

	svgame.numEntities = svgame.globals->maxClients + 1; // clients + world
	svs.initialized = true;
}
예제 #5
0
파일: g_spawn.c 프로젝트: turol/webquake2
/*
==============
SpawnEntities

Creates a server's entity / program execution context by
parsing textual entity definitions out of an ent file.
==============
*/
void SpawnEntities (const char *mapname, const char *entities_, const char *spawnpoint)
{
	char *entities = strdup(entities_);
	edict_t		*ent;
	int			inhibit;
	const char	*com_token;
	int			i;
	float		skill_level;

	skill_level = floor (skill->value);
	if (skill_level < 0)
		skill_level = 0;
	if (skill_level > 3)
		skill_level = 3;
	if (skill->value != skill_level)
		gi.cvar_forceset("skill", va("%f", skill_level));

	SaveClientData ();

	gi.FreeTags (TAG_LEVEL);

	memset (&level, 0, sizeof(level));
	memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0]));

	strncpy (level.mapname, mapname, sizeof(level.mapname)-1);
	strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1);

	// set client fields on player ents
	for (i=0 ; i<game.maxclients ; i++)
		g_edicts[i+1].client = game.clients + i;

	ent = NULL;
	inhibit = 0;

	bool isCommandLevel = (Q_stricmp(level.mapname, "command") != 0);

// parse ents
	while (1)
	{
		// parse the opening brace	
		com_token = COM_Parse (&entities);
		if (!entities)
			break;
		if (com_token[0] != '{')
			gi.error ("ED_LoadFromFile: found %s when expecting {",com_token);

		if (!ent)
			ent = g_edicts;
		else
			ent = G_Spawn ();
		entities = ED_ParseEdict (entities, ent);

		// yet another map hack
		if (isCommandLevel && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27"))
			ent->spawnflags &= ~SPAWNFLAG_NOT_HARD;

		// remove things (except the world) from different skill levels or deathmatch
		if (ent != g_edicts)
		{
			if (deathmatch->value)
			{
				if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH )
				{
					G_FreeEdict (ent);	
					inhibit++;
					continue;
				}
			}
			else
			{
				if ( /* ((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || */
					((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) ||
					((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) ||
					(((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD))
					)
					{
						G_FreeEdict (ent);	
						inhibit++;
						continue;
					}
			}

			ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH);
		}

		ED_CallSpawn (ent);
	}	

	gi.dprintf ("%i entities inhibited\n", inhibit);

#if 0
	i = 1;
	ent = EDICT_NUM(i);
	while (i < globals.num_edicts) {
		if (ent->inuse != 0 || ent->inuse != 1)
			Com_DPrintf("Invalid entity %d\n", i);
		i++, ent++;
	}
#endif

	G_FindTeams ();

	PlayerTrail_Init ();

	free(entities);
}
예제 #6
0
static void SV_FinishPMove( playermove_t *pmove, sv_client_t *cl )
{
    edict_t	*clent = cl->edict;

    clent->v.teleport_time = pmove->waterjumptime;
    VectorCopy( pmove->origin, clent->v.origin );
    VectorCopy( pmove->view_ofs, clent->v.view_ofs );
    VectorCopy( pmove->velocity, clent->v.velocity );
    VectorCopy( pmove->basevelocity, clent->v.basevelocity );
    VectorCopy( pmove->punchangle, clent->v.punchangle );
    VectorCopy( pmove->movedir, clent->v.movedir );
    clent->v.flTimeStepSound = pmove->flTimeStepSound;
    clent->v.flFallVelocity = pmove->flFallVelocity;
    clent->v.oldbuttons = pmove->oldbuttons;
    clent->v.waterlevel = pmove->waterlevel;
    clent->v.watertype = pmove->watertype;
    clent->v.maxspeed = pmove->clientmaxspeed;
    clent->v.flDuckTime = pmove->flDuckTime;
    clent->v.flSwimTime = pmove->flSwimTime;
    clent->v.iStepLeft = pmove->iStepLeft;
    clent->v.movetype = pmove->movetype;
    clent->v.friction = pmove->friction;
    clent->v.deadflag = pmove->deadflag;
    clent->v.effects = pmove->effects;
    clent->v.bInDuck = pmove->bInDuck;
    clent->v.flags = pmove->flags;

    // copy back user variables
    clent->v.iuser1 = pmove->iuser1;
    clent->v.iuser2 = pmove->iuser2;
    clent->v.iuser3 = pmove->iuser3;
    clent->v.iuser4 = pmove->iuser4;
    clent->v.fuser1 = pmove->fuser1;
    clent->v.fuser2 = pmove->fuser2;
    clent->v.fuser3 = pmove->fuser3;
    clent->v.fuser4 = pmove->fuser4;
    VectorCopy( pmove->vuser1, clent->v.vuser1 );
    VectorCopy( pmove->vuser2, clent->v.vuser2 );
    VectorCopy( pmove->vuser3, clent->v.vuser3 );
    VectorCopy( pmove->vuser4, clent->v.vuser4 );

    if( svgame.pmove->onground == -1 )
    {
        clent->v.flags &= ~FL_ONGROUND;
    }
    else if( pmove->onground >= 0 && pmove->onground < pmove->numphysent )
    {
        clent->v.flags |= FL_ONGROUND;
        clent->v.groundentity = EDICT_NUM( svgame.pmove->physents[svgame.pmove->onground].info );
    }

    // angles
    // show 1/3 the pitch angle and all the roll angle
    if( !clent->v.fixangle )
    {
        VectorCopy( pmove->angles, clent->v.v_angle );
        clent->v.angles[PITCH] = -( clent->v.v_angle[PITCH] / 3.0f );
        clent->v.angles[ROLL] = clent->v.v_angle[ROLL];
        clent->v.angles[YAW] = clent->v.v_angle[YAW];
    }

    SV_SetMinMaxSize( clent, pmove->player_mins[pmove->usehull], pmove->player_maxs[pmove->usehull] );

    // all next calls ignore footstep sounds
    pmove->runfuncs = false;
}
예제 #7
0
/*
============
SV_PushMove

============
*/
static edict_t *SV_PushMove( edict_t *pusher, float movetime )
{
	int		i, e, block;
	int		num_moved, oldsolid;
	vec3_t		mins, maxs, lmove;
	sv_pushed_t	*p, *pushed_p;
	edict_t		*check;

	if( sv.state == ss_loading || VectorIsNull( pusher->v.velocity ))
	{
		pusher->v.ltime += movetime;
		return NULL;
	}

	for( i = 0; i < 3; i++ )
	{
		lmove[i] = pusher->v.velocity[i] * movetime;
		mins[i] = pusher->v.absmin[i] + lmove[i];
		maxs[i] = pusher->v.absmax[i] + lmove[i];
	}

	pushed_p = svgame.pushed;

	// save the pusher's original position
	pushed_p->ent = pusher;
	VectorCopy( pusher->v.origin, pushed_p->origin );
	VectorCopy( pusher->v.angles, pushed_p->angles );
	pushed_p++;

	// move the pusher to it's final position
	SV_LinearMove( pusher, movetime, pusher->v.friction );
	SV_LinkEdict( pusher, false );
	pusher->v.ltime += movetime;
	oldsolid = pusher->v.solid;

	// non-solid pushers can't push anything
	if( pusher->v.solid == SOLID_NOT )
		return NULL;

	// see if any solid entities are inside the final position
	num_moved = 0;

	for( e = 1; e < svgame.numEntities; e++ )
	{
		check = EDICT_NUM( e );
		if( !SV_IsValidEdict( check )) continue;

		// filter movetypes to collide with
		if( !SV_CanPushed( check ))
			continue;

		pusher->v.solid = SOLID_NOT;
		block = SV_TestEntityPosition( check, pusher );
		pusher->v.solid = oldsolid;
		if( block ) continue;

		// if the entity is standing on the pusher, it will definately be moved
		if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher ))
		{
			if( check->v.absmin[0] >= maxs[0]
			 || check->v.absmin[1] >= maxs[1]
			 || check->v.absmin[2] >= maxs[2]
			 || check->v.absmax[0] <= mins[0]
			 || check->v.absmax[1] <= mins[1]
			 || check->v.absmax[2] <= mins[2] )
				continue;

			// see if the ent's bbox is inside the pusher's final position
			if( !SV_TestEntityPosition( check, NULL ))
				continue;
		}

		// remove the onground flag for non-players
		if( check->v.movetype != MOVETYPE_WALK )
			check->v.flags &= ~FL_ONGROUND;

		// save original position of contacted entity
		pushed_p->ent = check;
		VectorCopy( check->v.origin, pushed_p->origin );
		VectorCopy( check->v.angles, pushed_p->angles );
		pushed_p++;

		// try moving the contacted entity
		pusher->v.solid = SOLID_NOT;
		SV_PushEntity( check, lmove, vec3_origin, &block );
		pusher->v.solid = oldsolid;

		// if it is still inside the pusher, block
		if( SV_TestEntityPosition( check, NULL ) && block )
		{
			if( !SV_CanBlock( check ))
				continue;

			pusher->v.ltime -= movetime;

			// move back any entities we already moved
			// go backwards, so if the same entity was pushed
			// twice, it goes back to the original position
			for( p = pushed_p - 1; p >= svgame.pushed; p-- )
			{
				VectorCopy( p->origin, p->ent->v.origin );
				VectorCopy( p->angles, p->ent->v.angles );
				SV_LinkEdict( p->ent, (p->ent == check) ? true : false );
			}
			return check;
		}
	}
	return NULL;
}
예제 #8
0
int LoadGamestate(char *level, char *startspot)
{
	char	name[MAX_OSPATH];
	FILE	*f;
	char	mapname[MAX_QPATH];
	float	time, sk;
	char	str[32768], *start;
	int		i, r;
	edict_t	*ent;
	int		entnum;
	int		version;
//	float	spawn_parms[NUM_SPAWN_PARMS];

	sprintf (name, "%s/%s.gip", com_gamedir, level);

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

	fscanf (f, "%i\n", &version);
	if (version != SAVEGAME_VERSION)
	{
		fclose (f);
		Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
		return -1;
	}
	fscanf (f, "%s\n", str);
//	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
//		fscanf (f, "%f\n", &spawn_parms[i]);
	fscanf (f, "%f\n", &sk);
	Cvar_SetValue ("skill", sk);

	fscanf (f, "%s\n",mapname);
	fscanf (f, "%f\n",&time);

	SV_SpawnServer (mapname, startspot);

	if (!sv.active)
	{
		Con_Printf ("Couldn't load map\n");
		return -1;
	}

// load the light styles
	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
	{
		fscanf (f, "%s\n", str);
		sv.lightstyles[i] = Hunk_Alloc (strlen(str)+1);
		strcpy (sv.lightstyles[i], str);
	}

// load the edicts out of the savegame file
	while (!feof(f))
	{
		fscanf (f, "%i\n",&entnum);
		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)
			Sys_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,"{"))
			Sys_Error ("First token isn't a brace");

		// parse an edict

		ent = EDICT_NUM(entnum);
		memset (&ent->v, 0, progs->entityfields * 4);
		ent->free = false;
		ED_ParseEdict (start, ent);

		// link it into the bsp tree
		if (!ent->free)
			SV_LinkEdict (ent, false);
	}

//	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];

	return 0;
}
예제 #9
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];
}
예제 #10
0
void Host_Savegame_f (void)
{
	char	name[256];
	FILE	*f;
	int		i;
	char	comment[SAVEGAME_COMMENT_LENGTH+1];

	if (cmd_source != src_command)
		return;

	if (!sv.active)
	{
		Con_Printf ("Not playing a local game.\n");
		return;
	}

	if (cl.intermission)
	{
		Con_Printf ("Can't save in intermission.\n");
		return;
	}

	if (svs.maxclients != 1)
	{
		Con_Printf ("Can't save multiplayer games.\n");
		return;
	}

	if (Cmd_Argc() != 2)
	{
		Con_Printf ("save <savename> : save a game\n");
		return;
	}

	if (strstr(Cmd_Argv(1), ".."))
	{
		Con_Printf ("Relative pathnames are not allowed.\n");
		return;
	}

	for (i=0 ; i<svs.maxclients ; i++)
	{
		if (svs.clients[i].active && (svs.clients[i].edict->u.v.health <= 0) )
		{
			Con_Printf ("Can't savegame with a dead player\n");
			return;
		}
	}

	sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
	COM_DefaultExtension (name, ".sav");

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

	fprintf (f, "%i\n", SAVEGAME_VERSION);
	Host_SavegameComment (comment);
	fprintf (f, "%s\n", comment);
	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
		fprintf (f, "%f\n", svs.clients->spawn_parms[i]);
	fprintf (f, "%d\n", current_skill);
	fprintf (f, "%s\n", sv.name);
	fprintf (f, "%f\n",sv.time);

// write the light styles

	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
	{
		if (sv.lightstyles[i])
			fprintf (f, "%s\n", sv.lightstyles[i]);
		else
			fprintf (f,"m\n");
	}


	ED_WriteGlobals (f);
	for (i=0 ; i<sv.num_edicts ; i++)
	{
		ED_Write (f, EDICT_NUM(i));
		fflush (f);
	}
	fclose (f);
	Con_Printf ("done.\n");
}
예제 #11
0
void Host_Loadgame_f (void)
{
	char	name[MAX_OSPATH];
	FILE	*f;
	char	mapname[MAX_QPATH];
	float	time, tfloat;
	char	str[32768], *start;
	int		i, r;
	edict_t	*ent;
	int		entnum;
	int		version;
	float			spawn_parms[NUM_SPAWN_PARMS];

	if (cmd_source != src_command)
		return;

	if (Cmd_Argc() != 2)
	{
		Con_Printf ("load <savename> : load a game\n");
		return;
	}

	cls.demonum = -1;		// stop demo loop in case this fails

	sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
	COM_DefaultExtension (name, ".sav");

// we can't call SCR_BeginLoadingPlaque, because too much stack space has
// been used.  The menu calls it before stuffing loadgame command
//	SCR_BeginLoadingPlaque ();

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

	fscanf (f, "%i\n", &version);
	if (version != SAVEGAME_VERSION)
	{
		fclose (f);
		Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
		return;
	}
	fscanf (f, "%s\n", str);
	for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
		fscanf (f, "%f\n", &spawn_parms[i]);
// this silliness is so we can load 1.06 save files, which have float skill values
	fscanf (f, "%f\n", &tfloat);
	current_skill = (int)(tfloat + 0.1);
	Cvar_SetValue ("skill", (float)current_skill);

#ifdef QUAKE2
	Cvar_SetValue ("deathmatch", 0);
	Cvar_SetValue ("coop", 0);
	Cvar_SetValue ("teamplay", 0);
#endif

	fscanf (f, "%s\n",mapname);
	fscanf (f, "%f\n",&time);

	CL_Disconnect_f ();

#ifdef QUAKE2
	SV_SpawnServer (mapname, NULL);
#else
	SV_SpawnServer (mapname);
#endif
	if (!sv.active)
	{
		Con_Printf ("Couldn't load map\n");
		return;
	}
	sv.paused = true;		// pause until all clients connect
	sv.loadgame = true;

// load the light styles

	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
	{
		fscanf (f, "%s\n", str);
		sv.lightstyles[i] = (char*) Hunk_Alloc (strlen(str)+1);
		strcpy (sv.lightstyles[i], str);
	}

// load the edicts out of the savegame file
	entnum = -1;		// -1 is the globals
	while (!feof(f))
	{
		for (i=0 ; i< (int) (sizeof(str)-1) ; i++)
		{
			r = fgetc (f);
			if (r == EOF || !r)
				break;
			str[i] = r;
			if (r == '}')
			{
				i++;
				break;
			}
		}
		if (i == sizeof(str)-1)
			Sys_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,"{"))
			Sys_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);
			memset (&ent->u.v, 0, progs->entityfields * 4);
			ent->free = false;
			ED_ParseEdict (start, ent);

		// link it into the bsp tree
			if (!ent->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];

	if (cls.state != ca_dedicated)
	{
		CL_EstablishConnection ("local");
		Host_Reconnect_f ();
	}
}
예제 #12
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;
}
예제 #13
0
static void
Host_Loadgame_f (void)
{
	dstring_t  *name = 0;
	QFile      *f;
	char       *mapname = 0;
	script_t   *script = 0;
	plitem_t   *game = 0;
	plitem_t   *list;
	plitem_t   *item;
	char       *script_data = 0;
	int         i;
	int         entnum;
	int         count;
	int         version;
	float       spawn_parms[NUM_SPAWN_PARMS];

	if (cmd_source != src_command)
		goto end;

	if (Cmd_Argc () != 2) {
		Sys_Printf ("load <savename> : load a game\n");
		goto end;
	}

	cls.demonum = -1;					// stop demo loop in case this fails

	name = dstring_newstr ();
	dsprintf (name, "%s/%s", qfs_gamedir->dir.def, Cmd_Argv (1));
	QFS_DefaultExtension (name, ".sav");

	cl.loading = true;
	CL_UpdateScreen (cl.time);

	Sys_Printf ("Loading game from %s...\n", name->str);
	f = QFS_Open (name->str, "rz");
	if (!f) {
		Sys_Printf ("ERROR: couldn't open.\n");
		goto end;
	}
	script_data = malloc (Qfilesize (f) + 1);
	i = Qread (f, script_data, Qfilesize (f));
	script_data[i] = 0;
	Qclose (f);

	script = Script_New ();
	script->single = "";		// disable {}()': lexing
	Script_Start (script, name->str, script_data);

	Script_GetToken (script, 1);
	if (strequal (script->token->str, PACKAGE_NAME)) {
		if (!Script_TokenAvailable (script, 1)) {
			Sys_Printf ("Unexpected EOF reading %s\n", name->str);
			goto end;
		}
		game = PL_GetPropertyList (script->p);
	} else {
		sscanf (script->token->str, "%i", &version);
		if (version != SAVEGAME_VERSION) {
			Sys_Printf ("Savegame is version %i, not %i\n", version,
						SAVEGAME_VERSION);
			goto end;
		}
		game = convert_to_game_dict (script);
	}

	item = PL_ObjectForKey (game, "spawn_parms");
	for (i = 0; i < NUM_SPAWN_PARMS; i++) {
		if (i >= PL_A_NumObjects (item))
			break;
		spawn_parms[i] = atof (PL_String (PL_ObjectAtIndex (item, i)));
	}
	current_skill = atoi (PL_String (PL_ObjectForKey (game, "current_skill")));
	Cvar_SetValue (skill, current_skill);
	mapname = strdup (PL_String (PL_ObjectForKey (game, "name")));

	CL_Disconnect_f ();

	SV_SpawnServer (mapname);
	if (!sv.active) {
		Sys_Printf ("Couldn't load map %s\n", mapname);
		goto end;
	}
	sv.paused = true;					// pause until all clients connect
	sv.loadgame = true;

	list = PL_ObjectForKey (game, "lightstyles");
	for (i = 0; i < MAX_LIGHTSTYLES; i++) {
		const char *style;
		char       *str;
		if (i >= PL_A_NumObjects (list))
			break;
		item = PL_ObjectAtIndex (list, i);
		style = PL_String (item);
		sv.lightstyles[i] = str = Hunk_Alloc (strlen (style) + 1);
		strcpy (str, style);
	}

	ED_InitGlobals (&sv_pr_state, PL_ObjectForKey (game, "globals"));

	list = PL_ObjectForKey (game, "entities");
	entnum = 0;
	count = PL_A_NumObjects (list);
	if (count > sv.max_edicts)
		Host_Error ("too many entities in saved game. adjust max_edicts\n");
	for (entnum = 0; entnum < count; entnum++) {
		plitem_t   *entity = PL_ObjectAtIndex (list, entnum);
		edict_t    *ent = EDICT_NUM (&sv_pr_state, entnum);

		memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4);
		ent->free = false;
		ED_InitEntity (&sv_pr_state, entity, ent);

		// link it into the bsp tree
		if (!ent->free)
			SV_LinkEdict (ent, false);
	}

	sv.num_edicts = entnum;
	sv.time = atof (PL_String (PL_ObjectForKey (game, "time")));

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

	if (cls.state != ca_dedicated) {
		CL_EstablishConnection ("local");
		Host_Reconnect_f ();
	}
end:
	if (game)
		PL_Free (game);
	if (mapname)
		free (mapname);
	if (script)
		Script_Delete (script);
	if (script_data)
		free (script_data);
	if (name)
		dstring_delete (name);
}
예제 #14
0
파일: sv_mm.c 프로젝트: Kaperstone/warsow
/*
* sv_clientconnect_done
* callback for clientconnect POST request
*/
static void sv_mm_clientconnect_done( stat_query_t *query, qboolean success, void *customp )
{
	stat_query_section_t *root, *ratings_section;
	int session_id, isession_id;
	client_t *cl;
	edict_t *ent;

	/*
	 * ch : JSON API
	 * {
	 *		id: [int],	// 0 on error, > 0 on logged-in user, < 0 for "anonymous" user
	 *		login: [string],	// login-name for user on success
	 *		ratings: [
	 *			{ gametype: [string], rating: [float]: deviation: [float] }
	 *			..
	 *		]
	 * }
	 */

	/*
	 * since we are now generating the local session in SV_MM_ClientConnect, we should
	 * check if session_id < 0 just in case so that we wont try to regenerate local
	 * session or do anything stupid like that
	 * (currently we dont even tell MM about these so ignore)
	 */
	
	session_id = (int)customp;
	isession_id = 0;
	cl = SV_MM_ClientForSession( session_id );

	if( cl == NULL )
	{
		// or figure out the validation anyway from the received session-id?
		Com_Printf("SV_MM_ClientConnect: Couldnt find client with session-id %d\n", session_id );
		return;
	}

	if( !success )
		Com_Printf( "SV_MM_ClientConnect: Error\n" );
	else
	{
		root = sq_api->GetRoot( query );
		if( query == NULL )
		{
			Com_Printf("SV_MM_ParseResponse: Failed to parse data\n");
		}
		else
		{
			isession_id = (int)sq_api->GetNumber( root, "id" );
			if( isession_id == 0 )
			{
				Com_Printf( "SV_MM_ClientConnect: Client not logged in\n");
			}
			else if( isession_id != session_id )
			{
				Com_Printf( "SV_MM_ClientConnect: Session-id doesnt match %d -> %d\n", isession_id, session_id );
				isession_id = 0;
			}
			else
			{
				const char *login = sq_api->GetString( root, "login" );
				ratings_section = sq_api->GetSection( root, "ratings" );

				Q_strncpyz( cl->mm_login, login, sizeof( cl->mm_login ) );

				if( !Info_SetValueForKey( cl->userinfo, "cl_mm_login", login ) ) {
					Com_Printf( "Failed to set infokey cl_mm_login for player %s\n", login );
				}

				if( ge != NULL && ratings_section != NULL )
				{
					int idx = 0;
					stat_query_section_t *element = sq_api->GetArraySection( ratings_section, idx++ );
					ent = EDICT_NUM( (cl - svs.clients) + 1 );
					while( element != NULL )
					{
						ge->AddRating( ent, sq_api->GetString( element, "gametype" ),
							sq_api->GetNumber( element, "rating" ),
							sq_api->GetNumber( element, "deviation" ) );
						element = sq_api->GetArraySection( ratings_section, idx++ );
					}
				}
				SV_UserinfoChanged( cl );
			}
		}
	}

	// unable to validate client, either kick him out or force local session
	if( isession_id == 0 )
	{
		if( sv_mm_loginonly->integer )
		{
			SV_DropClient( cl, DROP_TYPE_GENERAL, "Error: This server requires login. Create account at http://www.warsow.net/" );
			return;
		}

		// TODO: check that session_id >= 0
		isession_id = SV_MM_GenerateLocalSession();
		Com_Printf("SV_MM_ClientConnect: Forcing local_session %d on client %s\n", isession_id, cl->name );
		cl->mm_session = isession_id;
		// TODO: reflect this to the userinfo
		Info_SetValueForKey( cl->userinfo, "cl_mm_session", va("%d", isession_id ) );

		// We should also notify MM about the new local session id?
		// Or another option would be that MM doesnt track local sessions at all,
		// it just emits the results straight away.

		// resend scc query
		// cl->socket->address
	}

	Com_Printf("SV_MM_ClientConnect: %s with session id %d\n", cl->name, cl->mm_session );
}
예제 #15
0
/*
===========
SV_RunCmd
===========
*/
void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed )
{
    usercmd_t lastcmd;
    edict_t	*clent, *touch;
    double	frametime;
    int	i, oldmsec;
    pmtrace_t	*pmtrace;
    trace_t	trace;
    vec3_t	oldvel;

    clent = cl->edict;

    if( cl->next_movetime > host.realtime )
    {
        cl->last_movetime += ( ucmd->msec * 0.001f );
        return;
    }

    cl->next_movetime = 0.0;

    // chop up very long commands
    if( ucmd->msec > 50 )
    {
        lastcmd = *ucmd;
        oldmsec = ucmd->msec;
        lastcmd.msec = oldmsec / 2;

        SV_RunCmd( cl, &lastcmd, random_seed );

        lastcmd.msec = oldmsec / 2 + (oldmsec & 1);	// give them back thier msec.
        lastcmd.impulse = 0;
        SV_RunCmd( cl, &lastcmd, random_seed );
        return;
    }

    if( !cl->fakeclient )
    {
        SV_SetupMoveInterpolant( cl );
    }

    lastcmd = *ucmd;
    svgame.dllFuncs.pfnCmdStart( cl->edict, ucmd, random_seed );

    frametime = ucmd->msec * 0.001;
    cl->timebase += frametime;
    cl->last_movetime += frametime;

    PM_CheckMovingGround( clent, frametime );

    VectorCopy( clent->v.v_angle, svgame.pmove->oldangles ); // save oldangles
    if( !clent->v.fixangle ) VectorCopy( ucmd->viewangles, clent->v.v_angle );

    VectorClear( clent->v.clbasevelocity );

    // copy player buttons
    clent->v.button = ucmd->buttons;
    if( ucmd->impulse ) clent->v.impulse = ucmd->impulse;

    if( ucmd->impulse == 204 )
    {
        // force client.dll update
        SV_RefreshUserinfo();
    }

    svgame.globals->time = cl->timebase;
    svgame.dllFuncs.pfnPlayerPreThink( clent );
    SV_PlayerRunThink( clent, frametime, cl->timebase );

    // If conveyor, or think, set basevelocity, then send to client asap too.
    if( !VectorIsNull( clent->v.basevelocity ))
        VectorCopy( clent->v.basevelocity, clent->v.clbasevelocity );

    // setup playermove state
    SV_SetupPMove( svgame.pmove, cl, ucmd, cl->physinfo );

    // motor!
    svgame.dllFuncs.pfnPM_Move( svgame.pmove, true );

    // copy results back to client
    SV_FinishPMove( svgame.pmove, cl );

    // link into place and touch triggers
    SV_LinkEdict( clent, true );
    VectorCopy( clent->v.velocity, oldvel ); // save velocity

    // touch other objects
    for( i = 0; i < svgame.pmove->numtouch; i++ )
    {
        // never touch the objects when "playersonly" is active
        if( i == MAX_PHYSENTS || ( sv.hostflags & SVF_PLAYERSONLY ))
            break;

        pmtrace = &svgame.pmove->touchindex[i];
        touch = EDICT_NUM( svgame.pmove->physents[pmtrace->ent].info );
        if( touch == clent ) continue;

        VectorCopy( pmtrace->deltavelocity, clent->v.velocity );
        SV_ConvertPMTrace( &trace, pmtrace, touch );
        SV_Impact( touch, clent, &trace );
    }

    // restore velocity
    VectorCopy( oldvel, clent->v.velocity );

    svgame.pmove->numtouch = 0;
    svgame.globals->time = cl->timebase;
    svgame.globals->frametime = frametime;

    // run post-think
    svgame.dllFuncs.pfnPlayerPostThink( clent );
    svgame.dllFuncs.pfnCmdEnd( clent );

    if( !cl->fakeclient )
    {
        SV_RestoreMoveInterpolant( cl );
    }
}
예제 #16
0
파일: sv_init.c 프로젝트: AK107/mvdsv
/*
================
SV_SpawnServer

Change the server to a new map, taking all connected
clients along with it.

This is only called from the SV_Map_f() function.
================
*/
void SV_SpawnServer (char *mapname, qbool devmap, char* entityfile)
{
    extern func_t ED_FindFunctionOffset (char *name);

    edict_t *ent;
    int i;

    extern cvar_t sv_loadentfiles, sv_loadentfiles_dir;
    char *entitystring;
    char oldmap[MAP_NAME_LEN];
    extern qbool	sv_allow_cheats;
    extern cvar_t	sv_cheats, sv_paused, sv_bigcoords;
#ifndef SERVERONLY
    extern void CL_ClearState (void);
#endif

    // store old map name
    snprintf (oldmap, MAP_NAME_LEN, "%s", sv.mapname);

    Con_DPrintf ("SpawnServer: %s\n",mapname);

#ifndef SERVERONLY
    // As client+server we do it here.
    // As serveronly we do it in NET_Init().
    NET_InitServer();
#endif

    SV_SaveSpawnparms ();
    SV_LoadAccounts();

#ifdef USE_PR2
    // remove bot clients
    for (i = 0; i < MAX_CLIENTS; i++)
    {
        if( sv_vm && svs.clients[i].isBot )
        {
            svs.clients[i].old_frags = 0;
            svs.clients[i].edict->v.frags = 0.0;
            svs.clients[i].name[0] = 0;
            svs.clients[i].state = cs_free;
            Info_RemoveAll(&svs.clients[i]._userinfo_ctx_);
            Info_RemoveAll(&svs.clients[i]._userinfoshort_ctx_);
            SV_FullClientUpdate(&svs.clients[i], &sv.reliable_datagram);
            svs.clients[i].isBot = 0;
        }
    }

#endif

    // Shutdown game.
    PR_GameShutDown();
    PR_UnLoadProgs();

    svs.spawncount++; // any partially connected client will be restarted

#ifndef SERVERONLY
    com_serveractive = false;
#endif
    sv.state = ss_dead;
    sv.paused = false;
    Cvar_SetROM(&sv_paused, "0");

    Host_ClearMemory();

#ifdef FTE_PEXT_FLOATCOORDS
    if (sv_bigcoords.value)
    {
        msg_coordsize = 4;
        msg_anglesize = 2;
    }
    else
    {
        msg_coordsize = 2;
        msg_anglesize = 1;
    }
#endif

    if ((int)coop.value)
        Cvar_Set (&deathmatch, "0");
    current_skill = (int) (skill.value + 0.5);
    if (current_skill < 0)
        current_skill = 0;
    Cvar_Set (&skill, va("%d", current_skill));
    if (current_skill > 3)
        current_skill = 3;

    if ((sv_cheats.value || devmap) && !sv_allow_cheats) {
        sv_allow_cheats = true;
        Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING);
    }
    else if ((!sv_cheats.value && !devmap) && sv_allow_cheats) {
        sv_allow_cheats = false;
        Info_SetValueForStarKey (svs.info, "*cheats", "", MAX_SERVERINFO_STRING);
    }


    // wipe the entire per-level structure
    // NOTE: this also set sv.mvdrecording to false, so calling SV_MVD_Record() at end of function
    memset (&sv, 0, sizeof(sv));


    sv.datagram.maxsize = sizeof(sv.datagram_buf);
    sv.datagram.data = sv.datagram_buf;
    sv.datagram.allowoverflow = true;

    sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
    sv.reliable_datagram.data = sv.reliable_datagram_buf;

    sv.multicast.maxsize = sizeof(sv.multicast_buf);
    sv.multicast.data = sv.multicast_buf;

    sv.signon.maxsize = sizeof(sv.signon_buffers[0]);
    sv.signon.data = sv.signon_buffers[0];
    sv.num_signon_buffers = 1;

    sv.time = 1.0;

    // load progs to get entity field count
    // which determines how big each edict is
    // and allocate edicts

    PR_LoadProgs ();
#ifdef WITH_NQPROGS
    PR_InitPatchTables();
#endif
    PR_InitProg();

    for (i = 0; i < MAX_EDICTS; i++)
    {
        ent = EDICT_NUM(i);
        ent->e = &sv.sv_edicts[i]; // assigning ->e field in each edict_t
        ent->e->entnum = i;
        ent->e->area.ed = ent; // yeah, pretty funny, but this help to find which edict_t own this area (link_t)
    }

    fofs_items2 = ED_FindFieldOffset ("items2"); // ZQ_ITEMS2 extension
    fofs_maxspeed = ED_FindFieldOffset ("maxspeed");
    fofs_gravity = ED_FindFieldOffset ("gravity");
    fofs_movement = ED_FindFieldOffset ("movement");
    fofs_vw_index = ED_FindFieldOffset ("vw_index");
    fofs_hideentity = ED_FindFieldOffset ("hideentity");
    fofs_trackent = ED_FindFieldOffset ("trackent");

    // find optional QC-exported functions.
    // we have it here, so we set it to NULL in case of PR2 progs.
    mod_SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect");
    mod_SpectatorThink = ED_FindFunctionOffset ("SpectatorThink");
    mod_SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect");
    mod_ChatMessage = ED_FindFunctionOffset ("ChatMessage");
    mod_UserInfo_Changed = ED_FindFunctionOffset ("UserInfo_Changed");
    mod_ConsoleCmd = ED_FindFunctionOffset ("ConsoleCmd");
    mod_UserCmd = ED_FindFunctionOffset ("UserCmd");
    mod_localinfoChanged = ED_FindFunctionOffset ("localinfoChanged");
    GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand");
    GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic");
    GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause");

    // leave slots at start for clients only
    sv.num_edicts = MAX_CLIENTS+1;
    for (i=0 ; i<MAX_CLIENTS ; i++)
    {
        ent = EDICT_NUM(i+1);
        // restore client name.
        ent->v.netname = PR_SetString(svs.clients[i].name);
        // reserve edict.
        svs.clients[i].edict = ent;
        //ZOID - make sure we update frags right
        svs.clients[i].old_frags = 0;
    }

    // fill sv.mapname and sv.modelname with new map name
    strlcpy (sv.mapname, mapname, sizeof(sv.mapname));
    snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname);
#ifndef SERVERONLY
    // set cvar
    Cvar_ForceSet (&host_mapname, mapname);
#endif

    if (!(sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2))) // true if bad map
    {
        Con_Printf ("Cant load map %s, falling back to %s\n", mapname, oldmap);

        // fill mapname, sv.mapname and sv.modelname with old map name
        strlcpy (sv.mapname, oldmap, sizeof(sv.mapname));
        snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname);
        mapname = oldmap;

        // and re-load old map
        sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2);

        // this should never happen
        if (!sv.worldmodel)
            SV_Error ("CM_LoadMap: bad map");
    }

    sv.map_checksum2 = Com_TranslateMapChecksum (sv.mapname, sv.map_checksum2);

    SV_ClearWorld (); // clear physics interaction links

#ifdef USE_PR2
    if ( sv_vm )
    {
        sv.sound_precache[0] = "";
        sv.model_precache[0] = "";
    }
    else
#endif

    {
        sv.sound_precache[0] = pr_strings;
        sv.model_precache[0] = pr_strings;
    }
    sv.model_precache[1] = sv.modelname;
    sv.models[1] = sv.worldmodel;
    for (i=1 ; i< CM_NumInlineModels() ; i++)
    {
        sv.model_precache[1+i] = localmodels[i];
        sv.models[i+1] =  CM_InlineModel (localmodels[i]);
    }

    //check player/eyes models for hacks
    sv.model_player_checksum = SV_CheckModel("progs/player.mdl");
    sv.eyes_player_checksum = SV_CheckModel("progs/eyes.mdl");

    //
    // spawn the rest of the entities on the map
    //

    // precache and static commands can be issued during
    // map initialization
    sv.state = ss_loading;
#ifndef SERVERONLY
    com_serveractive = true;
#endif

    ent = EDICT_NUM(0);
    ent->e->free = false;
    ent->v.model = PR_SetString(sv.modelname);
    ent->v.modelindex = 1;		// world model
    ent->v.solid = SOLID_BSP;
    ent->v.movetype = MOVETYPE_PUSH;

    // information about the server
    ent->v.netname = PR_SetString(VersionStringFull());
    ent->v.targetname = PR_SetString(SERVER_NAME);
    ent->v.impulse = VERSION_NUM;
    ent->v.items = pr_numbuiltins - 1;

    PR_GLOBAL(mapname) = PR_SetString(sv.mapname);
    // serverflags are for cross level information (sigils)
    PR_GLOBAL(serverflags) = svs.serverflags;
    if (pr_nqprogs)
    {
        pr_globals[35] = deathmatch.value;
        pr_globals[36] = coop.value;
        pr_globals[37] = teamplay.value;
        NQP_Reset ();
    }

    if (pr_nqprogs)
    {
        // register the cvars that NetQuake provides for mod use
        const char **var, *nqcvars[] = {"gamecfg", "scratch1", "scratch2", "scratch3", "scratch4",
                                        "saved1", "saved2", "saved3", "saved4", "savedgamecfg", "temp1", NULL
                                       };
        for (var = nqcvars; *var; var++)
            Cvar_Create((char *)/*stupid const warning*/ *var, "0", 0);
    }

    // run the frame start qc function to let progs check cvars
    if (!pr_nqprogs)
        SV_ProgStartFrame ();

    // ********* External Entity support (.ent file(s) in gamedir/maps) pinched from ZQuake *********
    // load and spawn all other entities
    entitystring = NULL;
    if ((int)sv_loadentfiles.value)
    {
        char ent_path[1024] = {0};

        if (!entityfile || !entityfile[0])
            entityfile = sv.mapname;

        // first try maps/sv_loadentfiles_dir/
        if (sv_loadentfiles_dir.string[0])
        {
            snprintf(ent_path, sizeof(ent_path), "maps/%s/%s.ent", sv_loadentfiles_dir.string, entityfile);
            entitystring = (char *) FS_LoadHunkFile(ent_path, NULL);
        }

        // try maps/ if not loaded yet.
        if (!entitystring)
        {
            snprintf(ent_path, sizeof(ent_path), "maps/%s.ent", entityfile);
            entitystring = (char *) FS_LoadHunkFile(ent_path, NULL);
        }

        if (entitystring) {
            Con_DPrintf ("Using entfile %s\n", ent_path);
        }
    }

    if (!entitystring) {
        entitystring = CM_EntityString();
    }

    PR_LoadEnts(entitystring);
    // ********* End of External Entity support code *********

    // look up some model indexes for specialized message compression
    SV_FindModelNumbers ();

    // all spawning is completed, any further precache statements
    // or prog writes to the signon message are errors
    sv.state = ss_active;

    // run two frames to allow everything to settle
    SV_Physics ();
    sv.time += 0.1;
    SV_Physics ();
    sv.time += 0.1;
    sv.old_time = sv.time;

    // save movement vars
    SV_SetMoveVars();

    // create a baseline for more efficient communications
    SV_CreateBaseline ();
    sv.signon_buffer_size[sv.num_signon_buffers-1] = sv.signon.cursize;

    Info_SetValueForKey (svs.info, "map", sv.mapname, MAX_SERVERINFO_STRING);

    // calltimeofday.
    {
        extern void PF_calltimeofday (void);
        pr_global_struct->time = sv.time;
        pr_global_struct->self = 0;

        PF_calltimeofday();
    }

    Con_DPrintf ("Server spawned.\n");

    // we change map - clear whole demo struct and sent initial state to all dest if any (for QTV only I thought)
    SV_MVD_Record(NULL, true);

#ifndef SERVERONLY
    CL_ClearState ();
#endif
}
예제 #17
0
/*
====================
SV_AddLinksToPmove

collect solid entities
====================
*/
void SV_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t pmove_maxs )
{
    link_t	*l, *next;
    edict_t	*check, *pl;
    vec3_t	mins, maxs;
    physent_t	*pe;

    pl = EDICT_NUM( svgame.pmove->player_index + 1 );
    //ASSERT( SV_IsValidEdict( pl ));
    if( !SV_IsValidEdict( pl ) )
    {
        MsgDev( D_ERROR, "SV_AddLinksToPmove: you have broken clients!\n");
        return;
    }

    // touch linked edicts
    for( l = node->solid_edicts.next; l != &node->solid_edicts; l = next )
    {
        next = l->next;
        check = EDICT_FROM_AREA( l );

        if( check->v.groupinfo != 0 )
        {
            if(( !svs.groupop && (check->v.groupinfo & pl->v.groupinfo ) == 0) ||
                    ( svs.groupop == 1 && ( check->v.groupinfo & pl->v.groupinfo ) != 0 ))
                continue;
        }

        if( ( ( check->v.owner > 0) && check->v.owner == pl ) || check->v.solid == SOLID_TRIGGER )
            continue; // player or player's own missile

        if( svgame.pmove->numvisent < MAX_PHYSENTS )
        {
            pe = &svgame.pmove->visents[svgame.pmove->numvisent];
            if( SV_CopyEdictToPhysEnt( pe, check ))
                svgame.pmove->numvisent++;
        }

        if( check->v.solid == SOLID_NOT && ( check->v.skin == CONTENTS_NONE || check->v.modelindex == 0 ))
            continue;

        // ignore monsterclip brushes
        if(( check->v.flags & FL_MONSTERCLIP ) && check->v.solid == SOLID_BSP )
            continue;

        if( check == pl ) continue;	// himself

        if( !sv_corpse_solid->value )
        {
            if((( check->v.flags & FL_CLIENT ) && check->v.health <= 0 ) || check->v.deadflag == DEAD_DEAD )
                continue;	// dead body
        }

        if( VectorIsNull( check->v.size ))
            continue;

        VectorCopy( check->v.absmin, mins );
        VectorCopy( check->v.absmax, maxs );

        if( check->v.flags & FL_CLIENT )
        {
            // trying to get interpolated values
            if( svs.currentPlayer )
                SV_GetTrueMinMax( svs.currentPlayer, ( NUM_FOR_EDICT( check ) - 1), mins, maxs );
        }

        if( !BoundsIntersect( pmove_mins, pmove_maxs, mins, maxs ))
            continue;

        if( svgame.pmove->numphysent < MAX_PHYSENTS )
        {
            pe = &svgame.pmove->physents[svgame.pmove->numphysent];

            if( SV_CopyEdictToPhysEnt( pe, check ))
                svgame.pmove->numphysent++;
        }
    }

    // recurse down both sides
    if( node->axis == -1 ) return;

    if( pmove_maxs[node->axis] > node->dist )
        SV_AddLinksToPmove( node->children[0], pmove_mins, pmove_maxs );
    if( pmove_mins[node->axis] < node->dist )
        SV_AddLinksToPmove( node->children[1], pmove_mins, pmove_maxs );
}
예제 #18
0
/*
===========
SV_RunCmd
===========
*/
static void SV_RunCmd (usercmd_t *ucmd)
{
	edict_t		*ent;
	int			i, n;
	int			oldmsec;

	cmd = *ucmd;

	// chop up very long commands
	if (cmd.msec > 50)
	{
		oldmsec = ucmd->msec;
		cmd.msec = oldmsec/2;
		SV_RunCmd (&cmd);
		cmd.msec = oldmsec/2;
		cmd.impulse = 0;
		SV_RunCmd (&cmd);
		return;
	}

	if (!sv_player->v.fixangle)
		VectorCopy (ucmd->angles, sv_player->v.v_angle);

	sv_player->v.button0 = ucmd->buttons & 1;
	sv_player->v.button2 = (ucmd->buttons & 2)>>1;

	if (ucmd->buttons & 4 || sv_player->v.playerclass == CLASS_DWARF) // crouched?
		sv_player->v.flags2 = ((int)sv_player->v.flags2) | FL2_CROUCHED;
	else
		sv_player->v.flags2 = ((int)sv_player->v.flags2) & (~FL2_CROUCHED);

	if (ucmd->impulse)
		sv_player->v.impulse = ucmd->impulse;

//
// angles
// show 1/3 the pitch angle and all the roll angle
	if (sv_player->v.health > 0)
	{
		if (!sv_player->v.fixangle)
		{
			sv_player->v.angles[PITCH] = -sv_player->v.v_angle[PITCH]/3;
			sv_player->v.angles[YAW] = sv_player->v.v_angle[YAW];
		}
		sv_player->v.angles[ROLL] = 
				V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;
	}

	host_frametime = ucmd->msec * 0.001;
	if (host_frametime > HX_FRAME_TIME)
		host_frametime = HX_FRAME_TIME;

	if (!host_client->spectator)
	{
		pr_global_struct->frametime = host_frametime;

		pr_global_struct->time = sv.time;
		pr_global_struct->self = EDICT_TO_PROG(sv_player);
		PR_ExecuteProgram (pr_global_struct->PlayerPreThink);

		SV_RunThink (sv_player);
	}

	for (i = 0; i < 3; i++)
		pmove.origin[i] = sv_player->v.origin[i] + (sv_player->v.mins[i] - player_mins[i]);

	VectorCopy (sv_player->v.velocity, pmove.velocity);
	VectorCopy (sv_player->v.v_angle, pmove.angles);

	pmove.spectator = host_client->spectator;
//	pmove.waterjumptime = sv_player->v.teleport_time;
	pmove.numphysent = 1;
	pmove.physents[0].model = sv.worldmodel;
	pmove.cmd = *ucmd;
	pmove.dead = sv_player->v.health <= 0;
	pmove.oldbuttons = host_client->oldbuttons;
	pmove.hasted = sv_player->v.hasted;
	pmove.movetype = sv_player->v.movetype;
	pmove.crouched = (sv_player->v.hull == HULL_CROUCH);
	pmove.teleport_time = realtime + (sv_player->v.teleport_time - sv.time);

//	movevars.entgravity = host_client->entgravity;
	movevars.entgravity = sv_player->v.gravity;
	movevars.maxspeed = host_client->maxspeed;

	for (i = 0; i < 3; i++)
	{
		pmove_mins[i] = pmove.origin[i] - 256;
		pmove_maxs[i] = pmove.origin[i] + 256;
	}
#if 1
	AddLinksToPmove ( sv_areanodes );
#else
	AddAllEntsToPmove ();
#endif

#if 0
	{
		int	before, after;

		before = PM_TestPlayerPosition (pmove.origin);
		PlayerMove ();
		after = PM_TestPlayerPosition (pmove.origin);

		if (sv_player->v.health > 0 && before && !after )
			Con_Printf ("player %s got stuck in playermove!!!!\n", host_client->name);
	}
#else
	PlayerMove ();
#endif

	host_client->oldbuttons = pmove.oldbuttons;
//	sv_player->v.teleport_time = pmove.waterjumptime;
	sv_player->v.waterlevel = waterlevel;
	sv_player->v.watertype = watertype;
	if (onground != -1)
	{
		sv_player->v.flags = (int)sv_player->v.flags | FL_ONGROUND;
		sv_player->v.groundentity = EDICT_TO_PROG(EDICT_NUM(pmove.physents[onground].info));
	}
	else
		sv_player->v.flags = (int)sv_player->v.flags & ~FL_ONGROUND;

	for (i = 0; i < 3; i++)
		sv_player->v.origin[i] = pmove.origin[i] - (sv_player->v.mins[i] - player_mins[i]);

#if 0
	// truncate velocity the same way the net protocol will
	for (i = 0; i < 3; i++)
		sv_player->v.velocity[i] = (int)pmove.velocity[i];
#else
	VectorCopy (pmove.velocity, sv_player->v.velocity);
#endif

	VectorCopy (pmove.angles, sv_player->v.v_angle);

	if (!host_client->spectator)
	{
		// link into place and touch triggers
		SV_LinkEdict (sv_player, true);

		// touch other objects
		for (i = 0; i < pmove.numtouch; i++)
		{
			n = pmove.physents[pmove.touchindex[i]].info;
			ent = EDICT_NUM(n);

		// Why not just do an SV_Impact here?
		//	SV_Impact(sv_player,ent);

			if (sv_player->v.touch)
			{
				pr_global_struct->self = EDICT_TO_PROG(sv_player);
				pr_global_struct->other = EDICT_TO_PROG(ent);
				PR_ExecuteProgram (sv_player->v.touch);
			}
			if (!ent->v.touch || (playertouch[n/8]&(1<<(n%8))))
				continue;
			pr_global_struct->self = EDICT_TO_PROG(ent);
			pr_global_struct->other = EDICT_TO_PROG(sv_player);
			PR_ExecuteProgram (ent->v.touch);
			playertouch[n/8] |= 1 << (n%8);
		}
	}
}
예제 #19
0
파일: g_spawn.c 프로젝트: Kiln707/KMQuake2
/*
==============
SpawnEntities

Creates a server's entity / program execution context by
parsing textual entity definitions out of an ent file.
==============
*/
void SpawnEntities (char *mapname, char *entities, char *spawnpoint)
{
	edict_t		*ent;
	int			inhibit;
	char		*com_token;
	int			i;
	float		skill_level;
	extern int	max_modelindex;
	extern int	max_soundindex;
	extern int	lastgibframe;

	if (developer->value)
		gi.dprintf("====== SpawnEntities ========\n");
	skill_level = floor (skill->value);
	if (skill_level < 0)
		skill_level = 0;
	if (skill_level > 3)
		skill_level = 3;
	if (skill->value != skill_level)
		gi.cvar_forceset("skill", va("%f", skill_level));

	SaveClientData ();

	gi.FreeTags (TAG_LEVEL);

	memset (&level, 0, sizeof(level));
	memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0]));
	// Lazarus: these are used to track model and sound indices
	//          in g_main.c:
	max_modelindex = 0;
	max_soundindex = 0;

	// Lazarus: last frame a gib was spawned in
	lastgibframe = 0;

	strncpy (level.mapname, mapname, sizeof(level.mapname)-1);
	strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1);

	// set client fields on player ents
	for (i=0 ; i<game.maxclients ; i++)
		g_edicts[i+1].client = game.clients + i;

	ent = NULL;
	inhibit = 0;

	// Knightamre- load the entity alias script file
	LoadAliasData();
	//gi.dprintf ("Size of alias data: %i\n", alias_data_size);

// parse ents
	while (1)
	{
		// parse the opening brace	
		com_token = COM_Parse (&entities);
		if (!entities)
			break;
		if (com_token[0] != '{')
			gi.error ("ED_LoadFromFile: found %s when expecting {",com_token);

		if (!ent)
			ent = g_edicts;
		else
			ent = G_Spawn ();
		entities = ED_ParseEdict (entities, ent);

		// yet another map hack
		if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27"))
			ent->spawnflags &= ~SPAWNFLAG_NOT_HARD;

		// remove things (except the world) from different skill levels or deathmatch
		if (ent != g_edicts)
		{
			if (deathmatch->value)
			{
				if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH )
				{
					G_FreeEdict (ent);	
					inhibit++;
					continue;
				}
			}
			else if (coop->value) // Knightmare added- not in coop flag support
			{
				if ( ent->spawnflags & SPAWNFLAG_NOT_COOP )
				{
					G_FreeEdict (ent);	
					inhibit++;
					continue;
				}

				// NOT_EASY && NOT_MEDIUM && NOT_HARD && NOT_DM == COOP_ONLY
				if ( (ent->spawnflags & SPAWNFLAG_NOT_EASY)
					&& (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)
					&& (ent->spawnflags & SPAWNFLAG_NOT_HARD)
					&& (ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH) )
					goto removeflags;

				if( ((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) ||
					((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) ||
					((skill->value >= 2) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) )
					{
						G_FreeEdict (ent);	
						inhibit++;
						continue;
					}
			}
			else // single player
			{
				if( ((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) ||
					((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) ||
					((skill->value >= 2) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) )
					{
						G_FreeEdict (ent);	
						inhibit++;
						continue;
					}
			}
removeflags:
			// Knightmare- remove no coop flag
			ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_DEATHMATCH|SPAWNFLAG_NOT_COOP);
		}

		ED_CallSpawn (ent);
		ent->s.renderfx |= RF_IR_VISIBLE; // ir goggles flag
	}	

	// Knightmare- unload the alias script file
	if (alias_data) { // If no alias file was loaded, don't bother
#ifdef KMQUAKE2_ENGINE_MOD // use new engine function instead
		gi.FreeFile(alias_data);
#else
//		if (alias_from_pak)
			gi.TagFree(alias_data);
//		else
//			free(&alias_data);
#endif
	}

	// Knightmare- unload the replacement entity data
/*	if (newents) // If no alias file was loaded, don't bother
#ifdef KMQUAKE2_ENGINE_MOD // use new engine function instead
		gi.FreeFile(newents);
#else
		free(&newents);
#endif*/

	gi.dprintf ("%i entities inhibited\n", inhibit);

#ifdef DEBUG
	i = 1;
	ent = EDICT_NUM(i);
	while (i < globals.num_edicts) {
		if (ent->inuse != 0 || ent->inuse != 1)
			Com_DPrintf("Invalid entity %d\n", i);
		i++, ent++;
	}
#endif

	G_FindTeams ();

	// DWH
	G_FindCraneParts ();

	// Get origin offsets (mainly for brush models w/o origin brushes)
	for (i=1, ent=g_edicts+i ; i < globals.num_edicts ; i++,ent++)
	{
		VectorAdd(ent->absmin,ent->absmax,ent->origin_offset);
		VectorScale(ent->origin_offset,0.5,ent->origin_offset);
		VectorSubtract(ent->origin_offset,ent->s.origin,ent->origin_offset);
	}

	// end DWH

	PlayerTrail_Init ();

//ZOID
	CTFSpawn();
	// Knightmare added
	if (deathmatch->value && !ctf->value)
		CTFSetupTechSpawn ();	
//ZOID

	if (!deathmatch->value)
		SetupHintPaths();

	for (i=1, ent=g_edicts+i; i < globals.num_edicts; i++, ent++)
	{
		if (!ent->movewith)
			continue;
		if (ent->movewith_ent)
			continue;
		ent->movewith_ent = G_Find(NULL, FOFS(targetname), ent->movewith);
		// Make sure that we can really "movewith" this guy. This check
		// allows us to have movewith parent with same targetname as
		// other entities
		while (ent->movewith_ent &&
			(Q_stricmp(ent->movewith_ent->classname,"func_train")     &&
			 Q_stricmp(ent->movewith_ent->classname,"model_train")    &&
			 Q_stricmp(ent->movewith_ent->classname,"func_door")      &&
			 Q_stricmp(ent->movewith_ent->classname,"func_vehicle")   &&
			 Q_stricmp(ent->movewith_ent->classname,"func_tracktrain")  ))
			 ent->movewith_ent = G_Find (ent->movewith_ent, FOFS(targetname), ent->movewith);
		if (ent->movewith_ent)
			movewith_init (ent->movewith_ent);
	}

/*	for(i=1, ent=g_edicts+i; i < globals.num_edicts; i++, ent++)
	{
		gi.dprintf("%s:%s - movewith=%s, movewith_ent=%s:%s, movewith_next=%s:%s\n====================\n",
			ent->classname, (ent->targetname ? ent->targetname : "noname"),
			(ent->movewith ? ent->movewith : "N/A"),
			(ent->movewith_ent ? ent->movewith_ent->classname : "N/A"),
			(ent->movewith_ent ? (ent->movewith_ent->targetname ? ent->movewith_ent->targetname : "noname") : "N/A"),
			(ent->movewith_next ? ent->movewith_next->classname : "N/A"),
			(ent->movewith_next ? (ent->movewith_next->targetname ? ent->movewith_next->targetname : "noname") : "N/A"));

	} */

	if (game.transition_ents)
		LoadTransitionEnts ();

	actor_files ();

}
예제 #20
0
/*
==================
SV_Begin_f
==================
*/
static void SV_Begin_f (void)
{
	int		i;

	host_client->state = cs_spawned;

	// handle the case of a level changing while a client was connecting
	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
	{
		Con_Printf ("%s from different level\n", __thisfunc__);
		SV_New_f ();
		return;
	}

	if (host_client->spectator)
	{
		SV_SpawnSpectator ();

		if (SpectatorConnect)
		{
			// copy spawn parms out of the client_t
			for (i = 0; i < NUM_SPAWN_PARMS; i++)
				(&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];

			// call the spawn function
			pr_global_struct->time = sv.time;
			pr_global_struct->self = EDICT_TO_PROG(sv_player);
			PR_ExecuteProgram (SpectatorConnect);
		}
	}
	else
	{
		// copy spawn parms out of the client_t
		for (i = 0; i < NUM_SPAWN_PARMS; i++)
			(&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];

		host_client->send_all_v = true;

		// call the spawn function
		pr_global_struct->time = sv.time;
		pr_global_struct->self = EDICT_TO_PROG(sv_player);
		PR_ExecuteProgram (pr_global_struct->ClientConnect);

		// actually spawn the player
		pr_global_struct->time = sv.time;
		pr_global_struct->self = EDICT_TO_PROG(sv_player);
		PR_ExecuteProgram (pr_global_struct->PutClientInServer);
	}

	// clear the net statistics, because connecting gives a bogus picture
	host_client->netchan.frame_latency = 0;
	host_client->netchan.frame_rate = 0;
	host_client->netchan.drop_count = 0;
	host_client->netchan.good_count = 0;
#if 0
//
// send a fixangle over the reliable channel to make sure it gets there
// 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( 1 + (host_client - svs.clients) );
	MSG_WriteByte (&host_client->netchan.message, svc_setangle);
	for (i = 0; i < 2; i++)
		MSG_WriteAngle (&host_client->netchan.message, ent->v.angles[i] );
	MSG_WriteAngle (&host_client->netchan.message, 0 );
#endif
}
예제 #21
0
/*
============
SV_PushRotate

============
*/
static edict_t *SV_PushRotate( edict_t *pusher, float movetime )
{
	int		i, e, block, oldsolid;
	matrix4x4		start_l, end_l;
	vec3_t		lmove, amove;
	sv_pushed_t	*p, *pushed_p;
	vec3_t		org, org2, temp;
	edict_t		*check;

	if( sv.state == ss_loading || VectorIsNull( pusher->v.avelocity ))
	{
		pusher->v.ltime += movetime;
		return NULL;
	}

	for( i = 0; i < 3; i++ )
		amove[i] = pusher->v.avelocity[i] * movetime;

	// create pusher initial position
	Matrix4x4_CreateFromEntity( start_l, pusher->v.angles, pusher->v.origin, 1.0f );

	pushed_p = svgame.pushed;

	// save the pusher's original position
	pushed_p->ent = pusher;
	VectorCopy( pusher->v.origin, pushed_p->origin );
	VectorCopy( pusher->v.angles, pushed_p->angles );
	pushed_p++;

	// move the pusher to it's final position
	SV_AngularMove( pusher, movetime, pusher->v.friction );
	SV_LinkEdict( pusher, false );
	pusher->v.ltime += movetime;
	oldsolid = pusher->v.solid;

	// non-solid pushers can't push anything
	if( pusher->v.solid == SOLID_NOT )
		return NULL;

	// create pusher final position
	Matrix4x4_CreateFromEntity( end_l, pusher->v.angles, pusher->v.origin, 1.0f );

	// see if any solid entities are inside the final position
	for( e = 1; e < svgame.numEntities; e++ )
	{
		check = EDICT_NUM( e );
		if( !SV_IsValidEdict( check )) continue;

		// filter movetypes to collide with
		if( !SV_CanPushed( check ))
			continue;

		pusher->v.solid = SOLID_NOT;
		block = SV_TestEntityPosition( check, pusher );
		pusher->v.solid = oldsolid;
		if( block ) continue;

		// if the entity is standing on the pusher, it will definately be moved
		if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher ))
		{
			if( check->v.absmin[0] >= pusher->v.absmax[0]
			|| check->v.absmin[1] >= pusher->v.absmax[1]
			|| check->v.absmin[2] >= pusher->v.absmax[2]
			|| check->v.absmax[0] <= pusher->v.absmin[0]
			|| check->v.absmax[1] <= pusher->v.absmin[1]
			|| check->v.absmax[2] <= pusher->v.absmin[2] )
				continue;

			// see if the ent's bbox is inside the pusher's final position
			if( !SV_TestEntityPosition( check, NULL ))
				continue;
		}

		// save original position of contacted entity
		pushed_p->ent = check;
		VectorCopy( check->v.origin, pushed_p->origin );
		VectorCopy( check->v.angles, pushed_p->angles );
		pushed_p->fixangle = check->v.fixangle;
		pushed_p++;

		// calculate destination position
		if( check->v.movetype == MOVETYPE_PUSHSTEP )
			VectorAverage( check->v.absmin, check->v.absmax, org );
		else VectorCopy( check->v.origin, org );

		Matrix4x4_VectorITransform( start_l, org, temp );
		Matrix4x4_VectorTransform( end_l, temp, org2 );
		VectorSubtract( org2, org, lmove );

		// try moving the contacted entity
		pusher->v.solid = SOLID_NOT;
		SV_PushEntity( check, lmove, amove, &block );
		pusher->v.solid = oldsolid;

		// if it is still inside the pusher, block
		if( SV_TestEntityPosition( check, NULL ) && block )
		{
			if( !SV_CanBlock( check ))
				continue;

			pusher->v.ltime -= movetime;

			// move back any entities we already moved
			// go backwards, so if the same entity was pushed
			// twice, it goes back to the original position
			for( p = pushed_p - 1; p >= svgame.pushed; p-- )
			{
				VectorCopy( p->origin, p->ent->v.origin );
				VectorCopy( p->angles, p->ent->v.angles );
				SV_LinkEdict( p->ent, (p->ent == check) ? true : false );
				p->ent->v.fixangle = p->fixangle;
			}
			return check;
		}
	}
	return NULL;
}
예제 #22
0
/*
==============
SV_InitGame

A brand new game has been started
==============
*/
void SV_InitGame (void)
{
	int		i;
	edict_t	*ent;
	char	idmaster[32];

	if (svs.initialized)
	{
		// cause any connected clients to reconnect
		SV_Shutdown ("Server restarted\n", true);
	}
	else
	{
		// make sure the client is down
		CL_Drop ();
		SCR_BeginLoadingPlaque ();
	}

	// get any latched variable changes (maxclients, etc)
	Cvar_GetLatchedVars ();

	svs.initialized = true;

	if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch"))
	{
		Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
		Cvar_FullSet ("coop", "0",  CVAR_SERVERINFO | CVAR_LATCH);
	}

	// dedicated servers are can't be single player and are usually DM
	// so unless they explicity set coop, force it to deathmatch
	if (dedicated->value)
	{
		if (!Cvar_VariableValue ("coop"))
			Cvar_FullSet ("deathmatch", "1",  CVAR_SERVERINFO | CVAR_LATCH);
	}

	// init clients
	if (Cvar_VariableValue ("deathmatch"))
	{
		if (maxclients->value <= 1)
			Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
		else if (maxclients->value > MAX_CLIENTS)
			Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
	}
	else if (Cvar_VariableValue ("coop"))
	{
		if (maxclients->value <= 1 || maxclients->value > 4)
			Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
#ifdef COPYPROTECT
		if (!sv.attractloop && !dedicated->value)
			Sys_CopyProtect ();
#endif
	}
	else	// non-deathmatch, non-coop is one player
	{
		Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
#ifdef COPYPROTECT
		if (!sv.attractloop)
			Sys_CopyProtect ();
#endif
	}

	svs.spawncount = rand();
	svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value);
	svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
	svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);

	// init network stuff
	NET_Config ( (maxclients->value > 1) );

	// heartbeats will always be sent to the id master
	svs.last_heartbeat = -99999;		// send immediately
	Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER);
	NET_StringToAdr (idmaster, &master_adr[0]);

	// init game
	SV_InitGameProgs ();
	for (i=0 ; i<maxclients->value ; i++)
	{
		ent = EDICT_NUM(i+1);
		ent->s.number = i+1;
		svs.clients[i].edict = ent;
		memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
	}
}
예제 #23
0
void ParseEntityString (qboolean respawn)
{
	edict_t		*ent;
	int			inhibit;
	const char	*com_token;
	const char	*entities;
	int			i;

	entities = level.entity_string;

	ent = NULL;
	inhibit = 0;
	i = 0;

	//mark all the spawned_entities as inuse so G_Spawn doesn't try to pick them during
	//trigger spawning etc
	for (i = 0; i < num_spawned_entities; i++)
		spawned_entities[i]->inuse = true;

	i = 0;

// parse ents
	while (1)
	{
		// parse the opening brace	
		com_token = COM_Parse (&entities);
		if (!entities)
			break;
		if (com_token[0] != '{')
			gi.error ("ED_LoadFromFile: found %s when expecting {",com_token);

		if (respawn)
		{
			ent = spawned_entities[i];
			if (ent != world)
			{
				//double check we aren't overwriting stuff that we shouldn't be
				if (ent->enttype == ENT_DOOR_TRIGGER || ent->enttype == ENT_PLAT_TRIGGER)
					TDM_Error ("ParseEntityString: Trying to reuse an already spawned ent!");
				G_FreeEdict (ent);
				G_InitEdict (ent);
			}
			i++;
		}
		else
		{
			if (!ent)
				ent = g_edicts;
			else
				ent = G_Spawn ();
		}
		entities = ED_ParseEdict (entities, ent);

		// yet another map hack
		if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27"))
			ent->spawnflags &= ~SPAWNFLAG_NOT_HARD;

		// remove things (except the world) from different skill levels or deathmatch
		if (ent != g_edicts)
		{
			if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH )
			{
				G_FreeEdict (ent);	
				inhibit++;

				//have to keep num_spawned in sync for respawn
				if (!respawn)
					spawned_entities[num_spawned_entities++] = ent;
				continue;
			}

			ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH);
		}
		else if (respawn)
			continue;

		ED_CallSpawn (ent);

		if (!respawn)
		{
			if (num_spawned_entities == MAX_EDICTS * 4)
				TDM_Error ("Exceeded MAX_EDICTS * 4 entities during entity string parse");
			spawned_entities[num_spawned_entities++] = ent;
		}
		else
		{
			//an elevator or something respawned on top of a player? don't do it for match start, since
			//players will be respawning anyway.
			if (tdm_match_status < MM_PLAYING && (ent->solid == SOLID_BBOX || ent->solid == SOLID_BSP))
			{
				edict_t	*touch[MAX_EDICTS];
				int		count;
				int		j;

				//r1: fix 00000196, can't killbox during map spawn due to risk of killing half-spawned
				//map entities. do a pseudo-killbox that only whacks players instead.

				count = gi.BoxEdicts (ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_SOLID);
				for (j = 0; j < count; j++)
				{
					if (touch[j] == ent)
						continue;

					//no point killing anything that won't clip (eg corpses)
					if (touch[j]->solid == SOLID_NOT || touch[j]->enttype == ENT_BODYQUE)
						continue;

					if (!touch[j]->client)
						continue;

					if (touch[j]->inuse)
						T_Damage (touch[j], ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
				}
			}
		}
	}

	//gi.dprintf ("%i entities inhibited\n", inhibit);

#ifdef DEBUG
	i = 1;
	ent = EDICT_NUM(i);
	while (i < globals.num_edicts) {
		if (ent->inuse != 0 || ent->inuse != 1)
			Com_DPrintf("Invalid entity %d\n", i);
		i++, ent++;
	}
#endif

	G_FindTeams ();
}
예제 #24
0
파일: sv_init.c 프로젝트: cfr/qfusion
/*
* SV_InitGame
* A brand new game has been started
*/
void SV_InitGame( void )
{
	int i;
	edict_t	*ent;
	netadr_t address, ipv6_address;
	bool socket_opened = false;

	// make sure the client is down
	CL_Disconnect( NULL );
	SCR_BeginLoadingPlaque();

	if( svs.initialized )
	{
		// cause any connected clients to reconnect
		SV_ShutdownGame( "Server restarted", true );

		// SV_ShutdownGame will also call Cvar_GetLatchedVars
	}
	else
	{
		// get any latched variable changes (sv_maxclients, etc)
		Cvar_GetLatchedVars( CVAR_LATCH );
	}

	svs.initialized = true;

	if( sv_skilllevel->integer > 2 )
		Cvar_ForceSet( "sv_skilllevel", "2" );
	if( sv_skilllevel->integer < 0 )
		Cvar_ForceSet( "sv_skilllevel", "0" );

	// init clients
	if( sv_maxclients->integer < 1 )
		Cvar_FullSet( "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH, true );
	else if( sv_maxclients->integer > MAX_CLIENTS )
		Cvar_FullSet( "sv_maxclients", va( "%i", MAX_CLIENTS ), CVAR_SERVERINFO | CVAR_LATCH, true );

	svs.spawncount = rand();
	svs.clients = Mem_Alloc( sv_mempool, sizeof( client_t )*sv_maxclients->integer );
	svs.client_entities.num_entities = sv_maxclients->integer * UPDATE_BACKUP * MAX_SNAP_ENTITIES;
	svs.client_entities.entities = Mem_Alloc( sv_mempool, sizeof( entity_state_t ) * svs.client_entities.num_entities );

	// init network stuff

	address.type = NA_NOTRANSMIT;
	ipv6_address.type = NA_NOTRANSMIT;

	if( !dedicated->integer )
	{
		NET_InitAddress( &address, NA_LOOPBACK );
		if( !NET_OpenSocket( &svs.socket_loopback, SOCKET_LOOPBACK, &address, true ) )
			Com_Error( ERR_FATAL, "Couldn't open loopback socket: %s\n", NET_ErrorString() );
	}

	if( dedicated->integer || sv_maxclients->integer > 1 )
	{
		// IPv4
		NET_StringToAddress( sv_ip->string, &address );
		NET_SetAddressPort( &address, sv_port->integer );
		if( !NET_OpenSocket( &svs.socket_udp, SOCKET_UDP, &address, true ) )
			Com_Printf( "Error: Couldn't open UDP socket: %s\n", NET_ErrorString() );
		else
			socket_opened = true;

		// IPv6
		NET_StringToAddress( sv_ip6->string, &ipv6_address );
		if( ipv6_address.type == NA_IP6 )
		{
			NET_SetAddressPort( &ipv6_address, sv_port6->integer );
			if( !NET_OpenSocket( &svs.socket_udp6, SOCKET_UDP, &ipv6_address, true ) )
				Com_Printf( "Error: Couldn't open UDP6 socket: %s\n", NET_ErrorString() );
			else
				socket_opened = true;
		}
		else
			Com_Printf( "Error: invalid IPv6 address: %s\n", sv_ip6->string );
	}

#ifdef TCP_ALLOW_CONNECT
	if( sv_tcp->integer && ( dedicated->integer || sv_maxclients->integer > 1 ) )
	{
		bool err = true;

		if( !NET_OpenSocket( &svs.socket_tcp, SOCKET_TCP, &address, true ) )
		{
			Com_Printf( "Error: Couldn't open TCP socket: %s\n", NET_ErrorString() );
		}
		else
		{
			NET_SetSocketNoDelay( &svs.socket_tcp, 1 );
			if( !NET_Listen( &svs.socket_tcp ) )
			{
				Com_Printf( "Error: Couldn't listen to TCP socket: %s\n", NET_ErrorString() );
				NET_CloseSocket( &svs.socket_tcp );
			}
			else
			{
				err = false;
				socket_opened = true;
			}
		}

		if( ipv6_address.type == NA_IP6 )
		{
			if( !NET_OpenSocket( &svs.socket_tcp6, SOCKET_TCP, &ipv6_address, true ) )
			{
				Com_Printf( "Error: Couldn't open TCP6 socket: %s\n", NET_ErrorString() );
			}
			else
			{
				NET_SetSocketNoDelay( &svs.socket_tcp6, 1 );
				if( !NET_Listen( &svs.socket_tcp6 ) )
				{
					Com_Printf( "Error: Couldn't listen to TCP6 socket: %s\n", NET_ErrorString() );
					NET_CloseSocket( &svs.socket_tcp6 );
				}
				else
				{
					err = false;
					socket_opened = true;
				}
			}
		}

		if( err ) {
			Cvar_ForceSet( "sv_tcp", "0" );
		}
	}
#endif

	if( dedicated->integer && !socket_opened )
		Com_Error( ERR_FATAL, "Couldn't open any socket\n" );

	// init mm
	// SV_MM_Init();

	// init game
	SV_InitGameProgs();
	for( i = 0; i < sv_maxclients->integer; i++ )
	{
		ent = EDICT_NUM( i+1 );
		ent->s.number = i+1;
		svs.clients[i].edict = ent;
	}

	// load the map
	assert( !svs.cms );
	svs.cms = CM_New( NULL );
	CM_AddReference( svs.cms );

	// keep CPU awake
	assert( !svs.wakelock );
	svs.wakelock = Sys_AcquireWakeLock();
}
예제 #25
0
/*
=============
ED_ParseEval

Can parse either fields or globals
returns false if error
=============
*/
static qboolean	ED_ParseEpair (void *base, ddef_t *key, const char *s)
{
	int		i;
	char	string[128];
	ddef_t	*def;
	char	*v, *w;
	void	*d;
	dfunction_t	*func;

	d = (void *)((int *)base + key->ofs);

	switch (key->type & ~DEF_SAVEGLOBAL)
	{
	case ev_string:
		*(string_t *)d = ED_NewString(s);
		break;

	case ev_float:
		*(float *)d = atof (s);
		break;

	case ev_vector:
		strcpy (string, s);
		v = string;
		w = string;
		for (i = 0; i < 3; i++)
		{
			while (*v && *v != ' ')
				v++;
			*v = 0;
			((float *)d)[i] = atof (w);
			w = v = v+1;
		}
		break;

	case ev_entity:
		*(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s)));
		break;

	case ev_field:
		def = ED_FindField (s);
		if (!def)
		{
			//johnfitz -- HACK -- suppress error becuase fog/sky fields might not be mentioned in defs.qc
			if (strncmp(s, "sky", 3) && strcmp(s, "fog"))
				Con_DPrintf ("Can't find field %s\n", s);
			return false;
		}
		*(int *)d = G_INT(def->ofs);
		break;

	case ev_function:
		func = ED_FindFunction (s);
		if (!func)
		{
			Con_Printf ("Can't find function %s\n", s);
			return false;
		}
		*(func_t *)d = func - pr_functions;
		break;

	default:
		break;
	}
	return true;
}
예제 #26
0
void SV_SaveGame_f (void) {
	char fname[MAX_OSPATH], comment[SAVEGAME_COMMENT_LENGTH+1];
	FILE *f;
	int i;

	if (Cmd_Argc() != 2) {
		Com_Printf ("Usage: %s <savefname> : save a game\n", Cmd_Argv(0));
		return;
	} else if (strstr(Cmd_Argv(1), "..")) {
		Com_Printf ("Relative pathfnames are not allowed.\n");
		return;
	} else if (sv.state != ss_active) {
		Com_Printf ("Not playing a local game.\n");
		return;
	} else if (cl.intermission) {
		Com_Printf ("Can't save in intermission.\n");
		return;
	} else if (deathmatch.value != 0 || coop.value != 0 || maxclients.value != 1) {
		Com_Printf ("Can't save multiplayer games.\n");
		return;
	}

	for (i = 1; i < MAX_CLIENTS; i++) {
		if (svs.clients[i].state == cs_spawned) {
			Com_Printf ("Can't save multiplayer games.\n");
			return;
		}
	}	

	if (svs.clients[0].state != cs_spawned) {
		Com_Printf ("Can't save, client #0 not spawned.\n");
		return;
	} else if (svs.clients[0].edict->v.health <= 0) {
		Com_Printf ("Can't save game with a dead player\n");
		// in fact, we can, but does it make sense?
		return;
	}

	snprintf (fname, sizeof(fname), "%s/save/%s", com_gamedir, Cmd_Argv(1));
	COM_DefaultExtension (fname, ".sav");
	
	Com_Printf ("Saving game to %s...\n", fname);
	if (!(f = fopen (fname, "w"))) {		
		FS_CreatePath (fname);
		if (!(f = fopen (fname, "w"))) {
			Com_Printf ("ERROR: couldn't open.\n");
			return;
		}
	}

	fprintf (f, "%i\n", SAVEGAME_VERSION);
	SV_SavegameComment (comment);
	fprintf (f, "%s\n", comment);
	for (i = 0 ; i < NUM_SPAWN_PARMS; i++)
		fprintf (f, "%f\n", svs.clients->spawn_parms[i]);
	fprintf (f, "%d\n", current_skill);
	fprintf (f, "%s\n", sv.mapname);
	fprintf (f, "%f\n", sv.time);

	// write the light styles
	for (i = 0; i < MAX_LIGHTSTYLES; i++) {
		if (sv.lightstyles[i])
			fprintf (f, "%s\n", sv.lightstyles[i]);
		else
			fprintf (f,"m\n");
	}

	ED_WriteGlobals (f);
	for (i = 0; i < sv.num_edicts; i++) {
		ED_Write (f, EDICT_NUM(i));
		fflush (f);
	}
	fclose (f);
	Com_Printf ("done.\n");
}
예제 #27
0
파일: pr_edict.cpp 프로젝트: luaman/zq
/*
=============
ED_ParseEval

Can parse either fields or globals
returns false if error
=============
*/
qbool ED_ParseEpair (void *base, ddef_t *key, char *s)
{
	int		i;
	char	string[128];
	ddef_t	*def;
	char	*v, *w;
	void	*d;
	dfunction_t	*func;
	
	d = (void *)((int *)base + key->ofs);
	
	switch (key->type & ~DEF_SAVEGLOBAL)
	{
	case ev_string:
		*(string_t *)d = PR_SetString(ED_NewString (s));
		break;
		
	case ev_float:
		*(float *)d = atof (s);
		break;
		
	case ev_vector:
		strlcpy (string, s, sizeof(string));
		v = string;
		w = string;
		for (i=0 ; i<3 ; i++)
		{
			while (*v && *v != ' ')
				v++;
			*v = 0;
			((float *)d)[i] = atof (w);
			w = v = v+1;
		}
		break;
		
	case ev_entity:
		*(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s)));
		break;
		
	case ev_field:
		def = ED_FindField (s);
		if (!def)
		{
			Com_Printf ("Can't find field %s\n", s);
			return false;
		}
		*(int *)d = G_INT(def->ofs);
		break;
	
	case ev_function:
		func = ED_FindFunction (s);
		if (!func)
		{
			Com_Printf ("Can't find function %s\n", s);
			return false;
		}
		*(func_t *)d = func - pr_functions;
		break;
		
	default:
		break;
	}
	return true;
}
예제 #28
0
파일: sv_main.c 프로젝트: AkBKukU/Quake-2
/*
==================
SVC_DirectConnect

A connection request that did not come from the master
==================
*/
void SVC_DirectConnect (void)
{
	char		userinfo[MAX_INFO_STRING];
	netadr_t	adr;
	int			i;
	client_t	*cl, *newcl;
	client_t	temp;
	edict_t		*ent;
	int			edictnum;
	int			version;
	int			qport;
	int			challenge;

	adr = net_from;

	Com_DPrintf ("SVC_DirectConnect ()\n");

	version = atoi(Cmd_Argv(1));
	if (version != PROTOCOL_VERSION)
	{
		Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is version %4.2f.\n", VERSION);
		Com_DPrintf ("    rejected connect from version %i\n", version);
		return;
	}

	qport = atoi(Cmd_Argv(2));

	challenge = atoi(Cmd_Argv(3));

	strncpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-1);
	userinfo[sizeof(userinfo) - 1] = 0;

	// force the IP key/value pair so the game can filter based on ip
	Info_SetValueForKey (userinfo, "ip", NET_AdrToString(net_from));

	// attractloop servers are ONLY for local clients
	if (sv.attractloop)
	{
		if (!NET_IsLocalAddress (adr))
		{
			Com_Printf ("Remote connect in attract loop.  Ignored.\n");
			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n");
			return;
		}
	}

	// see if the challenge is valid
	if (!NET_IsLocalAddress (adr))
	{
		for (i=0 ; i<MAX_CHALLENGES ; i++)
		{
			if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
			{
				if (challenge == svs.challenges[i].challenge)
					break;		// good
				Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nBad challenge.\n");
				return;
			}
		}
		if (i == MAX_CHALLENGES)
		{
			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nNo challenge for address.\n");
			return;
		}
	}

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

	// if there is already a slot for this ip, reuse it
	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
	{
		if (cl->state == cs_free)
			continue;
		if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
			&& ( cl->netchan.qport == qport 
			|| adr.port == cl->netchan.remote_address.port ) )
		{
			if (!NET_IsLocalAddress (adr) && (svs.realtime - cl->lastconnect) < ((int)sv_reconnect_limit->value * 1000))
			{
				Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (adr));
				return;
			}
			Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));
			newcl = cl;
			goto gotnewcl;
		}
	}

	// find a client slot
	newcl = NULL;
	for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
	{
		if (cl->state == cs_free)
		{
			newcl = cl;
			break;
		}
	}
	if (!newcl)
	{
		Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is full.\n");
		Com_DPrintf ("Rejected a connection.\n");
		return;
	}

gotnewcl:	
	// build a new connection
	// accept the new client
	// this is the only place a client_t is ever initialized
	*newcl = temp;
	sv_client = newcl;
	edictnum = (newcl-svs.clients)+1;
	ent = EDICT_NUM(edictnum);
	newcl->edict = ent;
	newcl->challenge = challenge; // save challenge for checksumming

	// get the game a chance to reject this connection or modify the userinfo
	if (!(ge->ClientConnect (ent, userinfo)))
	{
		if (*Info_ValueForKey (userinfo, "rejmsg")) 
			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\n%s\nConnection refused.\n",  
				Info_ValueForKey (userinfo, "rejmsg"));
		else
			Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n" );
		Com_DPrintf ("Game rejected a connection.\n");
		return;
	}

	// parse some info from the info strings
	strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1);
	SV_UserinfoChanged (newcl);

	// send the connect packet to the client
	Netchan_OutOfBandPrint (NS_SERVER, adr, "client_connect");

	Netchan_Setup (NS_SERVER, &newcl->netchan , adr, qport);

	newcl->state = cs_connected;
	
	SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf) );
	newcl->datagram.allowoverflow = true;
	newcl->lastmessage = svs.realtime;	// don't timeout
	newcl->lastconnect = svs.realtime;
}
예제 #29
0
void SV_LoadGame_f (void) {
	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, i, r;

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

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

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

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

	fscanf (f, "%s\n", str);
	for (i = 0; i < NUM_SPAWN_PARMS; i++)
		fscanf (f, "%f\n", &spawn_parms[i]);

	// this silliness is so we can load 1.06 save files, which have float skill values
	fscanf (f, "%f\n", &tfloat);
	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);

	fscanf (f, "%s\n", mapname);
	fscanf (f, "%f\n", &time);

	Host_EndGame();

	CL_BeginLocalConnection ();

	SV_SpawnServer (mapname, false);

	if (sv.state != ss_active) {
		Com_Printf ("Couldn't load map\n");
		return;
	}
	sv.paused = true;		// pause until all clients connect
	sv.loadgame = true;

	Sys_Error("The local server is currently broken. Sorry.");

	// load the light styles
	for (i = 0; i < MAX_LIGHTSTYLES; i++) {
		fscanf (f, "%s\n", str);
#if 0
		/* You need to fix that call */
		sv.lightstyles[i] = Junk_Alloc(strlen(str) + 1);
#endif
		strcpy (sv.lightstyles[i], str);
	}

	// 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);
			memset (&ent->v, 0, progs->entityfields * 4);
			ent->free = false;
			ED_ParseEdict (start, ent);
	
			// link it into the bsp tree
			if (!ent->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[0]->spawn_parms[i] = spawn_parms[i];
}
예제 #30
0
void SV_Begin_f (void)
{
	unsigned pmodel = 0, emodel = 0;
	int		i;

	if (host_client->state == cs_spawned)
		return; // don't begin again

	host_client->state = cs_spawned;
	
	// handle the case of a level changing while a client was connecting
	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
	{
		Con_Printf ("SV_Begin_f from different level\n");
		SV_New_f ();
		return;
	}

	if (host_client->spectator)
	{
		SV_SpawnSpectator ();

		if (SpectatorConnect) {
			// copy spawn parms out of the client_t
			for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
				(&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
	
			// call the spawn function
			pr_global_struct->time = sv.time;
			pr_global_struct->self = EDICT_TO_PROG(sv_player);
			PR_ExecuteProgram (SpectatorConnect);
		}
	}
	else
	{
		// copy spawn parms out of the client_t
		for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
			(&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];

		// call the spawn function
		pr_global_struct->time = sv.time;
		pr_global_struct->self = EDICT_TO_PROG(sv_player);
		PR_ExecuteProgram (pr_global_struct->ClientConnect);

		// actually spawn the player
		pr_global_struct->time = sv.time;
		pr_global_struct->self = EDICT_TO_PROG(sv_player);
		PR_ExecuteProgram (pr_global_struct->PutClientInServer);	
	}

	// clear the net statistics, because connecting gives a bogus picture
	host_client->netchan.frame_latency = 0;
	host_client->netchan.frame_rate = 0;
	host_client->netchan.drop_count = 0;
	host_client->netchan.good_count = 0;

	//check he's not cheating

	pmodel = atoi(Info_ValueForKey (host_client->userinfo, "pmodel"));
	emodel = atoi(Info_ValueForKey (host_client->userinfo, "emodel"));

	if (pmodel != sv.model_player_checksum ||
		emodel != sv.eyes_player_checksum)
		SV_BroadcastPrintf (PRINT_HIGH, "%s WARNING: non standard player/eyes model detected\n", host_client->name);

	// if we are paused, tell the client
	if (sv.paused) {
		ClientReliableWrite_Begin (host_client, svc_setpause, 2);
		ClientReliableWrite_Byte (host_client, sv.paused);
		SV_ClientPrintf(host_client, PRINT_HIGH, "Server is paused.\n");
	}

#if 0
//
// send a fixangle over the reliable channel to make sure it gets there
// 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( 1 + (host_client - svs.clients) );
	MSG_WriteByte (&host_client->netchan.message, svc_setangle);
	for (i=0 ; i < 2 ; i++)
		MSG_WriteAngle (&host_client->netchan.message, ent->v.angles[i] );
	MSG_WriteAngle (&host_client->netchan.message, 0 );
#endif
}