Beispiel #1
0
        bool ClientCommand(client_t cl, NetBuffer msg)
        {
            int seq = msg.ReadInt32();
            string s = msg.ReadString();

            // see if we have already executed it
            if (cl.lastClientCommand >= seq)
                return true;

            Common.Instance.WriteLine("ClientCommand: {0}[s{1}]: {2}", cl.name, seq, s);

            // drop the connection if we have somehow lost commands
            if (seq > cl.lastClientCommand + 1)
            {
                Common.Instance.WriteLine("Client {0} lost {1} clientCommands", cl.name, seq-cl.lastClientCommand+1);
                DropClient(cl, "Lost reliable commands");
                return false;
            }

            // don't allow another command for one second
            cl.nextReliableTime = (int)time + 1000;

            ExecuteClientCommand(cl, s);
            cl.lastClientCommand = seq;
            cl.lastClientCommandString = s;
            return true;    // continue procesing
        }
Beispiel #2
0
    public static void Host_Ping_f()
    {
        if (cmd_source == cmd_source_t.src_command)
        {
            Cmd_ForwardToServer();
            return;
        }

        SV_ClientPrintf("Client ping times:\n");
        for (int i = 0; i < svs.maxclients; i++)
        {
            client_t client = svs.clients[i];
            if (!client.active)
            {
                continue;
            }
            float total = 0;
            for (int j = 0; j < q_shared.NUM_PING_TIMES; j++)
            {
                total += client.ping_times[j];
            }
            total /= q_shared.NUM_PING_TIMES;
            SV_ClientPrintf("{0,4} {1}\n", (int)(total * 1000), client.name);
        }
    }
Beispiel #3
0
    static void PF_lightstyle()
    {
        int    style = (int)G_FLOAT(q_shared.OFS_PARM0); // Uze: ???
        string val   = G_STRING(q_shared.OFS_PARM1);

        // change the string in sv
        sv.lightstyles[style] = val;

        // send message to all clients on this server
        if (!sv.active)
        {
            return;
        }

        for (int j = 0; j < svs.maxclients; j++)
        {
            client_t client = svs.clients[j];
            if (client.active || client.spawned)
            {
                client.message.MSG_WriteChar(q_shared.svc_lightstyle);
                client.message.MSG_WriteChar(style);
                client.message.MSG_WriteString(val);
            }
        }
    }
Beispiel #4
0
        /*
         * =======================
         * SV_SendClientDatagram
         * =======================
         */
        static bool SV_SendClientDatagram(client_t client)
        {
            byte[]           buf = new byte[quakedef.MAX_DATAGRAM];
            common.sizebuf_t msg = new common.sizebuf_t();

            msg.data    = buf;
            msg.maxsize = buf.Length;
            msg.cursize = 0;

            common.MSG_WriteByte(msg, net.svc_time);
            common.MSG_WriteFloat(msg, sv.time);

            // add the client specific data to the datagram
            SV_WriteClientdataToMessage(client.edict, msg);

            SV_WriteEntitiesToClient(client.edict, msg);

            // copy the server datagram if there is space
            if (msg.cursize + sv.datagram.cursize < msg.maxsize)
            {
                common.SZ_Write(msg, sv.datagram.data, sv.datagram.cursize);
            }

            // send the datagram
            if (net.NET_SendUnreliableMessage(client.netconnection, msg) == -1)
            {
                return(false);
            }

            return(true);
        }
Beispiel #5
0
    public static void SV_ReadClientMove(ref usercmd_t move)
    {
        client_t client = host_client;

        // read ping time
        client.ping_times[client.num_pings % q_shared.NUM_PING_TIMES] = (float)(sv.time - Reader.MSG_ReadFloat());
        client.num_pings++;

        // read current angles
        Vector3 angles = Reader.ReadAngles();

        Mathlib.Copy(ref angles, out client.edict.v.v_angle);

        // read movement
        move.forwardmove = Reader.MSG_ReadShort();
        move.sidemove    = Reader.MSG_ReadShort();
        move.upmove      = Reader.MSG_ReadShort();

        // read buttons
        int bits = Reader.MSG_ReadByte();

        client.edict.v.button0 = bits & 1;
        client.edict.v.button2 = (bits & 2) >> 1;

        int i = Reader.MSG_ReadByte();

        if (i != 0)
        {
            client.edict.v.impulse = i;
        }
    }
Beispiel #6
0
    public static bool SV_SendClientDatagram(client_t client)
    {
        MsgWriter msg = new MsgWriter(q_shared.MAX_DATAGRAM); // Uze todo: make static?

        msg.MSG_WriteByte(q_shared.svc_time);
        msg.MSG_WriteFloat((float)sv.time);

        // add the client specific data to the datagram
        SV_WriteClientdataToMessage(client.edict, msg);

        SV_WriteEntitiesToClient(client.edict, msg);

        // copy the server datagram if there is space
        if (msg.Length + sv.datagram.Length < msg.Capacity)
        {
            msg.Write(sv.datagram.Data, 0, sv.datagram.Length);
        }

        // send the datagram
        if (NET_SendUnreliableMessage(client.netconnection, msg) == -1)
        {
            SV_DropClient(true);// if the message couldn't send, kick off
            return(false);
        }

        return(true);
    }
Beispiel #7
0
        /// <summary>
        /// SV_SendClientDatagram
        /// </summary>
        private bool SendClientDatagram(client_t client)
        {
            var msg = new MessageWriter(QDef.MAX_DATAGRAM);               // Uze todo: make static?

            msg.WriteByte(ProtocolDef.svc_time);
            msg.WriteFloat(( float )this.sv.time);

            // add the client specific data to the datagram
            this.WriteClientDataToMessage(client.edict, msg);

            this.WriteEntitiesToClient(client.edict, msg);

            // copy the server datagram if there is space
            if (msg.Length + this.sv.datagram.Length < msg.Capacity)
            {
                msg.Write(this.sv.datagram.Data, 0, this.sv.datagram.Length);
            }

            // send the datagram
            if (this.Host.Network.SendUnreliableMessage(client.netconnection, msg) == -1)
            {
                this.DropClient(true);                  // if the message couldn't send, kick off
                return(false);
            }

            return(true);
        }
Beispiel #8
0
        /*
         * =============================================================================
         *
         * EVENT MESSAGES
         *
         * =============================================================================
         */

        /*
         * ==============================================================================
         *
         * CLIENT SPAWNING
         *
         * ==============================================================================
         */

        /*
         * ================
         * SV_SendServerinfo
         *
         * Sends the first message from the server to a connected client.
         * This will be sent on the initial connection and upon each server load.
         * ================
         */
        static void SV_SendServerinfo(client_t client)
        {
            int    i;
            string s;
            string message;

            common.MSG_WriteByte(client.message, net.svc_print);
            message = "\u0002\nVERSION " + quakedef.VERSION + " SERVER (" + prog.pr_crc + " CRC)";
            common.MSG_WriteString(client.message, message);

            common.MSG_WriteByte(client.message, net.svc_serverinfo);
            common.MSG_WriteLong(client.message, net.PROTOCOL_VERSION);
            common.MSG_WriteByte(client.message, svs.maxclients);

            if (host.coop.value == 0 && host.deathmatch.value != 0)
            {
                common.MSG_WriteByte(client.message, net.GAME_DEATHMATCH);
            }
            else
            {
                common.MSG_WriteByte(client.message, net.GAME_COOP);
            }

            //sprintf(message, pr_strings + sv.edicts->v.message);
            message = prog.pr_string(sv.edicts[0].v.message);

            common.MSG_WriteString(client.message, message);

            for (i = 1, s = sv.model_precache[i]; s != null; i++)
            {
                s = sv.model_precache[i];
                common.MSG_WriteString(client.message, s);
            }
            common.MSG_WriteByte(client.message, 0);

            for (i = 1, s = sv.sound_precache[i]; s != null; i++)
            {
                s = sv.sound_precache[i];
                common.MSG_WriteString(client.message, s);
            }
            common.MSG_WriteByte(client.message, 0);

            // send music
            common.MSG_WriteByte(client.message, net.svc_cdtrack);
            common.MSG_WriteByte(client.message, (int)sv.edicts[0].v.sounds);
            common.MSG_WriteByte(client.message, (int)sv.edicts[0].v.sounds);

            // set view
            common.MSG_WriteByte(client.message, net.svc_setview);
            common.MSG_WriteShort(client.message, prog.NUM_FOR_EDICT(client.edict));

            common.MSG_WriteByte(client.message, net.svc_signonnum);
            common.MSG_WriteByte(client.message, 1);

            client.sendsignon = true;
            client.spawned    = false;          // need prespawn, spawn, etc
        }
