public void ParseStringTable(IBitStream reader, string tableName, DemoParser parser)
		{
            int numStrings = (int)reader.ReadInt(16);

			if (tableName == "modelprecache") {
				parser.modelprecache.Clear ();
			}

            for (int i = 0; i < numStrings; i++)
            {
                string stringName = reader.ReadString();

                if (stringName.Length >= 100)
                    throw new Exception("Roy said I should throw this.");

                if (reader.ReadBit())
                {
                    int userDataSize = (int)reader.ReadInt(16);

                    byte[] data = reader.ReadBytes(userDataSize);

					if (tableName == "userinfo") {
						PlayerInfo info = PlayerInfo.ParseFrom(new BinaryReader(new MemoryStream(data)));

						parser.RawPlayers[int.Parse(stringName)] = info;
					} else if (tableName == "instancebaseline") {
						int classid = int.Parse(stringName); //wtf volvo?

						parser.instanceBaseline[classid] = data; 
					} else if (tableName == "modelprecache") {
						parser.modelprecache.Add (stringName);
					}
                }
            }

            // Client side stuff
	        if ( reader.ReadBit() )
	        {
		        int numstrings = (int)reader.ReadInt(16);
		        for ( int i = 0 ; i < numstrings; i++ )
		        {
			        reader.ReadString(); // stringname

			        if ( reader.ReadBit() )
			        {
				        int userDataSize = ( int )reader.ReadInt(16);

				        reader.ReadBytes( userDataSize );

			        }
			        else
			        {
			        }
		        }
	        }
        }
		public void ParsePacket(IBitStream reader, DemoParser parser)
        {
			int numTables = reader.ReadByte();

			for (int i = 0; i < numTables; i++) {
				string tableName = reader.ReadString();

				ParseStringTable(reader, tableName, parser);
			}
        }
		public bool TryApplyMessage(ProtoBuf.IExtensible message, DemoParser parser)
		{
			CSVCMsg_UserMessage userMessage = message as CSVCMsg_UserMessage;
			if (userMessage == null)
				return false;

			var messageType = (Messages.ECstrike15UserMessages)userMessage.msg_type;
			// TODO: maybe, like, implement something here one day?
			//Problem: There is no real useful info here if I see it correcly. Sorry.
			return true;
		}
		public static void Apply(UpdateStringTable update, IBitStream reader, DemoParser parser)
		{
			CreateStringTable create = parser.stringTables[update.TableId];
			if (create.Name == "userinfo" || create.Name == "modelprecache" || create.Name == "instancebaseline") {
				/*
				 * Ignore updates for everything except the 3 used tables.
				 * Create a fake CreateStringTable message and parse it.
				 */
				create.NumEntries = update.NumChangedEntries;
				CreateStringTableUserInfoHandler.Apply(create, reader, parser);
			}
		}
