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)
{