Beispiel #9
0
    public static void SV_DropClient(bool crash)
    {
        client_t client = host_client;

        if (!crash)
        {
            // send any final messages (don't check for errors)
            if (NET_CanSendMessage(client.netconnection))
            {
                MsgWriter msg = client.message;
                msg.MSG_WriteByte(q_shared.svc_disconnect);
                NET_SendMessage(client.netconnection, msg);
            }

            if (client.edict != null && client.spawned)
            {
                // call the prog function for removing a client
                // this will set the body to a dead frame, among other things
                int saveSelf = pr_global_struct.self;
                pr_global_struct.self = EDICT_TO_PROG(client.edict);
                PR_ExecuteProgram(pr_global_struct.ClientDisconnect);
                pr_global_struct.self = saveSelf;
            }

            Con_DPrintf("Client {0} removed\n", client.name);
        }

        // break the net connection
        NET_Close(client.netconnection);
        client.netconnection = null;

        // free the client (the body stays around)
        client.active    = false;
        client.name      = null;
        client.old_frags = -999999;
        net_activeconnections--;

        // send notification to all clients
        for (int i = 0; i < svs.maxclients; i++)
        {
            client_t cl = svs.clients[i];
            if (!cl.active)
            {
                continue;
            }

            cl.message.MSG_WriteByte(q_shared.svc_updatename);
            cl.message.MSG_WriteByte(ClientNum);
            cl.message.MSG_WriteString("");
            cl.message.MSG_WriteByte(q_shared.svc_updatefrags);
            cl.message.MSG_WriteByte(ClientNum);
            cl.message.MSG_WriteShort(0);
            cl.message.MSG_WriteByte(q_shared.svc_updatecolors);
            cl.message.MSG_WriteByte(ClientNum);
            cl.message.MSG_WriteByte(0);
        }
    }
Beispiel #10
0
        void ClientThink(client_t cl, Input.UserCommand cmd)
        {
            cl.lastUsercmd = cmd;

            if (cl.state != clientState_t.CS_ACTIVE)
                return; // may have been kicked during the last usercmd

            Game.Instance.Client_Think(cl.id);
        }
Beispiel #11
0
        /**
         * Initializes player structures after successfull connection.
         */
        public static void gotnewcl(int i, int challenge, string userinfo, netadr_t adr, int qport)
        {
            // build a new connection
            // accept the new client
            // this is the only place a client_t is ever initialized

            SV_MAIN.sv_client = SV_INIT.svs.clients[i];

            var edictnum = i + 1;

            var ent = GameBase.g_edicts[edictnum];

            SV_INIT.svs.clients[i].edict = ent;

            // save challenge for checksumming
            SV_INIT.svs.clients[i].challenge = challenge;

            // get the game a chance to reject this connection or modify the
            // userinfo
            if (!PlayerClient.ClientConnect(ent, userinfo))
            {
                if (Info.Info_ValueForKey(userinfo, "rejmsg") != null)
                {
                    Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\n" + Info.Info_ValueForKey(userinfo, "rejmsg") + "\nConnection refused.\n");
                }
                else
                {
                    Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nConnection refused.\n");
                }

                Com.DPrintf("Game rejected a connection.\n");

                return;
            }

            // parse some info from the info strings
            SV_INIT.svs.clients[i].userinfo = userinfo;
            SV_MAIN.SV_UserinfoChanged(SV_INIT.svs.clients[i]);

            // send the connect packet to the client
            Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "client_connect");

            Netchan.Setup(Defines.NS_SERVER, SV_INIT.svs.clients[i].netchan, adr, qport);

            SV_INIT.svs.clients[i].state = Defines.cs_connected;

            SZ.Init(SV_INIT.svs.clients[i].datagram, SV_INIT.svs.clients[i].datagram_buf, SV_INIT.svs.clients[i].datagram_buf.Length);

            SV_INIT.svs.clients[i].datagram.allowoverflow = true;
            SV_INIT.svs.clients[i].lastmessage            = SV_INIT.svs.realtime;  // don't timeout
            SV_INIT.svs.clients[i].lastconnect            = SV_INIT.svs.realtime;
            Com.DPrintf("new client added.\n");
        }
Beispiel #12
0
    public static void SV_SendNop(client_t client)
    {
        MsgWriter msg = new MsgWriter(4);

        msg.MSG_WriteChar(q_shared.svc_nop);

        if (NET_SendUnreliableMessage(client.netconnection, msg) == -1)
        {
            SV_DropClient(true);        // if the message couldn't send, kick off
        }
        client.last_message = realtime;
    }
Beispiel #13
0
        /// <summary>
        /// SV_SendNop
        /// Send a nop message without trashing or sending the accumulated client
        /// message buffer
        /// </summary>
        private void SendNop(client_t client)
        {
            var msg = new MessageWriter(4);

            msg.WriteChar(ProtocolDef.svc_nop);

            if (this.Host.Network.SendUnreliableMessage(client.netconnection, msg) == -1)
            {
                this.DropClient(true);                   // if the message couldn't send, kick off
            }
            client.last_message = this.Host.RealTime;
        }
Beispiel #14
0
        /*
         * =======================
         * SV_SendNop
         *
         * Send a nop message without trashing or sending the accumulated client
         * message buffer
         * =======================
         */
        static void SV_SendNop(client_t client)
        {
            common.sizebuf_t msg = new common.sizebuf_t();
            byte[]           buf = new byte[4];

            msg.data    = buf;
            msg.maxsize = buf.Length;
            msg.cursize = 0;

            common.MSG_WriteChar(msg, net.svc_nop);

            net.NET_SendUnreliableMessage(client.netconnection, msg);
            client.last_message = host.realtime;
        }
Beispiel #15
0
    static void PF_setspawnparms()
    {
        edict_t ent = G_EDICT(q_shared.OFS_PARM0);
        int     i   = NUM_FOR_EDICT(ent);

        if (i < 1 || i > svs.maxclients)
        {
            PR_RunError("Entity is not a client");
        }

        // copy spawn parms out of the client_t
        client_t client = svs.clients[i - 1];

        pr_global_struct.SetParams(client.spawn_parms);
    }
Beispiel #16
0
        /**
         * Writes a frame to a client system.
         */
        public static void SV_WriteFrameToClient(client_t client, sizebuf_t msg)
        {
            //ptr
            client_frame_t frame, oldframe;
            int            lastframe;

            //Com.Printf ("%i . %i\n", new
            // Vargs().add(client.lastframe).add(sv.framenum));
            // this is the frame we are creating
            frame = client.frames[SV_INIT.sv.framenum & Defines.UPDATE_MASK];

            if (client.lastframe <= 0)
            {
                // client is asking for a retransmit
                oldframe  = null;
                lastframe = -1;
            }
            else if (SV_INIT.sv.framenum - client.lastframe >= Defines.UPDATE_BACKUP - 3)
            {
                // client hasn't gotten a good message through in a long time
                // Com_Printf ("%s: Delta request from out-of-date packet.\n",
                // client.name);
                oldframe  = null;
                lastframe = -1;
            }
            else
            {
                // we have a valid message to delta from
                oldframe  = client.frames[client.lastframe & Defines.UPDATE_MASK];
                lastframe = client.lastframe;
            }

            MSG.WriteByte(msg, Defines.svc_frame);
            MSG.WriteLong(msg, SV_INIT.sv.framenum);
            MSG.WriteLong(msg, lastframe);             // what we are delta'ing from
            MSG.WriteByte(msg, client.surpressCount);  // rate dropped packets
            client.surpressCount = 0;

            // send over the areabits
            MSG.WriteByte(msg, frame.areabytes);
            SZ.Write(msg, frame.areabits, frame.areabytes);

            // delta encode the playerstate
            SV_ENTS.SV_WritePlayerstateToClient(oldframe, frame, msg);

            // delta encode the entities
            SV_ENTS.SV_EmitPacketEntities(oldframe, frame, msg);
        }
Beispiel #17
0
    static void PF_centerprint()
    {
        int    entnum = NUM_FOR_EDICT(G_EDICT(q_shared.OFS_PARM0));
        string s      = PF_VarString(1);

        if (entnum < 1 || entnum > svs.maxclients)
        {
            Con_Printf("tried to centerprint to a non-client\n");
            return;
        }

        client_t client = svs.clients[entnum - 1];

        client.message.MSG_WriteChar(q_shared.svc_centerprint);
        client.message.MSG_WriteString(s);
    }
Beispiel #18
0
    static void PF_stuffcmd()
    {
        int entnum = NUM_FOR_EDICT(G_EDICT(q_shared.OFS_PARM0));

        if (entnum < 1 || entnum > svs.maxclients)
        {
            PR_RunError("Parm 0 not a client");
        }
        string str = G_STRING(q_shared.OFS_PARM1);

        client_t old = host_client;

        host_client = svs.clients[entnum - 1];
        Host_ClientCommands("{0}", str);
        host_client = old;
    }
Beispiel #19
0
        /**
         * Pull specific info from a newly changed userinfo string into a more C
         * freindly form.
         */
        public static void SV_UserinfoChanged(client_t cl)
        {
            string val;
            int    i;

            // call prog code to allow overrides
            PlayerClient.ClientUserinfoChanged(cl.edict, cl.userinfo);

            // name for C code
            cl.name = Info.Info_ValueForKey(cl.userinfo, "name");

            // mask off high bit
            //TODO: masking for german umlaute
            //for (i=0 ; i<sizeof(cl.name) ; i++)
            //	cl.name[i] &= 127;

            // rate command
            val = Info.Info_ValueForKey(cl.userinfo, "rate");

            if (val.Length > 0)
            {
                i       = Lib.atoi(val);
                cl.rate = i;

                if (cl.rate < 100)
                {
                    cl.rate = 100;
                }

                if (cl.rate > 15000)
                {
                    cl.rate = 15000;
                }
            }
            else
            {
                cl.rate = 5000;
            }

            // msg command
            val = Info.Info_ValueForKey(cl.userinfo, "msg");

            if (val.Length > 0)
            {
                cl.messagelevel = Lib.atoi(val);
            }
        }
