|
|
1.1.1.3 ! root 1: /* ! 2: Copyright (C) 1997-2001 Id Software, Inc. ! 3: ! 4: This program is free software; you can redistribute it and/or ! 5: modify it under the terms of the GNU General Public License ! 6: as published by the Free Software Foundation; either version 2 ! 7: of the License, or (at your option) any later version. ! 8: ! 9: This program is distributed in the hope that it will be useful, ! 10: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ! 12: ! 13: See the GNU General Public License for more details. ! 14: ! 15: You should have received a copy of the GNU General Public License ! 16: along with this program; if not, write to the Free Software ! 17: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ! 18: ! 19: */ 1.1 root 20: // sv_user.c -- server code for moving users 21: 22: #include "server.h" 23: 24: edict_t *sv_player; 25: 26: /* 27: ============================================================ 28: 29: USER STRINGCMD EXECUTION 30: 31: sv_client and sv_player will be valid. 32: ============================================================ 33: */ 34: 35: /* 36: ================== 37: SV_BeginDemoServer 38: ================== 39: */ 40: void SV_BeginDemoserver (void) 41: { 42: char name[MAX_OSPATH]; 43: 44: Com_sprintf (name, sizeof(name), "demos/%s", sv.name); 45: FS_FOpenFile (name, &sv.demofile); 46: if (!sv.demofile) 47: Com_Error (ERR_DROP, "Couldn't open %s\n", name); 48: } 49: 50: /* 51: ================ 52: SV_New_f 53: 54: Sends the first message from the server to a connected client. 55: This will be sent on the initial connection and upon each server load. 56: ================ 57: */ 58: void SV_New_f (void) 59: { 60: char *gamedir; 61: int playernum; 62: edict_t *ent; 63: 64: Com_DPrintf ("New() from %s\n", sv_client->name); 65: 66: if (sv_client->state != cs_connected) 67: { 68: Com_Printf ("New not valid -- already spawned\n"); 69: return; 70: } 71: 72: // demo servers just dump the file message 73: if (sv.state == ss_demo) 74: { 75: SV_BeginDemoserver (); 76: return; 77: } 78: 79: // 80: // serverdata needs to go over for all types of servers 81: // to make sure the protocol is right, and to set the gamedir 82: // 83: gamedir = Cvar_VariableString ("gamedir"); 84: 85: // send the serverdata 86: MSG_WriteByte (&sv_client->netchan.message, svc_serverdata); 87: MSG_WriteLong (&sv_client->netchan.message, PROTOCOL_VERSION); 88: MSG_WriteLong (&sv_client->netchan.message, svs.spawncount); 89: MSG_WriteByte (&sv_client->netchan.message, sv.attractloop); 90: MSG_WriteString (&sv_client->netchan.message, gamedir); 91: 92: if (sv.state == ss_cinematic || sv.state == ss_pic) 93: playernum = -1; 94: else 95: playernum = sv_client - svs.clients; 96: MSG_WriteShort (&sv_client->netchan.message, playernum); 97: 98: // send full levelname 99: MSG_WriteString (&sv_client->netchan.message, sv.configstrings[CS_NAME]); 100: 101: // 102: // game server 103: // 104: if (sv.state == ss_game) 105: { 106: // set up the entity for the client 107: ent = EDICT_NUM(playernum+1); 108: ent->s.number = playernum+1; 109: sv_client->edict = ent; 110: memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd)); 111: 112: // begin fetching configstrings 113: MSG_WriteByte (&sv_client->netchan.message, svc_stufftext); 114: MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i 0\n",svs.spawncount) ); 115: } 116: 117: } 118: 119: /* 120: ================== 121: SV_Configstrings_f 122: ================== 123: */ 124: void SV_Configstrings_f (void) 125: { 126: int start; 127: 128: Com_DPrintf ("Configstrings() from %s\n", sv_client->name); 129: 130: if (sv_client->state != cs_connected) 131: { 132: Com_Printf ("configstrings not valid -- already spawned\n"); 133: return; 134: } 135: 136: // handle the case of a level changing while a client was connecting 137: if ( atoi(Cmd_Argv(1)) != svs.spawncount ) 138: { 139: Com_Printf ("SV_Configstrings_f from different level\n"); 140: SV_New_f (); 141: return; 142: } 143: 144: start = atoi(Cmd_Argv(2)); 145: 146: // write a packet full of data 147: 148: while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2 149: && start < MAX_CONFIGSTRINGS) 150: { 151: if (sv.configstrings[start][0]) 152: { 153: MSG_WriteByte (&sv_client->netchan.message, svc_configstring); 154: MSG_WriteShort (&sv_client->netchan.message, start); 155: MSG_WriteString (&sv_client->netchan.message, sv.configstrings[start]); 156: } 157: start++; 158: } 159: 160: // send next command 161: 162: if (start == MAX_CONFIGSTRINGS) 163: { 164: MSG_WriteByte (&sv_client->netchan.message, svc_stufftext); 165: MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i 0\n",svs.spawncount) ); 166: } 167: else 168: { 169: MSG_WriteByte (&sv_client->netchan.message, svc_stufftext); 170: MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i %i\n",svs.spawncount, start) ); 171: } 172: } 173: 174: /* 175: ================== 176: SV_Baselines_f 177: ================== 178: */ 179: void SV_Baselines_f (void) 180: { 181: int start; 182: entity_state_t nullstate; 183: entity_state_t *base; 184: 185: Com_DPrintf ("Baselines() from %s\n", sv_client->name); 186: 187: if (sv_client->state != cs_connected) 188: { 189: Com_Printf ("baselines not valid -- already spawned\n"); 190: return; 191: } 192: 193: // handle the case of a level changing while a client was connecting 194: if ( atoi(Cmd_Argv(1)) != svs.spawncount ) 195: { 196: Com_Printf ("SV_Baselines_f from different level\n"); 197: SV_New_f (); 198: return; 199: } 200: 201: start = atoi(Cmd_Argv(2)); 202: 203: memset (&nullstate, 0, sizeof(nullstate)); 204: 205: // write a packet full of data 206: 207: while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2 208: && start < MAX_EDICTS) 209: { 210: base = &sv.baselines[start]; 211: if (base->modelindex || base->sound || base->effects) 212: { 213: MSG_WriteByte (&sv_client->netchan.message, svc_spawnbaseline); 1.1.1.2 root 214: MSG_WriteDeltaEntity (&nullstate, base, &sv_client->netchan.message, true, true); 1.1 root 215: } 216: start++; 217: } 218: 219: // send next command 220: 221: if (start == MAX_EDICTS) 222: { 223: MSG_WriteByte (&sv_client->netchan.message, svc_stufftext); 1.1.1.2 root 224: MSG_WriteString (&sv_client->netchan.message, va("precache %i\n", svs.spawncount) ); 1.1 root 225: } 226: else 227: { 228: MSG_WriteByte (&sv_client->netchan.message, svc_stufftext); 229: MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i %i\n",svs.spawncount, start) ); 230: } 231: } 232: 233: /* 234: ================== 235: SV_Begin_f 236: ================== 237: */ 238: void SV_Begin_f (void) 239: { 240: Com_DPrintf ("Begin() from %s\n", sv_client->name); 241: 242: // handle the case of a level changing while a client was connecting 243: if ( atoi(Cmd_Argv(1)) != svs.spawncount ) 244: { 245: Com_Printf ("SV_Begin_f from different level\n"); 246: SV_New_f (); 247: return; 248: } 249: 250: sv_client->state = cs_spawned; 1.1.1.3 ! root 251: 1.1 root 252: // call the game begin function 253: ge->ClientBegin (sv_player); 254: 255: Cbuf_InsertFromDefer (); 256: } 257: 258: //============================================================================= 259: 260: /* 261: ================== 262: SV_NextDownload_f 263: ================== 264: */ 265: void SV_NextDownload_f (void) 266: { 267: int r; 268: int percent; 269: int size; 270: 271: if (!sv_client->download) 272: return; 273: 274: r = sv_client->downloadsize - sv_client->downloadcount; 275: if (r > 1024) 276: r = 1024; 277: 278: MSG_WriteByte (&sv_client->netchan.message, svc_download); 279: MSG_WriteShort (&sv_client->netchan.message, r); 280: 281: sv_client->downloadcount += r; 282: size = sv_client->downloadsize; 283: if (!size) 284: size = 1; 285: percent = sv_client->downloadcount*100/size; 286: MSG_WriteByte (&sv_client->netchan.message, percent); 287: SZ_Write (&sv_client->netchan.message, 288: sv_client->download + sv_client->downloadcount - r, r); 289: 290: if (sv_client->downloadcount != sv_client->downloadsize) 291: return; 292: 293: FS_FreeFile (sv_client->download); 294: sv_client->download = NULL; 295: } 296: 297: /* 298: ================== 299: SV_BeginDownload_f 300: ================== 301: */ 302: void SV_BeginDownload_f(void) 303: { 304: char *name; 305: extern cvar_t *allow_download; 1.1.1.2 root 306: extern cvar_t *allow_download_players; 307: extern cvar_t *allow_download_models; 308: extern cvar_t *allow_download_sounds; 309: extern cvar_t *allow_download_maps; 310: extern int file_from_pak; // ZOID did file come from pak? 311: int offset = 0; 1.1 root 312: 313: name = Cmd_Argv(1); 1.1.1.2 root 314: 315: if (Cmd_Argc() > 2) 316: offset = atoi(Cmd_Argv(2)); // downloaded offset 317: 318: // hacked by zoid to allow more conrol over download 319: // first off, no .. or global allow check 1.1 root 320: if (strstr (name, "..") || !allow_download->value 1.1.1.2 root 321: // leading dot is no good 322: || *name == '.' 323: // leading slash bad as well, must be in subdir 324: || *name == '/' 325: // next up, skin check 326: || (strncmp(name, "players/", 6) == 0 && !allow_download_players->value) 327: // now models 328: || (strncmp(name, "models/", 6) == 0 && !allow_download_models->value) 329: // now sounds 330: || (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds->value) 331: // now maps (note special case for maps, must not be in pak) 332: || (strncmp(name, "maps/", 6) == 0 && !allow_download_maps->value) 333: // MUST be in a subdirectory 334: || !strstr (name, "/") ) 1.1 root 335: { // don't allow anything with .. path 336: MSG_WriteByte (&sv_client->netchan.message, svc_download); 337: MSG_WriteShort (&sv_client->netchan.message, -1); 338: MSG_WriteByte (&sv_client->netchan.message, 0); 339: return; 340: } 341: 1.1.1.2 root 342: 1.1 root 343: if (sv_client->download) 344: FS_FreeFile (sv_client->download); 345: 346: sv_client->downloadsize = FS_LoadFile (name, (void **)&sv_client->download); 1.1.1.2 root 347: sv_client->downloadcount = offset; 1.1 root 348: 1.1.1.2 root 349: if (offset > sv_client->downloadsize) 350: sv_client->downloadcount = sv_client->downloadsize; 351: 352: if (!sv_client->download 353: // special check for maps, if it came from a pak file, don't allow 354: // download ZOID 355: || (strncmp(name, "maps/", 5) == 0 && file_from_pak)) 1.1 root 356: { 357: Com_DPrintf ("Couldn't download %s to %s\n", name, sv_client->name); 1.1.1.2 root 358: if (sv_client->download) { 359: FS_FreeFile (sv_client->download); 360: sv_client->download = NULL; 361: } 362: 1.1 root 363: MSG_WriteByte (&sv_client->netchan.message, svc_download); 364: MSG_WriteShort (&sv_client->netchan.message, -1); 365: MSG_WriteByte (&sv_client->netchan.message, 0); 366: return; 367: } 368: 369: SV_NextDownload_f (); 370: Com_DPrintf ("Downloading %s to %s\n", name, sv_client->name); 371: } 372: 373: 1.1.1.2 root 374: 1.1 root 375: //============================================================================ 376: 377: 378: /* 379: ================= 380: SV_Disconnect_f 381: 382: The client is going to disconnect, so remove the connection immediately 383: ================= 384: */ 385: void SV_Disconnect_f (void) 386: { 387: // SV_EndRedirect (); 388: SV_DropClient (sv_client); 389: } 390: 391: 392: /* 393: ================== 394: SV_ShowServerinfo_f 395: 396: Dumps the serverinfo info string 397: ================== 398: */ 399: void SV_ShowServerinfo_f (void) 400: { 401: Info_Print (Cvar_Serverinfo()); 402: } 403: 404: 405: void SV_Nextserver (void) 406: { 407: char *v; 408: 1.1.1.2 root 409: //ZOID, ss_pic can be nextserver'd in coop mode 410: if (sv.state == ss_game || (sv.state == ss_pic && !Cvar_VariableValue("coop"))) 1.1 root 411: return; // can't nextserver while playing a normal game 412: 413: svs.spawncount++; // make sure another doesn't sneak in 414: v = Cvar_VariableString ("nextserver"); 415: if (!v[0]) 416: Cbuf_AddText ("killserver\n"); 417: else 418: { 419: Cbuf_AddText (v); 420: Cbuf_AddText ("\n"); 421: } 422: Cvar_Set ("nextserver",""); 423: } 424: 425: /* 426: ================== 427: SV_Nextserver_f 428: 429: A cinematic has completed or been aborted by a client, so move 430: to the next server, 431: ================== 432: */ 433: void SV_Nextserver_f (void) 434: { 1.1.1.2 root 435: if ( atoi(Cmd_Argv(1)) != svs.spawncount ) { 436: Com_DPrintf ("Nextserver() from wrong level, from %s\n", sv_client->name); 1.1 root 437: return; // leftover from last server 1.1.1.2 root 438: } 439: 440: Com_DPrintf ("Nextserver() from %s\n", sv_client->name); 1.1 root 441: 442: SV_Nextserver (); 443: } 444: 445: typedef struct 446: { 447: char *name; 448: void (*func) (void); 449: } ucmd_t; 450: 451: ucmd_t ucmds[] = 452: { 453: // auto issued 454: {"new", SV_New_f}, 455: {"configstrings", SV_Configstrings_f}, 456: {"baselines", SV_Baselines_f}, 457: {"begin", SV_Begin_f}, 458: 459: {"nextserver", SV_Nextserver_f}, 460: 461: {"disconnect", SV_Disconnect_f}, 462: 463: // issued by hand at client consoles 464: {"info", SV_ShowServerinfo_f}, 465: 466: {"download", SV_BeginDownload_f}, 467: {"nextdl", SV_NextDownload_f}, 468: 469: {NULL, NULL} 470: }; 471: 472: /* 473: ================== 474: SV_ExecuteUserCommand 475: ================== 476: */ 477: void SV_ExecuteUserCommand (char *s) 478: { 479: ucmd_t *u; 480: 481: Cmd_TokenizeString (s, true); 482: sv_player = sv_client->edict; 483: 484: // SV_BeginRedirect (RD_CLIENT); 485: 486: for (u=ucmds ; u->name ; u++) 487: if (!strcmp (Cmd_Argv(0), u->name) ) 488: { 489: u->func (); 490: break; 491: } 492: 493: if (!u->name && sv.state == ss_game) 494: ge->ClientCommand (sv_player); 495: 496: // SV_EndRedirect (); 497: } 498: 499: /* 500: =========================================================================== 501: 502: USER CMD EXECUTION 503: 504: =========================================================================== 505: */ 506: 507: 1.1.1.2 root 508: 509: void SV_ClientThink (client_t *cl, usercmd_t *cmd) 510: 1.1 root 511: { 512: cl->commandMsec -= cmd->msec; 1.1.1.2 root 513: 1.1 root 514: if (cl->commandMsec < 0 && sv_enforcetime->value ) 515: { 516: Com_DPrintf ("commandMsec underflow from %s\n", cl->name); 517: return; 518: } 1.1.1.2 root 519: 1.1 root 520: ge->ClientThink (cl->edict, cmd); 521: } 522: 1.1.1.2 root 523: 524: 1.1 root 525: #define MAX_STRINGCMDS 8 526: /* 527: =================== 528: SV_ExecuteClientMessage 529: 530: The current net_message is parsed for the given client 531: =================== 532: */ 533: void SV_ExecuteClientMessage (client_t *cl) 534: { 535: int c; 536: char *s; 1.1.1.2 root 537: 1.1 root 538: usercmd_t nullcmd; 539: usercmd_t oldest, oldcmd, newcmd; 540: int net_drop; 541: int stringCmdCount; 542: int checksum, calculatedChecksum; 543: int checksumIndex; 544: qboolean move_issued; 1.1.1.2 root 545: int lastframe; 1.1 root 546: 547: sv_client = cl; 548: sv_player = sv_client->edict; 549: 550: // only allow one move command 551: move_issued = false; 552: stringCmdCount = 0; 553: 554: while (1) 555: { 556: if (net_message.readcount > net_message.cursize) 557: { 558: Com_Printf ("SV_ReadClientMessage: badread\n"); 559: SV_DropClient (cl); 560: return; 561: } 562: 563: c = MSG_ReadByte (&net_message); 564: if (c == -1) 565: break; 566: 567: switch (c) 568: { 569: default: 570: Com_Printf ("SV_ReadClientMessage: unknown command char\n"); 571: SV_DropClient (cl); 572: return; 573: 574: case clc_nop: 575: break; 576: 577: case clc_userinfo: 578: strncpy (cl->userinfo, MSG_ReadString (&net_message), sizeof(cl->userinfo)-1); 579: SV_UserinfoChanged (cl); 580: break; 581: 582: case clc_move: 583: if (move_issued) 584: return; // someone is trying to cheat... 585: 1.1.1.2 root 586: move_issued = true; 1.1 root 587: checksumIndex = net_message.readcount; 588: checksum = MSG_ReadByte (&net_message); 1.1.1.2 root 589: lastframe = MSG_ReadLong (&net_message); 590: if (lastframe != cl->lastframe) { 591: cl->lastframe = lastframe; 592: if (cl->lastframe > 0) { 593: cl->frame_latency[cl->lastframe&(LATENCY_COUNTS-1)] = 594: svs.realtime - cl->frames[cl->lastframe & UPDATE_MASK].senttime; 595: } 596: } 1.1 root 597: 598: memset (&nullcmd, 0, sizeof(nullcmd)); 599: MSG_ReadDeltaUsercmd (&net_message, &nullcmd, &oldest); 600: MSG_ReadDeltaUsercmd (&net_message, &oldest, &oldcmd); 601: MSG_ReadDeltaUsercmd (&net_message, &oldcmd, &newcmd); 602: 603: if ( cl->state != cs_spawned ) 604: { 605: cl->lastframe = -1; 606: break; 607: } 608: 609: // if the checksum fails, ignore the rest of the packet 1.1.1.2 root 610: calculatedChecksum = COM_BlockSequenceCRCByte ( 1.1 root 611: net_message.data + checksumIndex + 1, 612: net_message.readcount - checksumIndex - 1, 613: cl->netchan.incoming_sequence); 614: 615: if (calculatedChecksum != checksum) 616: { 1.1.1.2 root 617: Com_DPrintf ("Failed command checksum for %s (%d != %d)/%d\n", 618: cl->name, calculatedChecksum, checksum, 619: cl->netchan.incoming_sequence); 1.1 root 620: return; 621: } 622: 623: if (!sv_paused->value) 624: { 625: net_drop = cl->netchan.dropped; 626: if (net_drop < 20) 627: { 1.1.1.2 root 628: 1.1 root 629: //if (net_drop > 2) 1.1.1.2 root 630: 1.1 root 631: // Com_Printf ("drop %i\n", net_drop); 632: while (net_drop > 2) 633: { 1.1.1.2 root 634: SV_ClientThink (cl, &cl->lastcmd); 635: 1.1 root 636: net_drop--; 637: } 638: if (net_drop > 1) 1.1.1.2 root 639: SV_ClientThink (cl, &oldest); 640: 1.1 root 641: if (net_drop > 0) 1.1.1.2 root 642: SV_ClientThink (cl, &oldcmd); 643: 1.1 root 644: } 1.1.1.2 root 645: SV_ClientThink (cl, &newcmd); 1.1 root 646: } 647: 648: cl->lastcmd = newcmd; 649: break; 650: 651: case clc_stringcmd: 652: s = MSG_ReadString (&net_message); 653: 654: // malicious users may try using too many string commands 655: if (++stringCmdCount < MAX_STRINGCMDS) 656: SV_ExecuteUserCommand (s); 1.1.1.2 root 657: 1.1 root 658: if (cl->state == cs_zombie) 659: return; // disconnect command 660: break; 661: } 662: } 663: } 664:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.