Annotation of quakeworld/server/sv_user.c, revision 1.1

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

unix.superglobalmegacorp.com

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