Exemplo n.º 1
0
 /// <summary>
 /// Fetches a property by fieldName from the provided Server Object
 /// </summary>
 /// <param name="server">The server we are fetching the field value from</param>
 /// <param name="fieldName">the field value we want</param>
 /// <returns></returns>
 private static string GetField(GameServer server, string fieldName)
 {
     object value = server.GetType().GetProperty(fieldName).GetValue(server, null);
     if (value == null)
         return String.Empty;
     else if (value is Boolean)
         return (bool)value ? "1" : "0";
     else
         return value.ToString();
 }
Exemplo n.º 2
0
        /// <summary>
        /// Executed every 60 seconds per server (Every 3rd ping), the BF2 server sends a full list
        /// of data that describes its current state, and this method is used to parse that
        /// data, and update the server in the Servers list
        /// </summary>
        /// <param name="remote">The servers remote address</param>
        /// <param name="data">The data we must parse, sent by the server</param>
        /// <returns>Returns whether or not the server needs to be validated, so it can be seen in the Server Browser</returns>
        private bool ParseServerDetails(IPEndPoint remote, byte[] data)
        {
            string key = String.Format("{0}:{1}", remote.Address, remote.Port);

            // split by 000 (info/player separator) and 002 (players/teams separator)
            // the players/teams separator is really 00, but because 00 may also be used elsewhere (an empty value for example), we hardcode it to 002
            // the 2 is the size of the teams, for BF2 this is always 2.
            string receivedData = Encoding.UTF8.GetString(data);
            string[] sections = receivedData.Split(new string[] { "\x00\x00\x00", "\x00\x00\x02" }, StringSplitOptions.None);
            if (sections.Length != 3 && !receivedData.EndsWith("\x00\x00"))
            {
                DebugLog.Write("Invalid Server Data Received From {0} :: {1}", key, sections[0]);
                return true; // true means we don't send back a response
            }

            // We only care about the server sections
            string serverVars = sections[0];
            string[] serverVarsSplit = serverVars.Split(new string[] { "\x00" }, StringSplitOptions.None);

            // Write to debug log
            DebugLog.Write("Server Data Received From {0}", key);
            for (int i = 0; i < sections.Length; i++)
                DebugLog.Write("    DataString {0}: {1}", i, sections[i]);

            // Start a new Server Object, and assign its BF2 server properties
            GameServer server = new GameServer(remote);
            for (int i = 0; i < serverVarsSplit.Length - 1; i += 2)
            {
                // Fetch the property
                PropertyInfo property = server.GetType().GetProperty(serverVarsSplit[i]);
                if (property == null)
                    continue;
                else if (property.Name == "hostname")
                {
                    // strip consecutive whitespace from hostname
                    property.SetValue(server, Regex.Replace(serverVarsSplit[i + 1], @"\s+", " ").Trim(), null);
                }
                else if (property.Name == "bf2_plasma")
                {
                    property.SetValue(server, false, null);
                }
                else if (property.Name == "bf2_ranked")
                {
                    // we're always a ranked server (helps for mods with a default bf2 main menu, and default filters wanting ranked servers)
                    property.SetValue(server, true, null);
                }
                else if (property.Name == "bf2_pure")
                {
                    // we're always a pure server
                    property.SetValue(server, true, null);
                }
                else if (property.PropertyType == typeof(Boolean))
                {
                    // parse string to bool (values come in as 1 or 0)
                    int value;
                    if (Int32.TryParse(serverVarsSplit[i + 1], NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
                    {
                        property.SetValue(server, value != 0, null);
                    }
                }
                else if (property.PropertyType == typeof(Int32))
                {
                    // parse string to int
                    int value;
                    if (Int32.TryParse(serverVarsSplit[i + 1], NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
                    {
                        property.SetValue(server, value, null);
                    }
                }
                else if (property.PropertyType == typeof(Double))
                {
                    // parse string to double
                    double value;
                    if (Double.TryParse(serverVarsSplit[i + 1], NumberStyles.Float, CultureInfo.InvariantCulture, out value))
                    {
                        property.SetValue(server, value, null);
                    }
                }
                else if (property.PropertyType == typeof(String))
                {
                    // parse string to string
                    property.SetValue(server, serverVarsSplit[i + 1], null);
                }
            }

            // you've got to have all these properties in order for your server to be valid
            if (!String.IsNullOrWhiteSpace(server.hostname) &&
                !String.IsNullOrWhiteSpace(server.gamevariant) &&
                !String.IsNullOrWhiteSpace(server.gamever) &&
                !String.IsNullOrWhiteSpace(server.gametype) &&
                !String.IsNullOrWhiteSpace(server.mapname) &&
                !String.IsNullOrWhiteSpace(server.gamename) &&
                server.gamename.Equals("battlefield2", StringComparison.InvariantCultureIgnoreCase) &&
                server.hostport > 1024 && server.hostport <= UInt16.MaxValue &&
                server.maxplayers > 0)
            {
                // Determine if we need to send a challenge key to the server for validation
                GameServer oldServer;
                bool IsValidated = Servers.TryGetValue(key, out oldServer) && oldServer.IsValidated;
                DebugLog.Write("Server Data Parsed Successfully... Needs Validated: " + ((IsValidated) ? "false" : "true"));

                // Copy over the local lan fix if we already have in the past
                if (IsValidated)
                {
                    server.AddressInfo.Address = oldServer.AddressInfo.Address;
                    server.country = oldServer.country;
                }

                // Add / Update Server
                server.IsValidated = IsValidated;
                server.LastPing = DateTime.Now;
                server.LastRefreshed = DateTime.Now;
                Servers.AddOrUpdate(key, server, (k, old) => { return server; });

                // Tell the requester if we are good to go
                return IsValidated;
            }

            // If we are here, the server information is partial/invalid. Return true to ignore server
            // until we can get some good data.
            DebugLog.Write("Data from {0} was partial. Assuming server switched game status. Complete data expected in 10 seconds.", key);
            return true;
        }
Exemplo n.º 3
0
        /// <summary>
        /// Executed every 60 seconds per server (Every 3rd ping), the BF2 server sends a full list
        /// of data that describes its current state, and this method is used to parse that
        /// data, and update the server in the Servers list
        /// </summary>
        /// <param name="remote">The servers remote address</param>
        /// <param name="data">The data we must parse, sent by the server</param>
        /// <returns>Returns whether or not the server needs to be validated, so it can be seen in the Server Browser</returns>
        private bool ParseServerDetails(IPEndPoint remote, byte[] data)
        {
            string key = String.Format("{0}:{1}", remote.Address, remote.Port);

            // split by 000 (info/player separator) and 002 (players/teams separator)
            // the players/teams separator is really 00, but because 00 may also be used elsewhere (an empty value for example), we hardcode it to 002
            // the 2 is the size of the teams, for BF2 this is always 2.
            string receivedData = Encoding.UTF8.GetString(data);

            string[] sections = receivedData.Split(new string[] { "\x00\x00\x00", "\x00\x00\x02" }, StringSplitOptions.None);
            if (sections.Length != 3 && !receivedData.EndsWith("\x00\x00"))
            {
                DebugLog.Write("Invalid Server Data Received From {0} :: {1}", key, sections[0]);
                return(true); // true means we don't send back a response
            }

            // We only care about the server sections
            string serverVars = sections[0];

            string[] serverVarsSplit = serverVars.Split(new string[] { "\x00" }, StringSplitOptions.None);

            // Write to debug log
            DebugLog.Write("Server Data Received From {0}", key);
            for (int i = 0; i < sections.Length; i++)
            {
                DebugLog.Write("    DataString {0}: {1}", i, sections[i]);
            }

            // Start a new Server Object, and assign its BF2 server properties
            GameServer server = new GameServer(remote);

            for (int i = 0; i < serverVarsSplit.Length - 1; i += 2)
            {
                // Fetch the property
                PropertyInfo property = server.GetType().GetProperty(serverVarsSplit[i]);
                if (property == null)
                {
                    continue;
                }
                else if (property.Name == "hostname")
                {
                    // strip consecutive whitespace from hostname
                    property.SetValue(server, Regex.Replace(serverVarsSplit[i + 1], @"\s+", " ").Trim(), null);
                }
                else if (property.Name == "bf2_plasma")
                {
                    property.SetValue(server, false, null);
                }
                else if (property.Name == "bf2_ranked")
                {
                    // we're always a ranked server (helps for mods with a default bf2 main menu, and default filters wanting ranked servers)
                    property.SetValue(server, true, null);
                }
                else if (property.Name == "bf2_pure")
                {
                    // we're always a pure server
                    property.SetValue(server, true, null);
                }
                else if (property.PropertyType == typeof(Boolean))
                {
                    // parse string to bool (values come in as 1 or 0)
                    int value;
                    if (Int32.TryParse(serverVarsSplit[i + 1], NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
                    {
                        property.SetValue(server, value != 0, null);
                    }
                }
                else if (property.PropertyType == typeof(Int32))
                {
                    // parse string to int
                    int value;
                    if (Int32.TryParse(serverVarsSplit[i + 1], NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
                    {
                        property.SetValue(server, value, null);
                    }
                }
                else if (property.PropertyType == typeof(Double))
                {
                    // parse string to double
                    double value;
                    if (Double.TryParse(serverVarsSplit[i + 1], NumberStyles.Float, CultureInfo.InvariantCulture, out value))
                    {
                        property.SetValue(server, value, null);
                    }
                }
                else if (property.PropertyType == typeof(String))
                {
                    // parse string to string
                    property.SetValue(server, serverVarsSplit[i + 1], null);
                }
            }

            // you've got to have all these properties in order for your server to be valid
            if (!String.IsNullOrWhiteSpace(server.hostname) &&
                !String.IsNullOrWhiteSpace(server.gamevariant) &&
                !String.IsNullOrWhiteSpace(server.gamever) &&
                !String.IsNullOrWhiteSpace(server.gametype) &&
                !String.IsNullOrWhiteSpace(server.mapname) &&
                !String.IsNullOrWhiteSpace(server.gamename) &&
                server.gamename.Equals("battlefield2", StringComparison.InvariantCultureIgnoreCase) &&
                server.hostport > 1024 && server.hostport <= UInt16.MaxValue &&
                server.maxplayers > 0)
            {
                // Determine if we need to send a challenge key to the server for validation
                GameServer oldServer;
                bool       IsValidated = Servers.TryGetValue(key, out oldServer) && oldServer.IsValidated;
                DebugLog.Write("Server Data Parsed Successfully... Needs Validated: " + ((IsValidated) ? "false" : "true"));

                // Copy over the local lan fix if we already have in the past
                if (IsValidated)
                {
                    server.AddressInfo.Address = oldServer.AddressInfo.Address;
                    server.country             = oldServer.country;
                }

                // Add / Update Server
                server.IsValidated   = IsValidated;
                server.LastPing      = DateTime.Now;
                server.LastRefreshed = DateTime.Now;
                Servers.AddOrUpdate(key, server, (k, old) => { return(server); });

                // Tell the requester if we are good to go
                return(IsValidated);
            }

            // If we are here, the server information is partial/invalid. Return true to ignore server
            // until we can get some good data.
            DebugLog.Write("Data from {0} was partial. Assuming server switched game status. Complete data expected in 10 seconds.", key);
            return(true);
        }