Esempio n. 1
0
        private void parseGameState(Q3HuffmanReader reader)
        {
            reader.readLong();

            while (true)
            {
                byte cmd = reader.readByte();
                if (cmd == Q3_SVC.EOF)
                {
                    break;
                }

                switch (cmd)
                {
                case Q3_SVC.CONFIGSTRING:
                    short key = reader.readShort();
                    if (key < 0 || key > Q3Const.MAX_CONFIGSTRINGS)
                    {
                        return;
                    }
                    clc.configs[key] = reader.readBigString();
                    break;

                case Q3_SVC.BASELINE:
                    long newnum = reader.readNumBits(Q3Const.GENTITYNUM_BITS);
                    if (newnum < 0 || newnum >= Q3Const.MAX_GENTITIES)
                    {
                        Q3Utils.PrintDebug(clc.errors, "Baseline number out of range: {0}", newnum);
                        return;
                    }

                    EntityState es = Ext2 <long, EntityState> .GetOrCreate(clc.entityBaselines, newnum);

                    if (!reader.readDeltaEntity(es, (int)newnum))
                    {
                        Q3Utils.PrintDebug(clc.errors, "unable to parse delta-entity state");
                        return;
                    }
                    break;

                default:
                    Q3Utils.PrintDebug(clc.errors, "bad command in parseGameState");
                    return;
                }
            }

            //clc.clientNum
            clc.clientNum = reader.readLong();

            //clc.checksumFeed
            clc.checksumFeed = reader.readLong();
        }
Esempio n. 2
0
        public bool readDeltaPlayerState(PlayerState state)
        {
            int lc = readByte();

            if (lc < 0 || lc > MapperFactory.PlayerStateFieldNum)
            {
                Q3Utils.PrintDebug("invalid entityState field count: {" + lc + "}");
                return(false);
            }

            for (int i = 0; i < lc; i++)
            {
                if (readNumBits(1) == 0)
                {
                    // no change;
                    continue;
                }

                MapperFactory.updatePlayerState(state, i, this, false);
            }

            // read arrays
            if (readNumBits(1) != 0)
            {
                //parse stats
                if (readNumBits(1) != 0)
                {
                    pstArrayRead(state.stats, Q3Const.MAX_STATS);
                }

                // parse persistant stats
                if (readNumBits(1) != 0)
                {
                    pstArrayRead(state.persistant, Q3Const.MAX_PERSISTANT);
                }

                // parse ammo
                if (readNumBits(1) != 0)
                {
                    pstArrayRead(state.ammo, Q3Const.MAX_WEAPONS);
                }

                // parse powerups
                if (readNumBits(1) != 0)
                {
                    pstLongArrayRead(state.powerups, Q3Const.MAX_POWERUPS);
                }
            }

            return(true);
        }
Esempio n. 3
0
        private Q3DemoConfigParser doParse(Q3DemoConfigParser msgParser)
        {
            Q3MessageStream messageStream = new Q3MessageStream(this.file_name);

            try
            {
                Q3DemoMessage msg = null;
                while ((msg = messageStream.nextMessage()) != null)
                {
                    if (!msgParser.parse(msg))
                    {
                        break;
                    }
                }
            }
            catch (Exception r) {
                Q3Utils.PrintDebug(msgParser.clc.errors, r.Message);
            }
            messageStream.close();
            return(msgParser);
        }
Esempio n. 4
0
        public bool readDeltaEntity(EntityState state, int number)
        {
            if (readNumBits(1) == 1)
            {
                state.number = Q3Const.MAX_GENTITIES - 1;
                // clear state and return
                return(true);
            }

            // check for no delta
            if (readNumBits(1) == 0)
            {
                state.number = number;
                return(true);
            }

            int lc = readByte();

            if (lc < 0 || lc > MapperFactory.EntityStateFieldNum)
            {
                Q3Utils.PrintDebug("invalid entityState field count: {" + lc + "}");
                return(false);
            }

            state.number = number;
            for (int i = 0; i < lc; i++)
            {
                if (readNumBits(1) == 0)
                {
                    //no change
                    continue;
                }

                bool reset = readNumBits(1) == 0;
                MapperFactory.updateEntityState(state, i, this, reset);
            }

            return(true);
        }