Beispiel #20
0
    public static void Host_Tell_f()
    {
        if (cmd_source == cmd_source_t.src_command)
        {
            Cmd_ForwardToServer();
            return;
        }

        if (cmd_argc < 3)
        {
            return;
        }

        string text = host_client.name + ": ";
        string p    = cmd_args;

        // remove quotes if present
        if (p.StartsWith("\""))
        {
            p = p.Substring(1, p.Length - 2);
        }

        text += p + "\n";

        client_t save = host_client;

        for (int j = 0; j < svs.maxclients; j++)
        {
            client_t client = svs.clients[j];
            if (!client.active || !client.spawned)
            {
                continue;
            }
            if (client.name == Cmd_Argv(1))
            {
                continue;
            }
            host_client = client;
            SV_ClientPrintf(text);
            break;
        }
        host_client = save;
    }
Beispiel #21
0
    public static void SV_ConnectClient(int clientnum)
    {
        client_t client = svs.clients[clientnum];

        Con_DPrintf("Client {0} connected\n", client.netconnection.address);

        int     edictnum = clientnum + 1;
        edict_t ent      = EDICT_NUM(edictnum);

        // set up the client_t
        qsocket_t netconnection = client.netconnection;

        float[] spawn_parms = new float[q_shared.NUM_SPAWN_PARMS];
        if (sv.loadgame)
        {
            Array.Copy(client.spawn_parms, spawn_parms, spawn_parms.Length);
        }

        client.Clear();
        client.netconnection         = netconnection;
        client.name                  = "unconnected";
        client.active                = true;
        client.spawned               = false;
        client.edict                 = ent;
        client.message.AllowOverflow = true; // we can catch it
        client.privileged            = false;

        if (sv.loadgame)
        {
            Array.Copy(spawn_parms, client.spawn_parms, spawn_parms.Length);
        }
        else
        {
            // call the progs to get default spawn parms for the new client
            PR_ExecuteProgram(pr_global_struct.SetNewParms);

            AssignGlobalSpawnparams(client);
        }

        SV_SendServerinfo(client);
    }
Beispiel #22
0
        void ClientEnterWorld(client_t cl, Input.UserCommand cmd)
        {
            Common.Instance.WriteLine("Going from PRIMED to ACTIVE for {0}", cl.name);
            cl.state = clientState_t.CS_ACTIVE;

            // resend all configstrings using the cs commands since these are
            // no longer sent when the client is CS_PRIMED
            UpdateConfigStrings(cl);

            // set up the entity for the client
            int clientNum = cl.id;
            sharedEntity ent = sv.gentities[clientNum];
            ent.s.number = clientNum;
            cl.gentity = ent;

            cl.deltaMessage = -1;
            cl.nextSnapshotTime = (int)time; // generate a snapshot immediately
            cl.lastUsercmd = cmd;

            Game.Instance.Client_Begin(clientNum);
        }
Beispiel #23
0
        /**
         * Called when the player is totally leaving the server, either willingly or
         * unwillingly. This is NOT called if the entire server is quiting or
         * crashing.
         */
        public static void SV_DropClient(client_t drop)
        {
            // add the disconnect
            MSG.WriteByte(drop.netchan.message, Defines.svc_disconnect);

            if (drop.state == Defines.cs_spawned)
            {
                // call the prog function for removing a client
                // this will remove the body, among other things
                PlayerClient.ClientDisconnect(drop.edict);
            }

            if (drop.download != null)
            {
                FS.FreeFile(drop.download);
                drop.download = null;
            }

            drop.state = Defines.cs_zombie;             // become free in a few seconds
            drop.name  = "";
        }
Beispiel #24
0
    public static void AssignGlobalSpawnparams(client_t client)
    {
        client.spawn_parms[0] = pr_global_struct.parm1;
        client.spawn_parms[1] = pr_global_struct.parm2;
        client.spawn_parms[2] = pr_global_struct.parm3;
        client.spawn_parms[3] = pr_global_struct.parm4;

        client.spawn_parms[4] = pr_global_struct.parm5;
        client.spawn_parms[5] = pr_global_struct.parm6;
        client.spawn_parms[6] = pr_global_struct.parm7;
        client.spawn_parms[7] = pr_global_struct.parm8;

        client.spawn_parms[8]  = pr_global_struct.parm9;
        client.spawn_parms[9]  = pr_global_struct.parm10;
        client.spawn_parms[10] = pr_global_struct.parm11;
        client.spawn_parms[11] = pr_global_struct.parm12;

        client.spawn_parms[12] = pr_global_struct.parm13;
        client.spawn_parms[13] = pr_global_struct.parm14;
        client.spawn_parms[14] = pr_global_struct.parm15;
        client.spawn_parms[15] = pr_global_struct.parm16;
    }
Beispiel #25
0
        private void AssignGlobalSpawnparams(client_t client)
        {
            client.spawn_parms[0] = this.Host.Programs.GlobalStruct.parm1;
            client.spawn_parms[1] = this.Host.Programs.GlobalStruct.parm2;
            client.spawn_parms[2] = this.Host.Programs.GlobalStruct.parm3;
            client.spawn_parms[3] = this.Host.Programs.GlobalStruct.parm4;

            client.spawn_parms[4] = this.Host.Programs.GlobalStruct.parm5;
            client.spawn_parms[5] = this.Host.Programs.GlobalStruct.parm6;
            client.spawn_parms[6] = this.Host.Programs.GlobalStruct.parm7;
            client.spawn_parms[7] = this.Host.Programs.GlobalStruct.parm8;

            client.spawn_parms[8]  = this.Host.Programs.GlobalStruct.parm9;
            client.spawn_parms[9]  = this.Host.Programs.GlobalStruct.parm10;
            client.spawn_parms[10] = this.Host.Programs.GlobalStruct.parm11;
            client.spawn_parms[11] = this.Host.Programs.GlobalStruct.parm12;

            client.spawn_parms[12] = this.Host.Programs.GlobalStruct.parm13;
            client.spawn_parms[13] = this.Host.Programs.GlobalStruct.parm14;
            client.spawn_parms[14] = this.Host.Programs.GlobalStruct.parm15;
            client.spawn_parms[15] = this.Host.Programs.GlobalStruct.parm16;
        }
Beispiel #26
0
    public static void SV_UpdateToReliableMessages()
    {
        // check for changes to be sent over the reliable streams
        for (int i = 0; i < svs.maxclients; i++)
        {
            host_client = svs.clients[i];
            if (host_client.old_frags != host_client.edict.v.frags)
            {
                for (int j = 0; j < svs.maxclients; j++)
                {
                    client_t client = svs.clients[j];
                    if (!client.active)
                    {
                        continue;
                    }

                    client.message.MSG_WriteByte(q_shared.svc_updatefrags);
                    client.message.MSG_WriteByte(i);
                    client.message.MSG_WriteShort((int)host_client.edict.v.frags);
                }

                host_client.old_frags = (int)host_client.edict.v.frags;
            }
        }

        for (int j = 0; j < svs.maxclients; j++)
        {
            client_t client = svs.clients[j];
            if (!client.active)
            {
                continue;
            }
            client.message.Write(sv.reliable_datagram.Data, 0, sv.reliable_datagram.Length);
        }

        sv.reliable_datagram.Clear();
    }
Beispiel #27
0
    /*
     * =================
     * SV_SendServerCommand
     *
     * Sends a reliable command string to be interpreted by
     * the client game module: "cp", "print", "chat", etc
     * A NULL client will broadcast to all clients
     * =================
     */
    static void SV_SendServerCommand(client_t cl, string fmt, params object[] args)
    {
        client_t client;
        int      j;
        string   message = va(fmt, args);

        if (cl != null)
        {
            SV_AddServerCommand(cl, message);
            return;
        }

        // hack to echo broadcast prints to console
        if (com_dedicated.integer && !strncmp(message, "print", 5))
        {
            Com_Printf("broadcast: %s\n", SV_ExpandNewlines(message));
        }

        // send the data to all relevent clients
        for (j = 0, client = svs.clients; j < sv_maxclients.integer; j++, client++)
        {
            if (client->state < CS_PRIMED)
            {
                continue;
            }

            // Ridah, don't need to send messages to AI
            if (client->gentity && client.gentity.r.svFlags & SVF_CASTAI)
            {
                continue;
            }

            // done.
            SV_AddServerCommand(client, message);
        }
    }
