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); } }
/// <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); }