Profanity deterrent kick players with offensive names
status parsing with Regex in IW4 is much cleaner fixed tempban not always kicking made plugin event tasks parallel
This commit is contained in:
parent
35e7f57156
commit
3a463be7f8
@ -192,6 +192,9 @@
|
|||||||
"GLOBAL_ERROR": "Error",
|
"GLOBAL_ERROR": "Error",
|
||||||
"GLOBAL_WARNING": "Warning",
|
"GLOBAL_WARNING": "Warning",
|
||||||
"GLOBAL_INFO": "Info",
|
"GLOBAL_INFO": "Info",
|
||||||
"GLOBAL_VERBOSE": "Verbose"
|
"GLOBAL_VERBOSE": "Verbose",
|
||||||
|
|
||||||
|
"MANAGER_CONSOLE_NOSERV": "No servers are currently being monitored",
|
||||||
|
"SERVER_PLUGIN_ERROR": "A plugin generated an error"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -40,7 +40,7 @@
|
|||||||
"SERVER_WARNLIMT_REACHED": "Слишком много предупреждений",
|
"SERVER_WARNLIMT_REACHED": "Слишком много предупреждений",
|
||||||
"SERVER_WARNING": "Предупреждение",
|
"SERVER_WARNING": "Предупреждение",
|
||||||
"SERVER_WEBSITE_GENERIC": "веб-сайт этого сервера",
|
"SERVER_WEBSITE_GENERIC": "веб-сайт этого сервера",
|
||||||
"BROADCAST_ONLINE": "^5IW4MADMIN ^7сейчас ^В СЕТИ",
|
"BROADCAST_ONLINE": "^5IW4MADMIN ^7сейчас СЕТИ",
|
||||||
"BROADCAST_OFFLINE": "IW4MAdmin отключается",
|
"BROADCAST_OFFLINE": "IW4MAdmin отключается",
|
||||||
"COMMAND_HELP_SYNTAX": "синтаксис:",
|
"COMMAND_HELP_SYNTAX": "синтаксис:",
|
||||||
"COMMAND_HELP_OPTIONAL": "опционально",
|
"COMMAND_HELP_OPTIONAL": "опционально",
|
||||||
|
@ -23,6 +23,11 @@ namespace Application.Misc
|
|||||||
string response = await RequestClient.GetStringAsync($"http://v2.api.iphub.info/ip/{ip}");
|
string response = await RequestClient.GetStringAsync($"http://v2.api.iphub.info/ip/{ip}");
|
||||||
var responseJson = JsonConvert.DeserializeObject<JObject>(response);
|
var responseJson = JsonConvert.DeserializeObject<JObject>(response);
|
||||||
int blockType = Convert.ToInt32(responseJson["block"]);
|
int blockType = Convert.ToInt32(responseJson["block"]);
|
||||||
|
if (responseJson.ContainsKey("isp"))
|
||||||
|
{
|
||||||
|
if (responseJson["isp"].ToString() == "TSF-IP-CORE")
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return blockType == 1;
|
return blockType == 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,9 @@ namespace Application.RconParsers
|
|||||||
Ban = "clientkick {0} \"{1}\"",
|
Ban = "clientkick {0} \"{1}\"",
|
||||||
TempBan = "tempbanclient {0} \"{1}\""
|
TempBan = "tempbanclient {0} \"{1}\""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static string StatusRegex = @"^( *[0-9]+) +([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){16}|bot[0-9]+) +(.{0,20}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:\d{1,5}|0+.0+:\d{1,5}) +(-*[0-9]+) +([0-9]+) *$";
|
||||||
|
|
||||||
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
||||||
{
|
{
|
||||||
return (await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command)).Skip(1).ToArray();
|
return (await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command)).Skip(1).ToArray();
|
||||||
@ -82,30 +84,33 @@ namespace Application.RconParsers
|
|||||||
{
|
{
|
||||||
String responseLine = S.Trim();
|
String responseLine = S.Trim();
|
||||||
|
|
||||||
if (Regex.Matches(responseLine, @" *^\d+", RegexOptions.IgnoreCase).Count > 0)
|
var regex = Regex.Match(responseLine, StatusRegex, RegexOptions.IgnoreCase);
|
||||||
|
if (regex.Success)
|
||||||
{
|
{
|
||||||
String[] playerInfo = responseLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
int clientNumber = int.Parse(regex.Groups[1].Value);
|
||||||
if (playerInfo.Length < 4)
|
int score = int.Parse(regex.Groups[2].Value);
|
||||||
continue;
|
|
||||||
int cID = -1;
|
int ping = 999;
|
||||||
int Ping = -1;
|
|
||||||
Int32.TryParse(playerInfo[2], out Ping);
|
// their state can be CNCT, ZMBI etc
|
||||||
String cName = Encoding.UTF8.GetString(Encoding.Convert(Utilities.EncodingType, Encoding.UTF8, Utilities.EncodingType.GetBytes(responseLine.Substring(46, 18).StripColors().Trim())));
|
if (regex.Groups[3].Value.Length <= 3)
|
||||||
long npID = Regex.Match(responseLine, @"([a-z]|[0-9]){16}|bot[0-9]+", RegexOptions.IgnoreCase).Value.ConvertLong();
|
{
|
||||||
int.TryParse(playerInfo[0], out cID);
|
ping = int.Parse(regex.Groups[3].Value);
|
||||||
var regex = Regex.Match(responseLine, @"\d+\.\d+\.\d+.\d+\:\d{1,5}");
|
}
|
||||||
int cIP = regex.Value.Split(':')[0].ConvertToIP();
|
|
||||||
regex = Regex.Match(responseLine, @"[0-9]{1,2}\s+[0-9]+\s+");
|
long networkId = regex.Groups[4].Value.ConvertLong();
|
||||||
int score = Int32.Parse(regex.Value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[1]);
|
string name = regex.Groups[5].Value.StripColors().Trim();
|
||||||
|
int ip = regex.Groups[7].Value.Split(':')[0].ConvertToIP();
|
||||||
|
|
||||||
Player P = new Player()
|
Player P = new Player()
|
||||||
{
|
{
|
||||||
Name = cName,
|
Name = name,
|
||||||
NetworkId = npID,
|
NetworkId = networkId,
|
||||||
ClientNumber = cID,
|
ClientNumber = clientNumber,
|
||||||
IPAddress = cIP,
|
IPAddress = ip,
|
||||||
Ping = Ping,
|
Ping = ping,
|
||||||
Score = score,
|
Score = score,
|
||||||
IsBot = cIP == 0
|
IsBot = ip == 0
|
||||||
};
|
};
|
||||||
|
|
||||||
StatusPlayers.Add(P);
|
StatusPlayers.Add(P);
|
||||||
|
@ -178,6 +178,9 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
if (player.Level != Player.Permission.Banned && currentBan.Type == Penalty.PenaltyType.Ban)
|
if (player.Level != Player.Permission.Banned && currentBan.Type == Penalty.PenaltyType.Ban)
|
||||||
await player.Ban($"{loc["SERVER_BAN_PREV"]} {currentBan.Offense}", autoKickClient);
|
await player.Ban($"{loc["SERVER_BAN_PREV"]} {currentBan.Offense}", autoKickClient);
|
||||||
|
|
||||||
|
// they didn't fully connect so empty their slot
|
||||||
|
Players[player.ClientNumber] = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +189,7 @@ namespace IW4MAdmin
|
|||||||
var e = new GameEvent(GameEvent.EventType.Connect, "", player, null, this);
|
var e = new GameEvent(GameEvent.EventType.Connect, "", player, null, this);
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
|
|
||||||
// e.OnProcessed.Wait();
|
e.OnProcessed.Wait();
|
||||||
|
|
||||||
if (!Manager.GetApplicationSettings().Configuration().EnableClientVPNs &&
|
if (!Manager.GetApplicationSettings().Configuration().EnableClientVPNs &&
|
||||||
await VPNCheck.UsingVPN(player.IPAddressString, Manager.GetApplicationSettings().Configuration().IPHubAPIKey))
|
await VPNCheck.UsingVPN(player.IPAddressString, Manager.GetApplicationSettings().Configuration().IPHubAPIKey))
|
||||||
@ -362,14 +365,15 @@ namespace IW4MAdmin
|
|||||||
await ProcessEvent(E);
|
await ProcessEvent(E);
|
||||||
Manager.GetEventApi().OnServerEvent(this, E);
|
Manager.GetEventApi().OnServerEvent(this, E);
|
||||||
|
|
||||||
foreach (IPlugin P in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
|
// this allows us to catch exceptions but still run it parallel
|
||||||
|
async Task pluginHandlingAsync(Task onEvent, string pluginName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (cts.IsCancellationRequested)
|
if (cts.IsCancellationRequested)
|
||||||
break;
|
return;
|
||||||
|
|
||||||
await P.OnEventAsync(E, this);
|
await onEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this happens if a plugin (login) wants to stop commands from executing
|
// this happens if a plugin (login) wants to stop commands from executing
|
||||||
@ -381,7 +385,7 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
catch (Exception Except)
|
catch (Exception Except)
|
||||||
{
|
{
|
||||||
Logger.WriteError(String.Format("The plugin \"{0}\" generated an error. ( see log )", P.Name));
|
Logger.WriteError($"{loc["SERVER_PLUGIN_ERROR"]} [{pluginName}]");
|
||||||
Logger.WriteDebug(String.Format("Error Message: {0}", Except.Message));
|
Logger.WriteDebug(String.Format("Error Message: {0}", Except.Message));
|
||||||
Logger.WriteDebug(String.Format("Error Trace: {0}", Except.StackTrace));
|
Logger.WriteDebug(String.Format("Error Trace: {0}", Except.StackTrace));
|
||||||
while (Except.InnerException != null)
|
while (Except.InnerException != null)
|
||||||
@ -389,11 +393,15 @@ namespace IW4MAdmin
|
|||||||
Except = Except.InnerException;
|
Except = Except.InnerException;
|
||||||
Logger.WriteDebug($"Inner exception: {Except.Message}");
|
Logger.WriteDebug($"Inner exception: {Except.Message}");
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pluginTasks = SharedLibraryCore.Plugins.PluginImporter.ActivePlugins.
|
||||||
|
Select(p => pluginHandlingAsync(p.OnEventAsync(E, this), p.Name));
|
||||||
|
|
||||||
|
// execute all the plugin updates simultaneously
|
||||||
|
await Task.WhenAll(pluginTasks);
|
||||||
|
|
||||||
// hack: this prevents commands from getting executing that 'shouldn't' be
|
// hack: this prevents commands from getting executing that 'shouldn't' be
|
||||||
if (E.Type == GameEvent.EventType.Command &&
|
if (E.Type == GameEvent.EventType.Command &&
|
||||||
E.Extra != null &&
|
E.Extra != null &&
|
||||||
@ -402,7 +410,6 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
await (((Command)E.Extra).ExecuteAsync(E));
|
await (((Command)E.Extra).ExecuteAsync(E));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -599,27 +606,35 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
override public async Task<bool> ProcessUpdatesAsync(CancellationToken cts)
|
override public async Task<bool> ProcessUpdatesAsync(CancellationToken cts)
|
||||||
{
|
{
|
||||||
|
// this isn't really used anymore
|
||||||
this.cts = cts;
|
this.cts = cts;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (Manager.ShutdownRequested())
|
||||||
|
{
|
||||||
|
foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
|
||||||
|
await plugin.OnUnloadAsync();
|
||||||
|
|
||||||
|
for (int i = 0; i < Players.Count; i++)
|
||||||
|
await RemovePlayer(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// only check every 2 minutes if the server doesn't seem to be responding
|
||||||
if ((DateTime.Now - LastPoll).TotalMinutes < 2 && ConnectionErrors >= 1)
|
if ((DateTime.Now - LastPoll).TotalMinutes < 2 && ConnectionErrors >= 1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// trying to reduce the polling rate as every 450ms is unnecessary
|
int polledPlayerCount = await PollPlayersAsync();
|
||||||
if ((DateTime.Now - LastPoll).TotalSeconds >= 10)
|
|
||||||
{
|
|
||||||
int polledPlayerCount = await PollPlayersAsync();
|
|
||||||
|
|
||||||
if (ConnectionErrors > 0)
|
if (ConnectionErrors > 0)
|
||||||
{
|
{
|
||||||
Logger.WriteVerbose($"{loc["MANAGER_CONNECTION_REST"]} {IP}:{Port}");
|
Logger.WriteVerbose($"{loc["MANAGER_CONNECTION_REST"]} {IP}:{Port}");
|
||||||
Throttled = false;
|
Throttled = false;
|
||||||
}
|
|
||||||
ConnectionErrors = 0;
|
|
||||||
LastPoll = DateTime.Now;
|
|
||||||
}
|
}
|
||||||
|
ConnectionErrors = 0;
|
||||||
|
LastPoll = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (NetworkException e)
|
catch (NetworkException e)
|
||||||
@ -637,6 +652,8 @@ namespace IW4MAdmin
|
|||||||
LastMessage = DateTime.Now - start;
|
LastMessage = DateTime.Now - start;
|
||||||
lastCount = DateTime.Now;
|
lastCount = DateTime.Now;
|
||||||
|
|
||||||
|
// todo: re-enable on tick
|
||||||
|
/*
|
||||||
if ((DateTime.Now - tickTime).TotalMilliseconds >= 1000)
|
if ((DateTime.Now - tickTime).TotalMilliseconds >= 1000)
|
||||||
{
|
{
|
||||||
foreach (var Plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
|
foreach (var Plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
|
||||||
@ -647,8 +664,9 @@ namespace IW4MAdmin
|
|||||||
await Plugin.OnTickAsync(this);
|
await Plugin.OnTickAsync(this);
|
||||||
}
|
}
|
||||||
tickTime = DateTime.Now;
|
tickTime = DateTime.Now;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
// update the player history
|
||||||
if ((lastCount - playerCountStart).TotalMinutes >= SharedLibraryCore.Helpers.PlayerHistory.UpdateInterval)
|
if ((lastCount - playerCountStart).TotalMinutes >= SharedLibraryCore.Helpers.PlayerHistory.UpdateInterval)
|
||||||
{
|
{
|
||||||
while (PlayerHistory.Count > ((60 / SharedLibraryCore.Helpers.PlayerHistory.UpdateInterval) * 12)) // 12 times a hour for 12 hours
|
while (PlayerHistory.Count > ((60 / SharedLibraryCore.Helpers.PlayerHistory.UpdateInterval) * 12)) // 12 times a hour for 12 hours
|
||||||
@ -657,6 +675,7 @@ namespace IW4MAdmin
|
|||||||
playerCountStart = DateTime.Now;
|
playerCountStart = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send out broadcast messages
|
||||||
if (LastMessage.TotalSeconds > Manager.GetApplicationSettings().Configuration().AutoMessagePeriod
|
if (LastMessage.TotalSeconds > Manager.GetApplicationSettings().Configuration().AutoMessagePeriod
|
||||||
&& BroadcastMessages.Count > 0
|
&& BroadcastMessages.Count > 0
|
||||||
&& ClientNum > 0)
|
&& ClientNum > 0)
|
||||||
@ -666,14 +685,6 @@ namespace IW4MAdmin
|
|||||||
start = DateTime.Now;
|
start = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Manager.ShutdownRequested())
|
|
||||||
{
|
|
||||||
foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
|
|
||||||
await plugin.OnUnloadAsync();
|
|
||||||
|
|
||||||
for (int i = 0; i < Players.Count; i++)
|
|
||||||
await RemovePlayer(i);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,16 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
|
|||||||
S.Logger.WriteWarning("Could not add client to profanity tracking");
|
S.Logger.WriteWarning("Could not add client to profanity tracking");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var objectionalWords = Settings.Configuration().OffensiveWords;
|
||||||
|
bool containsObjectionalWord = objectionalWords.FirstOrDefault(w => E.Origin.Name.ToLower().Contains(w)) != null;
|
||||||
|
|
||||||
|
if (containsObjectionalWord)
|
||||||
|
{
|
||||||
|
await E.Origin.Kick(Settings.Configuration().ProfanityKickMessage, new Player()
|
||||||
|
{
|
||||||
|
ClientId = 1
|
||||||
|
});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (E.Type == GameEvent.EventType.Disconnect)
|
if (E.Type == GameEvent.EventType.Disconnect)
|
||||||
|
@ -467,6 +467,14 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
// calculate the new weight against average times the weight against play time
|
// calculate the new weight against average times the weight against play time
|
||||||
clientStats.SPM = (killSPM * SPMAgainstPlayWeight) + (clientStats.SPM * (1 - SPMAgainstPlayWeight));
|
clientStats.SPM = (killSPM * SPMAgainstPlayWeight) + (clientStats.SPM * (1 - SPMAgainstPlayWeight));
|
||||||
|
|
||||||
|
if (clientStats.SPM < 0)
|
||||||
|
{
|
||||||
|
Log.WriteWarning("[StatManager:UpdateStats] clientStats SPM < 0");
|
||||||
|
Log.WriteDebug($"{scoreDifference}-{clientStats.RoundScore} - {clientStats.LastScore} - {clientStats.SessionScore}");
|
||||||
|
clientStats.SPM = 0;
|
||||||
|
}
|
||||||
|
|
||||||
clientStats.SPM = Math.Round(clientStats.SPM, 3);
|
clientStats.SPM = Math.Round(clientStats.SPM, 3);
|
||||||
clientStats.Skill = Math.Round((clientStats.SPM * KDRWeight), 3);
|
clientStats.Skill = Math.Round((clientStats.SPM * KDRWeight), 3);
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ namespace WebfrontCore.Controllers
|
|||||||
CurrentServer = server,
|
CurrentServer = server,
|
||||||
Name = Client.Name
|
Name = Client.Name
|
||||||
};
|
};
|
||||||
|
|
||||||
var remoteEvent = new GameEvent()
|
var remoteEvent = new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.Say,
|
Type = GameEvent.EventType.Say,
|
||||||
|
Loading…
Reference in New Issue
Block a user