|
|
1.1 ! root 1: /* ! 2: Copyright (C) 1996-1997 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: */ ! 20: // sv_user.c -- server code for moving users ! 21: ! 22: #include "qwsvdef.h" ! 23: ! 24: edict_t *sv_player; ! 25: ! 26: usercmd_t cmd; ! 27: ! 28: cvar_t cl_rollspeed = {"cl_rollspeed", "200"}; ! 29: cvar_t cl_rollangle = {"cl_rollangle", "2.0"}; ! 30: cvar_t sv_spectalk = {"sv_spectalk", "1"}; ! 31: ! 32: cvar_t sv_mapcheck = {"sv_mapcheck", "1"}; ! 33: ! 34: extern vec3_t player_mins; ! 35: ! 36: extern int fp_messages, fp_persecond, fp_secondsdead; ! 37: extern char fp_msg[]; ! 38: extern cvar_t pausable; ! 39: ! 40: /* ! 41: ============================================================ ! 42: ! 43: USER STRINGCMD EXECUTION ! 44: ! 45: host_client and sv_player will be valid. ! 46: ============================================================ ! 47: */ ! 48: ! 49: /* ! 50: ================ ! 51: SV_New_f ! 52: ! 53: Sends the first message from the server to a connected client. ! 54: This will be sent on the initial connection and upon each server load. ! 55: ================ ! 56: */ ! 57: void SV_New_f (void) ! 58: { ! 59: char *gamedir; ! 60: int playernum; ! 61: ! 62: if (host_client->state == cs_spawned) ! 63: return; ! 64: ! 65: host_client->state = cs_connected; ! 66: host_client->connection_started = realtime; ! 67: ! 68: // send the info about the new client to all connected clients ! 69: // SV_FullClientUpdate (host_client, &sv.reliable_datagram); ! 70: // host_client->sendinfo = true; ! 71: ! 72: gamedir = Info_ValueForKey (svs.info, "*gamedir"); ! 73: if (!gamedir[0]) ! 74: gamedir = "qw"; ! 75: ! 76: //NOTE: This doesn't go through ClientReliableWrite since it's before the user ! 77: //spawns. These functions are written to not overflow ! 78: if (host_client->num_backbuf) { ! 79: Con_Printf("WARNING %s: [SV_New] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize); ! 80: host_client->num_backbuf = 0; ! 81: SZ_Clear(&host_client->netchan.message); ! 82: } ! 83: ! 84: // send the serverdata ! 85: MSG_WriteByte (&host_client->netchan.message, svc_serverdata); ! 86: MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION); ! 87: MSG_WriteLong (&host_client->netchan.message, svs.spawncount); ! 88: MSG_WriteString (&host_client->netchan.message, gamedir); ! 89: ! 90: playernum = NUM_FOR_EDICT(host_client->edict)-1; ! 91: if (host_client->spectator) ! 92: playernum |= 128; ! 93: MSG_WriteByte (&host_client->netchan.message, playernum); ! 94: ! 95: // send full levelname ! 96: MSG_WriteString (&host_client->netchan.message, PR_GetString(sv.edicts->v.message)); ! 97: ! 98: // send the movevars ! 99: MSG_WriteFloat(&host_client->netchan.message, movevars.gravity); ! 100: MSG_WriteFloat(&host_client->netchan.message, movevars.stopspeed); ! 101: MSG_WriteFloat(&host_client->netchan.message, movevars.maxspeed); ! 102: MSG_WriteFloat(&host_client->netchan.message, movevars.spectatormaxspeed); ! 103: MSG_WriteFloat(&host_client->netchan.message, movevars.accelerate); ! 104: MSG_WriteFloat(&host_client->netchan.message, movevars.airaccelerate); ! 105: MSG_WriteFloat(&host_client->netchan.message, movevars.wateraccelerate); ! 106: MSG_WriteFloat(&host_client->netchan.message, movevars.friction); ! 107: MSG_WriteFloat(&host_client->netchan.message, movevars.waterfriction); ! 108: MSG_WriteFloat(&host_client->netchan.message, movevars.entgravity); ! 109: ! 110: // send music ! 111: MSG_WriteByte (&host_client->netchan.message, svc_cdtrack); ! 112: MSG_WriteByte (&host_client->netchan.message, sv.edicts->v.sounds); ! 113: ! 114: // send server info string ! 115: MSG_WriteByte (&host_client->netchan.message, svc_stufftext); ! 116: MSG_WriteString (&host_client->netchan.message, va("fullserverinfo \"%s\"\n", svs.info) ); ! 117: } ! 118: ! 119: /* ! 120: ================== ! 121: SV_Soundlist_f ! 122: ================== ! 123: */ ! 124: void SV_Soundlist_f (void) ! 125: { ! 126: char **s; ! 127: int n; ! 128: ! 129: if (host_client->state != cs_connected) ! 130: { ! 131: Con_Printf ("soundlist not valid -- allready spawned\n"); ! 132: return; ! 133: } ! 134: ! 135: // handle the case of a level changing while a client was connecting ! 136: if ( atoi(Cmd_Argv(1)) != svs.spawncount ) ! 137: { ! 138: Con_Printf ("SV_Soundlist_f from different level\n"); ! 139: SV_New_f (); ! 140: return; ! 141: } ! 142: ! 143: n = atoi(Cmd_Argv(2)); ! 144: ! 145: //NOTE: This doesn't go through ClientReliableWrite since it's before the user ! 146: //spawns. These functions are written to not overflow ! 147: if (host_client->num_backbuf) { ! 148: Con_Printf("WARNING %s: [SV_Soundlist] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize); ! 149: host_client->num_backbuf = 0; ! 150: SZ_Clear(&host_client->netchan.message); ! 151: } ! 152: ! 153: MSG_WriteByte (&host_client->netchan.message, svc_soundlist); ! 154: MSG_WriteByte (&host_client->netchan.message, n); ! 155: for (s = sv.sound_precache+1 + n ; ! 156: *s && host_client->netchan.message.cursize < (MAX_MSGLEN/2); ! 157: s++, n++) ! 158: MSG_WriteString (&host_client->netchan.message, *s); ! 159: ! 160: MSG_WriteByte (&host_client->netchan.message, 0); ! 161: ! 162: // next msg ! 163: if (*s) ! 164: MSG_WriteByte (&host_client->netchan.message, n); ! 165: else ! 166: MSG_WriteByte (&host_client->netchan.message, 0); ! 167: } ! 168: ! 169: /* ! 170: ================== ! 171: SV_Modellist_f ! 172: ================== ! 173: */ ! 174: void SV_Modellist_f (void) ! 175: { ! 176: char **s; ! 177: int n; ! 178: ! 179: if (host_client->state != cs_connected) ! 180: { ! 181: Con_Printf ("modellist not valid -- allready spawned\n"); ! 182: return; ! 183: } ! 184: ! 185: // handle the case of a level changing while a client was connecting ! 186: if ( atoi(Cmd_Argv(1)) != svs.spawncount ) ! 187: { ! 188: Con_Printf ("SV_Modellist_f from different level\n"); ! 189: SV_New_f (); ! 190: return; ! 191: } ! 192: ! 193: n = atoi(Cmd_Argv(2)); ! 194: ! 195: //NOTE: This doesn't go through ClientReliableWrite since it's before the user ! 196: //spawns. These functions are written to not overflow ! 197: if (host_client->num_backbuf) { ! 198: Con_Printf("WARNING %s: [SV_Modellist] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize); ! 199: host_client->num_backbuf = 0; ! 200: SZ_Clear(&host_client->netchan.message); ! 201: } ! 202: ! 203: MSG_WriteByte (&host_client->netchan.message, svc_modellist); ! 204: MSG_WriteByte (&host_client->netchan.message, n); ! 205: for (s = sv.model_precache+1+n ; ! 206: *s && host_client->netchan.message.cursize < (MAX_MSGLEN/2); ! 207: s++, n++) ! 208: MSG_WriteString (&host_client->netchan.message, *s); ! 209: MSG_WriteByte (&host_client->netchan.message, 0); ! 210: ! 211: // next msg ! 212: if (*s) ! 213: MSG_WriteByte (&host_client->netchan.message, n); ! 214: else ! 215: MSG_WriteByte (&host_client->netchan.message, 0); ! 216: } ! 217: ! 218: /* ! 219: ================== ! 220: SV_PreSpawn_f ! 221: ================== ! 222: */ ! 223: void SV_PreSpawn_f (void) ! 224: { ! 225: unsigned buf; ! 226: unsigned check; ! 227: ! 228: if (host_client->state != cs_connected) ! 229: { ! 230: Con_Printf ("prespawn not valid -- allready spawned\n"); ! 231: return; ! 232: } ! 233: ! 234: // handle the case of a level changing while a client was connecting ! 235: if ( atoi(Cmd_Argv(1)) != svs.spawncount ) ! 236: { ! 237: Con_Printf ("SV_PreSpawn_f from different level\n"); ! 238: SV_New_f (); ! 239: return; ! 240: } ! 241: ! 242: buf = atoi(Cmd_Argv(2)); ! 243: if (buf >= sv.num_signon_buffers) ! 244: buf = 0; ! 245: ! 246: if (!buf) { ! 247: // should be three numbers following containing checksums ! 248: check = atoi(Cmd_Argv(3)); ! 249: ! 250: // Con_DPrintf("Client check = %d\n", check); ! 251: ! 252: if (sv_mapcheck.value && check != sv.worldmodel->checksum && ! 253: check != sv.worldmodel->checksum2) { ! 254: SV_ClientPrintf (host_client, PRINT_HIGH, ! 255: "Map model file does not match (%s), %i != %i/%i.\n" ! 256: "You may need a new version of the map, or the proper install files.\n", ! 257: sv.modelname, check, sv.worldmodel->checksum, sv.worldmodel->checksum2); ! 258: SV_DropClient (host_client); ! 259: return; ! 260: } ! 261: host_client->checksum = check; ! 262: } ! 263: ! 264: //NOTE: This doesn't go through ClientReliableWrite since it's before the user ! 265: //spawns. These functions are written to not overflow ! 266: if (host_client->num_backbuf) { ! 267: Con_Printf("WARNING %s: [SV_PreSpawn] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize); ! 268: host_client->num_backbuf = 0; ! 269: SZ_Clear(&host_client->netchan.message); ! 270: } ! 271: ! 272: SZ_Write (&host_client->netchan.message, ! 273: sv.signon_buffers[buf], ! 274: sv.signon_buffer_size[buf]); ! 275: ! 276: buf++; ! 277: if (buf == sv.num_signon_buffers) ! 278: { // all done prespawning ! 279: MSG_WriteByte (&host_client->netchan.message, svc_stufftext); ! 280: MSG_WriteString (&host_client->netchan.message, va("cmd spawn %i 0\n",svs.spawncount) ); ! 281: } ! 282: else ! 283: { // need to prespawn more ! 284: MSG_WriteByte (&host_client->netchan.message, svc_stufftext); ! 285: MSG_WriteString (&host_client->netchan.message, ! 286: va("cmd prespawn %i %i\n", svs.spawncount, buf) ); ! 287: } ! 288: } ! 289: ! 290: /* ! 291: ================== ! 292: SV_Spawn_f ! 293: ================== ! 294: */ ! 295: void SV_Spawn_f (void) ! 296: { ! 297: int i; ! 298: client_t *client; ! 299: edict_t *ent; ! 300: eval_t *val; ! 301: int n; ! 302: ! 303: if (host_client->state != cs_connected) ! 304: { ! 305: Con_Printf ("Spawn not valid -- allready spawned\n"); ! 306: return; ! 307: } ! 308: ! 309: // handle the case of a level changing while a client was connecting ! 310: if ( atoi(Cmd_Argv(1)) != svs.spawncount ) ! 311: { ! 312: Con_Printf ("SV_Spawn_f from different level\n"); ! 313: SV_New_f (); ! 314: return; ! 315: } ! 316: ! 317: n = atoi(Cmd_Argv(2)); ! 318: ! 319: // make sure n is valid ! 320: if ( n < 0 || n > MAX_CLIENTS ) ! 321: { ! 322: Con_Printf ("SV_Spawn_f invalid client start\n"); ! 323: SV_New_f (); ! 324: return; ! 325: } ! 326: ! 327: ! 328: ! 329: // send all current names, colors, and frag counts ! 330: // FIXME: is this a good thing? ! 331: SZ_Clear (&host_client->netchan.message); ! 332: ! 333: // send current status of all other players ! 334: ! 335: // normally this could overflow, but no need to check due to backbuf ! 336: for (i=n, client = svs.clients + n ; i<MAX_CLIENTS ; i++, client++) ! 337: SV_FullClientUpdateToClient (client, host_client); ! 338: ! 339: // send all current light styles ! 340: for (i=0 ; i<MAX_LIGHTSTYLES ; i++) ! 341: { ! 342: ClientReliableWrite_Begin (host_client, svc_lightstyle, ! 343: 3 + (sv.lightstyles[i] ? strlen(sv.lightstyles[i]) : 1)); ! 344: ClientReliableWrite_Byte (host_client, (char)i); ! 345: ClientReliableWrite_String (host_client, sv.lightstyles[i]); ! 346: } ! 347: ! 348: // set up the edict ! 349: ent = host_client->edict; ! 350: ! 351: memset (&ent->v, 0, progs->entityfields * 4); ! 352: ent->v.colormap = NUM_FOR_EDICT(ent); ! 353: ent->v.team = 0; // FIXME ! 354: ent->v.netname = PR_SetString(host_client->name); ! 355: ! 356: host_client->entgravity = 1.0; ! 357: val = GetEdictFieldValue(ent, "gravity"); ! 358: if (val) ! 359: val->_float = 1.0; ! 360: host_client->maxspeed = sv_maxspeed.value; ! 361: val = GetEdictFieldValue(ent, "maxspeed"); ! 362: if (val) ! 363: val->_float = sv_maxspeed.value; ! 364: ! 365: // ! 366: // force stats to be updated ! 367: // ! 368: memset (host_client->stats, 0, sizeof(host_client->stats)); ! 369: ! 370: ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6); ! 371: ClientReliableWrite_Byte (host_client, STAT_TOTALSECRETS); ! 372: ClientReliableWrite_Long (host_client, pr_global_struct->total_secrets); ! 373: ! 374: ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6); ! 375: ClientReliableWrite_Byte (host_client, STAT_TOTALMONSTERS); ! 376: ClientReliableWrite_Long (host_client, pr_global_struct->total_monsters); ! 377: ! 378: ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6); ! 379: ClientReliableWrite_Byte (host_client, STAT_SECRETS); ! 380: ClientReliableWrite_Long (host_client, pr_global_struct->found_secrets); ! 381: ! 382: ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6); ! 383: ClientReliableWrite_Byte (host_client, STAT_MONSTERS); ! 384: ClientReliableWrite_Long (host_client, pr_global_struct->killed_monsters); ! 385: ! 386: // get the client to check and download skins ! 387: // when that is completed, a begin command will be issued ! 388: ClientReliableWrite_Begin (host_client, svc_stufftext, 8); ! 389: ClientReliableWrite_String (host_client, "skins\n" ); ! 390: ! 391: } ! 392: ! 393: /* ! 394: ================== ! 395: SV_SpawnSpectator ! 396: ================== ! 397: */ ! 398: void SV_SpawnSpectator (void) ! 399: { ! 400: int i; ! 401: edict_t *e; ! 402: ! 403: VectorCopy (vec3_origin, sv_player->v.origin); ! 404: VectorCopy (vec3_origin, sv_player->v.view_ofs); ! 405: sv_player->v.view_ofs[2] = 22; ! 406: ! 407: // search for an info_playerstart to spawn the spectator at ! 408: for (i=MAX_CLIENTS-1 ; i<sv.num_edicts ; i++) ! 409: { ! 410: e = EDICT_NUM(i); ! 411: if (!strcmp(PR_GetString(e->v.classname), "info_player_start")) ! 412: { ! 413: VectorCopy (e->v.origin, sv_player->v.origin); ! 414: return; ! 415: } ! 416: } ! 417: ! 418: } ! 419: ! 420: /* ! 421: ================== ! 422: SV_Begin_f ! 423: ================== ! 424: */ ! 425: void SV_Begin_f (void) ! 426: { ! 427: unsigned pmodel = 0, emodel = 0; ! 428: int i; ! 429: ! 430: if (host_client->state == cs_spawned) ! 431: return; // don't begin again ! 432: ! 433: host_client->state = cs_spawned; ! 434: ! 435: // handle the case of a level changing while a client was connecting ! 436: if ( atoi(Cmd_Argv(1)) != svs.spawncount ) ! 437: { ! 438: Con_Printf ("SV_Begin_f from different level\n"); ! 439: SV_New_f (); ! 440: return; ! 441: } ! 442: ! 443: if (host_client->spectator) ! 444: { ! 445: SV_SpawnSpectator (); ! 446: ! 447: if (SpectatorConnect) { ! 448: // copy spawn parms out of the client_t ! 449: for (i=0 ; i< NUM_SPAWN_PARMS ; i++) ! 450: (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i]; ! 451: ! 452: // call the spawn function ! 453: pr_global_struct->time = sv.time; ! 454: pr_global_struct->self = EDICT_TO_PROG(sv_player); ! 455: PR_ExecuteProgram (SpectatorConnect); ! 456: } ! 457: } ! 458: else ! 459: { ! 460: // copy spawn parms out of the client_t ! 461: for (i=0 ; i< NUM_SPAWN_PARMS ; i++) ! 462: (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i]; ! 463: ! 464: // call the spawn function ! 465: pr_global_struct->time = sv.time; ! 466: pr_global_struct->self = EDICT_TO_PROG(sv_player); ! 467: PR_ExecuteProgram (pr_global_struct->ClientConnect); ! 468: ! 469: // actually spawn the player ! 470: pr_global_struct->time = sv.time; ! 471: pr_global_struct->self = EDICT_TO_PROG(sv_player); ! 472: PR_ExecuteProgram (pr_global_struct->PutClientInServer); ! 473: } ! 474: ! 475: // clear the net statistics, because connecting gives a bogus picture ! 476: host_client->netchan.frame_latency = 0; ! 477: host_client->netchan.frame_rate = 0; ! 478: host_client->netchan.drop_count = 0; ! 479: host_client->netchan.good_count = 0; ! 480: ! 481: //check he's not cheating ! 482: ! 483: pmodel = atoi(Info_ValueForKey (host_client->userinfo, "pmodel")); ! 484: emodel = atoi(Info_ValueForKey (host_client->userinfo, "emodel")); ! 485: ! 486: if (pmodel != sv.model_player_checksum || ! 487: emodel != sv.eyes_player_checksum) ! 488: SV_BroadcastPrintf (PRINT_HIGH, "%s WARNING: non standard player/eyes model detected\n", host_client->name); ! 489: ! 490: // if we are paused, tell the client ! 491: if (sv.paused) { ! 492: ClientReliableWrite_Begin (host_client, svc_setpause, 2); ! 493: ClientReliableWrite_Byte (host_client, sv.paused); ! 494: SV_ClientPrintf(host_client, PRINT_HIGH, "Server is paused.\n"); ! 495: } ! 496: ! 497: #if 0 ! 498: // ! 499: // send a fixangle over the reliable channel to make sure it gets there ! 500: // Never send a roll angle, because savegames can catch the server ! 501: // in a state where it is expecting the client to correct the angle ! 502: // and it won't happen if the game was just loaded, so you wind up ! 503: // with a permanent head tilt ! 504: ent = EDICT_NUM( 1 + (host_client - svs.clients) ); ! 505: MSG_WriteByte (&host_client->netchan.message, svc_setangle); ! 506: for (i=0 ; i < 2 ; i++) ! 507: MSG_WriteAngle (&host_client->netchan.message, ent->v.angles[i] ); ! 508: MSG_WriteAngle (&host_client->netchan.message, 0 ); ! 509: #endif ! 510: } ! 511: ! 512: //============================================================================= ! 513: ! 514: /* ! 515: ================== ! 516: SV_NextDownload_f ! 517: ================== ! 518: */ ! 519: void SV_NextDownload_f (void) ! 520: { ! 521: byte buffer[1024]; ! 522: int r; ! 523: int percent; ! 524: int size; ! 525: ! 526: if (!host_client->download) ! 527: return; ! 528: ! 529: r = host_client->downloadsize - host_client->downloadcount; ! 530: if (r > 768) ! 531: r = 768; ! 532: r = fread (buffer, 1, r, host_client->download); ! 533: ClientReliableWrite_Begin (host_client, svc_download, 6+r); ! 534: ClientReliableWrite_Short (host_client, r); ! 535: ! 536: host_client->downloadcount += r; ! 537: size = host_client->downloadsize; ! 538: if (!size) ! 539: size = 1; ! 540: percent = host_client->downloadcount*100/size; ! 541: ClientReliableWrite_Byte (host_client, percent); ! 542: ClientReliableWrite_SZ (host_client, buffer, r); ! 543: ! 544: if (host_client->downloadcount != host_client->downloadsize) ! 545: return; ! 546: ! 547: fclose (host_client->download); ! 548: host_client->download = NULL; ! 549: ! 550: } ! 551: ! 552: void OutofBandPrintf(netadr_t where, char *fmt, ...) ! 553: { ! 554: va_list argptr; ! 555: char send[1024]; ! 556: ! 557: send[0] = 0xff; ! 558: send[1] = 0xff; ! 559: send[2] = 0xff; ! 560: send[3] = 0xff; ! 561: send[4] = A2C_PRINT; ! 562: va_start (argptr, fmt); ! 563: vsprintf (send+5, fmt, argptr); ! 564: va_end (argptr); ! 565: ! 566: NET_SendPacket (strlen(send)+1, send, where); ! 567: } ! 568: ! 569: /* ! 570: ================== ! 571: SV_NextUpload ! 572: ================== ! 573: */ ! 574: void SV_NextUpload (void) ! 575: { ! 576: byte buffer[1024]; ! 577: int r; ! 578: int percent; ! 579: int size; ! 580: client_t *client; ! 581: ! 582: if (!*host_client->uploadfn) { ! 583: SV_ClientPrintf(host_client, PRINT_HIGH, "Upload denied\n"); ! 584: ClientReliableWrite_Begin (host_client, svc_stufftext, 8); ! 585: ClientReliableWrite_String (host_client, "stopul"); ! 586: ! 587: // suck out rest of packet ! 588: size = MSG_ReadShort (); MSG_ReadByte (); ! 589: msg_readcount += size; ! 590: return; ! 591: } ! 592: ! 593: size = MSG_ReadShort (); ! 594: percent = MSG_ReadByte (); ! 595: ! 596: if (!host_client->upload) ! 597: { ! 598: host_client->upload = fopen(host_client->uploadfn, "wb"); ! 599: if (!host_client->upload) { ! 600: Sys_Printf("Can't create %s\n", host_client->uploadfn); ! 601: ClientReliableWrite_Begin (host_client, svc_stufftext, 8); ! 602: ClientReliableWrite_String (host_client, "stopul"); ! 603: *host_client->uploadfn = 0; ! 604: return; ! 605: } ! 606: Sys_Printf("Receiving %s from %d...\n", host_client->uploadfn, host_client->userid); ! 607: if (host_client->remote_snap) ! 608: OutofBandPrintf(host_client->snap_from, "Server receiving %s from %d...\n", host_client->uploadfn, host_client->userid); ! 609: } ! 610: ! 611: fwrite (net_message.data + msg_readcount, 1, size, host_client->upload); ! 612: msg_readcount += size; ! 613: ! 614: Con_DPrintf ("UPLOAD: %d received\n", size); ! 615: ! 616: if (percent != 100) { ! 617: ClientReliableWrite_Begin (host_client, svc_stufftext, 8); ! 618: ClientReliableWrite_String (host_client, "nextul\n"); ! 619: } else { ! 620: fclose (host_client->upload); ! 621: host_client->upload = NULL; ! 622: ! 623: Sys_Printf("%s upload completed.\n", host_client->uploadfn); ! 624: ! 625: if (host_client->remote_snap) { ! 626: char *p; ! 627: ! 628: if ((p = strchr(host_client->uploadfn, '/')) != NULL) ! 629: p++; ! 630: else ! 631: p = host_client->uploadfn; ! 632: OutofBandPrintf(host_client->snap_from, "%s upload completed.\nTo download, enter:\ndownload %s\n", ! 633: host_client->uploadfn, p); ! 634: } ! 635: } ! 636: ! 637: } ! 638: ! 639: /* ! 640: ================== ! 641: SV_BeginDownload_f ! 642: ================== ! 643: */ ! 644: void SV_BeginDownload_f(void) ! 645: { ! 646: char *name; ! 647: extern cvar_t allow_download; ! 648: extern cvar_t allow_download_skins; ! 649: extern cvar_t allow_download_models; ! 650: extern cvar_t allow_download_sounds; ! 651: extern cvar_t allow_download_maps; ! 652: extern int file_from_pak; // ZOID did file come from pak? ! 653: ! 654: name = Cmd_Argv(1); ! 655: // hacked by zoid to allow more conrol over download ! 656: // first off, no .. or global allow check ! 657: if (strstr (name, "..") || !allow_download.value ! 658: // leading dot is no good ! 659: || *name == '.' ! 660: // leading slash bad as well, must be in subdir ! 661: || *name == '/' ! 662: // next up, skin check ! 663: || (strncmp(name, "skins/", 6) == 0 && !allow_download_skins.value) ! 664: // now models ! 665: || (strncmp(name, "progs/", 6) == 0 && !allow_download_models.value) ! 666: // now sounds ! 667: || (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds.value) ! 668: // now maps (note special case for maps, must not be in pak) ! 669: || (strncmp(name, "maps/", 6) == 0 && !allow_download_maps.value) ! 670: // MUST be in a subdirectory ! 671: || !strstr (name, "/") ) ! 672: { // don't allow anything with .. path ! 673: ClientReliableWrite_Begin (host_client, svc_download, 4); ! 674: ClientReliableWrite_Short (host_client, -1); ! 675: ClientReliableWrite_Byte (host_client, 0); ! 676: return; ! 677: } ! 678: ! 679: if (host_client->download) { ! 680: fclose (host_client->download); ! 681: host_client->download = NULL; ! 682: } ! 683: ! 684: // lowercase name (needed for casesen file systems) ! 685: { ! 686: char *p; ! 687: ! 688: for (p = name; *p; p++) ! 689: *p = (char)tolower(*p); ! 690: } ! 691: ! 692: ! 693: host_client->downloadsize = COM_FOpenFile (name, &host_client->download); ! 694: host_client->downloadcount = 0; ! 695: ! 696: if (!host_client->download ! 697: // special check for maps, if it came from a pak file, don't allow ! 698: // download ZOID ! 699: || (strncmp(name, "maps/", 5) == 0 && file_from_pak)) ! 700: { ! 701: if (host_client->download) { ! 702: fclose(host_client->download); ! 703: host_client->download = NULL; ! 704: } ! 705: ! 706: Sys_Printf ("Couldn't download %s to %s\n", name, host_client->name); ! 707: ClientReliableWrite_Begin (host_client, svc_download, 4); ! 708: ClientReliableWrite_Short (host_client, -1); ! 709: ClientReliableWrite_Byte (host_client, 0); ! 710: return; ! 711: } ! 712: ! 713: SV_NextDownload_f (); ! 714: Sys_Printf ("Downloading %s to %s\n", name, host_client->name); ! 715: } ! 716: ! 717: //============================================================================= ! 718: ! 719: /* ! 720: ================== ! 721: SV_Say ! 722: ================== ! 723: */ ! 724: void SV_Say (qboolean team) ! 725: { ! 726: client_t *client; ! 727: int j, tmp; ! 728: char *p; ! 729: char text[2048]; ! 730: char t1[32], *t2; ! 731: ! 732: if (Cmd_Argc () < 2) ! 733: return; ! 734: ! 735: if (team) ! 736: { ! 737: strncpy (t1, Info_ValueForKey (host_client->userinfo, "team"), 31); ! 738: t1[31] = 0; ! 739: } ! 740: ! 741: if (host_client->spectator && (!sv_spectalk.value || team)) ! 742: sprintf (text, "[SPEC] %s: ", host_client->name); ! 743: else if (team) ! 744: sprintf (text, "(%s): ", host_client->name); ! 745: else { ! 746: sprintf (text, "%s: ", host_client->name); ! 747: } ! 748: ! 749: if (fp_messages) { ! 750: if (!sv.paused && realtime<host_client->lockedtill) { ! 751: SV_ClientPrintf(host_client, PRINT_CHAT, ! 752: "You can't talk for %d more seconds\n", ! 753: (int) (host_client->lockedtill - realtime)); ! 754: return; ! 755: } ! 756: tmp = host_client->whensaidhead - fp_messages + 1; ! 757: if (tmp < 0) ! 758: tmp = 10+tmp; ! 759: if (!sv.paused && ! 760: host_client->whensaid[tmp] && (realtime-host_client->whensaid[tmp] < fp_persecond)) { ! 761: host_client->lockedtill = realtime + fp_secondsdead; ! 762: if (fp_msg[0]) ! 763: SV_ClientPrintf(host_client, PRINT_CHAT, ! 764: "FloodProt: %s\n", fp_msg); ! 765: else ! 766: SV_ClientPrintf(host_client, PRINT_CHAT, ! 767: "FloodProt: You can't talk for %d seconds.\n", fp_secondsdead); ! 768: return; ! 769: } ! 770: host_client->whensaidhead++; ! 771: if (host_client->whensaidhead > 9) ! 772: host_client->whensaidhead = 0; ! 773: host_client->whensaid[host_client->whensaidhead] = realtime; ! 774: } ! 775: ! 776: p = Cmd_Args(); ! 777: ! 778: if (*p == '"') ! 779: { ! 780: p++; ! 781: p[Q_strlen(p)-1] = 0; ! 782: } ! 783: ! 784: Q_strcat(text, p); ! 785: Q_strcat(text, "\n"); ! 786: ! 787: Sys_Printf ("%s", text); ! 788: ! 789: for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) ! 790: { ! 791: if (client->state != cs_spawned) ! 792: continue; ! 793: if (host_client->spectator && !sv_spectalk.value) ! 794: if (!client->spectator) ! 795: continue; ! 796: ! 797: if (team) ! 798: { ! 799: // the spectator team ! 800: if (host_client->spectator) { ! 801: if (!client->spectator) ! 802: continue; ! 803: } else { ! 804: t2 = Info_ValueForKey (client->userinfo, "team"); ! 805: if (strcmp(t1, t2) || client->spectator) ! 806: continue; // on different teams ! 807: } ! 808: } ! 809: SV_ClientPrintf(client, PRINT_CHAT, "%s", text); ! 810: } ! 811: } ! 812: ! 813: ! 814: /* ! 815: ================== ! 816: SV_Say_f ! 817: ================== ! 818: */ ! 819: void SV_Say_f(void) ! 820: { ! 821: SV_Say (false); ! 822: } ! 823: /* ! 824: ================== ! 825: SV_Say_Team_f ! 826: ================== ! 827: */ ! 828: void SV_Say_Team_f(void) ! 829: { ! 830: SV_Say (true); ! 831: } ! 832: ! 833: ! 834: ! 835: //============================================================================ ! 836: ! 837: /* ! 838: ================= ! 839: SV_Pings_f ! 840: ! 841: The client is showing the scoreboard, so send new ping times for all ! 842: clients ! 843: ================= ! 844: */ ! 845: void SV_Pings_f (void) ! 846: { ! 847: client_t *client; ! 848: int j; ! 849: ! 850: for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) ! 851: { ! 852: if (client->state != cs_spawned) ! 853: continue; ! 854: ! 855: ClientReliableWrite_Begin (host_client, svc_updateping, 4); ! 856: ClientReliableWrite_Byte (host_client, j); ! 857: ClientReliableWrite_Short (host_client, SV_CalcPing(client)); ! 858: ClientReliableWrite_Begin (host_client, svc_updatepl, 4); ! 859: ClientReliableWrite_Byte (host_client, j); ! 860: ClientReliableWrite_Byte (host_client, client->lossage); ! 861: } ! 862: } ! 863: ! 864: ! 865: ! 866: /* ! 867: ================== ! 868: SV_Kill_f ! 869: ================== ! 870: */ ! 871: void SV_Kill_f (void) ! 872: { ! 873: if (sv_player->v.health <= 0) ! 874: { ! 875: SV_ClientPrintf (host_client, PRINT_HIGH, "Can't suicide -- allready dead!\n"); ! 876: return; ! 877: } ! 878: ! 879: pr_global_struct->time = sv.time; ! 880: pr_global_struct->self = EDICT_TO_PROG(sv_player); ! 881: PR_ExecuteProgram (pr_global_struct->ClientKill); ! 882: } ! 883: ! 884: /* ! 885: ================== ! 886: SV_TogglePause ! 887: ================== ! 888: */ ! 889: void SV_TogglePause (const char *msg) ! 890: { ! 891: int i; ! 892: client_t *cl; ! 893: ! 894: sv.paused ^= 1; ! 895: ! 896: if (msg) ! 897: SV_BroadcastPrintf (PRINT_HIGH, "%s", msg); ! 898: ! 899: // send notification to all clients ! 900: for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++) ! 901: { ! 902: if (!cl->state) ! 903: continue; ! 904: ClientReliableWrite_Begin (cl, svc_setpause, 2); ! 905: ClientReliableWrite_Byte (cl, sv.paused); ! 906: } ! 907: } ! 908: ! 909: ! 910: /* ! 911: ================== ! 912: SV_Pause_f ! 913: ================== ! 914: */ ! 915: void SV_Pause_f (void) ! 916: { ! 917: int i; ! 918: client_t *cl; ! 919: char st[sizeof(host_client->name) + 32]; ! 920: ! 921: if (!pausable.value) { ! 922: SV_ClientPrintf (host_client, PRINT_HIGH, "Pause not allowed.\n"); ! 923: return; ! 924: } ! 925: ! 926: if (host_client->spectator) { ! 927: SV_ClientPrintf (host_client, PRINT_HIGH, "Spectators can not pause.\n"); ! 928: return; ! 929: } ! 930: ! 931: if (sv.paused) ! 932: sprintf (st, "%s paused the game\n", host_client->name); ! 933: else ! 934: sprintf (st, "%s unpaused the game\n", host_client->name); ! 935: ! 936: SV_TogglePause(st); ! 937: } ! 938: ! 939: ! 940: /* ! 941: ================= ! 942: SV_Drop_f ! 943: ! 944: The client is going to disconnect, so remove the connection immediately ! 945: ================= ! 946: */ ! 947: void SV_Drop_f (void) ! 948: { ! 949: SV_EndRedirect (); ! 950: if (!host_client->spectator) ! 951: SV_BroadcastPrintf (PRINT_HIGH, "%s dropped\n", host_client->name); ! 952: SV_DropClient (host_client); ! 953: } ! 954: ! 955: /* ! 956: ================= ! 957: SV_PTrack_f ! 958: ! 959: Change the bandwidth estimate for a client ! 960: ================= ! 961: */ ! 962: void SV_PTrack_f (void) ! 963: { ! 964: int i; ! 965: edict_t *ent, *tent; ! 966: ! 967: if (!host_client->spectator) ! 968: return; ! 969: ! 970: if (Cmd_Argc() != 2) ! 971: { ! 972: // turn off tracking ! 973: host_client->spec_track = 0; ! 974: ent = EDICT_NUM(host_client - svs.clients + 1); ! 975: tent = EDICT_NUM(0); ! 976: ent->v.goalentity = EDICT_TO_PROG(tent); ! 977: return; ! 978: } ! 979: ! 980: i = atoi(Cmd_Argv(1)); ! 981: if (i < 0 || i >= MAX_CLIENTS || svs.clients[i].state != cs_spawned || ! 982: svs.clients[i].spectator) { ! 983: SV_ClientPrintf (host_client, PRINT_HIGH, "Invalid client to track\n"); ! 984: host_client->spec_track = 0; ! 985: ent = EDICT_NUM(host_client - svs.clients + 1); ! 986: tent = EDICT_NUM(0); ! 987: ent->v.goalentity = EDICT_TO_PROG(tent); ! 988: return; ! 989: } ! 990: host_client->spec_track = i + 1; // now tracking ! 991: ! 992: ent = EDICT_NUM(host_client - svs.clients + 1); ! 993: tent = EDICT_NUM(i + 1); ! 994: ent->v.goalentity = EDICT_TO_PROG(tent); ! 995: } ! 996: ! 997: ! 998: /* ! 999: ================= ! 1000: SV_Rate_f ! 1001: ! 1002: Change the bandwidth estimate for a client ! 1003: ================= ! 1004: */ ! 1005: void SV_Rate_f (void) ! 1006: { ! 1007: int rate; ! 1008: ! 1009: if (Cmd_Argc() != 2) ! 1010: { ! 1011: SV_ClientPrintf (host_client, PRINT_HIGH, "Current rate is %i\n", ! 1012: (int)(1.0/host_client->netchan.rate + 0.5)); ! 1013: return; ! 1014: } ! 1015: ! 1016: rate = atoi(Cmd_Argv(1)); ! 1017: if (rate < 500) ! 1018: rate = 500; ! 1019: if (rate > 10000) ! 1020: rate = 10000; ! 1021: ! 1022: SV_ClientPrintf (host_client, PRINT_HIGH, "Net rate set to %i\n", rate); ! 1023: host_client->netchan.rate = 1.0/rate; ! 1024: } ! 1025: ! 1026: ! 1027: /* ! 1028: ================= ! 1029: SV_Msg_f ! 1030: ! 1031: Change the message level for a client ! 1032: ================= ! 1033: */ ! 1034: void SV_Msg_f (void) ! 1035: { ! 1036: if (Cmd_Argc() != 2) ! 1037: { ! 1038: SV_ClientPrintf (host_client, PRINT_HIGH, "Current msg level is %i\n", ! 1039: host_client->messagelevel); ! 1040: return; ! 1041: } ! 1042: ! 1043: host_client->messagelevel = atoi(Cmd_Argv(1)); ! 1044: ! 1045: SV_ClientPrintf (host_client, PRINT_HIGH, "Msg level set to %i\n", host_client->messagelevel); ! 1046: } ! 1047: ! 1048: /* ! 1049: ================== ! 1050: SV_SetInfo_f ! 1051: ! 1052: Allow clients to change userinfo ! 1053: ================== ! 1054: */ ! 1055: void SV_SetInfo_f (void) ! 1056: { ! 1057: int i; ! 1058: char oldval[MAX_INFO_STRING]; ! 1059: ! 1060: ! 1061: if (Cmd_Argc() == 1) ! 1062: { ! 1063: Con_Printf ("User info settings:\n"); ! 1064: Info_Print (host_client->userinfo); ! 1065: return; ! 1066: } ! 1067: ! 1068: if (Cmd_Argc() != 3) ! 1069: { ! 1070: Con_Printf ("usage: setinfo [ <key> <value> ]\n"); ! 1071: return; ! 1072: } ! 1073: ! 1074: if (Cmd_Argv(1)[0] == '*') ! 1075: return; // don't set priveledged values ! 1076: ! 1077: strcpy(oldval, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1))); ! 1078: ! 1079: Info_SetValueForKey (host_client->userinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING); ! 1080: // name is extracted below in ExtractFromUserInfo ! 1081: // strncpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name") ! 1082: // , sizeof(host_client->name)-1); ! 1083: // SV_FullClientUpdate (host_client, &sv.reliable_datagram); ! 1084: // host_client->sendinfo = true; ! 1085: ! 1086: if (!strcmp(Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)), oldval)) ! 1087: return; // key hasn't changed ! 1088: ! 1089: // process any changed values ! 1090: SV_ExtractFromUserinfo (host_client); ! 1091: ! 1092: i = host_client - svs.clients; ! 1093: MSG_WriteByte (&sv.reliable_datagram, svc_setinfo); ! 1094: MSG_WriteByte (&sv.reliable_datagram, i); ! 1095: MSG_WriteString (&sv.reliable_datagram, Cmd_Argv(1)); ! 1096: MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1))); ! 1097: } ! 1098: ! 1099: /* ! 1100: ================== ! 1101: SV_ShowServerinfo_f ! 1102: ! 1103: Dumps the serverinfo info string ! 1104: ================== ! 1105: */ ! 1106: void SV_ShowServerinfo_f (void) ! 1107: { ! 1108: Info_Print (svs.info); ! 1109: } ! 1110: ! 1111: void SV_NoSnap_f(void) ! 1112: { ! 1113: if (*host_client->uploadfn) { ! 1114: *host_client->uploadfn = 0; ! 1115: SV_BroadcastPrintf (PRINT_HIGH, "%s refused remote screenshot\n", host_client->name); ! 1116: } ! 1117: } ! 1118: ! 1119: typedef struct ! 1120: { ! 1121: char *name; ! 1122: void (*func) (void); ! 1123: } ucmd_t; ! 1124: ! 1125: ucmd_t ucmds[] = ! 1126: { ! 1127: {"new", SV_New_f}, ! 1128: {"modellist", SV_Modellist_f}, ! 1129: {"soundlist", SV_Soundlist_f}, ! 1130: {"prespawn", SV_PreSpawn_f}, ! 1131: {"spawn", SV_Spawn_f}, ! 1132: {"begin", SV_Begin_f}, ! 1133: ! 1134: {"drop", SV_Drop_f}, ! 1135: {"pings", SV_Pings_f}, ! 1136: ! 1137: // issued by hand at client consoles ! 1138: {"rate", SV_Rate_f}, ! 1139: {"kill", SV_Kill_f}, ! 1140: {"pause", SV_Pause_f}, ! 1141: {"msg", SV_Msg_f}, ! 1142: ! 1143: {"say", SV_Say_f}, ! 1144: {"say_team", SV_Say_Team_f}, ! 1145: ! 1146: {"setinfo", SV_SetInfo_f}, ! 1147: ! 1148: {"serverinfo", SV_ShowServerinfo_f}, ! 1149: ! 1150: {"download", SV_BeginDownload_f}, ! 1151: {"nextdl", SV_NextDownload_f}, ! 1152: ! 1153: {"ptrack", SV_PTrack_f}, //ZOID - used with autocam ! 1154: ! 1155: {"snap", SV_NoSnap_f}, ! 1156: ! 1157: {NULL, NULL} ! 1158: }; ! 1159: ! 1160: /* ! 1161: ================== ! 1162: SV_ExecuteUserCommand ! 1163: ================== ! 1164: */ ! 1165: void SV_ExecuteUserCommand (char *s) ! 1166: { ! 1167: ucmd_t *u; ! 1168: ! 1169: Cmd_TokenizeString (s); ! 1170: sv_player = host_client->edict; ! 1171: ! 1172: SV_BeginRedirect (RD_CLIENT); ! 1173: ! 1174: for (u=ucmds ; u->name ; u++) ! 1175: if (!strcmp (Cmd_Argv(0), u->name) ) ! 1176: { ! 1177: u->func (); ! 1178: break; ! 1179: } ! 1180: ! 1181: if (!u->name) ! 1182: Con_Printf ("Bad user command: %s\n", Cmd_Argv(0)); ! 1183: ! 1184: SV_EndRedirect (); ! 1185: } ! 1186: ! 1187: /* ! 1188: =========================================================================== ! 1189: ! 1190: USER CMD EXECUTION ! 1191: ! 1192: =========================================================================== ! 1193: */ ! 1194: ! 1195: /* ! 1196: =============== ! 1197: V_CalcRoll ! 1198: ! 1199: Used by view and sv_user ! 1200: =============== ! 1201: */ ! 1202: float V_CalcRoll (vec3_t angles, vec3_t velocity) ! 1203: { ! 1204: vec3_t forward, right, up; ! 1205: float sign; ! 1206: float side; ! 1207: float value; ! 1208: ! 1209: AngleVectors (angles, forward, right, up); ! 1210: side = DotProduct (velocity, right); ! 1211: sign = side < 0 ? -1 : 1; ! 1212: side = fabs(side); ! 1213: ! 1214: value = cl_rollangle.value; ! 1215: ! 1216: if (side < cl_rollspeed.value) ! 1217: side = side * value / cl_rollspeed.value; ! 1218: else ! 1219: side = value; ! 1220: ! 1221: return side*sign; ! 1222: ! 1223: } ! 1224: ! 1225: ! 1226: ! 1227: ! 1228: //============================================================================ ! 1229: ! 1230: vec3_t pmove_mins, pmove_maxs; ! 1231: ! 1232: /* ! 1233: ==================== ! 1234: AddLinksToPmove ! 1235: ! 1236: ==================== ! 1237: */ ! 1238: void AddLinksToPmove ( areanode_t *node ) ! 1239: { ! 1240: link_t *l, *next; ! 1241: edict_t *check; ! 1242: int pl; ! 1243: int i; ! 1244: physent_t *pe; ! 1245: ! 1246: pl = EDICT_TO_PROG(sv_player); ! 1247: ! 1248: // touch linked edicts ! 1249: for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next) ! 1250: { ! 1251: next = l->next; ! 1252: check = EDICT_FROM_AREA(l); ! 1253: ! 1254: if (check->v.owner == pl) ! 1255: continue; // player's own missile ! 1256: if (check->v.solid == SOLID_BSP ! 1257: || check->v.solid == SOLID_BBOX ! 1258: || check->v.solid == SOLID_SLIDEBOX) ! 1259: { ! 1260: if (check == sv_player) ! 1261: continue; ! 1262: ! 1263: for (i=0 ; i<3 ; i++) ! 1264: if (check->v.absmin[i] > pmove_maxs[i] ! 1265: || check->v.absmax[i] < pmove_mins[i]) ! 1266: break; ! 1267: if (i != 3) ! 1268: continue; ! 1269: if (pmove.numphysent == MAX_PHYSENTS) ! 1270: return; ! 1271: pe = &pmove.physents[pmove.numphysent]; ! 1272: pmove.numphysent++; ! 1273: ! 1274: VectorCopy (check->v.origin, pe->origin); ! 1275: pe->info = NUM_FOR_EDICT(check); ! 1276: if (check->v.solid == SOLID_BSP) ! 1277: pe->model = sv.models[(int)(check->v.modelindex)]; ! 1278: else ! 1279: { ! 1280: pe->model = NULL; ! 1281: VectorCopy (check->v.mins, pe->mins); ! 1282: VectorCopy (check->v.maxs, pe->maxs); ! 1283: } ! 1284: } ! 1285: } ! 1286: ! 1287: // recurse down both sides ! 1288: if (node->axis == -1) ! 1289: return; ! 1290: ! 1291: if ( pmove_maxs[node->axis] > node->dist ) ! 1292: AddLinksToPmove ( node->children[0] ); ! 1293: if ( pmove_mins[node->axis] < node->dist ) ! 1294: AddLinksToPmove ( node->children[1] ); ! 1295: } ! 1296: ! 1297: ! 1298: /* ! 1299: ================ ! 1300: AddAllEntsToPmove ! 1301: ! 1302: For debugging ! 1303: ================ ! 1304: */ ! 1305: void AddAllEntsToPmove (void) ! 1306: { ! 1307: int e; ! 1308: edict_t *check; ! 1309: int i; ! 1310: physent_t *pe; ! 1311: int pl; ! 1312: ! 1313: pl = EDICT_TO_PROG(sv_player); ! 1314: check = NEXT_EDICT(sv.edicts); ! 1315: for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check)) ! 1316: { ! 1317: if (check->free) ! 1318: continue; ! 1319: if (check->v.owner == pl) ! 1320: continue; ! 1321: if (check->v.solid == SOLID_BSP ! 1322: || check->v.solid == SOLID_BBOX ! 1323: || check->v.solid == SOLID_SLIDEBOX) ! 1324: { ! 1325: if (check == sv_player) ! 1326: continue; ! 1327: ! 1328: for (i=0 ; i<3 ; i++) ! 1329: if (check->v.absmin[i] > pmove_maxs[i] ! 1330: || check->v.absmax[i] < pmove_mins[i]) ! 1331: break; ! 1332: if (i != 3) ! 1333: continue; ! 1334: pe = &pmove.physents[pmove.numphysent]; ! 1335: ! 1336: VectorCopy (check->v.origin, pe->origin); ! 1337: pmove.physents[pmove.numphysent].info = e; ! 1338: if (check->v.solid == SOLID_BSP) ! 1339: pe->model = sv.models[(int)(check->v.modelindex)]; ! 1340: else ! 1341: { ! 1342: pe->model = NULL; ! 1343: VectorCopy (check->v.mins, pe->mins); ! 1344: VectorCopy (check->v.maxs, pe->maxs); ! 1345: } ! 1346: ! 1347: if (++pmove.numphysent == MAX_PHYSENTS) ! 1348: break; ! 1349: } ! 1350: } ! 1351: } ! 1352: ! 1353: /* ! 1354: =========== ! 1355: SV_PreRunCmd ! 1356: =========== ! 1357: Done before running a player command. Clears the touch array ! 1358: */ ! 1359: byte playertouch[(MAX_EDICTS+7)/8]; ! 1360: ! 1361: void SV_PreRunCmd(void) ! 1362: { ! 1363: memset(playertouch, 0, sizeof(playertouch)); ! 1364: } ! 1365: ! 1366: /* ! 1367: =========== ! 1368: SV_RunCmd ! 1369: =========== ! 1370: */ ! 1371: void SV_RunCmd (usercmd_t *ucmd) ! 1372: { ! 1373: edict_t *ent; ! 1374: int i, n; ! 1375: int oldmsec; ! 1376: ! 1377: cmd = *ucmd; ! 1378: ! 1379: // chop up very long commands ! 1380: if (cmd.msec > 50) ! 1381: { ! 1382: oldmsec = ucmd->msec; ! 1383: cmd.msec = oldmsec/2; ! 1384: SV_RunCmd (&cmd); ! 1385: cmd.msec = oldmsec/2; ! 1386: cmd.impulse = 0; ! 1387: SV_RunCmd (&cmd); ! 1388: return; ! 1389: } ! 1390: ! 1391: if (!sv_player->v.fixangle) ! 1392: VectorCopy (ucmd->angles, sv_player->v.v_angle); ! 1393: ! 1394: sv_player->v.button0 = ucmd->buttons & 1; ! 1395: sv_player->v.button2 = (ucmd->buttons & 2)>>1; ! 1396: if (ucmd->impulse) ! 1397: sv_player->v.impulse = ucmd->impulse; ! 1398: ! 1399: // ! 1400: // angles ! 1401: // show 1/3 the pitch angle and all the roll angle ! 1402: if (sv_player->v.health > 0) ! 1403: { ! 1404: if (!sv_player->v.fixangle) ! 1405: { ! 1406: sv_player->v.angles[PITCH] = -sv_player->v.v_angle[PITCH]/3; ! 1407: sv_player->v.angles[YAW] = sv_player->v.v_angle[YAW]; ! 1408: } ! 1409: sv_player->v.angles[ROLL] = ! 1410: V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4; ! 1411: } ! 1412: ! 1413: host_frametime = ucmd->msec * 0.001; ! 1414: if (host_frametime > 0.1) ! 1415: host_frametime = 0.1; ! 1416: ! 1417: if (!host_client->spectator) ! 1418: { ! 1419: pr_global_struct->frametime = host_frametime; ! 1420: ! 1421: pr_global_struct->time = sv.time; ! 1422: pr_global_struct->self = EDICT_TO_PROG(sv_player); ! 1423: PR_ExecuteProgram (pr_global_struct->PlayerPreThink); ! 1424: ! 1425: SV_RunThink (sv_player); ! 1426: } ! 1427: ! 1428: for (i=0 ; i<3 ; i++) ! 1429: pmove.origin[i] = sv_player->v.origin[i] + (sv_player->v.mins[i] - player_mins[i]); ! 1430: VectorCopy (sv_player->v.velocity, pmove.velocity); ! 1431: VectorCopy (sv_player->v.v_angle, pmove.angles); ! 1432: ! 1433: pmove.spectator = host_client->spectator; ! 1434: pmove.waterjumptime = sv_player->v.teleport_time; ! 1435: pmove.numphysent = 1; ! 1436: pmove.physents[0].model = sv.worldmodel; ! 1437: pmove.cmd = *ucmd; ! 1438: pmove.dead = sv_player->v.health <= 0; ! 1439: pmove.oldbuttons = host_client->oldbuttons; ! 1440: ! 1441: movevars.entgravity = host_client->entgravity; ! 1442: movevars.maxspeed = host_client->maxspeed; ! 1443: ! 1444: for (i=0 ; i<3 ; i++) ! 1445: { ! 1446: pmove_mins[i] = pmove.origin[i] - 256; ! 1447: pmove_maxs[i] = pmove.origin[i] + 256; ! 1448: } ! 1449: #if 1 ! 1450: AddLinksToPmove ( sv_areanodes ); ! 1451: #else ! 1452: AddAllEntsToPmove (); ! 1453: #endif ! 1454: ! 1455: #if 0 ! 1456: { ! 1457: int before, after; ! 1458: ! 1459: before = PM_TestPlayerPosition (pmove.origin); ! 1460: PlayerMove (); ! 1461: after = PM_TestPlayerPosition (pmove.origin); ! 1462: ! 1463: if (sv_player->v.health > 0 && before && !after ) ! 1464: Con_Printf ("player %s got stuck in playermove!!!!\n", host_client->name); ! 1465: } ! 1466: #else ! 1467: PlayerMove (); ! 1468: #endif ! 1469: ! 1470: host_client->oldbuttons = pmove.oldbuttons; ! 1471: sv_player->v.teleport_time = pmove.waterjumptime; ! 1472: sv_player->v.waterlevel = waterlevel; ! 1473: sv_player->v.watertype = watertype; ! 1474: if (onground != -1) ! 1475: { ! 1476: sv_player->v.flags = (int)sv_player->v.flags | FL_ONGROUND; ! 1477: sv_player->v.groundentity = EDICT_TO_PROG(EDICT_NUM(pmove.physents[onground].info)); ! 1478: } ! 1479: else ! 1480: sv_player->v.flags = (int)sv_player->v.flags & ~FL_ONGROUND; ! 1481: for (i=0 ; i<3 ; i++) ! 1482: sv_player->v.origin[i] = pmove.origin[i] - (sv_player->v.mins[i] - player_mins[i]); ! 1483: ! 1484: #if 0 ! 1485: // truncate velocity the same way the net protocol will ! 1486: for (i=0 ; i<3 ; i++) ! 1487: sv_player->v.velocity[i] = (int)pmove.velocity[i]; ! 1488: #else ! 1489: VectorCopy (pmove.velocity, sv_player->v.velocity); ! 1490: #endif ! 1491: ! 1492: VectorCopy (pmove.angles, sv_player->v.v_angle); ! 1493: ! 1494: if (!host_client->spectator) ! 1495: { ! 1496: // link into place and touch triggers ! 1497: SV_LinkEdict (sv_player, true); ! 1498: ! 1499: // touch other objects ! 1500: for (i=0 ; i<pmove.numtouch ; i++) ! 1501: { ! 1502: n = pmove.physents[pmove.touchindex[i]].info; ! 1503: ent = EDICT_NUM(n); ! 1504: if (!ent->v.touch || (playertouch[n/8]&(1<<(n%8)))) ! 1505: continue; ! 1506: pr_global_struct->self = EDICT_TO_PROG(ent); ! 1507: pr_global_struct->other = EDICT_TO_PROG(sv_player); ! 1508: PR_ExecuteProgram (ent->v.touch); ! 1509: playertouch[n/8] |= 1 << (n%8); ! 1510: } ! 1511: } ! 1512: } ! 1513: ! 1514: /* ! 1515: =========== ! 1516: SV_PostRunCmd ! 1517: =========== ! 1518: Done after running a player command. ! 1519: */ ! 1520: void SV_PostRunCmd(void) ! 1521: { ! 1522: // run post-think ! 1523: ! 1524: if (!host_client->spectator) { ! 1525: pr_global_struct->time = sv.time; ! 1526: pr_global_struct->self = EDICT_TO_PROG(sv_player); ! 1527: PR_ExecuteProgram (pr_global_struct->PlayerPostThink); ! 1528: SV_RunNewmis (); ! 1529: } else if (SpectatorThink) { ! 1530: pr_global_struct->time = sv.time; ! 1531: pr_global_struct->self = EDICT_TO_PROG(sv_player); ! 1532: PR_ExecuteProgram (SpectatorThink); ! 1533: } ! 1534: } ! 1535: ! 1536: ! 1537: /* ! 1538: =================== ! 1539: SV_ExecuteClientMessage ! 1540: ! 1541: The current net_message is parsed for the given client ! 1542: =================== ! 1543: */ ! 1544: void SV_ExecuteClientMessage (client_t *cl) ! 1545: { ! 1546: int c; ! 1547: char *s; ! 1548: usercmd_t oldest, oldcmd, newcmd; ! 1549: client_frame_t *frame; ! 1550: vec3_t o; ! 1551: qboolean move_issued = false; //only allow one move command ! 1552: int checksumIndex; ! 1553: byte checksum, calculatedChecksum; ! 1554: int seq_hash; ! 1555: ! 1556: // calc ping time ! 1557: frame = &cl->frames[cl->netchan.incoming_acknowledged & UPDATE_MASK]; ! 1558: frame->ping_time = realtime - frame->senttime; ! 1559: ! 1560: // make sure the reply sequence number matches the incoming ! 1561: // sequence number ! 1562: if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence) ! 1563: cl->netchan.outgoing_sequence = cl->netchan.incoming_sequence; ! 1564: else ! 1565: cl->send_message = false; // don't reply, sequences have slipped ! 1566: ! 1567: // save time for ping calculations ! 1568: cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime; ! 1569: cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1; ! 1570: ! 1571: host_client = cl; ! 1572: sv_player = host_client->edict; ! 1573: ! 1574: // seq_hash = (cl->netchan.incoming_sequence & 0xffff) ; // ^ QW_CHECK_HASH; ! 1575: seq_hash = cl->netchan.incoming_sequence; ! 1576: ! 1577: // mark time so clients will know how much to predict ! 1578: // other players ! 1579: cl->localtime = sv.time; ! 1580: cl->delta_sequence = -1; // no delta unless requested ! 1581: while (1) ! 1582: { ! 1583: if (msg_badread) ! 1584: { ! 1585: Con_Printf ("SV_ReadClientMessage: badread\n"); ! 1586: SV_DropClient (cl); ! 1587: return; ! 1588: } ! 1589: ! 1590: c = MSG_ReadByte (); ! 1591: if (c == -1) ! 1592: break; ! 1593: ! 1594: switch (c) ! 1595: { ! 1596: default: ! 1597: Con_Printf ("SV_ReadClientMessage: unknown command char\n"); ! 1598: SV_DropClient (cl); ! 1599: return; ! 1600: ! 1601: case clc_nop: ! 1602: break; ! 1603: ! 1604: case clc_delta: ! 1605: cl->delta_sequence = MSG_ReadByte (); ! 1606: break; ! 1607: ! 1608: case clc_move: ! 1609: if (move_issued) ! 1610: return; // someone is trying to cheat... ! 1611: ! 1612: move_issued = true; ! 1613: ! 1614: checksumIndex = MSG_GetReadCount(); ! 1615: checksum = (byte)MSG_ReadByte (); ! 1616: ! 1617: // read loss percentage ! 1618: cl->lossage = MSG_ReadByte(); ! 1619: ! 1620: MSG_ReadDeltaUsercmd (&nullcmd, &oldest); ! 1621: MSG_ReadDeltaUsercmd (&oldest, &oldcmd); ! 1622: MSG_ReadDeltaUsercmd (&oldcmd, &newcmd); ! 1623: ! 1624: if ( cl->state != cs_spawned ) ! 1625: break; ! 1626: ! 1627: // if the checksum fails, ignore the rest of the packet ! 1628: calculatedChecksum = COM_BlockSequenceCRCByte( ! 1629: net_message.data + checksumIndex + 1, ! 1630: MSG_GetReadCount() - checksumIndex - 1, ! 1631: seq_hash); ! 1632: ! 1633: if (calculatedChecksum != checksum) ! 1634: { ! 1635: Con_DPrintf ("Failed command checksum for %s(%d) (%d != %d)\n", ! 1636: cl->name, cl->netchan.incoming_sequence, checksum, calculatedChecksum); ! 1637: return; ! 1638: } ! 1639: ! 1640: if (!sv.paused) { ! 1641: SV_PreRunCmd(); ! 1642: ! 1643: if (net_drop < 20) ! 1644: { ! 1645: while (net_drop > 2) ! 1646: { ! 1647: SV_RunCmd (&cl->lastcmd); ! 1648: net_drop--; ! 1649: } ! 1650: if (net_drop > 1) ! 1651: SV_RunCmd (&oldest); ! 1652: if (net_drop > 0) ! 1653: SV_RunCmd (&oldcmd); ! 1654: } ! 1655: SV_RunCmd (&newcmd); ! 1656: ! 1657: SV_PostRunCmd(); ! 1658: } ! 1659: ! 1660: cl->lastcmd = newcmd; ! 1661: cl->lastcmd.buttons = 0; // avoid multiple fires on lag ! 1662: break; ! 1663: ! 1664: ! 1665: case clc_stringcmd: ! 1666: s = MSG_ReadString (); ! 1667: SV_ExecuteUserCommand (s); ! 1668: break; ! 1669: ! 1670: case clc_tmove: ! 1671: o[0] = MSG_ReadCoord(); ! 1672: o[1] = MSG_ReadCoord(); ! 1673: o[2] = MSG_ReadCoord(); ! 1674: // only allowed by spectators ! 1675: if (host_client->spectator) { ! 1676: VectorCopy(o, sv_player->v.origin); ! 1677: SV_LinkEdict(sv_player, false); ! 1678: } ! 1679: break; ! 1680: ! 1681: case clc_upload: ! 1682: SV_NextUpload(); ! 1683: break; ! 1684: ! 1685: } ! 1686: } ! 1687: } ! 1688: ! 1689: /* ! 1690: ============== ! 1691: SV_UserInit ! 1692: ============== ! 1693: */ ! 1694: void SV_UserInit (void) ! 1695: { ! 1696: Cvar_RegisterVariable (&cl_rollspeed); ! 1697: Cvar_RegisterVariable (&cl_rollangle); ! 1698: Cvar_RegisterVariable (&sv_spectalk); ! 1699: Cvar_RegisterVariable (&sv_mapcheck); ! 1700: } ! 1701: ! 1702:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.