private void QueryCompleted(ServerQueryResponse response) { // var response = queryTask.Result; SetConnectingState(false); if (response.Success) { var s = response.Status; var q = s.Query; _pingStatus.SetPlayerCount(q.Players.Online, q.Players.Max); ConnectionEndpoint = s.EndPoint; if (!s.WaitingOnPing) { _pingStatus.SetPing(s.Delay); } if (q.Version.Protocol < (SavedServerEntry.ServerType == ServerType.Java ? JavaProtocol.ProtocolVersion : McpeProtocolInfo.ProtocolVersion)) { if (SavedServerEntry.ServerType == ServerType.Java) { _pingStatus.SetOutdated(q.Version.Name); } } else if (q.Version.Protocol > (SavedServerEntry.ServerType == ServerType.Java ? JavaProtocol.ProtocolVersion : McpeProtocolInfo.ProtocolVersion)) { _pingStatus.SetOutdated($"multiplayer.status.client_out_of_date", true); } if (q.Description.Extra != null) { StringBuilder builder = new StringBuilder(); foreach (var extra in q.Description.Extra) { if (extra.Color != null) { builder.Append(API.Utils.TextColor.GetColor(extra.Color).ToString()); } if (extra.Bold.HasValue) { builder.Append(ChatFormatting.Bold); } if (extra.Italic.HasValue) { builder.Append(ChatFormatting.Italic); } if (extra.Underlined.HasValue) { builder.Append(ChatFormatting.Underline); } if (extra.Strikethrough.HasValue) { builder.Append(ChatFormatting.Strikethrough); } if (extra.Obfuscated.HasValue) { builder.Append(ChatFormatting.Obfuscated); } builder.Append(extra.Text); } _serverMotd.Text = builder.ToString(); } else { _serverMotd.Text = q.Description.Text; } if (!string.IsNullOrWhiteSpace(q.Favicon)) { var match = FaviconRegex.Match(q.Favicon); if (match.Success && _graphicsDevice != null) { AutoResetEvent reset = new AutoResetEvent(false); Alex.Instance.UIThreadQueue.Enqueue(() => { using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(match.Groups["data"].Value))) { ServerIcon = GpuResourceManager.GetTexture2D(this, _graphicsDevice, ms); } reset.Set(); }); reset.WaitOne(); SavedServerEntry.CachedIcon = ServerIcon; _serverIcon.Texture = ServerIcon; } } } else { SetErrorMessage(response.ErrorMessage); } }
private static void RequestPlayers(ServerQueryResponse item, UdpClient udp) { try { IPEndPoint endp = null; var challengeRequest = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, PlayerRequestByte, 0xFF, 0xFF, 0xFF, 0xFF }; var sendlen = udp.Send(challengeRequest, 9); if (sendlen != 9) { return; } var challengeRespose = udp.Receive(ref endp); // challenge response if (challengeRespose[4] != RequestChallengeByte) { System.Diagnostics.Trace.WriteLine("Error in RequestPlayers - Challenge response"); return; } challengeRespose[4] = PlayerRequestByte; // change to player request sendlen = udp.Send(challengeRespose, 9); if (sendlen != 9) { return; } var playerRespose = udp.Receive(ref endp); if (playerRespose[4] != ReponseHeanderByte) { System.Diagnostics.Trace.WriteLine("Error in RequestPlayers - Players response"); return; } byte playerCount = playerRespose[5]; var offset = 6; var result = new List <ServerQueryResponse.Player>(byte.MaxValue); for (byte i = 0; i < playerCount; i++) { var p = new ServerQueryResponse.Player(); p.Idx = playerRespose[offset]; offset += 1; string s; offset += ReadStringNullTerminated(playerRespose, offset, out s, Encoding.UTF8); p.Name = s; p.Score = BitConverter.ToInt32(playerRespose, offset); offset += 4; p.OnlineTime = TimeSpan.FromSeconds(Convert.ToDouble(BitConverter.ToSingle(playerRespose, offset))); offset += 4; result.Add(p); } item.Players = result; return; } catch (Exception) { // ignored return; } }
private static void RequestRules(ServerQueryResponse item, System.Net.Sockets.UdpClient udp) { IPEndPoint endp = null; // Rules auslesen var challengeRequest = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, RuleRequestByte, 0xFF, 0xFF, 0xFF, 0xFF }; var sendlen = udp.Send(challengeRequest, 9); byte[] respose = udp.Receive(ref endp); if (respose[4] != RequestChallengeByte) { System.Diagnostics.Debug.WriteLine("Error in RequestRules - Challenge response"); return; } respose[4] = RuleRequestByte; sendlen = udp.Send(respose, 9); respose = udp.Receive(ref endp); if (respose[4] != RuleReponseByte) { // no valid response return; } Version version = new Version(item.Version); if (version.Major >= 1 && version.Minor >= 56) { SteamDefragmentedBytes unFramed = respose.DefragmentSteamBytes_1_56(); #if DEBUG bool writeFile = Directory.Exists(@"E:\temp\Data"); string filename = @"E:\temp\Data\V_" + item.Version + "_" + item.IpAdresse.ToString(); if (writeFile) { if (respose.Length > 7) { using (var file = new FileStream(filename + ".dat", FileMode.OpenOrCreate)) { file.Write(item.Data, 0, item.Data.Length); file.SetLength(item.Data.Length); } using (var file = new FileStream(filename + ".rdat", FileMode.OpenOrCreate)) { file.Write(respose, 0, respose.Length); file.SetLength(respose.Length); } using (var file = new FileStream(filename + ".rdefrag", FileMode.OpenOrCreate)) { file.Write(unFramed.Bytes, 0, unFramed.Bytes.Length); file.SetLength(unFramed.Bytes.Length); } } } #endif if (respose[4] != 0x45) { System.Diagnostics.Debug.WriteLine("Error in RequestRules - Rules response not valid"); return; } using (var decodedMem = unFramed.DecodeSteamRuleFile_1_56()) { #if DEBUG if (writeFile) { using (var file = new FileStream(filename + ".rules", FileMode.OpenOrCreate)) { decodedMem.Data.CopyTo(file); } } decodedMem.Data.Seek(0, SeekOrigin.Begin); #endif var mods = ReadRules(decodedMem, version); foreach (var keyValuePair in mods) { item.KeyValues.Add(keyValuePair.Key, keyValuePair.Value); } } } else { item.KeyValues.Add("sigNames:1:1", "Version " + item.Version + " not supported"); } }
public static SteamGameServer GetServerInfo(IPEndPoint gameServerQueryEndpoint) { byte[] startBytes = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }; byte Header = 0x54; string qryAsString = "Source Engine Query"; List <byte> qry = new List <byte>(); qry.AddRange(startBytes); qry.Add(Header); qry.AddRange(Encoding.Default.GetBytes(qryAsString)); qry.Add(0x00); ServerQueryResponse item = null; var sw = new System.Diagnostics.Stopwatch(); var buffer = new byte[2048]; using (System.Net.Sockets.UdpClient udp = new System.Net.Sockets.UdpClient()) { try { udp.Connect(gameServerQueryEndpoint); udp.AllowNatTraversal(true); udp.Client.ReceiveTimeout = 300; sw.Start(); udp.Send(qry.ToArray(), qry.Count); System.Net.Sockets.SocketError errorCode; var receivedLenght = udp.Client.Receive(buffer, 0, 2048, System.Net.Sockets.SocketFlags.None, out errorCode); sw.Stop(); if (errorCode != System.Net.Sockets.SocketError.Success) { return(null); } if (receivedLenght == buffer.Length) { throw new Exception("Buffer zu klein"); } var receivedBytes = new byte[receivedLenght]; Buffer.BlockCopy(buffer, 0, receivedBytes, 0, receivedLenght); //var receivedBytes = udp.Receive(ref endp); var enconding = System.Text.Encoding.UTF8; // System.Text.Encoding.ASCII; using (var mem = new System.IO.MemoryStream(receivedBytes)) using (var br = new System.IO.BinaryReader(mem, CharEncoding)) { br.ReadInt32(); br.ReadByte(); item = new ServerQueryResponse(); item.IpAdresse = gameServerQueryEndpoint.Address.ToString(); item.ProtocolVersion = br.ReadByte(); item.Ping = (int)sw.ElapsedMilliseconds; var count = Array.FindIndex(receivedBytes, (int)mem.Position, IsNULL) - (int)mem.Position; item.GameServerName = enconding.GetString(br.ReadBytes(count)); br.ReadByte(); // null-byte count = Array.FindIndex(receivedBytes, (int)mem.Position, IsNULL) - (int)mem.Position; item.Map = enconding.GetString(br.ReadBytes(count)); br.ReadByte(); // null-byte //item.Map = ReadStringNullTerminated(br, enconding); count = Array.FindIndex(receivedBytes, (int)mem.Position, IsNULL) - (int)mem.Position; item.Folder = enconding.GetString(br.ReadBytes(count)); br.ReadByte(); // null-byte count = Array.FindIndex(receivedBytes, (int)mem.Position, IsNULL) - (int)mem.Position; item.Game = enconding.GetString(br.ReadBytes(count)); br.ReadByte(); // null-byte item.ID = br.ReadInt16(); item.CurrentPlayerCount = br.ReadByte(); item.MaxPlayerCount = br.ReadByte(); item.CurrentBotsCount = br.ReadByte(); item.ServerType = (ServerQueryRequestType)br.ReadByte(); item.Password = br.ReadByte() == 1; item.VAC = br.ReadByte() == 1; item.Mode = br.ReadByte() == 1; count = Array.FindIndex(receivedBytes, (int)mem.Position, IsNULL) - (int)mem.Position; item.Version = enconding.GetString(br.ReadBytes(count)); br.ReadByte(); // null-byte var edfCode = br.ReadByte(); item.Data = receivedBytes; if ((edfCode & 0x80) == 0x80) { item.GamePort = br.ReadUInt16(); } if ((edfCode & 0x10) == 0x10) { item.ServerSteamId = br.ReadInt64(); } //if ((edfCode & 0x40) == 0x40) // Console.WriteLine("spectator server"); if ((edfCode & 0x20) == 0x20) { count = Array.FindIndex(receivedBytes, (int)mem.Position, IsNULL) - (int)mem.Position; item.Keywords = enconding.GetString(br.ReadBytes(count)); br.ReadByte(); // null-byte } if ((edfCode & 0x01) == 0x01) { item.GameID = br.ReadInt64(); } // https://community.bistudio.com/wiki/STEAMWORKSquery // https://developer.valvesoftware.com/wiki/Master_Server_Query_Protocol } RequestRules(item, udp); if (item.CurrentPlayerCount > 0) { udp.Client.ReceiveTimeout = Math.Max(300, Convert.ToInt32((6d * item.CurrentPlayerCount))); RequestPlayers(item, udp); } } catch { sw.Stop(); } } return(item != null ? new SteamGameServer { Host = gameServerQueryEndpoint.Address, QueryPort = gameServerQueryEndpoint.Port, Name = item.GameServerName, //Gamename = SteamGameNameFilter, Map = item.Map, Mission = item.Game, MaxPlayers = item.MaxPlayerCount, CurrentPlayerCount = item.CurrentPlayerCount, Passworded = item.Password, Port = item.GamePort, Version = item.Version, Keywords = item.Keywords, CurrentPlayers = new string[0], Ping = item.Ping, Players = item.Players?.Cast <ISteamGameServerPlayer>().ToArray(), Mods = GetValue("modNames", item.KeyValues), Modhashs = GetValue("modHashes", item.KeyValues), Signatures = GetValue("sigNames", item.KeyValues), VerifySignatures = item.Keywords.Contains(",vt,") } : null); }