diff --git a/Application/Commands/FindPlayerCommand.cs b/Application/Commands/FindPlayerCommand.cs
new file mode 100644
index 000000000..22f5b21ae
--- /dev/null
+++ b/Application/Commands/FindPlayerCommand.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Data.Models.Client;
+using SharedLibraryCore;
+using SharedLibraryCore.Commands;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Application.Commands
+{
+ ///
+ /// Finds player by name
+ ///
+ public class FindPlayerCommand : Command
+ {
+ public FindPlayerCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config,
+ translationLookup)
+ {
+ Name = "find";
+ Description = _translationLookup["COMMANDS_FIND_DESC"];
+ Alias = "f";
+ Permission = EFClient.Permission.Administrator;
+ RequiresTarget = false;
+ Arguments = new[]
+ {
+ new CommandArgument()
+ {
+ Name = _translationLookup["COMMANDS_ARGS_PLAYER"],
+ Required = true
+ }
+ };
+ }
+
+ public override async Task ExecuteAsync(GameEvent gameEvent)
+ {
+ if (gameEvent.Data.Length < 3)
+ {
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_FIND_MIN"]);
+ return;
+ }
+
+ var players = await gameEvent.Owner.Manager.GetClientService().FindClientsByIdentifier(gameEvent.Data);
+
+ if (!players.Any())
+ {
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_FIND_EMPTY"]);
+ return;
+ }
+
+ foreach (var client in players)
+ {
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_FIND_FORMAT_V2"].FormatExt(client.Name,
+ client.ClientId, Utilities.ConvertLevelToColor((EFClient.Permission) client.LevelInt, client.Level),
+ client.IPAddress, (DateTime.UtcNow - client.LastConnection).HumanizeForCurrentCulture()));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Application/Commands/ListAdminsCommand.cs b/Application/Commands/ListAdminsCommand.cs
new file mode 100644
index 000000000..188ffb5c1
--- /dev/null
+++ b/Application/Commands/ListAdminsCommand.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Data.Models.Client;
+using SharedLibraryCore;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Application.Commands
+{
+ ///
+ /// Lists all unmasked admins
+ ///
+ public class ListAdminsCommand : Command
+ {
+ public ListAdminsCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config,
+ translationLookup)
+ {
+ Name = "admins";
+ Description = _translationLookup["COMMANDS_ADMINS_DESC"];
+ Alias = "a";
+ Permission = EFClient.Permission.User;
+ RequiresTarget = false;
+ }
+
+ public static string OnlineAdmins(Server server, ITranslationLookup lookup)
+ {
+ var onlineAdmins = server.GetClientsAsList()
+ .Where(p => p.Level > EFClient.Permission.Flagged)
+ .Where(p => !p.Masked)
+ .Select(p =>
+ $"[(Color::Yellow){Utilities.ConvertLevelToColor(p.Level, p.ClientPermission.Name)}(Color::White)] {p.Name}")
+ .ToList();
+
+ return onlineAdmins.Any() ? string.Join(Environment.NewLine, onlineAdmins) : lookup["COMMANDS_ADMINS_NONE"];
+ }
+
+ public override Task ExecuteAsync(GameEvent gameEvent)
+ {
+ foreach (var line in OnlineAdmins(gameEvent.Owner, _translationLookup).Split(Environment.NewLine))
+ {
+ var _ = gameEvent.Message.IsBroadcastCommand(_config.BroadcastCommandPrefix)
+ ? gameEvent.Owner.Broadcast(line)
+ : gameEvent.Origin.Tell(line);
+ }
+
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Application/Commands/ListAliasesCommand.cs b/Application/Commands/ListAliasesCommand.cs
new file mode 100644
index 000000000..1056ac6b1
--- /dev/null
+++ b/Application/Commands/ListAliasesCommand.cs
@@ -0,0 +1,57 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Data.Models.Client;
+using SharedLibraryCore;
+using SharedLibraryCore.Commands;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Application.Commands
+{
+ ///
+ /// Lists alises of specified client
+ ///
+ public class ListAliasesCommand : Command
+ {
+ public ListAliasesCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config,
+ translationLookup)
+ {
+ Name = "alias";
+ Description = _translationLookup["COMMANDS_ALIAS_DESC"];
+ Alias = "known";
+ Permission = EFClient.Permission.Moderator;
+ RequiresTarget = true;
+ Arguments = new[]
+ {
+ new CommandArgument()
+ {
+ Name = _translationLookup["COMMANDS_ARGS_PLAYER"],
+ Required = true,
+ }
+ };
+ }
+
+ public override Task ExecuteAsync(GameEvent gameEvent)
+ {
+ var message = new StringBuilder();
+ var names = new List(gameEvent.Target.AliasLink.Children.Select(a => a.Name));
+ var ips = new List(gameEvent.Target.AliasLink.Children.Select(a => a.IPAddress.ConvertIPtoString())
+ .Distinct());
+
+ gameEvent.Origin.Tell($"[(Color::Accent){gameEvent.Target}(Color::White)]");
+
+ message.Append($"{_translationLookup["COMMANDS_ALIAS_ALIASES"]}: ");
+ message.Append(string.Join(" | ", names));
+ gameEvent.Origin.Tell(message.ToString());
+
+ message.Clear();
+ message.Append($"{_translationLookup["COMMANDS_ALIAS_IPS"]}: ");
+ message.Append(string.Join(" | ", ips));
+ gameEvent.Origin.Tell(message.ToString());
+
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Application/Commands/ListClientsCommand.cs b/Application/Commands/ListClientsCommand.cs
new file mode 100644
index 000000000..271e05019
--- /dev/null
+++ b/Application/Commands/ListClientsCommand.cs
@@ -0,0 +1,37 @@
+using System.Linq;
+using System.Threading.Tasks;
+using Data.Models.Client;
+using SharedLibraryCore;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Application.Commands
+{
+ ///
+ /// List online clients
+ ///
+ public class ListClientsCommand : Command
+ {
+ public ListClientsCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config,
+ translationLookup)
+ {
+ Name = "list";
+ Description = _translationLookup["COMMANDS_LIST_DESC"];
+ Alias = "l";
+ Permission = EFClient.Permission.Moderator;
+ RequiresTarget = false;
+ }
+
+ public override Task ExecuteAsync(GameEvent gameEvent)
+ {
+ var clientList = gameEvent.Owner.GetClientsAsList()
+ .Select(client =>
+ $"[(Color::Accent){client.ClientPermission.Name}(Color::White){(string.IsNullOrEmpty(client.Tag) ? "" : $" {client.Tag}")}(Color::White)][(Color::Yellow)#{client.ClientNumber}(Color::White)] {client.Name}")
+ .ToArray();
+
+ gameEvent.Origin.Tell(clientList);
+
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Application/Commands/ListPluginsCommand.cs b/Application/Commands/ListPluginsCommand.cs
new file mode 100644
index 000000000..4cc0566b4
--- /dev/null
+++ b/Application/Commands/ListPluginsCommand.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Data.Models.Client;
+using SharedLibraryCore;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Application.Commands
+{
+ ///
+ /// Lists the loaded plugins
+ ///
+ public class ListPluginsCommand : Command
+ {
+ private readonly IEnumerable _plugins;
+
+ public ListPluginsCommand(CommandConfiguration config, ITranslationLookup translationLookup,
+ IEnumerable plugins) : base(config, translationLookup)
+ {
+ Name = "plugins";
+ Description = _translationLookup["COMMANDS_PLUGINS_DESC"];
+ Alias = "p";
+ Permission = EFClient.Permission.Administrator;
+ RequiresTarget = false;
+ _plugins = plugins;
+ }
+
+ public override Task ExecuteAsync(GameEvent gameEvent)
+ {
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_PLUGINS_LOADED"]);
+ foreach (var plugin in _plugins.Where(plugin => !plugin.IsParser))
+ {
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_LIST_PLUGINS_FORMAT"]
+ .FormatExt(plugin.Name, plugin.Version, plugin.Author));
+ }
+
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Application/Commands/ListReportsCommand.cs b/Application/Commands/ListReportsCommand.cs
new file mode 100644
index 000000000..3c0f68563
--- /dev/null
+++ b/Application/Commands/ListReportsCommand.cs
@@ -0,0 +1,59 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Data.Models.Client;
+using SharedLibraryCore;
+using SharedLibraryCore.Commands;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Helpers;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Application.Commands
+{
+ ///
+ /// List all reports on the server
+ ///
+ public class ListReportsCommand : Command
+ {
+ public ListReportsCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config,
+ translationLookup)
+ {
+ Name = "reports";
+ Description = _translationLookup["COMMANDS_REPORTS_DESC"];
+ Alias = "reps";
+ Permission = EFClient.Permission.Moderator;
+ RequiresTarget = false;
+ Arguments = new[]
+ {
+ new CommandArgument
+ {
+ Name = _translationLookup["COMMANDS_ARGS_CLEAR"],
+ Required = false
+ }
+ };
+ }
+
+ public override Task ExecuteAsync(GameEvent gameEvent)
+ {
+ if (gameEvent.Data != null && gameEvent.Data.ToLower().Contains(_translationLookup["COMMANDS_ARGS_CLEAR"]))
+ {
+ gameEvent.Owner.Reports = new List();
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_REPORTS_CLEAR_SUCCESS"]);
+ return Task.CompletedTask;
+ }
+
+ if (gameEvent.Owner.Reports.Count < 1)
+ {
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_REPORTS_NONE"]);
+ return Task.CompletedTask;
+ }
+
+ foreach (var report in gameEvent.Owner.Reports)
+ {
+ gameEvent.Origin.Tell(
+ $"(Color::Accent){report.Origin.Name}(Color::White) -> (Color::Red){report.Target.Name}(Color::White): {report.Reason}");
+ }
+
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Application/Commands/PrivateMessageCommand.cs b/Application/Commands/PrivateMessageCommand.cs
new file mode 100644
index 000000000..b2a8b4311
--- /dev/null
+++ b/Application/Commands/PrivateMessageCommand.cs
@@ -0,0 +1,45 @@
+using System.Threading.Tasks;
+using Data.Models.Client;
+using SharedLibraryCore;
+using SharedLibraryCore.Commands;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Application.Commands
+{
+ ///
+ /// Sends a private message to another player
+ ///
+ public class PrivateMessageCommand : Command
+ {
+ public PrivateMessageCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
+ {
+ Name = "privatemessage";
+ Description = _translationLookup["COMMANDS_PM_DESC"];
+ Alias = "pm";
+ Permission = EFClient.Permission.User;
+ RequiresTarget = true;
+ Arguments = new[]
+ {
+ new CommandArgument
+ {
+ Name = _translationLookup["COMMANDS_ARGS_PLAYER"],
+ Required = true
+ },
+ new CommandArgument
+ {
+ Name = _translationLookup["COMMANDS_ARGS_MESSAGE"],
+ Required = true
+ }
+ };
+ }
+
+ public override Task ExecuteAsync(GameEvent gameEvent)
+ {
+ gameEvent.Target.Tell(_translationLookup["COMMANDS_PRIVATE_MESSAGE_FORMAT"].FormatExt(gameEvent.Origin.Name, gameEvent.Data));
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_PRIVATE_MESSAGE_RESULT"]
+ .FormatExt(gameEvent.Target.Name, gameEvent.Data));
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Application/Commands/ReportClientCommand.cs b/Application/Commands/ReportClientCommand.cs
new file mode 100644
index 000000000..cb20288fc
--- /dev/null
+++ b/Application/Commands/ReportClientCommand.cs
@@ -0,0 +1,77 @@
+using System.Threading.Tasks;
+using Data.Models.Client;
+using SharedLibraryCore;
+using SharedLibraryCore.Commands;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Application.Commands
+{
+ ///
+ /// Report client for given reason
+ ///
+ public class ReportClientCommand : Command
+ {
+ public ReportClientCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config,
+ translationLookup)
+ {
+ Name = "report";
+ Description = _translationLookup["COMMANDS_REPORT_DESC"];
+ Alias = "rep";
+ Permission = EFClient.Permission.User;
+ RequiresTarget = true;
+ Arguments = new[]
+ {
+ new CommandArgument
+ {
+ Name = _translationLookup["COMMANDS_ARGS_PLAYER"],
+ Required = true
+ },
+ new CommandArgument
+ {
+ Name = _translationLookup["COMMANDS_ARGS_REASON"],
+ Required = true
+ }
+ };
+ }
+
+ public override async Task ExecuteAsync(GameEvent commandEvent)
+ {
+ if (commandEvent.Data.ToLower().Contains("camp"))
+ {
+ commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_FAIL_CAMP"]);
+ return;
+ }
+
+ var success = false;
+
+ switch ((await commandEvent.Target.Report(commandEvent.Data, commandEvent.Origin)
+ .WaitAsync(Utilities.DefaultCommandTimeout, commandEvent.Owner.Manager.CancellationToken)).FailReason)
+ {
+ case GameEvent.EventFailReason.None:
+ commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_SUCCESS"]);
+ success = true;
+ break;
+ case GameEvent.EventFailReason.Exception:
+ commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_FAIL_DUPLICATE"]);
+ break;
+ case GameEvent.EventFailReason.Permission:
+ commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_FAIL"]
+ .FormatExt(commandEvent.Target.Name));
+ break;
+ case GameEvent.EventFailReason.Invalid:
+ commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_FAIL_SELF"]);
+ break;
+ case GameEvent.EventFailReason.Throttle:
+ commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_FAIL_TOOMANY"]);
+ break;
+ }
+
+ if (success)
+ {
+ commandEvent.Owner.ToAdmins(
+ $"(Color::Accent){commandEvent.Origin.Name}(Color::White) -> (Color::Red){commandEvent.Target.Name}(Color::White): {commandEvent.Data}");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Application/Commands/SayAllCommand.cs b/Application/Commands/SayAllCommand.cs
new file mode 100644
index 000000000..c819889f2
--- /dev/null
+++ b/Application/Commands/SayAllCommand.cs
@@ -0,0 +1,46 @@
+using System.Threading.Tasks;
+using Data.Models.Client;
+using SharedLibraryCore;
+using SharedLibraryCore.Commands;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Application.Commands
+{
+ ///
+ /// Prints out a message to all clients on all servers
+ ///
+ public class SayAllCommand : Command
+ {
+ public SayAllCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config,
+ translationLookup)
+ {
+ Name = "sayall";
+ Description = _translationLookup["COMMANDS_SAY_ALL_DESC"];
+ Alias = "sa";
+ Permission = EFClient.Permission.Moderator;
+ RequiresTarget = false;
+ Arguments = new[]
+ {
+ new CommandArgument
+ {
+ Name = _translationLookup["COMMANDS_ARGS_MESSAGE"],
+ Required = true
+ }
+ };
+ }
+
+ public override Task ExecuteAsync(GameEvent gameEvent)
+ {
+ var message = $"(Color::Accent){gameEvent.Origin.Name}(Color::White) - (Color::Red){gameEvent.Data}";
+
+ foreach (var server in gameEvent.Owner.Manager.GetServers())
+ {
+ server.Broadcast(message, gameEvent.Origin);
+ }
+
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_SAY_SUCCESS"]);
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Application/Commands/SayCommand.cs b/Application/Commands/SayCommand.cs
new file mode 100644
index 000000000..a23be59cc
--- /dev/null
+++ b/Application/Commands/SayCommand.cs
@@ -0,0 +1,42 @@
+using System.Threading.Tasks;
+using SharedLibraryCore;
+using SharedLibraryCore.Commands;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Interfaces;
+using EFClient = Data.Models.Client.EFClient;
+
+namespace IW4MAdmin.Application.Commands
+{
+ ///
+ /// Prints out a message to all clients on the server
+ ///
+ public class SayCommand : Command
+ {
+ public SayCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config,
+ translationLookup)
+ {
+ Name = "say";
+ Description = _translationLookup["COMMANDS_SAY_DESC"];
+ Alias = "s";
+ Permission = EFClient.Permission.Moderator;
+ RequiresTarget = false;
+ Arguments = new[]
+ {
+ new CommandArgument
+ {
+ Name = _translationLookup["COMMANDS_ARGS_MESSAGE"],
+ Required = true
+ }
+ };
+ }
+
+ public override Task ExecuteAsync(GameEvent gameEvent)
+ {
+ gameEvent.Owner.Broadcast(
+ _translationLookup["COMMANDS_SAY_FORMAT"].FormatExt(gameEvent.Origin.Name, gameEvent.Data),
+ gameEvent.Origin);
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_SAY_SUCCESS"]);
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Application/Commands/WhoAmICommand.cs b/Application/Commands/WhoAmICommand.cs
new file mode 100644
index 000000000..472f0d312
--- /dev/null
+++ b/Application/Commands/WhoAmICommand.cs
@@ -0,0 +1,38 @@
+using System.Threading.Tasks;
+using Data.Models.Client;
+using SharedLibraryCore;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Application.Commands
+{
+ ///
+ /// Prints client information
+ ///
+ public class WhoAmICommand : Command
+ {
+ public WhoAmICommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config,
+ translationLookup)
+ {
+ Name = "whoami";
+ Description = _translationLookup["COMMANDS_WHO_DESC"];
+ Alias = "who";
+ Permission = EFClient.Permission.User;
+ RequiresTarget = false;
+ }
+
+ public override Task ExecuteAsync(GameEvent gameEvent)
+ {
+ var you =
+ "[(Color::Yellow)#{{clientNumber}}(Color::White)] [(Color::Yellow)@{{clientId}}(Color::White)] [{{networkId}}] [{{ip}}] [(Color::Cyan){{level}}(Color::White){{tag}}(Color::White)] {{name}}"
+ .FormatExt(gameEvent.Origin.ClientNumber,
+ gameEvent.Origin.ClientId, gameEvent.Origin.GuidString,
+ gameEvent.Origin.IPAddressString, gameEvent.Origin.ClientPermission.Name,
+ string.IsNullOrEmpty(gameEvent.Origin.Tag) ? "" : $" {gameEvent.Origin.Tag}",
+ gameEvent.Origin.Name);
+ gameEvent.Origin.Tell(you);
+
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Application/DefaultSettings.json b/Application/DefaultSettings.json
index 77077203a..54673aef4 100644
--- a/Application/DefaultSettings.json
+++ b/Application/DefaultSettings.json
@@ -1,11 +1,11 @@
{
"AutoMessagePeriod": 60,
"AutoMessages": [
- "This server uses ^5IW4M Admin v{{VERSION}} ^7get it at ^5raidmax.org/IW4MAdmin",
- "^5IW4M Admin ^7sees ^5YOU!",
+ "This server uses (Color::Accent)IW4M Admin v{{VERSION}} (Color::White)get it at (Color::Accent)raidmax.org/IW4MAdmin",
+ "(Color::Accent)IW4M Admin (Color::White)sees (Color::Accent)YOU!",
"{{TOPSTATS}}",
- "This server has seen a total of ^5{{TOTALPLAYERS}} ^7players!",
- "Cheaters are ^1unwelcome ^7 on this server",
+ "This server has seen a total of (Color::Accent){{TOTALPLAYERS}} (Color::White)players!",
+ "Cheaters are (Color::Red)unwelcome (Color::White)on this server",
"Did you know 8/10 people agree with unverified statistics?"
],
"GlobalRules": [
diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs
index 412c8da81..0ba4a3251 100644
--- a/Application/IW4MServer.cs
+++ b/Application/IW4MServer.cs
@@ -23,7 +23,9 @@ using Serilog.Context;
using static SharedLibraryCore.Database.Models.EFClient;
using Data.Models;
using Data.Models.Server;
+using IW4MAdmin.Application.Commands;
using Microsoft.EntityFrameworkCore;
+using SharedLibraryCore.Formatting;
using static Data.Models.Client.EFClient;
namespace IW4MAdmin
@@ -433,7 +435,7 @@ namespace IW4MAdmin
if (E.Origin.Level > Permission.Moderator)
{
- E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count));
+ E.Origin.Tell(loc["SERVER_REPORT_COUNT_V2"].FormatExt(E.Owner.Reports.Count));
}
}
@@ -1109,6 +1111,15 @@ namespace IW4MAdmin
Version = RconParser.Version;
}
+ if (!RconParser.Configuration.ColorCodeMapping.ContainsKey(ColorCodes.Accent.ToString()))
+ {
+ var accentKey = Manager.GetApplicationSettings().Configuration().IngameAccentColorKey;
+ RconParser.Configuration.ColorCodeMapping.Add(ColorCodes.Accent.ToString(),
+ RconParser.Configuration.ColorCodeMapping.TryGetValue(accentKey, out var colorCode)
+ ? colorCode
+ : "");
+ }
+
var svRunning = await this.GetMappedDvarValueOrDefaultAsync("sv_running");
if (!string.IsNullOrEmpty(svRunning.Value) && svRunning.Value != "1")
@@ -1344,7 +1355,7 @@ namespace IW4MAdmin
return;
}
- var message = loc["COMMANDS_WARNING_FORMAT"]
+ var message = loc["COMMANDS_WARNING_FORMAT_V2"]
.FormatExt(activeClient.Warnings, activeClient.Name, reason);
activeClient.CurrentServer.Broadcast(message);
}
@@ -1472,7 +1483,7 @@ namespace IW4MAdmin
Manager.GetMessageTokens().Add(new MessageToken("TOTALPLAYERS", (Server s) => Task.Run(async () => (await Manager.GetClientService().GetTotalClientsAsync()).ToString())));
Manager.GetMessageTokens().Add(new MessageToken("VERSION", (Server s) => Task.FromResult(Application.Program.Version.ToString())));
Manager.GetMessageTokens().Add(new MessageToken("NEXTMAP", (Server s) => SharedLibraryCore.Commands.NextMapCommand.GetNextMap(s, _translationLookup)));
- Manager.GetMessageTokens().Add(new MessageToken("ADMINS", (Server s) => Task.FromResult(SharedLibraryCore.Commands.ListAdminsCommand.OnlineAdmins(s, _translationLookup))));
+ Manager.GetMessageTokens().Add(new MessageToken("ADMINS", (Server s) => Task.FromResult(ListAdminsCommand.OnlineAdmins(s, _translationLookup))));
}
}
}
diff --git a/Application/RConParsers/DynamicRConParserConfiguration.cs b/Application/RConParsers/DynamicRConParserConfiguration.cs
index 87fb54d6d..96355612c 100644
--- a/Application/RConParsers/DynamicRConParserConfiguration.cs
+++ b/Application/RConParsers/DynamicRConParserConfiguration.cs
@@ -3,6 +3,7 @@ using SharedLibraryCore.Interfaces;
using SharedLibraryCore.RCon;
using System.Collections.Generic;
using System.Globalization;
+using SharedLibraryCore.Formatting;
namespace IW4MAdmin.Application.RConParsers
{
@@ -31,6 +32,22 @@ namespace IW4MAdmin.Application.RConParsers
public int? DefaultRConPort { get; set; }
public string DefaultInstallationDirectoryHint { get; set; }
+ public ColorCodeMapping ColorCodeMapping { get; set; } = new ColorCodeMapping
+ {
+ // this is the default mapping (IW4), but can be overridden as needed in the parsers
+ {ColorCodes.Black.ToString(), "^0"},
+ {ColorCodes.Red.ToString(), "^1"},
+ {ColorCodes.Green.ToString(), "^2"},
+ {ColorCodes.Yellow.ToString(), "^3"},
+ {ColorCodes.Blue.ToString(), "^4"},
+ {ColorCodes.Cyan.ToString(), "^5"},
+ {ColorCodes.Pink.ToString(), "^6"},
+ {ColorCodes.White.ToString(), "^7"},
+ {ColorCodes.Map.ToString(), "^8"},
+ {ColorCodes.Grey.ToString(), "^9"},
+ {ColorCodes.Wildcard.ToString(), ":^"},
+ };
+
public DynamicRConParserConfiguration(IParserRegexFactory parserRegexFactory)
{
Status = parserRegexFactory.CreateParserRegex();
@@ -42,4 +59,4 @@ namespace IW4MAdmin.Application.RConParsers
MaxPlayersStatus = parserRegexFactory.CreateParserRegex();
}
}
-}
+}
\ No newline at end of file
diff --git a/Plugins/ScriptPlugins/ParserPT6.js b/Plugins/ScriptPlugins/ParserPT6.js
index 43d7ce4a6..01e839d71 100644
--- a/Plugins/ScriptPlugins/ParserPT6.js
+++ b/Plugins/ScriptPlugins/ParserPT6.js
@@ -3,7 +3,7 @@ var eventParser;
var plugin = {
author: 'RaidMax, Xerxes',
- version: 1.1,
+ version: 1.2,
name: 'Plutonium T6 Parser',
isParser: true,
@@ -38,6 +38,21 @@ var plugin = {
rconParser.Configuration.Status.AddMapping(103, 4);
rconParser.Configuration.Status.AddMapping(104, 5);
rconParser.Configuration.Status.AddMapping(105, 6);
+
+ // this is mostly default but just an example on how to map
+ rconParser.Configuration.ColorCodeMapping.Clear();
+ rconParser.Configuration.ColorCodeMapping.Add('Black', '^0');
+ rconParser.Configuration.ColorCodeMapping.Add('Red', '^1');
+ rconParser.Configuration.ColorCodeMapping.Add('Green', '^2');
+ rconParser.Configuration.ColorCodeMapping.Add('Yellow', '^3');
+ rconParser.Configuration.ColorCodeMapping.Add('Blue', '^4');
+ rconParser.Configuration.ColorCodeMapping.Add('Cyan', '^5');
+ rconParser.Configuration.ColorCodeMapping.Add('Pink', '^6');
+ rconParser.Configuration.ColorCodeMapping.Add('White', '^7');
+ rconParser.Configuration.ColorCodeMapping.Add('Map', '^8');
+ rconParser.Configuration.ColorCodeMapping.Add('Grey', '^9');
+ rconParser.Configuration.ColorCodeMapping.Add('LightBlue', '^;');
+ rconParser.Configuration.ColorCodeMapping.Add('LightYellow', '^:');
eventParser.Configuration.GameDirectory = '';
eventParser.Configuration.GuidNumberStyle = 7; // Integer
diff --git a/Plugins/Stats/Client/ServerDistributionCalculator.cs b/Plugins/Stats/Client/ServerDistributionCalculator.cs
index f772b29f3..02ed57fd3 100644
--- a/Plugins/Stats/Client/ServerDistributionCalculator.cs
+++ b/Plugins/Stats/Client/ServerDistributionCalculator.cs
@@ -11,6 +11,7 @@ using Microsoft.EntityFrameworkCore;
using SharedLibraryCore;
using SharedLibraryCore.Interfaces;
using Stats.Client.Abstractions;
+using Stats.Config;
using Stats.Helpers;
namespace Stats.Client
diff --git a/Plugins/Stats/Commands/MostKillsCommand.cs b/Plugins/Stats/Commands/MostKillsCommand.cs
index b6f34294d..cddf45f1f 100644
--- a/Plugins/Stats/Commands/MostKillsCommand.cs
+++ b/Plugins/Stats/Commands/MostKillsCommand.cs
@@ -9,8 +9,8 @@ using Data.Models.Client.Stats;
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Configuration;
using SharedLibraryCore.Interfaces;
-using IW4MAdmin.Plugins.Stats.Config;
using IW4MAdmin.Plugins.Stats.Helpers;
+using Stats.Config;
namespace IW4MAdmin.Plugins.Stats.Commands
{
@@ -76,7 +76,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands
var iqList = await iqStats.ToListAsync();
- return iqList.Select((stats, index) => translationLookup["PLUGINS_STATS_COMMANDS_MOSTKILLS_FORMAT"]
+ return iqList.Select((stats, index) => translationLookup["PLUGINS_STATS_COMMANDS_MOSTKILLS_FORMAT_V2"]
.FormatExt(index + 1, stats.Name, stats.Kills))
.Prepend(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_MOSTKILLS_HEADER"]);
}
diff --git a/Plugins/Stats/Commands/MostPlayedCommand.cs b/Plugins/Stats/Commands/MostPlayedCommand.cs
index 47328860f..8966d4bd4 100644
--- a/Plugins/Stats/Commands/MostPlayedCommand.cs
+++ b/Plugins/Stats/Commands/MostPlayedCommand.cs
@@ -20,9 +20,9 @@ namespace IW4MAdmin.Plugins.Stats.Commands
{
var serverId = StatManager.GetIdForServer(s);
- var mostPlayed = new List()
+ var mostPlayed = new List
{
- $"^5--{translationLookup["PLUGINS_STATS_COMMANDS_MOSTPLAYED_TEXT"]}--"
+ $"(Color::Accent)--{translationLookup["PLUGINS_STATS_COMMANDS_MOSTPLAYED_TEXT"]}--"
};
await using var context = contextFactory.CreateContext(false);
@@ -48,7 +48,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands
var iqList = await iqStats.ToListAsync();
mostPlayed.AddRange(iqList.Select((stats, index) =>
- $"#{index + 1} " + translationLookup["COMMANDS_MOST_PLAYED_FORMAT"].FormatExt(stats.Name, stats.Kills,
+ $"#{index + 1} " + translationLookup["COMMANDS_MOST_PLAYED_FORMAT_V2"].FormatExt(stats.Name, stats.Kills,
(DateTime.UtcNow - DateTime.UtcNow.AddSeconds(-stats.TimePlayed))
.HumanizeForCurrentCulture())));
diff --git a/Plugins/Stats/Commands/TopStats.cs b/Plugins/Stats/Commands/TopStats.cs
index fd3bc9d3b..4cb4607bd 100644
--- a/Plugins/Stats/Commands/TopStats.cs
+++ b/Plugins/Stats/Commands/TopStats.cs
@@ -1,35 +1,32 @@
-using Microsoft.EntityFrameworkCore;
-using System;
-using System.Linq;
+using System.Linq;
using System.Threading.Tasks;
-
using SharedLibraryCore;
using System.Collections.Generic;
-using Data.Abstractions;
-using Data.Models.Client.Stats;
-using SharedLibraryCore.Database.Models;
using IW4MAdmin.Plugins.Stats.Helpers;
using SharedLibraryCore.Configuration;
using SharedLibraryCore.Interfaces;
+using EFClient = Data.Models.Client.EFClient;
namespace IW4MAdmin.Plugins.Stats.Commands
{
- class TopStats : Command
+ public class TopStats : Command
{
public static async Task> GetTopStats(Server s, ITranslationLookup translationLookup)
{
- long serverId = StatManager.GetIdForServer(s);
+ var serverId = StatManager.GetIdForServer(s);
var topStatsText = new List()
{
- $"^5--{translationLookup["PLUGINS_STATS_COMMANDS_TOP_TEXT"]}--"
+ $"(Color::Accent)--{translationLookup["PLUGINS_STATS_COMMANDS_TOP_TEXT"]}--"
};
var stats = await Plugin.Manager.GetTopStats(0, 5, serverId);
- var statsList = stats.Select((stats, index) => $"#{index + 1} ^3{stats.Name}^7 - ^5{stats.KDR} ^7{translationLookup["PLUGINS_STATS_TEXT_KDR"]} | ^5{stats.Performance} ^7{translationLookup["PLUGINS_STATS_COMMANDS_PERFORMANCE"]}");
+ var statsList = stats.Select((stats, index) =>
+ translationLookup["COMMANDS_TOPSTATS_RESULT"]
+ .FormatExt(index + 1, stats.Name, stats.KDR, stats.Performance));
topStatsText.AddRange(statsList);
- // no one qualified
+ // no one qualified
if (topStatsText.Count == 1)
{
topStatsText = new List()
@@ -41,11 +38,10 @@ namespace IW4MAdmin.Plugins.Stats.Commands
return topStatsText;
}
- private readonly CommandConfiguration _config;
- private readonly IDatabaseContextFactory _contextFactory;
+ private new readonly CommandConfiguration _config;
- public TopStats(CommandConfiguration config, ITranslationLookup translationLookup,
- IDatabaseContextFactory contextFactory) : base(config, translationLookup)
+ public TopStats(CommandConfiguration config, ITranslationLookup translationLookup) : base(config,
+ translationLookup)
{
Name = "topstats";
Description = translationLookup["PLUGINS_STATS_COMMANDS_TOP_DESC"];
@@ -54,7 +50,6 @@ namespace IW4MAdmin.Plugins.Stats.Commands
RequiresTarget = false;
_config = config;
- _contextFactory = contextFactory;
}
public override async Task ExecuteAsync(GameEvent E)
@@ -76,4 +71,4 @@ namespace IW4MAdmin.Plugins.Stats.Commands
}
}
}
-}
+}
\ No newline at end of file
diff --git a/Plugins/Stats/Commands/ViewStats.cs b/Plugins/Stats/Commands/ViewStats.cs
index 5ef774de7..32ea905a4 100644
--- a/Plugins/Stats/Commands/ViewStats.cs
+++ b/Plugins/Stats/Commands/ViewStats.cs
@@ -24,9 +24,9 @@ namespace IW4MAdmin.Plugins.Stats.Commands
Alias = "xlrstats";
Permission = EFClient.Permission.User;
RequiresTarget = false;
- Arguments = new CommandArgument[]
+ Arguments = new []
{
- new CommandArgument()
+ new CommandArgument
{
Name = "player",
Required = false
@@ -73,14 +73,15 @@ namespace IW4MAdmin.Plugins.Stats.Commands
if (pStats == null)
{
await using var context = _contextFactory.CreateContext(false);
- pStats = (await context.Set()
- .FirstOrDefaultAsync(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId));
+ pStats = await context.Set()
+ .FirstOrDefaultAsync(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId);
}
// if it's still null then they've not gotten a kill or death yet
statLine = pStats == null
? _translationLookup["PLUGINS_STATS_COMMANDS_NOTAVAILABLE"]
- : $"^5{pStats.Kills} ^7{_translationLookup["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{_translationLookup["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{_translationLookup["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}";
+ : _translationLookup["COMMANDS_VIEW_STATS_RESULT"].FormatExt(pStats.Kills, pStats.Deaths,
+ pStats.KDR, pStats.Performance, performanceRankingString);
}
// getting self stats
@@ -108,7 +109,8 @@ namespace IW4MAdmin.Plugins.Stats.Commands
// if it's still null then they've not gotten a kill or death yet
statLine = pStats == null
? _translationLookup["PLUGINS_STATS_COMMANDS_NOTAVAILABLE"]
- : $"^5{pStats.Kills} ^7{_translationLookup["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{_translationLookup["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{_translationLookup["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}";
+ : _translationLookup["COMMANDS_VIEW_STATS_RESULT"].FormatExt(pStats.Kills, pStats.Deaths,
+ pStats.KDR, pStats.Performance, performanceRankingString);
}
if (E.Message.IsBroadcastCommand(_config.BroadcastCommandPrefix))
diff --git a/Plugins/Stats/Config/StatsConfiguration.cs b/Plugins/Stats/Config/StatsConfiguration.cs
index b50038534..3d2f3e1a7 100644
--- a/Plugins/Stats/Config/StatsConfiguration.cs
+++ b/Plugins/Stats/Config/StatsConfiguration.cs
@@ -1,11 +1,11 @@
-using SharedLibraryCore;
-using SharedLibraryCore.Interfaces;
-using Stats.Config;
-using System;
+using System;
using System.Collections.Generic;
+using IW4MAdmin.Plugins.Stats.Config;
+using SharedLibraryCore;
+using SharedLibraryCore.Interfaces;
using static IW4MAdmin.Plugins.Stats.Cheat.Detection;
-namespace IW4MAdmin.Plugins.Stats.Config
+namespace Stats.Config
{
public class StatsConfiguration : IBaseConfiguration
{
@@ -74,28 +74,28 @@ namespace IW4MAdmin.Plugins.Stats.Config
public IBaseConfiguration Generate()
{
AnticheatConfiguration.Enable =
- Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_SETUP_ENABLEAC"]);
- KillstreakMessages = new List()
+ Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_SETUP_ENABLEAC"].PromptBool();
+ KillstreakMessages = new List
{
- new StreakMessageConfiguration()
+ new StreakMessageConfiguration
{
Count = -1,
- Message = "Try not to kill yourself anymore"
+ Message = Utilities.CurrentLocalization.LocalizationIndex["STATS_STREAK_MESSAGE_SUICIDE"]
},
- new StreakMessageConfiguration()
+ new StreakMessageConfiguration
{
Count = 5,
- Message = "Great job! You're on a ^55 killstreak!"
+ Message = Utilities.CurrentLocalization.LocalizationIndex["STATS_STREAK_MESSAGE_5"]
},
- new StreakMessageConfiguration()
+ new StreakMessageConfiguration
{
Count = 10,
- Message = "Amazing! ^510 kills ^7without dying!"
+ Message = Utilities.CurrentLocalization.LocalizationIndex["STATS_STREAK_MESSAGE_10"]
},
- new StreakMessageConfiguration()
+ new StreakMessageConfiguration
{
Count = 25,
- Message = "You better call in that nuke, ^525 killstreak^7!"
+ Message = Utilities.CurrentLocalization.LocalizationIndex["STATS_STREAK_MESSAGE_25"]
}
};
@@ -104,12 +104,12 @@ namespace IW4MAdmin.Plugins.Stats.Config
new StreakMessageConfiguration()
{
Count = 5,
- Message = "Pick it up soldier, you've died ^55 times ^7in a row..."
+ Message = Utilities.CurrentLocalization.LocalizationIndex["STATS_DEATH_STREAK_MESSAGE_5"]
},
new StreakMessageConfiguration()
{
Count = 10,
- Message = "Seriously? ^510 deaths ^7without getting a kill?"
+ Message = Utilities.CurrentLocalization.LocalizationIndex["STATS_DEATH_STREAK_MESSAGE_10"]
},
};
diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs
index 4e0d63ee6..01026c57e 100644
--- a/Plugins/Stats/Helpers/StatManager.cs
+++ b/Plugins/Stats/Helpers/StatManager.cs
@@ -21,6 +21,7 @@ using Data.Models.Server;
using Humanizer.Localisation;
using Microsoft.Extensions.Logging;
using Stats.Client.Abstractions;
+using Stats.Config;
using Stats.Helpers;
using static IW4MAdmin.Plugins.Stats.Cheat.Detection;
using EFClient = SharedLibraryCore.Database.Models.EFClient;
diff --git a/Plugins/Stats/Plugin.cs b/Plugins/Stats/Plugin.cs
index 3959be7e4..7f4147271 100644
--- a/Plugins/Stats/Plugin.cs
+++ b/Plugins/Stats/Plugin.cs
@@ -20,6 +20,7 @@ using Microsoft.Extensions.Logging;
using SharedLibraryCore.Commands;
using IW4MAdmin.Plugins.Stats.Client.Abstractions;
using Stats.Client.Abstractions;
+using Stats.Config;
using EFClient = SharedLibraryCore.Database.Models.EFClient;
namespace IW4MAdmin.Plugins.Stats
@@ -88,7 +89,7 @@ namespace IW4MAdmin.Plugins.Stats
break;
case GameEvent.EventType.Command:
var shouldPersist = !string.IsNullOrEmpty(E.Data) &&
- E.Extra is SayCommand;
+ E.Extra?.GetType().Name == "SayCommand";
if (shouldPersist)
{
await Manager.AddMessageAsync(E.Origin.ClientId, StatManager.GetIdForServer(S), false, E.Data);
diff --git a/Plugins/Welcome/Plugin.cs b/Plugins/Welcome/Plugin.cs
index ab1e7e34b..7015c031f 100644
--- a/Plugins/Welcome/Plugin.cs
+++ b/Plugins/Welcome/Plugin.cs
@@ -45,16 +45,16 @@ namespace IW4MAdmin.Plugins.Welcome
public Task OnTickAsync(Server S) => Task.CompletedTask;
- public async Task OnEventAsync(GameEvent E, Server S)
+ public async Task OnEventAsync(GameEvent gameEvent, Server server)
{
- if (E.Type == GameEvent.EventType.Join)
+ if (gameEvent.Type == GameEvent.EventType.Join)
{
- var newPlayer = E.Origin;
- if ((newPlayer.Level >= Permission.Trusted && !E.Origin.Masked) ||
- (!string.IsNullOrEmpty(newPlayer.GetAdditionalProperty("ClientTag")) &&
+ var newPlayer = gameEvent.Origin;
+ if (newPlayer.Level >= Permission.Trusted && !gameEvent.Origin.Masked||
+ !string.IsNullOrEmpty(newPlayer.GetAdditionalProperty("ClientTag")) &&
newPlayer.Level != Permission.Flagged && newPlayer.Level != Permission.Banned &&
- !newPlayer.Masked))
- E.Owner.Broadcast(
+ !newPlayer.Masked)
+ gameEvent.Owner.Broadcast(
await ProcessAnnouncement(_configHandler.Configuration().PrivilegedAnnouncementMessage,
newPlayer));
@@ -73,10 +73,11 @@ namespace IW4MAdmin.Plugins.Welcome
.FirstOrDefaultAsync();
}
- E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7({penaltyReason}) has joined!");
+ gameEvent.Owner.ToAdmins(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_FLAG_MESSAGE"]
+ .FormatExt(newPlayer.Name, penaltyReason));
}
else
- E.Owner.Broadcast(await ProcessAnnouncement(_configHandler.Configuration().UserAnnouncementMessage,
+ gameEvent.Owner.Broadcast(await ProcessAnnouncement(_configHandler.Configuration().UserAnnouncementMessage,
newPlayer));
}
}
@@ -85,7 +86,7 @@ namespace IW4MAdmin.Plugins.Welcome
{
msg = msg.Replace("{{ClientName}}", joining.Name);
msg = msg.Replace("{{ClientLevel}}",
- $"{Utilities.ConvertLevelToColor(joining.Level, joining.ClientPermission.Name)}{(string.IsNullOrEmpty(joining.GetAdditionalProperty("ClientTag")) ? "" : $" ^7({joining.GetAdditionalProperty("ClientTag")}^7)")}");
+ $"{Utilities.ConvertLevelToColor(joining.Level, joining.ClientPermission.Name)}{(string.IsNullOrEmpty(joining.GetAdditionalProperty("ClientTag")) ? "" : $" (Color::White)({joining.GetAdditionalProperty("ClientTag")}(Color::White))")}");
// this prevents it from trying to evaluate it every message
if (msg.Contains("{{ClientLocation}}"))
{
diff --git a/Plugins/Welcome/WelcomeConfiguration.cs b/Plugins/Welcome/WelcomeConfiguration.cs
index 177538d55..f12050da3 100644
--- a/Plugins/Welcome/WelcomeConfiguration.cs
+++ b/Plugins/Welcome/WelcomeConfiguration.cs
@@ -11,9 +11,9 @@ namespace IW4MAdmin.Plugins.Welcome
public IBaseConfiguration Generate()
{
- UserAnnouncementMessage = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_USERANNOUNCE"];
- UserWelcomeMessage = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_USERWELCOME"];
- PrivilegedAnnouncementMessage = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_PRIVANNOUNCE"];
+ UserAnnouncementMessage = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_USERANNOUNCE_V2"];
+ UserWelcomeMessage = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_USERWELCOME_V2"];
+ PrivilegedAnnouncementMessage = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_PRIVANNOUNCE_V2"];
return this;
}
diff --git a/SharedLibraryCore/Commands/CommandProcessing.cs b/SharedLibraryCore/Commands/CommandProcessing.cs
index a85ad282b..8678220b1 100644
--- a/SharedLibraryCore/Commands/CommandProcessing.cs
+++ b/SharedLibraryCore/Commands/CommandProcessing.cs
@@ -136,7 +136,7 @@ namespace SharedLibraryCore.Commands
E.Origin.Tell(loc["COMMAND_TARGET_MULTI"]);
foreach (var p in matchingPlayers)
{
- E.Origin.Tell($"[^3{p.ClientNumber}^7] {p.Name}");
+ E.Origin.Tell($"[(Color::Yellow){p.ClientNumber}(Color::White)] {p.Name}");
}
throw new CommandException($"{E.Origin} had multiple players found for {C.Name}");
}
diff --git a/SharedLibraryCore/Commands/NativeCommands.cs b/SharedLibraryCore/Commands/NativeCommands.cs
index 6a4a76189..7f17fc500 100644
--- a/SharedLibraryCore/Commands/NativeCommands.cs
+++ b/SharedLibraryCore/Commands/NativeCommands.cs
@@ -219,72 +219,6 @@ namespace SharedLibraryCore.Commands
}
}
- ///
- /// Prints out a message to all clients on the server
- ///
- public class SayCommand : Command
- {
- public SayCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
- {
- Name = "say";
- Description = _translationLookup["COMMANDS_SAY_DESC"];
- Alias = "s";
- Permission = Permission.Moderator;
- RequiresTarget = false;
- Arguments = new[]
- {
- new CommandArgument()
- {
- Name = _translationLookup["COMMANDS_ARGS_MESSAGE"],
- Required = true
- }
- };
- }
-
- public override Task ExecuteAsync(GameEvent E)
- {
- E.Owner.Broadcast($"{(E.Owner.GameName == Server.Game.IW4 ? "^:" : "")}{E.Origin.Name} - ^6{E.Data}^7", E.Origin);
- E.Origin.Tell(_translationLookup["COMMANDS_SAY_SUCCESS"]);
- return Task.CompletedTask;
- }
- }
-
- ///
- /// Prints out a message to all clients on all servers
- ///
- public class SayAllCommand : Command
- {
- public SayAllCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
- {
- Name = "sayall";
- Description = _translationLookup["COMMANDS_SAY_ALL_DESC"];
- Alias = "sa";
- Permission = Permission.Moderator;
- RequiresTarget = false;
- Arguments = new[]
- {
- new CommandArgument()
- {
- Name = _translationLookup["COMMANDS_ARGS_MESSAGE"],
- Required = true
- }
- };
- }
-
- public override Task ExecuteAsync(GameEvent E)
- {
- string message = _translationLookup["COMMANDS_SAY_ALL_MESSAGE_FORMAT"].FormatExt(E.Origin.Name, E.Data);
-
- foreach (var server in E.Owner.Manager.GetServers())
- {
- server.Broadcast(message, E.Origin);
- }
-
- E.Origin.Tell(_translationLookup["COMMANDS_SAY_SUCCESS"]);
- return Task.CompletedTask;
- }
- }
-
///
/// Temporarily bans a client
///
@@ -452,57 +386,6 @@ namespace SharedLibraryCore.Commands
}
}
- ///
- /// Prints client information
- ///
- public class WhoAmICommand : Command
- {
- public WhoAmICommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
- {
- Name = "whoami";
- Description = _translationLookup["COMMANDS_WHO_DESC"];
- Alias = "who";
- Permission = Permission.User;
- RequiresTarget = false;
- }
-
- public override Task ExecuteAsync(GameEvent gameEvent)
- {
- var you = _translationLookup["COMMANDS_WHOAMI_FORMAT"].FormatExt(gameEvent.Origin.ClientNumber, gameEvent.Origin.ClientId, gameEvent.Origin.GuidString,
- gameEvent.Origin.IPAddressString, gameEvent.Origin.ClientPermission.Name, string.IsNullOrEmpty(gameEvent.Origin.Tag) ? "" : $" {gameEvent.Origin.Tag}^7", gameEvent.Origin.Name);
- gameEvent.Origin.Tell(you);
-
- return Task.CompletedTask;
- }
- }
-
- ///
- /// List online clients
- ///
- public class ListClientsCommand : Command
- {
- public ListClientsCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
- {
- Name = "list";
- Description = _translationLookup["COMMANDS_LIST_DESC"];
- Alias = "l";
- Permission = Permission.Moderator;
- RequiresTarget = false;
- }
-
- public override Task ExecuteAsync(GameEvent gameEvent)
- {
- var clientList = gameEvent.Owner.GetClientsAsList()
- .Select(client => _translationLookup["COMMANDS_LIST_FORMAT"]
- .FormatExt(client.ClientPermission.Name, string.IsNullOrEmpty(client.Tag) ? "" : $" {client.Tag}^7", client.ClientNumber, client.Name))
- .ToArray();
-
- gameEvent.Origin.Tell(clientList);
-
- return Task.CompletedTask;
- }
- }
-
///
/// Fast restarts the map
///
@@ -522,7 +405,7 @@ namespace SharedLibraryCore.Commands
await E.Owner.ExecuteCommandAsync("fast_restart");
var _ = !E.Origin.Masked ?
- E.Owner.Broadcast($"^5{E.Origin.Name} ^7{_translationLookup["COMMANDS_FASTRESTART_UNMASKED"]}") :
+ E.Owner.Broadcast($"(Color::Accent){E.Origin.Name} (Color::White){_translationLookup["COMMANDS_FASTRESTART_UNMASKED"]}") :
E.Owner.Broadcast(_translationLookup["COMMANDS_FASTRESTART_MASKED"]);
}
}
@@ -544,7 +427,7 @@ namespace SharedLibraryCore.Commands
public override async Task ExecuteAsync(GameEvent E)
{
_ = !E.Origin.Masked ?
- E.Owner.Broadcast($"{_translationLookup["COMMANDS_MAPROTATE"]} [^5{E.Origin.Name}^7]", E.Origin) :
+ E.Owner.Broadcast($"{_translationLookup["COMMANDS_MAPROTATE"]} [(Color::Accent){E.Origin.Name}(Color::White)]", E.Origin) :
E.Owner.Broadcast(_translationLookup["COMMANDS_MAPROTATE"], E.Origin);
await Task.Delay(E.Owner.Manager.GetApplicationSettings().Configuration().MapChangeDelaySeconds * 1000);
@@ -618,13 +501,13 @@ namespace SharedLibraryCore.Commands
else if (gameEvent.Origin.Level < Permission.Owner && !steppedPrivileges)
{
// only the owner is allowed to set levels
- gameEvent.Origin.Tell($"{_translationLookup["COMMANDS_SETLEVEL_STEPPEDDISABLED"]} ^5{gameEvent.Target.Name}");
+ gameEvent.Origin.Tell($"{_translationLookup["COMMANDS_SETLEVEL_STEPPEDDISABLED"]} (Color::White){gameEvent.Target.Name}");
return;
}
else if (gameEvent.Target.Level == Permission.Flagged)
{
- gameEvent.Origin.Tell(_translationLookup["COMMANDS_SETLEVEL_FLAGGED"].FormatExt(gameEvent.Target.Name));
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_SETLEVEL_FLAGGED"].FormatExt(gameEvent.Target.Name + "(Color::White)"));
return;
}
@@ -633,8 +516,8 @@ namespace SharedLibraryCore.Commands
{
// can't promote a client to higher than your current perms
// or your peer
- gameEvent.Origin.Tell(string.Format(_translationLookup["COMMANDS_SETLEVEL_LEVELTOOHIGH"], gameEvent.Target.Name, (gameEvent.Origin.Level - 1).ToLocalizedLevelName()));
- return;
+ gameEvent.Origin.Tell(_translationLookup["COMMANDS_SETLEVEL_LEVELTOOHIGH_V2"]
+ .FormatExt(gameEvent.Target.Name, (gameEvent.Origin.Level - 1).ToLocalizedLevelName()));
}
// valid
@@ -654,7 +537,7 @@ namespace SharedLibraryCore.Commands
if (result.FailReason == GameEvent.EventFailReason.Invalid)
{
gameEvent.Origin.Tell(_translationLookup["COMMANDS_SETLEVEL_INVALID"]
- .FormatExt(gameEvent.Target.Name, newPerm.ToString()));
+ .FormatExt(gameEvent.Target.Name + "(Color::White)", newPerm.ToString()));
return;
}
@@ -733,42 +616,6 @@ namespace SharedLibraryCore.Commands
}
}
- ///
- /// Lists all unmasked admins
- ///
- public class ListAdminsCommand : Command
- {
- public ListAdminsCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
- {
- Name = "admins";
- Description = _translationLookup["COMMANDS_ADMINS_DESC"];
- Alias = "a";
- Permission = Permission.User;
- RequiresTarget = false;
- }
-
- public static string OnlineAdmins(Server S, ITranslationLookup lookup)
- {
- var onlineAdmins = S.GetClientsAsList()
- .Where(p => p.Level > Permission.Flagged)
- .Where(p => !p.Masked)
- .Select(p => $"[^3{Utilities.ConvertLevelToColor(p.Level, p.ClientPermission.Name)}^7] {p.Name}");
-
- return onlineAdmins.Count() > 0 ?
- string.Join(Environment.NewLine, onlineAdmins) :
- lookup["COMMANDS_ADMINS_NONE"];
- }
-
- public override Task ExecuteAsync(GameEvent E)
- {
- foreach (string line in OnlineAdmins(E.Owner, _translationLookup).Split(Environment.NewLine))
- {
- var _ = E.Message.IsBroadcastCommand(_config.BroadcastCommandPrefix) ? E.Owner.Broadcast(line) : E.Origin.Tell(line);
- }
-
- return Task.CompletedTask;
- }
- }
///
/// Attempts to load the specified map
@@ -809,50 +656,6 @@ namespace SharedLibraryCore.Commands
}
}
- ///
- /// Finds player by name
- ///
- public class FindPlayerCommand : Command
- {
- public FindPlayerCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
- {
- Name = "find";
- Description = _translationLookup["COMMANDS_FIND_DESC"];
- Alias = "f";
- Permission = Permission.Administrator;
- RequiresTarget = false;
- Arguments = new[]
- {
- new CommandArgument()
- {
- Name = _translationLookup["COMMANDS_ARGS_PLAYER"],
- Required = true
- }
- };
- }
-
- public override async Task ExecuteAsync(GameEvent E)
- {
- if (E.Data.Length < 3)
- {
- E.Origin.Tell(_translationLookup["COMMANDS_FIND_MIN"]);
- return;
- }
-
- var db_players = (await (E.Owner.Manager.GetClientService() as ClientService).FindClientsByIdentifier(E.Data));
-
- if (db_players.Count == 0)
- {
- E.Origin.Tell(_translationLookup["COMMANDS_FIND_EMPTY"]);
- return;
- }
-
- foreach (var client in db_players)
- {
- E.Origin.Tell(_translationLookup["COMMANDS_FIND_FORMAT"].FormatExt(client.Name, client.ClientId, Utilities.ConvertLevelToColor((Permission)client.LevelInt, client.Level), client.IPAddress, client.LastConnectionText));
- }
- }
- }
///
/// Lists server and global rules
@@ -902,40 +705,7 @@ namespace SharedLibraryCore.Commands
}
}
- ///
- /// Sends a private message to another player
- ///
- public class PrivateMessageCommand : Command
- {
- public PrivateMessageCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
- {
- Name = "privatemessage";
- Description = _translationLookup["COMMANDS_PM_DESC"];
- Alias = "pm";
- Permission = Permission.User;
- RequiresTarget = true;
- Arguments = new[]
- {
- new CommandArgument()
- {
- Name = _translationLookup["COMMANDS_ARGS_PLAYER"],
- Required = true
- },
- new CommandArgument()
- {
- Name = _translationLookup["COMMANDS_ARGS_MESSAGE"],
- Required = true
- }
- };
- }
-
- public override Task ExecuteAsync(GameEvent E)
- {
- E.Target.Tell($"^1{E.Origin.Name} ^3[PM]^7 - {E.Data}");
- E.Origin.Tell($"To ^3{E.Target.Name} ^7-> {E.Data}");
- return Task.CompletedTask;
- }
- }
+
///
/// Flag given client for specified reason
@@ -1031,116 +801,6 @@ namespace SharedLibraryCore.Commands
}
}
- ///
- /// Report client for given reason
- ///
- public class ReportClientCommand : Command
- {
- public ReportClientCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
- {
- Name = "report";
- Description = _translationLookup["COMMANDS_REPORT_DESC"];
- Alias = "rep";
- Permission = Permission.User;
- RequiresTarget = true;
- Arguments = new[]
- {
- new CommandArgument()
- {
- Name = _translationLookup["COMMANDS_ARGS_PLAYER"],
- Required = true
- },
- new CommandArgument()
- {
- Name = _translationLookup["COMMANDS_ARGS_REASON"],
- Required = true
- }
- };
- }
-
- public override async Task ExecuteAsync(GameEvent commandEvent)
- {
- if (commandEvent.Data.ToLower().Contains("camp"))
- {
- commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_FAIL_CAMP"]);
- return;
- }
-
- bool success = false;
-
- switch ((await commandEvent.Target.Report(commandEvent.Data, commandEvent.Origin).WaitAsync(Utilities.DefaultCommandTimeout, commandEvent.Owner.Manager.CancellationToken)).FailReason)
- {
- case GameEvent.EventFailReason.None:
- commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_SUCCESS"]);
- success = true;
- break;
- case GameEvent.EventFailReason.Exception:
- commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_FAIL_DUPLICATE"]);
- break;
- case GameEvent.EventFailReason.Permission:
- commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_FAIL"].FormatExt(commandEvent.Target.Name));
- break;
- case GameEvent.EventFailReason.Invalid:
- commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_FAIL_SELF"]);
- break;
- case GameEvent.EventFailReason.Throttle:
- commandEvent.Origin.Tell(_translationLookup["COMMANDS_REPORT_FAIL_TOOMANY"]);
- break;
- }
-
- if (success)
- {
- commandEvent.Owner.ToAdmins(String.Format("^5{0}^7->^1{1}^7: {2}", commandEvent.Origin.Name, commandEvent.Target.Name, commandEvent.Data));
- }
- }
- }
-
- ///
- /// List all reports on the server
- ///
- public class ListReportsCommand : Command
- {
- public ListReportsCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
- {
- Name = "reports";
- Description = _translationLookup["COMMANDS_REPORTS_DESC"];
- Alias = "reps";
- Permission = Permission.Moderator;
- RequiresTarget = false;
- Arguments = new[]
- {
- new CommandArgument()
- {
- Name = _translationLookup["COMMANDS_ARGS_CLEAR"],
- Required = false
- }
- };
- }
-
- public override Task ExecuteAsync(GameEvent E)
- {
- if (E.Data != null && E.Data.ToLower().Contains(_translationLookup["COMMANDS_ARGS_CLEAR"]))
- {
- E.Owner.Reports = new List();
- E.Origin.Tell(_translationLookup["COMMANDS_REPORTS_CLEAR_SUCCESS"]);
- return Task.CompletedTask;
- }
-
- if (E.Owner.Reports.Count < 1)
- {
- E.Origin.Tell(_translationLookup["COMMANDS_REPORTS_NONE"]);
- return Task.CompletedTask;
- }
-
- foreach (Report R in E.Owner.Reports)
- {
- E.Origin.Tell(String.Format("^5{0}^7->^1{1}^7: {2}", R.Origin.Name, R.Target.Name, R.Reason));
- }
-
- return Task.CompletedTask;
- }
- }
-
///
/// Masks client from announcements and online admin list
///
@@ -1218,49 +878,6 @@ namespace SharedLibraryCore.Commands
}
}
- ///
- /// Lists alises of specified client
- ///
- public class ListAliasesCommand : Command
- {
- public ListAliasesCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
- {
- Name = "alias";
- Description = _translationLookup["COMMANDS_ALIAS_DESC"];
- Alias = "known";
- Permission = EFClient.Permission.Moderator;
- RequiresTarget = true;
- Arguments = new[]
- {
- new CommandArgument()
- {
- Name = _translationLookup["COMMANDS_ARGS_PLAYER"],
- Required = true,
- }
- };
- }
-
- public override Task ExecuteAsync(GameEvent E)
- {
- StringBuilder message = new StringBuilder();
- var names = new List(E.Target.AliasLink.Children.Select(a => a.Name));
- var IPs = new List(E.Target.AliasLink.Children.Select(a => a.IPAddress.ConvertIPtoString()).Distinct());
-
- E.Origin.Tell($"[^3{E.Target}^7]");
-
- message.Append($"{_translationLookup["COMMANDS_ALIAS_ALIASES"]}: ");
- message.Append(String.Join(" | ", names));
- E.Origin.Tell(message.ToString());
-
- message.Clear();
- message.Append($"{_translationLookup["COMMANDS_ALIAS_IPS"]}: ");
- message.Append(String.Join(" | ", IPs));
- E.Origin.Tell(message.ToString());
-
- return Task.CompletedTask;
- }
- }
-
///
/// Executes RCon command
///
@@ -1298,33 +915,6 @@ namespace SharedLibraryCore.Commands
}
}
- ///
- /// Lists the loaded plugins
- ///
- /*public class ListPluginsCommand : Command
- {
- private readonly IPluginImporter _pluginImporter;
- public ListPluginsCommand(CommandConfiguration config, ITranslationLookup translationLookup, IPluginImporter pluginImporter) : base(config, translationLookup)
- {
- Name = "plugins";
- Description = _translationLookup["COMMANDS_PLUGINS_DESC"];
- Alias = "p";
- Permission = Permission.Administrator;
- RequiresTarget = false;
- _pluginImporter = pluginImporter;
- }
-
- public override Task ExecuteAsync(GameEvent E)
- {
- E.Origin.Tell(_translationLookup["COMMANDS_PLUGINS_LOADED"]);
- foreach (var P in _pluginImporter.ActivePlugins)
- {
- E.Origin.Tell(string.Format("^3{0} ^7[v^3{1}^7] by ^5{2}^7", P.Name, P.Version, P.Author));
- }
- return Task.CompletedTask;
- }
- }*/
-
///
/// Lists external IP
///
@@ -1484,11 +1074,11 @@ namespace SharedLibraryCore.Commands
if (E.Target == null)
{
- E.Origin.Tell(_translationLookup["COMMANDS_PING_SELF"].FormatExt(E.Origin.Ping));
+ E.Origin.Tell(_translationLookup["COMMANDS_PING_SELF_V2"].FormatExt(E.Origin.Ping));
}
else
{
- E.Origin.Tell(_translationLookup["COMMANDS_PING_TARGET"].FormatExt(E.Target.Name, E.Target.Ping));
+ E.Origin.Tell(_translationLookup["COMMANDS_PING_TARGET_V2"].FormatExt(E.Target.Name, E.Target.Ping));
}
return Task.CompletedTask;
diff --git a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs
index b5cad9c09..80869ef58 100644
--- a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs
+++ b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs
@@ -108,7 +108,7 @@ namespace SharedLibraryCore.Configuration
public string ConnectionString { get; set; }
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_RCON_POLLRATE")]
- public int RConPollRate { get; set; } = 5000;
+ public int RConPollRate { get; set; } = 8000;
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_MAX_TB")]
public TimeSpan MaximumTempBanTime { get; set; } = new TimeSpan(24 * 30, 0, 0);
@@ -116,6 +116,9 @@ namespace SharedLibraryCore.Configuration
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_ENABLE_COLOR_CODES")]
public bool EnableColorCodes { get; set; }
+ [ConfigurationIgnore]
+ public string IngameAccentColorKey { get; set; } = "Cyan";
+
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_AUTOMESSAGE_PERIOD")]
public int AutoMessagePeriod { get; set; }
diff --git a/SharedLibraryCore/Formatting/ColorCodes.cs b/SharedLibraryCore/Formatting/ColorCodes.cs
new file mode 100644
index 000000000..49d19cacb
--- /dev/null
+++ b/SharedLibraryCore/Formatting/ColorCodes.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+namespace SharedLibraryCore.Formatting
+{
+ public enum ColorCodes
+ {
+ Black,
+ Red,
+ Green,
+ Yellow,
+ Blue,
+ Cyan,
+ Purple,
+ Pink,
+ White,
+ Map,
+ Grey,
+ Wildcard,
+ Accent
+ }
+
+ public class ColorCodeMapping : Dictionary
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/SharedLibraryCore/Helpers/ParseEnum.cs b/SharedLibraryCore/Helpers/ParseEnum.cs
index ec17f253e..eb005c866 100644
--- a/SharedLibraryCore/Helpers/ParseEnum.cs
+++ b/SharedLibraryCore/Helpers/ParseEnum.cs
@@ -1,8 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace SharedLibraryCore.Helpers
{
diff --git a/SharedLibraryCore/Interfaces/IPlugin.cs b/SharedLibraryCore/Interfaces/IPlugin.cs
index 47b1737e5..89d6e2857 100644
--- a/SharedLibraryCore/Interfaces/IPlugin.cs
+++ b/SharedLibraryCore/Interfaces/IPlugin.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Threading.Tasks;
+using System.Threading.Tasks;
namespace SharedLibraryCore.Interfaces
{
@@ -10,9 +9,9 @@ namespace SharedLibraryCore.Interfaces
Task OnEventAsync(GameEvent E, Server S);
Task OnTickAsync(Server S);
- //for logging purposes
- String Name { get; }
+ string Name { get; }
float Version { get; }
- String Author { get; }
+ string Author { get; }
+ bool IsParser => false;
}
}
diff --git a/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs b/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs
index 6770ef824..943185676 100644
--- a/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs
+++ b/SharedLibraryCore/Interfaces/IRConParserConfiguration.cs
@@ -1,6 +1,8 @@
using SharedLibraryCore.RCon;
using System.Collections.Generic;
using System.Globalization;
+using SharedLibraryCore.Formatting;
+using SharedLibraryCore.Localization;
namespace SharedLibraryCore.Interfaces
{
@@ -97,5 +99,7 @@ namespace SharedLibraryCore.Interfaces
/// Default Indicator of where the game is installed (ex file path or registry entry)
///
string DefaultInstallationDirectoryHint { get; }
+
+ ColorCodeMapping ColorCodeMapping { get; }
}
}
diff --git a/SharedLibraryCore/PartialEntities/EFClient.cs b/SharedLibraryCore/PartialEntities/EFClient.cs
index 679f0a577..bda9d2a33 100644
--- a/SharedLibraryCore/PartialEntities/EFClient.cs
+++ b/SharedLibraryCore/PartialEntities/EFClient.cs
@@ -100,8 +100,9 @@ namespace SharedLibraryCore.Database.Models
CorrelationId = CurrentServer.Manager.ProcessingEvents.Values
.FirstOrDefault(ev => ev.Type == GameEvent.EventType.Command && (ev.Origin?.ClientId == ClientId || ev.ImpersonationOrigin?.ClientId == ClientId))?.CorrelationId ?? Guid.NewGuid()
};
-
- e.Output.Add(message.StripColors());
+
+ e.Output.Add(message.FormatMessageForEngine(CurrentServer?.RconParser.Configuration.ColorCodeMapping)
+ .StripColors());
CurrentServer?.Manager.AddEvent(e);
return e;
diff --git a/SharedLibraryCore/Server.cs b/SharedLibraryCore/Server.cs
index 75ea9c8cf..fdd7a2d6c 100644
--- a/SharedLibraryCore/Server.cs
+++ b/SharedLibraryCore/Server.cs
@@ -132,10 +132,12 @@ namespace SharedLibraryCore
/// Message to be sent to all players
public GameEvent Broadcast(string message, EFClient sender = null)
{
- string formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Say ?? "", $"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FixIW4ForwardSlash()}");
- ServerLogger.LogDebug("All->" + message.StripColors());
+ var formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Say ?? "",
+ $"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FormatMessageForEngine(RconParser.Configuration.ColorCodeMapping)}");
+ ServerLogger.LogDebug("All-> {Message}",
+ message.FormatMessageForEngine(RconParser.Configuration.ColorCodeMapping).StripColors());
- var e = new GameEvent()
+ var e = new GameEvent
{
Type = GameEvent.EventType.Broadcast,
Data = formattedMessage,
@@ -165,6 +167,8 @@ namespace SharedLibraryCore
/// EFClient to send message to
protected async Task Tell(string message, EFClient targetClient)
{
+ var engineMessage = message.FormatMessageForEngine(RconParser.Configuration.ColorCodeMapping);
+
if (!Utilities.IsDevelopment)
{
var temporalClientId = targetClient.GetAdditionalProperty("ConnectionClientId");
@@ -173,24 +177,25 @@ namespace SharedLibraryCore
var formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Tell,
clientNumber,
- $"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FixIW4ForwardSlash()}");
+ $"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{engineMessage}");
if (targetClient.ClientNumber > -1 && message.Length > 0 && targetClient.Level != EFClient.Permission.Console)
await this.ExecuteCommandAsync(formattedMessage);
}
else
{
- ServerLogger.LogDebug("Tell[{clientNumber}]->{message}", targetClient.ClientNumber, message.StripColors());
+ ServerLogger.LogDebug("Tell[{ClientNumber}]->{Message}", targetClient.ClientNumber,
+ message.FormatMessageForEngine(RconParser.Configuration.ColorCodeMapping).StripColors());
}
-
if (targetClient.Level == EFClient.Permission.Console)
{
Console.ForegroundColor = ConsoleColor.Green;
using (LogContext.PushProperty("Server", ToString()))
{
- ServerLogger.LogInformation("Command output received: {message}", message);
+ ServerLogger.LogInformation("Command output received: {Message}",
+ engineMessage.StripColors());
}
- Console.WriteLine(message.StripColors());
+ Console.WriteLine(engineMessage.StripColors());
Console.ForegroundColor = ConsoleColor.Gray;
}
}
diff --git a/SharedLibraryCore/Services/ClientService.cs b/SharedLibraryCore/Services/ClientService.cs
index e74857130..0a5cba377 100644
--- a/SharedLibraryCore/Services/ClientService.cs
+++ b/SharedLibraryCore/Services/ClientService.cs
@@ -716,12 +716,15 @@ namespace SharedLibraryCore.Services
// we want to project our results
var iqClientProjection = iqClients.OrderByDescending(_client => _client.LastConnection)
- .Select(_client => new PlayerInfo()
+ .Select(_client => new PlayerInfo
{
Name = _client.CurrentAlias.Name,
- LevelInt = (int)_client.Level,
+ LevelInt = (int) _client.Level,
LastConnection = _client.LastConnection,
ClientId = _client.ClientId,
+ IPAddress = _client.CurrentAlias.IPAddress.HasValue
+ ? _client.CurrentAlias.IPAddress.Value.ToString()
+ : ""
});
var clients = await iqClientProjection.ToListAsync();
diff --git a/SharedLibraryCore/TagHelpers/ColorCode.cs b/SharedLibraryCore/TagHelpers/ColorCode.cs
index cce5dfc3e..d992fea92 100644
--- a/SharedLibraryCore/TagHelpers/ColorCode.cs
+++ b/SharedLibraryCore/TagHelpers/ColorCode.cs
@@ -1,8 +1,8 @@
-using Microsoft.AspNetCore.Razor.TagHelpers;
-using System.Linq;
+using System.Linq;
using System.Text.RegularExpressions;
+using Microsoft.AspNetCore.Razor.TagHelpers;
-namespace SharedLibraryCore
+namespace SharedLibraryCore.TagHelpers
{
[HtmlTargetElement("color-code")]
public class ColorCode : TagHelper
diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs
index 1e7324376..06468ea26 100644
--- a/SharedLibraryCore/Utilities.cs
+++ b/SharedLibraryCore/Utilities.cs
@@ -21,6 +21,7 @@ using static SharedLibraryCore.Server;
using ILogger = Microsoft.Extensions.Logging.ILogger;
using static Data.Models.Client.EFClient;
using Data.Models;
+using SharedLibraryCore.Formatting;
using static Data.Models.EFPenalty;
namespace SharedLibraryCore
@@ -178,6 +179,24 @@ namespace SharedLibraryCore
///
public static string FixIW4ForwardSlash(this string str) => str.Replace("//", "/ /");
+ public static string FormatMessageForEngine(this string str, ColorCodeMapping mapping)
+ {
+ if (mapping == null || string.IsNullOrEmpty(str))
+ {
+ return str;
+ }
+
+ var output = str;
+ var colorCodeMatches = Regex.Matches(output, @"\(Color::(.{1,16})\)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
+ foreach (var match in colorCodeMatches.Where(m => m.Success))
+ {
+ var key = match.Groups[1].ToString();
+ output = output.Replace(match.Value, mapping.TryGetValue(key, out var code) ? code : "");
+ }
+
+ return output.FixIW4ForwardSlash() + mapping[ColorCodes.White.ToString()];
+ }
+
private static readonly IList _zmGameTypes = new[] { "zclassic", "zstandard", "zcleansed", "zgrief" };
///
/// indicates if the given server is running a zombie game mode
@@ -189,36 +208,25 @@ namespace SharedLibraryCore
public static bool IsCodGame(this Server server) => server.RconParser?.RConEngine == "COD";
///
- /// Get the IW Engine color code corresponding to an admin level
+ /// Get the color key corresponding to a given user level
///
/// Specified player level
+ ///
///
- public static String ConvertLevelToColor(EFClient.Permission level, string localizedLevel)
+ public static string ConvertLevelToColor(Permission level, string localizedLevel)
{
- char colorCode = '6';
- // todo: maybe make this game independant?
- switch (level)
+ // todo: make configurable
+ var colorCode = level switch
{
- case EFClient.Permission.Banned:
- colorCode = '1';
- break;
- case EFClient.Permission.Flagged:
- colorCode = '9';
- break;
- case EFClient.Permission.Owner:
- colorCode = '5';
- break;
- case EFClient.Permission.User:
- colorCode = '2';
- break;
- case EFClient.Permission.Trusted:
- colorCode = '3';
- break;
- default:
- break;
- }
+ Permission.Banned => "Red",
+ Permission.Flagged => "Map",
+ Permission.Owner => "Accent",
+ Permission.User => "Yellow",
+ Permission.Trusted => "Green",
+ _ => "Pink"
+ };
- return $"^{colorCode}{localizedLevel ?? level.ToString()}";
+ return $"(Color::{colorCode}){localizedLevel ?? level.ToString()}";
}
public static string ToLocalizedLevelName(this Permission permission)
diff --git a/WebfrontCore/Controllers/ActionController.cs b/WebfrontCore/Controllers/ActionController.cs
index 32e83c365..8eb7fa755 100644
--- a/WebfrontCore/Controllers/ActionController.cs
+++ b/WebfrontCore/Controllers/ActionController.cs
@@ -46,7 +46,8 @@ namespace WebfrontCore.Controllers
case nameof(UnbanCommand):
_unbanCommandName = cmd.Name;
break;
- case nameof(SayCommand):
+ // todo: this should be flag driven
+ case "SayCommand":
_sayCommandName = cmd.Name;
break;
case nameof(KickCommand):
diff --git a/WebfrontCore/Controllers/Client/ClientController.cs b/WebfrontCore/Controllers/Client/ClientController.cs
index 68de0410b..48d36345f 100644
--- a/WebfrontCore/Controllers/Client/ClientController.cs
+++ b/WebfrontCore/Controllers/Client/ClientController.cs
@@ -11,6 +11,7 @@ using System.Linq;
using System.Threading.Tasks;
using Data.Models;
using IW4MAdmin.Plugins.Stats.Config;
+using Stats.Config;
using WebfrontCore.ViewComponents;
namespace WebfrontCore.Controllers
diff --git a/WebfrontCore/Controllers/Client/Legacy/StatsController.cs b/WebfrontCore/Controllers/Client/Legacy/StatsController.cs
index 0fdbf4bf8..ceb51d803 100644
--- a/WebfrontCore/Controllers/Client/Legacy/StatsController.cs
+++ b/WebfrontCore/Controllers/Client/Legacy/StatsController.cs
@@ -16,6 +16,7 @@ using Microsoft.Extensions.Logging;
using ILogger = Microsoft.Extensions.Logging.ILogger;
using Data.Abstractions;
using IW4MAdmin.Plugins.Stats.Config;
+using Stats.Config;
namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
{
diff --git a/WebfrontCore/Startup.cs b/WebfrontCore/Startup.cs
index ef3668da1..185e36d3d 100644
--- a/WebfrontCore/Startup.cs
+++ b/WebfrontCore/Startup.cs
@@ -26,6 +26,7 @@ using Data.Abstractions;
using Data.Helpers;
using IW4MAdmin.Plugins.Stats.Config;
using Stats.Client.Abstractions;
+using Stats.Config;
using WebfrontCore.Controllers.API.Validation;
using WebfrontCore.Middleware;
diff --git a/WebfrontCore/ViewComponents/TopPlayersViewComponent.cs b/WebfrontCore/ViewComponents/TopPlayersViewComponent.cs
index 6e92c5d5c..c9e719a3c 100644
--- a/WebfrontCore/ViewComponents/TopPlayersViewComponent.cs
+++ b/WebfrontCore/ViewComponents/TopPlayersViewComponent.cs
@@ -5,6 +5,7 @@ using IW4MAdmin.Plugins.Stats.Config;
using IW4MAdmin.Plugins.Stats.Helpers;
using Microsoft.AspNetCore.Mvc;
using SharedLibraryCore.Interfaces;
+using Stats.Config;
namespace WebfrontCore.ViewComponents
{