Miscellanous fixes

This commit is contained in:
RaidMax 2017-11-13 15:58:23 -06:00
parent 07e3c61e98
commit e64a216cc0
11 changed files with 260 additions and 163 deletions

View File

@ -15,7 +15,7 @@ namespace IW4MAdmin
{ {
// it looks like there's a library error in // it looks like there's a library error in
// Kayak.Http.HttpServerTransactionDelegate.OnError // Kayak.Http.HttpServerTransactionDelegate.OnError
if ((uint)e.HResult ==0x80004003) if ((uint)e.HResult == 0x80004003)
return; return;
ApplicationManager.GetInstance().Logger.WriteWarning("Web service has encountered an error - " + e.Message); ApplicationManager.GetInstance().Logger.WriteWarning("Web service has encountered an error - " + e.Message);
@ -77,19 +77,39 @@ namespace IW4MAdmin
catch (Exception e) catch (Exception e)
{ {
ApplicationManager.GetInstance().Logger.WriteError($"Webfront error during request"); if (e.GetType() == typeof(FormatException))
ApplicationManager.GetInstance().Logger.WriteDebug($"Message: {e.Message}");
ApplicationManager.GetInstance().Logger.WriteDebug($"Stack Trace: {e.StackTrace}");
response.OnResponse(new HttpResponseHead()
{ {
Status = "500 Internal Server Error", ApplicationManager.GetInstance().Logger.WriteWarning("Request parameter data format was incorrect");
Headers = new Dictionary<string, string>() ApplicationManager.GetInstance().Logger.WriteDebug($"Request Path {request.Path}");
ApplicationManager.GetInstance().Logger.WriteDebug($"Request Query String {request.QueryString}");
response.OnResponse(new HttpResponseHead()
{
Status = "400 Bad Request",
Headers = new Dictionary<string, string>()
{
{ "Content-Type", "text/html" },
{ "Content-Length", "0"},
}
}, new BufferedProducer(""));
}
else
{
ApplicationManager.GetInstance().Logger.WriteError($"Webfront error during request");
ApplicationManager.GetInstance().Logger.WriteDebug($"Message: {e.Message}");
ApplicationManager.GetInstance().Logger.WriteDebug($"Stack Trace: {e.StackTrace}");
response.OnResponse(new HttpResponseHead()
{
Status = "500 Internal Server Error",
Headers = new Dictionary<string, string>()
{ {
{ "Content-Type", "text/html" }, { "Content-Type", "text/html" },
{ "Content-Length", "0"}, { "Content-Length", "0"},
} }
}, new BufferedProducer("")); }, new BufferedProducer(""));
}
} }
} }
} }
@ -98,7 +118,7 @@ namespace IW4MAdmin
{ {
ArraySegment<byte> data; ArraySegment<byte> data;
public BufferedProducer(string data) : this(data, Encoding.UTF8) { } public BufferedProducer(string data) : this(data, Encoding.ASCII) { }
public BufferedProducer(string data, Encoding encoding) : this(encoding.GetBytes(data)) { } public BufferedProducer(string data, Encoding encoding) : this(encoding.GetBytes(data)) { }
public BufferedProducer(byte[] data) : this(new ArraySegment<byte>(data)) { } public BufferedProducer(byte[] data) : this(new ArraySegment<byte>(data)) { }
@ -109,8 +129,17 @@ namespace IW4MAdmin
public IDisposable Connect(IDataConsumer channel) public IDisposable Connect(IDataConsumer channel)
{ {
channel?.OnData(data, null); try
channel?.OnEnd(); {
channel?.OnData(data, null);
channel?.OnEnd();
}
catch (Exception)
{
}
return null; return null;
} }
} }
@ -129,19 +158,20 @@ namespace IW4MAdmin
public bool OnData(ArraySegment<byte> data, Action continuation) public bool OnData(ArraySegment<byte> data, Action continuation)
{ {
buffer?.Add(data); // this should hopefully clean the non ascii characters out.
buffer?.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(Encoding.ASCII.GetString(data.ToArray()))));
return false; return false;
} }
public void OnError(Exception error) public void OnError(Exception error)
{ {
errorCallback?.Invoke(error); // errorCallback?.Invoke(error);
} }
public void OnEnd() public void OnEnd()
{ {
var str = buffer var str = buffer
.Select(b => Encoding.UTF8.GetString(b.Array, b.Offset, b.Count)) .Select(b => Encoding.ASCII.GetString(b.Array, b.Offset, b.Count))
.Aggregate((result, next) => result + next); .Aggregate((result, next) => result + next);
resultCallback(str); resultCallback(str);

View File

@ -15,7 +15,8 @@ namespace IW4MAdmin
Info, Info,
Debug, Debug,
Warning, Warning,
Error Error,
Assert
} }
string FileName; string FileName;
@ -72,5 +73,11 @@ namespace IW4MAdmin
{ {
Write(msg, LogType.Warning); Write(msg, LogType.Warning);
} }
public void WriteAssert(bool condition, string msg)
{
if (!condition)
Write(msg, LogType.Assert);
}
} }
} }

