Beispiel #1
0
static HINSTANCE Sys_RetrieveDLL( const char *gamename )
{
	char *basepath = Cvar_VariableString( "fs_basepath" );
	char *homepath = Cvar_VariableString( "fs_homepath" );
	char *cdpath = Cvar_VariableString( "fs_cdpath" );
	char *gamedir = Cvar_VariableString( "fs_game" );

	// Try basepath/fs_game
	char *fn = FS_BuildOSPath( basepath, gamedir, gamename );
	HINSTANCE retVal = LoadLibrary( fn );
	if(retVal)
		goto successful;

	if( homepath[0] ) {
		// Try homepath/fs_game
		fn = FS_BuildOSPath( homepath, gamedir, gamename );
		retVal = LoadLibrary( fn );
		if(retVal)
			goto successful;
	}

	if( cdpath[0] ) {
		// Try cdpath/fs_game
		fn = FS_BuildOSPath( cdpath, gamedir, gamename );
		retVal = LoadLibrary( fn );
		if(retVal)
			goto successful;
	}

	// Try base folder if mod is loaded but not found
	if (gamedir[0] ) {
		// Try basepath/base
		fn = FS_BuildOSPath( basepath, OPENJKGAME, gamename );
		retVal = LoadLibrary( fn );
		if(retVal)
			goto successful;

		if( homepath[0] ) {
			// Try homepath/base
			fn = FS_BuildOSPath( homepath, OPENJKGAME, gamename );
			retVal = LoadLibrary( fn );
			if(retVal)
				goto successful;
		}

		if( cdpath[0] ) {
			// Try cdpath/fs_game
			fn = FS_BuildOSPath( cdpath, OPENJKGAME, gamename );
			retVal = LoadLibrary( fn );
			if(retVal)
				goto successful;
		}
	}

	// Try basepath
	fn = va( "%s/%s", basepath, gamename );
	retVal = LoadLibrary( fn );
	if(retVal)
		goto successful;

	if( homepath[0] ) {
		// Try homepath
		fn = va( "%s/%s", homepath, gamename );
		retVal = LoadLibrary( fn );
		if(retVal)
			goto successful;
	}

	if( cdpath[0] ) {
		// Try cdpath/fs_game
		fn = va( "%s/%s", cdpath, gamename );
		retVal = LoadLibrary( fn );
		if(retVal)
			goto successful;
	}

#ifdef _DEBUG
	// Try exepath (cwd)
	fn = NULL;
	retVal = LoadLibrary( gamename );
	if(retVal)
		goto successful;
#endif

successful:
	Com_DPrintf("LoadLibrary (%s)\n", fn?fn:gamename);
	return retVal;
}
Beispiel #2
0
/*
==============
SV_ServerRecord_f

Begins server demo recording.  Every entity and every message will be
recorded, but no playerinfo will be stored.  Primarily for demo merging.
==============
*/
void SV_ServerRecord_f (void)
{
	char	name[MAX_OSPATH];
	byte	buf_data[32768];
	sizebuf_t	buf;
	int		len;
	int		i;

	if (Cmd_Argc() != 2)
	{
		Com_Printf ("serverrecord <demoname>\n");
		return;
	}

	if (svs.demofile)
	{
		Com_Printf ("Already recording.\n");
		return;
	}

	if (sv.state != ss_game)
	{
		Com_Printf ("You must be in a level to record.\n");
		return;
	}

	//
	// open the demo file
	//
	Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));

	Com_Printf ("recording to %s.\n", name);
	FS_CreatePath (name);
	svs.demofile = fopen (name, "wb");
	if (!svs.demofile)
	{
		Com_Printf ("ERROR: couldn't open.\n");
		return;
	}

	// setup a buffer to catch all multicasts
	SZ_Init (&svs.demo_multicast, svs.demo_multicast_buf, sizeof(svs.demo_multicast_buf));

	//
	// write a single giant fake message with all the startup info
	//
	SZ_Init (&buf, buf_data, sizeof(buf_data));

	//
	// serverdata needs to go over for all types of servers
	// to make sure the protocol is right, and to set the gamedir
	//
	// send the serverdata
	MSG_WriteByte (&buf, svc_serverdata);
	MSG_WriteLong (&buf, PROTOCOL_VERSION);
	MSG_WriteLong (&buf, svs.spawncount);
	// 2 means server demo
	MSG_WriteByte (&buf, 2);	// demos are always attract loops
	MSG_WriteString (&buf, Cvar_VariableString ("gamedir"));
	MSG_WriteShort (&buf, -1);
	// send full levelname
	MSG_WriteString (&buf, sv.configstrings[CS_NAME]);

	for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
		if (sv.configstrings[i][0])
		{
			MSG_WriteByte (&buf, svc_configstring);
			MSG_WriteShort (&buf, i);
			MSG_WriteString (&buf, sv.configstrings[i]);
		}

	// write it to the demo file
	Com_DPrintf ("signon message length: %i\n", buf.cursize);
	len = LittleLong (buf.cursize);
	fwrite (&len, 4, 1, svs.demofile);
	fwrite (buf.data, buf.cursize, 1, svs.demofile);

	// the rest of the demo file will be individual frames
}
/*
Start a server-side demo.

This does it all, create the file and adjust the demo-related
stuff in client_t.

This is mostly ripped from sv_client.c/SV_SendClientGameState
and cl_main.c/CL_Record_f.
*/
static void SVD_StartDemoFile(client_t *client, const char *path) {

    int             i, len;
    entityState_t   *base, nullstate;
    msg_t           msg;
    byte            buffer[MAX_MSGLEN];
    fileHandle_t    file;
#ifdef USE_DEMO_FORMAT_42
    char            *s;
    int             v, size;
#endif

    Com_DPrintf("SVD_StartDemoFile\n");
    assert(!client->demo_recording);

    // create the demo file and write the necessary header
    file = FS_FOpenFileWrite(path);
    assert(file != 0);

    /* File_write_header_demo // ADD this fx */
    /* HOLBLIN  entete demo */
    #ifdef USE_DEMO_FORMAT_42
        //@Barbatos: get the mod version from the server
        s = Cvar_VariableString("g_modversion");

        size = strlen(s);
        len = LittleLong(size);
        FS_Write(&len, 4, file);
        FS_Write(s, size, file);

        v = LittleLong(DEMO_VERSION);
        FS_Write (&v, 4, file);

        len = 0;
        len = LittleLong(len);
        FS_Write(&len, 4, file);
        FS_Write(&len, 4, file);
    #endif
    /* END HOLBLIN  entete demo */

    MSG_Init(&msg, buffer, sizeof(buffer));
    MSG_Bitstream(&msg); // XXX server code doesn't do this, client code does
    MSG_WriteLong(&msg, client->lastClientCommand); // TODO: or is it client->reliableSequence?
    MSG_WriteByte(&msg, svc_gamestate);
    MSG_WriteLong(&msg, client->reliableSequence);

    for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
        if (sv.configstrings[i][0]) {
            MSG_WriteByte(&msg, svc_configstring);
            MSG_WriteShort(&msg, i);
            MSG_WriteBigString(&msg, sv.configstrings[i]);
        }
    }

    Com_Memset(&nullstate, 0, sizeof(nullstate));
    for (i = 0 ; i < MAX_GENTITIES; i++) {
        base = &sv.svEntities[i].baseline;
        if (!base->number) {
            continue;
        }
        MSG_WriteByte(&msg, svc_baseline);
        MSG_WriteDeltaEntity(&msg, &nullstate, base, qtrue);
    }

    MSG_WriteByte(&msg, svc_EOF);
    MSG_WriteLong(&msg, client - svs.clients);
    MSG_WriteLong(&msg, sv.checksumFeed);
    MSG_WriteByte(&msg, svc_EOF); // XXX server code doesn't do this, SV_Netchan_Transmit adds it!

    len = LittleLong(client->netchan.outgoingSequence - 1);
    FS_Write(&len, 4, file);

    len = LittleLong (msg.cursize);
    FS_Write(&len, 4, file);
    FS_Write(msg.data, msg.cursize, file);

    #ifdef USE_DEMO_FORMAT_42
        // add size of packet in the end for backward play /* holblin */
        FS_Write(&len, 4, file);
    #endif

    FS_Flush(file);

    // adjust client_t to reflect demo started
    client->demo_recording = qtrue;
    client->demo_file = file;
    client->demo_waiting = qtrue;
    client->demo_backoff = 1;
    client->demo_deltas = 0;
}
Beispiel #4
0
/*
==================
CL_SystemInfoChanged

The systeminfo configstring has been changed, so parse
new information out of it.  This will happen at every
gamestate, and possibly during gameplay.
==================
*/
void CL_SystemInfoChanged( void ) {
	char			*systemInfo;
	const char		*s, *t;
	char			key[BIG_INFO_KEY];
	char			value[BIG_INFO_VALUE];
	qboolean		gameSet;

	systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ];
	// NOTE TTimo:
	// when the serverId changes, any further messages we send to the server will use this new serverId
	// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
	// in some cases, outdated cp commands might get sent with this news serverId
	cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) );

	// don't set any vars when playing a demo
	if ( clc.demoplaying ) {
		return;
	}

#ifdef USE_VOIP
#ifdef LEGACY_PROTOCOL
	if(clc.compat)
		clc.voipEnabled = qfalse;
	else
#endif
	{
		s = Info_ValueForKey( systemInfo, "sv_voip" );
		if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive"))
			clc.voipEnabled = qfalse;
		else
			clc.voipEnabled = atoi(s);
	}
#endif

	s = Info_ValueForKey( systemInfo, "sv_cheats" );
	cl_connectedToCheatServer = atoi( s );
	if ( !cl_connectedToCheatServer ) {
		Cvar_SetCheatState();
	}

	// check pure server string
	s = Info_ValueForKey( systemInfo, "sv_paks" );
	t = Info_ValueForKey( systemInfo, "sv_pakNames" );
	FS_PureServerSetLoadedPaks( s, t );

	s = Info_ValueForKey( systemInfo, "sv_referencedPaks" );
	t = Info_ValueForKey( systemInfo, "sv_referencedPakNames" );
	FS_PureServerSetReferencedPaks( s, t );

	gameSet = qfalse;
	// scan through all the variables in the systeminfo and locally set cvars to match
	s = systemInfo;
	while ( s ) {
		int cvar_flags;
		
		Info_NextPair( &s, key, value );
		if ( !key[0] ) {
			break;
		}
		
		// ehw!
		if (!Q_stricmp(key, "fs_game"))
		{
			if(FS_CheckDirTraversal(value))
			{
				Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value);
				continue;
			}
				
			gameSet = qtrue;
		}

		if((cvar_flags = Cvar_Flags(key)) == CVAR_NONEXISTENT)
			Cvar_Get(key, value, CVAR_SERVER_CREATED | CVAR_ROM);
		else
		{
			// If this cvar may not be modified by a server discard the value.
			if(!(cvar_flags & (CVAR_SYSTEMINFO | CVAR_SERVER_CREATED | CVAR_USER_CREATED)))
			{
//#ifndef STANDALONE
				if(Q_stricmp(key, "g_synchronousClients") && Q_stricmp(key, "pmove_fixed") &&
				   Q_stricmp(key, "pmove_msec"))
//#endif
				{
					Com_Printf(S_COLOR_YELLOW "WARNING: server is not allowed to set %s=%s\n", key, value);
					continue;
				}
			}

			Cvar_SetSafe(key, value);
		}
	}
	// if game folder should not be set and it is set at the client side
	if ( !gameSet && *Cvar_VariableString("fs_game") ) {
		Cvar_Set( "fs_game", "" );
	}
	cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" );
}
Beispiel #5
0
/**
 * @brief A download message has been received from the server
 */