Beispiel #28
0
        /*
        ==================
        SV_DirectConnect

        A "connect" OOB command has been received
        ==================
        */
        void DirectConnect(IPEndPoint from, string[] tokens)
        {
            // Check banlist

            string userinfo = tokens[1];
            string schal = Info.ValueForKey(userinfo, "challenge");
            int challenge = int.Parse(schal);
            int qport = int.Parse(Info.ValueForKey(userinfo, "qport"));
            int i;
            // quick reject
            for (i = 0; i < clients.Count; i++)
            {
                client_t cl = clients[i];
                if (cl.state == clientState_t.CS_FREE)
                    continue;

                if (IPAddress.Equals(from.Address, cl.netchan.remoteAddress.Address)
                    && (qport == cl.netchan.qport || from.Port == cl.netchan.remoteAddress.Port))
                {
                    if ((time - cl.lastConnectTime) < sv_reconnectlimit.Integer * 1000f)
                    {
                        Common.Instance.WriteLine("DirConnect: ({0})=>Reconnect rejected : too soon.", from.Address.ToString());
                        return;
                    }
                    break;
                }
            }
            string ip = from.Address.ToString();
            Info.SetValueForKey(userinfo, "ip", ip);

            // see if the challenge is valid (LAN clients don't need to challenge)
            if (!Net.Instance.IsLanAddress(from.Address))
            {

                for (i = 0; i < challenges.Count; i++)
                {
                    if (IPEndPoint.Equals(from, challenges[i].adr))
                    {
                        if (challenge == challenges[i].challenge)
                            break;
                        else
                            Common.Instance.WriteLine("FIXFIX");
                    }
                }

                // No challenge found
                if (i == challenges.Count)
                {
                    Net.Instance.OutOfBandMessage(Net.NetSource.SERVER, from, "print\nNo or bad challenge for your address\n");
                    return;
                }

                // Challenge found
                challenge_t chal = challenges[i];
                if (chal.wasrefused)
                {
                    // Return silently, so that error messages written by the server keep being displayed.
                    return;
                }

                int ping = (int)time - chal.pingTime;

                // never reject a LAN client based on ping
                if (!Net.Instance.IsLanAddress(from.Address))
                {
                    if (sv_minping.Integer > 0 && ping < sv_minping.Value)
                    {
                        Net.Instance.OutOfBandMessage(Net.NetSource.SERVER, from, "print\nServer is for high pings only.\n");
                        Common.Instance.WriteLine("Client rejected due to low ping");
                        chal.wasrefused = true;
                        return;
                    }
                    if (sv_maxping.Integer > 0 && ping > sv_maxping.Value)
                    {
                        Net.Instance.OutOfBandMessage(Net.NetSource.SERVER, from, "print\nServer is for low pings only.\n");
                        Common.Instance.WriteLine("Client rejected due to high ping");
                        chal.wasrefused = true;
                        return;
                    }
                }

                Common.Instance.WriteLine("Client {0} connecting with {0} challenge ping", i, ping);
                chal.connected = true;
            }

            bool gotcl = false;
            client_t newCl = new client_t();
            // if there is already a slot for this ip, reuse it
            for (i = 0; i < clients.Count; i++)
            {
                client_t cl = clients[i];
                if (cl.state == clientState_t.CS_FREE)
                    continue;

                if (IPAddress.Equals(from.Address, cl.netchan.remoteAddress.Address)
                    && (qport == cl.netchan.qport || from.Port == cl.netchan.remoteAddress.Port))
                {
                    Common.Instance.WriteLine("{0}:reconnect", from.Address.ToString());
                    newCl = cl;
                    gotcl = true;
                    break;
                }
            }
            if (!gotcl)
            {
                newCl = null;
                // find a client slot
                for (i = 0; i < clients.Count; i++)
                {
                    client_t cl = clients[i];
                    if (cl.state == clientState_t.CS_FREE)
                    {
                        newCl = cl;
                        break;
                    }
                }

                if (newCl == null && i < sv_maxclients.Integer)
                {
                    newCl = new client_t();
                    clients.Add(newCl);
                    i = clients.Count - 1;
                    newCl.id = i;
                }

                if (newCl == null)
                {
                    Net.Instance.OutOfBandMessage(Net.NetSource.SERVER, from, "print\nServer is full\n");
                    Common.Instance.WriteLine("Rejected a connection");
                    return;
                }

                // we got a newcl, so reset the reliableSequence and reliableAcknowledge
                newCl.reliableAcknowledge = 0;
                newCl.reliableSequence = 0;
            }

            // build a new connection
            // accept the new client
            // this is the only place a client_t is ever initialized
            if (newCl.id != i)
            {
                int test = 2;
            }
            sharedEntity ent = sv.gentities[i];
            newCl.gentity = ent;

            // save the challenge
            newCl.challenge = challenge;

            // save the address
            newCl.netchan = Net.Instance.NetChan_Setup(Net.NetSource.SERVER, from, qport);

            // save the userinfo
            newCl.userinfo = userinfo;

            // get the game a chance to reject this connection or modify the userinfo
            string denied = Game.Instance.Client_Connect(i, true);
            if (denied != null)
            {
                Net.Instance.OutOfBandMessage(Net.NetSource.SERVER, from, string.Format("print\n{0}\n", denied));
                Common.Instance.WriteLine("Game rejected a connection: {0}", denied);
                return;
            }

            UserInfoChanged(newCl);

            // send the connect packet to the client
            Net.Instance.OutOfBandMessage(Net.NetSource.SERVER, from, "connectResponse");

            Common.Instance.WriteLine("Going from CS_FREE to CS_CONNECTED for {0}", i);
            newCl.state = clientState_t.CS_CONNECTED;
            newCl.nextSnapshotTime = (int)time;
            newCl.lastPacketTime = time;
            newCl.lastConnectTime = (int)time;

            // when we receive the first packet from the client, we will
            // notice that it is from a different serverid and that the
            // gamestate message was not just sent, forcing a retransmit
            newCl.gamestateMessageNum = -1;
        }
Beispiel #29
0
        /*
        =======================
        SV_SendNop

        Send a nop message without trashing or sending the accumulated client
        message buffer
        =======================
        */
        static void SV_SendNop(client_t client)
        {
            common.sizebuf_t	msg = new common.sizebuf_t();
            byte[]		        buf = new byte[4];

            msg.data = buf;
            msg.maxsize = buf.Length;
            msg.cursize = 0;

            common.MSG_WriteChar (msg, net.svc_nop);

            net.NET_SendUnreliableMessage (client.netconnection, msg);
            client.last_message = host.realtime;
        }
Beispiel #30
0
    public static void Host_Say(bool teamonly)
    {
        bool fromServer = false;

        if (cmd_source == cmd_source_t.src_command)
        {
            if (cls.state == cactive_t.ca_dedicated)
            {
                fromServer = true;
                teamonly   = false;
            }
            else
            {
                Cmd_ForwardToServer();
                return;
            }
        }

        if (cmd_argc < 2)
        {
            return;
        }

        client_t save = host_client;

        string p = cmd_args;

        // remove quotes if present
        if (p.StartsWith("\""))
        {
            p = p.Substring(1, p.Length - 2);
        }

        // turn on color set 1
        string text;

        if (!fromServer)
        {
            text = (char)1 + save.name + ": ";
        }
        else
        {
            text = (char)1 + "<" + hostname.@string + "> ";
        }

        text += p + "\n";

        for (int j = 0; j < svs.maxclients; j++)
        {
            client_t client = svs.clients[j];
            if (client == null || !client.active || !client.spawned)
            {
                continue;
            }
            if (teamplay.value != 0 && teamonly && client.edict.v.team != save.edict.v.team)
            {
                continue;
            }
            host_client = client;
            SV_ClientPrintf(text);
        }
        host_client = save;
    }
Beispiel #31
0
 void UpdateUserInfo(client_t cl, string[] tokens)
 {
     if (tokens.Length < 0)
     {
         SendServerCommand(cl, "print \"Userinfo not changed: needs argument\"\n");
     }
     cl.userinfo = tokens[1];
     UserInfoChanged(cl);
     Game.Instance.ClientUserInfoChanged(cl.id);
 }
Beispiel #32
0
        /*
        ==================
        SV_UserMove

        The message usually contains all the movement commands
        that were in the last three packets, so that the information
        in dropped packets can be recovered.

        On very fast clients, there may be multiple usercmd packed into
        each of the backup packets.
        ==================
        */
        void UserMove(client_t cl, NetBuffer buf, bool deltaCompressed)
        {
            if (deltaCompressed)
                cl.deltaMessage = cl.messageAcknowledge;
            else
                cl.deltaMessage = -1;

            int cmdCount = buf.ReadByte();

            if (cmdCount < 1)
            {
                Common.Instance.WriteLine("cmdCount < 1");
                return;
            }

            if (cmdCount > 32)
            {
                Common.Instance.WriteLine("cmdCount > 32");
                return;
            }

            List<Input.UserCommand> cmds = new List<Input.UserCommand>();
            Input.UserCommand oldcmd = new Input.UserCommand();
            for (int i = 0; i < cmdCount; i++)
            {
                Input.UserCommand cmd = Input.Instance.MSG_ReadDeltaUsercmdKey(buf, ref oldcmd);
                cmds.Add(cmd);
                oldcmd = cmd;
            }

            // save time for ping calculation
            cl.frames[cl.messageAcknowledge & 31].messageAcked = (int)time;

            // if this is the first usercmd we have received
            // this gamestate, put the client into the world
            if (cl.state == clientState_t.CS_PRIMED)
            {
                ClientEnterWorld(cl, cmds[cmds.Count-1]);
                // the moves can be processed normaly
            }

            if (cl.state != clientState_t.CS_ACTIVE)
            {
                cl.deltaMessage = -1;
                return;
            }

            // usually, the first couple commands will be duplicates
            // of ones we have previously received, but the servertimes
            // in the commands will cause them to be immediately discarded
            for (int i = 0; i < cmdCount; i++)
            {
                // if this is a cmd from before a map_restart ignore it
                if (cmds[i].serverTime > cmds[cmdCount - 1].serverTime)
                {
                    continue;
                }

                // don't execute if this is an old cmd which is already executed
                // these old cmds are included when cl_packetdup > 0
                if (cmds[i].serverTime <= cl.lastUsercmd.serverTime)
                {
                    continue;
                }

                ClientThink(cl, cmds[i]);
            }
        }
