private void RefreshThread() { using (TimedUdpClient client = new TimedUdpClient()) { IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 0); try { DateTime connectTime = DateTime.Now; Players.Clear(); //add default 27015 port if not present if(address.IndexOf(':') == -1) address += ":27015"; // attempt to connect Int32 colonIndex = address.IndexOf(':'); // what's the timeout??? client.Connect(address.Remove(colonIndex), Convert.ToInt32(address.Substring(colonIndex + 1))); 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) { title = "Server not responding"; } // calculate ping TimeSpan ping = DateTime.Now - connectTime; // parse A2S_INFO reply ParseInfoQueryReply(infoReply); if (client.Available > 0) { client.Receive(ref ipEndPoint); } //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 break; } title = "Player query failed"; } // check for a challenge number (source servers) BitBuffer bitBuffer = new BitBuffer(playerReply); if (bitBuffer.ReadInt32() != -1) { title = "Bad A2S_PLAYER reply"; } Byte type = bitBuffer.ReadByte(); if (type == S2C_CHALLENGE) { challengeNumber = bitBuffer.ReadInt32(); continue; } else if (type == S2C_PLAYER) { ParsePlayerQueryReply(bitBuffer); } else if (type == S2C_INFO_SOURCE) { ParsePlayerQueryReply(bitBuffer); } else { title = (String.Format("Bad A2S_PLAYER type: {0}", type)); } break; } } catch (ThreadAbortException) { throw; } finally { client.Close(); } } }
/// <summary> /// Parses S2C_PLAYER. /// </summary> /// <param name="data"></param> /// <param name="si"></param> private void ParsePlayerQueryReply(BitBuffer bitBuffer) { Int32 nPlayers = bitBuffer.ReadByte(); for (Int32 i = 0; i < nPlayers; i++) { bitBuffer.SeekBytes(1); // skip index Player player = new Player(); player.Name = bitBuffer.ReadString(); player.Score = bitBuffer.ReadInt32(); Single time = bitBuffer.ReadSingle(); player.Time = (time == -1 ? "BOT" : Common.DurationString(time)); players.Add(player); } }
/// <summary> /// Parses S2C_CHALLENGE and returns the challenge number. /// </summary> /// <param name="data"></param> /// <returns></returns> private Int32 ParseServerQueryGetChallengeReply(Byte[] data) { BitBuffer bitBuffer = new BitBuffer(data); if (bitBuffer.ReadInt32() != -1) { throw new ApplicationException("Bad A2S_SERVERQUERY_GETCHALLENGE reply"); } Byte type = bitBuffer.ReadByte(); if (type != S2C_CHALLENGE) { throw new ApplicationException(String.Format("Bad A2S_SERVERQUERY_GETCHALLENGE type: {0}", type)); } return bitBuffer.ReadInt32(); }
/// <summary> /// Parses S2C_INFO. /// </summary> /// <param name="data"></param> /// <param name="si"></param> private void ParseInfoQueryReply(Byte[] data) { BitBuffer bitBuffer = new BitBuffer(data); if (bitBuffer.ReadInt32() != -1) { throw new ApplicationException("Bad A2S_INFO reply"); } // read reply type Byte type = bitBuffer.ReadByte(); Boolean sourceEngine; if (type == S2C_INFO_SOURCE) { sourceEngine = true; } else if (type == S2C_INFO_GOLDSRC) { sourceEngine = false; } else { throw new ApplicationException(String.Format("Bad A2S_INFO type: {0}", type)); } // read the rest if (!sourceEngine) { bitBuffer.ReadString(); //si.Address = bitBuffer.ReadString(); // resolved hostname } else { bitBuffer.SeekBytes(1); // network version } title = bitBuffer.ReadString(); map = bitBuffer.ReadString(); // map if (sourceEngine) { bitBuffer.SeekBytes(2); // app id } bitBuffer.SeekBytes(1); // goldsrc: network version, source: num bots bitBuffer.SeekBytes(1); // dedicated bitBuffer.SeekBytes(1); // os }