void CL_ParseDownload(msg_t *msg)
{
	int           size;
	unsigned char data[MAX_MSGLEN];
	int           block;

	if (!*cls.download.downloadTempName)
	{
		Com_Printf("Server sending download, but no download was requested\n");
		CL_AddReliableCommand("stopdl");
		return;
	}

	// read the data
	block = MSG_ReadShort(msg);

	// unfortunately DLTYPE_WWW is -1 FIXME: change this someday!
	//if (block < 0)
	//{
	//Com_Error(ERR_DROP, "CL_ParseDownload: Server sending invalid download data");
	//}

	// www dl, if we haven't acknowledged the download redirect yet
	if (block == DLTYPE_WWW)
	{
		if (!cls.download.bWWWDl)
		{
			// server is sending us a www download
			Q_strncpyz(cls.download.originalDownloadName, cls.download.downloadName, sizeof(cls.download.originalDownloadName));
			Q_strncpyz(cls.download.downloadName, MSG_ReadString(msg), sizeof(cls.download.downloadName));
			cls.download.downloadSize  = MSG_ReadLong(msg);
			cls.download.downloadFlags = MSG_ReadLong(msg);
			if (cls.download.downloadFlags & (1 << DL_FLAG_URL))
			{
				Sys_OpenURL(cls.download.downloadName, qtrue);
				Cbuf_ExecuteText(EXEC_APPEND, "quit\n");
				CL_AddReliableCommand("wwwdl bbl8r");   // not sure if that's the right msg
				cls.download.bWWWDlAborting = qtrue;
				return;
			}
			Cvar_SetValue("cl_downloadSize", cls.download.downloadSize);
			Com_DPrintf("Server redirected download: %s\n", cls.download.downloadName);
			cls.download.bWWWDl = qtrue; // activate wwwdl client loop
			CL_AddReliableCommand("wwwdl ack");
			// make sure the server is not trying to redirect us again on a bad checksum
			if (strstr(cls.download.badChecksumList, va("@%s", cls.download.originalDownloadName)))
			{
				Com_Printf("refusing redirect to %s by server (bad checksum)\n", cls.download.downloadName);
				CL_AddReliableCommand("wwwdl fail");
				cls.download.bWWWDlAborting = qtrue;
				return;
			}
			// make downloadTempName an OS path
			Q_strncpyz(cls.download.downloadTempName, FS_BuildOSPath(Cvar_VariableString("fs_homepath"), cls.download.downloadTempName, ""), sizeof(cls.download.downloadTempName));
			cls.download.downloadTempName[strlen(cls.download.downloadTempName) - 1] = '\0';
			if (!DL_BeginDownload(cls.download.downloadTempName, cls.download.downloadName))
			{
				// setting bWWWDl to false after sending the wwwdl fail doesn't work
				// not sure why, but I suspect we have to eat all remaining block -1 that the server has sent us
				// still leave a flag so that CL_WWWDownload is inactive
				// we count on server sending us a gamestate to start up clean again
				CL_AddReliableCommand("wwwdl fail");
				cls.download.bWWWDlAborting = qtrue;
				Com_Printf("Failed to initialize download for '%s'\n", cls.download.downloadName);
			}
			// Check for a disconnected download
			// we'll let the server disconnect us when it gets the bbl8r message
			if (cls.download.downloadFlags & (1 << DL_FLAG_DISCON))
			{
				CL_AddReliableCommand("wwwdl bbl8r");
				cls.download.bWWWDlDisconnected = qtrue;
			}
			return;
		}
		else
		{
			// server keeps sending that message till we acknowledge it, eat and ignore
			//MSG_ReadLong( msg );
			MSG_ReadString(msg);
			MSG_ReadLong(msg);
			MSG_ReadLong(msg);
			return;
		}
	}

	if (!block)
	{
		// block zero is special, contains file size
		cls.download.downloadSize = MSG_ReadLong(msg);

		Cvar_SetValue("cl_downloadSize", cls.download.downloadSize);

		if (cls.download.downloadSize < 0)
		{
			Com_Error(ERR_DROP, "%s", MSG_ReadString(msg));
			return;
		}
	}

	size = MSG_ReadShort(msg);
	if (size < 0 || size > sizeof(data))
	{
		Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size);
		return;
	}

	MSG_ReadData(msg, data, size);

	if (cls.download.downloadBlock != block)
	{
		Com_DPrintf("CL_ParseDownload: Expected block %d, got %d\n", cls.download.downloadBlock, block);
		return;
	}

	// open the file if not opened yet
	if (!cls.download.download)
	{
		cls.download.download = FS_SV_FOpenFileWrite(cls.download.downloadTempName);

		if (!cls.download.download)
		{
			Com_Printf("Could not create %s\n", cls.download.downloadTempName);
			CL_AddReliableCommand("stopdl");
			Com_NextDownload();
			return;
		}
	}

	if (size)
	{
		FS_Write(data, size, cls.download.download);
	}

	CL_AddReliableCommand(va("nextdl %d", cls.download.downloadBlock));
	cls.download.downloadBlock++;

	cls.download.downloadCount += size;

	// So UI gets access to it
	Cvar_SetValue("cl_downloadCount", cls.download.downloadCount);

	if (!size)     // A zero length block means EOF
	{
		if (cls.download.download)
		{
			FS_FCloseFile(cls.download.download);
			cls.download.download = 0;

			// rename the file
			FS_SV_Rename(cls.download.downloadTempName, cls.download.downloadName);
		}
		*cls.download.downloadTempName = *cls.download.downloadName = 0;
		Cvar_Set("cl_downloadName", "");

		// send intentions now
		// We need this because without it, we would hold the last nextdl and then start
		// loading right away.  If we take a while to load, the server is happily trying
		// to send us that last block over and over.
		// Write it twice to help make sure we acknowledge the download
		CL_WritePacket();
		CL_WritePacket();

		// get another file if needed
		Com_NextDownload();
	}
}
Beispiel #6
0
/*
==============
Win_PrintCvarMatches

ydnar: to display cvar values
==============
*/
static void Win_PrintCvarMatches( const char *s ) {
	if ( !Q_stricmpn( s, win_currentMatch, win_acLength ) ) {
		Sys_Print( va( "  ^9%s = ^5%s^0\n", s, Cvar_VariableString( s ) ) );
	}
}
Beispiel #7
0
/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f( void ) {
	int i;
	client_t    *client;
	char        *denied;
	qboolean isBot;
	int delay = 0;
	gamestate_t new_gs, old_gs;     // NERVE - SMF
	int worldspawnflags;            // DHM - Nerve
	int nextgt;                     // DHM - Nerve
	sharedEntity_t  *world;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId ) {
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( sv.restartTime ) {
		return;
	}

	// DHM - Nerve :: Check for invalid gametype
	sv_gametype = Cvar_Get( "g_gametype", "5", CVAR_SERVERINFO | CVAR_LATCH );
	nextgt = sv_gametype->integer;

	world = SV_GentityNum( ENTITYNUM_WORLD );
	worldspawnflags = world->r.worldflags;
	if  (
		( nextgt == GT_WOLF && ( worldspawnflags & 1 ) ) ||
		( nextgt == GT_WOLF_STOPWATCH && ( worldspawnflags & 2 ) ) ||
		( ( nextgt == GT_WOLF_CP || nextgt == GT_WOLF_CPH ) && ( worldspawnflags & 4 ) )
		) {

		if ( !( worldspawnflags & 1 ) ) {
			Cvar_Set( "g_gametype", "5" );
		} else {
			Cvar_Set( "g_gametype", "7" );
		}

		sv_gametype = Cvar_Get( "g_gametype", "5", CVAR_SERVERINFO | CVAR_LATCH );
	}
	// dhm

	if ( Cmd_Argc() > 1 ) {
		delay = atoi( Cmd_Argv( 1 ) );
	}

	if ( delay ) {
		sv.restartTime = svs.time + delay * 1000;
		SV_SetConfigstring( CS_WARMUP, va( "%i", sv.restartTime ) );
		return;
	}

	// NERVE - SMF - read in gamestate or just default to GS_PLAYING
	old_gs = atoi( Cvar_VariableString( "gamestate" ) );

	if ( Cmd_Argc() > 2 ) {
		new_gs = atoi( Cmd_Argv( 2 ) );
	} else {
		new_gs = GS_PLAYING;
	}

	if ( !SV_TransitionGameState( new_gs, old_gs, delay ) ) {
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified ) {
		char mapname[MAX_QPATH];

		Com_Printf( "sv_maxclients variable change -- restarting.\n" );
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );

		SV_SpawnServer( mapname, qfalse );
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid
	// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) );

	// reset all the vm data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = SS_LOADING;
	sv.restarting = qtrue;

	Cvar_Set( "sv_serverRestarting", "1" );

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for ( i = 0 ; i < 3 ; i++ ) {
		VM_Call( gvm, GAME_RUN_FRAME, svs.time );
		svs.time += 100;
	}

	sv.state = SS_GAME;
	sv.restarting = qfalse;

	// connect and begin all the clients
	for ( i = 0 ; i < sv_maxclients->integer ; i++ ) {
		client = &svs.clients[i];

		// send the new gamestate to all connected clients
		if ( client->state < CS_CONNECTED ) {
			continue;
		}

		if ( client->netchan.remoteAddress.type == NA_BOT ) {
			isBot = qtrue;
		} else {
			isBot = qfalse;
		}

		// add the map_restart command
		SV_AddServerCommand( client, "map_restart\n" );

		// connect the client again, without the firstTime flag
		denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) );
		if ( denied ) {
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient( client, denied );
			Com_Printf( "SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i ); // bk010125
			continue;
		}

		client->state = CS_ACTIVE;

		SV_ClientEnterWorld( client, &client->lastUsercmd );
	}

	// run another frame to allow things to look at all the players
	VM_Call( gvm, GAME_RUN_FRAME, svs.time );
	svs.time += 100;

	Cvar_Set( "sv_serverRestarting", "0" );
}
Beispiel #8
0
const char *FS_ReferencedUpdateName() {
	char *fs_game = Cvar_VariableString("fs_game");
	if(!*fs_game)
		fs_game = "main";
	return va("%s/%s", fs_game, CL_UPDATE_PAK_BASENAME);
}
Beispiel #9
0
/*
================
SVC_Info

Responds with a short info message that should be enough to determine
if a user is interested in a server to do a full status
================
*/
void SVC_Info( netadr_t from ) {
	int i, count;
	char    *gamedir;
	char infostring[MAX_INFO_STRING];
	char    *antilag;

	// DHM - Nerve
#ifdef UPDATE_SERVER
	return;
#endif

	// ignore if we are in single player
	if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) {
		return;
	}

	// don't count privateclients
	count = 0;
	for ( i = sv_privateClients->integer ; i < sv_maxclients->integer ; i++ ) {
		if ( svs.clients[i].state >= CS_CONNECTED ) {
			count++;
		}
	}

	infostring[0] = 0;

	// echo back the parameter to status. so servers can use it as a challenge
	// to prevent timed spoofed reply packets that add ghost servers
	Info_SetValueForKey( infostring, "challenge", Cmd_Argv( 1 ) );

	Info_SetValueForKey( infostring, "protocol", va( "%i", PROTOCOL_VERSION ) );
	Info_SetValueForKey( infostring, "hostname", sv_hostname->string );
	Info_SetValueForKey( infostring, "mapname", sv_mapname->string );
	Info_SetValueForKey( infostring, "clients", va( "%i", count ) );
	Info_SetValueForKey( infostring, "sv_maxclients",
						 va( "%i", sv_maxclients->integer - sv_privateClients->integer ) );
	Info_SetValueForKey( infostring, "gametype", va( "%i", sv_gametype->integer ) );
	Info_SetValueForKey( infostring, "pure", va( "%i", sv_pure->integer ) );

	if ( sv_minPing->integer ) {
		Info_SetValueForKey( infostring, "minPing", va( "%i", sv_minPing->integer ) );
	}
	if ( sv_maxPing->integer ) {
		Info_SetValueForKey( infostring, "maxPing", va( "%i", sv_maxPing->integer ) );
	}
	gamedir = Cvar_VariableString( "fs_game" );
	if ( *gamedir ) {
		Info_SetValueForKey( infostring, "game", gamedir );
	}
	Info_SetValueForKey( infostring, "sv_allowAnonymous", va( "%i", sv_allowAnonymous->integer ) );

	// Rafael gameskill
	Info_SetValueForKey( infostring, "gameskill", va( "%i", sv_gameskill->integer ) );
	// done

	Info_SetValueForKey( infostring, "friendlyFire", va( "%i", sv_friendlyFire->integer ) );        // NERVE - SMF
	Info_SetValueForKey( infostring, "maxlives", va( "%i", sv_maxlives->integer ? 1 : 0 ) );        // NERVE - SMF
	Info_SetValueForKey( infostring, "tourney", va( "%i", sv_tourney->integer ) );              // NERVE - SMF
	Info_SetValueForKey( infostring, "gamename", GAMENAME_STRING );                               // Arnout: to be able to filter out Quake servers

	// TTimo
	antilag = Cvar_VariableString( "g_antilag" );
	if ( antilag ) {
		Info_SetValueForKey( infostring, "g_antilag", antilag );
	}

	NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring );
}
Beispiel #10
0
/**
 * @brief Recursively removes files matching a given pattern from homepath.
 *
 * Useful for removing incomplete downloads and other garbage.
 * Files listed in the com_cleanWhitelist cvar are protected from deletion.
 * Additionally, executable and configuration files are protected unless 'force'
 * argument is passed to this command.
 */