View File

@ -131,11 +131,14 @@ namespace IW4MAdmin
catch (ServerException e) catch (ServerException e)
{ {
Logger.WriteWarning($"Not monitoring server {Conf.IP}:{Conf.Port} due to uncorrectable errors"); Logger.WriteError($"Not monitoring server {Conf.IP}:{Conf.Port} due to uncorrectable errors");
if (e.GetType() == typeof(DvarException)) if (e.GetType() == typeof(DvarException))
Logger.WriteError($"Could not get the dvar value for {(e as DvarException).Data["dvar_name"]} (ensure the server has a map loaded)"); Logger.WriteDebug($"Could not get the dvar value for {(e as DvarException).Data["dvar_name"]} (ensure the server has a map loaded)");
else if (e.GetType() == typeof(NetworkException)) else if (e.GetType() == typeof(NetworkException))
Logger.WriteError(e.Message); {
Logger.WriteDebug(e.Message);
Logger.WriteDebug($"Internal Exception: {e.Data["internal_exception"]}");
}
} }
}); });
} }
@ -148,7 +151,7 @@ namespace IW4MAdmin
Commands.Add(new CQuit("quit", "quit IW4MAdmin", "q", Player.Permission.Owner, 0, false)); Commands.Add(new CQuit("quit", "quit IW4MAdmin", "q", Player.Permission.Owner, 0, false));
Commands.Add(new CKick("kick", "kick a player by name. syntax: !kick <player> <reason>.", "k", Player.Permission.Trusted, 2, true)); Commands.Add(new CKick("kick", "kick a player by name. syntax: !kick <player> <reason>.", "k", Player.Permission.Trusted, 2, true));
Commands.Add(new CSay("say", "broadcast message to all players. syntax: !say <message>.", "s", Player.Permission.Moderator, 1, false)); Commands.Add(new CSay("say", "broadcast message to all players. syntax: !say <message>.", "s", Player.Permission.Moderator, 1, false));
Commands.Add(new CTempBan("tempban", "temporarily ban a player for 1 hour. syntax: !tempban <player> <reason>.", "tb", Player.Permission.Moderator, 2, true)); Commands.Add(new CTempBan("tempban", "temporarily ban a player for for specified time (defaults to 1 hour). syntax: !tempban <player> <time>(m|h|d|w|y) <reason>.", "tb", Player.Permission.Moderator, 2, true));
Commands.Add(new CBan("ban", "permanently ban a player from the server. syntax: !ban <player> <reason>", "b", Player.Permission.SeniorAdmin, 2, true)); Commands.Add(new CBan("ban", "permanently ban a player from the server. syntax: !ban <player> <reason>", "b", Player.Permission.SeniorAdmin, 2, true));
Commands.Add(new CWhoAmI("whoami", "give information about yourself. syntax: !whoami.", "who", Player.Permission.User, 0, false)); Commands.Add(new CWhoAmI("whoami", "give information about yourself. syntax: !whoami.", "who", Player.Permission.User, 0, false));
Commands.Add(new CList("list", "list active clients syntax: !list.", "l", Player.Permission.Moderator, 0, false)); Commands.Add(new CList("list", "list active clients syntax: !list.", "l", Player.Permission.Moderator, 0, false));
@ -199,7 +202,7 @@ namespace IW4MAdmin
if (Status.RequestedTask == null || Status.RequestedTask.IsCompleted) if (Status.RequestedTask == null || Status.RequestedTask.IsCompleted)
{ {
Status.Update(new Task(() => (Status.Dependant as Server).ProcessUpdatesAsync(Status.GetToken()))); Status.Update(new Task(() => (Status.Dependant as Server).ProcessUpdatesAsync(Status.GetToken())));
if (Status.RunAverage > 1000) if (Status.RunAverage > 1000 + UPDATE_FREQUENCY)
Logger.WriteWarning($"Update task average execution is longer than desired for {(Status.Dependant as Server).GetIP()}::{(Status.Dependant as Server).GetPort()} [{Status.RunAverage}ms]"); Logger.WriteWarning($"Update task average execution is longer than desired for {(Status.Dependant as Server).GetIP()}::{(Status.Dependant as Server).GetPort()} [{Status.RunAverage}ms]");
} }
} }