Esempio n. 5
0
        public Dictionary <string, Dictionary <string, string> > getFriendlyInfo()
        {
            if (friendlyInfo != null)
            {
                return(friendlyInfo);
            }

            //All players
            var keyP = Q3Const.Q3_DEMO_CFG_FIELD_PLAYER;

            for (short i = 0; i < 32; i++)
            {
                var k1 = (short)(keyP + i);
                if (rawConfig.ContainsKey(k1))
                {
                    allPlayersConfigs.Add(k1, split_config_player(rawConfig[k1]));
                }
            }

            //Current player
            if (fin.HasValue)
            {
                kPlayer = getPlayerInfoByPlayerNum(fin.Value.Value.playerNum);
            }
            if (kPlayer == null && clientEvents.Count > 0)
            {
                //if spectator view player and there was no finish
                var lastEvent = clientEvents.LastOrDefault();
                if (lastEvent != null)
                {
                    kPlayer = getPlayerInfoByPlayerNum(lastEvent.playerNum);
                }
            }
            if (kPlayer == null)
            {
                kPlayer = getPlayerInfoByPlayerNum(clc.clientNum);
            }
            var keys = allPlayersConfigs.Keys.ToList();

            if (kPlayer == null && keys.Count == 1)
            {
                kPlayer = allPlayersConfigs[keys[0]];
            }

            friendlyInfo = new Dictionary <string, Dictionary <string, string> >();

            //console Times
            Dictionary <string, string> times = new Dictionary <string, string>();

            times.Add(keyDemoName, new FileInfo(demoPath).Name);
            if (timeStrings.Count > 0)
            {
                var strInfo = GetGoodTimeStringInfo();
                if (strInfo != null)
                {
                    if (!string.IsNullOrEmpty(strInfo.recordDateString))
                    {
                        times.Add(keyRecordDate, strInfo.recordDateString);
                    }
                    times.Add(keyRecordTime, strInfo.timeString);
                }
                else
                {
                    for (int i = 0; i < timeStrings.Count; i++)
                    {
                        var timeInfo = timeStrings[i];
                        if (!string.IsNullOrEmpty(timeInfo.recordDateString))
                        {
                            string keyDate = timeStrings.Count > 1 ? keyRecordDate + " " + (i + 1) : keyRecordDate;
                            times.Add(keyDate, timeInfo.recordDateString);
                        }
                        string keyTime = timeStrings.Count > 1 ? keyRecordTime + " " + (i + 1) : keyRecordTime;
                        times.Add(keyTime, timeInfo.timeString);
                    }
                }
            }
            if (fin != null)
            {
                string bestTime = getTimeByMillis(fin.Value.Value.time);
                bool   hasTr    = fin.Value.Key > 1;
                string trAdd    = hasTr ? " (Time reset)" : "";
                times.Add(keyBestTime, bestTime + trAdd);
            }

            friendlyInfo.Add(keyRecord, times);

            //demo triggers
            if (clientEvents != null && clientEvents.Count > 0)
            {
                Dictionary <string, string> triggers = new Dictionary <string, string>();
                try {
                    int stCount = 0;
                    int trCount = 0;
                    int cpCount = 0;
                    int ftCount = 0;
                    int pmCount = 0;
                    int cuCount = 0;
                    int tCount  = 0;

                    for (int i = 0; i < clientEvents.Count; i++)
                    {
                        ClientEvent ce   = clientEvents[i];
                        string      diff = "";
                        if (i > 0)
                        {
                            var  prev = clientEvents[i - 1];
                            long t    = ce.serverTime - prev.serverTime;
                            if (t > 0 && prev.serverTime > 0)
                            {
                                diff = string.Format(" (+{0})", getDiffByMillis(t));
                            }
                        }
                        if (ce.eventStartFile)
                        {
                            var user = getPlayerInfoByPlayerNum(clc.clientNum);
                            if (user == null)
                            {
                                user = getPlayerInfoByPlayerNum(ce.playerNum);
                            }
                            string username   = user == null ? null : Ext.GetOrNull(user, "name");
                            string userString = string.IsNullOrEmpty(username) ? "" : "Client: " + username;
                            triggers.Add("StartFile", userString);
                        }
                        if (ce.eventStartTime)
                        {
                            var    user       = getPlayerInfoByPlayerNum(ce.playerNum);
                            string username   = user == null ? null : Ext.GetOrNull(user, "name");
                            string userString = string.IsNullOrEmpty(username) ? "" : "Player: " + username;
                            triggers.Add("StartTimer" + getNumKey(++stCount), userString + diff);
                        }
                        if (ce.eventTimeReset)
                        {
                            var    user       = getPlayerInfoByPlayerNum(ce.playerNum);
                            string username   = user == null ? null : Ext.GetOrNull(user, "name");
                            string userString = string.IsNullOrEmpty(username) ? "" : "Player: " + username;
                            triggers.Add("TimeReset" + getNumKey(++trCount), userString + diff);
                        }
                        if (ce.eventFinish)
                        {
                            triggers.Add("FinishTimer" + getNumKey(++ftCount), getTimeByMillis(ce.time) + diff);
                        }
                        if (ce.eventCheckPoint)
                        {
                            triggers.Add("CheckPoint" + getNumKey(++cpCount), getTimeByMillis(ce.time) + diff);
                        }
                        if (ce.eventChangePmType)
                        {
                            string pmString = ce.playerMode < ClientEvent.pmTypesStrings.Length
                                ? ClientEvent.pmTypesStrings[ce.playerMode] : ce.playerMode.ToString();
                            triggers.Add("ChangePlayerMode" + getNumKey(++pmCount), pmString + diff);
                        }
                        if (ce.eventSomeTrigger && ce.playerMode == (int)ClientEvent.PlayerMode.PM_NORMAL)
                        {
                            triggers.Add("EventTrigger" + getNumKey(++tCount), getTimeByMillis(ce.time) + diff);
                        }
                        if (ce.eventChangeUser)
                        {
                            var    user       = getPlayerInfoByPlayerNum(ce.playerNum);
                            string username   = user == null ? null : Ext.GetOrNull(user, "name");
                            string userString = string.IsNullOrEmpty(username) ? "" : "Player: " + username;
                            triggers.Add("ChangeUser" + getNumKey(++cuCount), userString + diff);
                        }
                    }
                } catch (Exception ex) {
                    Q3Utils.PrintDebug(clc.errors, ex.Message);
                }
                friendlyInfo.Add(keyTriggers, triggers);
            }

            if (rawConfig == null)
            {
                return(friendlyInfo);
            }

            //Player
            if (kPlayer != null)
            {
                friendlyInfo.Add(keyPlayer, kPlayer);
            }
            else
            {
                for (int i = 0; i < keys.Count; i++)
                {
                    friendlyInfo.Add(keyPlayer + " " + (i + 1).ToString(), allPlayersConfigs[keys[i]]);
                }
            }

            Dictionary <string, string> clInfo = null;
            Dictionary <string, string> gInfo  = null;

            if (rawConfig.ContainsKey(Q3Const.Q3_DEMO_CFG_FIELD_CLIENT))
            {
                clInfo = Q3Utils.split_config(rawConfig[Q3Const.Q3_DEMO_CFG_FIELD_CLIENT]);
            }
            if (rawConfig.ContainsKey(Q3Const.Q3_DEMO_CFG_FIELD_GAME))
            {
                gInfo = split_config_game(rawConfig[Q3Const.Q3_DEMO_CFG_FIELD_GAME]);
            }

            //Gametype
            var parameters = Ext.Join(clInfo, gInfo);

            gameInfo = new GameInfo(parameters);
            var gameInfoDict = new Dictionary <string, string>();

            if (parameters.Count > 0)
            {
                bool diff = gameInfo.gameName.ToLowerInvariant() != gameInfo.gameNameShort.ToLowerInvariant();
                if (diff)
                {
                    gameInfoDict.Add("gameName", string.Format("{0} ({1})", gameInfo.gameName, gameInfo.gameNameShort));
                }
                else
                {
                    gameInfoDict.Add("gameName", gameInfo.gameName);
                }
                gameInfoDict.Add("gameType", string.Format("{0} ({1})", gameInfo.gameType, gameInfo.gameTypeShort));
                if (!string.IsNullOrEmpty(gameInfo.gameplayTypeShort))
                {
                    gameInfoDict.Add("gameplay", string.Format("{0} ({1})", gameInfo.gameplayType, gameInfo.gameplayTypeShort));
                }
                if (!string.IsNullOrEmpty(gameInfo.modType))
                {
                    gameInfoDict.Add("modType", string.Format("{0} ({1})", gameInfo.modTypeName, gameInfo.modType));
                }
            }

            //Game
            var game = Ext.Join(gameInfoDict, gInfo);

            if (game.Count > 0)
            {
                friendlyInfo.Add(keyGame, game);
            }

            //Client
            if (clInfo != null)
            {
                friendlyInfo.Add(keyClient, clInfo);
            }

            //Raw configs
            Dictionary <string, string> raw = new Dictionary <string, string>();

            foreach (var r in rawConfig)
            {
                raw.Add(r.Key.ToString(), r.Value);
            }
            friendlyInfo.Add(keyRaw, raw);

            //Console commands
            if (clc.console.Count > 0)
            {
                Dictionary <string, string> conTexts = new Dictionary <string, string>();
                foreach (var kv in clc.console)
                {
                    conTexts.Add(kv.Key.ToString(), removeColors(kv.Value.ToString()));
                }
                friendlyInfo.Add(keyConsole, conTexts);
            }
            if (clc.errors.Count > 0)
            {
                Dictionary <string, string> errTexts = new Dictionary <string, string>();
                int i = 0;
                foreach (var kv in clc.errors)
                {
                    errTexts.Add((++i).ToString(), kv.Key.ToString());
                }
                friendlyInfo.Add(keyErrors, errTexts);
            }

            return(friendlyInfo);
        }
