/* =========================================================================== Copyright (C) 1999 - 2005, Id Software, Inc. Copyright (C) 2000 - 2013, Raven Software, Inc. Copyright (C) 2001 - 2013, Activision, Inc. Copyright (C) 2013 - 2015, OpenJK contributors This file is part of the OpenJK source code. OpenJK is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program 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 this program; if not, see . =========================================================================== */ #include "../server/exe_headers.h" #include "server.h" #include "../game/weapons.h" #include "../game/g_items.h" #include "../game/statindex.h" #include "../win32/AutoVersion.h" /* =============================================================================== OPERATOR CONSOLE ONLY COMMANDS These commands can only be entered from stdin or by a remote operator datagram =============================================================================== */ qboolean qbLoadTransition = qfalse; //========================================================= // don't call this directly, it should only be called from SV_Map_f() or SV_MapTransition_f() // static bool SV_Map_( ForceReload_e eForceReload ) { char *map = NULL; char expanded[MAX_QPATH] = {0}; map = Cmd_Argv(1); if ( !*map ) { Com_Printf ("no map specified\n"); return false; } // 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 false; } Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map); if ( FS_ReadFile (expanded, NULL) == -1 ) { Com_Printf ("Can't find map %s\n", expanded); extern cvar_t *com_buildScript; if (com_buildScript && com_buildScript->integer) {//yes, it's happened, someone deleted a map during my build... Com_Error( ERR_FATAL, "Can't find map %s\n", expanded ); } return false; } if (map[0]!='_') { SG_WipeSavegame("auto"); } SV_SpawnServer( map, eForceReload, qtrue ); // start up the map return true; } // Save out some player data for later restore if this is a spawn point with KEEP_PREV (spawnflags&1) set... // // (now also called by auto-save code to setup the cvars correctly void SV_Player_EndOfLevelSave(void) { int i; // I could just call GetClientState() but that's in sv_bot.cpp, and I'm not sure if that's going to be deleted for // the single player build, so here's the guts again... // client_t* cl = &svs.clients[0]; // 0 because only ever us as a player if (cl && cl->gentity && cl->gentity->client // crash fix for voy4->brig transition when you kill Foster. // Shouldn't happen, but does sometimes... ) { Cvar_Set( sCVARNAME_PLAYERSAVE, ""); // default to blank // clientSnapshot_t* pFrame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK]; playerState_t* pState = cl->gentity->client; const char *s2; const char *s; #ifdef JK2_MODE s = va("%i %i %i %i %i %i %i %f %f %f %i %i %i %i %i %i", pState->stats[STAT_HEALTH], pState->stats[STAT_ARMOR], pState->stats[STAT_WEAPONS], pState->stats[STAT_ITEMS], pState->weapon, pState->weaponstate, pState->batteryCharge, pState->viewangles[0], pState->viewangles[1], pState->viewangles[2], pState->forcePowersKnown, pState->forcePower, pState->saberActive, pState->saberAnimLevel, pState->saberLockEnemy, pState->saberLockTime ); #else // |general info |-force powers |-saber 1 |-saber 2 |-general saber s = va("%i %i %i %i %i %i %i %f %f %f %i %i %i %i %i %s %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %s %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i", pState->stats[STAT_HEALTH], pState->stats[STAT_ARMOR], pState->stats[STAT_WEAPONS], pState->stats[STAT_ITEMS], pState->weapon, pState->weaponstate, pState->batteryCharge, pState->viewangles[0], pState->viewangles[1], pState->viewangles[2], //force power data pState->forcePowersKnown, pState->forcePower, pState->forcePowerMax, pState->forcePowerRegenRate, pState->forcePowerRegenAmount, //saber 1 data pState->saber[0].name, pState->saber[0].blade[0].active, pState->saber[0].blade[1].active, pState->saber[0].blade[2].active, pState->saber[0].blade[3].active, pState->saber[0].blade[4].active, pState->saber[0].blade[5].active, pState->saber[0].blade[6].active, pState->saber[0].blade[7].active, pState->saber[0].blade[0].color, pState->saber[0].blade[1].color, pState->saber[0].blade[2].color, pState->saber[0].blade[3].color, pState->saber[0].blade[4].color, pState->saber[0].blade[5].color, pState->saber[0].blade[6].color, pState->saber[0].blade[7].color, //saber 2 data pState->saber[1].name, pState->saber[1].blade[0].active, pState->saber[1].blade[1].active, pState->saber[1].blade[2].active, pState->saber[1].blade[3].active, pState->saber[1].blade[4].active, pState->saber[1].blade[5].active, pState->saber[1].blade[6].active, pState->saber[1].blade[7].active, pState->saber[1].blade[0].color, pState->saber[1].blade[1].color, pState->saber[1].blade[2].color, pState->saber[1].blade[3].color, pState->saber[1].blade[4].color, pState->saber[1].blade[5].color, pState->saber[1].blade[6].color, pState->saber[1].blade[7].color, //general saber data pState->saberStylesKnown, pState->saberAnimLevel, pState->saberLockEnemy, pState->saberLockTime ); #endif Cvar_Set( sCVARNAME_PLAYERSAVE, s ); //ammo s2 = ""; for (i=0;i< AMMO_MAX; i++) { s2 = va("%s %i",s2, pState->ammo[i]); } Cvar_Set( "playerammo", s2 ); //inventory s2 = ""; for (i=0;i< INV_MAX; i++) { s2 = va("%s %i",s2, pState->inventory[i]); } Cvar_Set( "playerinv", s2 ); // the new JK2 stuff - force powers, etc... // s2 = ""; for (i=0;i< NUM_FORCE_POWERS; i++) { s2 = va("%s %i",s2, pState->forcePowerLevel[i]); } Cvar_Set( "playerfplvl", s2 ); } } // Restart the server on a different map // static void SV_MapTransition_f(void) { const char *spawntarget; #ifdef JK2_MODE SCR_PrecacheScreenshot(); #endif SV_Player_EndOfLevelSave(); spawntarget = Cmd_Argv(2); if ( *spawntarget != '\0' ) { Cvar_Set( "spawntarget", spawntarget ); } else { Cvar_Set( "spawntarget", "" ); } SV_Map_( eForceReload_NOTHING ); } /* ================== SV_Map_f Restart the server on a different map, but clears a cvar so that typing "map blah" doesn't try and preserve player weapons/ammo/etc from the previous level that you haven't really exited (ie ignores KEEP_PREV on spawn points) ================== */ #ifdef JK2_MODE extern void SCR_UnprecacheScreenshot(); #endif static void SV_Map_f( void ) { Cvar_Set( sCVARNAME_PLAYERSAVE, ""); Cvar_Set( "spawntarget", "" ); Cvar_Set("tier_storyinfo", "0"); Cvar_Set("tiers_complete", ""); #ifdef JK2_MODE SCR_UnprecacheScreenshot(); #endif ForceReload_e eForceReload = eForceReload_NOTHING; // default for normal load char *cmd = Cmd_Argv( 0 ); if ( !Q_stricmp( cmd, "devmapbsp") ) eForceReload = eForceReload_BSP; else if ( !Q_stricmp( cmd, "devmapmdl") ) eForceReload = eForceReload_MODELS; else if ( !Q_stricmp( cmd, "devmapall") ) eForceReload = eForceReload_ALL; qboolean cheat = (qboolean)(!Q_stricmpn( cmd, "devmap", 6 ) ); // retain old cheat state if ( !cheat && Cvar_VariableIntegerValue( "helpUsObi" ) ) cheat = qtrue; if (SV_Map_( eForceReload )) { // 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 Cvar_Set( "helpUsObi", cheat ? "1" : "0" ); } #ifdef JK2_MODE Cvar_Set( "cg_missionstatusscreen", "0" ); #endif } /* ================== SV_LoadTransition_f ================== */ void SV_LoadTransition_f(void) { const char *map; const char *spawntarget; map = Cmd_Argv(1); if ( !*map ) { return; } qbLoadTransition = qtrue; #ifdef JK2_MODE SCR_PrecacheScreenshot(); #endif SV_Player_EndOfLevelSave(); //Save the full current state of the current map so we can return to it later SG_WriteSavegame( va("hub/%s", sv_mapname->string), qfalse ); //set the spawntarget if there is one spawntarget = Cmd_Argv(2); if ( *spawntarget != '\0' ) { Cvar_Set( "spawntarget", spawntarget ); } else { Cvar_Set( "spawntarget", "" ); } if ( !SV_TryLoadTransition( map ) ) {//couldn't load a savegame SV_Map_( eForceReload_NOTHING ); } qbLoadTransition = qfalse; } //=============================================================== char *ivtos( const vec3_t v ) { static int index; static char str[8][32]; char *s; // use an array so that multiple vtos won't collide s = str[index]; index = (index + 1)&7; Com_sprintf (s, 32, "( %i %i %i )", (int)v[0], (int)v[1], (int)v[2]); return s; } /* ================ SV_Status_f ================ */ static void SV_Status_f( void ) { client_t *cl; // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } cl = &svs.clients[0]; if ( !cl ) { Com_Printf("Server is not running.\n"); return; } #if defined(_WIN32) #define STATUS_OS "Windows" #elif defined(__linux__) #define STATUS_OS "Linux" #elif defined(MACOS_X) #define STATUS_OS "OSX" #else #define STATUS_OS "Unknown" #endif Com_Printf( "name : %s^7\n", cl->name ); Com_Printf( "score : %i\n", cl->gentity->client->persistant[PERS_SCORE] ); Com_Printf( "version : %s %s %i\n", STATUS_OS, VERSION_STRING_DOTTED, PROTOCOL_VERSION ); #ifdef JK2_MODE Com_Printf( "game : Jedi Outcast %s\n", FS_GetCurrentGameDir() ); #else Com_Printf( "game : Jedi Academy %s\n", FS_GetCurrentGameDir() ); #endif Com_Printf( "map : %s at %s\n", sv_mapname->string, ivtos( cl->gentity->client->origin ) ); } /* =========== 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( 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() != 1 ) { Com_Printf ("Usage: info\n"); return; } cl = &svs.clients[0]; if ( !cl->state ) { Com_Printf("Client is not active\n"); return; } Com_Printf( "userinfo\n" ); Com_Printf( "--------\n" ); Info_Print( cl->userinfo ); } //=========================================================== /* ================== SV_CompleteMapName ================== */ static void SV_CompleteMapName( char *args, int argNum ) { if ( argNum == 2 ) Field_CompleteFilename( "maps", "bsp", qtrue, qfalse ); } /* ================== SV_CompleteMapName ================== */ static void SV_CompleteSaveName( char *args, int argNum ) { if ( argNum == 2 ) Field_CompleteFilename( "saves", "sav", qtrue, qtrue ); } /* ================== SV_AddOperatorCommands ================== */ void SV_AddOperatorCommands( void ) { static qboolean initialized; if ( initialized ) { return; } initialized = qtrue; 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 ("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 ("devmapbsp", SV_Map_f); Cmd_SetCommandCompletionFunc( "devmapbsp", SV_CompleteMapName ); Cmd_AddCommand ("devmapmdl", SV_Map_f); Cmd_SetCommandCompletionFunc( "devmapmdl", SV_CompleteMapName ); Cmd_AddCommand ("devmapsnd", SV_Map_f); Cmd_SetCommandCompletionFunc( "devmapsnd", SV_CompleteMapName ); Cmd_AddCommand ("devmapall", SV_Map_f); Cmd_SetCommandCompletionFunc( "devmapall", SV_CompleteMapName ); Cmd_AddCommand ("maptransition", SV_MapTransition_f); Cmd_AddCommand ("load", SV_LoadGame_f); Cmd_SetCommandCompletionFunc( "load", SV_CompleteSaveName ); Cmd_AddCommand ("loadtransition", SV_LoadTransition_f); Cmd_AddCommand ("save", SV_SaveGame_f); Cmd_AddCommand ("wipe", SV_WipeGame_f); //#ifdef _DEBUG // extern void UI_Dump_f(void); // Cmd_AddCommand ("ui_dump", UI_Dump_f); //#endif } /* ================== SV_RemoveOperatorCommands ================== */ void SV_RemoveOperatorCommands( void ) { #if 0 // removing these won't let the server start again Cmd_RemoveCommand ("status"); Cmd_RemoveCommand ("serverinfo"); Cmd_RemoveCommand ("systeminfo"); Cmd_RemoveCommand ("dumpuser"); Cmd_RemoveCommand ("serverrecord"); Cmd_RemoveCommand ("serverstop"); Cmd_RemoveCommand ("sectorlist"); #endif }