Beispiel #33
0
        void ExecuteClientCommand(client_t cl, string cmd)
        {
            string[] tokens = Commands.TokenizeString(cmd);

            // see if it is a server level command
            Common.Instance.WriteLine("ExecuteClientCommand: {0}", tokens[0]);
            switch (tokens[0])
            {
                case "userinfo":
                    UpdateUserInfo(cl, tokens);
                    break;
                case "disconnect":
                    DropClient(cl, "disconnected");
                    break;
                default:
                    if (sv.state == serverState_t.SS_GAME)
                        Game.Instance.Client_Command(cl.id, tokens);
                    break;

            }
            //string[] ucmds = new string[] {"userinfo", "disconnect", "cp", "vdr", "download", "nextdl", "stopdl", "donedl" };
        }
Beispiel #34
0
        // Called when clients leaves server completely. Not called if server is crashing or quitting, handled in FinalMessage()
        private void DropClient(client_t cl, string reason)
        {
            if (cl.state == clientState_t.CS_ZOMBIE)
                return;     // already dropped

            // see if we already have a challenge for this ip
            int i;
            IPEndPoint clEndPoint = cl.netchan.remoteAddress;
            for (i = 0; i < challenges.Count; i++)
            {
                if (clEndPoint.Equals(challenges[i]))
                    break;
            }
            if (i != challenges.Count)
                challenges.RemoveAt(i); // Remove old challenge

            // tell everyone why they got dropped
            SendServerCommand(null, string.Format("print \"{0} {1}\"\n", cl.name, reason));

            // call the prog function for removing a client
            // this will remove the body, among other things
            Game.Instance.Client_Disconnect(cl.gentity.s.number);

            // add the disconnect command
            SendServerCommand(cl, string.Format("disconnect \"{0}\"", reason));

            // nuke user info
            SetUserInfo(cl, "");

            cl.state = clientState_t.CS_ZOMBIE; // become free in a few seconds
        }
Beispiel #35
0
    public static void SV_SendServerinfo(client_t client)
    {
        MsgWriter writer = client.message;

        writer.MSG_WriteByte(q_shared.svc_print);
        writer.MSG_WriteString(String.Format("{0}\nVERSION {1,4:F2} SERVER ({2} CRC)", (char)2, q_shared.VERSION, pr_crc));

        writer.MSG_WriteByte(q_shared.svc_serverinfo);
        writer.MSG_WriteLong(q_shared.PROTOCOL_VERSION);
        writer.MSG_WriteByte(svs.maxclients);

        if (!(coop.value != 0) && deathmatch.value != 0)
        {
            writer.MSG_WriteByte(q_shared.GAME_DEATHMATCH);
        }
        else
        {
            writer.MSG_WriteByte(q_shared.GAME_COOP);
        }

        string message = GetString(sv.edicts[0].v.message);

        writer.MSG_WriteString(message);

        for (int i = 1; i < sv.model_precache.Length; i++)
        {
            string tmp = sv.model_precache[i];
            if (String.IsNullOrEmpty(tmp))
            {
                break;
            }
            writer.MSG_WriteString(tmp);
        }
        writer.MSG_WriteByte(0);

        for (int i = 1; i < sv.sound_precache.Length; i++)
        {
            string tmp = sv.sound_precache[i];
            if (tmp == null)
            {
                break;
            }
            writer.MSG_WriteString(tmp);
        }
        writer.MSG_WriteByte(0);

        // send music
        writer.MSG_WriteByte(q_shared.svc_cdtrack);
        writer.MSG_WriteByte((int)sv.edicts[0].v.sounds);
        writer.MSG_WriteByte((int)sv.edicts[0].v.sounds);

        // set view
        writer.MSG_WriteByte(q_shared.svc_setview);
        writer.MSG_WriteShort(NUM_FOR_EDICT(client.edict));

        writer.MSG_WriteByte(q_shared.svc_signonnum);
        writer.MSG_WriteByte(1);

        client.sendsignon = true;
        client.spawned    = false;      // need prespawn, spawn, etc
    }
Beispiel #36
0
        void WriteSnapshotToClient(client_t cl, NetBuffer msg)
        {
            // this is the snapshot we are creating
            clientSnapshot_t frame = cl.frames[cl.netchan.outgoingSequence & 31];

            // try to use a previous frame as the source for delta compressing the snapshot
            clientSnapshot_t oldframe = null;
            int lastframe;
            if (cl.deltaMessage <= 0 || cl.state != clientState_t.CS_ACTIVE)
            {
                // client is asking for a retransmit
                oldframe = null;
                lastframe = 0;
            }
            else if (cl.netchan.outgoingSequence - cl.deltaMessage >= (32 - 3))
            {
                // client hasn't gotten a good message through in a long time
                Common.Instance.WriteLine("{0}:  Delta request from out of date packet.", cl.name);
                oldframe = null;
                lastframe = 0;
            }
            else
            {
                // we have a valid snapshot to delta from
                oldframe = cl.frames[cl.deltaMessage & 31];
                lastframe = cl.netchan.outgoingSequence - cl.deltaMessage;
                // the snapshot's entities may still have rolled off the buffer, though
                if (oldframe.first_entity <= nextSnapshotEntities - numSnapshotEntities)
                {
                    Common.Instance.WriteLine("{0}: Delta request from out of date entities.", cl.name);
                    oldframe = null;
                    lastframe = 0;
                }
            }

            msg.Write((byte)svc_ops_e.svc_snapshot);
            // send over the current server time so the client can drift
            // its view of time to try to match
            if (cl.oldServerTime > 0)
            {
                // The server has not yet got an acknowledgement of the
                // new gamestate from this client, so continue to send it
                // a time as if the server has not restarted. Note from
                // the client's perspective this time is strictly speaking
                // incorrect, but since it'll be busy loading a map at
                // the time it doesn't really matter.
                msg.Write((int)(sv.time + cl.oldServerTime));
            }
            else
                msg.Write((int)sv.time);

            // what we are delta'ing from
            msg.Write((byte)lastframe);

            int snapFlags = snapFlagServerBit;
            if (cl.rateDelayed)
                snapFlags |= SNAPFLAG_RATE_DELAYED;
            if (cl.state != clientState_t.CS_ACTIVE)
                snapFlags |= SNAPFLAG_NOT_ACTIVE;

            msg.Write((byte)snapFlags);

            // send over the areabits
            msg.Write((byte)frame.areabytes);
            msg.Write(frame.areabits);

            // delta encode the playerstate
            if (oldframe != null)
                Net.WriteDeltaPlayerstate(msg, oldframe.ps, frame.ps);
            else
                Net.WriteDeltaPlayerstate(msg, null, frame.ps);

            // delta encode the entities
            EmitPacketEntities(oldframe, frame, msg);
        }
Beispiel #37
0
        /*
        ==================
        SV_UpdateServerCommandsToClient

        (re)send all server commands the client hasn't acknowledged yet
        ==================
        */
        void UpdateServerCommandsToClient(client_t cl, NetBuffer msg)
        {
            // write any unacknowledged serverCommands
            for (int i = cl.reliableAcknowledge+1; i <= cl.reliableSequence; i++)
            {
                msg.Write((byte)svc_ops_e.svc_serverCommand);
                msg.Write(i);
                msg.Write(cl.reliableCommands[i & 63]);
            }
            cl.reliableSent = cl.reliableSequence;
        }
Beispiel #38
0
        void SendMessageToClient(NetBuffer msg, client_t client)
        {
            // record information about the message
            client.frames[client.netchan.outgoingSequence & 31].messageSize = msg.LengthBytes;
            client.frames[client.netchan.outgoingSequence & 31].messageSent = (int)time;
            client.frames[client.netchan.outgoingSequence & 31].messageAcked = -1;

            // send the datagram
            NetChan_Transmit(client, msg);

            // set nextSnapshotTime based on rate and requested number of updates
            int rateMsec = RateMsec(client, msg.LengthBytes);
            if (rateMsec < client.snapshotMsec * Common.Instance.timescale.Value)
            {
                // never send more packets than this, no matter what the rate is at
                rateMsec = (int)(client.snapshotMsec * Common.Instance.timescale.Value);
                client.rateDelayed = false;
            }
            else
                client.rateDelayed = true;

            client.nextSnapshotTime = (int)(time + (float)rateMsec * Common.Instance.timescale.Value);

            // don't pile up empty snapshots while connecting
            if (client.state != clientState_t.CS_ACTIVE)
            {
                // a gigantic connection message may have already put the nextSnapshotTime
                // more than a second away, so don't shorten it
                // do shorten if client is downloading
                if (client.nextSnapshotTime < time + (int)(1000 * Common.Instance.timescale.Value))
                    client.nextSnapshotTime = (int)(time + 1000 * Common.Instance.timescale.Value);
            }
        }
Beispiel #39
0
        void SendClientSnapshot(client_t client, int index)
        {
            // build the snapshot
            BuildClientSnapshot(client, index);

            NetBuffer msg = new NetBuffer();
            // let the client know which reliable clientCommands we have received
            msg.Write(client.lastClientCommand);
            // (re)send any reliable server commands
            UpdateServerCommandsToClient(client, msg);

            // send over all the relevant entityState_t
            // and the playerState_t
            WriteSnapshotToClient(client, msg);

            SendMessageToClient(msg, client);
        }
