diff --git a/.env.example b/.env.example index bd0f1e07..7c6bdaa0 100644 --- a/.env.example +++ b/.env.example @@ -7,6 +7,10 @@ ServerInfo__IntroAudioUrl=https://od.lk/s/Nl8yMDg4MTc0NDBf/intro-cs.mp3 # Expressed in seconds. ServerInfo__FlagAutoReturnTime=120 +ServerOwner__Name=MrDave +# Specify the secret key to give me admin. +ServerOwner__SecretKey= + # Expressed in minutes. CommandCooldowns__Health=3 CommandCooldowns__Armour=3 diff --git a/src/Application/Common/Resources/Messages.Designer.cs b/src/Application/Common/Resources/Messages.Designer.cs index 8910792f..e2aa4b17 100644 --- a/src/Application/Common/Resources/Messages.Designer.cs +++ b/src/Application/Common/Resources/Messages.Designer.cs @@ -627,6 +627,15 @@ internal static string OnFlagTaken { } } + /// + /// Looks up a localized string similar to Owner's name or secret key are not set. + /// + internal static string OwnerNameOrSecretKeyAreNotSet { + get { + return ResourceManager.GetString("OwnerNameOrSecretKeyAreNotSet", resourceCulture); + } + } + /// /// Looks up a localized string similar to Password cannot be empty. /// @@ -717,6 +726,15 @@ internal static string PlayerIsInClassSelection { } } + /// + /// Looks up a localized string similar to You are not the owner of this server. + /// + internal static string PlayerIsNotServerOwner { + get { + return ResourceManager.GetString("PlayerIsNotServerOwner", resourceCulture); + } + } + /// /// Looks up a localized string similar to That player name already exists. /// @@ -1085,5 +1103,14 @@ internal static string WrongPassword { return ResourceManager.GetString("WrongPassword", resourceCulture); } } + + /// + /// Looks up a localized string similar to The secret key you entered is incorrect. Please try again. + /// + internal static string WrongSecretKey { + get { + return ResourceManager.GetString("WrongSecretKey", resourceCulture); + } + } } } diff --git a/src/Application/Common/Resources/Messages.resx b/src/Application/Common/Resources/Messages.resx index 724f161a..61043f25 100644 --- a/src/Application/Common/Resources/Messages.resx +++ b/src/Application/Common/Resources/Messages.resx @@ -306,6 +306,9 @@ {PlayerName} has taken the {TeamName} team's {ColorName} flag! Keep an eye on the score! + + Owner's name or secret key are not set + Password cannot be empty @@ -336,6 +339,9 @@ The player is in the class selection + + You are not the owner of this server + That player name already exists @@ -459,4 +465,7 @@ The password you entered is incorrect. Please try again + + The secret key you entered is incorrect. Please try again + \ No newline at end of file diff --git a/src/Application/Players/Accounts/ServerOwnerSettings.cs b/src/Application/Players/Accounts/ServerOwnerSettings.cs new file mode 100644 index 00000000..b4c22154 --- /dev/null +++ b/src/Application/Players/Accounts/ServerOwnerSettings.cs @@ -0,0 +1,7 @@ +namespace CTF.Application.Players.Accounts; + +public class ServerOwnerSettings +{ + public string Name { get; init; } = string.Empty; + public string SecretKey { get; init; } = string.Empty; +} diff --git a/src/Application/Players/Accounts/Systems/ChangeRoleSystem.cs b/src/Application/Players/Accounts/Systems/ChangeRoleSystem.cs index 4ec76a66..41553b0b 100644 --- a/src/Application/Players/Accounts/Systems/ChangeRoleSystem.cs +++ b/src/Application/Players/Accounts/Systems/ChangeRoleSystem.cs @@ -1,6 +1,9 @@ namespace CTF.Application.Players.Accounts.Systems; -public class ChangeRoleSystem(IPlayerRepository playerRepository) : ISystem +public class ChangeRoleSystem( + IPlayerRepository playerRepository, + IDialogService dialogService, + ServerOwnerSettings serverOwnerSettings) : ISystem { [PlayerCommand("setrole")] public void SetRole( @@ -53,4 +56,65 @@ public void SetRole( targetPlayer.GameText(gameText, 4000, 3); currentPlayer.SendClientMessage(Color.Yellow, message); } + + [PlayerCommand("givemeadmin")] + public async void GiveMeAdmin(Player currentPlayer) + { + if (string.IsNullOrWhiteSpace(serverOwnerSettings.Name) || + string.IsNullOrWhiteSpace(serverOwnerSettings.SecretKey)) + { + currentPlayer.SendClientMessage(Color.Red, Messages.OwnerNameOrSecretKeyAreNotSet); + return; + } + + var ownerName = serverOwnerSettings.Name.Trim(); + bool isNotEquals = !currentPlayer.Name.Equals(ownerName, StringComparison.OrdinalIgnoreCase); + if (isNotEquals) + { + currentPlayer.SendClientMessage(Color.Red, Messages.PlayerIsNotServerOwner); + return; + } + + var dialog = new InputDialog() + { + Caption = "Secret key", + Content = "Enter secret key", + Button1 = "Accept", + Button2 = "Close" + }; + + InputDialogResponse response = await dialogService.ShowAsync(currentPlayer, dialog); + if (response.IsRightButtonOrDisconnected()) + return; + + var enteredSecretKey = response.InputText; + bool isWrongSecretKey = enteredSecretKey != serverOwnerSettings.SecretKey; + if (isWrongSecretKey) + { + const int MaxFailedAttempts = 3; + var failedAttemptCount = currentPlayer.GetComponent(); + failedAttemptCount ??= currentPlayer.AddComponent(); + failedAttemptCount.Value++; + if (failedAttemptCount.Value == MaxFailedAttempts) + { + currentPlayer.Kick(); + return; + } + currentPlayer.SendClientMessage(Color.Red, Messages.WrongSecretKey); + GiveMeAdmin(currentPlayer); + return; + } + + var gameText = Smart.Format(Messages.PromotedToRole, new { RoleName = RoleId.Admin }); + PlayerInfo playerInfo = currentPlayer.GetInfo(); + playerInfo.SetRole(RoleId.Admin); + playerRepository.UpdateRole(playerInfo); + currentPlayer.GameText(gameText, 4000, 3); + currentPlayer.GetComponent()?.Destroy(); + } + + private class FailedAttemptCountComponent : Component + { + public int Value { get; set; } = 0; + } } diff --git a/src/Host/Extensions/AppSettingsExtensions.cs b/src/Host/Extensions/AppSettingsExtensions.cs index cf6ad614..c17a395f 100644 --- a/src/Host/Extensions/AppSettingsExtensions.cs +++ b/src/Host/Extensions/AppSettingsExtensions.cs @@ -18,10 +18,15 @@ public static IServiceCollection AddSettings( .GetRequiredSection("TopPlayers") .Get(); + var serverOwnerSettings = configuration + .GetRequiredSection("ServerOwner") + .Get(); + services .AddSingleton(serverSettings) .AddSingleton(commandCooldowns) - .AddSingleton(topPlayersSettings); + .AddSingleton(topPlayersSettings) + .AddSingleton(serverOwnerSettings); return services; } diff --git a/src/Host/Usings.cs b/src/Host/Usings.cs index 390c0152..3aad8be2 100644 --- a/src/Host/Usings.cs +++ b/src/Host/Usings.cs @@ -9,6 +9,7 @@ global using CTF.Application.Common.Settings; global using CTF.Application.Common.Services; global using CTF.Application.Players; +global using CTF.Application.Players.Accounts; global using CTF.Application.Players.TopPlayers.Models; global using CTF.Host.Extensions; global using CTF.Host.Services;