Annotation of quake2/server/sv_user.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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