void Cmd_CleanHomepath_f(void)
{
	int      i, j, patternFiles = 0, delFiles = 0, totalFiles = 0;
	char     path[MAX_OSPATH];
	qboolean force = qfalse, pretend = qfalse;

	// *.so and *.dll are denied per default in FS_Remove but throw a Com_Error() -> game aborts
	const char whitelist[] = ".txt .cfg .dat .gm .way .so .dll";

	if (Cmd_Argc() < 3)
	{
		// files in fs_homepath are downloaded again when required - but better print a warning for inexperienced users
		Com_Printf("usage: clean [force | pretend] [modname / all] [pattern 1] [pattern n]\n"
		           "example: clean all *tmp */zzz* etmain/etkey\n"
		           "Warning: This command deletes files in fs_homepath. If you are not sure how to use this command do not play with fire!\n");
		return;
	}

	// if home- and basepath are same better don't start to clean ...
	if (FS_IsSamePath(Cvar_VariableString("fs_homepath"), Cvar_VariableString("fs_basepath")))
	{
		Com_Printf("Invalid configuration to run clean cmd - 'fs_homepath' and 'fs_basepath' are equal.\n");
		return;
	}

	// avoid unreferenced pk3 runtime issues (not on HD but still referenced in game)
#ifndef DEDICATED
	if (cls.state != CA_DISCONNECTED)
	{
		Com_Printf("You are connected to a server - enter '/disconnect' to run '/clean'.\n");
		return;
	}
#else
	if (com_sv_running && com_sv_running->integer)
	{
		Com_Printf("Server is running - enter '/killserver' to run '/clean'.\n");
		return;
	}
#endif // DEDICATED

	Cvar_VariableStringBuffer("fs_homepath", path, sizeof(path));

	// if there are any command options, they must be at the very beginning
	for (i = 1; i < Cmd_Argc(); i++)
	{
		if (!Q_stricmp(Cmd_Argv(i), "force") || !Q_stricmp(Cmd_Argv(i), "f"))
		{
			force = qtrue;
			continue;
		}

		if (!Q_stricmp(Cmd_Argv(i), "pretend") || !Q_stricmp(Cmd_Argv(i), "p"))
		{
			pretend = qtrue;
			continue;
		}

		break;
	}

	// if the first argument is "all" or "*", search the whole homepath
	if (Q_stricmp(Cmd_Argv(i), "all") && Q_stricmp(Cmd_Argv(i), "*"))
	{
		Q_strcat(path, sizeof(path), va("%c%s", PATH_SEP, Cmd_Argv(i)));

		// check if it points to a valid directory
		if (FS_OSStatFile(path) != 1)
		{
			Com_Printf("Cannot commence cleaning, because \"%s\" is not a valid directory under fs_homepath (%s)\n", Cmd_Argv(i), path);
			return;
		}
	}

	for (i++; i < Cmd_Argc(); i++)
	{
		char **pFiles = NULL;

		pFiles = Sys_ListFiles(path, NULL, Cmd_Argv(i), &patternFiles, qtrue);

		Com_Printf("Found %i files matching the pattern \"%s\" under %s\n", patternFiles, Cmd_Argv(i), path);

		for (j = 0; j < patternFiles; j++)
		{
			char     *tokens;
			char     tmp_whitelist[MAX_OSPATH];
			qboolean whitelisted = qfalse;

			totalFiles++;

			Q_strncpyz(tmp_whitelist, (force ? Cvar_VariableString("com_cleanwhitelist") : va("%s %s", Cvar_VariableString("com_cleanwhitelist"), whitelist)), sizeof(tmp_whitelist));

			// Check if this file is in the whitelist
			tokens = strtok(tmp_whitelist, " ,;");

			while (tokens != NULL)
			{
				if (strstr(pFiles[j], tokens))
				{
					Com_Printf("- skipping file[%i]: %s%c%s (whitelisted by pattern: %s)\n", j + 1, path, PATH_SEP, pFiles[j], tokens);
					whitelisted = qtrue;
					break;
				}
				tokens = strtok(NULL, " ,;");
			}

			if (whitelisted)
			{
				continue;
			}

			if (!pretend)
			{
				Com_Printf("- removing file[%i]: %s%c%s\n", j + 1, path, PATH_SEP, pFiles[j]);

				if (force)
				{
					remove(va("%s%c%s", path, PATH_SEP, pFiles[j])); // enable *.so & *.dll lib deletion
				}
				else
				{
					FS_Remove(va("%s%c%s", path, PATH_SEP, pFiles[j]));
				}
				delFiles++;
			}
			else
			{
				Com_Printf("- pretending to remove file[%i]: %s%c%s\n", j + 1, path, PATH_SEP, pFiles[j]);
			}
		}

		Sys_FreeFileList(pFiles);
		patternFiles = 0;
	}
	Com_Printf("Path of fs_homepath cleaned - %i matches - %i files skipped - %i files deleted.\n", totalFiles, totalFiles - delFiles, delFiles);
}
Beispiel #11
0
/*
====================
Interactive line editing and console scrollback
====================
*/
static void
Key_Console (int key, int unicode)
{
	// LordHavoc: copied most of this from Q2 to improve keyboard handling
	switch (key)
	{
	case K_KP_SLASH:
		key = '/';
		break;
	case K_KP_MINUS:
		key = '-';
		break;
	case K_KP_PLUS:
		key = '+';
		break;
	case K_KP_HOME:
		key = '7';
		break;
	case K_KP_UPARROW:
		key = '8';
		break;
	case K_KP_PGUP:
		key = '9';
		break;
	case K_KP_LEFTARROW:
		key = '4';
		break;
	case K_KP_5:
		key = '5';
		break;
	case K_KP_RIGHTARROW:
		key = '6';
		break;
	case K_KP_END:
		key = '1';
		break;
	case K_KP_DOWNARROW:
		key = '2';
		break;
	case K_KP_PGDN:
		key = '3';
		break;
	case K_KP_INS:
		key = '0';
		break;
	case K_KP_DEL:
		key = '.';
		break;
	}

	if ((key == 'v' && keydown[K_CTRL]) || ((key == K_INS || key == K_KP_INS) && keydown[K_SHIFT]))
	{
		char *cbd, *p;
		if ((cbd = Sys_GetClipboardData()) != 0)
		{
			int i;
#if 1
			p = cbd;
			while (*p)
			{
				if (*p == '\r' && *(p+1) == '\n')
				{
					*p++ = ';';
					*p++ = ' ';
				}
				else if (*p == '\n' || *p == '\r' || *p == '\b')
					*p++ = ';';
				p++;
			}
#else
			strtok(cbd, "\n\r\b");
#endif
			i = (int)strlen(cbd);
			if (i + key_linepos >= MAX_INPUTLINE)
				i= MAX_INPUTLINE - key_linepos - 1;
			if (i > 0)
			{
				// terencehill: insert the clipboard text between the characters of the line
				/*
				char *temp = (char *) Z_Malloc(MAX_INPUTLINE);
				cbd[i]=0;
				temp[0]=0;
				if ( key_linepos < (int)strlen(key_line) )
					strlcpy(temp, key_line + key_linepos, (int)strlen(key_line) - key_linepos +1);
				key_line[key_linepos] = 0;
				strlcat(key_line, cbd, sizeof(key_line));
				if (temp[0])
					strlcat(key_line, temp, sizeof(key_line));
				Z_Free(temp);
				key_linepos += i;
				*/
				// blub: I'm changing this to use memmove() like the rest of the code does.
				cbd[i] = 0;
				memmove(key_line + key_linepos + i, key_line + key_linepos, sizeof(key_line) - key_linepos - i);
				memcpy(key_line + key_linepos, cbd, i);
				key_linepos += i;
			}
			Z_Free(cbd);
		}
		return;
	}

	if (key == 'l' && keydown[K_CTRL])
	{
		Cbuf_AddText ("clear\n");
		return;
	}

	if (key == 'u' && keydown[K_CTRL]) // like vi/readline ^u: delete currently edited line
	{
		// clear line
		key_line[0] = ']';
		key_line[1] = 0;
		key_linepos = 1;
		return;
	}

	if (key == 'q' && keydown[K_CTRL]) // like zsh ^q: push line to history, don't execute, and clear
	{
		// clear line
		Key_History_Push();
		key_line[0] = ']';
		key_line[1] = 0;
		key_linepos = 1;
		return;
	}

	if (key == K_ENTER || key == K_KP_ENTER)
	{
		Cbuf_AddText (key_line+1);	// skip the ]
		Cbuf_AddText ("\n");
		Key_History_Push();
		key_line[0] = ']';
		key_line[1] = 0;	// EvilTypeGuy: null terminate
		key_linepos = 1;
		// force an update, because the command may take some time
		if (cls.state == ca_disconnected)
			CL_UpdateScreen ();
		return;
	}

	if (key == K_TAB)
	{
		if(keydown[K_CTRL]) // append to the cvar its value
		{
			int		cvar_len, cvar_str_len, chars_to_move;
			char	k;
			char	cvar[MAX_INPUTLINE];
			const char *cvar_str;
			
			// go to the start of the variable
			while(--key_linepos)
			{
				k = key_line[key_linepos];
				if(k == '\"' || k == ';' || k == ' ' || k == '\'')
					break;
			}
			key_linepos++;
			
			// save the variable name in cvar
			for(cvar_len=0; (k = key_line[key_linepos + cvar_len]) != 0; cvar_len++)
			{
				if(k == '\"' || k == ';' || k == ' ' || k == '\'')
					break;
				cvar[cvar_len] = k;
			}
			if (cvar_len==0)
				return;
			cvar[cvar_len] = 0;
			
			// go to the end of the cvar
			key_linepos += cvar_len;
			
			// save the content of the variable in cvar_str
			cvar_str = Cvar_VariableString(cvar);
			cvar_str_len = strlen(cvar_str);
			if (cvar_str_len==0)
				return;
			
			// insert space and cvar_str in key_line
			chars_to_move = strlen(&key_line[key_linepos]);
			if (key_linepos + 1 + cvar_str_len + chars_to_move < MAX_INPUTLINE)
			{
				if (chars_to_move)
					memmove(&key_line[key_linepos + 1 + cvar_str_len], &key_line[key_linepos], chars_to_move);
				key_line[key_linepos++] = ' ';
				memcpy(&key_line[key_linepos], cvar_str, cvar_str_len);
				key_linepos += cvar_str_len;
				key_line[key_linepos + chars_to_move] = 0;
			}
			else
				Con_Printf("Couldn't append cvar value, edit line too long.\n");
			return;
		}
		// Enhanced command completion
		// by EvilTypeGuy [email protected]
		// Thanks to Fett, Taniwha
		Con_CompleteCommandLine();
		return;
	}

	// Advanced Console Editing by Radix [email protected]
	// Added/Modified by EvilTypeGuy [email protected]
	// Enhanced by [515]
	// Enhanced by terencehill

	// move cursor to the previous character
	if (key == K_LEFTARROW || key == K_KP_LEFTARROW)
	{
		if (key_linepos < 2)
			return;
		if(keydown[K_CTRL]) // move cursor to the previous word
		{
			int		pos;
			char	k;
			pos = key_linepos-1;

			if(pos) // skip all "; ' after the word
				while(--pos)
				{
					k = key_line[pos];
					if (!(k == '\"' || k == ';' || k == ' ' || k == '\''))
						break;
				}

			if(pos)
				while(--pos)
				{
					k = key_line[pos];
					if(k == '\"' || k == ';' || k == ' ' || k == '\'')
						break;
				}
			key_linepos = pos + 1;
		}
		else if(keydown[K_SHIFT]) // move cursor to the previous character ignoring colors
		{
			int		pos;
			size_t          inchar = 0;
			pos = u8_prevbyte(key_line+1, key_linepos-1) + 1; // do NOT give the ']' to u8_prevbyte
			while (pos)
				if(pos-1 > 0 && key_line[pos-1] == STRING_COLOR_TAG && isdigit(key_line[pos]))
					pos-=2;
				else if(pos-4 > 0 && key_line[pos-4] == STRING_COLOR_TAG && key_line[pos-3] == STRING_COLOR_RGB_TAG_CHAR
						&& isxdigit(key_line[pos-2]) && isxdigit(key_line[pos-1]) && isxdigit(key_line[pos]))
					pos-=5;
				else
				{
					if(pos-1 > 0 && key_line[pos-1] == STRING_COLOR_TAG && key_line[pos] == STRING_COLOR_TAG) // consider ^^ as a character
						pos--;
					pos--;
					break;
				}
			// we need to move to the beginning of the character when in a wide character:
			u8_charidx(key_line, pos + 1, &inchar);
			key_linepos = pos + 1 - inchar;
		}
		else
		{
			key_linepos = u8_prevbyte(key_line+1, key_linepos-1) + 1; // do NOT give the ']' to u8_prevbyte
		}
		return;
	}

	// delete char before cursor
	if (key == K_BACKSPACE || (key == 'h' && keydown[K_CTRL]))
	{
		if (key_linepos > 1)
		{
			int newpos = u8_prevbyte(key_line+1, key_linepos-1) + 1; // do NOT give the ']' to u8_prevbyte
			strlcpy(key_line + newpos, key_line + key_linepos, sizeof(key_line) + 1 - key_linepos);
			key_linepos = newpos;
		}
		return;
	}

	// delete char on cursor
	if (key == K_DEL || key == K_KP_DEL)
	{
		size_t linelen;
		linelen = strlen(key_line);
		if (key_linepos < (int)linelen)
			memmove(key_line + key_linepos, key_line + key_linepos + u8_bytelen(key_line + key_linepos, 1), linelen - key_linepos);
		return;
	}


	// move cursor to the next character
	if (key == K_RIGHTARROW || key == K_KP_RIGHTARROW)
	{
		if (key_linepos >= (int)strlen(key_line))
			return;
		if(keydown[K_CTRL]) // move cursor to the next word
		{
			int		pos, len;
			char	k;
			len = (int)strlen(key_line);
			pos = key_linepos;

			while(++pos < len)
			{
				k = key_line[pos];
				if(k == '\"' || k == ';' || k == ' ' || k == '\'')
					break;
			}
			
			if (pos < len) // skip all "; ' after the word
				while(++pos < len)
				{
					k = key_line[pos];
					if (!(k == '\"' || k == ';' || k == ' ' || k == '\''))
						break;
				}
			key_linepos = pos;
		}
		else if(keydown[K_SHIFT]) // move cursor to the next character ignoring colors
		{
			int		pos, len;
			len = (int)strlen(key_line);
			pos = key_linepos;
			
			// go beyond all initial consecutive color tags, if any
			if(pos < len)
				while (key_line[pos] == STRING_COLOR_TAG)
				{
					if(isdigit(key_line[pos+1]))
						pos+=2;
					else if(key_line[pos+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(key_line[pos+2]) && isxdigit(key_line[pos+3]) && isxdigit(key_line[pos+4]))
						pos+=5;
					else
						break;
				}
			
			// skip the char
			if (key_line[pos] == STRING_COLOR_TAG && key_line[pos+1] == STRING_COLOR_TAG) // consider ^^ as a character
				pos++;
			pos += u8_bytelen(key_line + pos, 1);
			
			// now go beyond all next consecutive color tags, if any
			if(pos < len)
				while (key_line[pos] == STRING_COLOR_TAG)
				{
					if(isdigit(key_line[pos+1]))
						pos+=2;
					else if(key_line[pos+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(key_line[pos+2]) && isxdigit(key_line[pos+3]) && isxdigit(key_line[pos+4]))
						pos+=5;
					else
						break;
				}
			key_linepos = pos;
		}
		else
			key_linepos += u8_bytelen(key_line + key_linepos, 1);
		return;
	}

	if (key == K_INS || key == K_KP_INS) // toggle insert mode
	{
		key_insert ^= 1;
		return;
	}

	// End Advanced Console Editing

	if (key == K_UPARROW || key == K_KP_UPARROW || (key == 'p' && keydown[K_CTRL]))
	{
		Key_History_Up();
		return;
	}

	if (key == K_DOWNARROW || key == K_KP_DOWNARROW || (key == 'n' && keydown[K_CTRL]))
	{
		Key_History_Down();
		return;
	}
	// ~1.0795 = 82/76  using con_textsize 64 76 is height of the char, 6 is the distance between 2 lines

	if (keydown[K_CTRL])
	{
		// prints all the matching commands
		if (key == 'f')
		{
			Key_History_Find_All();
			return;
		}
		// Search forwards/backwards, pointing the history's index to the
		// matching command but without fetching it to let one continue the search.
		// To fetch it, it suffices to just press UP or DOWN.
		if (key == 'r')
		{
			if (keydown[K_SHIFT])
				Key_History_Find_Forwards();
			else
				Key_History_Find_Backwards();
			return;
		}
		// go to the last/first command of the history
		if (key == ',')
		{
			Key_History_First();
			return;
		}
		if (key == '.')
		{
			Key_History_Last();
			return;
		}
	}

	if (key == K_PGUP || key == K_KP_PGUP)
	{
		if(keydown[K_CTRL])
		{
			con_backscroll += ((vid_conheight.integer >> 2) / con_textsize.integer)-1;
		}
		else
			con_backscroll += ((vid_conheight.integer >> 1) / con_textsize.integer)-3;
		return;
	}
cellInfo_t sql_eval( sqlInfo_t *db, Expr expr, tableInfo_t * table, cellInfo_t * row, int index, int total, sqlData_t * params, cellInfo_t * aggregate )
{
	value_t		stack[ 64 ];
	int sp;
	int i;

	static char	buffer[ 16384 ];		// FIX ME: this is the source of bugs
	static int size = 0;

	int top = size;

	for ( i=0,sp=0; expr[ i ] != OP_END; ) {

		op_t op = READ_OP;

		switch( op ) {

			case OP_PUSH_INTEGER:		stack[ sp++ ].i = READ_INT;								break;
			case OP_PUSH_STRING:		stack[ sp++ ].s = READ_STRING;							break;
			case OP_PUSH_COLUMN:		stack[ sp++ ].p = table->columns + READ_OP;				break;
			case OP_PUSH_COLUMN_VAL:	stack[ sp++ ].i	= row[ READ_OP ].integer;				break;
			case OP_PUSH_STRING_PARAM:	stack[ sp++ ].s = params[ READ_OP ].payload.string;		break;
			case OP_PUSH_INTEGER_PARAM:	stack[ sp++ ].i = params[ READ_OP ].payload.integer;	break;
			case OP_ROWINDEX:			stack[ sp++ ].i = (row - table->rows) / table->column_count;	break;
			case OP_ROWNUMBER:			stack[ sp++ ].i = index; break;
			case OP_ROWTOTAL:			stack[ sp++ ].i = total; break;
			case OP_ROWCOUNT:			stack[ sp++ ].i = table->row_count; break;
			case OP_SYS_TIME:			stack[ sp++ ].i = Sys_Milliseconds(); break;
			

			case OP_SUBTRACT:		LVALUE.i = LEFT_OPERAND.i	-	RIGHT_OPERAND.i; sp--;	break;
			case OP_ADD:			LVALUE.i = LEFT_OPERAND.i	+	RIGHT_OPERAND.i; sp--;	break;
			case OP_DIVIDE:			LVALUE.i = LEFT_OPERAND.i	/	RIGHT_OPERAND.i; sp--;	break;
			case OP_MULTIPLY:		LVALUE.i = LEFT_OPERAND.i	*	RIGHT_OPERAND.i; sp--;	break;
			case OP_MODULUS:		LVALUE.i = LEFT_OPERAND.i	%	RIGHT_OPERAND.i; sp--;	break;

			case OP_LOGICAL_AND:	LVALUE.i = LEFT_OPERAND.i	&&	RIGHT_OPERAND.i; sp--;	break;
			case OP_LOGICAL_OR:		LVALUE.i = LEFT_OPERAND.i	||	RIGHT_OPERAND.i; sp--;	break;
			case OP_BITWISE_AND:	LVALUE.i = LEFT_OPERAND.i	&	RIGHT_OPERAND.i; sp--;	break;
			case OP_BITWISE_OR:		LVALUE.i = LEFT_OPERAND.i	|	RIGHT_OPERAND.i; sp--;	break;

			case OP_GT:				LVALUE.i = LEFT_OPERAND.i	>	RIGHT_OPERAND.i; sp--;	break;
			case OP_LT:				LVALUE.i = LEFT_OPERAND.i	<	RIGHT_OPERAND.i; sp--;	break;
			case OP_GE:				LVALUE.i = LEFT_OPERAND.i	>=	RIGHT_OPERAND.i; sp--;	break;
			case OP_LE:				LVALUE.i = LEFT_OPERAND.i	<=	RIGHT_OPERAND.i; sp--;	break;
			case OP_EQ:				LVALUE.i = LEFT_OPERAND.i	==	RIGHT_OPERAND.i; sp--;	break;
			case OP_NE:				LVALUE.i = LEFT_OPERAND.i	!=	RIGHT_OPERAND.i; sp--;	break;

			case OP_ATOI:
				if (stack[ sp-1 ].s) {
					stack[ sp-1 ].i = atoi( stack[ sp-1 ].s );
				} else {
					stack[ sp-1 ].i = -1;
				}
				break;
			case OP_LIKE:			LVALUE.i = Q_stricmp( LEFT_OPERAND.s, RIGHT_OPERAND.s ) == 0; sp--;	break;
			case OP_MATCH:			LVALUE.i = Com_Filter( RIGHT_OPERAND.s, LEFT_OPERAND.s, 0 ); sp--; break;
			case OP_NOTLIKE:		LVALUE.i = Q_stricmp( LEFT_OPERAND.s, RIGHT_OPERAND.s ) != 0; sp--; break;
			case OP_INT_MIN:		LVALUE.i = (LEFT_OPERAND.i<RIGHT_OPERAND.i)?LEFT_OPERAND.i:RIGHT_OPERAND.i; sp--; break;
			case OP_INT_MAX:		LVALUE.i = (LEFT_OPERAND.i>RIGHT_OPERAND.i)?LEFT_OPERAND.i:RIGHT_OPERAND.i; sp--; break;
			case OP_ABS:			stack[ sp-1 ].i = abs( stack[ sp-1 ].i ); break;

			case OP_UMINUS:			
				stack[ sp-1 ].i = -stack[ sp-1 ].i;
				break;

			case OP_NOT:
				stack[ sp-1 ].i = !(stack[ sp-1 ].i);
				break;

			case OP_REMOVE:
				{
					int p = READ_OP;
					int n = min( params[ p ].payload.integer, stack[ sp-1 ].i );
					params[ p ].payload.integer -= n;
					stack[ sp-1 ].i = n;
				} break;


			case OP_ASSIGN_INT_TO_COLUMN:
				{
					columnInfo_t *	c		= (columnInfo_t*)LEFT_OPERAND.p;
					ASSERT( c->num >= 0 && c->num < table->column_count );

					if ( row[ c->num ].integer != RIGHT_OPERAND.i ) {
						table->modified |= (1<<c->num);
					}

					LVALUE.i = row[ c->num ].integer	= RIGHT_OPERAND.i; sp--;
				} break;

			case OP_ASSIGN_STRING_TO_COLUMN:
				{
					//	a string is being inserted into a table.  this string is expected to remain
					//	constant throughout the life of the table.  strings stored in tables do not
					//	change.  string cells can not be modified with an 'UPDATE' command
					columnInfo_t *	c		= (columnInfo_t*)LEFT_OPERAND.p;
					cellInfo_t *	cell	= row + c->num;
					const char *	o		= cell->string;

					ASSERT( c->format == STRING );
					//ASSERT( cell->string == 0 );

					//	help!!
					if ( abs(RIGHT_OPERAND.i) < 0x10000 ) {
						//	can't figure out data type for cases like: INSERT INTO missions VALUES(7,'wealth',500); 3rd column in text
						//	so trying to guess
						LVALUE.s = cell->string = sql_alloc_string( db, fn( RIGHT_OPERAND.i, FN_PLAIN ) );  sp--;
					} else { 
						LVALUE.s = cell->string = sql_alloc_string( db, RIGHT_OPERAND.s ); sp--;
					}

					if ( Q_stricmp( o, cell->string ) ) {
						table->modified |= (1<<c->num);
					}

				} break;

			case OP_ASSIGN_CS_TO_ROW:
				{
					row_cs( db, table, row, stack[ sp-1 ].s );
				} break;

			case OP_COUNT:	(*aggregate).integer++;			break;
			case OP_MAX:
				{
					int v = stack[ sp-1 ].i;
					(*aggregate).integer = (index==0)?v:max( (*aggregate).integer, v );
				} break;
			case OP_MIN:
				{
					int v = stack[ sp-1 ].i;
					(*aggregate).integer = (index==0)?v:min( (*aggregate).integer, v );
				} break;


			case OP_SUM:
				(*aggregate).integer += stack[ sp-1 ].i;
				break;

			case OP_FORMAT:
				{
					char *	s		= buffer + size;
					int		flags	= READ_INT;

					size += fn_buffer( s, stack[ sp-1 ].i, flags );
					stack[ sp-1 ].s = s;

				} break;

			case OP_CONCAT:
				{
					LVALUE.s = concat( LEFT_OPERAND.s, RIGHT_OPERAND.s, buffer, sizeof(buffer), &size ); sp--;

				} break;

			case OP_COLLAPSE:
				{
					char * s = buffer + size;
					size += concat2( s, sizeof(buffer)-size, stack, sp );
					stack[ 0 ].s = s;
					sp = 1;
				} break;

			case OP_CVAR:
				{
					stack[ sp-1 ].s = Cvar_VariableString( stack[ sp-1 ].s );
				} break;

			case OP_ACCESS_TABLE:
				{
					tableInfo_t *	table;
					columnInfo_t *	c;

					table = find_table( db, LEFT_OPERAND.s );

					//	allow table access outside current db
					if ( !table ) {
						table = find_table( sql_getclientdb(), LEFT_OPERAND.s );
						if ( !table ) {
							table = find_table( sql_getserverdb(), LEFT_OPERAND.s );
							if ( !table ) {
								table = find_table( sql_getcommondb(), LEFT_OPERAND.s );
							}
						}
					}

#ifdef DEVELOPER
					if ( !table ) {
						Com_Error( ERR_FATAL, "table '%s' does not exist.\n\n%s", LEFT_OPERAND.s, CURRENT_STMT );
					}
#endif

					c = find_column( table, RIGHT_OPERAND.s );

#ifdef DEVELOPER
					if ( !c ) {
						Com_Error( ERR_FATAL, "column '%s' expected on table '%s'.\n\n%s\n", RIGHT_OPERAND.s, LEFT_OPERAND.s, CURRENT_STMT );
					}
#endif

					LVALUE.p		= table; sp--;
					stack[ sp++ ].p	= c;

				} break;

			case OP_LOOKUP_I:
				{
					tableInfo_t	*	t = stack[ sp-3 ].p;
					columnInfo_t *	c = stack[ sp-2 ].p;
					cellInfo_t		k;
					int				index;

					k.integer = stack[ sp-1 ].i;

					if ( !c->index ) {
						sql_create_index( db, t, c );
					}

#ifdef DEVELOPER
					if ( !c->index ) {
						Com_Error( ERR_FATAL, "index needed for column '%s' on table '%s'.\n\n%s", c->name, t->name, CURRENT_STMT );
					}
					if ( c->format != INTEGER ) {
						Com_Error( ERR_FATAL, "expecting column '%s' on table '%s' to be integer, not string.\n\n%s", c->name, t->name, CURRENT_STMT );
					}
#endif

					if ( t->last_changed != t->last_indexed )
						sql_table_reindex( t );

					index = search_index_i( c->index, t->row_count, t->rows, t->column_count, c->num, k );

					LVALUE.i = (index>=0)?c->index[ index ]:index; sp--;

				} break;

			case OP_ACCESS_ROW_I:
				{
					tableInfo_t *	t = stack[ sp-3 ].p;
					int				r = stack[ sp-2 ].i;
					columnInfo_t *	c = find_column( t, stack[ sp-1 ].s );

#ifdef DEVELOPER
					if ( !t ) {
						Com_Error( ERR_FATAL, "table '%s' does not exist.\n\n%s", stack[sp-3].s, CURRENT_STMT );
					}
					if ( !c ) {
						Com_Error( ERR_FATAL, "could not find column '%s' on table '%s' in statement:\n\n%s", stack[ sp-1 ].s, stack[sp-3].s, CURRENT_STMT );
					}
#endif

					sp -= 3;
					if ( r < 0 ) {
						stack[ sp++ ].i = -1;

					} else {

						int cell = (t->column_count*r) + c->num;

						if ( c->format == STRING ) {
							stack[ sp++ ].i = atoi( t->rows[ cell ].string );
						} else {
							stack[ sp++ ].i = t->rows[ cell ].integer;
						}
					}

				} break;

			case OP_LOOKUP_S:
				{
					tableInfo_t	*	t = stack[ sp-3 ].p;
					columnInfo_t *	c = stack[ sp-2 ].p;
					cellInfo_t		k;
					int				index;

					k.string = stack[ sp-1 ].s;

					if ( !c->index ) {
						sql_create_index( db, t, c );
					}

#ifdef DEVELOPER
					if ( !c->index ) {
						Com_Error( ERR_FATAL, "index needed for column '%s' on table '%s'.\n\n%s", c->name, t->name, CURRENT_STMT );
					}
					if ( c->format != STRING ) {
						Com_Error( ERR_FATAL, "expecting column '%s' on table '%s' to be string, not integer.\n\n%s", c->name, t->name, CURRENT_STMT );
					}
#endif

					if ( t->last_changed != t->last_indexed )
						sql_table_reindex( t );

					index = search_index_s( c->index, t->row_count, t->rows, t->column_count, c->num, k );

					LVALUE.i = (index>=0)?c->index[ index ]:index; sp--;

				} break;

			case OP_ACCESS_ROW_S:
				{
					tableInfo_t *	t = stack[ sp-3 ].p;
					int				r = stack[ sp-2 ].i;
					columnInfo_t *	c = find_column( t, stack[ sp-1 ].s );

#ifdef DEVELOPER
					if ( !t ) {
						Com_Error( ERR_FATAL, "table does not exist.\n\n%s", CURRENT_STMT );
					}
					if ( !c ) {
						Com_Error( ERR_FATAL, "invalid column for table '%s' in statement:\n\n%s", t->name, CURRENT_STMT );
					}
#endif

					sp -= 3;
					stack[ sp++ ].s = (r>=0)?t->rows[ (t->column_count*r) + c->num ].string:"???";
		
				} break;

			case OP_PUSH_GS:
				{
					int		offset	= READ_INT;

					stack[ sp++ ].i = db->gs[ offset ];
			
				} break;

			case OP_PUSH_GS_OFFSET:
				{
					int		offset	= READ_INT;

					stack[ sp-1 ].i = db->gs[ offset + stack[ sp-1 ].i ];
				} break;

			case OP_PUSH_PS_CLIENT:
				{
					int		offset	= READ_INT;
					stack[ sp++ ].i = db->ps[ offset ];
				} break;

			case OP_PUSH_PS_CLIENT_OFFSET:
				{
					int		offset	= READ_INT;

					stack[ sp-1 ].i = db->ps[ offset + stack[ sp-1 ].i ];
				} break;


			case OP_IFTHENELSE:
				{
					int		c	= stack[ sp-1 ].i;
					value_t	a	= stack[ sp-2 ];
					value_t	b	= stack[ sp-3 ];
					sp -= 3;

					stack[ sp++ ] = (c)?b:a;

				} break;

			case OP_SHADER:
				{
					ASSERT( db->shader );
					stack[ sp-1 ].i = db->shader( stack[ sp-1 ].s );
				} break;

			case OP_SOUND:
				{
					ASSERT( db->sound );
					stack[ sp-1 ].i = db->sound( stack[ sp-1 ].s );
				} break;

			case OP_MODEL:
				{
					ASSERT( db->model );
					stack[ sp-1 ].i = db->model( stack[ sp-1 ].s );
				} break;

			case OP_PORTRAIT:
				{
					ASSERT( db->portrait );
					stack[ sp-1 ].i = db->portrait( stack[ sp-1 ].s );
				} break;

			case OP_PUSH_INTEGER_GLOBAL:
				{
					const char * global_id = READ_STRING;
					ASSERT( db->global_int );
					stack[ sp++ ].i = db->global_int( global_id );
				} break;

				//	recursive integer call
			case OP_EVAL:
				{
					const char * s = stack[ sp-1 ].s;
					int r;

					switch ( SWITCHSTRING(s) )
					{
					case 0:
					case CS('0',0,0,0):
						r = 0;
						break;
					case CS('1',0,0,0):
						r = 1;
						break;
					default:
						{
							Expr		e;
							parseInfo_t	pi = { 0 };
							char		tmp[ SQL_STMT_ALLOC ];
							sqlStack_t*	save = db->stmt_buffer.c;

							db->stmt_buffer.c = (sqlStack_t*)tmp;
							db->stmt_buffer.c->top = sizeof(sqlStack_t);

								pi.db = db;
								e = parse_expression( &s, &pi );

								ASSERT( pi.rt == INTEGER );
								ASSERT( pi.more == 0 );
		
								r = sql_eval( db, e, table, row, index, total, params, aggregate ).integer;

							db->stmt_buffer.c = save;
						} break;
					}

					stack[ sp-1 ].i = r;
				} break;

				//	recursive string call
			case OP_PRINT:
				{
					const char * s = stack[ sp-1 ].s;
					Expr		e;
					parseInfo_t	pi = { 0 };
					char		tmp[ SQL_STMT_ALLOC ];
					sqlStack_t*	save = db->stmt_buffer.c;

					db->stmt_buffer.c = (sqlStack_t*)tmp;
					db->stmt_buffer.c->top = sizeof(sqlStack_t);

					pi.db		= db;
					pi.flags	= PARSE_STRINGLITERAL;

						e = parse_expression( &s, &pi );

						ASSERT( pi.rt == STRING );
						ASSERT( pi.more == 0 );
						
						stack[ sp-1 ].s = sql_eval( db, e, table, row, index, total, params, aggregate ).string;

					db->stmt_buffer.c = save;

				} break;

				//	execute a precompiled expression, returns string
			case OP_RUN:
				{
					int		index = stack[ sp-1 ].i;

					if ( index < 0 || index >= db->stmts_byindex_count || !db->stmts_byindex[ index ] ) {
						stack[ sp-1 ].s = "???";
						break;
					}

					stack[ sp-1 ].s = sql_eval( db, ((formatInfo_t*)db->stmts_byindex[ index ])->print, 0, 0, 0, 0, 0, 0 ).string;
					size += strlen(stack[ sp-1 ].s) + 1;

				} break;

			case OP_RND:
				{
					LVALUE.i = Rand_NextInt32InRange( &db->rand, LEFT_OPERAND.i, RIGHT_OPERAND.i ); sp--;
				} break;
#if DEVELOPER
			default:
				{
					Com_Error(ERR_FATAL, "invalid sql op code: '%d'.\n", op );

				} break;
#endif
		}

#ifdef DEVELOPER
		db->ops++;
#endif
	}

	ASSERT( size <= sizeof(buffer) );	// stack overflow

	size = top;

	if ( sp == 0 )
	{
		cellInfo_t c;
		c.integer = 0;
		return c;
	}

	ASSERT( sp == 1 );

	return *(cellInfo_t*)stack;
}
Beispiel #13
0
/*
=================
Host_Main
=================
*/
int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func )
{
	static double	oldtime, newtime;

	pChangeGame = func;	// may be NULL

	if( SDL_Init( SDL_INIT_VIDEO |
				SDL_INIT_TIMER |
				SDL_INIT_AUDIO |
				SDL_INIT_JOYSTICK |
				SDL_INIT_EVENTS ))
	{
		MsgDev(D_ERROR, "SDL_Init: %s", SDL_GetError());
		return 0;
	}

#ifndef _WIN32
#ifndef __ANDROID__
	// Start of IO functions
	FILE *fd = fopen("/proc/self/cmdline", "r");
	char moduleName[64], cmdLine[512] = "", *arg;
	size_t size = 0;
	int i = 0;
	for(i = 0; getdelim(&arg, &size, 0, fd) != -1; i++)
	{
		if(!i)
		{
			strcpy(moduleName, strrchr(arg, '/'));
			//strrchr adds a / at begin of string =(
			memmove(&moduleName[0], &moduleName[1], sizeof(moduleName) - 1);
		}
		else
		{
			strcat(cmdLine, arg);
			strcat(cmdLine, " ");
		}
	}
	free(arg);
	fclose(fd);
#endif
#else
	// TODO
#endif

	#ifndef __ANDROID__
	Host_InitCommon( moduleName, cmdLine, progname, bChangeGame );
	#else
	Host_InitCommon( NULL, "-dev 3 -log", progname, bChangeGame );
	#endif

	// init commands and vars
	if( host.developer >= 3 )
	{
		Cmd_AddCommand ( "sys_error", Sys_Error_f, "just throw a fatal error to test shutdown procedures");
		Cmd_AddCommand ( "host_error", Host_Error_f, "just throw a host error to test shutdown procedures");
		Cmd_AddCommand ( "crash", Host_Crash_f, "a way to force a bus error for development reasons");
		Cmd_AddCommand ( "net_error", Net_Error_f, "send network bad message from random place");
	}

	host_cheats = Cvar_Get( "sv_cheats", "0", CVAR_LATCH, "allow cheat variables to enable" );
	host_maxfps = Cvar_Get( "fps_max", "72", CVAR_ARCHIVE, "host fps upper limit" );
	host_framerate = Cvar_Get( "host_framerate", "0", 0, "locks frame timing to this value in seconds" );  
	host_serverstate = Cvar_Get( "host_serverstate", "0", CVAR_INIT, "displays current server state" );
	host_gameloaded = Cvar_Get( "host_gameloaded", "0", CVAR_INIT, "inidcates a loaded game.dll" );
	host_clientloaded = Cvar_Get( "host_clientloaded", "0", CVAR_INIT, "inidcates a loaded client.dll" );
	host_limitlocal = Cvar_Get( "host_limitlocal", "0", 0, "apply cl_cmdrate and rate to loopback connection" );
	con_gamemaps = Cvar_Get( "con_mapfilter", "1", CVAR_ARCHIVE, "when true show only maps in game folder" );
	build = Cvar_Get( "build", va( "%i", Q_buildnum()), CVAR_INIT, "returns a current build number" );
	ver = Cvar_Get( "ver", va( "%i/%g (hw build %i)", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( )), CVAR_INIT, "shows an engine version" );

	// content control
	Cvar_Get( "violence_hgibs", "1", CVAR_ARCHIVE, "show human gib entities" );
	Cvar_Get( "violence_agibs", "1", CVAR_ARCHIVE, "show alien gib entities" );
	Cvar_Get( "violence_hblood", "1", CVAR_ARCHIVE, "draw human blood" );
	Cvar_Get( "violence_ablood", "1", CVAR_ARCHIVE, "draw alien blood" );

	if( host.type != HOST_DEDICATED )
	{
		// when we in developer-mode automatically turn cheats on
		if( host.developer > 1 ) Cvar_SetFloat( "sv_cheats", 1.0f );
		Cbuf_AddText( "exec video.cfg\n" );
	}

	Mod_Init();
	NET_Init();
	Netchan_Init();

	// allow to change game from the console
	if( pChangeGame != NULL )
	{
		Cmd_AddCommand( "game", Host_ChangeGame_f, "change game" );
		Cvar_Get( "host_allow_changegame", "1", CVAR_READ_ONLY, "allows to change games" );
	}
	else
	{
		Cvar_Get( "host_allow_changegame", "0", CVAR_READ_ONLY, "allows to change games" );
	}

	SV_Init();
	CL_Init();

	if( host.type == HOST_DEDICATED )
	{
		Con_InitConsoleCommands ();

		Cmd_AddCommand( "quit", Sys_Quit, "quit the game" );
		Cmd_AddCommand( "exit", Sys_Quit, "quit the game" );

		// dedicated servers using settings from server.cfg file
		Cbuf_AddText( va( "exec %s\n", Cvar_VariableString( "servercfgfile" )));
		Cbuf_Execute();

		Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "defaultmap" )));
	}
	else
	{
		Cmd_AddCommand( "minimize", Host_Minimize_f, "minimize main window to tray" );
		Cbuf_AddText( "exec config.cfg\n" );
	}

	host.errorframe = 0;
	Cbuf_Execute();

	// post initializations
	switch( host.type )
	{
	case HOST_NORMAL:
		Con_ShowConsole( false ); // hide console
		// execute startup config and cmdline
		Cbuf_AddText( va( "exec %s.rc\n", SI.ModuleName ));
		// intentional fallthrough
	case HOST_DEDICATED:
		// if stuffcmds wasn't run, then init.rc is probably missing, use default
		if( !host.stuffcmdsrun ) Cbuf_AddText( "stuffcmds\n" );

		Cbuf_Execute();
		break;
	}

	host.change_game = false;	// done
	Cmd_RemoveCommand( "setr" );	// remove potentially backdoor for change render settings
	Cmd_RemoveCommand( "setgl" );

	// we need to execute it again here
	Cmd_ExecuteString( "exec config.cfg\n", src_command );
	oldtime = Sys_DoubleTime();
	SCR_CheckStartupVids();	// must be last

	SDL_StopTextInput(); // disable text input event. Enable this in chat/console?
	SDL_Event event;

	// main window message loop
	while( !host.crashed )
	{
		while( SDL_PollEvent( &event ) )
			SDLash_EventFilter( &event );
		newtime = Sys_DoubleTime ();
		Host_Frame( newtime - oldtime );
		oldtime = newtime;
	}

	// never reached
	return 0;
}
Beispiel #14
0
/**
 * @brief Responsible for doing a swapbuffers
 */
