From 425decdf7e9284d15aa726e3ae96b9942fb0e3ea Mon Sep 17 00:00:00 2001 From: IronClawTrem Date: Sun, 16 Feb 2020 03:40:06 +0000 Subject: create tremded branch --- src/server/sv_ccmds.cpp | 441 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 src/server/sv_ccmds.cpp (limited to 'src/server/sv_ccmds.cpp') diff --git a/src/server/sv_ccmds.cpp b/src/server/sv_ccmds.cpp new file mode 100644 index 0000000..5c8902d --- /dev/null +++ b/src/server/sv_ccmds.cpp @@ -0,0 +1,441 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. +Copyright (C) 2000-2013 Darklegion Development +Copyright (C) 2012-2018 ET:Legacy team +Copyright (C) 2015-2019 GrangerHub + +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 3 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, see + +=========================================================================== +*/ + +#include +#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 ) { + const char *cmd; + const char *map; + bool cheat; + char expanded[MAX_QPATH]; + char mapname[MAX_QPATH]; + int a; + 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 = true; + } else { + cheat = false; + } + + // 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 ); + + // set the cheat value + // if the level was started with "map ", then + // cheats will not be allowed. If started with "devmap " + // 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( a = 0; a < 3; ++a ) + for( i = 0; i < MAX_MASTER_SERVERS; i++ ) + sv_masters[ a ][ i ]->modified = true; +} + +/* +================ +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 = 0; + } + 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 ); + 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 ; iinteger ; 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 = true; + + SV_RestartGameProgs(); + + // run a few frames to allow everything to settle + for (i = 0; i < 3; i++) + { + VM_Call (sv.gvm, GAME_RUN_FRAME, sv.time); + sv.time += 100; + svs.time += 100; + } + + sv.state = SS_GAME; + sv.restarting = false; + + // connect and begin all the clients + for (i=0 ; iinteger ; 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 = (char*)VM_ExplicitArgPtr( sv.gvm, VM_Call( sv.gvm, GAME_CLIENT_CONNECT, i, false ) ); + 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 (sv.gvm, GAME_RUN_FRAME, sv.time); + sv.time += 100; + svs.time += 100; +} + + +//=============================================================== + +/** + * @brief SV_Status_f + */ +static void SV_Status_f(void) { + int i; + client_t *cl; + playerState_t *ps; + const char *s; + int ping; + unsigned int maxNameLength; + + // make sure server is running + if (!com_sv_running->integer) { + Com_Printf("Server is not running.\n"); + return; + } + + Com_Printf("cpu server utilization: %i %%\n" + "avg response time : %i ms\n" + "server time : %i\n" + "internal time : %i\n" + "map : %s\n\n" + "num score ping name lastmsg address qport rate lastConnectTime\n" + "--- ----- ---- ----------------------------------- ------- --------------------- ----- ----- ---------------\n", + ( int ) svs.stats.cpu, + ( int ) svs.stats.avg, + svs.time, + Sys_Milliseconds(), + sv_mapname->string); + + for (i = 0, cl = svs.clients ; i < sv_maxclients->integer ; i++, cl++) { + Com_Printf("%3i ", i); + ps = SV_GameClientNum(i); + Com_Printf("%5i ", ps->persistant[PERS_SCORE]); + + if (cl->state == CS_CONNECTED) { + Com_Printf("CNCT "); + } else if (cl->state == CS_ZOMBIE) { + Com_Printf("ZMBI "); + } else { + ping = cl->ping < 9999 ? cl->ping : 9999; + Com_Printf("%4i ", ping); + } + + s = NET_AdrToString(cl->netchan.remoteAddress); + + // extend the name length by couting extra color characters to keep well formated output + maxNameLength = sizeof(cl->name) + (strlen(cl->name) - Q_PrintStrlen(cl->name)) + 1; + + Com_Printf("%-*s %7i %-21s %5i %5i %i\n", maxNameLength, rc(cl->name), svs.time - cl->lastPacketTime, s, cl->netchan.qport, cl->rate, svs.time - cl->lastConnectTime); + } + + Com_Printf("\n"); +} + + +/* +================== +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 ) { + // make sure server is running + if ( !com_sv_running->integer ) { + Com_Printf( "Server is not running.\n" ); + return; + } + + Com_Printf ("Server info settings:\n"); + Info_Print ( Cvar_InfoString( CVAR_SERVERINFO ) ); +} + + +/* +=========== +SV_Systeminfo_f + +Examine the systeminfo string +=========== +*/ +static void SV_Systeminfo_f( void ) { + // make sure server is running + if ( !com_sv_running->integer ) { + Com_Printf( "Server is not running.\n" ); + return; + } + + Com_Printf ("System info settings:\n"); + Info_Print ( Cvar_InfoString_Big( CVAR_SYSTEMINFO ) ); +} + + +/* +================= +SV_KillServer +================= +*/ +static void SV_KillServer_f( void ) { + SV_Shutdown( "killserver" ); +} + +static void SV_SMQ_f( void ) { + static qboolean schmResolved = qfalse; + static netadr_t schmAddress; + + if ( !schmResolved ) { + schmResolved = qtrue; + NET_StringToAdr( "127.0.0.1", &schmAddress, NA_IP ); + schmAddress.port = 1337; + } + + if ( sv_schachtmeisterPort->modified && + sv_schachtmeisterPort->integer >= 1 && sv_schachtmeisterPort->integer <= 65535 ) + { + schmAddress.port = htons(sv_schachtmeisterPort->integer); + } + + if ( Cmd_Argc() >= 3 && !Q_stricmp( Cmd_Argv( 1 ), "ipa" ) ) { // compatibility with out-of-date crapware conceived in the future + NET_OutOfBandPrint( NS_SERVER, schmAddress, "sm2query %s", Cmd_ArgsFrom( 2 ) ); + Com_Printf( "^3query [^7sm2query %s^3]\n", Cmd_ArgsFrom( 2 ) ); // DELME + } else { + char args[ MAX_STRING_CHARS ]; + char *p; + int s, i; + + p = args; + s = sizeof( args ); + + for ( i = 1; i < Cmd_Argc(); ++i ) + { + int l; + Com_sprintf( p, s, " \"%s\"", Cmd_Argv( i ) ); + l = strlen( p ); + s -= l; + p += l; + } + + NET_OutOfBandPrint( NS_SERVER, schmAddress, "sm2query%s", args ); + Com_Printf( "^3query [^7sm2query%s^3]\n", args ); // DELME + } +} + +//=========================================================== + +/* +================== +SV_CompleteMapName +================== +*/ +static void SV_CompleteMapName( char *args, int argNum ) { + if( argNum == 2 ) { + Field_CompleteFilename( "maps", "bsp", true, false ); + } +} + +/* +================== +SV_AddOperatorCommands +================== +*/ +void SV_AddOperatorCommands( void ) { + static bool initialized = false; + + if ( initialized ) { + return; + } + initialized = true; + + Cmd_AddCommand ("heartbeat", SV_Heartbeat_f); + Cmd_AddCommand ("status", SV_Status_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); + Cmd_AddCommand ("smq", SV_SMQ_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 +} -- cgit