Annotation of quake2/server/sv_user.c, revision 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.