private void MessageNewUserMsg() { Int32 messageStartOffset = parser.BitBuffer.CurrentByte; // read message Byte id = parser.BitBuffer.ReadByte(); SByte length = parser.BitBuffer.ReadSByte(); String name = parser.BitBuffer.ReadString(16); parser.AddUserMessage(id, length, name); // FIXME: clean this up if (!demo.ConvertNetworkProtocol() && name != "CDChallenge" && name != "CDSalt") { return; } if (demo.Game == null || demo.Game.UserMessages == null) { return; } Byte newId; if (demo.Game.UserMessages.ContainsKey(name)) { newId = demo.Game.UserMessages[name]; } else { // cheating death // TODO: probably should have a list of "bad" user messages to remove... // TODO: should remove these messages even when not converting network protocols if (name == "CDChallenge" || name == "CDSalt") { // remove message Int32 messageFinishOffset = parser.BitBuffer.CurrentByte; parser.BitBuffer.SeekBytes(messageStartOffset - 1, SeekOrigin.Begin); parser.BitBuffer.RemoveBytes(messageFinishOffset - messageStartOffset + 1); // +1 for message id return; } // user message doesn't exist in CS 1.6. shouldn't happen, but meh... // TODO: use an id unused by compatibleUserMessageTable //newId = (Byte?)id; newId = firstFreeUserMessage; if (firstFreeUserMessage == 255) { throw new NoFreeUserMessageException(); } firstFreeUserMessage++; demo.Game.UserMessages.Add(name, newId); } BitWriter bitWriter = new BitWriter(); bitWriter.WriteByte((Byte)newId); bitWriter.WriteSByte(length); bitWriter.WriteString(name, 16); // insert new message ReWriteMessage(messageStartOffset, bitWriter.Data); }
private void RefreshThread() { using (TimedUdpClient client = new TimedUdpClient()) { IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 0); mainWindowInterface.SetServerProperty(this, "Title", "Connecting to Server"); mainWindowInterface.SetServerProperty(this, "State", StateEnum.Querying); // reset properties mainWindowInterface.SetServerProperty(this, "Ping", null); mainWindowInterface.SetServerProperty(this, "GameName", null); mainWindowInterface.SetServerProperty(this, "Map", null); mainWindowInterface.SetServerProperty(this, "NumSpectators", null); mainWindowInterface.SetServerProperty(this, "MaxSpectators", null); mainWindowInterface.SetServerProperty(this, "PasswordProtected", null); try { DateTime connectTime = DateTime.Now; // attempt to connect Int32 colonIndex = address.IndexOf(':'); // what's the timeout??? client.Connect(address.Remove(colonIndex), Convert.ToInt32(address.Substring(colonIndex + 1))); // update title as "connected" mainWindowInterface.SetServerProperty(this, "Title", "Connected"); if (abortRefresh) { Common.AbortThread(Thread); } // send A2S_INFO // -1 (int), A2S_INFO, "Source Engine Query" (string) DateTime sendTime = DateTime.Now; client.Send(new Byte[] { 0xFF, 0xFF, 0xFF, 0xFF, A2S_INFO, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x00 }); // receive A2S_INFO reply Byte[] infoReply = client.Receive(ref ipEndPoint); if (infoReply == null) { throw new ApplicationException("Server not responding."); } // calculate ping TimeSpan ping = DateTime.Now - connectTime; mainWindowInterface.SetServerProperty(this, "Ping", ping.Milliseconds); // parse A2S_INFO reply ParseInfoQueryReply(infoReply); if (client.Available > 0) // fuuuuuuckkkk yoooooouuu Vaaaaaaalllvvvveeee { client.Receive(ref ipEndPoint); } // send A2S_SERVERQUERY_GETCHALLENGE // -1 (int), A2S_SERVERQUERY_GETCHALLENGE /*client.Send(new Byte[] { 0xFF, 0xFF, 0xFF, 0xFF, A2S_SERVERQUERY_GETCHALLENGE }); // receive and parse A2S_SERVERQUERY_GETCHALLENGE reply Byte[] serverQueryGetChallengeReply = client.Receive(ref ipEndPoint); if (serverQueryGetChallengeReply == null) { throw new ApplicationException("Server ignored challenge."); }*/ //Int32 challengeNumber = ParseServerQueryGetChallengeReply(serverQueryGetChallengeReply); Int32 challengeNumber = -1; while (true) { if (abortRefresh) { Common.AbortThread(Thread); } // send A2S_PLAYER BitWriter bitWriter = new BitWriter(); bitWriter.WriteInt32(-1); bitWriter.WriteByte(A2S_PLAYER); bitWriter.WriteInt32(challengeNumber); client.Send(bitWriter.Data); // receive and parse A2S_PLAYER reply Byte[] playerReply = client.Receive(ref ipEndPoint); if (playerReply == null) { if (challengeNumber != -1) { // oh, it's a sourcetv server and valve are too incompetent to implement s2c_player break; } throw new ApplicationException("Player query failed."); } // check for a challenge number (source servers) BitBuffer bitBuffer = new BitBuffer(playerReply); if (bitBuffer.ReadInt32() != -1) { throw new ApplicationException("Bad A2S_PLAYER reply"); } Byte type = bitBuffer.ReadByte(); if (type == S2C_CHALLENGE) { challengeNumber = bitBuffer.ReadInt32(); continue; } else if (type == S2C_PLAYER) { ParsePlayerQueryReply(bitBuffer); } else { throw new ApplicationException(String.Format("Bad A2S_PLAYER type: {0}", type)); } break; } mainWindowInterface.SetServerProperty(this, "State", StateEnum.Succeeded); } catch (ThreadAbortException) { throw; } catch (Exception ex) { if (!abortRefresh) { mainWindowInterface.SetServerProperty(this, "Title", ex.Message); mainWindowInterface.SetServerProperty(this, "State", StateEnum.Failed); } } finally { client.Close(); } } }
private void MessageDeltaPacketEntities() { if (!demo.ConvertNetworkProtocol() || demo.IsBetaSteam()) { parser.MessageDeltaPacketEntities(); return; } Int32 messageStartOffset = parser.BitBuffer.CurrentByte; BitWriter bitWriter = new BitWriter(); // read message bitWriter.WriteUInt16(parser.BitBuffer.ReadUInt16()); // nEntities/maxEntities if (demo.NetworkProtocol <= 43) { parser.BitBuffer.Endian = BitBuffer.EndianType.Big; } bitWriter.WriteByte(parser.BitBuffer.ReadByte()); // delta sequence number UInt32 entityNumber = 0; while (true) { // check for footer UInt16 footer = parser.BitBuffer.ReadUInt16(); if (footer == 0) { bitWriter.WriteUInt16(footer); break; } parser.BitBuffer.SeekBits(-16); // option bits Boolean removeEntity = parser.BitBuffer.ReadBoolean(); bitWriter.WriteBoolean(removeEntity); Boolean absoluteEntityNumber = parser.BitBuffer.ReadBoolean(); bitWriter.WriteBoolean(absoluteEntityNumber); // entity number if (absoluteEntityNumber) { entityNumber = parser.BitBuffer.ReadUnsignedBits(11); bitWriter.WriteUnsignedBits(entityNumber, 11); } else { UInt32 deltaEntityNumber = parser.BitBuffer.ReadUnsignedBits(6); bitWriter.WriteUnsignedBits(deltaEntityNumber, 6); entityNumber += deltaEntityNumber; } if (!removeEntity) { // entity type Boolean custom = parser.BitBuffer.ReadBoolean(); bitWriter.WriteBoolean(custom); if (demo.NetworkProtocol <= 43) { parser.BitBuffer.SeekBits(1); // unknown, always 0 } String entityType = "entity_state_t"; if (entityNumber > 0 && entityNumber <= demo.MaxClients) { entityType = "entity_state_player_t"; } else if (custom) { entityType = "custom_entity_state_t"; } // delta compressed data Byte[] bitmaskBytes; HalfLifeDeltaStructure deltaDecoder = parser.GetDeltaStructure(entityType); HalfLifeDelta deltaEntity = deltaDecoder.CreateDelta(); deltaDecoder.ReadDelta(parser.BitBuffer, deltaEntity, out bitmaskBytes); if (demo.Game != null) { demo.Game.ConvertPacketEntititiesCallback(deltaEntity, entityType, demo.GameVersion); } deltaDecoder.WriteDelta(bitWriter, deltaEntity, bitmaskBytes); } } parser.BitBuffer.SkipRemainingBits(); parser.BitBuffer.Endian = BitBuffer.EndianType.Little; // insert new message ReWriteMessage(messageStartOffset, bitWriter.Data); }
public void ProcessFirstGameDataFrame(ref Byte[] frameData) { // A svc_director message preceeds svc_spawnbaseline in newer HLTV demos. The director message is used to initialise and reset the HUD. Since old HLTV demos omit this message, it can be added here (and set the perspective to first-person too). if (demo.Perspective != Demo.Perspectives.Hltv || haveParsedDirectorMessage) { return; } const Byte DRC_CMD_START = 1; const Byte DRC_CMD_MODE = 3; const Byte OBS_IN_EYE = 4; // Create a svc_director message to initialise the HUD. BitWriter directorMessage = new BitWriter(); directorMessage.WriteByte((Byte)HalfLifeDemoParser.MessageId.svc_director); directorMessage.WriteByte(1); // length directorMessage.WriteByte(DRC_CMD_START); // Create a svc_director message to set the perspective to first-person. directorMessage.WriteByte((Byte)HalfLifeDemoParser.MessageId.svc_director); directorMessage.WriteByte(2); // length directorMessage.WriteByte(DRC_CMD_MODE); directorMessage.WriteByte(OBS_IN_EYE); // Insert the new messages. BitBuffer bitBuffer = new BitBuffer(frameData); bitBuffer.InsertBytes(directorMessage.Data); frameData = bitBuffer.Data; }
public void WriteDelta(BitWriter bitWriter, HalfLifeDelta delta, Byte[] bitmaskBytes) { if (bitmaskBytes == null) // no bitmask bytes { bitWriter.WriteUnsignedBits(0, 3); return; } bitWriter.WriteUnsignedBits((UInt32)bitmaskBytes.Length, 3); for (Int32 i = 0; i < bitmaskBytes.Length; i++) { bitWriter.WriteByte(bitmaskBytes[i]); } for (Int32 i = 0; i < bitmaskBytes.Length; i++) { for (Int32 j = 0; j < 8; j++) { Int32 index = j + i * 8; if (index == entryList.Count) { return; } if ((bitmaskBytes[i] & (1 << j)) != 0) { WriteEntry(delta, bitWriter, entryList[index]); } } } }
private void MessageDeltaPacketEntities() { if (!demo.ConvertNetworkProtocol() || demo.IsBetaSteam()) { parser.MessageDeltaPacketEntities(); return; } Int32 messageStartOffset = parser.BitBuffer.CurrentByte; BitWriter bitWriter = new BitWriter(); // read message bitWriter.WriteUInt16(parser.BitBuffer.ReadUInt16()); // nEntities/maxEntities if (demo.NetworkProtocol <= 43) { parser.BitBuffer.Endian = BitBuffer.EndianType.Big; } bitWriter.WriteByte(parser.BitBuffer.ReadByte()); // delta sequence number UInt32 entityNumber = 0; while (true) { // check for footer UInt16 footer = parser.BitBuffer.ReadUInt16(); if (footer == 0) { bitWriter.WriteUInt16(footer); break; } parser.BitBuffer.SeekBits(-16); // option bits Boolean removeEntity = parser.BitBuffer.ReadBoolean(); bitWriter.WriteBoolean(removeEntity); Boolean absoluteEntityNumber = parser.BitBuffer.ReadBoolean(); bitWriter.WriteBoolean(absoluteEntityNumber); // entity number if (absoluteEntityNumber) { entityNumber = parser.BitBuffer.ReadUnsignedBits(11); bitWriter.WriteUnsignedBits(entityNumber, 11); } else { UInt32 deltaEntityNumber = parser.BitBuffer.ReadUnsignedBits(6); bitWriter.WriteUnsignedBits(deltaEntityNumber, 6); entityNumber += deltaEntityNumber; } if (!removeEntity) { // entity type Boolean custom = parser.BitBuffer.ReadBoolean(); bitWriter.WriteBoolean(custom); if (demo.NetworkProtocol <= 43) { parser.BitBuffer.SeekBits(1); // unknown, always 0 } String entityType = "entity_state_t"; if (entityNumber > 0 && entityNumber <= demo.MaxClients) { entityType = "entity_state_player_t"; } else if (custom) { entityType = "custom_entity_state_t"; } // delta compressed data Byte[] bitmaskBytes; HalfLifeDeltaStructure deltaDecoder = parser.GetDeltaStructure(entityType); HalfLifeDelta deltaEntity = deltaDecoder.CreateDelta(); deltaDecoder.ReadDelta(parser.BitBuffer, deltaEntity, out bitmaskBytes); if (demo.Game != null) { demo.Game.ConvertPacketEntititiesCallback(deltaEntity, entityType, demo.GameVersion); } deltaDecoder.WriteDelta(bitWriter, deltaEntity, bitmaskBytes); } } parser.BitBuffer.SkipRemainingBits(); parser.BitBuffer.Endian = BitBuffer.EndianType.Little; // insert new message ReWriteMessage(messageStartOffset, bitWriter.Data); }
private void MessageNewUserMsg() { Int32 messageStartOffset = parser.BitBuffer.CurrentByte; // read message Byte id = parser.BitBuffer.ReadByte(); SByte length = parser.BitBuffer.ReadSByte(); String name = parser.BitBuffer.ReadString(16); parser.AddUserMessage(id, length, name); // FIXME: clean this up if (!demo.ConvertNetworkProtocol() && name != "CDChallenge" && name != "CDSalt") { return; } if (demo.Game == null || demo.Game.UserMessages == null) { return; } Byte newId; if (demo.Game.UserMessages.ContainsKey(name)) { newId = demo.Game.UserMessages[name]; } else { // cheating death // TODO: probably should have a list of "bad" user messages to remove... // TODO: should remove these messages even when not converting network protocols if (name == "CDChallenge" || name == "CDSalt") { // remove message Int32 messageFinishOffset = parser.BitBuffer.CurrentByte; parser.BitBuffer.SeekBytes(messageStartOffset - 1, SeekOrigin.Begin); parser.BitBuffer.RemoveBytes(messageFinishOffset - messageStartOffset + 1); // +1 for message id return; } // user message doesn't exist in CS 1.6. shouldn't happen, but meh... // TODO: use an id unused by compatibleUserMessageTable //newId = (Byte?)id; newId = firstFreeUserMessage; if (firstFreeUserMessage == 255) { throw new NoFreeUserMessageException(); } firstFreeUserMessage++; demo.Game.UserMessages.Add(name, newId); } BitWriter bitWriter = new BitWriter(); bitWriter.WriteByte((Byte)newId); bitWriter.WriteSByte(length); bitWriter.WriteString(name, 16); // insert new message ReWriteMessage(messageStartOffset, bitWriter.Data); }