diff options
Diffstat (limited to 'src/server/sv_ccmds.c')
-rw-r--r-- | src/server/sv_ccmds.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/src/server/sv_ccmds.c b/src/server/sv_ccmds.c new file mode 100644 index 0000000..8e76fa1 --- /dev/null +++ b/src/server/sv_ccmds.c @@ -0,0 +1,326 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. +Copyright (C) 2000-2009 Darklegion Development + +This file is part of Tremulous. + +Tremulous is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Tremulous is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Tremulous; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "server.h" + +/* +=============================================================================== + +OPERATOR CONSOLE ONLY COMMANDS + +These commands can only be entered from stdin or by a remote operator datagram +=============================================================================== +*/ + +/* +================== +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]; + int i; + + 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 + 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; + } + + cmd = Cmd_Argv(0); + if ( !Q_stricmp( cmd, "devmap" ) ) { + cheat = qtrue; + killBots = qtrue; + } else { + cheat = qfalse; + killBots = qfalse; + } + + // save the map name here cause on a map restart we reload the autogen.cfg + // and thus nuke the arguments of the map command + Q_strncpyz(mapname, map, sizeof(mapname)); + + // start up the map + SV_SpawnServer( mapname, killBots ); + + // 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" ); + } + + // This forces the local master server IP address cache + // to be updated on sending the next heartbeat + for( i = 0; i < MAX_MASTER_SERVERS; i++ ) + sv_master[ i ]->modified = qtrue; +} + +/* +================ +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; + 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 ) { + 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; + } + + // 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 ) ); + 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_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 ) ); +} + + +/* +=========== +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_Big( CVAR_SYSTEMINFO ) ); +} + + +/* +================= +SV_KillServer +================= +*/ +static void SV_KillServer_f( void ) { + SV_Shutdown( "killserver" ); +} + +//=========================================================== + +/* +================== +SV_CompleteMapName +================== +*/ +static void SV_CompleteMapName( char *args, int argNum ) { + if( argNum == 2 ) { + Field_CompleteFilename( "maps", "bsp", qtrue, qfalse ); + } +} + +/* +================== +SV_AddOperatorCommands +================== +*/ +void SV_AddOperatorCommands( void ) { + static qboolean initialized; + + if ( initialized ) { + return; + } + initialized = qtrue; + + Cmd_AddCommand ("heartbeat", SV_Heartbeat_f); + Cmd_AddCommand ("serverinfo", SV_Serverinfo_f); + Cmd_AddCommand ("systeminfo", SV_Systeminfo_f); + Cmd_AddCommand ("map_restart", SV_MapRestart_f); + Cmd_AddCommand ("sectorlist", SV_SectorList_f); + Cmd_AddCommand ("map", SV_Map_f); + Cmd_SetCommandCompletionFunc( "map", SV_CompleteMapName ); + Cmd_AddCommand ("devmap", SV_Map_f); + Cmd_SetCommandCompletionFunc( "devmap", SV_CompleteMapName ); + Cmd_AddCommand ("killserver", SV_KillServer_f); +} + +/* +================== +SV_RemoveOperatorCommands +================== +*/ +void SV_RemoveOperatorCommands( void ) { +#if 0 + // removing these won't let the server start again + Cmd_RemoveCommand ("heartbeat"); + Cmd_RemoveCommand ("serverinfo"); + Cmd_RemoveCommand ("systeminfo"); + Cmd_RemoveCommand ("map_restart"); + Cmd_RemoveCommand ("sectorlist"); +#endif +} + |