diff --git a/Admin/Admin.cs b/Admin/Admin.cs deleted file mode 100644 index 273f62e69..000000000 --- a/Admin/Admin.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace IW4MAdmin -{ - class Admin - { - public Admin() - { - Time = DateTime.Now; - Server = new Server("127.0.0.1", 28960, "NO"); - } - - public Server Server; - - public static String getTime() - { - return DateTime.Now.ToString("H:mm:ss"); - } - - public void Monitor() - { - Server.Monitor(); - } - - private DateTime Time; - } -} diff --git a/Admin/Application.csproj b/Admin/Application.csproj deleted file mode 100644 index 3077fb01e..000000000 --- a/Admin/Application.csproj +++ /dev/null @@ -1,430 +0,0 @@ - - - - - Debug - AnyCPU - {DD5DCDA2-51DB-4B1A-922F-5705546E6115} - Library - Properties - IW4MAdmin - IW4MAdmin - v4.5.2 - 512 - - - true - ftp://raidmax.org/ - true - Web - true - Foreground - 7 - Days - false - false - false - http://raidmax.org/IW4M/Admin/ - http://raidmax.org/IW4MAdmin - en - IW4M Administration - ForeverNone LLC - publish.htm - false - 6 - 1.3.1.%2a - false - true - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - false - MinimumRecommendedRules.ruleset - false - true - - - x86 - pdbonly - true - bin\Release\ - TRACE - prompt - 3 - true - On - false - false - false - - - - - LocalIntranet - - - - false - - - IW4AdminIcon.ico - - - - - - - - OnOutputUpdated - - - false - - - - - - bin\Release-Stable\ - TRACE - true - true - 3 - pdbonly - x86 - On - prompt - false - MinimumRecommendedRules.ruleset - - - x86 - bin\x86\Debug\ - TRACE;DEBUG - - - x86 - bin\x86\Release\ - true - - - x86 - bin\x86\Release-Stable\ - true - - - true - bin\x64\Debug\ - CODE_ANALYSIS;DEBUG;TRACE - true - full - x64 - true - prompt - false - MinimumRecommendedRules.ruleset - - - bin\x64\Release-Nightly\ - TRACE - true - true - 3 - pdbonly - x64 - On - prompt - false - MinimumRecommendedRules.ruleset - - - bin\x64\Release-Stable\ - TRACE - true - true - 3 - pdbonly - x64 - On - prompt - false - MinimumRecommendedRules.ruleset - true - - - bin\Release\ - TRACE - true - true - 3 - pdbonly - x86 - On - prompt - false - MinimumRecommendedRules.ruleset - - - bin\x86\Release\ - true - x86 - MinimumRecommendedRules.ruleset - - - bin\x64\Release\ - TRACE - true - true - 3 - pdbonly - x64 - On - prompt - false - MinimumRecommendedRules.ruleset - true - - - - - - - - - - - - - - - - - - True - True - Settings.settings - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Always - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Visual C++ 2013 Runtime Libraries %28x86%29 - true - - - - - False - - - - - DataFile - True - File - - - False - - - - - DataFile - True - File - - - False - - - - - DataFile - True - File - - - False - - - - - Exclude - True - Assembly - - - False - - - - - Exclude - True - Assembly - - - False - - - - - Exclude - True - Assembly - - - False - - - - - Exclude - True - Assembly - - - - - {d51eeceb-438a-47da-870f-7d7b41bc24d6} - SharedLibrary - False - - - - - - - - xcopy /E "$(SolutionDir)lib" "$(TargetDir)lib" -copy /Y "$(SolutionDir)_customcallbacks.gsc" "$(SolutionDir)BUILD\userraw\scripts\_customcallbacks.gsc" - -copy /Y "$(TargetDir)$(TargetName).exe" "$(SolutionDir)BUILD" -copy /Y "$(TargetDir)IW4MAdmin.exe.config" "$(SolutionDir)BUILD" -xcopy /Y /I /E "$(SolutionDir)SharedLibrary\$(OutDir)*" "$(SolutionDir)Admin\Lib" - -xcopy /Y /I /E "$(ProjectDir)webfront\*" "$(SolutionDir)BUILD\Webfront" -xcopy /Y /I /E "$(SolutionDir)Admin\Config\*" "$(SolutionDir)BUILD\Config" - -if $(ConfigurationName) == Release-Nightly powershell.exe -file "$(SolutionDir)DEPLOY\publish_nightly.ps1" 1.6 -if $(ConfigurationName) == Release-Stable powershell.exe -file "$(SolutionDir)DEPLOY\publish_stable.ps1" 1.6 - - - - - - - - - - \ No newline at end of file diff --git a/Admin/Database.cs b/Admin/Database.cs deleted file mode 100644 index 2314636e4..000000000 --- a/Admin/Database.cs +++ /dev/null @@ -1,621 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Data.SQLite; -using System.Data; -using System.Linq; -using System.IO; -using System.Collections; -using SharedLibrary; - -namespace IW4MAdmin -{ - abstract class DatabaseA : SharedLibrary.Database - { - public Database(String FN) - { - FileName = FN; - DBCon = String.Format("Data Source={0}", FN); - Con = new SQLiteConnection(DBCon); - Open = false; - Init(); - } - - abstract public void Init(); - - //HELPERS - protected bool Insert(String tableName, Dictionary data) - { - String columns = ""; - String values = ""; - Boolean returnCode = true; - foreach (KeyValuePair val in data) - { - columns += String.Format(" {0},", val.Key); - values += String.Format(" '{0}',", val.Value); - } - columns = columns.Substring(0, columns.Length - 1); - values = values.Substring(0, values.Length - 1); - try - { - this.ExecuteNonQuery(String.Format("insert into {0}({1}) values({2});", tableName, columns, values)); - } - catch (Exception fail) - { - Console.WriteLine(fail.Message); - returnCode = false; - } - return returnCode; - } - - protected bool Update(String tableName, Dictionary data, String where) - { - String vals = ""; - Boolean returnCode = true; - if (data.Count >= 1) - { - foreach (KeyValuePair val in data) - { - vals += String.Format(" {0} = '{1}',", val.Key, val.Value); - } - vals = vals.Substring(0, vals.Length - 1); - } - try - { - ExecuteNonQuery(String.Format("update {0} set {1} where {2};", tableName, vals, where)); - } - catch (Exception fail) - { - Console.WriteLine(fail.Message); - returnCode = false; - } - return returnCode; - } - - protected DataRow getDataRow(String Q) - { - DataRow Result = GetDataTable(Q).Rows[0]; - return Result; - } - - protected int ExecuteNonQuery(String Request) - { - waitForClose(); - int rowsUpdated = 0; - - lock (Con) - { - Con.Open(); - SQLiteCommand CMD = new SQLiteCommand(Con); - CMD.CommandText = Request; - rowsUpdated = CMD.ExecuteNonQuery(); - Con.Close(); - } - - return rowsUpdated; - } - - protected DataTable GetDataTable(String sql) - { - DataTable dt = new DataTable(); - try - { - waitForClose(); - lock (Con) - { - Con.Open(); - SQLiteCommand mycommand = new SQLiteCommand(Con); - mycommand.CommandText = sql; - SQLiteDataReader reader = mycommand.ExecuteReader(); - dt.Load(reader); - reader.Close(); - Con.Close(); - } - - } - catch (Exception e) - { - Console.WriteLine(e.Message); - throw new Exception(e.Message); - } - return dt; - } - - protected void waitForClose() - { - while (Con.State == ConnectionState.Open) - { - Utilities.Wait(0.01); - } - - return; - } - - protected String FileName; - protected String DBCon; - protected SQLiteConnection Con; - protected bool Open; - } - - class ClientsDB : Database - { - public ClientsDB(String FN) : base(FN) { } - - public override void Init() - { - if(!File.Exists(FileName)) - { - String Create = "CREATE TABLE [CLIENTS] ( [Name] TEXT NULL, [npID] TEXT NULL, [Number] INTEGER PRIMARY KEY AUTOINCREMENT, [Level] INT DEFAULT 0 NULL, [LastOffense] TEXT NULL, [Connections] INT DEFAULT 1 NULL, [IP] TEXT NULL, [LastConnection] TEXT NULL);"; - ExecuteNonQuery(Create); - Create = "CREATE TABLE [BANS] ( [Reason] TEXT NULL, [npID] TEXT NULL, [bannedByID] TEXT NULL, [IP] TEXT NULL, [TIME] TEXT NULL);"; - ExecuteNonQuery(Create); - } - } - - //Returns a single player object with matching GUID, false if no matches - public Player getPlayer(String ID, int cNum) - { - String Query = String.Format("SELECT * FROM CLIENTS WHERE npID = '{0}' LIMIT 1", ID); - DataTable Result = GetDataTable(Query); - - if (Result != null && Result.Rows.Count > 0) - { - DataRow ResponseRow = Result.Rows[0]; - DateTime LC; - - try - { - LC = DateTime.Parse(ResponseRow["LastConnection"].ToString()); - } - catch (Exception) - { - LC = DateTime.Now; - } - - return new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), cNum, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString(), LC); - } - - else - return null; - } - - //Overloaded method for getPlayer, returns Client with matching DBIndex, null if none found - public Player getPlayer(int dbIndex) - { - String Query = String.Format("SELECT * FROM CLIENTS WHERE Number = '{0}' LIMIT 1", dbIndex); - DataTable Result = GetDataTable(Query); - - if (Result != null && Result.Rows.Count > 0) - { - DataRow p = Result.Rows[0]; - DateTime LC; - try - { - LC = DateTime.Parse(p["LastConnection"].ToString()); - } - catch (Exception) - { - LC = DateTime.Now; - } - - return new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32(p["Connections"]), p["IP"].ToString(), LC); - } - - else - return null; - } - - //get player by ip, (used for webfront) - public Player getPlayer(String IP) - { - String Query = String.Format("SELECT * FROM CLIENTS WHERE IP='{0}'", IP); - DataTable Result = GetDataTable(Query); - - if (Result != null && Result.Rows.Count > 0) - { - List lastKnown = new List(); - foreach (DataRow p in Result.Rows) - { - DateTime LC; - try - { - LC = DateTime.Parse(p["LastConnection"].ToString()); - lastKnown.Add(new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32((DateTime.Now - LC).TotalSeconds), p["IP"].ToString(), LC)); - } - - catch (Exception) - { - continue; - } - } - - if (lastKnown.Count > 0) - { - List Returning = lastKnown.OrderBy(t => t.Connections).ToList(); - return Returning[0]; - } - - else - return null; - } - - else - return null; - } - - //Returns a list of players matching name parameter, null if no players found matching - public List findPlayers(String name) - { - String Query = String.Format("SELECT * FROM CLIENTS WHERE Name LIKE '%{0}%' LIMIT 8", name); - DataTable Result = GetDataTable(Query); - - List Players = new List(); - - if (Result != null && Result.Rows.Count > 0) - { - foreach (DataRow p in Result.Rows) - { - DateTime LC; - try - { - LC = DateTime.Parse(p["LastConnection"].ToString()); - } - catch (Exception) - { - LC = DateTime.Now; - } - - Players.Add(new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32(p["Connections"]), p["IP"].ToString(), LC)); - } - return Players; - } - - else - return null; - } - - //Returns any player with level 4 permissions, null if no owner found - public Player getOwner() - { - String Query = String.Format("SELECT * FROM CLIENTS WHERE Level > '{0}'", 4); - DataTable Result = GetDataTable(Query); - - if (Result != null && Result.Rows.Count > 0) - { - DataRow ResponseRow = Result.Rows[0]; - if (ResponseRow["IP"].ToString().Length < 6) - ResponseRow["IP"] = "0"; - return new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), null, 0, ResponseRow["IP"].ToString()); - } - - else - return null; - } - - //Returns list of bans in database - public List getBans() - { - List Bans = new List(); - DataTable Result = GetDataTable("SELECT * FROM BANS ORDER BY TIME DESC"); - - foreach (DataRow Row in Result.Rows) - { - if (Row["TIME"].ToString().Length < 2) //compatibility with my old database - Row["TIME"] = DateTime.Now.ToString(); - - Bans.Add(new Ban(Row["Reason"].ToString(), Row["npID"].ToString(), Row["bannedByID"].ToString(), DateTime.Parse(Row["TIME"].ToString()), Row["IP"].ToString())); - } - - return Bans; - } - - //Returns all players with level > Flagged - public List getAdmins() - { - List Admins = new List(); - String Query = String.Format("SELECT * FROM CLIENTS WHERE LEVEL > '{0}'", 1); - DataTable Result = GetDataTable(Query); - - foreach (DataRow P in Result.Rows) - Admins.Add(new Player(P["Name"].ToString(), P["npID"].ToString(), (Player.Permission)P["Level"], P["IP"].ToString())); - - return Admins; - } - - //Returns total number of player entries in database - public int totalPlayers() - { - DataTable Result = GetDataTable("SELECT * from CLIENTS ORDER BY Number DESC LIMIT 1"); - if (Result.Rows.Count > 0) - return Convert.ToInt32(Result.Rows[0]["Number"]); - else - return 0; - } - - //Add specified player to database - public void addPlayer(Player P) - { - Dictionary newPlayer = new Dictionary(); - - newPlayer.Add("Name", Utilities.removeNastyChars(P.Name)); - newPlayer.Add("npID", P.npID); - newPlayer.Add("Level", (int)P.Level); - newPlayer.Add("LastOffense", ""); - newPlayer.Add("Connections", 1); - newPlayer.Add("IP", P.IP); - newPlayer.Add("LastConnection", Utilities.DateTimeSQLite(DateTime.Now)); - - Insert("CLIENTS", newPlayer); - } - - ///Update information of specified player - public void updatePlayer(Player P) - { - Dictionary updatedPlayer = new Dictionary(); - - updatedPlayer.Add("Name", P.Name); - updatedPlayer.Add("npID", P.npID); - updatedPlayer.Add("Level", (int)P.Level); - updatedPlayer.Add("LastOffense", P.LastOffense); - updatedPlayer.Add("Connections", P.Connections); - updatedPlayer.Add("IP", P.IP); - updatedPlayer.Add("LastConnection", Utilities.DateTimeSQLite(DateTime.Now)); - - Update("CLIENTS", updatedPlayer, String.Format("npID = '{0}'", P.npID)); - } - - - //Add specified ban to database - public void addBan(Ban B) - { - Dictionary newBan = new Dictionary(); - - newBan.Add("Reason", B.getReason()); - newBan.Add("npID", B.getID()); - newBan.Add("bannedByID", B.getBanner()); - newBan.Add("IP", B.getIP()); - newBan.Add("TIME", Utilities.DateTimeSQLite(DateTime.Now)); - - Insert("BANS", newBan); - } - - - //Deletes ban with matching GUID - public void removeBan(String GUID) - { - String Query = String.Format("DELETE FROM BANS WHERE npID = '{0}'", GUID); - ExecuteNonQuery(Query); - } - - public void removeBan(String GUID, String IP) - { - String Query = String.Format("DELETE FROM BANS WHERE npID = '{0}' or IP= '%{1}%'", GUID, IP); - ExecuteNonQuery(Query); - } - } - - class StatsDB : Database - { - public StatsDB(String FN) : base(FN) { } - - public override void Init() - { - if (!File.Exists(FileName)) - { - String Create = "CREATE TABLE [STATS] ( [Number] INTEGER, [KILLS] INTEGER DEFAULT 0, [DEATHS] INTEGER DEFAULT 0, [KDR] REAL DEFAULT 0, [SKILL] REAL DEFAULT 0, [MEAN] REAL DEFAULT 0, [DEV] REAL DEFAULT 0 );"; - ExecuteNonQuery(Create); - } - } - - // Return stats for player specified by Database ID, null if no matches - public Stats getStats(int DBID) - { - String Query = String.Format("SELECT * FROM STATS WHERE Number = '{0}'", DBID); - DataTable Result = GetDataTable(Query); - - if (Result != null && Result.Rows.Count > 0) - { - DataRow ResponseRow = Result.Rows[0]; - if (ResponseRow["MEAN"] == DBNull.Value) - ResponseRow["MEAN"] = Moserware.Skills.GameInfo.DefaultGameInfo.DefaultRating.Mean; - if (ResponseRow["DEV"] == DBNull.Value) - ResponseRow["DEV"] = Moserware.Skills.GameInfo.DefaultGameInfo.DefaultRating.StandardDeviation; - if (ResponseRow["SKILL"] == DBNull.Value) - ResponseRow["SKILL"] = 0; - - return new Stats(Convert.ToInt32(ResponseRow["Number"]), Convert.ToInt32(ResponseRow["KILLS"]), Convert.ToInt32(ResponseRow["DEATHS"]), Convert.ToDouble(ResponseRow["KDR"]), Convert.ToDouble(ResponseRow["SKILL"]), Convert.ToDouble(ResponseRow["MEAN"]), Convert.ToDouble(ResponseRow["DEV"])); - } - - else - return null; - } - - public void addPlayer(Player P) - { - Dictionary newPlayer = new Dictionary(); - - newPlayer.Add("Number", P.databaseID); - newPlayer.Add("KILLS", 0); - newPlayer.Add("DEATHS", 0); - newPlayer.Add("KDR", 0); - newPlayer.Add("SKILL", Moserware.Skills.GameInfo.DefaultGameInfo.DefaultRating.ConservativeRating); - newPlayer.Add("MEAN", Moserware.Skills.GameInfo.DefaultGameInfo.DefaultRating.Mean); - newPlayer.Add("DEV", Moserware.Skills.GameInfo.DefaultGameInfo.DefaultRating.StandardDeviation); - - Insert("STATS", newPlayer); - } - - //Update stat information of specified player - public void updatePlayer(Player P) - { - if (P.stats == null) - return; - - Dictionary updatedPlayer = new Dictionary(); - - updatedPlayer.Add("KILLS", P.stats.Kills); - updatedPlayer.Add("DEATHS", P.stats.Deaths); - updatedPlayer.Add("KDR", Math.Round(P.stats.KDR, 2)); - updatedPlayer.Add("SKILL", P.stats.Skill); - //updatedPlayer.Add("MEAN", P.stats.Rating.Mean); - //updatedPlayer.Add("DEV", P.stats.Rating.StandardDeviation); - - Update("STATS", updatedPlayer, String.Format("Number = '{0}'", P.databaseID)); - } - - //Returns top 5 players (we filter through them later) - public List topStats() - { - String Query = String.Format("SELECT * FROM STATS WHERE KILLS > '{0}' AND KDR < '{1}' AND SKILL > '{2}' ORDER BY SKILL DESC LIMIT 5", 250, 7, 245); - DataTable Result = GetDataTable(Query); - - List Top = new List(); - - if (Result != null && Result.Rows.Count > 0) - { - foreach (DataRow D in Result.Rows) - { - if (D["MEAN"] == DBNull.Value || D["DEV"] == DBNull.Value || D["SKILL"] == DBNull.Value) - continue; - - Stats S = new Stats(Convert.ToInt32(D["Number"]), Convert.ToInt32(D["KILLS"]), Convert.ToInt32(D["DEATHS"]), Convert.ToDouble(D["KDR"]), Convert.ToDouble(D["SKILL"]), Convert.ToDouble(D["MEAN"]), Convert.ToDouble(D["DEV"])); - Top.Add(S); - } - } - - return Top; - } - - public List getMultipleStats(int start, int length) - { - String Query = String.Format("SELECT * FROM STATS ORDER BY SKILL DESC LIMIT '{0}' OFFSET '{1}'", length, start); - DataTable Result = GetDataTable(Query); - - List Stats = new List(); - - if (Result != null && Result.Rows.Count > 0) - { - foreach (DataRow D in Result.Rows) - { - if (D["MEAN"] == DBNull.Value) - continue; - if (D["DEV"] == DBNull.Value) - continue; - - if (D["SKILL"] == DBNull.Value) - D["SKILL"] = 0; - - Stats S = new Stats(Convert.ToInt32(D["Number"]), Convert.ToInt32(D["KILLS"]), Convert.ToInt32(D["DEATHS"]), Convert.ToDouble(D["KDR"]), Convert.ToDouble(D["SKILL"]), Convert.ToDouble(D["MEAN"]), Convert.ToDouble(D["DEV"])); - Stats.Add(S); - } - } - - return Stats; - } - - public int totalStats() - { - DataTable Result = GetDataTable("SELECT * FROM STATS"); - return Result.Rows.Count; - } - - public void clearSkill() - { - String Query = "SELECT * FROM STATS"; - DataTable Result = GetDataTable(Query); - - if (Result != null && Result.Rows.Count > 0) - { - foreach (DataRow D in Result.Rows) - Update("STATS", new Dictionary () { {"SKILL", 1} }, String.Format("Number = '{0}'", D["Number"])); - } - } - } - - class AliasesDB : Database - { - public AliasesDB(String FN) : base(FN) { } - - public override void Init() - { - if (!File.Exists(FileName)) - { - String Create = "CREATE TABLE [ALIASES] ( [Number] INTEGER, [NAMES] TEXT NULL, [IPS] TEXTNULL );"; - ExecuteNonQuery(Create); - } - } - - public Aliases getPlayer(int dbIndex) - { - String Query = String.Format("SELECT * FROM ALIASES WHERE Number = '{0}' LIMIT 1", dbIndex); - DataTable Result = GetDataTable(Query); - - if (Result != null && Result.Rows.Count > 0) - { - DataRow p = Result.Rows[0]; - return new Aliases(Convert.ToInt32(p["Number"]), p["NAMES"].ToString(), p["IPS"].ToString()); - } - - else - return null; - } - - public List getPlayer(String IP) - { - String Query = String.Format("SELECT * FROM ALIASES WHERE IPS LIKE '%{0}%'", IP); - DataTable Result = GetDataTable(Query); - List players = new List(); - - if (Result != null && Result.Rows.Count > 0) - { - foreach (DataRow p in Result.Rows) - players.Add(new Aliases(Convert.ToInt32(p["Number"]), p["NAMES"].ToString(), p["IPS"].ToString())); - } - - return players; - } - - public List findPlayers(String name) - { - String[] EyePee = name.Split('.'); - String Penor = "THISISNOTANIP"; - if (EyePee.Length > 1) - Penor = (EyePee[0] + '.' + EyePee[1] + '.'); - - String Query = String.Format("SELECT * FROM ALIASES WHERE NAMES LIKE '%{0}%' OR IPS LIKE '%{1}%' LIMIT 15", name, Penor); - DataTable Result = GetDataTable(Query); - - List players = new List(); - - if (Result != null && Result.Rows.Count > 0) - { - foreach (DataRow p in Result.Rows) - players.Add(new Aliases(Convert.ToInt32(p["Number"]), p["NAMES"].ToString(), p["IPS"].ToString())); - } - - return players; - } - - public void addPlayer(Aliases Alias) - { - Dictionary newPlayer = new Dictionary(); - - newPlayer.Add("Number", Alias.getNumber()); - newPlayer.Add("NAMES", Alias.getNamesDB()); - newPlayer.Add("IPS", Alias.getIPSDB()); - - Insert("ALIASES", newPlayer); - } - - public void updatePlayer(Aliases Alias) - { - Dictionary updatedPlayer = new Dictionary(); - - updatedPlayer.Add("Number", Alias.getNumber()); - updatedPlayer.Add("NAMES", Alias.getNamesDB()); - updatedPlayer.Add("IPS", Alias.getIPSDB()); - - Update("ALIASES", updatedPlayer, String.Format("Number = '{0}'", Alias.getNumber())); - } - } -} diff --git a/Admin/File.cs b/Admin/File.cs deleted file mode 100644 index c6008609c..000000000 --- a/Admin/File.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; - -namespace IW4MAdmin -{ - class IFile - { - public IFile(String fileName) - { - //Not safe for directories with more than one folder but meh - _Directory = fileName.Split('\\')[0]; - Name = (fileName.Split('\\'))[fileName.Split('\\').Length-1]; - - if (!Directory.Exists(_Directory)) - Directory.CreateDirectory(_Directory); - - if (!File.Exists(fileName)) - { - try - { - FileStream penis = File.Create(fileName); - penis.Close(); - } - - catch - { - Console.WriteLine("Unable to open log file for writing!"); - } - } - - try - { - Handle = new StreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); - sze = Handle.BaseStream.Length; - } - - catch - { - //Console.WriteLine("Unable to open log file for writing!"); - } - } - - public IFile(String file, bool write) - { - Name = file; - writeHandle = new StreamWriter(new FileStream(Name, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)); - sze = 0; - } - - public long getSize() - { - sze = Handle.BaseStream.Length; - return sze; - } - - public void Write(String line) - { - if (writeHandle != null) - { - writeHandle.WriteLine(line); - writeHandle.Flush(); - } - } - - public String[] getParameters(int num) - { - if (sze > 0) - { - String firstLine = Handle.ReadLine(); - String[] Parms = firstLine.Split(':'); - if (Parms.Length < num) - return null; - else - return Parms; - } - - return null; - } - - public void Close() - { - if(Handle != null) - Handle.Close(); - if (writeHandle != null) - writeHandle.Close(); - } - - public String[] readAll() - { - return Handle.ReadToEnd().Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); - } - - public String getLines() - { - return Handle.ReadToEnd(); - } - - public String[] Tail(int lineCount) - { - var buffer = new List(lineCount); - string line; - for (int i = 0; i < lineCount; i++) - { - line = Handle.ReadLine(); - if (line == null) return buffer.ToArray(); - buffer.Add(line); - } - - int lastLine = lineCount - 1; //The index of the last line read from the buffer. Everything > this index was read earlier than everything <= this indes - - while (null != (line = Handle.ReadLine())) - { - lastLine++; - if (lastLine == lineCount) lastLine = 0; - buffer[lastLine] = line; - } - - if (lastLine == lineCount - 1) return buffer.ToArray(); - var retVal = new string[lineCount]; - buffer.CopyTo(lastLine + 1, retVal, 0, lineCount - lastLine - 1); - buffer.CopyTo(0, retVal, lineCount - lastLine - 1, lastLine + 1); - return retVal; - } - //END - - private long sze; - private String Name; - private String _Directory; - StreamReader Handle; - StreamWriter writeHandle; - } -} diff --git a/Admin/IW4AdminIcon.ico b/Admin/IW4AdminIcon.ico deleted file mode 100644 index 3edaf82e7..000000000 Binary files a/Admin/IW4AdminIcon.ico and /dev/null differ diff --git a/Admin/IW4M-Admin - Shortcut.lnk b/Admin/IW4M-Admin - Shortcut.lnk deleted file mode 100644 index 42d3849b7..000000000 Binary files a/Admin/IW4M-Admin - Shortcut.lnk and /dev/null differ diff --git a/Admin/Properties/AssemblyInfo.cs b/Admin/Properties/AssemblyInfo.cs deleted file mode 100644 index 98e27902d..000000000 --- a/Admin/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Resources; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("IW4MAdmin Application")] -[assembly: AssemblyDescription("Server administration for IW4X Servers")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("ForeverNone LLC")] -[assembly: AssemblyProduct("IW4MAdmin")] -[assembly: AssemblyCopyright("2018")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(true)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("62f47df4-c8eb-4b5d-bdd8-9de0ca6b570f")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.6.*")] -[assembly: NeutralResourcesLanguageAttribute("en")] diff --git a/Admin/Properties/Settings.Designer.cs b/Admin/Properties/Settings.Designer.cs deleted file mode 100644 index 7f8642214..000000000 --- a/Admin/Properties/Settings.Designer.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IW4MAdmin.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.5.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} diff --git a/Admin/Properties/Settings.settings b/Admin/Properties/Settings.settings deleted file mode 100644 index 049245f40..000000000 --- a/Admin/Properties/Settings.settings +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/Admin/Webfront/_header.html b/Admin/Webfront/_header.html deleted file mode 100644 index 6efa94c1a..000000000 --- a/Admin/Webfront/_header.html +++ /dev/null @@ -1,105 +0,0 @@ - - - - - IW4MAdmin by RaidMax - - - - - - - - - - - - -
-
diff --git a/Admin/Webfront/profile.html b/Admin/Webfront/profile.html deleted file mode 100644 index 308a50c37..000000000 --- a/Admin/Webfront/profile.html +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - - IW4MAdmin by RaidMax - - - - - - - - - - - - -
-
-
-
-
- _ -
-
-
-
- -
-
-
- _ -
-
- Played _ hours -
-
- First seen _ ago -
-
- Last seen _ ago -
-
-
-
-
-
-
- No recent events -
-
-
-
- - diff --git a/Admin/app.manifest b/Admin/app.manifest deleted file mode 100644 index ddbf42b9f..000000000 --- a/Admin/app.manifest +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Admin/config/maps.cfg b/Admin/config/maps.cfg deleted file mode 100644 index 14317d6b2..000000000 --- a/Admin/config/maps.cfg +++ /dev/null @@ -1,44 +0,0 @@ -mp_rust:Rust -mp_highrise:Highrise -mp_terminal:Terminal -mp_crash:Crash -mp_nightshift:Skidrow -mp_quarry:Quarry -mp_afghan:Afghan -mp_derail:Derail -mp_estate:Estate -mp_favela:Favela -mp_highrise:Highrise -mp_invasion:Invasion -mp_checkpoint:Karachi -mp_quarry:Quarry -mp_rundown:Rundown -mp_boneyard:Scrapyard -mp_nightshift:Skidrow -mp_subbase:Sub Base -mp_underpass:Underpass -mp_brecourt:Wasteland -mp_overgrown:Overgrown -mp_strike:Strike -mp_vacant:Vacant -mp_abandon:Carnival -mp_trailerpark:Trailer Park -mp_fuel2:Fuel -mp_storm:Storm -mp_complex:Bailout -mp_compact:Salvage -mp_nuked:Nuketown -iw4_credits:IW4 Credits -mp_killhouse:Killhouse -mp_bog_sh:Bog -mp_cargoship_sh:Freighter -mp_shipment:Shipment -mp_shipment_long:Shipment - Long -mp_rust_long:Rust - Long -mp_firingrange:Firing Range -mp_storm_spring:Chemical Plant -mp_fav_tropical:Favela - Tropical -mp_estate_tropical:Estate - Tropical -mp_crash_tropical:Crash - Tropical -mp_bloc_sh:Forgotten City -mp_raidmax:^1L^23^33^4T^5M^6A^75^8T^93^0R \ No newline at end of file diff --git a/Admin/config/messages.cfg b/Admin/config/messages.cfg deleted file mode 100644 index c72ab1b78..000000000 --- a/Admin/config/messages.cfg +++ /dev/null @@ -1,8 +0,0 @@ -60 -Over ^5{{TOTALPLAYTIME}} ^7man hours have been played on this server! -This server uses ^5IW4M Admin v{{VERSION}} ^7get it at ^5raidmax.org/IW4MAdmin -^5IW4M Admin ^7sees ^5YOU! -This server has harvested the information of ^5{{TOTALPLAYERS}} ^7players! -Cheaters are ^1unwelcome ^7 on this server -Did you know 8/10 people agree with unverified statistics? -^5{{TOTALKILLS}} ^7innocent people have been murdered in this server! \ No newline at end of file diff --git a/Admin/config/rules.cfg b/Admin/config/rules.cfg deleted file mode 100644 index 71e9fe9a8..000000000 --- a/Admin/config/rules.cfg +++ /dev/null @@ -1,6 +0,0 @@ -Cheating/Exploiting is not allowed -Respect other players -Administrators have the final say -No Racism or excessive trolling -Keep grenade launcher use to a minimum -Balance teams at ALL times \ No newline at end of file diff --git a/Admin/config/web.cfg b/Admin/config/web.cfg deleted file mode 100644 index 499c2157c..000000000 --- a/Admin/config/web.cfg +++ /dev/null @@ -1,2 +0,0 @@ -127.0.0.1 -80 \ No newline at end of file diff --git a/Admin/lib b/Admin/lib deleted file mode 100644 index fc38b3684..000000000 Binary files a/Admin/lib and /dev/null differ diff --git a/Admin/packages.config b/Admin/packages.config deleted file mode 100644 index a272c64df..000000000 --- a/Admin/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Admin/webfront/admins.html b/Admin/webfront/admins.html deleted file mode 100644 index 836f89b14..000000000 --- a/Admin/webfront/admins.html +++ /dev/null @@ -1,71 +0,0 @@ - - - -
-
-
Owner
-
-
-
- -
-
-
Senior Administrator
-
-
-
- -
-
-
Administrator
-
-
-
- -
-
-
Moderator
-
-
-
- -
-
-
Trusted
-
-
-
-
\ No newline at end of file diff --git a/Admin/webfront/bans.html b/Admin/webfront/bans.html deleted file mode 100644 index 0f8480a8b..000000000 --- a/Admin/webfront/bans.html +++ /dev/null @@ -1,5 +0,0 @@ -
-
Penalties
Back
-
- {{BANS}} -
\ No newline at end of file diff --git a/Admin/webfront/chat.html b/Admin/webfront/chat.html deleted file mode 100644 index 6aef35315..000000000 --- a/Admin/webfront/chat.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - \ No newline at end of file diff --git a/Admin/webfront/console.html b/Admin/webfront/console.html deleted file mode 100644 index ae50750f5..000000000 --- a/Admin/webfront/console.html +++ /dev/null @@ -1,70 +0,0 @@ -
- -
-
-
-
-
- - -
-
- diff --git a/Admin/webfront/error.html b/Admin/webfront/error.html deleted file mode 100644 index 06af03051..000000000 --- a/Admin/webfront/error.html +++ /dev/null @@ -1,11 +0,0 @@ -
-
ERROR!
Back
-
-
-
-
-
- Uh Oh, it looks like there was an error processing your request.
- Reason: {{ERROR}} -
-
diff --git a/Admin/webfront/footer.html b/Admin/webfront/footer.html deleted file mode 100644 index 80a785395..000000000 --- a/Admin/webfront/footer.html +++ /dev/null @@ -1,8 +0,0 @@ -
- - - - - diff --git a/Admin/webfront/images/minimap_mp_rust.png b/Admin/webfront/images/minimap_mp_rust.png deleted file mode 100644 index dea454aa9..000000000 Binary files a/Admin/webfront/images/minimap_mp_rust.png and /dev/null differ diff --git a/Admin/webfront/images/minimap_mp_terminal.png b/Admin/webfront/images/minimap_mp_terminal.png deleted file mode 100644 index a0fe667f7..000000000 Binary files a/Admin/webfront/images/minimap_mp_terminal.png and /dev/null differ diff --git a/Admin/webfront/login.html b/Admin/webfront/login.html deleted file mode 100644 index b94079b1c..000000000 --- a/Admin/webfront/login.html +++ /dev/null @@ -1,12 +0,0 @@ -
-
Register
-
-
-
- - - - - -
-
diff --git a/Admin/webfront/main.css b/Admin/webfront/main.css deleted file mode 100644 index 9eb8edd45..000000000 --- a/Admin/webfront/main.css +++ /dev/null @@ -1,237 +0,0 @@ -* { margin: 0; padding: 0; } -html { background-color: rgb(34, 34, 34); color: rgb(204, 204, 204); font-family: 'Open Sans', serif; min-width: 720px; } -body { background-color: rgb(34,34,34); color: rgb(204, 204, 204); font-family: 'Open Sans'; } - -a:link, a:visited, input[type="submit"], input[type="submit"]:hover { -webkit-transition: color 100ms ease-out; -moz-transition: color 100ms ease-out; -o-transition: color 100ms ease-out; transition: color 100ms ease-out; text-decoration: none; color: rgb(204, 204, 204); } -a:link:hover, a:visited:hover { color: rgb(0, 122, 204); } - -.error { color: rgba(255, 69, 69, 0.85); } - -div#header { border-bottom: solid #ff6633 1px; width: calc(100% - 10px); background-color: #181818; padding-left: 10px; } - -div#header #navHeader { color: #fff; font-size: 4vw; width: 25vw; } -div#header #navContainer { display: table; width: 100%; } -div#header #navContainer .navEntry { display: table-cell; text-align: center; vertical-align: middle; } -div#header #navContainer .navEntry a { padding: 1.2vw; width: 4vw; } -div#header #navContainer .navEntry:hover { background-color: rgb(34, 34, 34); } - -div#content { margin: 3em 10%; } -div#content .serverContainer { background-color: #191919; margin-top: 0; margin-bottom: 0; font-size: 1.25vw; padding-bottom: 100px; } -div#content hr { border-width: 0; height: 0.25em; background-color: #007ACC; } -div#content .serverInfo { width: 100%; } -div#content .serverInfo .tableCell { padding: 0 0.5em; } - -div#content .serverTitle { width: calc( 100% / 3); background-color: #007ACC; } -div#content .serverPlayers { text-align: right; width: calc( 100% / 3); background-color: #007ACC; } -div#content .serverMap { text-align: center; width: calc( 100% / 3); background-color: #007ACC; } -div#content .serverPlayerList {float: right; margin: 0.5em; } -div#content .serverChatList { float: left; margin: 0.5em; max-width: 60%; overflow:hidden } -div#content .playerName { font-size: 1.1vw; color: rgba(78, 140, 77, 0.64); width: 10em; text-align: right; } -div#content .playerName:hover { color: rgb(0, 122, 204) !important; } -div#content .chatPlayerName { font-weight: bold; font-size: 1.1vw; color:#fff; padding-right: 0.5em; opacity: 0.5; } -div#content .chatPlayerMessage {font-size: 1.1vw; color: #fff; opacity: 1; } - -div#content .playerPenalty, div#content .playerInfo { margin: 0 auto; padding: 1em 10px; background-color: #181818; width: calc(100% - 20px); } -div#content .penaltyName { width: 15%; } -div#content .penaltyName a:link, div#content .penaltyName a:visited, div#content .playerInfo a:link, div#content .playerInfo a:visited { color: rgb(0, 122, 204) !important; } -div#content .penaltyName a:hover, div#content .playerInfo a:hover { color: rgb(255, 255, 255) !important; opacity: 0.75; } -div#content .penaltyTime { text-align: left; width:8%; } -div#content .penaltyOrigin {width: 12%;} -div#content .penaltyRemaining { text-align: right; width: 10%; } -div#content .playerPenalty .penaltyTime { opacity: 0.5; } -div#content .penaltyType { width: 10%; } -div#content .penaltyReason { width: 45%; } -div#content .penaltyHeader, div#content .contentHeader { width: calc(100% - 20px); background-color: #007ACC; font-size: 15pt; padding: 0.5em 10px; } -div#content .alternate_1 { background-color: rgb(34, 34, 34); } - -div#content #paginationButtons { color: #007ACC; font-size: 30pt; } -div#content #nextPage, div#content #previousPage { padding-right: 0.5em; padding-top: 0.5em; } - -div#content .contentColumn { width: 16%; } - -div#content .playerSearchWrap { width: 60%; margin-bottom: 3em; } -div#content .search { background-color: #181818; border: none; color: #fff; font-size: 16pt; width: 60%; font-size: 15pt; padding: 0.5em 10px; } -div#content .searchButton { width: 20%; background-color: #007ACC; font-size: 16pt; border: none; color: #fff; font-size: 15pt; padding: 0.5em 10px; margin-right: -5px; } -div#content .searchButton:hover { color: #fff; } - -div#content .playerInfo .tableCell { width: 16%; } -div#content .hiddenElements { display: none; color: rgb(204, 204, 204); } -div#content .hiddenWrapper { color: #007ACC;} - -div#content #consoleWrap { width: 60%; margin: 0 auto; } -div#content #console { padding: 1em; height: 35vh; background-color: #181818; } -div#content #consoleWrap .search { width: calc(80% - 10px); float: left; } -div#consoleWrap .playerSearchWrap input[type="text"]:focus, select:focus { border-width: 0; outline: none; } -div#consoleWrap .playerSearchWrap { margin: 0 !important; width: 100%; } -div#consoleWrap .searchButton { width: calc(20% - 10px); } -div#consoleWrap .searchButton:hover { background-color: #007ACC !important; } - -input[type="text"], input[type="password"], textarea, select#threadCategory, select#serverSelection { margin: 0.25em; background-color: rgb(34, 34, 34); border: solid 1px rgb(55, 55, 55); color: #fff; font-size: 16pt; font-size: 15pt; padding: 0.5em 10px; } -select#serverSelection { background-color: #181818; margin: 0;} -input.search { margin: 0; } -input[type="submit"]:hover, div#submitReplyButton:hover { background-color: #ff6633 !important; } -label { text-align: right; } - -div.infoBox .header { text-align: center; background-color: #007ACC; padding: 0.5em 0; width: 100%; margin: 0 auto; } -div.infoBox form { padding: 10px; } -div.infoBox { width: 50%; margin: 0 auto; background-color: #181818; border: 1em solid #007ACC; border-width: 0 0 0.25em 0; min-width: 550px; } -div.infoBox input[type="text"], div.infoBox input[type="password"] { width: 70%; } -div.infoBox input[type="submit"], #userCP input[type="submit"] { width: 20%; background-color: #007ACC; font-size: 16pt; border: none; color: #fff; font-size: 15pt; padding: 0.5em 10px; margin: 0.25em; } - -div.alertBox { display: none; margin-top: 15px; margin-left: 15px; } - -div#consoleWrap select { width: 100%; } - -div#view { width: 100%; margin: 0 auto; } -div#threadView { width: 80%; padding-right: 3em;} -div#threadView hr { width: 100%; } -div#recentTitle { position: relative; top: -1em; } -div#view .threadPreview { background-color: #181818; padding: 0 10px; width: calc(100% - 20px); } -div#view .threadPreview .threadTitle { padding: 0 0.5em; width: 80%; } -div#view .threadPreview .threadInfo { font-size: 9pt; text-align: right; width: 50%; } -div#view .categoryDescription { font-size: 10.5pt; opacity: 0.5; margin-left: 2em; position: relative; top: -2.5px; } -div#content .individualThreadInfo { border-bottom: 1px solid rgba(255, 255, 255, 0.2); padding: 0.5em 1em; display: table; width: calc(100% - 2em); } -div#content .individualThreadInfo:nth-child(3) { border-bottom: none; padding-bottom: 0.5em; } -div#content .individualThreadInfo i { font-size: 16pt; width: 16pt; } -div.title a:link:hover, div.title a:visited:hover { color: #ff6633 !important; } - -div#categoryHeader { font-size: 2em; position: relative; top: -15px; } -hr.simple { position: absolute; left: 0; width: 100% !important; border: none; height: 1px !important; background-color: rgba(255,255,255, 0.3) !important; margin: 1em 0; } -div#categoryContainer { width: 100%; background-color: rgb(24, 24, 24); margin-top: 1em; /*border: 1px solid rgba(255,255,255, 0.2); border-top: none; border-botom:*/ } -div#categoryContainer .categoryThread { padding: 0.5em; width: calc(100% - 1em); } -div#categoryContainer .categoryThread:nth-child(even) { background-color: rgb(19, 19, 19); } -div#categoryContainer .threadTitle { font-weight: bold; text-align: left; } -div#categoryContainer .threadAuthor { font-size: 0.75em; opacity: 0.5; font-style: italic; } -div#categoryContainer .threadTime { vertical-align: middle; text-align: right; } -div#categoryContainer .threadReplyCount { vertical-align: middle; width: 1em; text-align: center; padding: 0 0.5em; } -div#categoryContainer .threadReplyBG { background-color: #007ACC; width: 2em; height: 1.4em; border-radius: 8px; } - -div#postThreadCaption, div#replyThreadCaption, div#submitReplyButton { background-color: #007ACC; padding: 0.5em 1em; opacity: 0.9; margin-top: -10px; } -div#replyThreadCaption { margin: 0; } -div#postThreadCaption:hover, div#replyThreadCaption:hover { color: #fff; opacity: 1; } - -div#postThreadContainer, div#threadContainer { width: 80%; margin: 0 auto; } -textarea#threadContent { width: calc(100% - 40px); height: 20em; font-size: 12pt; max-width: calc(100% - 40px); min-width: calc(100% - 40px);} -select#threadCategory { border: solid 1px rgb(55, 55, 55); width: 25%; } -input#threadTitle { width: calc(75% - 50px); } - -div#threadContainer .userInfo { width: 10em; padding: 1em; margin: 0 auto; text-align: center; } -div#threadContainer .threadInfo { padding: 1em; vertical-align: top; background-color: #181818; } -div#threadContainer .threadStart { border-bottom: 1px solid rgba(255,255,255,0.2); } -div.threadInfo .threadTitle { font-size: 24pt; word-break: break-all; } -div#threadContainer .userAvatar { margin: 0.5em 0; width: 10em; height: 10em; text-align: center; background-size: contain; border-radius: 10px; background-repeat: no-repeat; background-position: center center; } -div#threadContainer .threadContent { margin: 1em 0; font-size: 11pt; word-break: break-all; } -div#threadContainer .threadContent img { max-width: 100%;} -div#threadContainer .threadContent a { color: rgb(0, 122, 204) !important; } -div#threadContainer .threadContent a:hover { color: #fff !important; } -div.threadContent ol, div.threadContent ol { margin: 1em; } -div.categoryThread .threadActions { color: rgba(255, 69, 69, 0.85); font-size: 18pt; width: 19px; } - -div#postReplyContainer { position: fixed; bottom: 0; left: 0; width: 100%; height: 20em; background-color: #181818; } -div#postReplyClose { position: absolute; right: 0.25em; font-size: 24pt; } -div#postReplyClose:hover { color: #007ACC; cursor: pointer; } - -div#replyContentContainer { width: 68%; margin: 0.75em auto; } -textarea#replyContentBox { background-color: rgb(14,14,14); width: 100%; height: 10em; margin: 0.5em 0; resize: none; overflow:hidden } -div#submitReplyButton { margin: 0; width: 3em; text-align: center; cursor: pointer; } - -div#textNav { position: relative; top: -1.5em; word-break: break-all; } - -.categoryThread .fa-circle-o { width: 1em; padding-right: 0.5em; display: table-cell; vertical-align: middle; } - -div #userCover { - position: absolute; - left: 0; - padding: 0.5em 0; - width: 100%; - background: #ff6633; - font-size: 24pt; - text-align: center; - color: #fff; - margin-top: -1.5em; -} - -div#userInfoBox { background-color: #181818; padding: 1em; padding-top: 2em; width: 65%; margin: 0 auto; } -div#userInfoBox .fa { font-size: 3em; width: 65px; padding: 0.25em 0; } -div.userInfoField .tableCell { vertical-align: middle; padding-right: 1em; padding-left: 0.25em; } - -div#userAvatar { width: 20em; height: 20em; background-size: contain; margin-right: 1.5em; border-radius: 50px; background-position: center center; background-color: rgba(0,0,0,0.1); } - -.loader { - position: fixed; - left: 0px; - top: 0px; - width: 100%; - height: 100%; - z-index: 9999; - background: url('data:image/gif;base64,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'); - background-repeat: no-repeat; - background-position: center center; - background-size: 5%; - opacity: 0.5; - display: none; -} - -.table { display: table; } -.tableCell { display: table-cell; } -.alignRight { text-align: right; } - -.themeBlue { color: #007ACC !important; } -.themeBlue:hover { color: #fff !important; } -.themeOrange { color: #ff6633; } -.themeOrange:hover{ color: #007ACC !important; } - -div.threadInfo .actionHover { float: right; color: rgba(255, 69, 69, 0.85); margin: 0 4px; } -.actionHover { cursor: pointer; } -.actionHover:hover { color: #007ACC !important; } -.actionHover.actionEdit { color:#007ACC !important; } - -.datThing { background-color: #007ACC; font-size: 16pt; border: none; color: #fff; font-size: 15pt; padding: 0.5em 10px; } -span.light { opacity: 0.5; } -span.userTitle span:hover {color: #007ACC !important; } -input#bannercolor { margin: 0.35em; width: 265px; border: none; height: 45px; } -div#footer { position: fixed; bottom: 0.5em; right: 0.5em; opacity: 0.5; } - -.privilege-title { font-size: 24pt; } -.privilege-title + hr { margin-bottom: 10px; } -.privilege hr { margin-top: 10px !important; } -.admin-name a { font-size: 14pt; color: #007ACC !important; } -.admin-name a:hover { color: #fff !important; } -.clients { margin: 0.5em; } -.canvasjs-chart-credit { display: none; } -.player-history { margin-top: -100px; height: 100px; } - -.stats-minimap-image { height: 512px; width: 512px; } -.stats-minimap-container { max-width: 512px; margin: 2em 0; float: left;} -#stats { width: 100%; } -.stats-serverinfo { float: left;margin: 2em 1em; font-size: 16pt; } -#KillEventCount { margin-bottom: 1em; } - -.slider { - -webkit-appearance: none; - width: 100%; - height: 15px; - background: rgb(24,24,24); - outline: 1px rgba(255, 255, 255, 0.1) solid; - opacity: 0.7; - -webkit-transition: .2s; - transition: opacity .2s; -} - -.slider::-webkit-slider-thumb { - -webkit-appearance: none; - appearance: none; - width: 25px; - height: 25px; - border-radius: 50%; - background: #007ACC; - cursor: pointer; -} - -.slider::-moz-range-thumb { - width: 25px; - height: 25px; - border-radius: 50%; - background: #007ACC; - cursor: pointer; -} \ No newline at end of file diff --git a/Admin/webfront/main.html b/Admin/webfront/main.html deleted file mode 100644 index 26ab93834..000000000 --- a/Admin/webfront/main.html +++ /dev/null @@ -1,106 +0,0 @@ - - -
-
diff --git a/Admin/webfront/mobile.css b/Admin/webfront/mobile.css deleted file mode 100644 index 1412d27e8..000000000 --- a/Admin/webfront/mobile.css +++ /dev/null @@ -1,8 +0,0 @@ -@media screen and (max-width: 1200px) -{ - div#content { padding-left: 0; margin-left: 1em; padding-right: 0; margin-right: 1em; } - div#view { width: 100%; } - div#threadContainer { width: 90%; } - div#userInfoBox { width: 95%; } - div#userCover { width: 100%; left: 0; } -} diff --git a/Admin/webfront/notfound.html b/Admin/webfront/notfound.html deleted file mode 100644 index bee188ff4..000000000 --- a/Admin/webfront/notfound.html +++ /dev/null @@ -1,5 +0,0 @@ -
-
IW4M Admin
-

404 Page not found!

-
-
\ No newline at end of file diff --git a/Admin/webfront/penalties.html b/Admin/webfront/penalties.html deleted file mode 100644 index e7ddedc13..000000000 --- a/Admin/webfront/penalties.html +++ /dev/null @@ -1,58 +0,0 @@ - - -
-
Name
-
Type
-
Reason
-
Admin
-
Time
-
Remaining
-
-
-
-
-
- - -
diff --git a/Admin/webfront/players.html b/Admin/webfront/players.html deleted file mode 100644 index e3d671a5e..000000000 --- a/Admin/webfront/players.html +++ /dev/null @@ -1,117 +0,0 @@ - - - -
- - -
- -
-
Name
-
Level
-
Last Seen
-
-
-
-
- -
- - -
- - diff --git a/Admin/webfront/scripts/wordcloud2.js b/Admin/webfront/scripts/wordcloud2.js deleted file mode 100644 index 35fd5d6e2..000000000 --- a/Admin/webfront/scripts/wordcloud2.js +++ /dev/null @@ -1,2369 +0,0 @@ -'use strict'; - - - -// setImmediate - -if (!window.setImmediate) { - - window.setImmediate = (function setupSetImmediate() { - - return window.msSetImmediate || - - window.webkitSetImmediate || - - window.mozSetImmediate || - - window.oSetImmediate || - - (function setupSetZeroTimeout() { - - if (!window.postMessage || !window.addEventListener) { - - return null; - - } - - - - var callbacks = [undefined]; - - var message = 'zero-timeout-message'; - - - - // Like setTimeout, but only takes a function argument. There's - - // no time argument (always zero) and no arguments (you have to - - // use a closure). - - var setZeroTimeout = function setZeroTimeout(callback) { - - var id = callbacks.length; - - callbacks.push(callback); - - window.postMessage(message + id.toString(36), '*'); - - - - return id; - - }; - - - - window.addEventListener('message', function setZeroTimeoutMessage(evt) { - - // Skipping checking event source, retarded IE confused this window - - // object with another in the presence of iframe - - if (typeof evt.data !== 'string' || - - evt.data.substr(0, message.length) !== message/* || - - evt.source !== window */) { - - return; - - } - - - - evt.stopImmediatePropagation(); - - - - var id = parseInt(evt.data.substr(message.length), 36); - - if (!callbacks[id]) { - - return; - - } - - - - callbacks[id](); - - callbacks[id] = undefined; - - }, true); - - - - /* specify clearImmediate() here since we need the scope */ - - window.clearImmediate = function clearZeroTimeout(id) { - - if (!callbacks[id]) { - - return; - - } - - - - callbacks[id] = undefined; - - }; - - - - return setZeroTimeout; - - })() || - - // fallback - - function setImmediateFallback(fn) { - - window.setTimeout(fn, 0); - - }; - - })(); - -} - - - -if (!window.clearImmediate) { - - window.clearImmediate = (function setupClearImmediate() { - - return window.msClearImmediate || - - window.webkitClearImmediate || - - window.mozClearImmediate || - - window.oClearImmediate || - - // "clearZeroTimeout" is implement on the previous block || - - // fallback - - function clearImmediateFallback(timer) { - - window.clearTimeout(timer); - - }; - - })(); - -} - - - -(function(global) { - - - - // Check if WordCloud can run on this browser - - var isSupported = (function isSupported() { - - var canvas = document.createElement('canvas'); - - if (!canvas || !canvas.getContext) { - - return false; - - } - - - - var ctx = canvas.getContext('2d'); - - if (!ctx) { - - return false; - - } - - if (!ctx.getImageData) { - - return false; - - } - - if (!ctx.fillText) { - - return false; - - } - - - - if (!Array.prototype.some) { - - return false; - - } - - if (!Array.prototype.push) { - - return false; - - } - - - - return true; - - }()); - - - - // Find out if the browser impose minium font size by - - // drawing small texts on a canvas and measure it's width. - - var minFontSize = (function getMinFontSize() { - - if (!isSupported) { - - return; - - } - - - - var ctx = document.createElement('canvas').getContext('2d'); - - - - // start from 20 - - var size = 20; - - - - // two sizes to measure - - var hanWidth, mWidth; - - - - while (size) { - - ctx.font = size.toString(10) + 'px sans-serif'; - - if ((ctx.measureText('\uFF37').width === hanWidth) && - - (ctx.measureText('m').width) === mWidth) { - - return (size + 1); - - } - - - - hanWidth = ctx.measureText('\uFF37').width; - - mWidth = ctx.measureText('m').width; - - - - size--; - - } - - - - return 0; - - })(); - - - - // Based on http://jsfromhell.com/array/shuffle - - var shuffleArray = function shuffleArray(arr) { - - for (var j, x, i = arr.length; i; - - j = Math.floor(Math.random() * i), - - x = arr[--i], arr[i] = arr[j], - - arr[j] = x) {} - - return arr; - - }; - - - - var WordCloud = function WordCloud(elements, options) { - - if (!isSupported) { - - return; - - } - - - - if (!Array.isArray(elements)) { - - elements = [elements]; - - } - - - - elements.forEach(function(el, i) { - - if (typeof el === 'string') { - - elements[i] = document.getElementById(el); - - if (!elements[i]) { - - throw 'The element id specified is not found.'; - - } - - } else if (!el.tagName && !el.appendChild) { - - throw 'You must pass valid HTML elements, or ID of the element.'; - - } - - }); - - - - /* Default values to be overwritten by options object */ - - var settings = { - - list: [], - - fontFamily: '"Trebuchet MS", "Heiti TC", "?????", ' + - - '"Arial Unicode MS", "Droid Fallback Sans", sans-serif', - - fontWeight: 'normal', - - color: 'random-dark', - - minSize: 0, // 0 to disable - - weightFactor: 1, - - clearCanvas: true, - - backgroundColor: '#fff', // opaque white = rgba(255, 255, 255, 1) - - - - gridSize: 8, - - drawOutOfBound: false, - - origin: null, - - - - drawMask: false, - - maskColor: 'rgba(255,0,0,0.3)', - - maskGapWidth: 0.3, - - - - wait: 0, - - abortThreshold: 0, // disabled - - abort: function noop() {}, - - - - minRotation: - Math.PI / 2, - - maxRotation: Math.PI / 2, - - rotationSteps: 0, - - - - shuffle: true, - - rotateRatio: 0.1, - - - - shape: 'circle', - - ellipticity: 0.65, - - - - classes: null, - - - - hover: null, - - click: null - - }; - - - - if (options) { - - for (var key in options) { - - if (key in settings) { - - settings[key] = options[key]; - - } - - } - - } - - - - /* Convert weightFactor into a function */ - - if (typeof settings.weightFactor !== 'function') { - - var factor = settings.weightFactor; - - settings.weightFactor = function weightFactor(pt) { - - return pt * factor; //in px - - }; - - } - - - - /* Convert shape into a function */ - - if (typeof settings.shape !== 'function') { - - switch (settings.shape) { - - case 'circle': - - /* falls through */ - - default: - - // 'circle' is the default and a shortcut in the code loop. - - settings.shape = 'circle'; - - break; - - - - case 'cardioid': - - settings.shape = function shapeCardioid(theta) { - - return 1 - Math.sin(theta); - - }; - - break; - - - - /* - - - - To work out an X-gon, one has to calculate "m", - - where 1/(cos(2*PI/X)+m*sin(2*PI/X)) = 1/(cos(0)+m*sin(0)) - - http://www.wolframalpha.com/input/?i=1%2F%28cos%282*PI%2FX%29%2Bm*sin%28 - - 2*PI%2FX%29%29+%3D+1%2F%28cos%280%29%2Bm*sin%280%29%29 - - - - Copy the solution into polar equation r = 1/(cos(t') + m*sin(t')) - - where t' equals to mod(t, 2PI/X); - - - - */ - - - - case 'diamond': - - // http://www.wolframalpha.com/input/?i=plot+r+%3D+1%2F%28cos%28mod+ - - // %28t%2C+PI%2F2%29%29%2Bsin%28mod+%28t%2C+PI%2F2%29%29%29%2C+t+%3D - - // +0+..+2*PI - - settings.shape = function shapeSquare(theta) { - - var thetaPrime = theta % (2 * Math.PI / 4); - - return 1 / (Math.cos(thetaPrime) + Math.sin(thetaPrime)); - - }; - - break; - - - - case 'square': - - // http://www.wolframalpha.com/input/?i=plot+r+%3D+min(1%2Fabs(cos(t - - // )),1%2Fabs(sin(t)))),+t+%3D+0+..+2*PI - - settings.shape = function shapeSquare(theta) { - - return Math.min( - - 1 / Math.abs(Math.cos(theta)), - - 1 / Math.abs(Math.sin(theta)) - - ); - - }; - - break; - - - - case 'triangle-forward': - - // http://www.wolframalpha.com/input/?i=plot+r+%3D+1%2F%28cos%28mod+ - - // %28t%2C+2*PI%2F3%29%29%2Bsqrt%283%29sin%28mod+%28t%2C+2*PI%2F3%29 - - // %29%29%2C+t+%3D+0+..+2*PI - - settings.shape = function shapeTriangle(theta) { - - var thetaPrime = theta % (2 * Math.PI / 3); - - return 1 / (Math.cos(thetaPrime) + - - Math.sqrt(3) * Math.sin(thetaPrime)); - - }; - - break; - - - - case 'triangle': - - case 'triangle-upright': - - settings.shape = function shapeTriangle(theta) { - - var thetaPrime = (theta + Math.PI * 3 / 2) % (2 * Math.PI / 3); - - return 1 / (Math.cos(thetaPrime) + - - Math.sqrt(3) * Math.sin(thetaPrime)); - - }; - - break; - - - - case 'pentagon': - - settings.shape = function shapePentagon(theta) { - - var thetaPrime = (theta + 0.955) % (2 * Math.PI / 5); - - return 1 / (Math.cos(thetaPrime) + - - 0.726543 * Math.sin(thetaPrime)); - - }; - - break; - - - - case 'star': - - settings.shape = function shapeStar(theta) { - - var thetaPrime = (theta + 0.955) % (2 * Math.PI / 10); - - if ((theta + 0.955) % (2 * Math.PI / 5) - (2 * Math.PI / 10) >= 0) { - - return 1 / (Math.cos((2 * Math.PI / 10) - thetaPrime) + - - 3.07768 * Math.sin((2 * Math.PI / 10) - thetaPrime)); - - } else { - - return 1 / (Math.cos(thetaPrime) + - - 3.07768 * Math.sin(thetaPrime)); - - } - - }; - - break; - - } - - } - - - - /* Make sure gridSize is a whole number and is not smaller than 4px */ - - settings.gridSize = Math.max(Math.floor(settings.gridSize), 4); - - - - /* shorthand */ - - var g = settings.gridSize; - - var maskRectWidth = g - settings.maskGapWidth; - - - - /* normalize rotation settings */ - - var rotationRange = Math.abs(settings.maxRotation - settings.minRotation); - - var rotationSteps = Math.abs(Math.floor(settings.rotationSteps)); - - var minRotation = Math.min(settings.maxRotation, settings.minRotation); - - - - /* information/object available to all functions, set when start() */ - - var grid, // 2d array containing filling information - - ngx, ngy, // width and height of the grid - - center, // position of the center of the cloud - - maxRadius; - - - - /* timestamp for measuring each putWord() action */ - - var escapeTime; - - - - /* function for getting the color of the text */ - - var getTextColor; - - function random_hsl_color(min, max) { - - return 'hsl(' + - - (Math.random() * 360).toFixed() + ',' + - - (Math.random() * 30 + 70).toFixed() + '%,' + - - (Math.random() * (max - min) + min).toFixed() + '%)'; - - } - - switch (settings.color) { - - case 'random-dark': - - getTextColor = function getRandomDarkColor() { - - return random_hsl_color(10, 50); - - }; - - break; - - - - case 'random-light': - - getTextColor = function getRandomLightColor() { - - return random_hsl_color(50, 90); - - }; - - break; - - - - default: - - if (typeof settings.color === 'function') { - - getTextColor = settings.color; - - } - - break; - - } - - - - /* function for getting the classes of the text */ - - var getTextClasses = null; - - if (typeof settings.classes === 'function') { - - getTextClasses = settings.classes; - - } - - - - /* Interactive */ - - var interactive = false; - - var infoGrid = []; - - var hovered; - - - - var getInfoGridFromMouseTouchEvent = - - function getInfoGridFromMouseTouchEvent(evt) { - - var canvas = evt.currentTarget; - - var rect = canvas.getBoundingClientRect(); - - var clientX; - - var clientY; - - /** Detect if touches are available */ - - if (evt.touches) { - - clientX = evt.touches[0].clientX; - - clientY = evt.touches[0].clientY; - - } else { - - clientX = evt.clientX; - - clientY = evt.clientY; - - } - - var eventX = clientX - rect.left; - - var eventY = clientY - rect.top; - - - - var x = Math.floor(eventX * ((canvas.width / rect.width) || 1) / g); - - var y = Math.floor(eventY * ((canvas.height / rect.height) || 1) / g); - - - - return infoGrid[x][y]; - - }; - - - - var wordcloudhover = function wordcloudhover(evt) { - - var info = getInfoGridFromMouseTouchEvent(evt); - - - - if (hovered === info) { - - return; - - } - - - - hovered = info; - - if (!info) { - - settings.hover(undefined, undefined, evt); - - - - return; - - } - - - - settings.hover(info.item, info.dimension, evt); - - - - }; - - - - var wordcloudclick = function wordcloudclick(evt) { - - var info = getInfoGridFromMouseTouchEvent(evt); - - if (!info) { - - return; - - } - - - - settings.click(info.item, info.dimension, evt); - - evt.preventDefault(); - - }; - - - - /* Get points on the grid for a given radius away from the center */ - - var pointsAtRadius = []; - - var getPointsAtRadius = function getPointsAtRadius(radius) { - - if (pointsAtRadius[radius]) { - - return pointsAtRadius[radius]; - - } - - - - // Look for these number of points on each radius - - var T = radius * 8; - - - - // Getting all the points at this radius - - var t = T; - - var points = []; - - - - if (radius === 0) { - - points.push([center[0], center[1], 0]); - - } - - - - while (t--) { - - // distort the radius to put the cloud in shape - - var rx = 1; - - if (settings.shape !== 'circle') { - - rx = settings.shape(t / T * 2 * Math.PI); // 0 to 1 - - } - - - - // Push [x, y, t]; t is used solely for getTextColor() - - points.push([ - - center[0] + radius * rx * Math.cos(-t / T * 2 * Math.PI), - - center[1] + radius * rx * Math.sin(-t / T * 2 * Math.PI) * - - settings.ellipticity, - - t / T * 2 * Math.PI]); - - } - - - - pointsAtRadius[radius] = points; - - return points; - - }; - - - - /* Return true if we had spent too much time */ - - var exceedTime = function exceedTime() { - - return ((settings.abortThreshold > 0) && - - ((new Date()).getTime() - escapeTime > settings.abortThreshold)); - - }; - - - - /* Get the deg of rotation according to settings, and luck. */ - - var getRotateDeg = function getRotateDeg() { - - if (settings.rotateRatio === 0) { - - return 0; - - } - - - - if (Math.random() > settings.rotateRatio) { - - return 0; - - } - - - - if (rotationRange === 0) { - - return minRotation; - - } - - - - if (rotationSteps > 0) { - - // Min rotation + zero or more steps * span of one step - - return minRotation + - - Math.floor(Math.random() * rotationSteps) * - - rotationRange / (rotationSteps - 1); - - } - - else { - - return minRotation + Math.random() * rotationRange; - - } - - }; - - - - var getTextInfo = function getTextInfo(word, weight, rotateDeg) { - - // calculate the acutal font size - - // fontSize === 0 means weightFactor function wants the text skipped, - - // and size < minSize means we cannot draw the text. - - var debug = false; - - var fontSize = settings.weightFactor(weight); - - if (fontSize <= settings.minSize) { - - return false; - - } - - - - // Scale factor here is to make sure fillText is not limited by - - // the minium font size set by browser. - - // It will always be 1 or 2n. - - var mu = 1; - - if (fontSize < minFontSize) { - - mu = (function calculateScaleFactor() { - - var mu = 2; - - while (mu * fontSize < minFontSize) { - - mu += 2; - - } - - return mu; - - })(); - - } - - - - var fcanvas = document.createElement('canvas'); - - var fctx = fcanvas.getContext('2d', { willReadFrequently: true }); - - - - fctx.font = settings.fontWeight + ' ' + - - (fontSize * mu).toString(10) + 'px ' + settings.fontFamily; - - - - // Estimate the dimension of the text with measureText(). - - var fw = fctx.measureText(word).width / mu; - - var fh = Math.max(fontSize * mu, - - fctx.measureText('m').width, - - fctx.measureText('\uFF37').width) / mu; - - - - // Create a boundary box that is larger than our estimates, - - // so text don't get cut of (it sill might) - - var boxWidth = fw + fh * 2; - - var boxHeight = fh * 3; - - var fgw = Math.ceil(boxWidth / g); - - var fgh = Math.ceil(boxHeight / g); - - boxWidth = fgw * g; - - boxHeight = fgh * g; - - - - // Calculate the proper offsets to make the text centered at - - // the preferred position. - - - - // This is simply half of the width. - - var fillTextOffsetX = - fw / 2; - - // Instead of moving the box to the exact middle of the preferred - - // position, for Y-offset we move 0.4 instead, so Latin alphabets look - - // vertical centered. - - var fillTextOffsetY = - fh * 0.4; - - - - // Calculate the actual dimension of the canvas, considering the rotation. - - var cgh = Math.ceil((boxWidth * Math.abs(Math.sin(rotateDeg)) + - - boxHeight * Math.abs(Math.cos(rotateDeg))) / g); - - var cgw = Math.ceil((boxWidth * Math.abs(Math.cos(rotateDeg)) + - - boxHeight * Math.abs(Math.sin(rotateDeg))) / g); - - var width = cgw * g; - - var height = cgh * g; - - - - fcanvas.setAttribute('width', width); - - fcanvas.setAttribute('height', height); - - - - if (debug) { - - // Attach fcanvas to the DOM - - document.body.appendChild(fcanvas); - - // Save it's state so that we could restore and draw the grid correctly. - - fctx.save(); - - } - - - - // Scale the canvas with |mu|. - - fctx.scale(1 / mu, 1 / mu); - - fctx.translate(width * mu / 2, height * mu / 2); - - fctx.rotate(- rotateDeg); - - - - // Once the width/height is set, ctx info will be reset. - - // Set it again here. - - fctx.font = settings.fontWeight + ' ' + - - (fontSize * mu).toString(10) + 'px ' + settings.fontFamily; - - - - // Fill the text into the fcanvas. - - // XXX: We cannot because textBaseline = 'top' here because - - // Firefox and Chrome uses different default line-height for canvas. - - // Please read https://bugzil.la/737852#c6. - - // Here, we use textBaseline = 'middle' and draw the text at exactly - - // 0.5 * fontSize lower. - - fctx.fillStyle = '#000'; - - fctx.textBaseline = 'middle'; - - fctx.fillText(word, fillTextOffsetX * mu, - - (fillTextOffsetY + fontSize * 0.5) * mu); - - - - // Get the pixels of the text - - var imageData = fctx.getImageData(0, 0, width, height).data; - - - - if (exceedTime()) { - - return false; - - } - - - - if (debug) { - - // Draw the box of the original estimation - - fctx.strokeRect(fillTextOffsetX * mu, - - fillTextOffsetY, fw * mu, fh * mu); - - fctx.restore(); - - } - - - - // Read the pixels and save the information to the occupied array - - var occupied = []; - - var gx = cgw, gy, x, y; - - var bounds = [cgh / 2, cgw / 2, cgh / 2, cgw / 2]; - - while (gx--) { - - gy = cgh; - - while (gy--) { - - y = g; - - singleGridLoop: { - - while (y--) { - - x = g; - - while (x--) { - - if (imageData[((gy * g + y) * width + - - (gx * g + x)) * 4 + 3]) { - - occupied.push([gx, gy]); - - - - if (gx < bounds[3]) { - - bounds[3] = gx; - - } - - if (gx > bounds[1]) { - - bounds[1] = gx; - - } - - if (gy < bounds[0]) { - - bounds[0] = gy; - - } - - if (gy > bounds[2]) { - - bounds[2] = gy; - - } - - - - if (debug) { - - fctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; - - fctx.fillRect(gx * g, gy * g, g - 0.5, g - 0.5); - - } - - break singleGridLoop; - - } - - } - - } - - if (debug) { - - fctx.fillStyle = 'rgba(0, 0, 255, 0.5)'; - - fctx.fillRect(gx * g, gy * g, g - 0.5, g - 0.5); - - } - - } - - } - - } - - - - if (debug) { - - fctx.fillStyle = 'rgba(0, 255, 0, 0.5)'; - - fctx.fillRect(bounds[3] * g, - - bounds[0] * g, - - (bounds[1] - bounds[3] + 1) * g, - - (bounds[2] - bounds[0] + 1) * g); - - } - - - - // Return information needed to create the text on the real canvas - - return { - - mu: mu, - - occupied: occupied, - - bounds: bounds, - - gw: cgw, - - gh: cgh, - - fillTextOffsetX: fillTextOffsetX, - - fillTextOffsetY: fillTextOffsetY, - - fillTextWidth: fw, - - fillTextHeight: fh, - - fontSize: fontSize - - }; - - }; - - - - /* Determine if there is room available in the given dimension */ - - var canFitText = function canFitText(gx, gy, gw, gh, occupied) { - - // Go through the occupied points, - - // return false if the space is not available. - - var i = occupied.length; - - while (i--) { - - var px = gx + occupied[i][0]; - - var py = gy + occupied[i][1]; - - - - if (px >= ngx || py >= ngy || px < 0 || py < 0) { - - if (!settings.drawOutOfBound) { - - return false; - - } - - continue; - - } - - - - if (!grid[px][py]) { - - return false; - - } - - } - - return true; - - }; - - - - /* Actually draw the text on the grid */ - - var drawText = function drawText(gx, gy, info, word, weight, - - distance, theta, rotateDeg, attributes) { - - - - var fontSize = info.fontSize; - - var color; - - if (getTextColor) { - - color = getTextColor(word, weight, fontSize, distance, theta); - - } else { - - color = settings.color; - - } - - - - var classes; - - if (getTextClasses) { - - classes = getTextClasses(word, weight, fontSize, distance, theta); - - } else { - - classes = settings.classes; - - } - - - - var dimension; - - var bounds = info.bounds; - - dimension = { - - x: (gx + bounds[3]) * g, - - y: (gy + bounds[0]) * g, - - w: (bounds[1] - bounds[3] + 1) * g, - - h: (bounds[2] - bounds[0] + 1) * g - - }; - - - - elements.forEach(function(el) { - - if (el.getContext) { - - var ctx = el.getContext('2d'); - - var mu = info.mu; - - - - // Save the current state before messing it - - ctx.save(); - - ctx.scale(1 / mu, 1 / mu); - - - - ctx.font = settings.fontWeight + ' ' + - - (fontSize * mu).toString(10) + 'px ' + settings.fontFamily; - - ctx.fillStyle = color; - - - - // Translate the canvas position to the origin coordinate of where - - // the text should be put. - - ctx.translate((gx + info.gw / 2) * g * mu, - - (gy + info.gh / 2) * g * mu); - - - - if (rotateDeg !== 0) { - - ctx.rotate(- rotateDeg); - - } - - - - // Finally, fill the text. - - - - // XXX: We cannot because textBaseline = 'top' here because - - // Firefox and Chrome uses different default line-height for canvas. - - // Please read https://bugzil.la/737852#c6. - - // Here, we use textBaseline = 'middle' and draw the text at exactly - - // 0.5 * fontSize lower. - - ctx.textBaseline = 'middle'; - - ctx.fillText(word, info.fillTextOffsetX * mu, - - (info.fillTextOffsetY + fontSize * 0.5) * mu); - - - - // The below box is always matches how s are positioned - - /* ctx.strokeRect(info.fillTextOffsetX, info.fillTextOffsetY, - - info.fillTextWidth, info.fillTextHeight); */ - - - - // Restore the state. - - ctx.restore(); - - } else { - - // drawText on DIV element - - var span = document.createElement('span'); - - var transformRule = ''; - - transformRule = 'rotate(' + (- rotateDeg / Math.PI * 180) + 'deg) '; - - if (info.mu !== 1) { - - transformRule += - - 'translateX(-' + (info.fillTextWidth / 4) + 'px) ' + - - 'scale(' + (1 / info.mu) + ')'; - - } - - var styleRules = { - - 'position': 'absolute', - - 'display': 'block', - - 'font': settings.fontWeight + ' ' + - - (fontSize * info.mu) + 'px ' + settings.fontFamily, - - 'left': ((gx + info.gw / 2) * g + info.fillTextOffsetX) + 'px', - - 'top': ((gy + info.gh / 2) * g + info.fillTextOffsetY) + 'px', - - 'width': info.fillTextWidth + 'px', - - 'height': info.fillTextHeight + 'px', - - 'lineHeight': fontSize + 'px', - - 'whiteSpace': 'nowrap', - - 'transform': transformRule, - - 'webkitTransform': transformRule, - - 'msTransform': transformRule, - - 'transformOrigin': '50% 40%', - - 'webkitTransformOrigin': '50% 40%', - - 'msTransformOrigin': '50% 40%' - - }; - - if (color) { - - styleRules.color = color; - - } - - span.textContent = word; - - for (var cssProp in styleRules) { - - span.style[cssProp] = styleRules[cssProp]; - - } - - if (attributes) { - - for (var attribute in attributes) { - - span.setAttribute(attribute, attributes[attribute]); - - } - - } - - if (classes) { - - span.className += classes; - - } - - el.appendChild(span); - - } - - }); - - }; - - - - /* Help function to updateGrid */ - - var fillGridAt = function fillGridAt(x, y, drawMask, dimension, item) { - - if (x >= ngx || y >= ngy || x < 0 || y < 0) { - - return; - - } - - - - grid[x][y] = false; - - - - if (drawMask) { - - var ctx = elements[0].getContext('2d'); - - ctx.fillRect(x * g, y * g, maskRectWidth, maskRectWidth); - - } - - - - if (interactive) { - - infoGrid[x][y] = { item: item, dimension: dimension }; - - } - - }; - - - - /* Update the filling information of the given space with occupied points. - - Draw the mask on the canvas if necessary. */ - - var updateGrid = function updateGrid(gx, gy, gw, gh, info, item) { - - var occupied = info.occupied; - - var drawMask = settings.drawMask; - - var ctx; - - if (drawMask) { - - ctx = elements[0].getContext('2d'); - - ctx.save(); - - ctx.fillStyle = settings.maskColor; - - } - - - - var dimension; - - if (interactive) { - - var bounds = info.bounds; - - dimension = { - - x: (gx + bounds[3]) * g, - - y: (gy + bounds[0]) * g, - - w: (bounds[1] - bounds[3] + 1) * g, - - h: (bounds[2] - bounds[0] + 1) * g - - }; - - } - - - - var i = occupied.length; - - while (i--) { - - var px = gx + occupied[i][0]; - - var py = gy + occupied[i][1]; - - - - if (px >= ngx || py >= ngy || px < 0 || py < 0) { - - continue; - - } - - - - fillGridAt(px, py, drawMask, dimension, item); - - } - - - - if (drawMask) { - - ctx.restore(); - - } - - }; - - - - /* putWord() processes each item on the list, - - calculate it's size and determine it's position, and actually - - put it on the canvas. */ - - var putWord = function putWord(item) { - - var word, weight, attributes; - - if (Array.isArray(item)) { - - word = item[0]; - - weight = item[1]; - - } else { - - word = item.word; - - weight = item.weight; - - attributes = item.attributes; - - } - - var rotateDeg = getRotateDeg(); - - - - // get info needed to put the text onto the canvas - - var info = getTextInfo(word, weight, rotateDeg); - - - - // not getting the info means we shouldn't be drawing this one. - - if (!info) { - - return false; - - } - - - - if (exceedTime()) { - - return false; - - } - - - - // If drawOutOfBound is set to false, - - // skip the loop if we have already know the bounding box of - - // word is larger than the canvas. - - if (!settings.drawOutOfBound) { - - var bounds = info.bounds; - - if ((bounds[1] - bounds[3] + 1) > ngx || - - (bounds[2] - bounds[0] + 1) > ngy) { - - return false; - - } - - } - - - - // Determine the position to put the text by - - // start looking for the nearest points - - var r = maxRadius + 1; - - - - var tryToPutWordAtPoint = function(gxy) { - - var gx = Math.floor(gxy[0] - info.gw / 2); - - var gy = Math.floor(gxy[1] - info.gh / 2); - - var gw = info.gw; - - var gh = info.gh; - - - - // If we cannot fit the text at this position, return false - - // and go to the next position. - - if (!canFitText(gx, gy, gw, gh, info.occupied)) { - - return false; - - } - - - - // Actually put the text on the canvas - - drawText(gx, gy, info, word, weight, - - (maxRadius - r), gxy[2], rotateDeg, attributes); - - - - // Mark the spaces on the grid as filled - - updateGrid(gx, gy, gw, gh, info, item); - - - - // Return true so some() will stop and also return true. - - return true; - - }; - - - - while (r--) { - - var points = getPointsAtRadius(maxRadius - r); - - - - if (settings.shuffle) { - - points = [].concat(points); - - shuffleArray(points); - - } - - - - // Try to fit the words by looking at each point. - - // array.some() will stop and return true - - // when putWordAtPoint() returns true. - - // If all the points returns false, array.some() returns false. - - var drawn = points.some(tryToPutWordAtPoint); - - - - if (drawn) { - - // leave putWord() and return true - - return true; - - } - - } - - // we tried all distances but text won't fit, return false - - return false; - - }; - - - - /* Send DOM event to all elements. Will stop sending event and return - - if the previous one is canceled (for cancelable events). */ - - var sendEvent = function sendEvent(type, cancelable, detail) { - - if (cancelable) { - - return !elements.some(function(el) { - - var evt = document.createEvent('CustomEvent'); - - evt.initCustomEvent(type, true, cancelable, detail || {}); - - return !el.dispatchEvent(evt); - - }, this); - - } else { - - elements.forEach(function(el) { - - var evt = document.createEvent('CustomEvent'); - - evt.initCustomEvent(type, true, cancelable, detail || {}); - - el.dispatchEvent(evt); - - }, this); - - } - - }; - - - - /* Start drawing on a canvas */ - - var start = function start() { - - // For dimensions, clearCanvas etc., - - // we only care about the first element. - - var canvas = elements[0]; - - - - if (canvas.getContext) { - - ngx = Math.ceil(canvas.width / g); - - ngy = Math.ceil(canvas.height / g); - - } else { - - var rect = canvas.getBoundingClientRect(); - - ngx = Math.ceil(rect.width / g); - - ngy = Math.ceil(rect.height / g); - - } - - - - // Sending a wordcloudstart event which cause the previous loop to stop. - - // Do nothing if the event is canceled. - - if (!sendEvent('wordcloudstart', true)) { - - return; - - } - - - - // Determine the center of the word cloud - - center = (settings.origin) ? - - [settings.origin[0]/g, settings.origin[1]/g] : - - [ngx / 2, ngy / 2]; - - - - // Maxium radius to look for space - - maxRadius = Math.floor(Math.sqrt(ngx * ngx + ngy * ngy)); - - - - /* Clear the canvas only if the clearCanvas is set, - - if not, update the grid to the current canvas state */ - - grid = []; - - - - var gx, gy, i; - - if (!canvas.getContext || settings.clearCanvas) { - - elements.forEach(function(el) { - - if (el.getContext) { - - var ctx = el.getContext('2d'); - - ctx.fillStyle = settings.backgroundColor; - - ctx.clearRect(0, 0, ngx * (g + 1), ngy * (g + 1)); - - ctx.fillRect(0, 0, ngx * (g + 1), ngy * (g + 1)); - - } else { - - el.textContent = ''; - - el.style.backgroundColor = settings.backgroundColor; - - el.style.position = 'relative'; - - } - - }); - - - - /* fill the grid with empty state */ - - gx = ngx; - - while (gx--) { - - grid[gx] = []; - - gy = ngy; - - while (gy--) { - - grid[gx][gy] = true; - - } - - } - - } else { - - /* Determine bgPixel by creating - - another canvas and fill the specified background color. */ - - var bctx = document.createElement('canvas').getContext('2d'); - - - - bctx.fillStyle = settings.backgroundColor; - - bctx.fillRect(0, 0, 1, 1); - - var bgPixel = bctx.getImageData(0, 0, 1, 1).data; - - - - /* Read back the pixels of the canvas we got to tell which part of the - - canvas is empty. - - (no clearCanvas only works with a canvas, not divs) */ - - var imageData = - - canvas.getContext('2d').getImageData(0, 0, ngx * g, ngy * g).data; - - - - gx = ngx; - - var x, y; - - while (gx--) { - - grid[gx] = []; - - gy = ngy; - - while (gy--) { - - y = g; - - singleGridLoop: while (y--) { - - x = g; - - while (x--) { - - i = 4; - - while (i--) { - - if (imageData[((gy * g + y) * ngx * g + - - (gx * g + x)) * 4 + i] !== bgPixel[i]) { - - grid[gx][gy] = false; - - break singleGridLoop; - - } - - } - - } - - } - - if (grid[gx][gy] !== false) { - - grid[gx][gy] = true; - - } - - } - - } - - - - imageData = bctx = bgPixel = undefined; - - } - - - - // fill the infoGrid with empty state if we need it - - if (settings.hover || settings.click) { - - - - interactive = true; - - - - /* fill the grid with empty state */ - - gx = ngx + 1; - - while (gx--) { - - infoGrid[gx] = []; - - } - - - - if (settings.hover) { - - canvas.addEventListener('mousemove', wordcloudhover); - - } - - - - var touchend = function (e) { - - e.preventDefault(); - - }; - - - - if (settings.click) { - - canvas.addEventListener('click', wordcloudclick); - - canvas.addEventListener('touchstart', wordcloudclick); - - canvas.addEventListener('touchend', touchend); - - canvas.style.webkitTapHighlightColor = 'rgba(0, 0, 0, 0)'; - - } - - - - canvas.addEventListener('wordcloudstart', function stopInteraction() { - - canvas.removeEventListener('wordcloudstart', stopInteraction); - - - - canvas.removeEventListener('mousemove', wordcloudhover); - - canvas.removeEventListener('click', wordcloudclick); - - canvas.removeEventListener('touchstart', wordcloudclick); - - canvas.removeEventListener('touchend', touchend); - - hovered = undefined; - - }); - - } - - - - i = 0; - - var loopingFunction, stoppingFunction; - - if (settings.wait !== 0) { - - loopingFunction = window.setTimeout; - - stoppingFunction = window.clearTimeout; - - } else { - - loopingFunction = window.setImmediate; - - stoppingFunction = window.clearImmediate; - - } - - - - var addEventListener = function addEventListener(type, listener) { - - elements.forEach(function(el) { - - el.addEventListener(type, listener); - - }, this); - - }; - - - - var removeEventListener = function removeEventListener(type, listener) { - - elements.forEach(function(el) { - - el.removeEventListener(type, listener); - - }, this); - - }; - - - - var anotherWordCloudStart = function anotherWordCloudStart() { - - removeEventListener('wordcloudstart', anotherWordCloudStart); - - stoppingFunction(timer); - - }; - - - - addEventListener('wordcloudstart', anotherWordCloudStart); - - - - var timer = loopingFunction(function loop() { - - if (i >= settings.list.length) { - - stoppingFunction(timer); - - sendEvent('wordcloudstop', false); - - removeEventListener('wordcloudstart', anotherWordCloudStart); - - - - return; - - } - - escapeTime = (new Date()).getTime(); - - var drawn = putWord(settings.list[i]); - - var canceled = !sendEvent('wordclouddrawn', true, { - - item: settings.list[i], drawn: drawn }); - - if (exceedTime() || canceled) { - - stoppingFunction(timer); - - settings.abort(); - - sendEvent('wordcloudabort', false); - - sendEvent('wordcloudstop', false); - - removeEventListener('wordcloudstart', anotherWordCloudStart); - - return; - - } - - i++; - - timer = loopingFunction(loop, settings.wait); - - }, settings.wait); - - }; - - - - // All set, start the drawing - - start(); - - }; - - - - WordCloud.isSupported = isSupported; - - WordCloud.minFontSize = minFontSize; - - - - // Expose the library as an AMD module - - if (typeof define === 'function' && define.amd) { - - global.WordCloud = WordCloud; - - define('wordcloud', [], function() { return WordCloud; }); - - } else if (typeof module !== 'undefined' && module.exports) { - - module.exports = WordCloud; - - } else { - - global.WordCloud = WordCloud; - - } - - - -})(this); //jshint ignore:line \ No newline at end of file diff --git a/Admin/webfront/stats.html b/Admin/webfront/stats.html deleted file mode 100644 index 4a371cd23..000000000 --- a/Admin/webfront/stats.html +++ /dev/null @@ -1,146 +0,0 @@ -
-
- - -
-
- - diff --git a/IW4MAdmin.sln b/IW4MAdmin.sln index 28fe4406c..7d8ee6125 100644 --- a/IW4MAdmin.sln +++ b/IW4MAdmin.sln @@ -1,18 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27130.2027 +VisualStudioVersion = 15.0.27130.2036 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Application", "Admin\Application.csproj", "{DD5DCDA2-51DB-4B1A-922F-5705546E6115}" - ProjectSection(ProjectDependencies) = postProject - {B8C2A759-8663-4F6F-9BA4-19595F5E12C1} = {B8C2A759-8663-4F6F-9BA4-19595F5E12C1} - {AF097E6B-48D5-4452-9CCF-0A81A21F341D} = {AF097E6B-48D5-4452-9CCF-0A81A21F341D} - {4785AB75-66F3-4391-985D-63A5A049A0FA} = {4785AB75-66F3-4391-985D-63A5A049A0FA} - {428D8EB9-ECA3-4A66-AA59-3A944378C33F} = {428D8EB9-ECA3-4A66-AA59-3A944378C33F} - {C9E821BF-23AD-4CB5-B7F9-B3B99B606650} = {C9E821BF-23AD-4CB5-B7F9-B3B99B606650} - {D51EECEB-438A-47DA-870F-7D7B41BC24D6} = {D51EECEB-438A-47DA-870F-7D7B41BC24D6} - EndProjectSection -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatsPlugin", "Plugins\SimpleStats\StatsPlugin.csproj", "{4785AB75-66F3-4391-985D-63A5A049A0FA}" ProjectSection(ProjectDependencies) = postProject {D51EECEB-438A-47DA-870F-7D7B41BC24D6} = {D51EECEB-438A-47DA-870F-7D7B41BC24D6} @@ -46,6 +36,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Plugins\Tests\Test EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebfrontCore", "WebfrontCore\WebfrontCore.csproj", "{65340D7D-5831-406C-ACAD-B13BA634BDE2}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{4101CDED-AF1E-4FCF-9194-BEA2E634016E}" + ProjectSection(SolutionItems) = preProject + Admin\Config\maps.cfg = Admin\Config\maps.cfg + Admin\Config\messages.cfg = Admin\Config\messages.cfg + Admin\Config\rules.cfg = Admin\Config\rules.cfg + Admin\Config\web.cfg = Admin\Config\web.cfg + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -66,38 +64,6 @@ Global Release-Stable|x86 = Release-Stable|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|x64.ActiveCfg = Debug|x64 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|x64.Build.0 = Debug|x64 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|x86.ActiveCfg = Debug|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Debug|x86.Build.0 = Debug|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|Any CPU.ActiveCfg = Debug|Any CPU - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|Any CPU.Build.0 = Debug|Any CPU - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|Mixed Platforms.ActiveCfg = Release-Stable|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|Mixed Platforms.Build.0 = Release-Stable|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|x64.ActiveCfg = Release-Nightly|x64 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|x64.Build.0 = Release-Nightly|x64 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|x86.ActiveCfg = Release|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release|x86.Build.0 = Release|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Nightly|Any CPU.ActiveCfg = Release-Nightly|Any CPU - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Nightly|Any CPU.Build.0 = Release-Nightly|Any CPU - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Nightly|Mixed Platforms.ActiveCfg = Release-Nightly|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Nightly|Mixed Platforms.Build.0 = Release-Nightly|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Nightly|x64.ActiveCfg = Release-Nightly|x64 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Nightly|x64.Build.0 = Release-Nightly|x64 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Nightly|x86.ActiveCfg = Release-Nightly|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Nightly|x86.Build.0 = Release-Nightly|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Stable|Any CPU.ActiveCfg = Release-Stable|Any CPU - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Stable|Any CPU.Build.0 = Release-Stable|Any CPU - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Stable|Mixed Platforms.ActiveCfg = Release-Stable|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Stable|Mixed Platforms.Build.0 = Release-Stable|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Stable|x64.ActiveCfg = Release-Stable|x64 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Stable|x64.Build.0 = Release-Stable|x64 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Stable|x86.ActiveCfg = Release-Stable|x86 - {DD5DCDA2-51DB-4B1A-922F-5705546E6115}.Release-Stable|x86.Build.0 = Release-Stable|x86 {4785AB75-66F3-4391-985D-63A5A049A0FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4785AB75-66F3-4391-985D-63A5A049A0FA}.Debug|Any CPU.Build.0 = Debug|Any CPU {4785AB75-66F3-4391-985D-63A5A049A0FA}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 @@ -384,6 +350,7 @@ Global {C9E821BF-23AD-4CB5-B7F9-B3B99B606650} = {26E8B310-269E-46D4-A612-24601F16065F} {1479DE87-ACB5-4046-81C8-A0BA5041227D} = {26E8B310-269E-46D4-A612-24601F16065F} {B8C2A759-8663-4F6F-9BA4-19595F5E12C1} = {26E8B310-269E-46D4-A612-24601F16065F} + {4101CDED-AF1E-4FCF-9194-BEA2E634016E} = {8C8F3945-0AEF-4949-A1F7-B18E952E50BC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {84F8F8E0-1F73-41E0-BD8D-BB6676E2EE87} diff --git a/Plugins/EventAPI/EventAPI.csproj b/Plugins/EventAPI/EventAPI.csproj index ccd88208e..08dfe5194 100644 --- a/Plugins/EventAPI/EventAPI.csproj +++ b/Plugins/EventAPI/EventAPI.csproj @@ -72,14 +72,8 @@ - - ..\..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll - - - - copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\plugins\" diff --git a/Plugins/EventAPI/packages.config b/Plugins/EventAPI/packages.config deleted file mode 100644 index a272c64df..000000000 --- a/Plugins/EventAPI/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Plugins/Welcome/CountryLookup.cs b/Plugins/Welcome/CountryLookup.cs index 1db60c2a0..6fb653324 100644 --- a/Plugins/Welcome/CountryLookup.cs +++ b/Plugins/Welcome/CountryLookup.cs @@ -59,7 +59,7 @@ namespace CountryLookupProj fileInput = new FileStream(fileName, FileMode.Open, FileAccess.Read); } - public string lookupCountryCode(string str) + public string LookupCountryCode(string str) { IPAddress addr; try @@ -70,10 +70,10 @@ namespace CountryLookupProj { return "--"; } - return lookupCountryCode(addr); + return LookupCountryCode(addr); } - private long addrToNum(IPAddress addr) + private long AddrToNum(IPAddress addr) { long ipnum = 0; byte[] b = BitConverter.GetBytes(addr.Address); @@ -89,12 +89,12 @@ namespace CountryLookupProj return ipnum; } - public string lookupCountryCode(IPAddress addr) + public string LookupCountryCode(IPAddress addr) { - return (countryCode[(int)SeekCountry(0, addrToNum(addr), 31)]); + return (countryCode[(int)SeekCountry(0, AddrToNum(addr), 31)]); } - public string lookupCountryName(string str) + public string LookupCountryName(string str) { IPAddress addr; try @@ -105,12 +105,12 @@ namespace CountryLookupProj { return "a third world country"; } - return lookupCountryName(addr); + return LookupCountryName(addr); } - public string lookupCountryName(IPAddress addr) + public string LookupCountryName(IPAddress addr) { - return (countryName[(int)SeekCountry(0, addrToNum(addr), 31)]); + return (countryName[(int)SeekCountry(0, AddrToNum(addr), 31)]); } private long SeekCountry(long offset, long ipnum, int depth) diff --git a/Plugins/Welcome/Plugin.cs b/Plugins/Welcome/Plugin.cs index 31c76b3f1..4b4aca94f 100644 --- a/Plugins/Welcome/Plugin.cs +++ b/Plugins/Welcome/Plugin.cs @@ -127,7 +127,7 @@ namespace Welcome_Plugin try { CountryLookupProj.CountryLookup CLT = new CountryLookupProj.CountryLookup("Plugins/GeoIP.dat"); - msg = msg.Replace("{{ClientLocation}}", CLT.lookupCountryName(joining.IPAddressString)); + msg = msg.Replace("{{ClientLocation}}", CLT.LookupCountryName(joining.IPAddressString)); } catch (Exception) diff --git a/SharedLibrary/Database/Importer.cs b/SharedLibrary/Database/Importer.cs index 2db50f8ca..bcc297850 100644 --- a/SharedLibrary/Database/Importer.cs +++ b/SharedLibrary/Database/Importer.cs @@ -74,9 +74,9 @@ namespace SharedLibrary.Database context.SaveChanges(); } - catch (Exception e) + catch (Exception) { - var a = 1; + } if (recreateContext) @@ -152,9 +152,9 @@ namespace SharedLibrary.Database context.SaveChanges(); } - catch (Exception e) + catch (Exception) { - var a = 1; + } if (recreateContext) @@ -208,9 +208,9 @@ namespace SharedLibrary.Database context.SaveChanges(); } - catch (Exception e) + catch (Exception) { - var a = 1; + } if (recreateContext) diff --git a/SharedLibrary/SharedLibrary.csproj b/SharedLibrary/SharedLibrary.csproj index a91f36fe7..30ff4685e 100644 --- a/SharedLibrary/SharedLibrary.csproj +++ b/SharedLibrary/SharedLibrary.csproj @@ -206,16 +206,13 @@ - move "$(TargetDir)Newtonsoft.Json.dll" "$(TargetDir)lib\Newtonsoft.Json.dll" -move "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)BUILD\Lib\Newtonsoft.Json.dll" -copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\lib" + copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\lib" copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)Admin\lib" -copy /Y "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)BUILD\lib" -copy /Y "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)Admin\lib" - if not exist "$(TargetDir)x86" md "$(TargetDir)x86" - xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\x86\*.*" "$(TargetDir)x86" - if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64" - xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\amd64\*.*" "$(TargetDir)amd64" + +if not exist "$(TargetDir)x86" md "$(TargetDir)x86" + xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\x86\*.*" "$(TargetDir)x86" +if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64" + xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\amd64\*.*" "$(TargetDir)amd64" xcopy /Y /I /E "$(TargetDir)*" "$(SolutionDir)BUILD\Lib" diff --git a/Admin/Kayak.cs b/WebfrontCore/Application/Kayak.cs similarity index 100% rename from Admin/Kayak.cs rename to WebfrontCore/Application/Kayak.cs diff --git a/Admin/Logger.cs b/WebfrontCore/Application/Logger.cs similarity index 100% rename from Admin/Logger.cs rename to WebfrontCore/Application/Logger.cs diff --git a/Admin/Main.cs b/WebfrontCore/Application/Main.cs similarity index 77% rename from Admin/Main.cs rename to WebfrontCore/Application/Main.cs index b96504ce9..3f20d3740 100644 --- a/Admin/Main.cs +++ b/WebfrontCore/Application/Main.cs @@ -22,14 +22,12 @@ namespace IW4MAdmin static public ApplicationManager ServerManager = ApplicationManager.GetInstance(); public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar; - public static void Main(string[] args) + public static void Start() { AppDomain.CurrentDomain.SetData("DataDirectory", OperatingDirectory); System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.BelowNormal; Version = 1.6; - handler = new ConsoleEventDelegate(OnProcessExit); - SetConsoleCtrlHandler(handler, true); //double.TryParse(CheckUpdate(), out double latestVersion); Console.WriteLine("====================================================="); @@ -49,7 +47,6 @@ namespace IW4MAdmin Task.Run(() => { ServerManager.Start(); - /* String userInput; Player Origin = ServerManager.GetClientService().Get(1).Result.AsPlayer(); @@ -68,7 +65,7 @@ namespace IW4MAdmin ServerManager.Servers[0].ExecuteEvent(E); Console.Write('>'); - } while (ServerManager.Running);*/ + } while (ServerManager.Running); }); } @@ -80,43 +77,11 @@ namespace IW4MAdmin Console.ReadKey(); return; } - - try - { - - } - - catch (Exception e) - { - throw e; - } } - static ConsoleEventDelegate handler; - - static private bool OnProcessExit(int e) - { - try - { - ServerManager.Stop(); - return true; - } - - catch - { - return true; - } - } - - private delegate bool ConsoleEventDelegate(int eventType); - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add); - static void CheckDirectories() { string curDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar; - if (!Directory.Exists($"{curDirectory}Lib")) - throw new Exception("Lib folder does not exist"); if (!Directory.Exists($"{curDirectory}Config")) { diff --git a/Admin/Manager.cs b/WebfrontCore/Application/Manager.cs similarity index 98% rename from Admin/Manager.cs rename to WebfrontCore/Application/Manager.cs index be6dcbdd9..1c38592e8 100644 --- a/Admin/Manager.cs +++ b/WebfrontCore/Application/Manager.cs @@ -28,8 +28,6 @@ namespace IW4MAdmin List TaskStatuses; List Commands; List MessageTokens; - //WebService WebSvc; - Thread WebThread; ClientService ClientSvc; AliasService AliasSvc; PenaltyService PenaltySvc; @@ -221,7 +219,7 @@ namespace IW4MAdmin } #if !DEBUG foreach (var S in Servers) - S.Broadcast("^1IW4MAdmin going offline!"); + S.Broadcast("^1IW4MAdmin going offline!").Wait(); #endif _servers.Clear(); //WebSvc.WebScheduler.Stop(); diff --git a/Admin/Server.cs b/WebfrontCore/Application/Server.cs similarity index 100% rename from Admin/Server.cs rename to WebfrontCore/Application/Server.cs diff --git a/Admin/ServerConfigurationGenerator.cs b/WebfrontCore/Application/ServerConfigurationGenerator.cs similarity index 100% rename from Admin/ServerConfigurationGenerator.cs rename to WebfrontCore/Application/ServerConfigurationGenerator.cs diff --git a/WebfrontCore/Startup.cs b/WebfrontCore/Startup.cs index 106db5c79..19d9c0468 100644 --- a/WebfrontCore/Startup.cs +++ b/WebfrontCore/Startup.cs @@ -21,7 +21,7 @@ namespace WebfrontCore .AddEnvironmentVariables(); Configuration = builder.Build(); - IW4MAdmin.Program.Main(null); + IW4MAdmin.Program.Start(); } public IConfigurationRoot Configuration { get; } diff --git a/WebfrontCore/WebfrontCore.csproj b/WebfrontCore/WebfrontCore.csproj index 32839abc0..af95ca8d8 100644 --- a/WebfrontCore/WebfrontCore.csproj +++ b/WebfrontCore/WebfrontCore.csproj @@ -3,18 +3,24 @@ net452 true - WebfrontCore + IW4MAdmin Exe WebfrontCore AnyCPU;x86 + wwwroot\favicon.ico x86 + + + + + PreserveNewest @@ -49,9 +55,6 @@ - - true - true @@ -63,8 +66,8 @@ - - + +