Beispiel #40
0
        /*
        ================
        SV_SendClientGameState

        Sends the first message from the server to a connected client.
        This will be sent on the initial connection and upon each new map load.

        It will be resent if the client acknowledges a later message but has
        the wrong gamestate.
        ================
        */
        void SendClientGameState(client_t cl)
        {
            Common.Instance.WriteLine("SendClientGameState for {0}", cl.name);
            Common.Instance.WriteLine("Going from CONNECTED to PRIMED for {0}", cl.name);
            cl.state = clientState_t.CS_PRIMED;
            cl.pureAuthentic = 0;
            cl.gotCP = false;

            // when we receive the first packet from the client, we will
            // notice that it is from a different serverid and that the
            // gamestate message was not just sent, forcing a retransmit
            cl.gamestateMessageNum = cl.netchan.outgoingSequence;

            NetBuffer msg = new NetBuffer();
            // NOTE, MRE: all server->client messages now acknowledge
            // let the client know which reliable clientCommands we have received
            msg.Write(cl.lastClientCommand);

            // send any server commands waiting to be sent first.
            // we have to do this cause we send the client->reliableSequence
            // with a gamestate and it sets the clc.serverCommandSequence at
            // the client side
            UpdateServerCommandsToClient(cl, msg);

            // send the gamestate
            msg.Write((byte)svc_ops_e.svc_gamestate);
            msg.Write(cl.reliableSequence);

            // write the configstrings
            foreach (int i in sv.configstrings.Keys)
            {
                msg.Write((byte)svc_ops_e.svc_configstring);
                msg.Write((short)i);
                msg.Write(sv.configstrings[i]);
            }

            // write the baselines
            Common.entityState_t nullstate = new Common.entityState_t();
            for (int i = 0; i < 1024; i++)
            {
                Common.entityState_t bases = sv.svEntities[i].baseline;
                if (bases == null || bases.number <= 0)
                    continue;

                msg.Write((byte)svc_ops_e.svc_baseline);
                Net.Instance.MSG_WriteDeltaEntity(msg, ref nullstate, ref bases, true);
            }

            msg.Write((byte)svc_ops_e.svc_EOF);
            msg.Write(cl.id);
            SendMessageToClient(msg, cl);
        }
Beispiel #41
0
        /// <summary>
        /// SV_SendServerinfo
        /// Sends the first message from the server to a connected client.
        /// This will be sent on the initial connection and upon each server load.
        /// </summary>
        private void SendServerInfo(client_t client)
        {
            var writer = client.message;

            writer.WriteByte(ProtocolDef.svc_print);
            writer.WriteString(string.Format("{0}\nVERSION {1,4:F2} SERVER ({2} CRC)", ( char )2, QDef.VERSION, this.Host.Programs.Crc));

            writer.WriteByte(ProtocolDef.svc_serverinfo);
            writer.WriteLong(ProtocolDef.PROTOCOL_VERSION);
            writer.WriteByte(this.svs.maxclients);

            if (!this.Host.Cvars.Coop.Get <bool>() && this.Host.Cvars.Deathmatch.Get <int>() != 0)
            {
                writer.WriteByte(ProtocolDef.GAME_DEATHMATCH);
            }
            else
            {
                writer.WriteByte(ProtocolDef.GAME_COOP);
            }

            var message = this.Host.Programs.GetString(this.sv.edicts[0].v.message);

            writer.WriteString(message);

            for (var i = 1; i < this.sv.model_precache.Length; i++)
            {
                var tmp = this.sv.model_precache[i];
                if (string.IsNullOrEmpty(tmp))
                {
                    break;
                }
                writer.WriteString(tmp);
            }
            writer.WriteByte(0);

            for (var i = 1; i < this.sv.sound_precache.Length; i++)
            {
                var tmp = this.sv.sound_precache[i];
                if (tmp == null)
                {
                    break;
                }
                writer.WriteString(tmp);
            }
            writer.WriteByte(0);

            // send music
            writer.WriteByte(ProtocolDef.svc_cdtrack);
            writer.WriteByte(( int )this.sv.edicts[0].v.sounds);
            writer.WriteByte(( int )this.sv.edicts[0].v.sounds);

            // set view
            writer.WriteByte(ProtocolDef.svc_setview);
            writer.WriteShort(this.NumForEdict(client.edict));

            writer.WriteByte(ProtocolDef.svc_signonnum);
            writer.WriteByte(1);

            client.sendsignon = true;
            client.spawned    = false;              // need prespawn, spawn, etc
        }
Beispiel #42
0
 void NetChan_Transmit(client_t cl, NetBuffer msg)
 {
     msg.Write((byte)svc_ops_e.svc_EOF);
     Net.Instance.NetChan_Transmit(cl.netchan, msg);
 }
Beispiel #43
0
        public void SendServerCommand(client_t cl, string fmt)
        {
            // Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt
            // The actual cause of the bug is probably further downstream
            // and should maybe be addressed later, but this certainly
            // fixes the problem for now
            if (fmt.Length > 1022)
            {
                Common.Instance.WriteLine("SendServerCommand: too long :(");
                return;
            }

            if (cl != null)
            {
                AddServerCommand(cl, fmt);
                return;
            }

            // send the data to all relevent clients
            foreach (client_t client in clients)
            {
                AddServerCommand(client, fmt);
            }
        }
Beispiel #44
0
        //public bool GetEntityToken(ref string result)
        //{
        //    string s = Common.Parse(sv.entityParseString, sv.entityParsePoint);
        //    result = s;
        //    if (sv.entityParsePoint >= sv.entityParseString.Length)
        //        return false;
        //    else
        //        return true;
        //}
        void UserInfoChanged(client_t cl)
        {
            cl.name = Info.ValueForKey(cl.userinfo, "name");
            string val;
            // rate command
            // if the client is on the same subnet as the server and we aren't running an
            // internet public server, assume they don't need a rate choke
            if (Net.Instance.IsLanAddress(cl.netchan.remoteAddress.Address))
            {
                cl.rate = 99999;
            }
            else
            {
                cl.rate = 25000;
                val = Info.ValueForKey(cl.userinfo, "rate");
                if (val != null)
                {
                    int i;
                    if (int.TryParse(val, out i))
                    {
                        cl.rate = i;
                        if (cl.rate < 1000)
                            cl.rate = 1000;
                        else if (cl.rate > 90000)
                            cl.rate = 90000;
                    }
                    else
                        cl.rate = 25000;
                }

            }

            val = Info.ValueForKey(cl.userinfo, "handicap");
            if (val != null && val.Length > 0)
            {
                int handi;
                if (int.TryParse(val, out handi) && handi <= 0 && handi > 100)
                    cl.userinfo = Info.SetValueForKey(cl.userinfo, "handicap", "100");
            }

            // snaps command
            val = Info.ValueForKey(cl.userinfo, "cl_updaterate");
            if (val != null && val.Length > 0)
            {
                int i = 1;
                int.TryParse(val, out i);
                if (i < 1)
                    i = 1;
                else if (i > sv_fps.Integer)
                    i = sv_fps.Integer;

                cl.snapshotMsec = (int)(1000f / i);
            }
            else
            {
                cl.snapshotMsec = 50;
            }
        }
Beispiel #45
0
    public static void Host_Spawn_f()
    {
        if (cmd_source == cmd_source_t.src_command)
        {
            Con_Printf("spawn is not valid from the console\n");
            return;
        }

        if (host_client.spawned)
        {
            Con_Printf("Spawn not valid -- allready spawned\n");
            return;
        }

        edict_t ent;

        // run the entrance script
        if (sv.loadgame)
        {
            // loaded games are fully inited allready
            // if this is the last client to be connected, unpause
            sv.paused = false;
        }
        else
        {
            // set up the edict
            ent = host_client.edict;

            ent.Clear(); //memset(&ent.v, 0, progs.entityfields * 4);
            ent.v.colormap = NUM_FOR_EDICT(ent);
            ent.v.team     = (host_client.colors & 15) + 1;
            ent.v.netname  = ED_NewString(host_client.name);

            // copy spawn parms out of the client_t
            pr_global_struct.SetParams(host_client.spawn_parms);

            // call the spawn function

            pr_global_struct.time = (float)sv.time;
            pr_global_struct.self = EDICT_TO_PROG(sv_player);
            PR_ExecuteProgram(pr_global_struct.ClientConnect);

            if ((Sys_FloatTime() - host_client.netconnection.connecttime) <= sv.time)
            {
                Con_DPrintf("{0} entered the game\n", host_client.name);
            }

            PR_ExecuteProgram(pr_global_struct.PutClientInServer);
        }


        // send all current names, colors, and frag counts
        MsgWriter msg = host_client.message;

        msg.Clear();

        // send time of update
        msg.MSG_WriteByte(q_shared.svc_time);
        msg.MSG_WriteFloat((float)sv.time);

        for (int i = 0; i < svs.maxclients; i++)
        {
            client_t client = svs.clients[i];
            msg.MSG_WriteByte(q_shared.svc_updatename);
            msg.MSG_WriteByte(i);
            msg.MSG_WriteString(client.name);
            msg.MSG_WriteByte(q_shared.svc_updatefrags);
            msg.MSG_WriteByte(i);
            msg.MSG_WriteShort(client.old_frags);
            msg.MSG_WriteByte(q_shared.svc_updatecolors);
            msg.MSG_WriteByte(i);
            msg.MSG_WriteByte(client.colors);
        }

        // send all current light styles
        for (int i = 0; i < q_shared.MAX_LIGHTSTYLES; i++)
        {
            msg.MSG_WriteByte(q_shared.svc_lightstyle);
            msg.MSG_WriteByte((char)i);
            msg.MSG_WriteString(sv.lightstyles[i]);
        }

        //
        // send some stats
        //
        msg.MSG_WriteByte(q_shared.svc_updatestat);
        msg.MSG_WriteByte(q_shared.STAT_TOTALSECRETS);
        msg.MSG_WriteLong((int)pr_global_struct.total_secrets);

        msg.MSG_WriteByte(q_shared.svc_updatestat);
        msg.MSG_WriteByte(q_shared.STAT_TOTALMONSTERS);
        msg.MSG_WriteLong((int)pr_global_struct.total_monsters);

        msg.MSG_WriteByte(q_shared.svc_updatestat);
        msg.MSG_WriteByte(q_shared.STAT_SECRETS);
        msg.MSG_WriteLong((int)pr_global_struct.found_secrets);

        msg.MSG_WriteByte(q_shared.svc_updatestat);
        msg.MSG_WriteByte(q_shared.STAT_MONSTERS);
        msg.MSG_WriteLong((int)pr_global_struct.killed_monsters);


        //
        // send a fixangle
        // Never send a roll angle, because savegames can catch the server
        // in a state where it is expecting the client to correct the angle
        // and it won't happen if the game was just loaded, so you wind up
        // with a permanent head tilt
        ent = EDICT_NUM(1 + ClientNum);
        msg.MSG_WriteByte(q_shared.svc_setangle);
        msg.MSG_WriteAngle(ent.v.angles.x);
        msg.MSG_WriteAngle(ent.v.angles.y);
        msg.MSG_WriteAngle(0);

        SV_WriteClientdataToMessage(sv_player, host_client.message);

        msg.MSG_WriteByte(q_shared.svc_signonnum);
        msg.MSG_WriteByte(3);
        host_client.sendsignon = true;
    }