Example #5
0
		/// <summary>
		/// Parses a demo-packet. 
		/// </summary>
		/// <param name="bitstream">Bitstream.</param>
		/// <param name="demo">Demo.</param>
		public static void ParsePacket(IBitStream bitstream, DemoParser demo)
        {
			//As long as there is stuff to read
			while (!bitstream.ChunkFinished)
            {
				int cmd = bitstream.ReadProtobufVarInt(); //What type of packet is this?
				int length = bitstream.ReadProtobufVarInt(); //And how long is it?
				bitstream.BeginChunk(length * 8); //read length bytes
				if (cmd == (int)SVC_Messages.svc_PacketEntities) { //Parse packet entities
					new PacketEntities().Parse(bitstream, demo); 
				} else if (cmd == (int)SVC_Messages.svc_GameEventList) { //and all this other stuff
					new GameEventList().Parse(bitstream, demo);
				} else if (cmd == (int)SVC_Messages.svc_GameEvent) {
					new GameEvent().Parse(bitstream, demo);
				} else if (cmd == (int)SVC_Messages.svc_CreateStringTable) {
					new CreateStringTable().Parse(bitstream, demo);
				} else if (cmd == (int)SVC_Messages.svc_UpdateStringTable) {
					new UpdateStringTable().Parse(bitstream, demo);
				} else if (cmd == (int)NET_Messages.net_Tick) { //and all this other stuff
						new NETTick().Parse(bitstream, demo);
				} else {
					//You can use this flag to see what information the other packets contain, 
					//if you want. Then you can look into the objects. Has some advnatages, and some disdavantages (mostly speed), 
					//so we use our own lightning-fast parsing code. 
					#if SLOW_PROTOBUF 
					Type toParse = null;

					if (Enum.IsDefined(typeof(SVC_Messages), cmd)) {
						SVC_Messages msg = (SVC_Messages)cmd;
						toParse = Assembly.GetExecutingAssembly().GetType("DemoInfo.Messages.CSVCMsg_" + msg.ToString().Substring(4));
					} else if (Enum.IsDefined(typeof(NET_Messages), cmd)) {
						NET_Messages msg = (NET_Messages)cmd;
						toParse = Assembly.GetExecutingAssembly().GetType("DemoInfo.Messages.CNETMsg_" + msg.ToString().Substring(4));
					}

					var data = bitstream.ReadBytes(length);
					if (toParse == null)
						continue;

					ProtoBuf.IExtensible result;
					using (var memstream = new MemoryStream(data))
						result = memstream.ReadProtobufMessage(toParse);

					foreach (var parser in Parsers)
						if (parser.TryApplyMessage(result, demo) && (parser.Priority > 0))
							break;
					#endif
				}
				bitstream.EndChunk();
            }
        }
		/// <summary>
		/// Reads an update that occures when a new edict enters the PVS (potentially visible system)
		/// </summary>
		/// <returns>The new Entity.</returns>
        private static Entity ReadEnterPVS(IBitStream reader, int id, DemoParser parser)
        {
			//What kind of entity?
            int serverClassID = (int)reader.ReadInt(parser.SendTableParser.ClassBits);

			//So find the correct server class
            ServerClass entityClass = parser.SendTableParser.ServerClasses[serverClassID];

            reader.ReadInt(10); //Entity serial. 
			//Never used anywhere I guess. Every parser just skips this


			Entity newEntity = new Entity(id, entityClass);

			//give people the chance to subscribe to events for this
			newEntity.ServerClass.AnnounceNewEntity(newEntity);

			//And then parse the instancebaseline. 
			//basically you could call
			//newEntity.ApplyUpdate(parser.instanceBaseline[entityClass]; 
			//This code below is just faster, since it only parses stuff once
			//which is faster. 

			object[] fastBaseline;
			if (parser.PreprocessedBaselines.TryGetValue(serverClassID, out fastBaseline))
				PropertyEntry.Emit(newEntity, fastBaseline);
			else {
				var preprocessedBaseline = new List<object>();
				if (parser.instanceBaseline.ContainsKey(serverClassID))
					using (var collector = new PropertyCollector(newEntity, preprocessedBaseline))
					using (var bitStream = BitStreamUtil.Create(parser.instanceBaseline[serverClassID]))
						newEntity.ApplyUpdate(bitStream);

				parser.PreprocessedBaselines.Add(serverClassID, preprocessedBaseline.ToArray());
			}

            return newEntity;
        }
		/// <summary>
		/// Decodes the bytes in the packet-entites message. 
		/// </summary>
		/// <param name="packetEntities">Packet entities.</param>
		/// <param name="reader">Reader.</param>
		/// <param name="parser">Parser.</param>
		public static void Apply(PacketEntities packetEntities, IBitStream reader, DemoParser parser)
        {
			int currentEntity = -1;

			for (int i = 0; i < packetEntities.UpdatedEntries; i++) {

				//First read which entity is updated
				currentEntity += 1 + (int)reader.ReadUBitInt();

				//Find out whether we should create, destroy or update it. 
				// Leave flag
				if (!reader.ReadBit()) {
					// enter flag
					if (reader.ReadBit()) {
						//create it
						var e = ReadEnterPVS(reader, currentEntity, parser);

						parser.Entities[currentEntity] = e;

						e.ApplyUpdate(reader);
					} else {
						// preserve / update
						Entity e = parser.Entities[currentEntity];
						e.ApplyUpdate(reader);
					}
				} else {
					// leave / destroy
					parser.Entities [currentEntity].Leave ();
					parser.Entities[currentEntity] = null;

					//dunno, but you gotta read this. 
					if (reader.ReadBit()) {
					}
				}
			}
        }
		public bool TryApplyMessage(ProtoBuf.IExtensible message, DemoParser parser)
		{
			CSVCMsg_UserMessage userMessage = message as CSVCMsg_UserMessage;

			if (userMessage == null || !Enum.IsDefined(typeof(ECstrike15UserMessages), userMessage.msg_type))
				return false;

			ECstrike15UserMessages msg = (ECstrike15UserMessages)userMessage.msg_type;
			Type toParse = Assembly.GetExecutingAssembly().GetType("DemoInfo.Messages.CCSUsrMsg_" + msg.ToString().Substring(6));

			using (var memstream = new MemoryStream(userMessage.msg_data))
			{
				ProtoBuf.IExtensible data = memstream.ReadProtobufMessage(toParse);
				if (data != null)
				{
					switch (data.GetType().Name)
					{
						case "CCSUsrMsg_SayText":
							{
								SayTextEventArgs e = new SayTextEventArgs();
								CCSUsrMsg_SayText sayMsg = (CCSUsrMsg_SayText)data;
								e.Text = sayMsg.text;
								e.TextAllChat = sayMsg.textallchat;
								e.Chat = sayMsg.chat;
								parser.RaiseSayText(e);
								break;
							}
						case "CCSUsrMsg_SayText2":
							{
								SayText2EventArgs e = new SayText2EventArgs();
								CCSUsrMsg_SayText2 sayMsg = (CCSUsrMsg_SayText2)data;
								e.TextAllChat = sayMsg.textallchat;
								e.Chat = sayMsg.chat;

								// get the player who wrote the message
								foreach (KeyValuePair<int, Player> keyValuePair in parser.Players)
								{
									if (keyValuePair.Value.Name == [email protected][0])
									{
										e.Sender = parser.Players[keyValuePair.Key];
										break;
									}
								}

								// @params is a 4 length array but only 2 are used [0] = nickname [1] = message text
								e.Text = [email protected][0] + " : " + [email protected][1];
								parser.RaiseSayText2(e);
								break;
							}
						case "CCSUsrMsg_ServerRankUpdate":
							{
								ServerRankUpdateEventArgs e = new ServerRankUpdateEventArgs
								{
									RankStructList = new List<ServerRankUpdateEventArgs.RankStruct>()
								};

								CCSUsrMsg_ServerRankUpdate rankMsg = (CCSUsrMsg_ServerRankUpdate)data;

								foreach (CCSUsrMsg_ServerRankUpdate.RankUpdate rankUpdate in (rankMsg.rank_update))
								{
									ServerRankUpdateEventArgs.RankStruct rankStruct = new ServerRankUpdateEventArgs.RankStruct
									{
										New = rankUpdate.rank_new,
										Old = rankUpdate.rank_old,
										NumWins = rankUpdate.num_wins,
										RankChange = rankUpdate.rank_change,
										SteamId = rankUpdate.account_id + VALVE_MAGIC_NUMBER
									};
									e.RankStructList.Add(rankStruct);
								}

								parser.RaiseServerRankUpdate(e);

								break;
							}
						default:
							// TODO: maybe, like, implement something here one day?
							//Problem: There is no real useful info here if I see it correcly. Sorry.
							//var messageType = (Messages.ECstrike15UserMessages)userMessage.msg_type;
							return true;
					}
				}
				return false;
			}
		}
        public static void Apply(CreateStringTable table, IBitStream reader, DemoParser parser)
        {
			if (table.Name == "modelprecache") {
                while (parser.modelprecache.Count < table.MaxEntries) {
                    parser.modelprecache.Add(null);
                }
			}

			if (reader.ReadBit())
				throw new NotImplementedException("Encoded with dictionaries, unable to decode");

			int nTemp = table.MaxEntries;
			int nEntryBits = 0;
			while ((nTemp >>= 1) != 0)
				++nEntryBits;

			List<string> history = new List<string>();

			int lastEntry = -1;

			for (int i = 0; i < table.NumEntries; i++) {
				int entryIndex = lastEntry + 1;
				// d in the entity-index
				if (!reader.ReadBit()) {
					entryIndex = (int)reader.ReadInt(nEntryBits);
				}

				lastEntry = entryIndex;

				// Read the name of the string into entry.
				string entry = "";
				if (entryIndex < 0 || entryIndex >= table.MaxEntries) {
					throw new InvalidDataException("bogus string index");
				}

				if (reader.ReadBit()) {
					bool substringcheck = reader.ReadBit();

					if (substringcheck) {
						int index = (int)reader.ReadInt(5);
						int bytestocopy = (int)reader.ReadInt(5);

						entry = history[index].Substring(0, bytestocopy);

						entry += reader.ReadString(1024);
					} else {
						entry = reader.ReadString(1024);
					}
				}

				if (entry == null)
					entry = "";

				if (history.Count > 31)
					history.RemoveAt(0);

				history.Add(entry);

				// Read in the user data.
				byte[] userdata = new byte[0];
				if (reader.ReadBit()) {
					if (table.UserDataFixedSize) {
						userdata = reader.ReadBits(table.UserDataSizeBits);
					} else {
						int bytesToRead = (int)reader.ReadInt(14);

						userdata = reader.ReadBytes(bytesToRead);
					}
				}

				if (userdata.Length == 0)
					break;

				if (table.Name == "userinfo") {
					// Now we'll parse the players out of it.
					BinaryReader playerReader = new BinaryReader(new MemoryStream(userdata));
					PlayerInfo info = PlayerInfo.ParseFrom(playerReader);

					parser.RawPlayers[entryIndex] = info;
				} else if (table.Name == "instancebaseline") {
					int classid = int.Parse(entry); //wtf volvo?

					parser.instanceBaseline[classid] = userdata;
                }
                else if (table.Name == "modelprecache") {
                    parser.modelprecache[entryIndex] = entry;
                }
			}

			parser.stringTables.Add(table);
        }