void GLimp_EndFrame(void)
{
	// don't flip if drawing to front buffer
	//FIXME: remove this nonesense
	if (Q_stricmp(Cvar_VariableString("r_drawBuffer"), "GL_FRONT") != 0)
	{
		SDL_GL_SwapWindow(main_window);
	}

	if (r_fullscreen->modified)
	{
		qboolean fullscreen;
		qboolean needToToggle;

		// Find out the current state
		fullscreen = !!(SDL_GetWindowFlags(main_window) & SDL_WINDOW_FULLSCREEN);

		if (r_fullscreen->integer && Cvar_VariableIntegerValue("in_nograb"))
		{
			Com_Printf("Fullscreen not allowed with in_nograb 1\n");
			Cvar_Set("r_fullscreen", "0");
			r_fullscreen->modified = qfalse;
		}

		// Is the state we want different from the current state?
		needToToggle = !!r_fullscreen->integer != fullscreen;

		if (needToToggle)
		{
			// SDL_WM_ToggleFullScreen didn't work, so do it the slow way
			if (!(SDL_SetWindowFullscreen(main_window, r_fullscreen->integer) >= 0)) // !sdlToggled
			{
				Cbuf_ExecuteText(EXEC_APPEND, "vid_restart\n");
			}

			IN_Restart();
		}

#ifdef MACOS_X_GAMMA_RESET_FIX
		// OS X 10.9 has a bug where toggling in or out of fullscreen mode
		// will cause the gamma to reset to the system default after an unknown
		// short delay. This little fix simply causes the gamma to be reset
		// again after a hopefully-long-enough-delay of 3 seconds.
		// Radar 15961845
		gammaResetTime = CL_ScaledMilliseconds() + 3000;
#endif
		r_fullscreen->modified = qfalse;
	}

#ifdef MACOS_X_GAMMA_RESET_FIX
	if ((gammaResetTime != 0) && (gammaResetTime < CL_ScaledMilliseconds()))
	{
		// Circuitous way of resetting the gamma to its current value.
		char old[6] = { 0 };
		Q_strncpyz(old, va("%i", Cvar_VariableIntegerValue("r_gamma")), 5);
		if (strlen(old))
		{
			Cvar_Set("r_gamma", "1");
			Cvar_Set("r_gamma", old);
		}

		gammaResetTime = 0;
	}
#endif
}
Beispiel #15
0
/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f( void ) {
	int			i;
	client_t	*client;
	char		*denied;
	qboolean	isBot;
	int			delay;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId ) {
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( sv.restartTime ) {
		return;
	}

	if (Cmd_Argc() > 1 ) {
		delay = atoi( Cmd_Argv(1) );
	}
	else {
		delay = 5;
	}
	if( delay ) {
		sv.restartTime = svs.time + delay * 1000;
		SV_SetConfigstring( CS_WARMUP, va("%i", sv.restartTime) );
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified || sv_gametype->modified ) {
		char	mapname[MAX_QPATH];

		Com_Printf( "variable change -- restarting.\n" );
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );

		SV_SpawnServer( mapname, qfalse, eForceReload_NOTHING );
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid
	sv.restartedServerId = sv.serverId;
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va("%i", sv.serverId ) );

	// reset all the vm data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = SS_LOADING;
	sv.restarting = qtrue;

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for ( i = 0 ;i < 3 ; i++ ) {
		VM_Call( gvm, GAME_RUN_FRAME, svs.time );
		svs.time += 100;
	}

	sv.state = SS_GAME;
	sv.restarting = qfalse;

	// connect and begin all the clients
	for (i=0 ; i<sv_maxclients->integer ; i++) {
		client = &svs.clients[i];

		// send the new gamestate to all connected clients
		if ( client->state < CS_CONNECTED) {
			continue;
		}

		if ( client->netchan.remoteAddress.type == NA_BOT ) {
			isBot = qtrue;
		} else {
			isBot = qfalse;
		}

		// add the map_restart command
		SV_AddServerCommand( client, "map_restart\n" );

		// connect the client again, without the firstTime flag
		denied = (char *)VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) );
		if ( denied ) {
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient( client, denied );
			Com_Printf( "SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i ); // bk010125
			continue;
		}

		client->state = CS_ACTIVE;

		SV_ClientEnterWorld( client, &client->lastUsercmd );
	}	

	// run another frame to allow things to look at all the players
	VM_Call( gvm, GAME_RUN_FRAME, svs.time );
	svs.time += 100;
}
Beispiel #16
0
/*
=================
Host_Main
=================
*/
int EXPORT Host_Main( int argc, const char **argv, const char *progname, int bChangeGame, pfnChangeGame func )
{
	static double	oldtime, newtime;
#ifdef XASH_SDL
	SDL_Event event;
#endif
	pChangeGame = func;	// may be NULL

	Host_InitCommon( argc, argv, progname, bChangeGame );

	// init commands and vars
	if( host.developer >= 3 )
	{
		Cmd_AddCommand ( "sys_error", Sys_Error_f, "just throw a fatal error to test shutdown procedures");
		Cmd_AddCommand ( "host_error", Host_Error_f, "just throw a host error to test shutdown procedures");
		Cmd_AddCommand ( "crash", Host_Crash_f, "a way to force a bus error for development reasons");
		Cmd_AddCommand ( "net_error", Net_Error_f, "send network bad message from random place");
	}

	host_cheats = Cvar_Get( "sv_cheats", "0", CVAR_LATCH, "allow usage of cheat commands and variables" );
	host_maxfps = Cvar_Get( "fps_max", "72", CVAR_ARCHIVE, "host fps upper limit" );
	host_sleeptime = Cvar_Get( "sleeptime", "1", CVAR_ARCHIVE, "higher value means lower accuracy" );
	host_framerate = Cvar_Get( "host_framerate", "0", 0, "locks frame timing to this value in seconds" );  
	host_serverstate = Cvar_Get( "host_serverstate", "0", CVAR_INIT, "displays current server state" );
	host_gameloaded = Cvar_Get( "host_gameloaded", "0", CVAR_INIT, "indicates a loaded game library" );
	host_clientloaded = Cvar_Get( "host_clientloaded", "0", CVAR_INIT, "indicates a loaded client library" );
	host_limitlocal = Cvar_Get( "host_limitlocal", "0", 0, "apply cl_cmdrate and rate to loopback connection" );
	con_gamemaps = Cvar_Get( "con_mapfilter", "1", CVAR_ARCHIVE, "when enabled, show only maps in game folder (no maps from base folder when running mod)" );
	download_types = Cvar_Get( "download_types", "msec", CVAR_ARCHIVE, "list of types to download: Model, Sounds, Events, Custom" );
	build = Cvar_Get( "build", va( "%i", Q_buildnum()), CVAR_INIT, "returns a current build number" );
	ver = Cvar_Get( "ver", va( "%i/%s.%i", PROTOCOL_VERSION, XASH_VERSION, Q_buildnum( ) ), CVAR_INIT, "shows an engine version" );
	host_mapdesign_fatal = Cvar_Get( "host_mapdesign_fatal", "1", CVAR_ARCHIVE, "make map design errors fatal" );
	host_xashds_hacks = Cvar_Get( "xashds_hacks", "0", 0, "hacks for xashds in singleplayer" );

	// content control
	Cvar_Get( "violence_hgibs", "1", CVAR_ARCHIVE, "show human gib entities" );
	Cvar_Get( "violence_agibs", "1", CVAR_ARCHIVE, "show alien gib entities" );
	Cvar_Get( "violence_hblood", "1", CVAR_ARCHIVE, "draw human blood" );
	Cvar_Get( "violence_ablood", "1", CVAR_ARCHIVE, "draw alien blood" );

	if( host.type != HOST_DEDICATED )
	{
		// when we're in developer-mode, automatically turn cheats on
		if( host.developer > 1 ) Cvar_SetFloat( "sv_cheats", 1.0f );
		Cbuf_AddText( "exec video.cfg\n" );
	}

	Mod_Init();
	NET_Init();
	Netchan_Init();

	// allow to change game from the console
	if( pChangeGame != NULL )
	{
		Cmd_AddCommand( "game", Host_ChangeGame_f, "change active game/mod" );
		Cvar_Get( "host_allow_changegame", "1", CVAR_READ_ONLY, "whether changing game/mod is allowed" );
	}
	else
	{
		Cvar_Get( "host_allow_changegame", "0", CVAR_READ_ONLY, "allows to change games" );
	}

	SV_Init();
	CL_Init();

	HTTP_Init();

	// post initializations
	switch( host.type )
	{
	case HOST_NORMAL:
		Con_ShowConsole( false ); // hide console
		// execute startup config and cmdline
		Cbuf_AddText( va( "exec %s.rc\n", SI.ModuleName ));
		// intentional fallthrough
	case HOST_DEDICATED:
		// if stuffcmds wasn't run, then init.rc is probably missing, use default
		if( !host.stuffcmdsrun ) Cbuf_AddText( "stuffcmds\n" );

		Cbuf_Execute();
		break;
	case HOST_UNKNOWN:
		break;
	}

	if( host.type == HOST_DEDICATED )
	{
		char *defaultmap;
		Con_InitConsoleCommands ();

		Cmd_AddCommand( "quit", Sys_Quit, "quit the game" );
		Cmd_AddCommand( "exit", Sys_Quit, "quit the game" );

		SV_InitGameProgs();

		Cbuf_AddText( "exec config.cfg\n" );

		// dedicated servers are using settings from server.cfg file
		Cbuf_AddText( va( "exec %s\n", Cvar_VariableString( "servercfgfile" )));
		Cbuf_Execute();

		defaultmap = Cvar_VariableString( "defaultmap" );
		if( !defaultmap[0] )
			Msg( "Please add \"defaultmap\" cvar with default map name to your server.cfg!\n" );
		else
			Cbuf_AddText( va( "map %s\n", defaultmap ));

		Cvar_FullSet( "xashds_hacks", "0", CVAR_READ_ONLY );

		NET_Config( true );
	}
	else
	{
		Cmd_AddCommand( "minimize", Host_Minimize_f, "minimize main window to taskbar" );
		Cbuf_AddText( "exec config.cfg\n" );
		// listenserver/multiplayer config.
		// need load it to update menu options.
		Cbuf_AddText( "exec game.cfg\n" );
	}

	host.errorframe = 0;
	Cbuf_Execute();

	host.change_game = false;	// done
	Cmd_RemoveCommand( "setr" );	// remove potential backdoor for changing renderer settings
	Cmd_RemoveCommand( "setgl" );

	// we need to execute it again here
	if( host.type != HOST_DEDICATED )
		Cmd_ExecuteString( "exec config.cfg\n", src_command );

	// exec all files from userconfig.d 
	Host_Userconfigd_f();

	oldtime = Sys_DoubleTime();
	IN_TouchInitConfig();
	SCR_CheckStartupVids();	// must be last
#ifdef XASH_SDL
	SDL_StopTextInput(); // disable text input event. Enable this in chat/console?
#endif

	if( host.state == HOST_INIT )
		host.state = HOST_FRAME; // initialization is finished

	// main window message loop
	while( !host.crashed && !host.shutdown_issued )
	{
#ifdef XASH_SDL
		while( !host.crashed && !host.shutdown_issued && SDL_PollEvent( &event ) )
			SDLash_EventFilter( &event );
#endif
		newtime = Sys_DoubleTime ();
		Host_Frame( newtime - oldtime );

		oldtime = newtime;
	}

	// never reached
	return 0;
}
Beispiel #17
0
/*
===============
CL_StartHTTPDownload

Actually starts a download by adding it to the curl multi
handle.
===============
*/
static void CL_StartHTTPDownload (dlqueue_t *entry, dlhandle_t *dl)
{
	size_t		len;
	char		tempFile[MAX_OSPATH];
	char		escapedFilePath[MAX_QPATH*4];
	
	//yet another hack to accomodate filelists, how i wish i could push :(
	//NULL file handle indicates filelist.
	len = strlen (entry->quakePath);
	if (len > 9 && !strcmp (entry->quakePath + len - 9, ".filelist"))
	{
		dl->file = NULL;
		CL_EscapeHTTPPath (entry->quakePath, escapedFilePath);
	}
	else
	{
		CL_HTTP_Reset_KBps_counter ();	// Knightmare- for KB/s counter

		Com_sprintf (dl->filePath, sizeof(dl->filePath), "%s/%s", FS_Gamedir(), entry->quakePath);

		Com_sprintf (tempFile, sizeof(tempFile), "%s/%s", cl.gamedir, entry->quakePath);
		CL_EscapeHTTPPath (dl->filePath, escapedFilePath);

	//	strncat (dl->filePath, ".tmp");
		Q_strncatz (dl->filePath, ".tmp", sizeof(dl->filePath));

		FS_CreatePath (dl->filePath);

		//don't bother with http resume... too annoying if server doesn't support it.
		dl->file = fopen (dl->filePath, "wb");
		if (!dl->file)
		{
			Com_Printf ("CL_StartHTTPDownload: Couldn't open %s for writing.\n", dl->filePath);
			entry->state = DLQ_STATE_DONE;
			//CL_RemoveHTTPDownload (entry->quakePath);
			return;
		}
	}

	dl->tempBuffer = NULL;
	dl->speed = 0;
	dl->fileSize = 0;
	dl->position = 0;
	dl->queueEntry = entry;

	if (!dl->curl)
		dl->curl = curl_easy_init ();

	Com_sprintf (dl->URL, sizeof(dl->URL), "%s%s", cls.downloadServer, escapedFilePath);

	curl_easy_setopt (dl->curl, CURLOPT_ENCODING, "");
	//curl_easy_setopt (dl->curl, CURLOPT_DEBUGFUNCTION, CL_CURL_Debug);
	//curl_easy_setopt (dl->curl, CURLOPT_VERBOSE, 1);
	curl_easy_setopt (dl->curl, CURLOPT_NOPROGRESS, 0);
	if (dl->file)
	{
		curl_easy_setopt (dl->curl, CURLOPT_WRITEDATA, dl->file);
		curl_easy_setopt (dl->curl, CURLOPT_WRITEFUNCTION, NULL);
	}
	else
	{
		curl_easy_setopt (dl->curl, CURLOPT_WRITEDATA, dl);
		curl_easy_setopt (dl->curl, CURLOPT_WRITEFUNCTION, CL_HTTP_Recv);
	}
	curl_easy_setopt (dl->curl, CURLOPT_PROXY, cl_http_proxy->string);
	curl_easy_setopt (dl->curl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt (dl->curl, CURLOPT_MAXREDIRS, 5);
	curl_easy_setopt (dl->curl, CURLOPT_WRITEHEADER, dl);
	curl_easy_setopt (dl->curl, CURLOPT_HEADERFUNCTION, CL_HTTP_Header);
	curl_easy_setopt (dl->curl, CURLOPT_PROGRESSFUNCTION, CL_HTTP_Progress);
	curl_easy_setopt (dl->curl, CURLOPT_PROGRESSDATA, dl);
	curl_easy_setopt (dl->curl, CURLOPT_USERAGENT, Cvar_VariableString ("version"));
	curl_easy_setopt (dl->curl, CURLOPT_REFERER, cls.downloadReferer);
	curl_easy_setopt (dl->curl, CURLOPT_URL, dl->URL);

	if (curl_multi_add_handle (multi, dl->curl) != CURLM_OK)
	{
		Com_Printf ("curl_multi_add_handle: error\n");
		dl->queueEntry->state = DLQ_STATE_DONE;
		return;
	}

	handleCount++;
	//Com_Printf ("started dl: hc = %d\n", LOG_GENERAL, handleCount);
	Com_DPrintf  ("CL_StartHTTPDownload: Fetching %s...\n", dl->URL);
	dl->queueEntry->state = DLQ_STATE_RUNNING;
}
Beispiel #18
0
qboolean CL_InitUpdateDownloads(void)
{
#ifdef FEATURE_AUTOUPDATE
	if (autoupdate.updateStarted && NET_CompareAdr(autoupdate.autoupdateServer, clc.serverAddress))
	{
		if (strlen(com_updatefiles->string) > 4)
		{
			char *updateFile;
			char updateFilesRemaining[MAX_TOKEN_CHARS] = "";

			clc.bWWWDl             = qtrue;
			cls.bWWWDlDisconnected = qtrue;

			updateFile = strtok(com_updatefiles->string, ";");

			if (updateFile == NULL)
			{
				Com_Error(ERR_AUTOUPDATE, "Could not parse update string.");
			}
			else
			{
				// download format: @[email protected]
				Q_strncpyz(clc.downloadList, va("@%[email protected]%s", updateFile, updateFile), MAX_INFO_STRING);
				Q_strncpyz(cls.originalDownloadName, updateFile, sizeof(cls.originalDownloadName));
				Q_strncpyz(cls.downloadName, va("%s/%s", UPDATE_SERVER_NAME, updateFile), sizeof(cls.downloadName));
				Q_strncpyz(cls.downloadTempName,
				           FS_BuildOSPath(Cvar_VariableString("fs_homepath"), AUTOUPDATE_DIR, va("%s.tmp", cls.originalDownloadName)),
				           sizeof(cls.downloadTempName));
				// TODO: add file size, so UI can show progress bar
				//Cvar_SetValue("cl_downloadSize", clc.downloadSize);

				if (!DL_BeginDownload(cls.downloadTempName, cls.downloadName))
				{
					Com_Error(ERR_AUTOUPDATE, "Could not download an update file: \"%s\"", cls.downloadName);
					clc.bWWWDlAborting = qtrue;
				}

				while (1)
				{
					updateFile = strtok(NULL, ";");

					if (updateFile == NULL)
					{
						break;
					}

					Q_strcat(updateFilesRemaining, sizeof(updateFilesRemaining), va("%s;", updateFile));
				}

				if (strlen(updateFilesRemaining) > 4)
				{
					Cvar_Set("com_updatefiles", updateFilesRemaining);
				}
				else
				{
					Cvar_Set("com_updatefiles", "");
				}
			}
		}
		return qtrue;
	}
#endif // FEATURE_AUTOUPDATE

	return qfalse;
}
Beispiel #19
0
/*
========================
UI_DrawConnectScreen

This will also be overlaid on the cgame info screen during loading
to prevent it from blinking away too rapidly on local or lan games.
========================
*/
void UI_DrawConnectScreen( qboolean overlay ) {
	char			*s;
	uiClientState_t	cstate;
	char			info[MAX_INFO_VALUE];

	Menu_Cache();

	if ( !overlay ) {
		// draw the dialog background
		UI_SetColor( color_white );
		UI_DrawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, uis.menuBackShader );
	}

	// see what information we should display
	trap_GetClientState( &cstate );

	info[0] = '\0';
	if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) {
		UI_DrawProportionalString( 320, 16, va( "Loading %s", Info_ValueForKey( info, "mapname" ) ), UI_BIGFONT|UI_CENTER|UI_DROPSHADOW, color_white );
	}

	if (!cstate.demoplaying) {
		UI_DrawProportionalString( 320, 64, va("Connecting to %s", cstate.servername), UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
		//UI_DrawProportionalString( 320, 96, "Press Esc to abort", UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
	}

	// display global MOTD at bottom
	UI_DrawProportionalString( SCREEN_WIDTH/2, SCREEN_HEIGHT-32, 
		Info_ValueForKey( cstate.updateInfoString, "motd" ), UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
	
	// print any server info (server full, bad version, etc)
	if ( cstate.connState < CA_CONNECTED ) {
		UI_DrawProportionalString_AutoWrapped( 320, 192, 630, 20, cstate.messageString, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, menu_text_color );
	}

#if 0
	// display password field
	if ( passwordNeeded ) {
		s_ingame_menu.x = SCREEN_WIDTH * 0.50 - 128;
		s_ingame_menu.nitems = 0;
		s_ingame_menu.wrapAround = qtrue;

		passwordField.generic.type = MTYPE_FIELD;
		passwordField.generic.name = "Password:";
		passwordField.generic.callback = 0;
		passwordField.generic.x		= 10;
		passwordField.generic.y		= 180;
		Field_Clear( &passwordField.field );
		passwordField.width = 256;
		passwordField.field.widthInChars = 16;
		Q_strncpyz( passwordField.field.buffer, Cvar_VariableString("password"), 
			sizeof(passwordField.field.buffer) );

		Menu_AddItem( &s_ingame_menu, ( void * ) &s_customize_player_action );

		MField_Draw( &passwordField );
	}
#endif

	if ( lastConnState > cstate.connState ) {
		lastLoadingText[0] = '\0';
	}
	lastConnState = cstate.connState;

	switch ( cstate.connState ) {
	case CA_CONNECTING:
		s = va("Awaiting challenge...%i", cstate.connectPacketCount);
		break;
	case CA_CHALLENGING:
		s = va("Awaiting connection...%i", cstate.connectPacketCount);
		break;
	case CA_CONNECTED: {
		char downloadName[MAX_INFO_VALUE];

			trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) );
			if (*downloadName) {
				UI_DisplayDownloadInfo( downloadName );
				return;
			}
		}
		s = "Awaiting gamestate...";
		break;
	case CA_LOADING:
		return;
	case CA_PRIMED:
		return;
	default:
		return;
	}

	UI_DrawProportionalString( 320, 128, s, UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, color_white );

	// password required / connection rejected information goes here
}
Beispiel #20
0
void *Sys_GetGameAPI (void *parms)
{
	void	*(*GetGameAPI) (void *);
	
	const char	*basepath;
	const char	*cdpath;
	const char	*gamedir;
	const char	*homepath;
	const char	*fn;
	
	const char *gamename;
	if(Cvar_VariableIntegerValue("com_jk2"))
	{
		gamename = "jk2game" ARCH_STRING DLL_EXT;
	}
	else
	{
		gamename = "jagame" ARCH_STRING DLL_EXT;
	}
	
	if (game_library)
		Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
	
	// check the current debug directory first for development purposes
	homepath = Cvar_VariableString( "fs_homepath" );
	basepath = Cvar_VariableString( "fs_basepath" );
	cdpath = Cvar_VariableString( "fs_cdpath" );
	gamedir = Cvar_VariableString( "fs_game" );
	
	if(!gamedir || !gamedir[0])
		gamedir = BASEGAME;
	
	fn = FS_BuildOSPath( basepath, gamedir, gamename );
	
	game_library = Sys_LoadLibrary( fn );
	
//First try in mod directories. basepath -> homepath -> cdpath
	if (!game_library) {
		if (homepath[0]) {
			Com_Printf( "Sys_GetGameAPI(%s) failed: \"%s\"\n", fn, Sys_LibraryError() );
			
			fn = FS_BuildOSPath( homepath, gamedir, gamename);
			game_library = Sys_LoadLibrary( fn );
		}
	}
	
	if (!game_library) {
		if( cdpath[0] ) {
			Com_Printf( "Sys_GetGameAPI(%s) failed: \"%s\"\n", fn, Sys_LibraryError() );
			
			fn = FS_BuildOSPath( cdpath, gamedir, gamename );
			game_library = Sys_LoadLibrary( fn );
		}
	}
	
//Now try in base. basepath -> homepath -> cdpath
	if (!game_library) {
		Com_Printf( "Sys_GetGameAPI(%s) failed: \"%s\"\n", fn, Sys_LibraryError() );
		
		fn = FS_BuildOSPath( basepath, BASEGAME, gamename);
		game_library = Sys_LoadLibrary( fn );
	}
	
	if (!game_library) {
		if ( homepath[0] ) {
			Com_Printf( "Sys_GetGameAPI(%s) failed: \"%s\"\n", fn, Sys_LibraryError() );
			
			fn = FS_BuildOSPath( homepath, BASEGAME, gamename);
			game_library = Sys_LoadLibrary( fn );
		}
	}
	
	if (!game_library) {
		if( cdpath[0] ) {
			Com_Printf( "Sys_GetGameAPI(%s) failed: \"%s\"\n", fn, Sys_LibraryError() );
			
			fn = FS_BuildOSPath( cdpath, BASEGAME, gamename );
			game_library = Sys_LoadLibrary( fn );
		}
	}
//Still couldn't find it.
	if (!game_library) {
		Com_Printf( "Sys_GetGameAPI(%s) failed: \"%s\"\n", fn, Sys_LibraryError() );
		Com_Error( ERR_FATAL, "Couldn't load game" );
	}
	
	
	Com_Printf ( "Sys_GetGameAPI(%s): succeeded ...\n", fn );

	GetGameAPI = (void *(*)(void *))Sys_LoadFunction (game_library, "GetGameAPI");
	if (!GetGameAPI)
	{
		Sys_UnloadGame ();
		return NULL;
	}
	
	return GetGameAPI (parms);
}
Beispiel #21
0
/**
 * @brief Loads a mod library.
 * #1 look in fs_homepath
 * #2 look in fs_basepath
 * #3 try to revert to the default mod library
 */