Esempio n. 6
0
        private long getTime(PlayerState ps, int snap_serverTime, int df_ver, int mapNameChecksum)
        {
            int time = shl32(ps.stats[7], 0x10) | (ps.stats[8] & 0xffff);

            if (time == 0)
            {
                return(0);
            }
            //encryption in cheated demos changed somewhere between >=19110 and <=19112
            if (client.isOnline || (df_ver >= 19112 && client.isCheatsOn))
            {
                return(time);
            }

            time ^= Math.Abs((int)(Math.Floor(ps.origin[0]))) & 0xffff;
            time ^= shl32(Math.Abs((int)Math.Floor(ps.velocity[0])), 0x10);
            time ^= ps.stats[0] > 0 ? ps.stats[0] & 0xff : 150;
            time ^= shl32(ps.movementDir & 0xf, 0x1c);

            //if time was byte array(least significant at time[0]):
            //time[3] ^= time[2]
            //time[2] ^= time[1]
            //time[1] ^= time[0]
            //time[0] unchanged

            for (int i = 0x18; i > 0; i -= 8)
            {
                var temp = (shr32(time, i) ^ shr32(time, i - 8)) & 0xff;
                time = (time & ~shl32(0xff, i)) | shl32(temp, i);
            }

            var local1c = shl32(snap_serverTime, 2);

            //df_ver = 19124;
            //map_type = 24; // global_11cdc8, not sure why i called this map_type
            local1c += shl32(df_ver + mapNameChecksum, 8);
            local1c ^= shl32(snap_serverTime, 0x18);
            time    ^= local1c;
            local1c  = shr32(time, 0x1c); // time[28:32]
            local1c |= shl32(~local1c, 4) & 0xff;
            local1c |= shl32(local1c, 8);
            local1c |= shl32(local1c, 0x10);
            time    ^= local1c;
            local1c  = shr32(time, 0x16) & 0x3f; // time[22:28]
            time    &= 0x3fffff;

            // local20 = time[0:6] + time[6:12] + time[12:18] ...
            var local20 = 0;

            for (int l = 0; l < 3; l++)
            {
                local20 += shr32(time, 6 * l) & 0x3f;
            }

            // ... + time[18:22]
            local20 += shr32(time, 0x12) & 0xf;

            if (local1c != (local20 & 0x3f))
            {
                Q3Utils.PrintDebug(clc.errors, "bad checksum at decoding demo time");
            }
            return(time);
        }