Beispiel #46
0
        /*
        =======================
        SV_SendNop

        Send a nop message without trashing or sending the accumulated client
        message buffer
        =======================
        */
        static void SV_SendNop(client_t client)
        {
            common.sizebuf_t	msg = new common.sizebuf_t();
            Uint8Array          buf = new Uint8Array(4);

            msg.data = buf;
            msg.maxsize = buf.Length;
            msg.cursize = 0;

            common.MSG_WriteChar (msg, net.svc_nop);

            if (net.NET_SendUnreliableMessage(client.netconnection, msg) == -1)
                host.SV_DropClient(true);	// if the message couldn't send, kick off

            client.last_message = host.realtime;
        }
Beispiel #47
0
        /*
        ===============
        SV_SendConfigstring

        Creates and sends the server command necessary to update the CS index for the
        given client
        ===============
        */
        void SendConfigString(client_t client, int index)
        {
            SendServerCommand(client, string.Format("cs {0} \"{1}\"\n", index, sv.configstrings[index]));
        }
Beispiel #48
0
    public static void Host_Kick_f()
    {
        if (cmd_source == cmd_source_t.src_command)
        {
            if (!sv.active)
            {
                Cmd_ForwardToServer();
                return;
            }
        }
        else if (pr_global_struct.deathmatch != 0 && !host_client.privileged)
        {
            return;
        }

        client_t save     = host_client;
        bool     byNumber = false;
        int      i;

        if (cmd_argc > 2 && Cmd_Argv(1) == "#")
        {
            i = (int)atof(Cmd_Argv(2)) - 1;
            if (i < 0 || i >= svs.maxclients)
            {
                return;
            }
            if (!svs.clients[i].active)
            {
                return;
            }

            host_client = svs.clients[i];
            byNumber    = true;
        }
        else
        {
            for (i = 0; i < svs.maxclients; i++)
            {
                host_client = svs.clients[i];
                if (!host_client.active)
                {
                    continue;
                }
                if (SameText(host_client.name, Cmd_Argv(1)))
                {
                    break;
                }
            }
        }

        if (i < svs.maxclients)
        {
            string who;
            if (cmd_source == cmd_source_t.src_command)
            {
                if (cls.state == cactive_t.ca_dedicated)
                {
                    who = "Console";
                }
                else
                {
                    who = cl_name.@string;
                }
            }
            else
            {
                who = save.name;
            }

            // can't kick yourself!
            if (host_client == save)
            {
                return;
            }

            string message = null;
            if (cmd_argc > 2)
            {
                message = COM_Parse(cmd_args);
                if (byNumber)
                {
                    message = message.Substring(1);                  // skip the #
                    message = message.Trim();                        // skip white space
                    message = message.Substring(Cmd_Argv(2).Length); // skip the number
                }
                message = message.Trim();
            }
            if (!String.IsNullOrEmpty(message))
            {
                SV_ClientPrintf("Kicked by {0}: {1}\n", who, message);
            }
            else
            {
                SV_ClientPrintf("Kicked by {0}\n", who);
            }
            SV_DropClient(false);
        }

        host_client = save;
    }
Beispiel #49
0
        /*
        =======================
        SV_SendClientDatagram
        =======================
        */
        static bool SV_SendClientDatagram(client_t client)
        {
            byte[]		        buf = new byte[quakedef.MAX_DATAGRAM];
            common.sizebuf_t    msg = new common.sizebuf_t();

            msg.data = buf;
            msg.maxsize = buf.Length;
            msg.cursize = 0;

            common.MSG_WriteByte (msg, net.svc_time);
            common.MSG_WriteFloat (msg, sv.time);

            // add the client specific data to the datagram
            SV_WriteClientdataToMessage(client.edict, msg);

            SV_WriteEntitiesToClient(client.edict, msg);

            // copy the server datagram if there is space
            if (msg.cursize + sv.datagram.cursize < msg.maxsize)
                common.SZ_Write(msg, sv.datagram.data, sv.datagram.cursize);

            // send the datagram
            if (net.NET_SendUnreliableMessage (client.netconnection, msg) == -1)
            {
                return false;
            }

            return true;
        }
Beispiel #50
0
    public static void Host_Status_f()
    {
        bool flag = true;

        if (cmd_source == cmd_source_t.src_command)
        {
            if (!sv.active)
            {
                Cmd_ForwardToServer();
                return;
            }
        }
        else
        {
            flag = false;
        }

        StringBuilder sb = new StringBuilder(256);

        sb.Append(String.Format("host:    {0}\n", Cvar.Cvar_VariableString("hostname")));
        sb.Append(String.Format("version: {0:F2}\n", q_shared.VERSION));
        if (NetTcpIp.Instance.IsInitialized)
        {
            sb.Append("tcp/ip:  ");
            sb.Append(my_tcpip_address);
            sb.Append('\n');
        }

        sb.Append("map:     ");
        sb.Append(sv.name);
        sb.Append('\n');
        sb.Append(String.Format("players: {0} active ({1} max)\n\n", net_activeconnections, svs.maxclients));
        for (int j = 0; j < svs.maxclients; j++)
        {
            client_t client = svs.clients[j];
            if (!client.active)
            {
                continue;
            }

            int seconds = (int)(net_time - client.netconnection.connecttime);
            int hours, minutes = seconds / 60;
            if (minutes > 0)
            {
                seconds -= (minutes * 60);
                hours    = minutes / 60;
                if (hours > 0)
                {
                    minutes -= (hours * 60);
                }
            }
            else
            {
                hours = 0;
            }
            sb.Append(String.Format("#{0,-2} {1,-16}  {2}  {2}:{4,2}:{5,2}",
                                    j + 1, client.name, (int)client.edict.v.frags, hours, minutes, seconds));
            sb.Append("   ");
            sb.Append(client.netconnection.address);
            sb.Append('\n');
        }

        if (flag)
        {
            Con_Printf(sb.ToString());
        }
        else
        {
            SV_ClientPrintf(sb.ToString());
        }
    }
Beispiel #51
0
        private void AddServerCommand(client_t client, string cmd)
        {
            // do not send commands until the gamestate has been sent
            if (client.state < clientState_t.CS_PRIMED)
            {
                return;
            }

            client.reliableSequence++;
            // if we would be losing an old command that hasn't been acknowledged,
            // we must drop the connection
            // we check == instead of >= so a broadcast print added by SV_DropClient()
            // doesn't cause a recursive drop client
            if (client.reliableSequence - client.reliableAcknowledge == 64 + 1)
            {
                Common.Instance.WriteLine("======== pending server commands =========");
                int i;
                for (i = client.reliableAcknowledge+1; i <= client.reliableSequence; i++)
                {
                    Common.Instance.WriteLine("cmd {0}: {1}", i, client.reliableCommands[i & 63]);
                }
                Common.Instance.WriteLine("cmd {0}: {1}", i, cmd);
                DropClient(client, "Server command overflow");
                return;
            }
            int index = client.reliableSequence & 63;
            client.reliableCommands[index] = cmd;
        }
Beispiel #52
0
        private void SetUserInfo(client_t cl, string p)
        {
            if (cl == null || p == null)
                return;

            foreach (client_t client in clients)
            {
                if (client.Equals(cl))
                {
                    client.userinfo = p;
                    client.name = Info.ValueForKey(p, "name");

                    break;
                }
            }
        }
