2013-04-04 14:52:42 +00:00
|
|
|
|
|
|
|
#include "server.h"
|
2013-04-04 18:02:27 +00:00
|
|
|
#include "../strings/str_server.h"
|
|
|
|
#include "../qcommon/strip.h"
|
2013-04-04 14:52:42 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
===============================================================================
|
|
|
|
|
|
|
|
OPERATOR CONSOLE ONLY COMMANDS
|
|
|
|
|
|
|
|
These commands can only be entered from stdin or by a remote operator datagram
|
|
|
|
===============================================================================
|
|
|
|
*/
|
|
|
|
|
2013-04-04 18:24:26 +00:00
|
|
|
const char *SV_GetStripEdString(char *refSection, char *refName)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
static char text[1024]={0};
|
|
|
|
trap_SP_GetStringTextString(va("%s_%s", refSection, refName), text, sizeof(text));
|
|
|
|
return text;
|
|
|
|
*/
|
|
|
|
|
|
|
|
//Well, it would've been lovely doing it the above way, but it would mean mixing
|
|
|
|
//languages for the client depending on what the server is. So we'll mark this as
|
|
|
|
//a striped reference with @@@ and send the refname to the client, and when it goes
|
|
|
|
//to print it will get scanned for the striped reference indication and dealt with
|
|
|
|
//properly.
|
|
|
|
static char text[1024]={0};
|
|
|
|
Com_sprintf(text, sizeof(text), "@@@%s", refName);
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-04-04 14:52:42 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_GetPlayerByName
|
|
|
|
|
|
|
|
Returns the player with name from Cmd_Argv(1)
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
static client_t *SV_GetPlayerByName( void ) {
|
|
|
|
client_t *cl;
|
|
|
|
int i;
|
|
|
|
char *s;
|
|
|
|
char cleanName[64];
|
|
|
|
|
|
|
|
// make sure server is running
|
|
|
|
if ( !com_sv_running->integer ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Cmd_Argc() < 2 ) {
|
|
|
|
Com_Printf( "No player specified.\n" );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = Cmd_Argv(1);
|
|
|
|
|
|
|
|
// check for a name match
|
|
|
|
for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) {
|
|
|
|
if ( !cl->state ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ( !Q_stricmp( cl->name, s ) ) {
|
|
|
|
return cl;
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_strncpyz( cleanName, cl->name, sizeof(cleanName) );
|
|
|
|
Q_CleanStr( cleanName );
|
|
|
|
if ( !Q_stricmp( cleanName, s ) ) {
|
|
|
|
return cl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf( "Player %s is not on the server\n", s );
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_GetPlayerByNum
|
|
|
|
|
|
|
|
Returns the player with idnum from Cmd_Argv(1)
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
static client_t *SV_GetPlayerByNum( void ) {
|
|
|
|
client_t *cl;
|
|
|
|
int i;
|
|
|
|
int idnum;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
// make sure server is running
|
|
|
|
if ( !com_sv_running->integer ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Cmd_Argc() < 2 ) {
|
|
|
|
Com_Printf( "No player specified.\n" );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = Cmd_Argv(1);
|
|
|
|
|
|
|
|
for (i = 0; s[i]; i++) {
|
|
|
|
if (s[i] < '0' || s[i] > '9') {
|
|
|
|
Com_Printf( "Bad slot number: %s\n", s);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
idnum = atoi( s );
|
|
|
|
if ( idnum < 0 || idnum >= sv_maxclients->integer ) {
|
|
|
|
Com_Printf( "Bad client slot: %i\n", idnum );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cl = &svs.clients[idnum];
|
|
|
|
if ( !cl->state ) {
|
|
|
|
Com_Printf( "Client %i is not active\n", idnum );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return cl;
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_Map_f
|
|
|
|
|
|
|
|
Restart the server on a different map
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
static void SV_Map_f( void ) {
|
|
|
|
char *cmd;
|
|
|
|
char *map;
|
|
|
|
qboolean killBots, cheat;
|
|
|
|
char expanded[MAX_QPATH];
|
|
|
|
char mapname[MAX_QPATH];
|
|
|
|
|
|
|
|
map = Cmd_Argv(1);
|
|
|
|
if ( !map ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure the level exists before trying to change, so that
|
|
|
|
// a typo at the server console won't end the game
|
|
|
|
if (strchr (map, '\\') ) {
|
|
|
|
Com_Printf ("Can't have mapnames with a \\\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map);
|
|
|
|
if ( FS_ReadFile (expanded, NULL) == -1 ) {
|
|
|
|
Com_Printf ("Can't find map %s\n", expanded);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// force latched values to get set
|
|
|
|
Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH );
|
|
|
|
|
|
|
|
cmd = Cmd_Argv(0);
|
|
|
|
if( Q_stricmpn( cmd, "sp", 2 ) == 0 ) {
|
|
|
|
Cvar_SetValue( "g_gametype", GT_SINGLE_PLAYER );
|
|
|
|
Cvar_SetValue( "g_doWarmup", 0 );
|
|
|
|
// may not set sv_maxclients directly, always set latched
|
|
|
|
Cvar_SetLatched( "sv_maxclients", "8" );
|
|
|
|
cmd += 2;
|
|
|
|
cheat = qfalse;
|
|
|
|
killBots = qtrue;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ( !Q_stricmpn( cmd, "devmap",6 ) || !Q_stricmp( cmd, "spdevmap" ) ) {
|
|
|
|
cheat = qtrue;
|
|
|
|
killBots = qtrue;
|
|
|
|
} else {
|
|
|
|
cheat = qfalse;
|
|
|
|
killBots = qfalse;
|
|
|
|
}
|
2013-04-04 21:05:53 +00:00
|
|
|
/*
|
2013-04-04 14:52:42 +00:00
|
|
|
if( sv_gametype->integer == GT_SINGLE_PLAYER ) {
|
|
|
|
Cvar_SetValue( "g_gametype", GT_FFA );
|
|
|
|
}
|
2013-04-04 21:05:53 +00:00
|
|
|
*/
|
2013-04-04 14:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// save the map name here cause on a map restart we reload the jk2mpconfig.cfg
|
|
|
|
// and thus nuke the arguments of the map command
|
|
|
|
Q_strncpyz(mapname, map, sizeof(mapname));
|
|
|
|
|
|
|
|
ForceReload_e eForceReload = eForceReload_NOTHING; // default for normal load
|
|
|
|
|
|
|
|
// if ( !Q_stricmp( cmd, "devmapbsp") ) { // not relevant in MP codebase
|
|
|
|
// eForceReload = eForceReload_BSP;
|
|
|
|
// }
|
|
|
|
// else
|
|
|
|
if ( !Q_stricmp( cmd, "devmapmdl") ) {
|
|
|
|
eForceReload = eForceReload_MODELS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if ( !Q_stricmp( cmd, "devmapall") ) {
|
|
|
|
eForceReload = eForceReload_ALL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// start up the map
|
|
|
|
SV_SpawnServer( mapname, killBots, eForceReload );
|
|
|
|
|
|
|
|
// set the cheat value
|
|
|
|
// if the level was started with "map <levelname>", then
|
|
|
|
// cheats will not be allowed. If started with "devmap <levelname>"
|
|
|
|
// then cheats will be allowed
|
|
|
|
if ( cheat ) {
|
|
|
|
Cvar_Set( "sv_cheats", "1" );
|
|
|
|
} else {
|
|
|
|
Cvar_Set( "sv_cheats", "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;
|
|
|
|
}
|
2013-04-04 18:24:26 +00:00
|
|
|
if( delay && (!Cvar_VariableValue("g_doWarmup") || Cvar_VariableValue("g_gametype") == GT_TOURNAMENT) ) {
|
2013-04-04 14:52:42 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===============================================================
|
|
|
|
|
2013-04-04 18:24:26 +00:00
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_GetPlayerByName
|
|
|
|
|
|
|
|
Returns the player with name from Cmd_Argv(1)
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
static client_t *SV_GetPlayerByFedName( const char *name )
|
|
|
|
{
|
|
|
|
client_t *cl;
|
|
|
|
int i;
|
|
|
|
char cleanName[64];
|
|
|
|
|
|
|
|
// make sure server is running
|
|
|
|
if ( !com_sv_running->integer )
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for a name match
|
|
|
|
for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ )
|
|
|
|
{
|
|
|
|
if ( !cl->state )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ( !Q_stricmp( cl->name, name ) )
|
|
|
|
{
|
|
|
|
return cl;
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_strncpyz( cleanName, cl->name, sizeof(cleanName) );
|
|
|
|
Q_CleanStr( cleanName );
|
|
|
|
if ( !Q_stricmp( cleanName, name ) )
|
|
|
|
{
|
|
|
|
return cl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SV_KickByName( const char *name )
|
|
|
|
{
|
|
|
|
client_t *cl;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// make sure server is running
|
|
|
|
if ( !com_sv_running->integer )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cl = SV_GetPlayerByFedName(name);
|
|
|
|
if ( !cl )
|
|
|
|
{
|
|
|
|
if ( !Q_stricmp(name, "all") )
|
|
|
|
{
|
|
|
|
for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ )
|
|
|
|
{
|
|
|
|
if ( !cl->state )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if( cl->netchan.remoteAddress.type == NA_LOOPBACK )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" );
|
|
|
|
cl->lastPacketTime = svs.time; // in case there is a funny zombie
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( !Q_stricmp(name, "allbots") )
|
|
|
|
{
|
|
|
|
for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ )
|
|
|
|
{
|
|
|
|
if ( !cl->state )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if( cl->netchan.remoteAddress.type != NA_BOT )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" );
|
|
|
|
cl->lastPacketTime = svs.time; // in case there is a funny zombie
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if( cl->netchan.remoteAddress.type == NA_LOOPBACK )
|
|
|
|
{
|
|
|
|
// SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
|
|
|
|
SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" );
|
|
|
|
cl->lastPacketTime = svs.time; // in case there is a funny zombie
|
|
|
|
}
|
|
|
|
|
2013-04-04 14:52:42 +00:00
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_Kick_f
|
|
|
|
|
|
|
|
Kick a user off of the server FIXME: move to game
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
static void SV_Kick_f( void ) {
|
|
|
|
client_t *cl;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// make sure server is running
|
|
|
|
if ( !com_sv_running->integer ) {
|
|
|
|
Com_Printf( "Server is not running.\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Cmd_Argc() != 2 ) {
|
|
|
|
Com_Printf ("Usage: kick <player name>\nkick all = kick everyone\nkick allbots = kick all bots\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-04 18:24:26 +00:00
|
|
|
if (!Q_stricmp(Cmd_Argv(1), "Padawan"))
|
|
|
|
{ //if you try to kick the default name, also try to kick ""
|
|
|
|
SV_KickByName("");
|
|
|
|
}
|
|
|
|
|
2013-04-04 14:52:42 +00:00
|
|
|
cl = SV_GetPlayerByName();
|
|
|
|
if ( !cl ) {
|
|
|
|
if ( !Q_stricmp(Cmd_Argv(1), "all") ) {
|
|
|
|
for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) {
|
|
|
|
if ( !cl->state ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-04-04 18:24:26 +00:00
|
|
|
SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" );
|
2013-04-04 14:52:42 +00:00
|
|
|
cl->lastPacketTime = svs.time; // in case there is a funny zombie
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( !Q_stricmp(Cmd_Argv(1), "allbots") ) {
|
|
|
|
for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) {
|
|
|
|
if ( !cl->state ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if( cl->netchan.remoteAddress.type != NA_BOT ) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-04-04 18:24:26 +00:00
|
|
|
SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" );
|
2013-04-04 14:52:42 +00:00
|
|
|
cl->lastPacketTime = svs.time; // in case there is a funny zombie
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
|
2013-04-04 18:24:26 +00:00
|
|
|
// SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
|
|
|
|
SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST"));
|
2013-04-04 14:52:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-04 18:24:26 +00:00
|
|
|
SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" );
|
2013-04-04 14:52:42 +00:00
|
|
|
cl->lastPacketTime = svs.time; // in case there is a funny zombie
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_Ban_f
|
|
|
|
|
|
|
|
Ban a user from being able to play on this server through the auth
|
|
|
|
server
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
#ifdef USE_CD_KEY
|
|
|
|
|
|
|
|
static void SV_Ban_f( void ) {
|
|
|
|
client_t *cl;
|
|
|
|
|
|
|
|
// make sure server is running
|
|
|
|
if ( !com_sv_running->integer ) {
|
|
|
|
Com_Printf( "Server is not running.\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Cmd_Argc() != 2 ) {
|
|
|
|
Com_Printf ("Usage: banUser <player name>\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cl = SV_GetPlayerByName();
|
|
|
|
|
|
|
|
if (!cl) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
|
2013-04-04 18:24:26 +00:00
|
|
|
// SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
|
|
|
|
SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST"));
|
2013-04-04 14:52:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// look up the authorize server's IP
|
|
|
|
if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
|
|
|
|
Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
|
|
|
|
if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {
|
|
|
|
Com_Printf( "Couldn't resolve address\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
|
|
|
|
Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
|
|
|
|
svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
|
|
|
|
svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
|
|
|
|
BigShort( svs.authorizeAddress.port ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise send their ip to the authorize server
|
|
|
|
if ( svs.authorizeAddress.type != NA_BAD ) {
|
|
|
|
NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
|
|
|
|
"banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1],
|
|
|
|
cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
|
|
|
|
Com_Printf("%s was banned from coming back\n", cl->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_BanNum_f
|
|
|
|
|
|
|
|
Ban a user from being able to play on this server through the auth
|
|
|
|
server
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
static void SV_BanNum_f( void ) {
|
|
|
|
client_t *cl;
|
|
|
|
|
|
|
|
// make sure server is running
|
|
|
|
if ( !com_sv_running->integer ) {
|
|
|
|
Com_Printf( "Server is not running.\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Cmd_Argc() != 2 ) {
|
|
|
|
Com_Printf ("Usage: banClient <client number>\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cl = SV_GetPlayerByNum();
|
|
|
|
if ( !cl ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
|
2013-04-04 18:24:26 +00:00
|
|
|
// SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
|
|
|
|
SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST"));
|
2013-04-04 14:52:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// look up the authorize server's IP
|
|
|
|
if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
|
|
|
|
Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
|
|
|
|
if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {
|
|
|
|
Com_Printf( "Couldn't resolve address\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
|
|
|
|
Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
|
|
|
|
svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
|
|
|
|
svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
|
|
|
|
BigShort( svs.authorizeAddress.port ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise send their ip to the authorize server
|
|
|
|
if ( svs.authorizeAddress.type != NA_BAD ) {
|
|
|
|
NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
|
|
|
|
"banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1],
|
|
|
|
cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
|
|
|
|
Com_Printf("%s was banned from coming back\n", cl->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // USE_CD_KEY
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_KickNum_f
|
|
|
|
|
|
|
|
Kick a user off of the server FIXME: move to game
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
static void SV_KickNum_f( void ) {
|
|
|
|
client_t *cl;
|
|
|
|
|
|
|
|
// make sure server is running
|
|
|
|
if ( !com_sv_running->integer ) {
|
|
|
|
Com_Printf( "Server is not running.\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Cmd_Argc() != 2 ) {
|
|
|
|
Com_Printf ("Usage: kicknum <client number>\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cl = SV_GetPlayerByNum();
|
|
|
|
if ( !cl ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) {
|
2013-04-04 18:24:26 +00:00
|
|
|
// SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n");
|
|
|
|
SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST"));
|
2013-04-04 14:52:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-04 18:24:26 +00:00
|
|
|
SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" );
|
2013-04-04 14:52:42 +00:00
|
|
|
cl->lastPacketTime = svs.time; // in case there is a funny zombie
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
SV_Status_f
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
static void SV_Status_f( void )
|
|
|
|
{
|
2013-04-04 21:05:53 +00:00
|
|
|
int i;
|
2013-04-04 14:52:42 +00:00
|
|
|
client_t *cl;
|
|
|
|
playerState_t *ps;
|
|
|
|
const char *s;
|
|
|
|
int ping;
|
2013-04-04 21:05:53 +00:00
|
|
|
char state[32];
|
2013-04-04 22:24:29 +00:00
|
|
|
qboolean avoidTruncation = qfalse;
|
2013-04-04 14:52:42 +00:00
|
|
|
|
|
|
|
// make sure server is running
|
|
|
|
if ( !com_sv_running->integer )
|
|
|
|
{
|
|
|
|
Com_Printf( SP_GetStringText(STR_SERVER_SERVER_NOT_RUNNING) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-04 22:24:29 +00:00
|
|
|
if ( Cmd_Argc() > 1 )
|
|
|
|
{
|
|
|
|
if (!Q_stricmp("notrunc", Cmd_Argv(1)))
|
|
|
|
{
|
|
|
|
avoidTruncation = qtrue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-04 14:52:42 +00:00
|
|
|
Com_Printf ("map: %s\n", sv_mapname->string );
|
|
|
|
|
|
|
|
Com_Printf ("num score ping name lastmsg address qport rate\n");
|
|
|
|
Com_Printf ("--- ----- ---- --------------- ------- --------------------- ----- -----\n");
|
|
|
|
for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++)
|
|
|
|
{
|
|
|
|
if (!cl->state)
|
2013-04-04 21:05:53 +00:00
|
|
|
{
|
2013-04-04 14:52:42 +00:00
|
|
|
continue;
|
2013-04-04 21:05:53 +00:00
|
|
|
}
|
2013-04-04 14:52:42 +00:00
|
|
|
|
|
|
|
if (cl->state == CS_CONNECTED)
|
2013-04-04 21:05:53 +00:00
|
|
|
{
|
|
|
|
strcpy(state, "CNCT ");
|
|
|
|
}
|
2013-04-04 14:52:42 +00:00
|
|
|
else if (cl->state == CS_ZOMBIE)
|
2013-04-04 21:05:53 +00:00
|
|
|
{
|
|
|
|
strcpy(state, "ZMBI ");
|
|
|
|
}
|
2013-04-04 14:52:42 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ping = cl->ping < 9999 ? cl->ping : 9999;
|
2013-04-04 21:05:53 +00:00
|
|
|
sprintf(state, "%4i", ping);
|
2013-04-04 14:52:42 +00:00
|
|
|
}
|
|
|
|
|
2013-04-04 21:05:53 +00:00
|
|
|
ps = SV_GameClientNum( i );
|
2013-04-04 14:52:42 +00:00
|
|
|
s = NET_AdrToString( cl->netchan.remoteAddress );
|
2013-04-04 22:24:29 +00:00
|
|
|
|
|
|
|
if (!avoidTruncation)
|
|
|
|
{
|
|
|
|
Com_Printf ("%3i %5i %s %-15.15s %7i %21s %5i %5i\n",
|
|
|
|
i,
|
|
|
|
ps->persistant[PERS_SCORE],
|
|
|
|
state,
|
|
|
|
cl->name,
|
|
|
|
svs.time - cl->lastPacketTime,
|
|
|
|
s,
|
|
|
|
cl->netchan.qport,
|
|
|
|
cl->rate
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Com_Printf ("%3i %5i %s %s %7i %21s %5i %5i\n",
|
|
|
|
i,
|
|
|
|
ps->persistant[PERS_SCORE],
|
|
|
|
state,
|
|
|
|
cl->name,
|
|
|
|
svs.time - cl->lastPacketTime,
|
|
|
|
s,
|
|
|
|
cl->netchan.qport,
|
|
|
|
cl->rate
|
|
|
|
);
|
|
|
|
}
|
2013-04-04 14:52:42 +00:00
|
|
|
}
|
|
|
|
Com_Printf ("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_ConSay_f
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
static void SV_ConSay_f(void) {
|
|
|
|
char *p;
|
|
|
|
char text[1024];
|
|
|
|
|
|
|
|
if( !com_dedicated->integer ) {
|
|
|
|
Com_Printf( "Server is not dedicated.\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure server is running
|
|
|
|
if ( !com_sv_running->integer ) {
|
|
|
|
Com_Printf( "Server is not running.\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Cmd_Argc () < 2 ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-04 21:05:53 +00:00
|
|
|
strcpy (text, "Server: ");
|
2013-04-04 14:52:42 +00:00
|
|
|
p = Cmd_Args();
|
|
|
|
|
|
|
|
if ( *p == '"' ) {
|
|
|
|
p++;
|
|
|
|
p[strlen(p)-1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcat(text, p);
|
|
|
|
|
|
|
|
SV_SendServerCommand(NULL, "chat \"%s\n\"", text);
|
|
|
|
}
|
|
|
|
|
2013-04-04 21:05:53 +00:00
|
|
|
static const char *forceToggleNamePrints[] =
|
|
|
|
{
|
|
|
|
"HEAL",//FP_HEAL
|
|
|
|
"JUMP",//FP_LEVITATION
|
|
|
|
"SPEED",//FP_SPEED
|
|
|
|
"PUSH",//FP_PUSH
|
|
|
|
"PULL",//FP_PULL
|
|
|
|
"MINDTRICK",//FP_TELEPTAHY
|
|
|
|
"GRIP",//FP_GRIP
|
|
|
|
"LIGHTNING",//FP_LIGHTNING
|
|
|
|
"DARK RAGE",//FP_RAGE
|
|
|
|
"PROTECT",//FP_PROTECT
|
|
|
|
"ABSORB",//FP_ABSORB
|
|
|
|
"TEAM HEAL",//FP_TEAM_HEAL
|
|
|
|
"TEAM REPLENISH",//FP_TEAM_FORCE
|
|
|
|
"DRAIN",//FP_DRAIN
|
|
|
|
"SEEING",//FP_SEE
|
|
|
|
"SABER OFFENSE",//FP_SABERATTACK
|
|
|
|
"SABER DEFENSE",//FP_SABERDEFEND
|
|
|
|
"SABER THROW",//FP_SABERTHROW
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_ForceToggle_f
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
void SV_ForceToggle_f(void)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
int fpDisabled = Cvar_VariableValue("g_forcePowerDisable");
|
|
|
|
int targetPower = 0;
|
|
|
|
const char *powerDisabled = "Enabled";
|
|
|
|
|
|
|
|
if ( Cmd_Argc () < 2 )
|
|
|
|
{ //no argument supplied, spit out a list of force powers and their numbers
|
|
|
|
while (i < NUM_FORCE_POWERS)
|
|
|
|
{
|
|
|
|
if (fpDisabled & (1 << i))
|
|
|
|
{
|
|
|
|
powerDisabled = "Disabled";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
powerDisabled = "Enabled";
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf(va("%i - %s - Status: %s\n", i, forceToggleNamePrints[i], powerDisabled));
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf("Example usage: forcetoggle 3\n(toggles PUSH)\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
targetPower = atoi(Cmd_Argv(1));
|
|
|
|
|
|
|
|
if (targetPower < 0 || targetPower >= NUM_FORCE_POWERS)
|
|
|
|
{
|
|
|
|
Com_Printf("Specified a power that does not exist.\nExample usage: forcetoggle 3\n(toggles PUSH)\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fpDisabled & (1 << targetPower))
|
|
|
|
{
|
|
|
|
powerDisabled = "enabled";
|
|
|
|
fpDisabled &= ~(1 << targetPower);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
powerDisabled = "disabled";
|
|
|
|
fpDisabled |= (1 << targetPower);
|
|
|
|
}
|
|
|
|
|
|
|
|
Cvar_Set("g_forcePowerDisable", va("%i", fpDisabled));
|
|
|
|
|
|
|
|
Com_Printf("%s has been %s.\n", forceToggleNamePrints[targetPower], powerDisabled);
|
|
|
|
}
|
2013-04-04 14:52:42 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_Heartbeat_f
|
|
|
|
|
|
|
|
Also called by SV_DropClient, SV_DirectConnect, and SV_SpawnServer
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
void SV_Heartbeat_f( void ) {
|
|
|
|
svs.nextHeartbeatTime = -9999999;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
===========
|
|
|
|
SV_Serverinfo_f
|
|
|
|
|
|
|
|
Examine the serverinfo string
|
|
|
|
===========
|
|
|
|
*/
|
|
|
|
static void SV_Serverinfo_f( void ) {
|
|
|
|
Com_Printf ("Server info settings:\n");
|
|
|
|
Info_Print ( Cvar_InfoString( CVAR_SERVERINFO ) );
|
|
|
|
if ( !com_sv_running->integer ) {
|
|
|
|
Com_Printf( "Server is not running.\n" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
===========
|
|
|
|
SV_Systeminfo_f
|
|
|
|
|
|
|
|
Examine or change the serverinfo string
|
|
|
|
===========
|
|
|
|
*/
|
|
|
|
static void SV_Systeminfo_f( void ) {
|
|
|
|
Com_Printf ("System info settings:\n");
|
|
|
|
Info_Print ( Cvar_InfoString( CVAR_SYSTEMINFO ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
===========
|
|
|
|
SV_DumpUser_f
|
|
|
|
|
|
|
|
Examine all a users info strings FIXME: move to game
|
|
|
|
===========
|
|
|
|
*/
|
|
|
|
static void SV_DumpUser_f( void ) {
|
|
|
|
client_t *cl;
|
|
|
|
|
|
|
|
// make sure server is running
|
|
|
|
if ( !com_sv_running->integer ) {
|
|
|
|
Com_Printf( "Server is not running.\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Cmd_Argc() != 2 ) {
|
|
|
|
Com_Printf ("Usage: info <userid>\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cl = SV_GetPlayerByName();
|
|
|
|
if ( !cl ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf( "userinfo\n" );
|
|
|
|
Com_Printf( "--------\n" );
|
|
|
|
Info_Print( cl->userinfo );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
SV_KillServer
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
static void SV_KillServer_f( void ) {
|
|
|
|
SV_Shutdown( "killserver" );
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_AddOperatorCommands
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
void SV_AddOperatorCommands( void ) {
|
|
|
|
static qboolean initialized;
|
|
|
|
|
|
|
|
if ( initialized ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
initialized = qtrue;
|
|
|
|
|
|
|
|
Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
|
|
|
|
Cmd_AddCommand ("kick", SV_Kick_f);
|
|
|
|
#ifdef USE_CD_KEY
|
|
|
|
Cmd_AddCommand ("banUser", SV_Ban_f);
|
|
|
|
Cmd_AddCommand ("banClient", SV_BanNum_f);
|
|
|
|
#endif // USE_CD_KEY
|
|
|
|
|
|
|
|
Cmd_AddCommand ("clientkick", SV_KickNum_f);
|
|
|
|
Cmd_AddCommand ("status", SV_Status_f);
|
|
|
|
Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
|
|
|
|
Cmd_AddCommand ("systeminfo", SV_Systeminfo_f);
|
|
|
|
Cmd_AddCommand ("dumpuser", SV_DumpUser_f);
|
|
|
|
Cmd_AddCommand ("map_restart", SV_MapRestart_f);
|
|
|
|
Cmd_AddCommand ("sectorlist", SV_SectorList_f);
|
|
|
|
Cmd_AddCommand ("map", SV_Map_f);
|
|
|
|
#ifndef PRE_RELEASE_DEMO
|
|
|
|
Cmd_AddCommand ("devmap", SV_Map_f);
|
|
|
|
Cmd_AddCommand ("spmap", SV_Map_f);
|
|
|
|
Cmd_AddCommand ("spdevmap", SV_Map_f);
|
|
|
|
// Cmd_AddCommand ("devmapbsp", SV_Map_f); // not used in MP codebase, no server BSP_cacheing
|
|
|
|
Cmd_AddCommand ("devmapmdl", SV_Map_f);
|
|
|
|
Cmd_AddCommand ("devmapall", SV_Map_f);
|
|
|
|
#endif
|
|
|
|
Cmd_AddCommand ("killserver", SV_KillServer_f);
|
|
|
|
// if( com_dedicated->integer )
|
|
|
|
{
|
|
|
|
Cmd_AddCommand ("svsay", SV_ConSay_f);
|
|
|
|
}
|
2013-04-04 21:05:53 +00:00
|
|
|
|
|
|
|
Cmd_AddCommand ("forcetoggle", SV_ForceToggle_f);
|
2013-04-04 14:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_RemoveOperatorCommands
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
void SV_RemoveOperatorCommands( void ) {
|
|
|
|
#if 0
|
|
|
|
// removing these won't let the server start again
|
|
|
|
Cmd_RemoveCommand ("heartbeat");
|
|
|
|
Cmd_RemoveCommand ("kick");
|
|
|
|
Cmd_RemoveCommand ("banUser");
|
|
|
|
Cmd_RemoveCommand ("banClient");
|
|
|
|
Cmd_RemoveCommand ("status");
|
|
|
|
Cmd_RemoveCommand ("serverinfo");
|
|
|
|
Cmd_RemoveCommand ("systeminfo");
|
|
|
|
Cmd_RemoveCommand ("dumpuser");
|
|
|
|
Cmd_RemoveCommand ("map_restart");
|
|
|
|
Cmd_RemoveCommand ("sectorlist");
|
|
|
|
Cmd_RemoveCommand ("svsay");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|