sv_main.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. // leave this as first line for PCH reasons...
  2. //
  3. #include "../server/exe_headers.h"
  4. #include "server.h"
  5. /*
  6. Ghoul2 Insert Start
  7. */
  8. #if !defined (MINIHEAP_H_INC)
  9. #include "../qcommon/miniheap.h"
  10. #endif
  11. /*
  12. Ghoul2 Insert End
  13. */
  14. serverStatic_t svs; // persistant server info
  15. server_t sv; // local server
  16. game_export_t *ge;
  17. cvar_t *sv_fps; // time rate for running non-clients
  18. cvar_t *sv_timeout; // seconds without any message
  19. cvar_t *sv_zombietime; // seconds to sink messages after disconnect
  20. cvar_t *sv_reconnectlimit; // minimum seconds between connect messages
  21. cvar_t *sv_showloss; // report when usercmds are lost
  22. cvar_t *sv_killserver; // menu system can set to 1 to shut server down
  23. cvar_t *sv_mapname;
  24. cvar_t *sv_spawntarget;
  25. cvar_t *sv_mapChecksum;
  26. cvar_t *sv_serverid;
  27. cvar_t *sv_testsave; // Run the savegame enumeration every game frame
  28. cvar_t *sv_compress_saved_games; // compress the saved games on the way out (only affect saver, loader can read both)
  29. /*
  30. =============================================================================
  31. EVENT MESSAGES
  32. =============================================================================
  33. */
  34. /*
  35. ===============
  36. SV_ExpandNewlines
  37. Converts newlines to "\n" so a line prints nicer
  38. ===============
  39. */
  40. char *SV_ExpandNewlines( char *in ) {
  41. static char string[1024];
  42. int l;
  43. l = 0;
  44. while ( *in && l < sizeof(string) - 3 ) {
  45. if ( *in == '\n' ) {
  46. string[l++] = '\\';
  47. string[l++] = 'n';
  48. } else {
  49. string[l++] = *in;
  50. }
  51. in++;
  52. }
  53. string[l] = 0;
  54. return string;
  55. }
  56. /*
  57. ======================
  58. SV_AddServerCommand
  59. The given command will be transmitted to the client, and is guaranteed to
  60. not have future snapshot_t executed before it is executed
  61. ======================
  62. */
  63. void SV_AddServerCommand( client_t *client, const char *cmd ) {
  64. int index;
  65. // if we would be losing an old command that hasn't been acknowledged,
  66. // we must drop the connection
  67. if ( client->reliableSequence - client->reliableAcknowledge > MAX_RELIABLE_COMMANDS ) {
  68. SV_DropClient( client, "Server command overflow" );
  69. return;
  70. }
  71. client->reliableSequence++;
  72. index = client->reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );
  73. if ( client->reliableCommands[ index ] ) {
  74. Z_Free( client->reliableCommands[ index ] );
  75. }
  76. client->reliableCommands[ index ] = CopyString( cmd );
  77. }
  78. /*
  79. =================
  80. SV_SendServerCommand
  81. Sends a reliable command string to be interpreted by
  82. the client game module: "cp", "print", "chat", etc
  83. A NULL client will broadcast to all clients
  84. =================
  85. */
  86. void SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
  87. va_list argptr;
  88. byte message[MAX_MSGLEN];
  89. int len;
  90. client_t *client;
  91. int j;
  92. message[0] = svc_serverCommand;
  93. va_start (argptr,fmt);
  94. vsprintf ((char *)message+1, fmt,argptr);
  95. va_end (argptr);
  96. len = strlen( (char *)message ) + 1;
  97. if ( cl != NULL ) {
  98. SV_AddServerCommand( cl, (char *)message );
  99. return;
  100. }
  101. // send the data to all relevent clients
  102. for (j = 0, client = svs.clients; j < 1 ; j++, client++) {
  103. if ( client->state < CS_PRIMED ) {
  104. continue;
  105. }
  106. SV_AddServerCommand( client, (char *)message );
  107. }
  108. }
  109. /*
  110. ==============================================================================
  111. CONNECTIONLESS COMMANDS
  112. ==============================================================================
  113. */
  114. /*
  115. ================
  116. SVC_Status
  117. Responds with all the info that qplug or qspy can see about the server
  118. and all connected players. Used for getting detailed information after
  119. the simple info query.
  120. ================
  121. */
  122. void SVC_Status( netadr_t from ) {
  123. char player[1024];
  124. char status[MAX_MSGLEN];
  125. int i;
  126. client_t *cl;
  127. int statusLength;
  128. int playerLength;
  129. int score;
  130. char infostring[MAX_INFO_STRING];
  131. strcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO ) );
  132. // echo back the parameter to status. so servers can use it as a challenge
  133. // to prevent timed spoofed reply packets that add ghost servers
  134. Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );
  135. status[0] = 0;
  136. statusLength = 0;
  137. for (i=0 ; i < 1 ; i++) {
  138. cl = &svs.clients[i];
  139. if ( cl->state >= CS_CONNECTED ) {
  140. if ( cl->gentity && cl->gentity->client ) {
  141. score = cl->gentity->client->persistant[PERS_SCORE];
  142. } else {
  143. score = 0;
  144. }
  145. Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n",
  146. score, cl->ping, cl->name);
  147. playerLength = strlen(player);
  148. if (statusLength + playerLength >= sizeof(status) ) {
  149. break; // can't hold any more
  150. }
  151. strcpy (status + statusLength, player);
  152. statusLength += playerLength;
  153. }
  154. }
  155. NET_OutOfBandPrint( NS_SERVER, from, "statusResponse\n%s\n%s", infostring, status );
  156. }
  157. /*
  158. ================
  159. SVC_Info
  160. Responds with a short info message that should be enough to determine
  161. if a user is interested in a server to do a full status
  162. ================
  163. */
  164. static void SVC_Info( netadr_t from ) {
  165. int i, count;
  166. char infostring[MAX_INFO_STRING];
  167. count = 0;
  168. for ( i = 0 ; i < 1 ; i++ ) {
  169. if ( svs.clients[i].state >= CS_CONNECTED ) {
  170. count++;
  171. }
  172. }
  173. infostring[0] = 0;
  174. // echo back the parameter to status. so servers can use it as a challenge
  175. // to prevent timed spoofed reply packets that add ghost servers
  176. Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );
  177. Info_SetValueForKey( infostring, "protocol", va("%i", PROTOCOL_VERSION) );
  178. //Info_SetValueForKey( infostring, "hostname", sv_hostname->string );
  179. Info_SetValueForKey( infostring, "mapname", sv_mapname->string );
  180. Info_SetValueForKey( infostring, "clients", va("%i", count) );
  181. Info_SetValueForKey( infostring, "sv_maxclients", va("%i", 1) );
  182. NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring );
  183. }
  184. /*
  185. =================
  186. SV_ConnectionlessPacket
  187. A connectionless packet has four leading 0xff
  188. characters to distinguish it from a game channel.
  189. Clients that are in the game can still send
  190. connectionless packets.
  191. =================
  192. */
  193. static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
  194. char *s;
  195. char *c;
  196. MSG_BeginReading( msg );
  197. MSG_ReadLong( msg ); // skip the -1 marker
  198. s = MSG_ReadStringLine( msg );
  199. Cmd_TokenizeString( s );
  200. c = Cmd_Argv(0);
  201. Com_DPrintf ("SV packet %s : %s\n", NET_AdrToString(from), c);
  202. if (!strcmp(c,"getstatus")) {
  203. SVC_Status( from );
  204. } else if (!strcmp(c,"getinfo")) {
  205. SVC_Info( from );
  206. } else if (!strcmp(c,"connect")) {
  207. SV_DirectConnect( from );
  208. } else if (!strcmp(c,"disconnect")) {
  209. // if a client starts up a local server, we may see some spurious
  210. // server disconnect messages when their new server sees our final
  211. // sequenced messages to the old client
  212. } else {
  213. Com_DPrintf ("bad connectionless packet from %s:\n%s\n"
  214. , NET_AdrToString (from), s);
  215. }
  216. }
  217. //============================================================================
  218. /*
  219. =================
  220. SV_ReadPackets
  221. =================
  222. */
  223. void SV_PacketEvent( netadr_t from, msg_t *msg ) {
  224. int i;
  225. client_t *cl;
  226. int qport;
  227. // check for connectionless packet (0xffffffff) first
  228. if ( msg->cursize >= 4 && *(int *)msg->data == -1) {
  229. SV_ConnectionlessPacket( from, msg );
  230. return;
  231. }
  232. // read the qport out of the message so we can fix up
  233. // stupid address translating routers
  234. MSG_BeginReading( msg );
  235. MSG_ReadLong( msg ); // sequence number
  236. MSG_ReadLong( msg ); // sequence number
  237. qport = MSG_ReadShort( msg ) & 0xffff;
  238. // find which client the message is from
  239. for (i=0, cl=svs.clients ; i < 1 ; i++,cl++) {
  240. if (cl->state == CS_FREE) {
  241. continue;
  242. }
  243. if ( !NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) ) {
  244. continue;
  245. }
  246. // it is possible to have multiple clients from a single IP
  247. // address, so they are differentiated by the qport variable
  248. if (cl->netchan.qport != qport) {
  249. continue;
  250. }
  251. // the IP port can't be used to differentiate them, because
  252. // some address translating routers periodically change UDP
  253. // port assignments
  254. if (cl->netchan.remoteAddress.port != from.port) {
  255. Com_Printf( "SV_ReadPackets: fixing up a translated port\n" );
  256. cl->netchan.remoteAddress.port = from.port;
  257. }
  258. // make sure it is a valid, in sequence packet
  259. if (Netchan_Process(&cl->netchan, msg)) {
  260. // zombie clients stil neet to do the Netchan_Process
  261. // to make sure they don't need to retransmit the final
  262. // reliable message, but they don't do any other processing
  263. if (cl->state != CS_ZOMBIE) {
  264. cl->lastPacketTime = sv.time; // don't timeout
  265. cl->frames[ cl->netchan.incomingAcknowledged & PACKET_MASK ]
  266. .messageAcked = sv.time;
  267. SV_ExecuteClientMessage( cl, msg );
  268. }
  269. }
  270. return;
  271. }
  272. // if we received a sequenced packet from an address we don't reckognize,
  273. // send an out of band disconnect packet to it
  274. NET_OutOfBandPrint( NS_SERVER, from, "disconnect" );
  275. }
  276. /*
  277. ===================
  278. SV_CalcPings
  279. Updates the cl->ping variables
  280. ===================
  281. */
  282. void SV_CalcPings (void) {
  283. int i, j;
  284. client_t *cl;
  285. int total, count;
  286. int delta;
  287. for (i=0 ; i < 1 ; i++) {
  288. cl = &svs.clients[i];
  289. if ( cl->state != CS_ACTIVE ) {
  290. continue;
  291. }
  292. if ( cl->gentity->svFlags & SVF_BOT ) {
  293. continue;
  294. }
  295. total = 0;
  296. count = 0;
  297. for ( j = 0 ; j < PACKET_BACKUP ; j++ ) {
  298. delta = cl->frames[j].messageAcked - cl->frames[j].messageSent;
  299. if ( delta >= 0 ) {
  300. count++;
  301. total += delta;
  302. }
  303. }
  304. if (!count) {
  305. cl->ping = 999;
  306. } else {
  307. cl->ping = total/count;
  308. if ( cl->ping > 999 ) {
  309. cl->ping = 999;
  310. }
  311. }
  312. // let the game dll know about the ping
  313. cl->gentity->client->ping = cl->ping;
  314. }
  315. }
  316. /*
  317. ==================
  318. SV_CheckTimeouts
  319. If a packet has not been received from a client for timeout->integer
  320. seconds, drop the conneciton. Server time is used instead of
  321. realtime to avoid dropping the local client while debugging.
  322. When a client is normally dropped, the client_t goes into a zombie state
  323. for a few seconds to make sure any final reliable message gets resent
  324. if necessary
  325. ==================
  326. */
  327. void SV_CheckTimeouts( void ) {
  328. int i;
  329. client_t *cl;
  330. int droppoint;
  331. int zombiepoint;
  332. droppoint = sv.time - 1000 * sv_timeout->integer;
  333. zombiepoint = sv.time - 1000 * sv_zombietime->integer;
  334. for (i=0,cl=svs.clients ; i < 1 ; i++,cl++) {
  335. // message times may be wrong across a changelevel
  336. if (cl->lastPacketTime > sv.time) {
  337. cl->lastPacketTime = sv.time;
  338. }
  339. if (cl->state == CS_ZOMBIE
  340. && cl->lastPacketTime < zombiepoint) {
  341. cl->state = CS_FREE; // can now be reused
  342. continue;
  343. }
  344. if ( cl->state >= CS_CONNECTED && cl->lastPacketTime < droppoint) {
  345. // wait several frames so a debugger session doesn't
  346. // cause a timeout
  347. if ( ++cl->timeoutCount > 5 ) {
  348. SV_DropClient (cl, "timed out");
  349. cl->state = CS_FREE; // don't bother with zombie state
  350. }
  351. } else {
  352. cl->timeoutCount = 0;
  353. }
  354. }
  355. }
  356. /*
  357. ==================
  358. SV_CheckPaused
  359. ==================
  360. */
  361. qboolean SV_CheckPaused( void ) {
  362. if ( !cl_paused->integer ) {
  363. return qfalse;
  364. }
  365. sv_paused->integer = 1;
  366. return qtrue;
  367. }
  368. /*
  369. This wonderful hack is needed to avoid rendering frames until several camera related things
  370. have wended their way through the network. The problem is basically that the server asks the
  371. client where the camera is to decide what entities down to the client. However right after
  372. certain transitions the client tends to give a wrong answer. CGCam_Disable is one such time/
  373. When this happens we want to dump all rendered frame until these things have happened, in
  374. order:
  375. 0) (This state will mean that we are awaiting state 1)
  376. 1) The server has run a frame and built a packet
  377. 2) The client has computed a camera position
  378. 3) The server has run a frame and built a packet
  379. 4) The client has recieved a packet (This state also means the game is running normally).
  380. We will keep track of this here:
  381. */
  382. /*
  383. ==================
  384. SV_Frame
  385. Player movement occurs as a result of packet events, which
  386. happen before SV_Frame is called
  387. ==================
  388. */
  389. extern cvar_t *cl_newClock;
  390. void SV_Frame( int msec,float fractionMsec ) {
  391. int frameMsec;
  392. int startTime=0;
  393. // the menu kills the server with this cvar
  394. if ( sv_killserver->integer ) {
  395. SV_Shutdown ("Server was killed.\n");
  396. Cvar_Set( "sv_killserver", "0" );
  397. return;
  398. }
  399. if ( !com_sv_running->integer ) {
  400. return;
  401. }
  402. extern void SE_CheckForLanguageUpdates(void);
  403. SE_CheckForLanguageUpdates(); // will fast-return else load different language if menu changed it
  404. // allow pause if only the local client is connected
  405. if ( SV_CheckPaused() ) {
  406. return;
  407. }
  408. // go ahead and let time slip if the server really hitched badly
  409. if ( msec > 1000 ) {
  410. Com_DPrintf( "SV_Frame: Truncating msec of %i to 1000\n", msec );
  411. msec = 1000;
  412. }
  413. // if it isn't time for the next frame, do nothing
  414. if ( sv_fps->integer < 1 ) {
  415. Cvar_Set( "sv_fps", "10" );
  416. }
  417. frameMsec = 1000 / sv_fps->integer ;
  418. sv.timeResidual += msec;
  419. sv.timeResidualFraction+=fractionMsec;
  420. if (sv.timeResidualFraction>=1.0f)
  421. {
  422. sv.timeResidualFraction-=1.0f;
  423. if (cl_newClock&&cl_newClock->integer)
  424. {
  425. sv.timeResidual++;
  426. }
  427. }
  428. if ( sv.timeResidual < frameMsec ) {
  429. return;
  430. }
  431. // if time is about to hit the 32nd bit, restart the
  432. // level, which will force the time back to zero, rather
  433. // than checking for negative time wraparound everywhere.
  434. // 2giga-milliseconds = 23 days, so it won't be too often
  435. if ( sv.time > 0x70000000 ) {
  436. SV_Shutdown( "Restarting server due to time wrapping" );
  437. Com_Printf("You win. if you can play this long and not die, you deserve to win.\n");
  438. return;
  439. }
  440. // update infostrings if anything has been changed
  441. if ( cvar_modifiedFlags & CVAR_SERVERINFO ) {
  442. SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );
  443. cvar_modifiedFlags &= ~CVAR_SERVERINFO;
  444. }
  445. if ( cvar_modifiedFlags & CVAR_SYSTEMINFO ) {
  446. SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ) );
  447. cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;
  448. }
  449. if ( com_speeds->integer ) {
  450. startTime = Sys_Milliseconds ();
  451. }
  452. // SV_BotFrame( sv.time );
  453. // run the game simulation in chunks
  454. while ( sv.timeResidual >= frameMsec ) {
  455. sv.timeResidual -= frameMsec;
  456. sv.time += frameMsec;
  457. G2API_SetTime(sv.time,G2T_SV_TIME);
  458. // let everything in the world think and move
  459. ge->RunFrame( sv.time );
  460. }
  461. if ( com_speeds->integer ) {
  462. time_game = Sys_Milliseconds () - startTime;
  463. }
  464. SG_TestSave(); // returns immediately if not active, used for fake-save-every-cycle to test (mainly) Icarus disk code
  465. // check timeouts
  466. SV_CheckTimeouts ();
  467. // update ping based on the last known frame from all clients
  468. SV_CalcPings ();
  469. // send messages back to the clients
  470. SV_SendClientMessages ();
  471. }
  472. //============================================================================