Esempio n. 7
0
        private void parsePacketEntities(Q3HuffmanReader decoder, CLSnapshot oldframe, CLSnapshot newframe)
        {
            newframe.parseEntitiesNum = client.parseEntitiesNum;
            newframe.numEntities      = 0;
            int         newnum   = 0;
            int         oldindex = 0;
            int         oldnum   = 0;
            EntityState oldstate = null;

            if (oldframe == null)
            {
                oldnum = 99999;
            }
            else
            {
                if (oldindex >= oldframe.numEntities)
                {
                    oldnum = 99999;
                }
                else
                {
                    oldstate = Ext2 <int, EntityState> .GetOrCreate(client.parseEntities, (oldframe.parseEntitiesNum + oldindex)& (Q3Const.MAX_PARSE_ENTITIES - 1));

                    oldnum = oldstate.number;
                }
            }

            while (true)
            {
                newnum = (int)decoder.readNumBits(Q3Const.GENTITYNUM_BITS);

                if (newnum == (Q3Const.MAX_GENTITIES - 1))
                {
                    break;
                }

                if (decoder.isEOD())
                {
                    Q3Utils.PrintDebug(clc.errors, "ERR_DROP, CL_ParsePacketEntities: end of message");
                    return;
                }

                while (oldnum < newnum)
                {
                    // one or more entities from the old packet are unchanged
                    CL_DeltaEntity(decoder, newframe, oldnum, oldstate, true);

                    oldindex++;

                    if (oldindex >= oldframe.numEntities)
                    {
                        oldnum = 99999;
                    }
                    else
                    {
                        oldstate = Ext2 <int, EntityState> .GetOrCreate(client.parseEntities,
                                                                        (oldframe.parseEntitiesNum + oldindex)& (Q3Const.MAX_PARSE_ENTITIES - 1));

                        oldnum = oldstate.number;
                    }
                }

                if (oldnum == newnum)
                {
                    // delta from previous state
                    CL_DeltaEntity(decoder, newframe, newnum, oldstate, false);

                    oldindex++;

                    if (oldindex >= oldframe.numEntities)
                    {
                        oldnum = 99999;
                    }
                    else
                    {
                        oldstate = Ext2 <int, EntityState> .GetOrCreate(client.parseEntities,
                                                                        (oldframe.parseEntitiesNum + oldindex)& (Q3Const.MAX_PARSE_ENTITIES - 1));

                        oldnum = oldstate.number;
                    }
                    continue;
                }

                if (oldnum > newnum)
                {
                    // delta from baseline
                    EntityState es = Ext2 <int, EntityState> .GetOrCreate(client.entityBaselines, newnum);

                    CL_DeltaEntity(decoder, newframe, newnum, es, false);
                    continue;
                }
            }

            // any remaining entities in the old frame are copied over
            while (oldnum != 99999)
            {
                // one or more entities from the old packet are unchanged
                CL_DeltaEntity(decoder, newframe, oldnum, oldstate, true);

                oldindex++;

                if (oldindex >= oldframe.numEntities)
                {
                    oldnum = 99999;
                }
                else
                {
                    oldstate = Ext2 <int, EntityState> .GetOrCreate(client.parseEntities,
                                                                    (oldframe.parseEntitiesNum + oldindex)& (Q3Const.MAX_PARSE_ENTITIES - 1));

                    oldnum = oldstate.number;
                }
            }
        }