void *Sys_LoadDll(const char *name,
                  intptr_t(**entryPoint) (int, ...),
                  intptr_t (*systemcalls)(intptr_t, ...))
{
	void *libHandle;
	void (*dllEntry)(intptr_t (*syscallptr)(intptr_t, ...));
	char fname[MAX_OSPATH];
	char *basepath;
	char *homepath;
	char *gamedir;

	assert(name);

	Com_sprintf(fname, sizeof(fname), Sys_GetDLLName("%s"), name);

	// TODO: use fs_searchpaths from files.c
	basepath = Cvar_VariableString("fs_basepath");
	homepath = Cvar_VariableString("fs_homepath");
	gamedir  = Cvar_VariableString("fs_game");

#ifndef DEDICATED
	// if the server is pure, extract the dlls from the mp_bin.pk3 so
	// that they can be referenced
	if (Cvar_VariableValue("sv_pure") && Q_stricmp(name, "qagame"))
	{
		FS_CL_ExtractFromPakFile(homepath, gamedir, fname);
	}
#endif

	libHandle = Sys_TryLibraryLoad(homepath, gamedir, fname);

	if (!libHandle && basepath)
	{
		libHandle = Sys_TryLibraryLoad(basepath, gamedir, fname);
	}

	// HACK: sometimes a library is loaded from the mod dir when it shouldn't. Why?
	if (!libHandle && strcmp(gamedir, DEFAULT_MODGAME))
	{
		Com_Printf("Sys_LoadDll: failed to load the mod library. Trying to revert to the default one.\n");
		libHandle = Sys_TryLibraryLoad(basepath, DEFAULT_MODGAME, fname);
	}

	if (!libHandle)
	{
		Com_Printf("Sys_LoadDll(%s) failed to load library\n", name);
		return NULL;
	}

	dllEntry    = (void (QDECL *)(intptr_t (QDECL *)(intptr_t, ...)))Sys_LoadFunction(libHandle, "dllEntry");
	*entryPoint = (intptr_t (QDECL *)(int, ...))Sys_LoadFunction(libHandle, "vmMain");

	if (!*entryPoint || !dllEntry)
	{
		Com_Printf("Sys_LoadDll(%s) failed to find vmMain function:\n\"%s\" !\n", name, Sys_LibraryError());
		Sys_UnloadLibrary(libHandle);

		return NULL;
	}

	Com_Printf("Sys_LoadDll(%s) found vmMain function at %p\n", name, *entryPoint);
	dllEntry(systemcalls);

	return libHandle;
}
Beispiel #22
0
/*
================
SVC_Info

Responds with a short info message that should be enough to determine
if a user is interested in a server to do a full status
================
*/
void SVC_Info( netadr_t from ) {
	int		i, count, wDisable;
	char	*gamedir;
	char	infostring[MAX_INFO_STRING];

	// ignore if we are in single player
	/*
	if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) {
		return;
	}
	*/

	// don't count privateclients
	count = 0;
	for ( i = sv_privateClients->integer ; i < sv_maxclients->integer ; i++ ) {
		if ( svs.clients[i].state >= CS_CONNECTED ) {
			count++;
		}
	}

	infostring[0] = 0;

	// echo back the parameter to status. so servers can use it as a challenge
	// to prevent timed spoofed reply packets that add ghost servers
	Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );

	if ( JK2MF_GetGameVersion() == JK2_102 )
		Info_SetValueForKey( infostring, "protocol", va("%i", PROTOCOL_VERSION102) );
	else
		Info_SetValueForKey(infostring, "protocol", va("%i", PROTOCOL_VERSION104));

	Info_SetValueForKey( infostring, "hostname", sv_hostname->string );
	Info_SetValueForKey( infostring, "mapname", sv_mapname->string );
	Info_SetValueForKey( infostring, "clients", va("%i", count) );
	Info_SetValueForKey( infostring, "sv_maxclients", 
		va("%i", sv_maxclients->integer - sv_privateClients->integer ) );
	Info_SetValueForKey( infostring, "gametype", va("%i", sv_gametype->integer ) );
	Info_SetValueForKey( infostring, "needpass", va("%i", sv_needpass->integer ) );
	Info_SetValueForKey( infostring, "truejedi", va("%i", Cvar_VariableIntegerValue( "g_jediVmerc" ) ) );
	if ( sv_gametype->integer == GT_TOURNAMENT )
	{
		wDisable = Cvar_VariableIntegerValue( "g_duelWeaponDisable" );
	}
	else
	{
		wDisable = Cvar_VariableIntegerValue( "g_weaponDisable" );
	}
	Info_SetValueForKey( infostring, "wdisable", va("%i", wDisable ) );
	Info_SetValueForKey( infostring, "fdisable", va("%i", Cvar_VariableIntegerValue( "g_forcePowerDisable" ) ) );
	//Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) );

	if( sv_minPing->integer ) {
		Info_SetValueForKey( infostring, "minPing", va("%i", sv_minPing->integer) );
	}
	if( sv_maxPing->integer ) {
		Info_SetValueForKey( infostring, "maxPing", va("%i", sv_maxPing->integer) );
	}
	gamedir = Cvar_VariableString( "fs_game" );
	if( *gamedir ) {
		Info_SetValueForKey( infostring, "game", gamedir );
	}
	Info_SetValueForKey( infostring, "sv_allowAnonymous", va("%i", sv_allowAnonymous->integer) );

	NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring );
}
Beispiel #23
0
void CL_SystemInfoChanged(void)
{
	char       *systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[CS_SYSTEMINFO];
	const char *s, *t;
	char       key[BIG_INFO_KEY];
	char       value[BIG_INFO_VALUE];
	qboolean   gameSet;

	// NOTE: when the serverId changes, any further messages we send to the server will use this new serverId
	// in some cases, outdated cp commands might get sent with this news serverId
	cl.serverId = atoi(Info_ValueForKey(systemInfo, "sv_serverid"));

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

	// don't set any vars when playing a demo
	if (clc.demoplaying)
	{
		return;
	}

	s                         = Info_ValueForKey(systemInfo, "sv_cheats");
	cl_connectedToCheatServer = atoi(s);      //bani
	if (!cl_connectedToCheatServer)
	{
		Cvar_SetCheatState();
	}

	// check pure server string
	s = Info_ValueForKey(systemInfo, "sv_paks");
	t = Info_ValueForKey(systemInfo, "sv_pakNames");
	FS_PureServerSetLoadedPaks(s, t);

	s = Info_ValueForKey(systemInfo, "sv_referencedPaks");
	t = Info_ValueForKey(systemInfo, "sv_referencedPakNames");
	FS_PureServerSetReferencedPaks(s, t);

	gameSet = qfalse;
	// scan through all the variables in the systeminfo and locally set cvars to match
	s = systemInfo;
	while (s)
	{
		int cvar_flags;

		Info_NextPair(&s, key, value);
		if (!key[0])
		{
			break;
		}

		// ehw!
		if (!Q_stricmp(key, "fs_game"))
		{
			if (FS_CheckDirTraversal(value))
			{
				Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value);
				continue;
			}

			gameSet = qtrue;
		}

		if ((cvar_flags = Cvar_Flags(key)) == CVAR_NONEXISTENT)
		{
			Cvar_Get(key, value, CVAR_SERVER_CREATED | CVAR_ROM);
		}
		else
		{
			// If this cvar may not be modified by a server discard the value.
			if (!(cvar_flags & (CVAR_SYSTEMINFO | CVAR_SERVER_CREATED | CVAR_USER_CREATED)))
			{
				if (Q_stricmp(key, "g_synchronousClients") && Q_stricmp(key, "pmove_fixed") &&
				    Q_stricmp(key, "pmove_msec"))
				{
					Com_DPrintf(S_COLOR_YELLOW "WARNING: server is not allowed to set %s=%s\n", key, value);
					continue;
				}
			}

			Cvar_SetSafe(key, value);
		}
	}

	// if game folder should not be set and it is set at the client side
	if (!gameSet && *Cvar_VariableString("fs_game"))
	{
		Cvar_Set("fs_game", "");
	}

	// big hack to clear the image cache on a pure change
	//cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" );
	if (Cvar_VariableValue("sv_pure"))
	{
		if (!cl_connectedToPureServer && cls.state <= CA_CONNECTED)
		{
			CL_PurgeCache();
		}
		cl_connectedToPureServer = qtrue;
	}
	else
	{
		if (cl_connectedToPureServer && cls.state <= CA_CONNECTED)
		{
			CL_PurgeCache();
		}
		cl_connectedToPureServer = qfalse;
	}
}
Beispiel #24
0
// -1 : error,  0 : map already exists,  1 : ok
int DL_Begin( const char *map, qboolean nonblocking )
{
	char url[1024];
	char urlt[1024];
	CURLMcode resm;
	char *c;

	if (!clc.demoplaying) Cvar_Set( "cl_downloadDemo", "" );

	if( DL_Active() ) {
		Com_Printf("Already downloading map '%s'.\n", Cvar_VariableString("cl_downloadName") );
		return -1;
	}

	if (FS_FileIsInPAK(va("maps/%s.bsp", map), NULL) != -1) {
		Com_Printf("Map already exists locally.\n");
		return 0;
	}
	if (strncasecmp(dl_source->string, "http://", 7)) {
		if (strstr(dl_source->string, "://")) {
			Com_Printf("Invalid dl_source.\n");
			return -1;
		}
		Cvar_Set("dl_source", va("http://%s", dl_source->string));
	}
	if ((c = strstr(dl_source->string, "%m")) == 0) {
		Com_Printf("Cvar dl_source is missing a %%m token.\n");
		return -1;
	}
	if (strlen(dl_source->string) -2 +strlen(curl_easy_escape(curl, map, 0)) >= sizeof(url)) {
		Com_Printf("Cvar dl_source too large.\n");
		return -1;
	}

	Q_strncpyz(url, dl_source->string, c-dl_source->string +1);	// +1 makes room for the trailing 0
	Com_sprintf(urlt, sizeof(urlt), "%s%s%s", url, curl_easy_escape(curl, map, 0), c+2);
	strcpy(url,urlt);

	// set a default destination filename; Content-Disposition headers will override.
	Com_sprintf(path, sizeof(path), "%s.pk3", map);

	curl = curl_easy_init();
	if (!curl) {
		Com_Printf("Download failed to initialize.\n");
		return -1;
	}

	*dl_error = 0;
	*motd = 0;
	curl_easy_setopt(curl, CURLOPT_URL, url);
	curl_easy_setopt(curl, CURLOPT_USERAGENT, useragent);
	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);	// fail if http returns an error code
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Curl_WriteCallback_f);
	curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, Curl_HeaderCallback_f);
	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
	curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, Curl_VerboseCallback_f);
	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, Curl_ProgressCallback_f);
	//curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)(4*1024) ); // 4 KB/s for testing timeouts

	if( nonblocking )
	{
		curlm = curl_multi_init();
		if( !curlm )
		{
			curl_easy_cleanup( curl );
			curl = NULL;
			Com_Printf("Download failed to initialize ( nonblocking ).\n");
			return -1;
		}
		resm = curl_multi_add_handle( curlm, curl );
		if( resm != CURLM_OK )
		{
			curl_multi_cleanup( curlm );
			curl_easy_cleanup( curl );
			curlm = NULL;
			curl = NULL;
			Com_Printf("Download failed to initialize ( nonblocking ).\n");
			return -1;
		}	
	}

	Com_Printf("Attempting download: %s\n", url);

	Cvar_Set( "cl_downloadName", map );  // show the ui download progress screen
	Cvar_SetValue( "cl_downloadSize", 0 );
	Cvar_SetValue( "cl_downloadCount", 0 );
	Cvar_SetValue( "cl_downloadTime", cls.realtime ); // download start time offset

	return 1;
}
Beispiel #25
0
/*
==================
CL_SystemInfoChanged

The systeminfo configstring has been changed, so parse
new information out of it.  This will happen at every
gamestate, and possibly during gameplay.
==================
*/
void CL_SystemInfoChanged( void ) {
    char			*systemInfo;
    const char		*s, *t;
    char			key[BIG_INFO_KEY];
    char			value[BIG_INFO_VALUE];
    qboolean		gameSet;

    systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ];
    // NOTE TTimo:
    // when the serverId changes, any further messages we send to the server will use this new serverId
    // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
    // in some cases, outdated cp commands might get sent with this new serverId
    cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) );

    // don't set any vars when playing a demo
    if ( clc.demoplaying ) {
        return;
    }

    s = Info_ValueForKey( systemInfo, "sv_cheats" );
    cl_connectedToCheatServer = atoi( s );
    if ( !cl_connectedToCheatServer )
    {
        Cvar_SetCheatState();
    }

    // check pure server string
    s = Info_ValueForKey( systemInfo, "sv_paks" );
    t = Info_ValueForKey( systemInfo, "sv_pakNames" );
    FS_PureServerSetLoadedPaks( s, t );

    s = Info_ValueForKey( systemInfo, "sv_referencedPaks" );
    t = Info_ValueForKey( systemInfo, "sv_referencedPakNames" );
    FS_PureServerSetReferencedPaks( s, t );

    gameSet = qfalse;
    // scan through all the variables in the systeminfo and locally set cvars to match
    s = systemInfo;
    while ( s ) {
        Info_NextPair( &s, key, value );
        if ( !key[0] ) {
            break;
        }
        // ehw!
        if ( !Q_stricmp( key, "fs_game" ) ) {
            if(FS_CheckDirTraversal(value))
            {
                Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value);
                continue;
            }

            if(!FS_FilenameCompare(value, BASEGAME))
            {
                Com_Printf(S_COLOR_YELLOW "WARNING: Server sent \"%s\" fs_game value, clearing.\n", value);
                Q_strncpyz(value, "", sizeof(value));
            }

            gameSet = qtrue;
        }
        Cvar_Server_Set( key, value );
    }
    // if game folder should not be set and it is set at the client side
    if ( !gameSet && *Cvar_VariableString("fs_game") ) {
        Cvar_Set( "fs_game", "" );
    }
    cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" );
}
Beispiel #26
0
void DL_End( CURLcode res, CURLMcode resm )
{
	CURLMsg *msg;
	int msgs;

	if( dl_verbose->integer == 0 && dl_showprogress->integer == 2 && !curlm )
		Com_Printf( "\n" );
	
	if( curlm )
	{	
		// res = final download result
		while( ( msg = curl_multi_info_read( curlm, &msgs ) ) )
		{
			if( msg->msg != CURLMSG_DONE )
			{
				if( dl_error[0] == '\0' )
					Q_strncpyz( dl_error, "Download Interrupted.", sizeof(dl_error) );
			}
			else if( msg->easy_handle == curl )
			{
				if( msg->data.result != CURLE_OK );
					res = msg->data.result;
			}
			else
			{
				Com_Printf( "Invalid cURL handle.\n" );
			}
		}

		curl_multi_cleanup( curlm );
		curlm = NULL;		
	}

	if( curl )
	{
		curl_easy_cleanup( curl );
		curl = NULL;
	}

	// get possible error messages
	if( !*dl_error && res != CURLE_OK )
		Q_strncpyz( dl_error, curl_easy_strerror(res), sizeof(dl_error) );
	if( !*dl_error && resm != CURLM_OK )
		Q_strncpyz( dl_error, curl_multi_strerror(resm), sizeof(dl_error) );
	if( !*dl_error && !f )
		Q_strncpyz( dl_error, "File is not opened.", sizeof(dl_error) );

	if (f) {
		FS_FCloseFile(f);
		f = 0;
		if (!*dl_error) {	// download succeeded
			char dest[MAX_OSPATH];
			Com_Printf("Download complete, restarting filesystem.\n");
			Q_strncpyz(dest, path, strlen(path)-3);	// -4 +1 for the trailing \0
			Q_strcat(dest, sizeof(dest), ".pk3");
			if (!FS_FileExists(dest)) {
				FS_SV_Rename(path, dest);
				FS_Restart(clc.checksumFeed);
				if (dl_showmotd->integer && *motd) {
					Com_Printf("Server motd: %s\n", motd);
				}
			} else {
				// normally such errors should be caught upon starting the transfer. Anyway better do
				// it here again - the filesystem might have changed, plus this may help contain some
				// bugs / exploitable flaws in the code.
				Com_Printf("Failed to copy downloaded file to its location - file already exists.\n");
				FS_HomeRemove(path);
			}
		} else {
			FS_HomeRemove(path);
		}
	}

	Cvar_Set( "cl_downloadName", "" );  // hide the ui downloading screen
	Cvar_SetValue( "cl_downloadSize", 0 );
	Cvar_SetValue( "cl_downloadCount", 0 );
	Cvar_SetValue( "cl_downloadTime", 0 );
	Cvar_Set( "cl_downloadMotd", "" );

	if( *dl_error )
	{
		if( clc.state == CA_CONNECTED )
			Com_Error( ERR_DROP, "%s\n", dl_error ); // download error while connecting, can not continue loading
		else
			Com_Printf( "%s\n", dl_error ); // download error while in game, do not disconnect

		*dl_error = '\0';
	}
	else
	{
		if (strlen(Cvar_VariableString("cl_downloadDemo"))) {
			Cbuf_AddText( va("demo %s\n", Cvar_VariableString("cl_downloadDemo") ) );
		// download completed, request new gamestate to check possible new map if we are not already in game
		} else if( clc.state == CA_CONNECTED)
			CL_AddReliableCommand( "donedl", qfalse); // get new gamestate info from server
	}
}
Beispiel #27
0
/*
==================
CL_SystemInfoChanged

The systeminfo configstring has been changed, so parse
new information out of it.  This will happen at every
gamestate, and possibly during gameplay.
==================
*/
void CL_SystemInfoChanged( void ) {
	char            *systemInfo;
	const char      *s, *t;
	char key[BIG_INFO_KEY];
	char value[BIG_INFO_VALUE];
	qboolean		gameSet;

	systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ];
	cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) );

