1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7
8 This file is part of the OpenJK source code.
9
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 ===========================================================================
22 */
23
24 #include "../server/exe_headers.h"
25
26 #include "server.h"
27 #include "../game/weapons.h"
28 #include "../game/g_items.h"
29 #include "../game/statindex.h"
30
31 #include "../win32/AutoVersion.h"
32
33
34 /*
35 ===============================================================================
36
37 OPERATOR CONSOLE ONLY COMMANDS
38
39 These commands can only be entered from stdin or by a remote operator datagram
40 ===============================================================================
41 */
42
43 qboolean qbLoadTransition = qfalse;
44
45 //=========================================================
46 // don't call this directly, it should only be called from SV_Map_f() or SV_MapTransition_f()
47 //
SV_Map_(ForceReload_e eForceReload)48 static bool SV_Map_( ForceReload_e eForceReload )
49 {
50 char *map = NULL;
51 char expanded[MAX_QPATH] = {0};
52
53 map = Cmd_Argv(1);
54 if ( !*map ) {
55 Com_Printf ("no map specified\n");
56 return false;
57 }
58
59 // make sure the level exists before trying to change, so that
60 // a typo at the server console won't end the game
61 if (strchr (map, '\\') ) {
62 Com_Printf ("Can't have mapnames with a \\\n");
63 return false;
64 }
65
66 Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map);
67
68 if ( FS_ReadFile (expanded, NULL) == -1 ) {
69 Com_Printf ("Can't find map %s\n", expanded);
70 extern cvar_t *com_buildScript;
71 if (com_buildScript && com_buildScript->integer)
72 {//yes, it's happened, someone deleted a map during my build...
73 Com_Error( ERR_FATAL, "Can't find map %s\n", expanded );
74 }
75 return false;
76 }
77
78 if (map[0]!='_')
79 {
80 SG_WipeSavegame("auto");
81 }
82
83 SV_SpawnServer( map, eForceReload, qtrue ); // start up the map
84 return true;
85 }
86
87
88
89 // Save out some player data for later restore if this is a spawn point with KEEP_PREV (spawnflags&1) set...
90 //
91 // (now also called by auto-save code to setup the cvars correctly
SV_Player_EndOfLevelSave(void)92 void SV_Player_EndOfLevelSave(void)
93 {
94 int i;
95
96 // 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
97 // the single player build, so here's the guts again...
98 //
99 client_t* cl = &svs.clients[0]; // 0 because only ever us as a player
100
101 if (cl
102 &&
103 cl->gentity && cl->gentity->client // crash fix for voy4->brig transition when you kill Foster.
104 // Shouldn't happen, but does sometimes...
105 )
106 {
107 Cvar_Set( sCVARNAME_PLAYERSAVE, ""); // default to blank
108
109 // clientSnapshot_t* pFrame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK];
110 playerState_t* pState = cl->gentity->client;
111 const char *s2;
112 const char *s;
113 #ifdef JK2_MODE
114 s = va("%i %i %i %i %i %i %i %f %f %f %i %i %i %i %i %i",
115 pState->stats[STAT_HEALTH],
116 pState->stats[STAT_ARMOR],
117 pState->stats[STAT_WEAPONS],
118 pState->stats[STAT_ITEMS],
119 pState->weapon,
120 pState->weaponstate,
121 pState->batteryCharge,
122 pState->viewangles[0],
123 pState->viewangles[1],
124 pState->viewangles[2],
125 pState->forcePowersKnown,
126 pState->forcePower,
127 pState->saberActive,
128 pState->saberAnimLevel,
129 pState->saberLockEnemy,
130 pState->saberLockTime
131 );
132 #else
133 // |general info |-force powers |-saber 1 |-saber 2 |-general saber
134 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",
135 pState->stats[STAT_HEALTH],
136 pState->stats[STAT_ARMOR],
137 pState->stats[STAT_WEAPONS],
138 pState->stats[STAT_ITEMS],
139 pState->weapon,
140 pState->weaponstate,
141 pState->batteryCharge,
142 pState->viewangles[0],
143 pState->viewangles[1],
144 pState->viewangles[2],
145 //force power data
146 pState->forcePowersKnown,
147 pState->forcePower,
148 pState->forcePowerMax,
149 pState->forcePowerRegenRate,
150 pState->forcePowerRegenAmount,
151 //saber 1 data
152 pState->saber[0].name,
153 pState->saber[0].blade[0].active,
154 pState->saber[0].blade[1].active,
155 pState->saber[0].blade[2].active,
156 pState->saber[0].blade[3].active,
157 pState->saber[0].blade[4].active,
158 pState->saber[0].blade[5].active,
159 pState->saber[0].blade[6].active,
160 pState->saber[0].blade[7].active,
161 pState->saber[0].blade[0].color,
162 pState->saber[0].blade[1].color,
163 pState->saber[0].blade[2].color,
164 pState->saber[0].blade[3].color,
165 pState->saber[0].blade[4].color,
166 pState->saber[0].blade[5].color,
167 pState->saber[0].blade[6].color,
168 pState->saber[0].blade[7].color,
169 //saber 2 data
170 pState->saber[1].name,
171 pState->saber[1].blade[0].active,
172 pState->saber[1].blade[1].active,
173 pState->saber[1].blade[2].active,
174 pState->saber[1].blade[3].active,
175 pState->saber[1].blade[4].active,
176 pState->saber[1].blade[5].active,
177 pState->saber[1].blade[6].active,
178 pState->saber[1].blade[7].active,
179 pState->saber[1].blade[0].color,
180 pState->saber[1].blade[1].color,
181 pState->saber[1].blade[2].color,
182 pState->saber[1].blade[3].color,
183 pState->saber[1].blade[4].color,
184 pState->saber[1].blade[5].color,
185 pState->saber[1].blade[6].color,
186 pState->saber[1].blade[7].color,
187 //general saber data
188 pState->saberStylesKnown,
189 pState->saberAnimLevel,
190 pState->saberLockEnemy,
191 pState->saberLockTime
192 );
193 #endif
194 Cvar_Set( sCVARNAME_PLAYERSAVE, s );
195
196 //ammo
197 s2 = "";
198 for (i=0;i< AMMO_MAX; i++)
199 {
200 s2 = va("%s %i",s2, pState->ammo[i]);
201 }
202 Cvar_Set( "playerammo", s2 );
203
204 //inventory
205 s2 = "";
206 for (i=0;i< INV_MAX; i++)
207 {
208 s2 = va("%s %i",s2, pState->inventory[i]);
209 }
210 Cvar_Set( "playerinv", s2 );
211
212 // the new JK2 stuff - force powers, etc...
213 //
214 s2 = "";
215 for (i=0;i< NUM_FORCE_POWERS; i++)
216 {
217 s2 = va("%s %i",s2, pState->forcePowerLevel[i]);
218 }
219 Cvar_Set( "playerfplvl", s2 );
220 }
221 }
222
223
224 // Restart the server on a different map
225 //
SV_MapTransition_f(void)226 static void SV_MapTransition_f(void)
227 {
228 const char *spawntarget;
229
230 #ifdef JK2_MODE
231 SCR_PrecacheScreenshot();
232 #endif
233 SV_Player_EndOfLevelSave();
234
235 spawntarget = Cmd_Argv(2);
236 if ( *spawntarget != '\0' )
237 {
238 Cvar_Set( "spawntarget", spawntarget );
239 }
240 else
241 {
242 Cvar_Set( "spawntarget", "" );
243 }
244
245 SV_Map_( eForceReload_NOTHING );
246 }
247
248 /*
249 ==================
250 SV_Map_f
251
252 Restart the server on a different map, but clears a cvar so that typing "map blah" doesn't try and preserve
253 player weapons/ammo/etc from the previous level that you haven't really exited (ie ignores KEEP_PREV on spawn points)
254 ==================
255 */
256 #ifdef JK2_MODE
257 extern void SCR_UnprecacheScreenshot();
258 #endif
SV_Map_f(void)259 static void SV_Map_f( void )
260 {
261 Cvar_Set( sCVARNAME_PLAYERSAVE, "");
262 Cvar_Set( "spawntarget", "" );
263 Cvar_Set("tier_storyinfo", "0");
264 Cvar_Set("tiers_complete", "");
265 #ifdef JK2_MODE
266 SCR_UnprecacheScreenshot();
267 #endif
268
269 ForceReload_e eForceReload = eForceReload_NOTHING; // default for normal load
270
271 char *cmd = Cmd_Argv( 0 );
272 if ( !Q_stricmp( cmd, "devmapbsp") )
273 eForceReload = eForceReload_BSP;
274 else if ( !Q_stricmp( cmd, "devmapmdl") )
275 eForceReload = eForceReload_MODELS;
276 else if ( !Q_stricmp( cmd, "devmapall") )
277 eForceReload = eForceReload_ALL;
278
279 qboolean cheat = (qboolean)(!Q_stricmpn( cmd, "devmap", 6 ) );
280
281 // retain old cheat state
282 if ( !cheat && Cvar_VariableIntegerValue( "helpUsObi" ) )
283 cheat = qtrue;
284
285 if (SV_Map_( eForceReload ))
286 {
287 // set the cheat value
288 // if the level was started with "map <levelname>", then
289 // cheats will not be allowed. If started with "devmap <levelname>"
290 // then cheats will be allowed
291 Cvar_Set( "helpUsObi", cheat ? "1" : "0" );
292 }
293 #ifdef JK2_MODE
294 Cvar_Set( "cg_missionstatusscreen", "0" );
295 #endif
296 }
297
298 /*
299 ==================
300 SV_LoadTransition_f
301 ==================
302 */
SV_LoadTransition_f(void)303 void SV_LoadTransition_f(void)
304 {
305 const char *map;
306 const char *spawntarget;
307
308 map = Cmd_Argv(1);
309 if ( !*map ) {
310 return;
311 }
312
313 qbLoadTransition = qtrue;
314
315 #ifdef JK2_MODE
316 SCR_PrecacheScreenshot();
317 #endif
318 SV_Player_EndOfLevelSave();
319
320 //Save the full current state of the current map so we can return to it later
321 SG_WriteSavegame( va("hub/%s", sv_mapname->string), qfalse );
322
323 //set the spawntarget if there is one
324 spawntarget = Cmd_Argv(2);
325 if ( *spawntarget != '\0' )
326 {
327 Cvar_Set( "spawntarget", spawntarget );
328 }
329 else
330 {
331 Cvar_Set( "spawntarget", "" );
332 }
333
334 if ( !SV_TryLoadTransition( map ) )
335 {//couldn't load a savegame
336 SV_Map_( eForceReload_NOTHING );
337 }
338 qbLoadTransition = qfalse;
339 }
340 //===============================================================
341
ivtos(const vec3_t v)342 char *ivtos( const vec3_t v ) {
343 static int index;
344 static char str[8][32];
345 char *s;
346
347 // use an array so that multiple vtos won't collide
348 s = str[index];
349 index = (index + 1)&7;
350
351 Com_sprintf (s, 32, "( %i %i %i )", (int)v[0], (int)v[1], (int)v[2]);
352
353 return s;
354 }
355
356 /*
357 ================
358 SV_Status_f
359 ================
360 */
SV_Status_f(void)361 static void SV_Status_f( void ) {
362 client_t *cl;
363
364 // make sure server is running
365 if ( !com_sv_running->integer ) {
366 Com_Printf( "Server is not running.\n" );
367 return;
368 }
369
370 cl = &svs.clients[0];
371
372 if ( !cl ) {
373 Com_Printf("Server is not running.\n");
374 return;
375 }
376
377 #if defined(_WIN32)
378 #define STATUS_OS "Windows"
379 #elif defined(__linux__)
380 #define STATUS_OS "Linux"
381 #elif defined(MACOS_X)
382 #define STATUS_OS "OSX"
383 #else
384 #define STATUS_OS "Unknown"
385 #endif
386
387 Com_Printf( "name : %s^7\n", cl->name );
388 Com_Printf( "score : %i\n", cl->gentity->client->persistant[PERS_SCORE] );
389 Com_Printf( "version : %s %s %i\n", STATUS_OS, VERSION_STRING_DOTTED, PROTOCOL_VERSION );
390 #ifdef JK2_MODE
391 Com_Printf( "game : Jedi Outcast %s\n", FS_GetCurrentGameDir() );
392 #else
393 Com_Printf( "game : Jedi Academy %s\n", FS_GetCurrentGameDir() );
394 #endif
395 Com_Printf( "map : %s at %s\n", sv_mapname->string, ivtos( cl->gentity->client->origin ) );
396 }
397
398 /*
399 ===========
400 SV_Serverinfo_f
401
402 Examine the serverinfo string
403 ===========
404 */
SV_Serverinfo_f(void)405 static void SV_Serverinfo_f( void ) {
406 Com_Printf ("Server info settings:\n");
407 Info_Print ( Cvar_InfoString( CVAR_SERVERINFO ) );
408 }
409
410
411 /*
412 ===========
413 SV_Systeminfo_f
414
415 Examine or change the serverinfo string
416 ===========
417 */
SV_Systeminfo_f(void)418 static void SV_Systeminfo_f( void ) {
419 Com_Printf ("System info settings:\n");
420 Info_Print ( Cvar_InfoString( CVAR_SYSTEMINFO ) );
421 }
422
423
424 /*
425 ===========
426 SV_DumpUser_f
427
428 Examine all a users info strings FIXME: move to game
429 ===========
430 */
SV_DumpUser_f(void)431 static void SV_DumpUser_f( void ) {
432 client_t *cl;
433
434 // make sure server is running
435 if ( !com_sv_running->integer ) {
436 Com_Printf( "Server is not running.\n" );
437 return;
438 }
439
440 if ( Cmd_Argc() != 1 ) {
441 Com_Printf ("Usage: info\n");
442 return;
443 }
444
445 cl = &svs.clients[0];
446 if ( !cl->state ) {
447 Com_Printf("Client is not active\n");
448 return;
449 }
450
451 Com_Printf( "userinfo\n" );
452 Com_Printf( "--------\n" );
453 Info_Print( cl->userinfo );
454 }
455
456 //===========================================================
457
458 /*
459 ==================
460 SV_CompleteMapName
461 ==================
462 */
SV_CompleteMapName(char * args,int argNum)463 static void SV_CompleteMapName( char *args, int argNum ) {
464 if ( argNum == 2 )
465 Field_CompleteFilename( "maps", "bsp", qtrue, qfalse );
466 }
467
468 /*
469 ==================
470 SV_CompleteMapName
471 ==================
472 */
SV_CompleteSaveName(char * args,int argNum)473 static void SV_CompleteSaveName( char *args, int argNum ) {
474 if ( argNum == 2 )
475 Field_CompleteFilename( "saves", "sav", qtrue, qtrue );
476 }
477
478 /*
479 ==================
480 SV_AddOperatorCommands
481 ==================
482 */
SV_AddOperatorCommands(void)483 void SV_AddOperatorCommands( void ) {
484 static qboolean initialized;
485
486 if ( initialized ) {
487 return;
488 }
489 initialized = qtrue;
490
491 Cmd_AddCommand ("status", SV_Status_f);
492 Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
493 Cmd_AddCommand ("systeminfo", SV_Systeminfo_f);
494 Cmd_AddCommand ("dumpuser", SV_DumpUser_f);
495 Cmd_AddCommand ("sectorlist", SV_SectorList_f);
496 Cmd_AddCommand ("map", SV_Map_f);
497 Cmd_SetCommandCompletionFunc( "map", SV_CompleteMapName );
498 Cmd_AddCommand ("devmap", SV_Map_f);
499 Cmd_SetCommandCompletionFunc( "devmap", SV_CompleteMapName );
500 Cmd_AddCommand ("devmapbsp", SV_Map_f);
501 Cmd_SetCommandCompletionFunc( "devmapbsp", SV_CompleteMapName );
502 Cmd_AddCommand ("devmapmdl", SV_Map_f);
503 Cmd_SetCommandCompletionFunc( "devmapmdl", SV_CompleteMapName );
504 Cmd_AddCommand ("devmapsnd", SV_Map_f);
505 Cmd_SetCommandCompletionFunc( "devmapsnd", SV_CompleteMapName );
506 Cmd_AddCommand ("devmapall", SV_Map_f);
507 Cmd_SetCommandCompletionFunc( "devmapall", SV_CompleteMapName );
508 Cmd_AddCommand ("maptransition", SV_MapTransition_f);
509 Cmd_AddCommand ("load", SV_LoadGame_f);
510 Cmd_SetCommandCompletionFunc( "load", SV_CompleteSaveName );
511 Cmd_AddCommand ("loadtransition", SV_LoadTransition_f);
512 Cmd_AddCommand ("save", SV_SaveGame_f);
513 Cmd_AddCommand ("wipe", SV_WipeGame_f);
514
515 //#ifdef _DEBUG
516 // extern void UI_Dump_f(void);
517 // Cmd_AddCommand ("ui_dump", UI_Dump_f);
518 //#endif
519 }
520
521 /*
522 ==================
523 SV_RemoveOperatorCommands
524 ==================
525 */
SV_RemoveOperatorCommands(void)526 void SV_RemoveOperatorCommands( void ) {
527 #if 0
528 // removing these won't let the server start again
529 Cmd_RemoveCommand ("status");
530 Cmd_RemoveCommand ("serverinfo");
531 Cmd_RemoveCommand ("systeminfo");
532 Cmd_RemoveCommand ("dumpuser");
533 Cmd_RemoveCommand ("serverrecord");
534 Cmd_RemoveCommand ("serverstop");
535 Cmd_RemoveCommand ("sectorlist");
536 #endif
537 }
538
539