|
|
1.1 ! root 1: // sv_main.c -- server main program ! 2: ! 3: #include "server.h" ! 4: ! 5: /* ! 6: ============================================================================= ! 7: ! 8: Com_Printf redirection ! 9: ! 10: ============================================================================= ! 11: */ ! 12: ! 13: char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; ! 14: ! 15: void SV_FlushRedirect (int sv_redirected, char *outputbuf) ! 16: { ! 17: if (sv_redirected == RD_PACKET) ! 18: { ! 19: Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", outputbuf); ! 20: } ! 21: else if (sv_redirected == RD_CLIENT) ! 22: { ! 23: MSG_WriteByte (&sv_client->netchan.message, svc_print); ! 24: MSG_WriteByte (&sv_client->netchan.message, PRINT_HIGH); ! 25: MSG_WriteString (&sv_client->netchan.message, outputbuf); ! 26: } ! 27: } ! 28: ! 29: ! 30: /* ! 31: ============================================================================= ! 32: ! 33: EVENT MESSAGES ! 34: ! 35: ============================================================================= ! 36: */ ! 37: ! 38: ! 39: /* ! 40: ================= ! 41: SV_ClientPrintf ! 42: ! 43: Sends text across to be displayed if the level passes ! 44: ================= ! 45: */ ! 46: void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...) ! 47: { ! 48: va_list argptr; ! 49: char string[1024]; ! 50: ! 51: if (level < cl->messagelevel) ! 52: return; ! 53: ! 54: va_start (argptr,fmt); ! 55: vsprintf (string, fmt,argptr); ! 56: va_end (argptr); ! 57: ! 58: MSG_WriteByte (&cl->netchan.message, svc_print); ! 59: MSG_WriteByte (&cl->netchan.message, level); ! 60: MSG_WriteString (&cl->netchan.message, string); ! 61: } ! 62: ! 63: /* ! 64: ================= ! 65: SV_BroadcastPrintf ! 66: ! 67: Sends text to all active clients ! 68: ================= ! 69: */ ! 70: void SV_BroadcastPrintf (int level, char *fmt, ...) ! 71: { ! 72: va_list argptr; ! 73: char string[2048]; ! 74: client_t *cl; ! 75: int i; ! 76: ! 77: va_start (argptr,fmt); ! 78: vsprintf (string, fmt,argptr); ! 79: va_end (argptr); ! 80: ! 81: // echo to console ! 82: if (dedicated->value) ! 83: { ! 84: char copy[1024]; ! 85: int i; ! 86: ! 87: // mask off high bits ! 88: for (i=0 ; i<1023 && string[i] ; i++) ! 89: copy[i] = string[i]&127; ! 90: copy[i] = 0; ! 91: Com_Printf ("%s", copy); ! 92: } ! 93: ! 94: for (i=0, cl = svs.clients ; i<maxclients->value; i++, cl++) ! 95: { ! 96: if (level < cl->messagelevel) ! 97: continue; ! 98: if (cl->state != cs_spawned) ! 99: continue; ! 100: MSG_WriteByte (&cl->netchan.message, svc_print); ! 101: MSG_WriteByte (&cl->netchan.message, level); ! 102: MSG_WriteString (&cl->netchan.message, string); ! 103: } ! 104: } ! 105: ! 106: /* ! 107: ================= ! 108: SV_BroadcastCommand ! 109: ! 110: Sends text to all active clients ! 111: ================= ! 112: */ ! 113: void SV_BroadcastCommand (char *fmt, ...) ! 114: { ! 115: va_list argptr; ! 116: char string[1024]; ! 117: ! 118: if (!sv.state) ! 119: return; ! 120: va_start (argptr,fmt); ! 121: vsprintf (string, fmt,argptr); ! 122: va_end (argptr); ! 123: ! 124: MSG_WriteByte (&sv.multicast, svc_stufftext); ! 125: MSG_WriteString (&sv.multicast, string); ! 126: SV_Multicast (NULL, MULTICAST_ALL_R); ! 127: } ! 128: ! 129: ! 130: /* ! 131: ================= ! 132: SV_Multicast ! 133: ! 134: Sends the contents of sv.multicast to a subset of the clients, ! 135: then clears sv.multicast. ! 136: ! 137: MULTICAST_ALL same as broadcast (origin can be NULL) ! 138: MULTICAST_PVS send to clients potentially visible from org ! 139: MULTICAST_PHS send to clients potentially hearable from org ! 140: ================= ! 141: */ ! 142: void SV_Multicast (vec3_t origin, multicast_t to) ! 143: { ! 144: client_t *client; ! 145: byte *mask; ! 146: int leafnum, cluster; ! 147: int j; ! 148: qboolean reliable; ! 149: int area1, area2; ! 150: ! 151: reliable = false; ! 152: ! 153: if (to != MULTICAST_ALL_R && to != MULTICAST_ALL) ! 154: { ! 155: leafnum = CM_PointLeafnum (origin); ! 156: area1 = CM_LeafArea (leafnum); ! 157: } ! 158: else ! 159: { ! 160: leafnum = 0; // just to avoid compiler warnings ! 161: area1 = 0; ! 162: } ! 163: ! 164: // if doing a serverrecord, store everything ! 165: if (svs.demofile) ! 166: SZ_Write (&svs.demo_multicast, sv.multicast.data, sv.multicast.cursize); ! 167: ! 168: switch (to) ! 169: { ! 170: case MULTICAST_ALL_R: ! 171: reliable = true; // intentional fallthrough ! 172: case MULTICAST_ALL: ! 173: leafnum = 0; ! 174: mask = NULL; ! 175: break; ! 176: ! 177: case MULTICAST_PHS_R: ! 178: reliable = true; // intentional fallthrough ! 179: case MULTICAST_PHS: ! 180: leafnum = CM_PointLeafnum (origin); ! 181: cluster = CM_LeafCluster (leafnum); ! 182: mask = CM_ClusterPHS (cluster); ! 183: break; ! 184: ! 185: case MULTICAST_PVS_R: ! 186: reliable = true; // intentional fallthrough ! 187: case MULTICAST_PVS: ! 188: leafnum = CM_PointLeafnum (origin); ! 189: cluster = CM_LeafCluster (leafnum); ! 190: mask = CM_ClusterPVS (cluster); ! 191: break; ! 192: ! 193: default: ! 194: mask = NULL; ! 195: Com_Error (ERR_FATAL, "SV_Multicast: bad to:%i", to); ! 196: } ! 197: ! 198: // send the data to all relevent clients ! 199: for (j = 0, client = svs.clients; j < maxclients->value; j++, client++) ! 200: { ! 201: if (client->state == cs_free || client->state == cs_zombie) ! 202: continue; ! 203: if (client->state != cs_spawned && !reliable) ! 204: continue; ! 205: ! 206: if (mask) ! 207: { ! 208: leafnum = CM_PointLeafnum (client->edict->s.origin); ! 209: cluster = CM_LeafCluster (leafnum); ! 210: area2 = CM_LeafArea (leafnum); ! 211: if (!CM_AreasConnected (area1, area2)) ! 212: continue; ! 213: if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) ) ! 214: continue; ! 215: } ! 216: ! 217: if (reliable) ! 218: SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize); ! 219: else ! 220: SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize); ! 221: } ! 222: ! 223: SZ_Clear (&sv.multicast); ! 224: } ! 225: ! 226: ! 227: /* ! 228: ================== ! 229: SV_StartSound ! 230: ! 231: Each entity can have eight independant sound sources, like voice, ! 232: weapon, feet, etc. ! 233: ! 234: If cahnnel & 8, the sound will be sent to everyone, not just ! 235: things in the PHS. ! 236: ! 237: FIXME: if entity isn't in PHS, they must be forced to be sent or ! 238: have the origin explicitly sent. ! 239: ! 240: Channel 0 is an auto-allocate channel, the others override anything ! 241: already running on that entity/channel pair. ! 242: ! 243: An attenuation of 0 will play full volume everywhere in the level. ! 244: Larger attenuations will drop off. (max 4 attenuation) ! 245: ! 246: Timeofs can range from 0.0 to 0.1 to cause sounds to be started ! 247: later in the frame than they normally would. ! 248: ! 249: If origin is NULL, the origin is determined from the entity origin ! 250: or the midpoint of the entity box for bmodels. ! 251: ================== ! 252: */ ! 253: void SV_StartSound (vec3_t origin, edict_t *entity, int channel, ! 254: int soundindex, float volume, ! 255: float attenuation, float timeofs) ! 256: { ! 257: int sendchan; ! 258: int flags; ! 259: int i; ! 260: int ent; ! 261: vec3_t origin_v; ! 262: qboolean use_phs; ! 263: ! 264: if (volume < 0 || volume > 1.0) ! 265: Com_Error (ERR_FATAL, "SV_StartSound: volume = %f", volume); ! 266: ! 267: if (attenuation < 0 || attenuation > 4) ! 268: Com_Error (ERR_FATAL, "SV_StartSound: attenuation = %f", attenuation); ! 269: ! 270: // if (channel < 0 || channel > 15) ! 271: // Com_Error (ERR_FATAL, "SV_StartSound: channel = %i", channel); ! 272: ! 273: if (timeofs < 0 || timeofs > 0.255) ! 274: Com_Error (ERR_FATAL, "SV_StartSound: timeofs = %f", timeofs); ! 275: ! 276: ent = NUM_FOR_EDICT(entity); ! 277: ! 278: if (channel & 8) // no PHS flag ! 279: { ! 280: use_phs = false; ! 281: channel &= 7; ! 282: } ! 283: else ! 284: use_phs = true; ! 285: ! 286: sendchan = (ent<<3) | (channel&7); ! 287: ! 288: flags = 0; ! 289: if (volume != DEFAULT_SOUND_PACKET_VOLUME) ! 290: flags |= SND_VOLUME; ! 291: if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) ! 292: flags |= SND_ATTENUATION; ! 293: ! 294: // the client doesn't know that bmodels have weird origins ! 295: // the origin can also be explicitly set ! 296: if ( (entity->svflags & SVF_NOCLIENT) ! 297: || (entity->solid == SOLID_BSP) ! 298: || origin ) ! 299: flags |= SND_POS; ! 300: ! 301: // always send the entity number for channel overrides ! 302: flags |= SND_ENT; ! 303: ! 304: if (timeofs) ! 305: flags |= SND_OFFSET; ! 306: ! 307: // use the entity origin unless it is a bmodel or explicitly specified ! 308: if (!origin) ! 309: { ! 310: origin = origin_v; ! 311: if (entity->solid == SOLID_BSP) ! 312: { ! 313: for (i=0 ; i<3 ; i++) ! 314: origin_v[i] = entity->s.origin[i]+0.5*(entity->mins[i]+entity->maxs[i]); ! 315: } ! 316: else ! 317: { ! 318: VectorCopy (entity->s.origin, origin_v); ! 319: } ! 320: } ! 321: ! 322: MSG_WriteByte (&sv.multicast, svc_sound); ! 323: MSG_WriteByte (&sv.multicast, flags); ! 324: MSG_WriteByte (&sv.multicast, soundindex); ! 325: ! 326: if (flags & SND_VOLUME) ! 327: MSG_WriteByte (&sv.multicast, volume*255); ! 328: if (flags & SND_ATTENUATION) ! 329: MSG_WriteByte (&sv.multicast, attenuation*64); ! 330: if (flags & SND_OFFSET) ! 331: MSG_WriteByte (&sv.multicast, timeofs*1000); ! 332: ! 333: if (flags & SND_ENT) ! 334: MSG_WriteShort (&sv.multicast, sendchan); ! 335: ! 336: if (flags & SND_POS) ! 337: MSG_WritePos (&sv.multicast, origin); ! 338: ! 339: // if the sound doesn't attenuate,send it to everyone ! 340: // (global radio chatter, voiceovers, etc) ! 341: if (attenuation == ATTN_NONE) ! 342: use_phs = false; ! 343: ! 344: if (channel & CHAN_RELIABLE) ! 345: { ! 346: if (use_phs) ! 347: SV_Multicast (origin, MULTICAST_PHS_R); ! 348: else ! 349: SV_Multicast (origin, MULTICAST_ALL_R); ! 350: } ! 351: else ! 352: { ! 353: if (use_phs) ! 354: SV_Multicast (origin, MULTICAST_PHS); ! 355: else ! 356: SV_Multicast (origin, MULTICAST_ALL); ! 357: } ! 358: } ! 359: ! 360: ! 361: /* ! 362: =============================================================================== ! 363: ! 364: FRAME UPDATES ! 365: ! 366: =============================================================================== ! 367: */ ! 368: ! 369: ! 370: ! 371: /* ! 372: ======================= ! 373: SV_SendClientDatagram ! 374: ======================= ! 375: */ ! 376: qboolean SV_SendClientDatagram (client_t *client) ! 377: { ! 378: byte msg_buf[MAX_MSGLEN]; ! 379: sizebuf_t msg; ! 380: ! 381: SV_BuildClientFrame (client); ! 382: ! 383: SZ_Init (&msg, msg_buf, sizeof(msg_buf)); ! 384: msg.allowoverflow = true; ! 385: ! 386: // send over all the relevant entity_state_t ! 387: // and the player_state_t ! 388: SV_WriteFrameToClient (client, &msg); ! 389: ! 390: // copy the accumulated multicast datagram ! 391: // for this client out to the message ! 392: // it is necessary for this to be after the WriteEntities ! 393: // so that entity references will be current ! 394: if (client->datagram.overflowed) ! 395: Com_Printf ("WARNING: datagram overflowed for %s\n", client->name); ! 396: else ! 397: SZ_Write (&msg, client->datagram.data, client->datagram.cursize); ! 398: SZ_Clear (&client->datagram); ! 399: ! 400: if (msg.overflowed) ! 401: { // must have room left for the packet header ! 402: Com_Printf ("WARNING: msg overflowed for %s\n", client->name); ! 403: SZ_Clear (&msg); ! 404: } ! 405: ! 406: // send the datagram ! 407: Netchan_Transmit (&client->netchan, msg.cursize, msg.data); ! 408: ! 409: // record the size for rate estimation ! 410: client->message_size[sv.framenum % RATE_MESSAGES] = msg.cursize; ! 411: ! 412: return true; ! 413: } ! 414: ! 415: ! 416: /* ! 417: ================== ! 418: SV_DemoCompleted ! 419: ================== ! 420: */ ! 421: void SV_DemoCompleted (void) ! 422: { ! 423: if (sv.demofile) ! 424: { ! 425: fclose (sv.demofile); ! 426: sv.demofile = NULL; ! 427: } ! 428: SV_Nextserver (); ! 429: } ! 430: ! 431: ! 432: /* ! 433: ======================= ! 434: SV_RateDrop ! 435: ! 436: Returns true if the client is over its current ! 437: bandwidth estimation and should not be sent another packet ! 438: ======================= ! 439: */ ! 440: qboolean SV_RateDrop (client_t *c) ! 441: { ! 442: int total; ! 443: int i; ! 444: ! 445: // never drop over the loopback ! 446: if (c->netchan.remote_address.type == NA_LOOPBACK) ! 447: return false; ! 448: ! 449: total = 0; ! 450: ! 451: for (i = 0 ; i < RATE_MESSAGES ; i++) ! 452: { ! 453: total += c->message_size[i]; ! 454: } ! 455: ! 456: if (total > c->rate) ! 457: { ! 458: c->surpressCount++; ! 459: c->message_size[sv.framenum % RATE_MESSAGES] = 0; ! 460: return true; ! 461: } ! 462: ! 463: return false; ! 464: } ! 465: ! 466: /* ! 467: ======================= ! 468: SV_SendClientMessages ! 469: ======================= ! 470: */ ! 471: void SV_SendClientMessages (void) ! 472: { ! 473: int i; ! 474: client_t *c; ! 475: int msglen; ! 476: byte msgbuf[MAX_MSGLEN]; ! 477: int r; ! 478: ! 479: msglen = 0; ! 480: ! 481: // read the next demo message if needed ! 482: if (sv.state == ss_demo && sv.demofile) ! 483: { ! 484: if (sv_paused->value) ! 485: msglen = 0; ! 486: else ! 487: { ! 488: // get the next message ! 489: r = fread (&msglen, 4, 1, sv.demofile); ! 490: if (r != 1) ! 491: { ! 492: SV_DemoCompleted (); ! 493: return; ! 494: } ! 495: msglen = LittleLong (msglen); ! 496: if (msglen == -1) ! 497: { ! 498: SV_DemoCompleted (); ! 499: return; ! 500: } ! 501: if (msglen > MAX_MSGLEN) ! 502: Com_Error (ERR_DROP, "SV_SendClientMessages: msglen > MAX_MSGLEN"); ! 503: r = fread (msgbuf, msglen, 1, sv.demofile); ! 504: if (r != 1) ! 505: { ! 506: SV_DemoCompleted (); ! 507: return; ! 508: } ! 509: } ! 510: } ! 511: ! 512: // send a message to each connected client ! 513: for (i=0, c = svs.clients ; i<maxclients->value; i++, c++) ! 514: { ! 515: if (!c->state) ! 516: continue; ! 517: // if the reliable message overflowed, ! 518: // drop the client ! 519: if (c->netchan.message.overflowed) ! 520: { ! 521: SZ_Clear (&c->netchan.message); ! 522: SZ_Clear (&c->datagram); ! 523: SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name); ! 524: SV_DropClient (c); ! 525: } ! 526: ! 527: if (sv.state == ss_cinematic ! 528: || sv.state == ss_demo ! 529: || sv.state == ss_pic ! 530: ) ! 531: Netchan_Transmit (&c->netchan, msglen, msgbuf); ! 532: else if (c->state == cs_spawned) ! 533: { ! 534: // don't overrun bandwidth ! 535: if (SV_RateDrop (c)) ! 536: continue; ! 537: ! 538: SV_SendClientDatagram (c); ! 539: } ! 540: else ! 541: { ! 542: // just update reliable if needed ! 543: if (c->netchan.message.cursize || curtime - c->netchan.last_sent > 1000 ) ! 544: Netchan_Transmit (&c->netchan, 0, NULL); ! 545: } ! 546: } ! 547: } ! 548:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.