#ifdef USE_VOIP
#ifdef LEGACY_PROTOCOL
	if(clc.compat)
		clc.voipEnabled = qfalse;
	else
#endif
	{
		s = Info_ValueForKey( systemInfo, "sv_voipProtocol" );
		clc.voipEnabled = !Q_stricmp(s, "opus");
	}
#endif

	// don't set any vars when playing a demo
	if ( clc.demoplaying ) {
		return;
	}

	s = Info_ValueForKey( systemInfo, "sv_cheats" );
	cl_connectedToCheatServer = atoi( s );
	if ( !cl_connectedToCheatServer ) {
		Cvar_SetCheatState();
	}

	// check pure server string
	s = Info_ValueForKey( systemInfo, "sv_paks" );
	t = Info_ValueForKey( systemInfo, "sv_pakNames" );
	FS_PureServerSetLoadedPaks( s, t );

	s = Info_ValueForKey( systemInfo, "sv_referencedPaks" );
	t = Info_ValueForKey( systemInfo, "sv_referencedPakNames" );
	FS_PureServerSetReferencedPaks( s, t );

	gameSet = qfalse;
	// scan through all the variables in the systeminfo and locally set cvars to match
	s = systemInfo;
	while ( s ) {
		int cvar_flags;
		
		Info_NextPair( &s, key, value );
		if ( !key[0] ) {
			break;
		}
		
		// ehw!
		if (!Q_stricmp(key, "fs_game"))
		{
			if(FS_CheckDirTraversal(value))
			{
				Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value);
				continue;
			}
				
			gameSet = qtrue;
		}

		if((cvar_flags = Cvar_Flags(key)) == CVAR_NONEXISTENT)
			Cvar_Get(key, value, CVAR_SERVER_CREATED | CVAR_ROM);
		else
		{
			// If this cvar may not be modified by a server discard the value.
			if(!(cvar_flags & (CVAR_SYSTEMINFO | CVAR_SERVER_CREATED | CVAR_USER_CREATED)))
			{
#ifndef STANDALONE
				if(Q_stricmp(key, "g_synchronousClients") && Q_stricmp(key, "pmove_fixed") &&
				   Q_stricmp(key, "pmove_msec"))
#endif
				{
					Com_DPrintf(S_COLOR_YELLOW "WARNING: server is not allowed to set %s=%s\n", key, value);
					continue;
				}
			}

			Cvar_SetSafe(key, value);
		}
	}
	// if game folder should not be set and it is set at the client side
	if ( !gameSet && *Cvar_VariableString("fs_game") ) {
		Cvar_Set( "fs_game", "" );
	}
	cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" );
}
Beispiel #28
0
std::string pjkCvarStrValue(const char * name) {
	return std::string(Cvar_VariableString(name));
}
/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f( void ) {
	int			i;
	client_t	*client;
	char		*denied;
	qboolean	isBot;
	int			delay;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId ) {
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer ) {
		Com_Printf( "Server is not running.\n" );
		return;
	}

	if ( sv.restartTime ) {
		return;
	}

	if (Cmd_Argc() > 1 ) {
		delay = atoi( Cmd_Argv(1) );
	}
	else {
		delay = 5;
	}
	if( delay && !Cvar_VariableValue("g_doWarmup") ) {
		sv.restartTime = sv.time + delay * 1000;
		SV_SetConfigstring( CS_WARMUP, va("%i", sv.restartTime) );
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified || sv_gametype->modified ) {
		char	mapname[MAX_QPATH];

		Com_Printf( "variable change -- restarting.\n" );
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );

		SV_SpawnServer( mapname, qfalse );
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid	
	// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va("%i", sv.serverId ) );

	// if a map_restart occurs while a client is changing maps, we need
	// to give them the correct time so that when they finish loading
	// they don't violate the backwards time check in cl_cgame.c
	for (i = 0; i < sv_maxclients->integer; i++) {
		if (svs.clients[i].state == CS_PRIMED) {
			svs.clients[i].oldServerTime = sv.restartTime;
		}
	}

	// reset all the vm data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = SS_LOADING;
	sv.restarting = qtrue;

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for (i = 0; i < 3; i++)
	{
		VM_Call (gvm, GAME_RUN_FRAME, sv.time);
		sv.time += 100;
		svs.time += 100;
	}

	sv.state = SS_GAME;
	sv.restarting = qfalse;

	// connect and begin all the clients
	for (i=0 ; i<sv_maxclients->integer ; i++) {

		client = &svs.clients[i];

		// send the new gamestate to all connected clients
		if ( client->state < CS_CONNECTED) {
			continue;
		}

		if ( client->netchan.remoteAddress.type == NA_BOT ) {
			isBot = qtrue;
		} else {
			isBot = qfalse;
		}

		// add the map_restart command
		SV_AddServerCommand( client, "map_restart\n" );

		// connect the client again, without the firstTime flag
		denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) );
		if ( denied ) {
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient( client, denied );
			Com_Printf( "SV_MapRestart_f(%d): dropped client %i - denied!\n", delay, i );
			continue;
		}

		if(client->state == CS_ACTIVE) {
			SV_ClientEnterWorld(client, &client->lastUsercmd);
		}
		else {
			// If we don't reset client->lastUsercmd and are restarting during map load,
		 	// the client will hang because we'll use the last Usercmd from the previous map,
		 	// which is wrong obviously.
		 	SV_ClientEnterWorld(client, NULL);
		}
	}	

	// run another frame to allow things to look at all the players
	VM_Call (gvm, GAME_RUN_FRAME, sv.time);
	sv.time += 100;
	svs.time += 100;
}
/*
==================
SV_Frame

Player movement occurs as a result of packet events, which
happen before SV_Frame is called
==================
*/
void SV_Frame( int msec ) {
	int		frameMsec;
	int		startTime;

	// the menu kills the server with this cvar
	if ( sv_killserver->integer ) {
		SV_Shutdown ("Server was killed");
		Cvar_Set( "sv_killserver", "0" );
		return;
	}

	if (!com_sv_running->integer)
	{
           if(com_dedicated->integer)
           {
            // Block indefinitely until something interesting happens
            // on STDIN.
            NET_Sleep(-1);
           }
		return;
	}

	// allow pause if only the local client is connected
	if ( SV_CheckPaused() ) {
		return;
	}

	// if it isn't time for the next frame, do nothing
	if ( sv_fps->integer < 1 ) {
		Cvar_Set( "sv_fps", "10" );
	}

	frameMsec = 1000 / sv_fps->integer * com_timescale->value;
	// don't let it scale below 1ms
	if(frameMsec < 1)
	{
		Cvar_Set("timescale", va("%f", sv_fps->integer / 1000.0f));
		frameMsec = 1;
	}

	sv.timeResidual += msec;

	if (!com_dedicated->integer) SV_BotFrame (sv.time + sv.timeResidual);

	if ( com_dedicated->integer && sv.timeResidual < frameMsec ) {
		// NET_Sleep will give the OS time slices until either get a packet
		// or time enough for a server frame has gone by
		NET_Sleep(frameMsec - sv.timeResidual);
		return;
	}

	// if time is about to hit the 32nd bit, kick all clients
	// and clear sv.time, rather
	// than checking for negative time wraparound everywhere.
	// 2giga-milliseconds = 23 days, so it won't be too often
	if ( svs.time > 0x70000000 ) {
		SV_Shutdown( "Restarting server due to time wrapping" );
		Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "mapname" ) ) );
		return;
	}
	// this can happen considerably earlier when lots of clients play and the map doesn't change
	if ( svs.nextSnapshotEntities >= 0x7FFFFFFE - svs.numSnapshotEntities ) {
		SV_Shutdown( "Restarting server due to numSnapshotEntities wrapping" );
		Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "mapname" ) ) );
		return;
	}

	if( sv.restartTime && sv.time >= sv.restartTime ) {
		sv.restartTime = 0;
		Cbuf_AddText( "map_restart 0\n" );
		return;
	}

	// update infostrings if anything has been changed
	if ( cvar_modifiedFlags & CVAR_SERVERINFO ) {
		SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );
		cvar_modifiedFlags &= ~CVAR_SERVERINFO;
	}
	if ( cvar_modifiedFlags & CVAR_SYSTEMINFO ) {
		SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString_Big( CVAR_SYSTEMINFO ) );
		cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;
	}

	if ( com_speeds->integer ) {
		startTime = Sys_Milliseconds ();
	} else {
		startTime = 0;	// quite a compiler warning
	}

	// update ping based on the all received frames
	SV_CalcPings();

	if (com_dedicated->integer) SV_BotFrame (sv.time);

	// run the game simulation in chunks
	while ( sv.timeResidual >= frameMsec ) {
		sv.timeResidual -= frameMsec;
		svs.time += frameMsec;
		sv.time += frameMsec;

		// let everything in the world think and move
		VM_Call (gvm, GAME_RUN_FRAME, sv.time);
	}

	if ( com_speeds->integer ) {
		time_game = Sys_Milliseconds () - startTime;
	}

	// check timeouts
	SV_CheckTimeouts();
	
	// check user info buffer thingy
	SV_CheckClientUserinfoTimer();

	// send messages back to the clients
	SV_SendClientMessages();
        
        // send a heartbeat to the master if needed
	SV_MasterHeartbeat();
}