diff --git a/.gitignore b/.gitignore index 2f1e1e7d4..861a675c9 100644 --- a/.gitignore +++ b/.gitignore @@ -226,3 +226,4 @@ bootstrap-custom.min.css /WebfrontCore/Views/Plugins/Stats /WebfrontCore/wwwroot/**/dds +/DiscordWebhook/env diff --git a/Application/Application.csproj b/Application/Application.csproj index 376e41431..3c97ef03d 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -5,7 +5,7 @@ netcoreapp2.1 false RaidMax.IW4MAdmin.Application - 2.1.2 + 2.1.4 RaidMax Forever None IW4MAdmin diff --git a/Application/Core/ClientAuthentication.cs b/Application/Core/ClientAuthentication.cs index 25247418d..1f818cabc 100644 --- a/Application/Core/ClientAuthentication.cs +++ b/Application/Core/ClientAuthentication.cs @@ -65,6 +65,12 @@ namespace IW4MAdmin.Application.Core public IList GetAuthenticatedClients() { + if (AuthenticatedClients.Values.Count > 18) + { + Program.ServerManager.GetLogger().WriteWarning($"auth client count is {AuthenticatedClients.Values.Count}, this is bad"); + return AuthenticatedClients.Values.Take(18).ToList(); + } + return AuthenticatedClients.Values.ToList(); } diff --git a/Application/EventParsers/IW4EventParser.cs b/Application/EventParsers/IW4EventParser.cs index bf5f701f0..2f0af3947 100644 --- a/Application/EventParsers/IW4EventParser.cs +++ b/Application/EventParsers/IW4EventParser.cs @@ -10,7 +10,7 @@ namespace IW4MAdmin.Application.EventParsers { class IW4EventParser : IEventParser { - private const string SayRegex = @"(say|sayteam);(.{16,32});([0-9]+)(.*);(.*)"; + private const string SayRegex = @"(say|sayteam);(.{1,32});([0-9]+)(.*);(.*)"; public virtual GameEvent GetEvent(Server server, string logLine) { @@ -121,7 +121,7 @@ namespace IW4MAdmin.Application.EventParsers // join if (eventType == "J") { - var regexMatch = Regex.Match(logLine, @"^(J;)(.{4,32});([0-9]+);(.*)$"); + var regexMatch = Regex.Match(logLine, @"^(J;)(.{1,32});([0-9]+);(.*)$"); if (regexMatch.Success) { return new GameEvent() @@ -141,7 +141,7 @@ namespace IW4MAdmin.Application.EventParsers if (eventType == "Q") { - var regexMatch = Regex.Match(logLine, @"^(Q;)(.{4,32});([0-9]+);(.*)$"); + var regexMatch = Regex.Match(logLine, @"^(Q;)(.{1,32});([0-9]+);(.*)$"); if (regexMatch.Success) { return new GameEvent() diff --git a/Application/Logger.cs b/Application/Logger.cs index d8d066dc9..d11a8b56e 100644 --- a/Application/Logger.cs +++ b/Application/Logger.cs @@ -39,7 +39,7 @@ namespace IW4MAdmin.Application catch (Exception) { } - string LogLine = $"[{DateTime.Now.ToString("HH:mm:ss")}] - {stringType}: {msg}"; + string LogLine = $"[{DateTime.Now.ToString("MM.dd.yyy HH:mm:ss.fff")}] - {stringType}: {msg}"; lock (ThreadLock) { #if DEBUG diff --git a/Application/Misc/VPNCheck.cs b/Application/Misc/VPNCheck.cs index 12a5e1bdb..f044643da 100644 --- a/Application/Misc/VPNCheck.cs +++ b/Application/Misc/VPNCheck.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -namespace Application.Misc +namespace IW4MAdmin.Application.Misc { public class VPNCheck { diff --git a/Application/RconParsers/IW3RConParser.cs b/Application/RconParsers/IW3RConParser.cs index 2d12e9a59..dfff63cc2 100644 --- a/Application/RconParsers/IW3RConParser.cs +++ b/Application/RconParsers/IW3RConParser.cs @@ -1,14 +1,13 @@ -using Application.RconParsers; -using SharedLibraryCore.RCon; +using SharedLibraryCore.RCon; using System; using System.Collections.Generic; using System.Text; -namespace Application.RconParsers +namespace IW4MAdmin.Application.RconParsers { class IW3RConParser : IW4RConParser { - private static CommandPrefix Prefixes = new CommandPrefix() + private static readonly CommandPrefix Prefixes = new CommandPrefix() { Tell = "tell {0} {1}", Say = "say {0}", diff --git a/Application/RconParsers/IW4RConParser.cs b/Application/RconParsers/IW4RConParser.cs index 8a1a2378a..af37227ef 100644 --- a/Application/RconParsers/IW4RConParser.cs +++ b/Application/RconParsers/IW4RConParser.cs @@ -10,7 +10,7 @@ using SharedLibraryCore; using SharedLibraryCore.RCon; using SharedLibraryCore.Exceptions; -namespace Application.RconParsers +namespace IW4MAdmin.Application.RconParsers { class IW4RConParser : IRConParser { @@ -111,18 +111,12 @@ namespace Application.RconParsers Name = name, NetworkId = networkId, ClientNumber = clientNumber, - IPAddress = ip, + IPAddress = ip == 0 ? int.MinValue : ip, Ping = ping, Score = score, IsBot = ip == 0 }; - if (P.IsBot) - { - // set it to 127.0.0.2 - P.IPAddress = 33554559; - } - StatusPlayers.Add(P); } } diff --git a/Application/RconParsers/IW5MRConParser.cs b/Application/RconParsers/IW5MRConParser.cs index 43044fa33..4112e0ef4 100644 --- a/Application/RconParsers/IW5MRConParser.cs +++ b/Application/RconParsers/IW5MRConParser.cs @@ -2,17 +2,15 @@ using System.Collections.Generic; using System.Text.RegularExpressions; using System.Threading.Tasks; +using System.Text; using SharedLibraryCore; using SharedLibraryCore.Interfaces; using SharedLibraryCore.Objects; using SharedLibraryCore.RCon; using SharedLibraryCore.Exceptions; -using System.Text; -using System.Linq; -using System.Net.Http; -namespace Application.RconParsers +namespace IW4MAdmin.WApplication.RconParsers { public class IW5MRConParser : IRConParser { diff --git a/Application/RconParsers/T6MRConParser.cs b/Application/RconParsers/T6MRConParser.cs index 398fd86ea..48016f0b3 100644 --- a/Application/RconParsers/T6MRConParser.cs +++ b/Application/RconParsers/T6MRConParser.cs @@ -12,7 +12,7 @@ using System.Text; using System.Linq; using System.Net.Http; -namespace Application.RconParsers +namespace IW4MAdmin.Application.RconParsers { public class T6MRConParser : IRConParser { diff --git a/Application/Server.cs b/Application/Server.cs index de7af1e1e..28f131207 100644 --- a/Application/Server.cs +++ b/Application/Server.cs @@ -14,13 +14,14 @@ using SharedLibraryCore.Database.Models; using SharedLibraryCore.Dtos; using SharedLibraryCore.Configuration; using SharedLibraryCore.Exceptions; +using SharedLibraryCore.Localization; -using Application.Misc; -using Application.RconParsers; +using IW4MAdmin.Application.Misc; +using IW4MAdmin.Application.RconParsers; using IW4MAdmin.Application.EventParsers; using IW4MAdmin.Application.IO; -using SharedLibraryCore.Localization; using IW4MAdmin.Application.Core; +using IW4MAdmin.WApplication.RconParsers; namespace IW4MAdmin { @@ -56,7 +57,6 @@ namespace IW4MAdmin public async Task OnPlayerJoined(Player logClient) { - if (Players[logClient.ClientNumber] == null || Players[logClient.ClientNumber].NetworkId != logClient.NetworkId) { @@ -184,6 +184,16 @@ namespace IW4MAdmin player = client.AsPlayer(); } + // reserved slots stuff + if ((MaxClients - ClientNum) < ServerConfig.ReservedSlotNumber && + ! player.IsPrivileged()) + { + Logger.WriteDebug($"Kicking {polledPlayer} their spot is reserved"); + string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, loc["SERVER_KICK_SLOT_IS_RESERVED"]); + await this.ExecuteCommandAsync(formattedKick); + return false; + } + Logger.WriteInfo($"Client {player} connected..."); // Do the player specific stuff @@ -590,7 +600,6 @@ namespace IW4MAdmin AuthQueue.AuthenticateClients(CurrentPlayers); - // all polled players should be authenticated var addPlayerTasks = AuthQueue.GetAuthenticatedClients() .Select(client => AddPlayer(client)); @@ -796,7 +805,7 @@ namespace IW4MAdmin CustomCallback = await ScriptLoaded(); string mainPath = EventParser.GetGameDir(); #if DEBUG - basepath.Value = @"D:\"; + basepath.Value = @"\\192.168.88.253\Call of Duty Black Ops II"; #endif string logPath; if (GameName == Game.IW5) diff --git a/DiscordWebhook/DiscordWebhook.py b/DiscordWebhook/DiscordWebhook.py new file mode 100644 index 000000000..ed59e5fcb --- /dev/null +++ b/DiscordWebhook/DiscordWebhook.py @@ -0,0 +1,134 @@ +import requests +import time +import json +import collections + +class WebhookAuthor(): + def __init__(self, name=None, url=None, icon_url=None): + if name: + self.name = name + if url: + self.url = url + if icon_url: + self.icon_url = icon_url + +class WebhookField(): + def __init__(self, name=None, value=None, inline=False): + if name: + self.name = name + if value: + self.value = value + if inline: + self.inline = inline + +class WebhookEmbed(): + def __init__(self): + self.author = '' + self.title = '' + self.url = '' + self.description = '' + self.color = 0 + self.fields = [] + self.thumbnail = {} + +class WebhookParams(): + def __init__(self, username=None, avatar_url=None, content=None): + self.username = '' + self.avatar_url = '' + self.content = '' + self.embeds = [] + + def to_json(self): + return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True) + +def get_client_profile(profile_id): + return '{}/Client/ProfileAsync/{}'.format(base_url, str(profile_id)) + +with open('config.json') as json_config_file: + json_config = json.load(json_config_file) + +# this should be an URL to an IP or FQN to an IW4MAdmin instance +# ie http://127.0.0.1 or http://IW4MAdmin.com +base_url = json_config['IW4MAdminUrl'] +end_point = '/api/event' +request_url = base_url + end_point +# this should be the full discord webhook url +# ie https://discordapp.com/api/webhooks// +discord_webhook_url = json_config['DiscordWebhookUrl'] +# this should be the numerical id of the discord group +# 12345678912345678 +notify_role_ids = json_config['NotifyRoleIds'] + +def get_new_events(): + events = [] + response = requests.get(request_url) + data = response.json() + + for event in data: + # commonly used event info items + event_type = event['eventType']['name'] + server_name = event['ownerEntity']['name'] + + webhook_item = WebhookParams() + webhook_item_embed = WebhookEmbed() + + webhook_item.username = 'IW4MAdmin' + webhook_item.avatar_url = 'https://raidmax.org/IW4MAdmin/img/iw4adminicon-3.png' + webhook_item_embed.color = 31436 + webhook_item_embed.url = base_url + webhook_item_embed.thumbnail = { 'url' : 'https://raidmax.org/IW4MAdmin/img/iw4adminicon-3.png' } + webhook_item.embeds.append(webhook_item_embed) + + role_ids_string = '' + for id in notify_role_ids: + role_ids_string += '\r\n<@&{}>\r\n'.format(id) + + webhook_notifyrole = WebhookField('Notifies',role_ids_string) + + if event_type == 'Report': + origin_client_name = event['originEntity']['name'] + origin_client_id = int(event['originEntity']['id']) + + target_client_name = event['targetEntity']['name'] + target_client_id = int(event['targetEntity']['id']) + + report_reason = event['extraInfo'] + + server_field = WebhookField('Server', server_name) + report_reason_field = WebhookField('Reason', report_reason) + reported_by_field = WebhookField('By', '[{}]({})'.format(origin_client_name, get_client_profile(origin_client_id))) + reported_field = WebhookField('Reported Player', '[{}]({})'.format(target_client_name, get_client_profile(target_client_id))) + + webhook_item_embed.title = 'Player Reported' + webhook_item_embed.fields.append(server_field) + webhook_item_embed.fields.append(reported_field) + webhook_item_embed.fields.append(reported_by_field) + webhook_item_embed.fields.append(report_reason_field) + + #make sure there's at least one group to notify + if len(notify_role_ids) > 0: + webhook_item.content = role_ids_string + + else: + continue + + events.append(webhook_item) + + return events + +def execute_webhook(data): + for event in data: + event_json = event.to_json() + response = requests.post(discord_webhook_url, data=event_json, headers={'Content-type' : 'application/json'}) + +def run(): + while True: + try: + new_events = get_new_events() + execute_webhook(new_events) + except: + print('failed to get new events') + time.sleep(2.5) + +if __name__ == "__main__": + run() \ No newline at end of file diff --git a/DiscordWebhook/DiscordWebhook.pyproj b/DiscordWebhook/DiscordWebhook.pyproj new file mode 100644 index 000000000..0dfa2fb79 --- /dev/null +++ b/DiscordWebhook/DiscordWebhook.pyproj @@ -0,0 +1,50 @@ + + + Debug + 2.0 + 15a81d6e-7502-46ce-8530-0647a380b5f4 + . + DiscordWebhook.py + + + . + . + DiscordWebhook + DiscordWebhook + MSBuild|env|$(MSBuildProjectFullPath) + + + true + false + + + true + false + + + + + + + env + 3.6 + env (Python 3.6 (64-bit)) + Scripts\python.exe + Scripts\pythonw.exe + PYTHONPATH + X64 + + + + + + + + + + + + + \ No newline at end of file diff --git a/DiscordWebhook/config.json b/DiscordWebhook/config.json new file mode 100644 index 000000000..a9ebc393c --- /dev/null +++ b/DiscordWebhook/config.json @@ -0,0 +1,5 @@ +{ + "IW4MAdminUrl": "", + "DiscordWebhookUrl": "", + "NotifyRoleIds": [] +} \ No newline at end of file diff --git a/IW4MAdmin.sln b/IW4MAdmin.sln index a0daec403..ec5be4d67 100644 --- a/IW4MAdmin.sln +++ b/IW4MAdmin.sln @@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Plugins\Tests\Test EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IW4ScriptCommands", "Plugins\IW4ScriptCommands\IW4ScriptCommands.csproj", "{6C706CE5-A206-4E46-8712-F8C48D526091}" EndProject +Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "DiscordWebhook", "DiscordWebhook\DiscordWebhook.pyproj", "{15A81D6E-7502-46CE-8530-0647A380B5F4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -287,6 +289,18 @@ Global {6C706CE5-A206-4E46-8712-F8C48D526091}.Release|x64.Build.0 = Release|Any CPU {6C706CE5-A206-4E46-8712-F8C48D526091}.Release|x86.ActiveCfg = Release|Any CPU {6C706CE5-A206-4E46-8712-F8C48D526091}.Release|x86.Build.0 = Release|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Debug|x64.ActiveCfg = Debug|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Debug|x86.ActiveCfg = Debug|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|Any CPU.ActiveCfg = Release|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|Mixed Platforms.ActiveCfg = Release|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|x64.ActiveCfg = Release|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|x86.ActiveCfg = Release|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Release|x64.ActiveCfg = Release|Any CPU + {15A81D6E-7502-46CE-8530-0647A380B5F4}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index 31097d4b2..221959b8b 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -411,14 +411,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers kill.DeathType == IW4Info.MeansOfDeath.MOD_HEAD_SHOT) { clientStats.HitLocations.Single(hl => hl.Location == kill.HitLoc).HitCount += 1; - - //statsSvc.ClientStatSvc.Update(clientStats); - // await statsSvc.ClientStatSvc.SaveChangesAsync(); } - //statsSvc.KillStatsSvc.Insert(kill); - //await statsSvc.KillStatsSvc.SaveChangesAsync(); - if (Plugin.Config.Configuration().EnableAntiCheat) { async Task executePenalty(Cheat.DetectionPenaltyResult penalty) diff --git a/SharedLibraryCore/Configuration/ServerConfiguration.cs b/SharedLibraryCore/Configuration/ServerConfiguration.cs index fc6cb814e..a0e084149 100644 --- a/SharedLibraryCore/Configuration/ServerConfiguration.cs +++ b/SharedLibraryCore/Configuration/ServerConfiguration.cs @@ -14,6 +14,7 @@ namespace SharedLibraryCore.Configuration public bool UseT6MParser { get; set; } public bool UseIW5MParser { get; set; } public string ManualLogPath { get; set; } + public int ReservedSlotNumber { get; set; } public IBaseConfiguration Generate() { @@ -46,6 +47,8 @@ namespace SharedLibraryCore.Configuration if (UseIW5MParser) ManualLogPath = Utilities.PromptString(loc["SETUP_SERVER_MANUALLOG"]); + ReservedSlotNumber = loc["SETUP_SERVER_RESERVEDSLOT"].PromptInt(0, 32); + return this; } diff --git a/SharedLibraryCore/Dtos/PenaltyInfo.cs b/SharedLibraryCore/Dtos/PenaltyInfo.cs index 25d789d03..9a959be10 100644 --- a/SharedLibraryCore/Dtos/PenaltyInfo.cs +++ b/SharedLibraryCore/Dtos/PenaltyInfo.cs @@ -13,6 +13,7 @@ namespace SharedLibraryCore.Dtos public string PunisherName { get; set; } public int PunisherId { get; set; } public string PunisherLevel { get; set; } + public int PunisherLevelId { get; set; } public string Offense { get; set; } public string AutomatedOffense { get; set; } public string Type { get; set; } diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index a56eab4ab..e6231fc3b 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -199,7 +199,8 @@ namespace SharedLibraryCore return id; var bot = Regex.Match(str, @"bot[0-9]+").Value; if (!string.IsNullOrEmpty(bot)) - return -1;//Convert.ToInt64(bot.Substring(3)) + 1; + // should set their GUID to the negation of their 1 based index (-1 - -18) + return -(Convert.ToInt64(bot.Substring(3)) + 1); return 0; } @@ -365,7 +366,7 @@ namespace SharedLibraryCore CurrentAlias = client.CurrentAlias, CurrentAliasId = client.CurrentAlias.AliasId, // todo: make sure this is up to date - IsBot = client.NetworkId == -1, + IsBot = client.IPAddress == int.MinValue, Password = client.Password, PasswordSalt = client.PasswordSalt }; @@ -379,6 +380,33 @@ namespace SharedLibraryCore return (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y'; } + /// + /// prompt user to enter a number + /// + /// question to prompt with + /// maximum value to allow + /// minimum value to allow + /// integer from user's input + public static int PromptInt(this string question, int minValue = 0, int maxValue = int.MaxValue) + { + Console.Write($"{question}: "); + int response; + + while (!int.TryParse(Console.ReadLine(), out response) || + response < minValue || + response > maxValue) + { + string range = ""; + if (minValue != 0 || maxValue != int.MaxValue) + { + range = $" [{minValue}-{maxValue}]"; + } + Console.Write($"Please enter a valid number{range}: "); + } + + return response; + } + public static string PromptString(string question) { string response; @@ -455,6 +483,5 @@ namespace SharedLibraryCore var response = await server.RemoteConnection.SendQueryAsync(RCon.StaticHelpers.QueryType.GET_INFO); return response.FirstOrDefault(r => r[0] == '\\')?.DictionaryFromKeyValue(); } - } } diff --git a/WebfrontCore/Controllers/API/APIController.cs b/WebfrontCore/Controllers/API/APIController.cs index 61c093b86..1f6990a0c 100644 --- a/WebfrontCore/Controllers/API/APIController.cs +++ b/WebfrontCore/Controllers/API/APIController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using SharedLibraryCore; using System; using System.Collections.Generic; using System.Linq; @@ -39,8 +40,8 @@ namespace WebfrontCore.Controllers.API player.Ping, State = player.State.ToString(), player.ClientNumber, - ConnectionTime = (DateTime.UtcNow - player.ConnectionTime).TotalSeconds, - player.Level, + ConnectionTime = Math.Round((DateTime.UtcNow - player.ConnectionTime).TotalSeconds, 0), + Level = player.Level.ToLocalizedLevelName(), }) }); diff --git a/WebfrontCore/ViewComponents/PenaltyListViewComponent.cs b/WebfrontCore/ViewComponents/PenaltyListViewComponent.cs index 9e0038217..6fb6d06ab 100644 --- a/WebfrontCore/ViewComponents/PenaltyListViewComponent.cs +++ b/WebfrontCore/ViewComponents/PenaltyListViewComponent.cs @@ -21,6 +21,7 @@ namespace WebfrontCore.ViewComponents PunisherId = p.PunisherId, PunisherName = p.Punisher.Name, PunisherLevel = p.Punisher.Level.ToLocalizedLevelName(), + PunisherLevelId = (int)p.Punisher.Level, #if DEBUG Offense = !string.IsNullOrEmpty(p.AutomatedOffense) ? p.AutomatedOffense : p.Offense, #else diff --git a/WebfrontCore/Views/Client/Find/Index.cshtml b/WebfrontCore/Views/Client/Find/Index.cshtml index dc87ab176..edf986ec1 100644 --- a/WebfrontCore/Views/Client/Find/Index.cshtml +++ b/WebfrontCore/Views/Client/Find/Index.cshtml @@ -16,7 +16,7 @@ {
@Html.ActionLink(client.Name, "ProfileAsync", "Client", new { id = client.ClientId })
-
@client.Level
+
@client.Level
@client.LastSeen @loc["WEBFRONT_PENALTY_TEMPLATE_AGO"]
} diff --git a/WebfrontCore/Views/Client/Profile/Index.cshtml b/WebfrontCore/Views/Client/Profile/Index.cshtml index 2fd07afee..0cd125e52 100644 --- a/WebfrontCore/Views/Client/Profile/Index.cshtml +++ b/WebfrontCore/Views/Client/Profile/Index.cshtml @@ -7,7 +7,7 @@ }
-
+
@if (string.IsNullOrEmpty(gravatarUrl)) { @shortCode @@ -71,7 +71,7 @@ }
-
@Model.Level
+
@Model.Level
@loc["WEBFRONT_PROFILE_PLAYER"] @Model.TimePlayed @loc["GLOBAL_TIME_HOURS"] diff --git a/WebfrontCore/Views/Penalty/_Penalty.cshtml b/WebfrontCore/Views/Penalty/_Penalty.cshtml index 7bba5ffd1..b3491c0e9 100644 --- a/WebfrontCore/Views/Penalty/_Penalty.cshtml +++ b/WebfrontCore/Views/Penalty/_Penalty.cshtml @@ -29,7 +29,7 @@ @loc["WEBFRONT_PENALTY_TEMPLATE_ADMIN"] - @Html.ActionLink(Model.PunisherName, "ProfileAsync", "Client", new { id = Model.PunisherId }, new { @class = "level-color-" + Model.PunisherLevel.ToLower() }) + @Html.ActionLink(Model.PunisherName, "ProfileAsync", "Client", new { id = Model.PunisherId }, new { @class = "level-color-" + Model.PunisherLevelId }) }) @@ -60,7 +60,7 @@ @Model.Offense - @Html.ActionLink(Model.PunisherName, "ProfileAsync", "Client", new { id = Model.PunisherId }, new { @class = "level-color-" + Model.PunisherLevel.ToLower() }) + @Html.ActionLink(Model.PunisherName, "ProfileAsync", "Client", new { id = Model.PunisherId }, new { @class = "level-color-" + Model.PunisherLevelId }) }) @{ diff --git a/WebfrontCore/Views/Server/_ClientActivity.cshtml b/WebfrontCore/Views/Server/_ClientActivity.cshtml index 51bc6b391..9dc1588f7 100644 --- a/WebfrontCore/Views/Server/_ClientActivity.cshtml +++ b/WebfrontCore/Views/Server/_ClientActivity.cshtml @@ -36,7 +36,7 @@ @{ for (int i = 0; i < half; i++) { - string levelColorClass = !ViewBag.Authorized ? "" : $"level-color-{Model.Players[i].Level.ToLower()}"; + string levelColorClass = !ViewBag.Authorized ? "" : $"level-color-{Model.Players[i].LevelInt}"; @Html.ActionLink(Model.Players[i].Name, "ProfileAsync", "Client", new { id = Model.Players[i].ClientId }, new { @class = levelColorClass })
} } @@ -45,7 +45,7 @@ @{ for (int i = half; i < Model.ClientCount; i++) { - string levelColorClass = !ViewBag.Authorized ? "" : $"level-color-{Model.Players[i].Level.ToLower()}"; + string levelColorClass = !ViewBag.Authorized ? "" : $"level-color-{Model.Players[i].LevelInt}"; @Html.ActionLink(Model.Players[i].Name, "ProfileAsync", "Client", new { id = Model.Players[i].ClientId }, new { @class = levelColorClass })
} } diff --git a/WebfrontCore/WebfrontCore.csproj b/WebfrontCore/WebfrontCore.csproj index 9129dccc1..e94b91e96 100644 --- a/WebfrontCore/WebfrontCore.csproj +++ b/WebfrontCore/WebfrontCore.csproj @@ -44,6 +44,7 @@ + diff --git a/WebfrontCore/wwwroot/css/profile.css b/WebfrontCore/wwwroot/css/profile.css index 7ce2fbe75..d4c74925b 100644 --- a/WebfrontCore/wwwroot/css/profile.css +++ b/WebfrontCore/wwwroot/css/profile.css @@ -2,81 +2,81 @@ background-color: grey; } -.level-color-user, .level-color-guest { +.level-color-user, .level-color-guest, .level-color-0 { color: #6c757d; color: rgba(255, 255, 255, 0.68); } -.level-bgcolor-user, .level-bgcolor-guest { +.level-bgcolor-user, .level-bgcolor-guest, .level-bgcolor-0 { background-color: #6c757d; background-color: rgba(255, 255, 255, 0.68); } -.level-color-trusted { +.level-color-trusted, .level-color-2 { color: #749363; color: rgba(116,147,99,1); } -.level-bgcolor-trusted { +.level-bgcolor-trusted, .level-bgcolor-2 { background-color: #749363; background-color: rgba(116,147,99,1); } -.level-color-flagged { +.level-color-flagged, .level-color-1 { color: #fd9c38; color: rgba(253, 139, 22, 0.85); } -.level-bgcolor-flagged { +.level-bgcolor-flagged, .level-bgcolor-1 { background-color: #fd9c38; background-color: rgba(253, 139, 22, 0.85); } -.level-color-banned, .level-color-console { +.level-color-banned, .level-color-console, .level-color--1 { color: #ff6060; color: rgba(255, 69, 69, 0.85); } -.level-bgcolor-banned { +.level-bgcolor-banned, .level-bgcolor--1 { background-color: #ff6060; background-color: rgba(255, 69, 69, 0.85); } -.level-color-moderator { +.level-color-moderator, .level-color-3 { color: #f0de8b; color: rgba(235, 211, 101, 0.75); } -.level-bgcolor-moderator { +.level-bgcolor-moderator, .level-bgcolor-3 { background-color: #f0de8b; background-color: rgba(235, 211, 101, 0.75); } -.level-color-administrator { +.level-color-administrator, .level-color-4 { color: #f1a8e8; color: rgba(236, 130, 222, 0.69); } -.level-bgcolor-administrator { +.level-bgcolor-administrator, .level.bgcolor-4 { background-color: #f1a8e8; background-color: rgba(236, 130, 222, 0.69); } -.level-color-senioradmin { +.level-color-senioradmin, .level-color-5 { color: #50bcc3; color: rgba(50, 177, 185, 0.85); } -.level-bgcolor-senioradmin { +.level-bgcolor-senioradmin, .level-bgcolor-5 { background-color: #50bcc3; background-color: rgba(50, 177, 185, 0.85); } -.level-color-owner { +.level-color-owner, .level-color-6 { color: rgb(0, 122, 204); } -.level-bgcolor-owner { +.level-bgcolor-owner, .level-bgcolor-6 { background-color: rgb(0, 122, 204); }