Esempio n. 8
0
        private void parseSnapshot(Q3HuffmanReader decoder)
        {
            if (client.clientConfig == null)
            {
                client.clientConfig = new Dictionary <string, string>();

                if (clc.configs.ContainsKey(Q3Const.Q3_DEMO_CFG_FIELD_GAME))
                {
                    var gameConfig = Q3Utils.split_config(clc.configs[Q3Const.Q3_DEMO_CFG_FIELD_GAME]);
                    client.isCheatsOn = Ext.GetOrZero(gameConfig, "sv_cheats") > 0;
                }
                if (clc.configs.ContainsKey(Q3Const.Q3_DEMO_CFG_FIELD_CLIENT))
                {
                    client.clientConfig    = Q3Utils.split_config(clc.configs[Q3Const.Q3_DEMO_CFG_FIELD_CLIENT]);
                    client.dfvers          = Ext.GetOrZero(client.clientConfig, "defrag_vers");
                    client.mapname         = Ext.GetOrNull(client.clientConfig, "mapname");
                    client.mapNameChecksum = getMapNameChecksum(client.mapname);
                    client.isOnline        = Ext.GetOrZero(client.clientConfig, "defrag_gametype") > 4;
                }
            }

            CLSnapshot newSnap = new CLSnapshot();
            CLSnapshot old     = null;

            newSnap.serverCommandNum = clc.serverCommandSequence;
            newSnap.serverTime       = decoder.readLong();
            newSnap.messageNum       = clc.serverMessageSequence;

            int deltaNum = decoder.readByte();

            if (deltaNum == 0)
            {
                newSnap.deltaNum = -1;
            }
            else
            {
                newSnap.deltaNum = newSnap.messageNum - deltaNum;
            }
            newSnap.snapFlags = decoder.readByte();
            // If the frame is delta compressed from data that we
            // no longer have available, we must suck up the rest of
            // the frame, but not use it, then ask for a non-compressed
            // message
            if (newSnap.deltaNum <= 0)
            {
                newSnap.valid   = true;        // uncompressed frame
                old             = null;
                clc.demowaiting = false;       // we can start recording now
            }
            else
            {
                old = Ext2 <int, CLSnapshot> .GetOrCreate(client.snapshots, newSnap.deltaNum& Q3Const.PACKET_MASK);

                if (old == null || !old.valid)
                {
                    // should never happen
                    Q3Utils.PrintDebug(clc.errors, "Delta from invalid frame (not supposed to happen!)");
                }
                else if (old.messageNum != newSnap.deltaNum)
                {
                    // The frame that the server did the delta from
                    // is too old, so we can't reconstruct it properly.
                    Q3Utils.PrintDebug(clc.errors, "Delta frame too old.");
                }
                else if ((client.parseEntitiesNum - old.parseEntitiesNum) > (Q3Const.MAX_PARSE_ENTITIES - 128))
                {
                    Q3Utils.PrintDebug(clc.errors, "Delta parseEntitiesNum too old");
                }
                else
                {
                    newSnap.valid = true;  // valid delta parse
                }
            }

            int len = decoder.readByte();

            if (len > newSnap.areamask.Length)
            {
                Q3Utils.PrintDebug(clc.errors, "CL_ParseSnapshot: Invalid size {0} for areamask", len);
                return;
            }
            decoder.readData(newSnap.areamask, len);
            if (old != null)
            {
                newSnap.ps.copy(old.ps);
            }
            decoder.readDeltaPlayerState(newSnap.ps);
            parsePacketEntities(decoder, old, newSnap);

            // if not valid, dump the entire thing now that it has
            // been properly read
            if (!newSnap.valid)
            {
                return;
            }

            // clear the valid flags of any snapshots between the last
            // received and this one, so if there was a dropped packet
            // it won't look like something valid to delta from next
            // time we wrap around in the buffer
            int oldMessageNum = client.snap.messageNum + 1;

            if (newSnap.messageNum - oldMessageNum >= Q3Const.PACKET_BACKUP)
            {
                oldMessageNum = newSnap.messageNum - (Q3Const.PACKET_BACKUP - 1);
            }
            for (; oldMessageNum < newSnap.messageNum; oldMessageNum++)
            {
                CLSnapshot s;
                if (client.snapshots.TryGetValue(oldMessageNum & Q3Const.PACKET_MASK, out s))
                {
                    if (s != null)
                    {
                        s.valid = false;
                    }
                }
            }

            // copy to the current good spot
            client.snap = newSnap;

            // skip ping calculations
            client.snap.ping = 0;

            // save the frame off in the backup array for later delta comparisons
            client.snapshots[client.snap.messageNum & Q3Const.PACKET_MASK] = client.snap;

            client.newSnapshots = true;

            updateClientEvents(newSnap);
        }