/// <summary> /// Gets the country code for a string IP address /// </summary> /// <param name="IP"></param> /// <returns></returns> public static string GetCountryCode(IPAddress IP) { // Return default config Country Code if (IPAddress.IsLoopback(IP) || HttpServer.LocalIPs.Contains(IP)) return Program.Config.ASP_LocalIpCountryCode; try { using (DatabaseDriver Driver = new DatabaseDriver(DatabaseEngine.Sqlite, ConnectionString)) { // Fetch country code from Ip2Nation Driver.Connect(); List<Dictionary<string, object>> Rows = Driver.Query( "SELECT country FROM ip2nation WHERE ip < @P0 ORDER BY ip DESC LIMIT 1", Networking.IP2Long(IP.ToString()) ); string CC = (Rows.Count == 0) ? "xx" : Rows[0]["country"].ToString(); // Fix country! return (CC == "xx" || CC == "01") ? Program.Config.ASP_LocalIpCountryCode : CC; } } catch { return Program.Config.ASP_LocalIpCountryCode; } }
/// <summary> /// Initializes a new Snapshot, with the specified Date it was Posted /// </summary> /// <param name="Snapshot">The snapshot source</param> /// <param name="Date">The original date in which this snapshot was created</param> public Snapshot(string Snapshot, DateTime Date) { // Load out database connection this.Driver = ASPServer.Database.Driver; this.Date = Date; this.TimeStamp = Date.ToUnixTimestamp(); // Get our snapshot key value pairs string[] Data = Snapshot.Split('\\'); Snapshot = null; // Check for invalid snapshot string if (Data.Length < 36 || Data.Length % 2 != 0) { IsValidSnapshot = false; return; } // Make sure we have an End of file if (Data[Data.Length - 2] != "EOF" && Data[Data.Length - 4] != "EOF") { IsValidSnapshot = false; return; } // Define if we are central update this.IsCentralUpdate = (Data[Data.Length - 2] == "cdb_update"); // Server data this.ServerPrefix = Data[0]; this.ServerName = Data[1]; this.ServerPort = int.Parse(Data[3].ToString()); this.QueryPort = int.Parse(Data[5].ToString()); // Map Data this.MapName = Data[7]; this.MapId = int.Parse(Data[9]); this.MapStart = (int)Math.Round(float.Parse(Data[11]), 0); this.MapEnd = (int)Math.Round(float.Parse(Data[13]), 0); // Misc Data this.WinningTeam = int.Parse(Data[15]); this.GameMode = int.Parse(Data[17]); this.Mod = Data[21]; this.PlayersConnected = int.Parse(Data[23]); // Army Data this.WinningArmy = int.Parse(Data[25]); this.Team1Army = int.Parse(Data[27]); this.Team1Tickets = int.Parse(Data[29]); this.Team2Army = int.Parse(Data[31]); this.Team2Tickets = int.Parse(Data[33]); // Setup snapshot variables PlayerData = new List<Dictionary<string, string>>(); KillData = new List<Dictionary<string, string>>(); // Check for custom map, with no ID if (MapId == 99) { IsCustomMap = true; // Check for existing data List<Dictionary<string, object>> Rows = Driver.Query("SELECT id FROM mapinfo WHERE name=@P0", MapName); if (Rows.Count == 0) { // Create new MapId Rows = Driver.Query("SELECT MAX(id) AS id FROM mapinfo WHERE id >= " + MainForm.Config.ASP_CustomMapID); MapId = (Rows.Count == 0 || String.IsNullOrWhiteSpace(Rows[0]["id"].ToString())) ? MainForm.Config.ASP_CustomMapID : (Int32.Parse(Rows[0]["id"].ToString()) + 1); // make sure the mapid is at least the min custom map id if (MapId < MainForm.Config.ASP_CustomMapID) MapId = MainForm.Config.ASP_CustomMapID; // Insert map data, so we dont lose this mapid we generated if (Rows.Count == 0 || MapId == MainForm.Config.ASP_CustomMapID) Driver.Execute("INSERT INTO mapinfo(id, name) VALUES (@P0, @P1)", MapId, MapName); } else MapId = Int32.Parse(Rows[0]["id"].ToString()); } else IsCustomMap = (MapId > MainForm.Config.ASP_CustomMapID); // Do player snapshots, 36 is first player for (int i = 36; i < Data.Length; i += 2) { string[] Parts = Data[i].Split('_'); // Ignore uncomplete snapshots if (Parts.Length == 1) { if (Parts[0] == "EOF") break; else IsValidSnapshot = false; return; } int id = int.Parse(Parts[1]); if (Parts[0] == "pID") { PlayerData.Add(new Dictionary<string, string>()); KillData.Add(new Dictionary<string, string>()); } // Kill and death data has its own array key if (Parts[0] == "mvks") continue; if (Parts[0] == "mvns") KillData[id].Add(Data[i + 1], Data[i + 3]); else PlayerData[id].Add(Parts[0], Data[i + 1]); } // Set that we appear to be valid IsValidSnapshot = true; }
/// <summary> /// Fethces the full country name from a country code supplied from GetCountryCode() /// </summary> /// <param name="Code"></param> /// <returns></returns> public static string GetCountyNameFromCode(string Code) { try { using (DatabaseDriver Driver = new DatabaseDriver(DatabaseEngine.Sqlite, ConnectionString)) { // Fetch country code from Ip2Nation Driver.Connect(); List<Dictionary<string, object>> Rows = Driver.Query( "SELECT country FROM ip2nationcountries WHERE iso_code_2 = @P0", Code.ToUpperInvariant() ); return (Rows.Count == 0) ? Code: Rows[0]["country"].ToString(); } } catch { return Code; } }
/// <summary> /// This request provides details of the players unlocked weapons /// </summary> /// <queryParam name="pid" type="int">The unique player ID</queryParam> /// <queryParam name ="nick" type="string">Unique player nickname</queryParam> /// <param name="Client">The HttpClient who made the request</param> /// <param name="Driver">The Stats Database Driver. Connection errors are handled in the calling object</param> public GetUnlocksInfo(HttpClient Client, StatsDatabase Database) { // Load class Variables this.Response = Client.Response; this.Driver = Database; // Earned and Available Unlocks int HasUsed = 0; int Earned = 0; int Available = 0; // Get player ID if (Client.Request.QueryString.ContainsKey("pid")) Int32.TryParse(Client.Request.QueryString["pid"], out Pid); // Prepare Output Response.WriteResponseStart(); Response.WriteHeaderLine("pid", "nick", "asof"); // Our ourput changes based on the selected Unlocks config setting switch(MainForm.Config.ASP_UnlocksMode) { // Player Based - Unlocks are earned case 0: // Make sure the player exists Rows = Driver.Query("SELECT name, score, rank, availunlocks, usedunlocks FROM player WHERE id=@P0", Pid); if(Rows.Count == 0) goto case 2; // No Unlocks // Start Output Response.WriteDataLine(Pid, Rows[0]["name"].ToString().Trim(), DateTime.UtcNow.ToUnixTimestamp()); // Get total number of unlocks player is allowed to have givin his rank, and bonus unlocks Rank = Int32.Parse(Rows[0]["rank"].ToString()); HasUsed = Int32.Parse(Rows[0]["usedunlocks"].ToString()); Available = Int32.Parse(Rows[0]["availunlocks"].ToString()); Earned = GetBonusUnlocks(); // Determine total unlocks available, based on what he has earned, minus what he has used already Rows = Driver.Query("SELECT COUNT(id) AS count FROM unlocks WHERE id = @P0 AND state = 's'", Pid); int Used = Int32.Parse(Rows[0]["count"].ToString()); Earned -= Used; // Update database if the database is off if (Earned != Available || HasUsed != Used) Driver.Execute("UPDATE player SET availunlocks = @P0, usedunlocks = @P1 WHERE id = @P2", Earned, Used, Pid); // Output more Response.WriteHeaderLine("enlisted", "officer"); Response.WriteDataLine(Earned, 0); Response.WriteHeaderLine("id", "state"); // Add each unlock's state Dictionary<string, bool> Unlocks = new Dictionary<string, bool>(); Rows = Driver.Query("SELECT kit, state FROM unlocks WHERE id=@P0 ORDER BY kit ASC", Pid); if (Rows.Count == 0) { // Create Player Unlock Data StringBuilder Query = new StringBuilder("INSERT INTO unlocks VALUES "); // Normal unlocks for (int i = 11; i < 100; i += 11) { // 88 and above are Special Forces unlocks, and wont display at all if the base unlocks are not earned if (i < 78 ) Response.WriteDataLine(i, "n"); Query.AppendFormat("({0}, {1}, 'n'), ", Pid, i); } // Sf Unlocks, Dont display these because thats how Gamespy does it for (int i = 111; i < 556; i += 111) { Query.AppendFormat("({0}, {1}, 'n')", Pid, i); if (i != 555) Query.Append(", "); } // Do Insert Driver.Execute(Query.ToString()); } else { foreach (Dictionary<string, object> Unlock in Rows) { // Add unlock to output if its a base unlock int Id = Int32.Parse(Unlock["kit"].ToString()); if (Id < 78) Response.WriteDataLine(Unlock["kit"], Unlock["state"]); // Add Unlock to list Unlocks.Add(Unlock["kit"].ToString(), (Unlock["state"].ToString() == "s")); } // Add SF Unlocks... We need the base class unlock unlocked first CheckUnlock(88, 22, Unlocks); CheckUnlock(99, 33, Unlocks); CheckUnlock(111, 44, Unlocks); CheckUnlock(222, 55, Unlocks); CheckUnlock(333, 66, Unlocks); CheckUnlock(444, 11, Unlocks); CheckUnlock(555, 77, Unlocks); } break; // All Unlocked case 1: Response.WriteDataLine(Pid, "All_Unlocks", DateTime.UtcNow.ToUnixTimestamp()); Response.WriteHeaderLine("enlisted", "officer"); Response.WriteDataLine(0, 0); Response.WriteHeaderLine("id", "state"); for (int i = 11; i < 100; i += 11) Response.WriteDataLine(i, "s"); for (int i = 111; i < 556; i += 111) Response.WriteDataLine(i, "s"); break; // Unlocks Disabled case 2: default: Response.WriteDataLine(Pid, "No_Unlocks", DateTime.UtcNow.ToUnixTimestamp()); Response.WriteHeaderLine("enlisted", "officer"); Response.WriteDataLine(0, 0); Response.WriteHeaderLine("id", "state"); for (int i = 11; i < 78; i += 11) Response.WriteDataLine(i, "n"); break; } // Send Response Response.Send(); }
/// <summary> /// Creates the connection to the database, and handles /// the excpetion (if any) that are thrown /// </summary> /// <summary> /// Creates the connection to the database, and handles /// the excpetion (if any) that are thrown /// </summary> public void CheckConnection() { if (Driver == null || !Driver.IsConnected) { try { // First time connection if (Driver == null) { // Create database connection Driver = new DatabaseDriver( MainForm.Config.StatsDBEngine, MainForm.Config.StatsDBHost, MainForm.Config.StatsDBPort, MainForm.Config.StatsDBName, MainForm.Config.StatsDBUser, MainForm.Config.StatsDBPass ); Driver.Connect(); // Create SQL tables on new SQLite DB's if (Driver.IsNewDatabase) { CreateSqliteTables(Driver); return; } else { // Try and get database version try { var Rows = Driver.Query("SELECT dbver FROM _version LIMIT 1"); if (Rows.Count == 0) throw new Exception(); // Force insert of IP2Nation } catch { // Table doesnt contain a _version table, so run the createTables.sql if (Driver.DatabaseEngine == DatabaseEngine.Sqlite) CreateSqliteTables(Driver); else CreateMysqlTables(Driver); } return; } } // Connect to DB Driver.Connect(); // Set global packet size with MySql if (Driver.DatabaseEngine == DatabaseEngine.Mysql) Driver.Execute("SET GLOBAL max_allowed_packet=51200"); } catch (Exception E) { throw new Exception( "Database Connect Error: " + Environment.NewLine + E.Message + Environment.NewLine + "Forcing Server Shutdown..." ); } } }