Annotation of quake2/server/sv_send.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.