diff --git a/Admin/Application.csproj b/Admin/Application.csproj index b87ac4376..bc9bc9ed2 100644 --- a/Admin/Application.csproj +++ b/Admin/Application.csproj @@ -156,6 +156,9 @@ + + PreserveNewest + PreserveNewest diff --git a/Admin/lib/SharedLibrary.dll b/Admin/lib/SharedLibrary.dll index 462243611..df9a7c688 100644 Binary files a/Admin/lib/SharedLibrary.dll and b/Admin/lib/SharedLibrary.dll differ diff --git a/Admin/webfront/chat.html b/Admin/webfront/chat.html new file mode 100644 index 000000000..5f282702b --- /dev/null +++ b/Admin/webfront/chat.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Plugins/SimpleStats/Chat/ChatDatabase.cs b/Plugins/SimpleStats/Chat/ChatDatabase.cs new file mode 100644 index 000000000..4da3f03f6 --- /dev/null +++ b/Plugins/SimpleStats/Chat/ChatDatabase.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using SharedLibrary; +using System.IO; +using System.Data; + +namespace StatsPlugin +{ + public class ChatDatabase : Database + { + public ChatDatabase(string FN) : base(FN) + { + } + + public override void Init() + { + if (!File.Exists(FileName)) + { + string createChatHistory = @"CREATE TABLE `CHATHISTORY` ( + `ClientID` INTEGER NOT NULL, + `Message` TEXT NOT NULL, + `ServerID` INTEGER NOT NULL, + `TimeSent` TEXT NOT NULL + );"; + + ExecuteNonQuery(createChatHistory); + + string createChatStats = @"CREATE TABLE `WORDSTATS` ( + `Word` TEXT NOT NULL, + `Count` INTEGER NOT NULL DEFAULT 1, + PRIMARY KEY(`Word`) + );"; + + ExecuteNonQuery(createChatStats); + } + } + + private List GetChatHistoryFromQuery(DataTable dt) + { + return dt.Select().Select(q => new ChatHistory() + { + ClientID = Convert.ToInt32(q["ClientID"].ToString()), + Message = q["Message"].ToString(), + ServerID = Convert.ToInt32(q["ServerID"].ToString()), + TimeSent = DateTime.Parse(q["TimeSent"].ToString()) + }) + .ToList(); + } + + public List GetChatForPlayer(int clientID) + { + var queryResult = GetDataTable("CHATHISTORY", new KeyValuePair("ClientID", clientID)); + return GetChatHistoryFromQuery(queryResult); + } + + public List GetChatForServer(int serverID) + { + var queryResult = GetDataTable("CHATHISTORY", new KeyValuePair("ServerID", serverID)); + return GetChatHistoryFromQuery(queryResult); + } + + public void AddChatHistory(int clientID, int serverID, string message) + { + var chat = new Dictionary() + { + { "ClientID", clientID }, + { "ServerID", serverID }, + { "Message", message}, + { "TimeSent", DateTime.UtcNow } + }; + + Insert("CHATHISTORY", chat); + + message.Split(' ').Where(word => word.Length >= 3).Any(word => + { + word = word.ToLower(); + Insert("WORDSTATS", new Dictionary() { { "Word", word } }, true); + // shush :^) + ExecuteNonQuery($"UPDATE WORDSTATS SET Count = Count + 1 WHERE Word='{word.CleanChars()}'"); + return true; + } + ); + } + + public KeyValuePair[] GetWords() + { + var result = GetDataTable("SELECT * FROM WORDSTATS ORDER BY Count desc LIMIT 100"); + return result.Select().Select(w => new KeyValuePair(w["Word"].ToString(), Convert.ToInt32(w["Count"].ToString()))).ToArray(); + } + } +} diff --git a/Plugins/SimpleStats/Chat/ChatHistory.cs b/Plugins/SimpleStats/Chat/ChatHistory.cs new file mode 100644 index 000000000..46563b003 --- /dev/null +++ b/Plugins/SimpleStats/Chat/ChatHistory.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StatsPlugin +{ + public class ChatHistory + { + public int ClientID { get; set; } + public string Message { get; set; } + public int ServerID { get; set; } + public DateTime TimeSent { get; set; } + } +} diff --git a/Plugins/SimpleStats/Chat/ChatHistoryPage.cs b/Plugins/SimpleStats/Chat/ChatHistoryPage.cs new file mode 100644 index 000000000..1d44ee0c6 --- /dev/null +++ b/Plugins/SimpleStats/Chat/ChatHistoryPage.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using SharedLibrary; +using System.Collections.Specialized; + +namespace StatsPlugin.Chat +{ + public class ChatPage : HTMLPage + { + public ChatPage() : base(false) { } + + public override string GetContent(NameValueCollection querySet, IDictionary headers) + { + StringBuilder S = new StringBuilder(); + S.Append(LoadHeader()); + + IFile chat = new IFile("webfront\\chat.html"); + S.Append(chat.GetText()); + chat.Close(); + + S.Append(LoadFooter()); + + return S.ToString(); + } + + public override string GetName() => "Chat Stats"; + public override string GetPath() => "/chat"; + } + + public class WordCloudJSON : IPage + { + public string GetName() => "Word Cloud JSON"; + public string GetPath() => "/_words"; + public string GetContentType() => "application/json"; + public bool Visible() => false; + + public HttpResponse GetPage(NameValueCollection querySet, IDictionary headers) + { + + HttpResponse resp = new HttpResponse() + { + contentType = GetContentType(), + content = Stats.ChatDB.GetWords().Select(w => new + { + Word = w.Key, + Count = w.Value + }) + .OrderByDescending(x => x.Count) + .ToArray(), + + additionalHeaders = new Dictionary() + }; + + return resp; + } + } + + public class ClientChatJSON : IPage + { + public string GetName() => "Client Chat JSON"; + public string GetPath() => "/_clientchat"; + public string GetContentType() => "application/json"; + public bool Visible() => false; + + public HttpResponse GetPage(NameValueCollection querySet, IDictionary headers) + { + + HttpResponse resp = new HttpResponse() + { + contentType = GetContentType(), + content = Stats.ChatDB.GetChatForPlayer(Convert.ToInt32(querySet["clientid"])).ToArray(), + additionalHeaders = new Dictionary() + }; + + return resp; + } + } +} diff --git a/Plugins/SimpleStats/Plugin.cs b/Plugins/SimpleStats/Plugin.cs index 243fb5085..d454ffb8b 100644 --- a/Plugins/SimpleStats/Plugin.cs +++ b/Plugins/SimpleStats/Plugin.cs @@ -99,6 +99,7 @@ namespace StatsPlugin public static SharedLibrary.Interfaces.IManager ManagerInstance; public static int MAX_KILLEVENTS = 1000; public static Dictionary ServerStats { get; private set; } + public static ChatDatabase ChatDB { get; private set; } public class ServerStatInfo { @@ -197,10 +198,15 @@ namespace StatsPlugin WebService.PageList.Add(new StatsPage()); WebService.PageList.Add(new KillStatsJSON()); + WebService.PageList.Add(new Chat.WordCloudJSON()); + WebService.PageList.Add(new Chat.ClientChatJSON()); + WebService.PageList.Add(new Chat.ChatPage()); ManagerInstance.GetMessageTokens().Add(new MessageToken("TOTALKILLS", GetTotalKills)); ManagerInstance.GetMessageTokens().Add(new MessageToken("TOTALPLAYTIME", GetTotalPlaytime)); + ChatDB = new ChatDatabase("Database/ChatHistory.rm"); + try { var minimapConfig = MinimapConfig.Read("Config/minimaps.cfg"); @@ -354,6 +360,11 @@ namespace StatsPlugin await Victim.Tell(MessageOnStreak(curServer.killStreaks[Victim.ClientID], curServer.deathStreaks[Victim.ClientID])); } + + if (E.Type == Event.GType.Say) + { + ChatDB.AddChatHistory(E.Origin.DatabaseID, E.Owner.GetPort(), E.Data); + } } public static string GetTotalKills() diff --git a/Plugins/SimpleStats/StatsPlugin.csproj b/Plugins/SimpleStats/StatsPlugin.csproj index ef206e123..2d884f400 100644 --- a/Plugins/SimpleStats/StatsPlugin.csproj +++ b/Plugins/SimpleStats/StatsPlugin.csproj @@ -69,6 +69,9 @@ + + + diff --git a/Plugins/Tests/Plugin.cs b/Plugins/Tests/Plugin.cs index 0d72b4151..3327dbc0b 100644 --- a/Plugins/Tests/Plugin.cs +++ b/Plugins/Tests/Plugin.cs @@ -65,13 +65,17 @@ namespace IW4MAdmin.Plugins await S.RemovePlayer(index); await S.AddPlayer(p); + Interval = DateTime.Now; if (S.ClientNum > 0) { + //"K;26d2f66b95184934;1;allies;egor;5c56fef676b3818d;0;axis;1_din;m21_heartbeat_mp;98;MOD_RIFLE_BULLET;torso_lower"; var victimPlayer = S.Players.Where(pl => pl != null).ToList()[rand.Next(0, S.ClientNum - 1)]; var attackerPlayer = S.Players.Where(pl => pl != null).ToList()[rand.Next(0, S.ClientNum - 1)]; + await S.ExecuteEvent(new Event(Event.GType.Say, $"test_{attackerPlayer.ClientID}", victimPlayer, attackerPlayer, S)); + string[] eventLine = null; for (int i = 0; i < 1; i++) diff --git a/SharedLibrary/Database.cs b/SharedLibrary/Database.cs index 6ae9b9f03..2eca9f9b5 100644 --- a/SharedLibrary/Database.cs +++ b/SharedLibrary/Database.cs @@ -22,7 +22,7 @@ namespace SharedLibrary abstract public void Init(); - protected bool Insert(String tableName, Dictionary data) + protected bool Insert(String tableName, Dictionary data, bool ignore = false) { string names = ""; string parameters = ""; @@ -36,10 +36,12 @@ namespace SharedLibrary var Con = GetNewConnection(); + string ignoreCmd = ignore ? " OR IGNORE " : " "; + SQLiteCommand insertcmd = new SQLiteCommand() { Connection = Con, - CommandText = String.Format("INSERT INTO `{0}` ({1}) VALUES ({2});", tableName, names, parameters) + CommandText = String.Format("INSERT{0}INTO `{1}` ({2}) VALUES ({3});", ignoreCmd, tableName, names, parameters) }; foreach (string key in data.Keys) {