Beispiel #53
0
        /*
        =============================================================================

        EVENT MESSAGES

        =============================================================================
        */
        /*
        ==============================================================================

        CLIENT SPAWNING

        ==============================================================================
        */
        /*
        ================
        SV_SendServerinfo

        Sends the first message from the server to a connected client.
        This will be sent on the initial connection and upon each server load.
        ================
        */
        static void SV_SendServerinfo(client_t client)
        {
            int             i;
            string          s;
            string			message;

            common.MSG_WriteByte (client.message, net.svc_print);
            message = "\u0002\nVERSION " + quakedef.VERSION + " SERVER (" + prog.pr_crc + " CRC)";
            common.MSG_WriteString(client.message, message);

            common.MSG_WriteByte(client.message, net.svc_serverinfo);
            common.MSG_WriteLong(client.message, net.PROTOCOL_VERSION);
            common.MSG_WriteByte(client.message, svs.maxclients);

            if (host.coop.value == 0 && host.deathmatch.value != 0)
                common.MSG_WriteByte(client.message, net.GAME_DEATHMATCH);
            else
                common.MSG_WriteByte(client.message, net.GAME_COOP);

            //sprintf(message, pr_strings + sv.edicts->v.message);
            message = prog.pr_string(sv.edicts[0].v.message);

            common.MSG_WriteString(client.message, message);

            for (i = 1, s = sv.model_precache[i]; s != null; i++)
            {
                s = sv.model_precache[i];
                common.MSG_WriteString(client.message, s);
            }
            common.MSG_WriteByte(client.message, 0);

            for (i = 1, s = sv.sound_precache[i]; s != null; i++)
            {
                s = sv.sound_precache[i];
                common.MSG_WriteString(client.message, s);
            }
            common.MSG_WriteByte(client.message, 0);

            // send music
            common.MSG_WriteByte(client.message, net.svc_cdtrack);
            common.MSG_WriteByte(client.message, (int)sv.edicts[0].v.sounds);
            common.MSG_WriteByte(client.message, (int)sv.edicts[0].v.sounds);

            // set view
            common.MSG_WriteByte (client.message, net.svc_setview);
            common.MSG_WriteShort (client.message, prog.NUM_FOR_EDICT(client.edict));

            common.MSG_WriteByte(client.message, net.svc_signonnum);
            common.MSG_WriteByte(client.message, 1);

            client.sendsignon = true;
            client.spawned = false;		// need prespawn, spawn, etc
        }
Beispiel #54
0
        /*
        =============
        SV_BuildClientSnapshot

        Decides which entities are going to be visible to the client, and
        copies off the playerstate and areabits.

        This properly handles multiple recursive portals, but the render
        currently doesn't.

        For viewing through other player's eyes, clent can be something other than client->gentity
        =============
        */
        void BuildClientSnapshot(client_t client, int index)
        {
            List<int> snapshotEntityNumbers = new List<int>();
            // bump the counter used to prevent double adding
            sv.snapshotCounter++;

            // this is the frame we are creating
            clientSnapshot_t frame = client.frames[client.netchan.outgoingSequence & 31];

            // clear everything in this snapshot
            frame.num_entities = 0;
            frame.areabits = new byte[32];

            sharedEntity clent = client.gentity;
            if (clent == null || client.state == clientState_t.CS_ZOMBIE)
            {
                return;
            }

            // grab the current playerState_t
            Common.PlayerState ps = GameClientNum(index);

            //frame.ps = ps;
            frame.ps = ps.Clone();

            // never send client's own entity, because it can
            // be regenerated from the playerstate
            int clientnum = frame.ps.clientNum;
            if (clientnum < 0 || clientnum >= 1024)
            {
                Common.Instance.Error("bad gEnt");
            }

            svEntity_t svEnt = sv.svEntities[clientnum];
            svEnt.snapshotCounter = sv.snapshotCounter;

            // find the client's viewpoint
            Vector3 org = ps.origin;
            org[2] += ps.viewheight;

            // add all the entities directly visible to the eye, which
            // may include portal entities that merge other viewpoints
            AddEntitiesVisibleFromPoint(org, ref frame, snapshotEntityNumbers, false);

            // if there were portals visible, there may be out of order entities
            // in the list which will need to be resorted for the delta compression
            // to work correctly.  This also catches the error condition
            // of an entity being included twice.
            snapshotEntityNumbers.Sort((a, b) => { return a.CompareTo(b); });

            // now that all viewpoint's areabits have been OR'd together, invert
            // all of them to make it a mask vector, which is what the renderer wants
            for (int i = 0; i < 8; i++)
            {
                frame.areabits[i] = (byte)(frame.areabits[i] ^ -1);
            }

            // copy the entity states out
            frame.num_entities = 0;
            frame.first_entity = nextSnapshotEntities;
            for (int i = 0; i < snapshotEntityNumbers.Count; i++)
            {

                sharedEntity ent = sv.gentities[snapshotEntityNumbers[i]];
                snapshotEntities[nextSnapshotEntities++ % numSnapshotEntities] = new Common.entityState_t() { angles = ent.s.angles, angles2 = ent.s.angles2, apos = ent.s.apos, clientNum = ent.s.clientNum, eFlags = ent.s.eFlags, eType = ent.s.eType
                , frame = ent.s.frame, groundEntityNum = ent.s.groundEntityNum, number = ent.s.number, pos = ent.s.pos, solid = ent.s.solid, origin = ent.s.origin, otherEntityNum = ent.s.otherEntityNum, time = ent.s.time, modelindex = ent.s.modelindex};
                //Common.Instance.WriteLine("Sending ent {0} to client {1}", snapshotEntityNumbers[i], index);
                frame.num_entities++;
            }
        }
Beispiel #55
0
        /*
        ===============
        SV_UpdateConfigstrings

        Called when a client goes from CS_PRIMED to CS_ACTIVE.  Updates all
        Configstring indexes that have changed while the client was in CS_PRIMED
        ===============
        */
        void UpdateConfigStrings(client_t cl)
        {
            for (int i = 0; i < cl.csUpdated.Length; i++)
            {
                // if the CS hasn't changed since we went to CS_PRIMED, ignore
                if (!cl.csUpdated[i])
                    continue;
                // do not always send server info to all clients
                if (i == (int)ConfigString.CS_SERVERINFO && cl.gentity != null
                    && (cl.gentity.r.svFlags & Common.svFlags.NOSERVERINFO) == Common.svFlags.NOSERVERINFO)
                {
                    continue;
                }

                SendConfigString(cl, i);
                cl.csUpdated[i] = false;
            }
        }
Beispiel #56
0
        /*
        ====================
        SV_RateMsec

        Return the number of msec a given size message is supposed
        to take to clear, based on the current rate
        ====================
        */
        int RateMsec(client_t client, int msgSize)
        {
            int headerSize = 48;
            //// individual messages will never be larger than fragment size
            //if (msgSize > 1500)
            //    msgSize = 1500;

            int rate = client.rate; // FIX: variable rate

            int rateMsec = (int)((msgSize + headerSize) * 1000 / rate * Common.Instance.timescale.Value);
            return rateMsec;
        }
Beispiel #57
0
        void ExecuteClientMessage(client_t cl, NetBuffer buf)
        {
            int serverId = buf.ReadInt32();
            cl.messageAcknowledge = buf.ReadInt32();
            if (cl.messageAcknowledge < 0)
            {
                // usually only hackers create messages like this
                // it is more annoying for them to let them hanging
                DropClient(cl, "Illegible client message");
                return;
            }

            cl.reliableAcknowledge = buf.ReadInt32();
            // NOTE: when the client message is fux0red the acknowledgement numbers
            // can be out of range, this could cause the server to send thousands of server
            // commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient
            if (cl.reliableAcknowledge < cl.reliableSequence - 64)
            {
                DropClient(cl, "Illegible client message");
                cl.reliableAcknowledge = cl.reliableSequence;
                return;
            }

            // if this is a usercmd from a previous gamestate,
            // ignore it or retransmit the current gamestate
            //
            if (serverId != sv.serverId && !cl.lastClientCommandString.Equals("nextdl"))
            {
                if (serverId >= sv.restartedServerId && serverId < sv.serverId)
                {
                    // they just haven't caught the map_restart yet
                    Common.Instance.WriteLine("{0} : ignoring pre map_restart / outdated client message", cl.name);
                    return;
                }

                // if we can tell that the client has dropped the last
                // gamestate we sent them, resend it
                if (cl.messageAcknowledge > cl.gamestateMessageNum)
                {
                    Common.Instance.WriteLine("{0} : dropped gamestate, resending", cl.name);
                    SendClientGameState(cl);
                }
                return;
            }

            // this client has acknowledged the new gamestate so it's
            // safe to start sending it the real time again
            if (cl.oldServerTime > 0 && serverId == sv.serverId)
            {
                Common.Instance.WriteLine("{0} acknowledged gamestate", cl.name);
                cl.oldServerTime = 0;
            }

            // read optional clientCommand strings
            int c;
            do
            {
                c = buf.ReadByte();

                if (c == (int)clc_ops_e.clc_EOF)
                    break;

                if (c != (int)clc_ops_e.clc_clientCommand)
                    break;

                if (!ClientCommand(cl, buf))
                    break;  // we couldn't execute it because of the flood protection

                if (cl.state == clientState_t.CS_ZOMBIE)
                    return; // disconnect command
            } while (true);

            // read the usercmd_t
            if (c == (int)clc_ops_e.clc_move)
            {
                UserMove(cl, buf, true);
            }
            else if (c == (int)clc_ops_e.clc_moveNoDelta)
            {
                UserMove(cl, buf, false);
            }
            else if (c != (int)clc_ops_e.clc_EOF)
            {
                Common.Instance.WriteLine("WARNING: bad command byte for client {0}", cl.name);
            }
        }