View File

@ -27,6 +27,12 @@ namespace IW4MAdmin
return true; return true;
} }
if (P.Name.Length < 3)
{
await this.ExecuteCommandAsync($"clientkick {P.ClientID} \"Your name must contain atleast 3 characters.\"");
return false;
}
Logger.WriteDebug($"Client slot #{P.ClientID} now reserved"); Logger.WriteDebug($"Client slot #{P.ClientID} now reserved");
try try
@ -332,7 +338,7 @@ namespace IW4MAdmin
if (ConnectionErrors > 0) if (ConnectionErrors > 0)
{ {
Logger.WriteInfo($"Connection has been reestablished with {IP}:{Port}"); Logger.WriteVerbose($"Connection has been reestablished with {IP}:{Port}");
Throttled = false; Throttled = false;
} }
ConnectionErrors = 0; ConnectionErrors = 0;
@ -345,6 +351,7 @@ namespace IW4MAdmin
if (ConnectionErrors == 1) if (ConnectionErrors == 1)
{ {
Logger.WriteError($"{e.Message} {IP}:{Port}, reducing polling rate"); Logger.WriteError($"{e.Message} {IP}:{Port}, reducing polling rate");
Logger.WriteDebug($"Internal Exception: {e.Data["internal_exception"]}");
Throttled = true; Throttled = true;
} }
return; return;
@ -478,7 +485,7 @@ namespace IW4MAdmin
this.MaxClients = maxplayers.Value; this.MaxClients = maxplayers.Value;
this.FSGame = game.Value; this.FSGame = game.Value;
await this.SetDvarAsync("sv_kickbantime", 3600); await this.SetDvarAsync("sv_kickbantime", 60);
await this.SetDvarAsync("sv_network_fps", 1000); await this.SetDvarAsync("sv_network_fps", 1000);
await this.SetDvarAsync("com_maxfps", 1000); await this.SetDvarAsync("com_maxfps", 1000);
@ -655,7 +662,7 @@ namespace IW4MAdmin
public override async Task TempBan(String Reason, TimeSpan length, Player Target, Player Origin) public override async Task TempBan(String Reason, TimeSpan length, Player Target, Player Origin)
{ {
await this.ExecuteCommandAsync($"tempbanclient {Target.ClientID } \"^1Player Temporarily Banned: ^5{ Reason }\""); await this.ExecuteCommandAsync($"clientkick {Target.ClientID } \"^1Player Temporarily Banned: ^5{ Reason }\"");
Penalty newPenalty = new Penalty(Penalty.Type.TempBan, Reason.StripColors(), Target.NetworkID, Origin.NetworkID, DateTime.Now, Target.IP, DateTime.Now + length); Penalty newPenalty = new Penalty(Penalty.Type.TempBan, Reason.StripColors(), Target.NetworkID, Origin.NetworkID, DateTime.Now, Target.IP, DateTime.Now + length);
await Task.Run(() => await Task.Run(() =>
{ {
@ -678,10 +685,10 @@ namespace IW4MAdmin
{ {
if (server.GetPlayersAsList().Count > 0) if (server.GetPlayersAsList().Count > 0)
{ {
var activeClient = server.GetPlayersAsList().Find(x => x.NetworkID == Target.NetworkID); var activeClient = server.GetPlayersAsList().SingleOrDefault(x => x.NetworkID == Target.NetworkID);
if (activeClient != null) if (activeClient != null)
{ {
await server.ExecuteCommandAsync($"tempbanclient {activeClient.ClientID} \"{Message} ^7 ({Website}) ^7\""); await server.ExecuteCommandAsync($"clientkick {activeClient.ClientID} \"{Message} ^7 ({Website}) ^7\"");
break; break;
} }
} }

Binary file not shown.

View File

@ -1,30 +1,47 @@
<script src="/webfront/scripts/wordcloud2.js"></script> <script src="/webfront/scripts/wordcloud2.js"></script>
<div class="chat-history"></div> <div style="display:none;" class="chat-history">
<canvas id="chat-word-cloud" width="625" height="625"></canvas> <h2>Chat history </h2>
<br/>
</div>
<div id="word-cloud-wrapper" style="text-align: center; display: none;">
<canvas id="chat-word-cloud" width="750" height="750"></canvas>
</div>
<script> <script>
if (parseGet("clientid") == "undefined") { if (parseGet("clientid") == "undefined") {
$('#word-cloud-wrapper').show();
$.getJSON("/_words", function (result) { $.getJSON("/_words", function (result) {
var wordList = []; var wordList = [];
var largestWord = 0;
$.each(result, function (i, word) { $.each(result, function (i, word) {
if (word.Count > largestWord)
largestWord = word.Count;
wordList.push([word.Word, word.Count]); wordList.push([word.Word, word.Count]);
}); });
var _weightFactor = Math.min(1, (1 / largestWord) / 0.003599);
WordCloud(document.getElementById('chat-word-cloud'), { list: wordList, backgroundColor: "rgb(34,34,34)", minSize: "14pt", color: "rgb(0, 122, 204)", wait: 20, weightFactor: 2 }); WordCloud(document.getElementById('chat-word-cloud'), { list: wordList, backgroundColor: "rgb(34,34,34)", color: "rgb(0, 122, 204)", wait: 0, weightFactor: _weightFactor });
}); });
} }
else { else {
$('.chat-history').show();
$.getJSON("/_clientchat?clientid=" + parseGet("clientid"), function (result) { $.getJSON("/_clientchat?clientid=" + parseGet("clientid"), function (result) {
result = result.sort(function (a, b) { result = result.sort(function (a, b) {
// Turn your strings into dates, and then subtract them
// to get a value that is either negative, positive, or zero.
return new Date(b.TimeSent) - new Date(a.TimeSent); return new Date(b.TimeSent) - new Date(a.TimeSent);
}); });
if (result.length == 0) {
$('.chat-history h2').append('is empty.');
}
else {
$('.chat-history h2').append('for <b>' + result[0].ClientName + '</b> (' + result.length + ' messages)');
}
$.each(result, function (i, chat) { $.each(result, function (i, chat) {
var date = new Date(chat.TimeSent); var date = new Date(chat.TimeSent);
$('.chat-history').append("<div><span>" + date.toLocaleString() + " &mdash; </span><span><b>" + chat.Client.Name + "</b></span>: <span>" + chat.Message + "</span></div>"); $('.chat-history').append("<div><span>" + date.toLocaleString() + " &mdash; </span><span><b>" + chat.ClientName + "</b></span>: <span>" + chat.Message + "</span></div>");
}); });
}); });
} }

View File

@ -143,6 +143,11 @@ namespace EventAPI
AddRestEvent(new RestEvent(RestEvent.EventType.NOTIFICATION, RestEvent.EventVersion.IW4MAdmin, E.Data, "Chat", E.Origin.Name, "")); AddRestEvent(new RestEvent(RestEvent.EventType.NOTIFICATION, RestEvent.EventVersion.IW4MAdmin, E.Data, "Chat", E.Origin.Name, ""));
} }
if (E.Type == Event.GType.Report)
{
AddRestEvent(new RestEvent(RestEvent.EventType.ALERT, RestEvent.EventVersion.IW4MAdmin, $"**{E.Origin.Name}** has reported **{E.Target.Name}** for: {E.Data.Trim()}", E.Target.Name, E.Origin.Name, ""));
}
if (E.Type == Event.GType.Say && E.Origin.Level < Player.Permission.Moderator) if (E.Type == Event.GType.Say && E.Origin.Level < Player.Permission.Moderator)
{ {
string message = E.Data.ToLower(); string message = E.Data.ToLower();
@ -153,7 +158,8 @@ namespace EventAPI
message.Contains("aim") || message.Contains("aim") ||
message.Contains("wall") || message.Contains("wall") ||
message.Contains("cheto") || message.Contains("cheto") ||
message.Contains("hak"); message.Contains("hak") ||
message.Contains("bot");
if (flagged) if (flagged)
{ {
@ -181,7 +187,7 @@ namespace EventAPI
public static void AddRestEvent(RestEvent E) public static void AddRestEvent(RestEvent E)
{ {
if (APIEvents.Count > 10) if (APIEvents.Count > 20)
APIEvents.Dequeue(); APIEvents.Dequeue();
APIEvents.Enqueue(E); APIEvents.Enqueue(E);
} }

View File

@ -16,6 +16,8 @@ namespace StatsPlugin
"with", "with",
"from", "from",
"about", "about",
"your",
"just",
"into", "into",
"over", "over",
"after", "after",
@ -26,6 +28,7 @@ namespace StatsPlugin
"but", "but",
"his", "his",
"they", "they",
"then",
"her", "her",
"she", "she",
"will", "will",
@ -45,6 +48,8 @@ namespace StatsPlugin
"think", "think",
"look", "look",
"want", "want",
"can",
"was",
"give", "give",
"use", "use",
"find", "find",
@ -82,6 +87,7 @@ namespace StatsPlugin
"the", "the",
"and", "and",
"that", "that",
"than",
"have", "have",
"this", "this",
"one", "one",
@ -90,7 +96,9 @@ namespace StatsPlugin
"yah", "yah",
"why", "why",
"who" , "who" ,
"when"}; "when",
"where",
};
public ChatDatabase(string FN) : base(FN) public ChatDatabase(string FN) : base(FN)
{ {

View File

@ -78,7 +78,7 @@ namespace StatsPlugin.Chat
ServerID = c.ServerID, ServerID = c.ServerID,
Message = c.Message, Message = c.Message,
TimeSent = c.TimeSent, TimeSent = c.TimeSent,
Client = client ClientName = client.Name,
}), }),
additionalHeaders = new Dictionary<string, string>() additionalHeaders = new Dictionary<string, string>()
}; };

View File

@ -230,139 +230,155 @@ namespace StatsPlugin
public async Task OnEventAsync(Event E, Server S) public async Task OnEventAsync(Event E, Server S)
{ {
if (E.Type == Event.GType.Start) try
{ {
statLists.Add(new StatTracking(S.GetPort())); if (E.Type == Event.GType.Start)
ServerStats.Add(S.GetPort(), new ServerStatInfo());
var config = new ConfigurationManager(S);
if (config.GetProperty("EnableTrusted") == null)
config.AddProperty(new KeyValuePair<string, object>("EnableTrusted", true));
}
if (E.Type == Event.GType.Stop)
{
statLists.RemoveAll(s => s.Port == S.GetPort());
ServerStats.Remove(S.GetPort());
}
if (E.Type == Event.GType.Connect)
{
ResetCounters(E.Origin.ClientID, S.GetPort());
var config = new ConfigurationManager(E.Owner);
if (!(bool)config.GetProperty("EnableTrusted"))
return;
PlayerStats checkForTrusted = statLists.Find(x => x.Port == S.GetPort()).playerStats.GetStats(E.Origin);
//todo: move this out of here!!
if (checkForTrusted.TotalPlayTime >= 4320 && E.Origin.Level < Player.Permission.Trusted && E.Origin.Level != Player.Permission.Flagged)
{ {
E.Origin.SetLevel(Player.Permission.Trusted); statLists.Add(new StatTracking(S.GetPort()));
E.Owner.Manager.GetClientDatabase().UpdatePlayer(E.Origin); ServerStats.Add(S.GetPort(), new ServerStatInfo());
await E.Origin.Tell("Congratulations, you are now a ^5trusted ^7player! Type ^5!help ^7to view new commands.");
await E.Origin.Tell("You earned this by playing for ^53 ^7full days!"); var config = new ConfigurationManager(S);
if (config.GetProperty("EnableTrusted") == null)
config.AddProperty(new KeyValuePair<string, object>("EnableTrusted", true));
} }
}
if (E.Type == Event.GType.MapEnd || E.Type == Event.GType.Stop) if (E.Type == Event.GType.Stop)
{
foreach (Player P in S.GetPlayersAsList())
{ {
statLists.RemoveAll(s => s.Port == S.GetPort());
if (P == null) ServerStats.Remove(S.GetPort());
continue;
CalculateAndSaveSkill(P, statLists.Find(x => x.Port == S.GetPort()));
ResetCounters(P.ClientID, S.GetPort());
E.Owner.Logger.WriteInfo($"Updated skill for {P}");
//E.Owner.Log.Write(String.Format("\r\nJoin: {0}\r\nInactive Minutes: {1}\r\nnewPlayTime: {2}\r\nnewSPM: {3}\r\nkdrWeight: {4}\r\nMultiplier: {5}\r\nscoreWeight: {6}\r\nnewSkillFactor: {7}\r\nprojectedNewSkill: {8}\r\nKills: {9}\r\nDeaths: {10}", connectionTime[P.clientID].ToShortTimeString(), inactiveMinutes[P.clientID], newPlayTime, newSPM, kdrWeight, Multiplier, scoreWeight, newSkillFactor, disconnectStats.Skill, disconnectStats.Kills, disconnectStats.Deaths));
} }
}
if (E.Type == Event.GType.MapChange) if (E.Type == Event.GType.Connect)
{
ServerStats[S.GetPort()].GetKillQueue().Clear();
ServerStats[S.GetPort()].RoundStartTime = DateTime.Now;
}
if (E.Type == Event.GType.Disconnect)
{
CalculateAndSaveSkill(E.Origin, statLists.Find(x => x.Port == S.GetPort()));
ResetCounters(E.Origin.ClientID, S.GetPort());
E.Owner.Logger.WriteInfo($"Updated skill for disconnecting client {E.Origin}");
}
if (E.Type == Event.GType.Kill)
{
if (E.Origin == E.Target || E.Origin == null)
return;
string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
if (killInfo.Length >= 9 && killInfo[0].Contains("ScriptKill"))
{ {
var killEvent = new KillInfo(E.Origin.DatabaseID, E.Target.DatabaseID, S.CurrentMap.Name, killInfo[7], killInfo[8], killInfo[5], killInfo[6], killInfo[3], killInfo[4]) ResetCounters(E.Origin.ClientID, S.GetPort());
var config = new ConfigurationManager(E.Owner);
if (!(bool)config.GetProperty("EnableTrusted"))
return;
PlayerStats checkForTrusted = statLists.Find(x => x.Port == S.GetPort()).playerStats.GetStats(E.Origin);
//todo: move this out of here!!
if (checkForTrusted.TotalPlayTime >= 4320 && E.Origin.Level < Player.Permission.Trusted && E.Origin.Level != Player.Permission.Flagged)
{ {
KillerPlayer = E.Origin.Name, E.Origin.SetLevel(Player.Permission.Trusted);
VictimPlayer = E.Target.Name, E.Owner.Manager.GetClientDatabase().UpdatePlayer(E.Origin);
}; await E.Origin.Tell("Congratulations, you are now a ^5trusted ^7player! Type ^5!help ^7to view new commands.");
await E.Origin.Tell("You earned this by playing for ^53 ^7full days!");
if (ServerStats[S.GetPort()].GetKillQueue().Count > MAX_KILLEVENTS - 1) }
ServerStats[S.GetPort()].GetKillQueue().Dequeue();
ServerStats[S.GetPort()].GetKillQueue().Enqueue(killEvent);
//S.Logger.WriteInfo($"{E.Origin.Name} killed {E.Target.Name} with a {killEvent.Weapon} from a distance of {Vector3.Distance(killEvent.KillOrigin, killEvent.DeathOrigin)} with {killEvent.Damage} damage, at {killEvent.HitLoc}");
var cs = statLists.Find(x => x.Port == S.GetPort());
cs.playerStats.AddKill(killEvent);
} }
Player Killer = E.Origin; if (E.Type == Event.GType.MapEnd || E.Type == Event.GType.Stop)
StatTracking curServer = statLists.Find(x => x.Port == S.GetPort()); {
PlayerStats killerStats = curServer.playerStats.GetStats(Killer); foreach (Player P in S.GetPlayersAsList())
{
curServer.lastKill[E.Origin.ClientID] = DateTime.Now; if (P == null)
curServer.Kills[E.Origin.ClientID]++; continue;
if ((DateTime.Now - curServer.lastKill[E.Origin.ClientID]).TotalSeconds > 120) CalculateAndSaveSkill(P, statLists.Find(x => x.Port == S.GetPort()));
curServer.inactiveMinutes[E.Origin.ClientID] += 2; ResetCounters(P.ClientID, S.GetPort());
killerStats.Kills++; E.Owner.Logger.WriteInfo($"Updated skill for {P}");
//E.Owner.Log.Write(String.Format("\r\nJoin: {0}\r\nInactive Minutes: {1}\r\nnewPlayTime: {2}\r\nnewSPM: {3}\r\nkdrWeight: {4}\r\nMultiplier: {5}\r\nscoreWeight: {6}\r\nnewSkillFactor: {7}\r\nprojectedNewSkill: {8}\r\nKills: {9}\r\nDeaths: {10}", connectionTime[P.clientID].ToShortTimeString(), inactiveMinutes[P.clientID], newPlayTime, newSPM, kdrWeight, Multiplier, scoreWeight, newSkillFactor, disconnectStats.Skill, disconnectStats.Kills, disconnectStats.Deaths));
}
}
killerStats.KDR = (killerStats.Deaths == 0) ? killerStats.Kills : killerStats.KDR = Math.Round((double)killerStats.Kills / (double)killerStats.Deaths, 2); if (E.Type == Event.GType.MapChange)
{
ServerStats[S.GetPort()].GetKillQueue().Clear();
ServerStats[S.GetPort()].RoundStartTime = DateTime.Now;
}
curServer.playerStats.UpdateStats(Killer, killerStats); if (E.Type == Event.GType.Disconnect)
{
CalculateAndSaveSkill(E.Origin, statLists.Find(x => x.Port == S.GetPort()));
ResetCounters(E.Origin.ClientID, S.GetPort());
E.Owner.Logger.WriteInfo($"Updated skill for disconnecting client {E.Origin}");
}
curServer.killStreaks[Killer.ClientID] += 1; if (E.Type == Event.GType.Kill)
curServer.deathStreaks[Killer.ClientID] = 0; {
if (E.Origin == E.Target || E.Origin == null)
return;
await Killer.Tell(MessageOnStreak(curServer.killStreaks[Killer.ClientID], curServer.deathStreaks[Killer.ClientID])); string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
if (killInfo.Length >= 9 && killInfo[0].Contains("ScriptKill"))
{
var killEvent = new KillInfo(E.Origin.DatabaseID, E.Target.DatabaseID, S.CurrentMap.Name, killInfo[7], killInfo[8], killInfo[5], killInfo[6], killInfo[3], killInfo[4])
{
KillerPlayer = E.Origin.Name,
VictimPlayer = E.Target.Name,
};
if (ServerStats[S.GetPort()].GetKillQueue().Count > MAX_KILLEVENTS - 1)
ServerStats[S.GetPort()].GetKillQueue().Dequeue();
ServerStats[S.GetPort()].GetKillQueue().Enqueue(killEvent);
//S.Logger.WriteInfo($"{E.Origin.Name} killed {E.Target.Name} with a {killEvent.Weapon} from a distance of {Vector3.Distance(killEvent.KillOrigin, killEvent.DeathOrigin)} with {killEvent.Damage} damage, at {killEvent.HitLoc}");
var cs = statLists.Find(x => x.Port == S.GetPort());
cs.playerStats.AddKill(killEvent);
}
Player Killer = E.Origin;
StatTracking curServer = statLists.Find(x => x.Port == S.GetPort());
PlayerStats killerStats = curServer.playerStats.GetStats(Killer);
if (killerStats == null)
killerStats = new PlayerStats(0, 0, 0, 0, 0, 0);
curServer.lastKill[E.Origin.ClientID] = DateTime.Now;
curServer.Kills[E.Origin.ClientID]++;
if ((DateTime.Now - curServer.lastKill[E.Origin.ClientID]).TotalSeconds > 120)
curServer.inactiveMinutes[E.Origin.ClientID] += 2;
killerStats.Kills++;
killerStats.KDR = (killerStats.Deaths == 0) ? killerStats.Kills : killerStats.KDR = Math.Round((double)killerStats.Kills / (double)killerStats.Deaths, 2);
curServer.playerStats.UpdateStats(Killer, killerStats);
curServer.killStreaks[Killer.ClientID] += 1;
curServer.deathStreaks[Killer.ClientID] = 0;
await Killer.Tell(MessageOnStreak(curServer.killStreaks[Killer.ClientID], curServer.deathStreaks[Killer.ClientID]));
}
if (E.Type == Event.GType.Death)
{
if (E.Origin == E.Target || E.Origin == null)
return;
Player Victim = E.Origin;
StatTracking curServer = statLists.Find(x => x.Port == S.GetPort());
PlayerStats victimStats = curServer.playerStats.GetStats(Victim);
if (victimStats == null)
victimStats = new PlayerStats(0, 0, 0, 0, 0, 0);
victimStats.Deaths++;
victimStats.KDR = Math.Round(victimStats.Kills / (double)victimStats.Deaths, 2);
curServer.playerStats.UpdateStats(Victim, victimStats);
curServer.deathStreaks[Victim.ClientID] += 1;
curServer.killStreaks[Victim.ClientID] = 0;
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);
}
} }
if (E.Type == Event.GType.Death) catch (Exception e)
{ {
if (E.Origin == E.Target || E.Origin == null) S.Logger.WriteWarning("StatsPlugin::OnEventAsync failed to complete");
return; S.Logger.WriteDebug($"Server:{S}\r\nOrigin:{E.Origin}\r\nTarget:{E.Target}");
S.Logger.WriteDebug($"Exception: {e.Message}");
Player Victim = E.Origin;
StatTracking curServer = statLists.Find(x => x.Port == S.GetPort());
PlayerStats victimStats = curServer.playerStats.GetStats(Victim);
victimStats.Deaths++;
victimStats.KDR = Math.Round(victimStats.Kills / (double)victimStats.Deaths, 2);
curServer.playerStats.UpdateStats(Victim, victimStats);
curServer.deathStreaks[Victim.ClientID] += 1;
curServer.killStreaks[Victim.ClientID] = 0;
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);
} }
} }
@ -388,7 +404,8 @@ namespace StatsPlugin
return; return;
PlayerStats DisconnectingPlayerStats = curServer.playerStats.GetStats(P); PlayerStats DisconnectingPlayerStats = curServer.playerStats.GetStats(P);
if (curServer.Kills[P.ClientID] == 0)
if (DisconnectingPlayerStats == null || curServer.Kills[P.ClientID] == 0)
return; return;
else if (curServer.lastKill[P.ClientID] > curServer.connectionTime[P.ClientID]) else if (curServer.lastKill[P.ClientID] > curServer.connectionTime[P.ClientID])
@ -430,6 +447,7 @@ namespace StatsPlugin
if (selectedPlayers == null) if (selectedPlayers == null)
return; return;
selectedPlayers.Kills[cID] = 0; selectedPlayers.Kills[cID] = 0;
selectedPlayers.connectionTime[cID] = DateTime.Now; selectedPlayers.connectionTime[cID] = DateTime.Now;
selectedPlayers.inactiveMinutes[cID] = 0; selectedPlayers.inactiveMinutes[cID] = 0;

View File

@ -23,8 +23,8 @@ namespace SharedLibrary.Network
static string[] SendQuery(QueryType Type, Server QueryServer, string Parameters = "") static string[] SendQuery(QueryType Type, Server QueryServer, string Parameters = "")
{ {
var ServerOOBConnection = new UdpClient(); var ServerOOBConnection = new UdpClient();
ServerOOBConnection.Client.SendTimeout = 1000; ServerOOBConnection.Client.SendTimeout = 5000;
ServerOOBConnection.Client.ReceiveTimeout = 1000; ServerOOBConnection.Client.ReceiveTimeout = 5000;
var Endpoint = new IPEndPoint(IPAddress.Parse(QueryServer.GetIP()), QueryServer.GetPort()); var Endpoint = new IPEndPoint(IPAddress.Parse(QueryServer.GetIP()), QueryServer.GetPort());
string QueryString = String.Empty; string QueryString = String.Empty;
@ -76,15 +76,16 @@ namespace SharedLibrary.Network
throw e; throw e;
} }
catch (Exception) catch (Exception e)
{ {
attempts++; attempts++;
if (attempts > 5) if (attempts > 2)
{ {
var e = new Exceptions.NetworkException("Could not communicate with the server"); var ne = new Exceptions.NetworkException("Could not communicate with the server");
e.Data["server_address"] = ServerOOBConnection.Client.RemoteEndPoint.ToString(); ne.Data["internal_exception"] = e.Message;
ne.Data["server_address"] = ServerOOBConnection.Client.RemoteEndPoint.ToString();
ServerOOBConnection.Close(); ServerOOBConnection.Close();
throw e; throw ne;
} }
Thread.Sleep(1000); Thread.Sleep(1000);