From 844e894db87ff000c5084fc717a01dd16ef983a1 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Thu, 28 Sep 2023 01:02:40 +0200 Subject: [PATCH 01/22] docs From edcd5badf0ebb0cb01b8ef909b2194f61b0afb14 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Thu, 28 Sep 2023 01:02:58 +0200 Subject: [PATCH 02/22] docs From 3c0a6ac186745b21e0e640b9af4e882d37bc5e2a Mon Sep 17 00:00:00 2001 From: Bluscream Date: Thu, 28 Sep 2023 01:03:16 +0200 Subject: [PATCH 03/22] docs --- Allowlist.cs.md | 23 +++++++++++++ Announcements.cs.md | 0 BasicProgression.cs.md | 0 BasicServerSettings.cs.md | 0 CommandHandler.cs.md | 34 +++++++++++++++++++ DiscordWebhooks.cs.md | 0 LoadingScreenText.cs.md | 0 MOTD.cs.md | 26 +++++++++++++++ ModeratorTools.cs.md | 69 +++++++++++++++++++++++++++++++++++++++ ModuleUpdates.cs.md | 0 PermissionsCommands.cs.md | 25 ++++++++++++++ PlayerFinder.cs.md | 0 PlayerPermissions.cs.md | 0 ProfanityFilter.cs.md | 0 RichText.cs.md | 0 Rotation.cs.md | 0 SpectateControl.cs.md | 0 Voting.cs.md | 23 +++++++++++++ 18 files changed, 200 insertions(+) create mode 100644 Allowlist.cs.md create mode 100644 Announcements.cs.md create mode 100644 BasicProgression.cs.md create mode 100644 BasicServerSettings.cs.md create mode 100644 CommandHandler.cs.md create mode 100644 DiscordWebhooks.cs.md create mode 100644 LoadingScreenText.cs.md create mode 100644 MOTD.cs.md create mode 100644 ModeratorTools.cs.md create mode 100644 ModuleUpdates.cs.md create mode 100644 PermissionsCommands.cs.md create mode 100644 PlayerFinder.cs.md create mode 100644 PlayerPermissions.cs.md create mode 100644 ProfanityFilter.cs.md create mode 100644 RichText.cs.md create mode 100644 Rotation.cs.md create mode 100644 SpectateControl.cs.md create mode 100644 Voting.cs.md diff --git a/Allowlist.cs.md b/Allowlist.cs.md new file mode 100644 index 0000000..b91759d --- /dev/null +++ b/Allowlist.cs.md @@ -0,0 +1,23 @@ +# 1 Modules in Allowlist.cs + +| Description | Version | +|:-------------------------------------------------------------------|:----------| +| Block players who are not on the allowlist from joining the server | 1.0.0 | + +## Commands +| Command | Function Name | Description | Allowed Roles | Parameters | Defaults | +|:-------------|:----------------|:------------------------------------|:----------------|:------------------------------------------------|:-----------| +| allow add | void | Adds a player to the allowlist | Moderator | ['RunnerPlayer commandSource', 'ulong steamID'] | {} | +| allow remove | void | Removes a player from the allowlist | Moderator | ['RunnerPlayer commandSource', 'ulong steamID'] | {} | + +## Public Methods +| Function Name | Parameters | Defaults | +|:----------------|:-------------------------------------------------|:-----------| +| | | | +| | | | +| | | | +| Task | ['ulong steamID', 'PlayerJoiningArguments args'] | {} | +| AllowAdd | ['RunnerPlayer commandSource', 'ulong steamID'] | {} | +| AllowRemove | ['RunnerPlayer commandSource', 'ulong steamID'] | {} | +| | | | +| | | | \ No newline at end of file diff --git a/Announcements.cs.md b/Announcements.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/BasicProgression.cs.md b/BasicProgression.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/BasicServerSettings.cs.md b/BasicServerSettings.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/CommandHandler.cs.md b/CommandHandler.cs.md new file mode 100644 index 0000000..fd635cd --- /dev/null +++ b/CommandHandler.cs.md @@ -0,0 +1,34 @@ +# 1 Modules in CommandHandler.cs + +| Description | Version | +|:-------------------------------------------|:----------| +| Basic in-game chat command handler library | 1.0.0 | + +## Commands +| Command | Function Name | Description | Allowed Roles | Parameters | Defaults | +|:----------|:----------------|:----------------------------------|:----------------|:------------------------------------------|:--------------| +| help | void | Shows this help message | | ['RunnerPlayer player', 'int page = 1'] | {'page': '1'} | +| cmdhelp | void | Shows help for a specific command | | ['RunnerPlayer player', 'string command'] | {} | +| modules | void | Lists all loaded modules | Admin | ['RunnerPlayer commandSource'] | {} | + +## Public Methods +| Function Name | Parameters | Defaults | +|:-------------------|:-----------------------------------------------------------------|:--------------| +| | | | +| | | | +| | | | +| | | | +| | | | +| | | | +| | | | +| void | [''] | {} | +| Register | ['BattleBitModule module'] | {} | +| Task | ['RunnerPlayer player', 'ChatChannel channel', 'string message'] | {} | +| HelpCommand | ['RunnerPlayer player', 'int page = 1'] | {'page': '1'} | +| CommandHelpCommand | ['RunnerPlayer player', 'string command'] | {} | +| ListModules | ['RunnerPlayer commandSource'] | {} | +| | | | +| | | | +| | | | +| | | | +| | | | \ No newline at end of file diff --git a/DiscordWebhooks.cs.md b/DiscordWebhooks.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/LoadingScreenText.cs.md b/LoadingScreenText.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/MOTD.cs.md b/MOTD.cs.md new file mode 100644 index 0000000..4c22197 --- /dev/null +++ b/MOTD.cs.md @@ -0,0 +1,26 @@ +# 1 Modules in MOTD.cs + +| Description | Version | +|:---------------------------------------------------------|:----------| +| Show a message of the day to players who join the server | 1.0.0 | + +## Commands +| Command | Function Name | Description | Allowed Roles | Parameters | Defaults | +|:----------|:----------------|:---------------|:----------------|:----------------------------------------------|:-----------| +| setmotd | void | Sets the MOTD | Admin | ['RunnerPlayer commandSource', 'string motd'] | {} | +| motd | void | Shows the MOTD | | ['RunnerPlayer commandSource'] | {} | + +## Public Methods +| Function Name | Parameters | Defaults | +|:----------------|:----------------------------------------------|:-----------| +| | | | +| | | | +| | | | +| void | [''] | {} | +| Task | ['GameState oldState', 'GameState newState'] | {} | +| Task | ['RunnerPlayer player'] | {} | +| SetMOTD | ['RunnerPlayer commandSource', 'string motd'] | {} | +| ShowMOTD | ['RunnerPlayer commandSource'] | {} | +| | | | +| | | | +| | | | \ No newline at end of file diff --git a/ModeratorTools.cs.md b/ModeratorTools.cs.md new file mode 100644 index 0000000..98b329b --- /dev/null +++ b/ModeratorTools.cs.md @@ -0,0 +1,69 @@ +# 1 Modules in ModeratorTools.cs + +| Description | Version | +|:----------------------|:----------| +| Basic moderator tools | 1.0.0 | + +## Commands +| Command | Function Name | Description | Allowed Roles | Parameters | Defaults | +|:--------------|:----------------|:-----------------------------------------------|:----------------|:-------------------------------------------------------------------------------------------------|:--------------------------------------| +| Say | void | Prints a message to all players | Moderator | ['RunnerPlayer commandSource', 'string message'] | {} | +| SayToPlayer | void | Prints a message to all players | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string message'] | {} | +| AnnounceShort | void | Prints a short announce to all players | Moderator | ['RunnerPlayer commandSource', 'string message'] | {} | +| AnnounceLong | void | Prints a long announce to all players | Moderator | ['RunnerPlayer commandSource', 'string message'] | {} | +| Message | void | Messages a specific player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string message', 'float? timeout = null'] | {'timeout': 'null'} | +| Clear | void | Clears the chat | Moderator | ['RunnerPlayer commandSource'] | {} | +| Kick | void | Kicks a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? reason = null'] | {'reason': 'null'} | +| Ban | void | Bans a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target'] | {} | +| Kill | void | Kills a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Gag | void | Gags a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Ungag | void | Ungags a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Mute | void | Mutes a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Unmute | void | Unmutes a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Silence | void | Mutes and gags a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Unsilence | void | Unmutes and ungags a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| LockSpawn | void | Prevents a player or all players from spawning | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer? target = null', 'string? message = null'] | {'target': 'null', 'message': 'null'} | +| UnlockSpawn | void | Allows a player or all players to spawn | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer? target = null', 'string? message = null'] | {'target': 'null', 'message': 'null'} | +| tp2me | void | Teleports a player to you | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target'] | {} | +| tpme2 | void | Teleports you to a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target'] | {} | +| tp | void | Teleports a player to another player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'RunnerPlayer destination'] | {} | +| tp2pos | void | Teleports a player to a position | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'int x', 'int y', 'int z'] | {} | +| tpme2pos | void | Teleports you to a position | Moderator | ['RunnerPlayer commandSource', 'int x', 'int y', 'int z'] | {} | +| freeze | void | Freezes a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| unfreeze | void | Unfreezes a player | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Inspect | void | Inspects a player or stops inspection | Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer? target = null'] | {'target': 'null'} | + +## Public Methods +| Function Name | Parameters | Defaults | +|:-----------------------|:-------------------------------------------------------------------------------------------------|:--------------------------------------| +| | | | +| | | | +| void | [''] | {} | +| Task | [''] | {} | +| Say | ['RunnerPlayer commandSource', 'string message'] | {} | +| SayToPlayer | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string message'] | {} | +| AnnounceShort | ['RunnerPlayer commandSource', 'string message'] | {} | +| AnnounceLong | ['RunnerPlayer commandSource', 'string message'] | {} | +| Message | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string message', 'float? timeout = null'] | {'timeout': 'null'} | +| Clear | ['RunnerPlayer commandSource'] | {} | +| Kick | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? reason = null'] | {'reason': 'null'} | +| Ban | ['RunnerPlayer commandSource', 'RunnerPlayer target'] | {} | +| Kill | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Gag | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Ungag | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Mute | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Unmute | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Silence | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Unsilence | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| LockSpawn | ['RunnerPlayer commandSource', 'RunnerPlayer? target = null', 'string? message = null'] | {'target': 'null', 'message': 'null'} | +| UnlockSpawn | ['RunnerPlayer commandSource', 'RunnerPlayer? target = null', 'string? message = null'] | {'target': 'null', 'message': 'null'} | +| TeleportPlayerToMe | ['RunnerPlayer commandSource', 'RunnerPlayer target'] | {} | +| TeleportMeToPlayer | ['RunnerPlayer commandSource', 'RunnerPlayer target'] | {} | +| TeleportPlayerToPlayer | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'RunnerPlayer destination'] | {} | +| TeleportPlayerToPos | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'int x', 'int y', 'int z'] | {} | +| TeleportMeToPos | ['RunnerPlayer commandSource', 'int x', 'int y', 'int z'] | {} | +| Freeze | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Unfreeze | ['RunnerPlayer commandSource', 'RunnerPlayer target', 'string? message = null'] | {'message': 'null'} | +| Inspect | ['RunnerPlayer commandSource', 'RunnerPlayer? target = null'] | {'target': 'null'} | +| Task | ['RunnerPlayer player', 'ChatChannel channel', 'string msg'] | {} | +| Task | ['RunnerPlayer player', 'OnPlayerSpawnArguments request'] | {} | \ No newline at end of file diff --git a/ModuleUpdates.cs.md b/ModuleUpdates.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/PermissionsCommands.cs.md b/PermissionsCommands.cs.md new file mode 100644 index 0000000..288e29b --- /dev/null +++ b/PermissionsCommands.cs.md @@ -0,0 +1,25 @@ +# 1 Modules in PermissionsCommands.cs + +| Description | Version | +|:--------------------------------------------------------------|:----------| +| Provide addperm and removeperm commands for PlayerPermissions | 1.0.0 | + +## Commands +| Command | Function Name | Description | Allowed Roles | Parameters | Defaults | +|:-----------|:----------------|:-------------------------------------|:-----------------|:--------------------------------------------------------------------------|:-------------------------| +| addperm | void | Adds a permission to a player | Admin | ['RunnerPlayer commandSource', 'RunnerPlayer player', 'Roles permission'] | {} | +| removeperm | void | Removes a permission from a player | Admin | ['RunnerPlayer commandSource', 'RunnerPlayer player', 'Roles permission'] | {} | +| clearperms | void | Removes all permission from a player | Admin | ['RunnerPlayer commandSource', 'RunnerPlayer player'] | {} | +| listperms | void | Lists player permissions | Admin, Moderator | ['RunnerPlayer commandSource', 'RunnerPlayer? targetPlayer = null'] | {'targetPlayer': 'null'} | + +## Public Methods +| Function Name | Parameters | Defaults | +|:------------------------|:--------------------------------------------------------------------------|:-------------------------| +| | | | +| | | | +| | | | +| void | [''] | {} | +| AddPermissionCommand | ['RunnerPlayer commandSource', 'RunnerPlayer player', 'Roles permission'] | {} | +| RemovePermissionCommand | ['RunnerPlayer commandSource', 'RunnerPlayer player', 'Roles permission'] | {} | +| ClearPermissionCommand | ['RunnerPlayer commandSource', 'RunnerPlayer player'] | {} | +| ListPermissionCommand | ['RunnerPlayer commandSource', 'RunnerPlayer? targetPlayer = null'] | {'targetPlayer': 'null'} | \ No newline at end of file diff --git a/PlayerFinder.cs.md b/PlayerFinder.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/PlayerPermissions.cs.md b/PlayerPermissions.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/ProfanityFilter.cs.md b/ProfanityFilter.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/RichText.cs.md b/RichText.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/Rotation.cs.md b/Rotation.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/SpectateControl.cs.md b/SpectateControl.cs.md new file mode 100644 index 0000000..e69de29 diff --git a/Voting.cs.md b/Voting.cs.md new file mode 100644 index 0000000..626d7b5 --- /dev/null +++ b/Voting.cs.md @@ -0,0 +1,23 @@ +# 1 Modules in Voting.cs + +| Description | Version | +|:--------------------------|:----------| +| Simple chat voting system | 1.0.0 | + +## Commands +| Command | Function Name | Description | Allowed Roles | Parameters | Defaults | +|:----------|:----------------|:--------------------|:----------------|:----------------------------------------------------------------|:-----------| +| vote | void | Votes for an option | Moderator | ['RunnerPlayer commandSource', 'string text', 'string options'] | {} | + +## Public Methods +| Function Name | Parameters | Defaults | +|:-----------------|:----------------------------------------------------------------|:-----------| +| | | | +| | | | +| | | | +| | | | +| void | [''] | {} | +| StartVoteCommand | ['RunnerPlayer commandSource', 'string text', 'string options'] | {} | +| async | ['RunnerPlayer player', 'ChatChannel channel', 'string msg'] | {} | +| | | | +| | | | \ No newline at end of file From c9a2da076fc48e4ea072461278bdf6f00504009c Mon Sep 17 00:00:00 2001 From: Bluscream Date: Tue, 3 Oct 2023 01:35:48 +0200 Subject: [PATCH 04/22] rename role templates --- PlayerRolesFromGranularPermissions.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PlayerRolesFromGranularPermissions.cs b/PlayerRolesFromGranularPermissions.cs index f99d34a..410f919 100644 --- a/PlayerRolesFromGranularPermissions.cs +++ b/PlayerRolesFromGranularPermissions.cs @@ -42,8 +42,10 @@ public class PlayerRolesConfiguration : ModuleConfiguration { { "Role.Admin", Roles.Admin }, { "Role.Moderator", Roles.Moderator }, - { "Role.Modmin", Roles.Admin | Roles.Moderator } - }; + { "Role.Staff", Roles.Admin | Roles.Moderator }, + { "Role.Member", Roles.Admin | Roles.Moderator | Roles.Vip }, + { "Role.All", Roles.Admin | Roles.Moderator | Roles.Special | Roles.Vip } + }; public bool AppendRoles { get; set; } = false; } From 5db23198b42361d27c68e1d4a802139f25ba883c Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sat, 14 Oct 2023 02:39:33 +0200 Subject: [PATCH 05/22] ahh lol why --- LoadingScreenText.cs | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/LoadingScreenText.cs b/LoadingScreenText.cs index 4883982..c2cfaf5 100644 --- a/LoadingScreenText.cs +++ b/LoadingScreenText.cs @@ -1,22 +1,37 @@ -using BBRAPIModules; +using BattleBitAPI.Common; +using BBRAPIModules; +using Bluscream; +using System.Linq; using System.Threading.Tasks; namespace BattleBitBaseModules; +[RequireModule(typeof(Bluscream.BluscreamLib))] +[RequireModule(typeof(BattleBitBaseModules.RichText))] [Module("Configure the loading screen text of your server", "1.0.0")] public class LoadingScreenText : BattleBitModule { + [ModuleReference] public LoadingScreenTextConfiguration Configuration { get; set; } = null!; - public override Task OnConnected() - { - this.Server.LoadingScreenText = this.Configuration.LoadingScreenText; + public override Task OnConnected() { + UpdateLoadingScreenText(); return Task.CompletedTask; + } - return Task.CompletedTask; + public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { + UpdateLoadingScreenText(); return Task.CompletedTask; } -} -public class LoadingScreenTextConfiguration : ModuleConfiguration -{ - public string LoadingScreenText { get; set; } = "This is a community server!"; -} \ No newline at end of file + public void UpdateLoadingScreenText() { + this.Server.LoadingScreenText = this.Configuration.LoadingScreenText + .Replace("{server}", this.Server.ServerName) + .Replace("{gamemode}", this.Server.Gamemode.ToTitleCase()) + .Replace("{map}", this.Server.Map.ToTitleCase()) + .Replace("{players}", this.Server.AllPlayers.Count().ToString()) + .Replace("{slots}", this.Server.MaxPlayerCount.ToString()); + } + + public class LoadingScreenTextConfiguration : ModuleConfiguration { + public string LoadingScreenText { get; set; } = "<#87CEEB>Welcome to {server}<#87CEEB>!
We are currently playing {gamemode}<#87CEEB> on {map}<#87CEEB> with {players}<#87CEEB>/{slots}<#87CEEB> players!
Enjoy your stay!"; + } +} From 51d796b8ca76f4a5a1b00d6fb66f4d0fc4a79673 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sat, 14 Oct 2023 20:00:35 +0200 Subject: [PATCH 06/22] add SteamApi name fix to ChatOverwrites --- ChatOverwrite.cs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/ChatOverwrite.cs b/ChatOverwrite.cs index a783827..34c67d4 100644 --- a/ChatOverwrite.cs +++ b/ChatOverwrite.cs @@ -1,8 +1,10 @@ using BattleBitAPI.Common; using BBRAPIModules; +using Bluscream; using Permissions; using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -11,8 +13,14 @@ namespace ChatOverwrite; [RequireModule(typeof(GranularPermissions))] [Module("Overwrite chat messages", "1.0.0")] -public class ChatOverwrite : BattleBitModule -{ +public class ChatOverwrite : BattleBitModule { + + [ModuleReference] +#if DEBUG + public SteamApi? SteamApi { get; set; } = null!; +#else + public SteamApi? SteamApi { get; set; } +#endif public ChatOverwriteConfiguration Configuration { get; set; } = null!; [ModuleReference] @@ -74,12 +82,25 @@ public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel string textColor = channel == ChatChannel.TeamChat ? "blue" : (channel == ChatChannel.SquadChat ? "green" : "white"); - chatTarget.SayToChat(string.Format(overwriteMessage.Text, nameColor, player.Name, teamAndSquadIndicator, textColor, msg, gradientName)); + var playerName = GetPlayerName(player); + + chatTarget.SayToChat(string.Format(overwriteMessage.Text, nameColor, playerName, teamAndSquadIndicator, textColor, msg, gradientName)); } return Task.FromResult(false); } + public string GetPlayerName(RunnerPlayer player) { + if (SteamApi is not null) { + var steam = SteamApi.GetData(player)?.Result; + if (steam is not null && steam.Summary is not null) { + if (!string.IsNullOrWhiteSpace(steam.Summary.RealName)) return steam.Summary.RealName; + else if (!string.IsNullOrWhiteSpace(steam.Summary.PersonaName)) return steam.Summary.PersonaName; + } + } + return player.Name ?? player.SteamID.ToString(); + } + private static string FormatTextWithGradient(string text, string[] gradientColors) { if (string.IsNullOrEmpty(text) || gradientColors.Length == 0) From 093baade4eef5cead73961c380d82f45e1890c30 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sat, 14 Oct 2023 20:04:43 +0200 Subject: [PATCH 07/22] small improvement + add ChatOverwrite.Normal config --- ChatOverwrite.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ChatOverwrite.cs b/ChatOverwrite.cs index 34c67d4..2584f1d 100644 --- a/ChatOverwrite.cs +++ b/ChatOverwrite.cs @@ -93,7 +93,7 @@ public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel public string GetPlayerName(RunnerPlayer player) { if (SteamApi is not null) { var steam = SteamApi.GetData(player)?.Result; - if (steam is not null && steam.Summary is not null) { + if (steam?.Summary is not null) { if (!string.IsNullOrWhiteSpace(steam.Summary.RealName)) return steam.Summary.RealName; else if (!string.IsNullOrWhiteSpace(steam.Summary.PersonaName)) return steam.Summary.PersonaName; } @@ -133,6 +133,7 @@ public class ChatOverwriteConfiguration : ModuleConfiguration { public Dictionary Overwrites { get; set; } = new() { + { "ChatOverwrite.Normal", new("{1}{2} : {4}") }, { "ChatOverwrite.Rainbow", new("{5}{2} : {4}", new string[] { "red", "orange", "yellow", "green", "blue", "purple" }) }, { "ChatOverwrite.Large", new("{1}{2} : {4}") }, { "ChatOverwrite.Sus", new("{1}{2} : I am an idiot and cheat in online games. Please go to my Steam profile and report me!") }, From 37b0f9a10a4df817e4203ca24d8bba260c9094d8 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sat, 14 Oct 2023 20:23:57 +0200 Subject: [PATCH 08/22] added more default PermissionRoles --- PlayerRolesFromGranularPermissions.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PlayerRolesFromGranularPermissions.cs b/PlayerRolesFromGranularPermissions.cs index 410f919..a22ac36 100644 --- a/PlayerRolesFromGranularPermissions.cs +++ b/PlayerRolesFromGranularPermissions.cs @@ -42,7 +42,10 @@ public class PlayerRolesConfiguration : ModuleConfiguration { { "Role.Admin", Roles.Admin }, { "Role.Moderator", Roles.Moderator }, - { "Role.Staff", Roles.Admin | Roles.Moderator }, + { "Role.Staff", Roles.Admin | Roles.Moderator }, + { "Role.Vip", Roles.Vip }, + { "Role.Special", Roles.Special }, + { "Role.None", 0 }, { "Role.Member", Roles.Admin | Roles.Moderator | Roles.Vip }, { "Role.All", Roles.Admin | Roles.Moderator | Roles.Special | Roles.Vip } }; From 1003ff6768b0d3278771980ef87f47b61a080518 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sat, 14 Oct 2023 21:01:54 +0200 Subject: [PATCH 09/22] commandhandler update + chatoverwrite handle whitespace --- ChatOverwrite.cs | 2 +- CommandHandler.cs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChatOverwrite.cs b/ChatOverwrite.cs index 2584f1d..d3cdb41 100644 --- a/ChatOverwrite.cs +++ b/ChatOverwrite.cs @@ -98,7 +98,7 @@ public string GetPlayerName(RunnerPlayer player) { else if (!string.IsNullOrWhiteSpace(steam.Summary.PersonaName)) return steam.Summary.PersonaName; } } - return player.Name ?? player.SteamID.ToString(); + return string.IsNullOrWhiteSpace(player.Name) ? player.SteamID.ToString() : player.Name; } private static string FormatTextWithGradient(string text, string[] gradientColors) diff --git a/CommandHandler.cs b/CommandHandler.cs index 174ce51..8931cfe 100644 --- a/CommandHandler.cs +++ b/CommandHandler.cs @@ -320,6 +320,11 @@ private void handleCommand(RunnerPlayer? player, string message) { RunnerPlayer? targetPlayer = null; + if (ulong.TryParse(argument, out ulong steamId) && this.Server.AllPlayers.FirstOrDefault(p => p.SteamID == steamId) is RunnerPlayer playerBySteamId) { + args[i] = targetPlayer; + continue; + } + if (this.PlayerFinder is not null) { try From abd2eecb1d9a7ca3bfbf083c02ba8d06c97d8267 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sat, 14 Oct 2023 23:08:46 +0200 Subject: [PATCH 10/22] add color reset --- RichText.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/RichText.cs b/RichText.cs index ff60bd0..7c8a223 100644 --- a/RichText.cs +++ b/RichText.cs @@ -158,8 +158,9 @@ public static class Alignments public static readonly string None = ""; } -public static class Colors -{ +public static class Colors { + public static readonly string None = ""; + public static readonly string Reset = ""; public static readonly string Black = ""; public static readonly string Blue = ""; public static readonly string Brown = ""; From 0bddfe2e943880ca21d9a3efa8fdc61948dfcdb7 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sun, 15 Oct 2023 03:11:19 +0200 Subject: [PATCH 11/22] add maptime + use richtext --- LoadingScreenText.cs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/LoadingScreenText.cs b/LoadingScreenText.cs index c2cfaf5..c6f302c 100644 --- a/LoadingScreenText.cs +++ b/LoadingScreenText.cs @@ -1,6 +1,8 @@ using BattleBitAPI.Common; using BBRAPIModules; using Bluscream; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -12,7 +14,7 @@ namespace BattleBitBaseModules; public class LoadingScreenText : BattleBitModule { [ModuleReference] - public LoadingScreenTextConfiguration Configuration { get; set; } = null!; + public LoadingScreenTextConfiguration Config { get; set; } = null!; public override Task OnConnected() { UpdateLoadingScreenText(); return Task.CompletedTask; @@ -22,16 +24,33 @@ public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArgumen UpdateLoadingScreenText(); return Task.CompletedTask; } + public override Task OnGameStateChanged(GameState oldState, GameState newState) { + UpdateLoadingScreenText(); return Task.CompletedTask; + } + public void UpdateLoadingScreenText() { - this.Server.LoadingScreenText = this.Configuration.LoadingScreenText + var newText = this.Config.LoadingScreenText .Replace("{server}", this.Server.ServerName) - .Replace("{gamemode}", this.Server.Gamemode.ToTitleCase()) - .Replace("{map}", this.Server.Map.ToTitleCase()) + .Replace("{gamemode}", this.Server.GetCurrentGameMode().DisplayName) + .Replace("{map}", this.Server.GetCurrentMap().DisplayName) + .Replace("{maptime}", this.Server.DayNight.ToString().ToTitleCase()) .Replace("{players}", this.Server.AllPlayers.Count().ToString()) .Replace("{slots}", this.Server.MaxPlayerCount.ToString()); + + foreach (var replacement in Config.randomReplacements) { + newText = newText.Replace($"{{random.{replacement.Key}}}", replacement.Value[Random.Shared.Next(replacement.Value.Length)]); + } + + this.Server.LoadingScreenText = newText; } public class LoadingScreenTextConfiguration : ModuleConfiguration { - public string LoadingScreenText { get; set; } = "<#87CEEB>Welcome to {server}<#87CEEB>!
We are currently playing {gamemode}<#87CEEB> on {map}<#87CEEB> with {players}<#87CEEB>/{slots}<#87CEEB> players!
Enjoy your stay!"; + public Dictionary randomReplacements = new Dictionary() { + { "welcome", new string[] { "Enjoy your stay!", "Have a good one!", "Get Ready for battle!" } }, + }; + public string LoadingScreenText { get; set; } = +@$"{Colors.SkyBlue}Welcome to {Colors.None}{{server}}{Colors.SkyBlue}! +We are currently playing {Colors.None}{{gamemode}}{Colors.SkyBlue} on {Colors.None}{{map}}{Colors.SkyBlue} at {Colors.None}{{maptime}}{Colors.SkyBlue} with {Colors.None}{{players}}{Colors.SkyBlue}/{Colors.None}{{slots}}{Colors.SkyBlue} players! +{{random.welcome}}"; } } From 98c63805b53b8ddc17eb825161d8ddc402dbfc15 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Mon, 16 Oct 2023 01:40:03 +0200 Subject: [PATCH 12/22] prep for commandhandler rewrite more loadingscreentext improvements --- CommandHandler.cs | 37 +++++++++++++++++++++++++++++++++++++ LoadingScreenText.cs | 38 +++++++++++++++++++++++++++----------- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/CommandHandler.cs b/CommandHandler.cs index 8931cfe..7c8f5ee 100644 --- a/CommandHandler.cs +++ b/CommandHandler.cs @@ -11,6 +11,43 @@ namespace Commands; +public enum CommandSource { + Unknown, + Chat, + Console, + Custom +} + +public struct CommandInvoker { + public RunnerPlayer? Player; + public string Name { get { + return Player?.Name ?? "Unknown"; + } } +} + +public struct CommandContext { + public CommandSource CommandSource { get; set; } + public string Target { get; set; } + public CommandInvoker Invoker { get; set; } + public RunnerServer? Server { get; set; } + + public bool Reply(string message) { + var success = false; + switch (CommandSource) { + case CommandSource.Chat: + try { Invoker.Player?.SayToChat(message); success = true; } catch (Exception ex) { Log("Could not respond to player!"); } + break; + case CommandSource.Custom: + // Custom Implementation with callbacks maybe + break; + default: + Log(message); success = true; + break; + } + return success; + } +} + [Module("Basic in-game chat command handler library", "1.1.0")] public class CommandHandler : BattleBitModule { diff --git a/LoadingScreenText.cs b/LoadingScreenText.cs index c6f302c..3eb41ed 100644 --- a/LoadingScreenText.cs +++ b/LoadingScreenText.cs @@ -17,19 +17,30 @@ public class LoadingScreenText : BattleBitModule public LoadingScreenTextConfiguration Config { get; set; } = null!; public override Task OnConnected() { - UpdateLoadingScreenText(); return Task.CompletedTask; + UpdateLoadingScreenText(this.Config.ConnectLoadingScreenText); return Task.CompletedTask; } - public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { - UpdateLoadingScreenText(); return Task.CompletedTask; + UpdateLoadingScreenText(this.Config.ConnectLoadingScreenText); return Task.CompletedTask; } - - public override Task OnGameStateChanged(GameState oldState, GameState newState) { - UpdateLoadingScreenText(); return Task.CompletedTask; + public override Task OnRoundEnded() { + UpdateLoadingScreenText(this.Config.MapChangeLoadingScreenText); return Task.CompletedTask; } + //public override Task OnSessionChanged(long oldSessionID, long newSessionID) { + // UpdateLoadingScreenText(this.Config.MapChangeLoadingScreenText); return Task.CompletedTask; + //} + //public override Task OnGameStateChanged(GameState oldState, GameState newState) { + // switch (newState) { + // case GameState.EndingGame: + // UpdateLoadingScreenText(this.Config.MapChangeLoadingScreenText); + // break; + // default: + // UpdateLoadingScreenText(this.Config.ConnectLoadingScreenText); + // break; + // } + // return Task.CompletedTask; + //} - public void UpdateLoadingScreenText() { - var newText = this.Config.LoadingScreenText + public string FormatText(string input) => input .Replace("{server}", this.Server.ServerName) .Replace("{gamemode}", this.Server.GetCurrentGameMode().DisplayName) .Replace("{map}", this.Server.GetCurrentMap().DisplayName) @@ -37,20 +48,25 @@ public void UpdateLoadingScreenText() { .Replace("{players}", this.Server.AllPlayers.Count().ToString()) .Replace("{slots}", this.Server.MaxPlayerCount.ToString()); + public void UpdateLoadingScreenText(string template) { + var newText = FormatText(template); foreach (var replacement in Config.randomReplacements) { - newText = newText.Replace($"{{random.{replacement.Key}}}", replacement.Value[Random.Shared.Next(replacement.Value.Length)]); + newText = newText.Replace($"{{random.{replacement.Key}}}", FormatText(replacement.Value[Random.Shared.Next(replacement.Value.Length)])); } - this.Server.LoadingScreenText = newText; + this.Logger.Warn($"Changed Loading Screen Text:\n{this.Server.LoadingScreenText}"); } public class LoadingScreenTextConfiguration : ModuleConfiguration { public Dictionary randomReplacements = new Dictionary() { { "welcome", new string[] { "Enjoy your stay!", "Have a good one!", "Get Ready for battle!" } }, }; - public string LoadingScreenText { get; set; } = + public string ConnectLoadingScreenText { get; set; } = @$"{Colors.SkyBlue}Welcome to {Colors.None}{{server}}{Colors.SkyBlue}! We are currently playing {Colors.None}{{gamemode}}{Colors.SkyBlue} on {Colors.None}{{map}}{Colors.SkyBlue} at {Colors.None}{{maptime}}{Colors.SkyBlue} with {Colors.None}{{players}}{Colors.SkyBlue}/{Colors.None}{{slots}}{Colors.SkyBlue} players! +{{random.welcome}}"; + public string MapChangeLoadingScreenText { get; set; } = +@$"{Colors.SkyBlue}Welcome to {Colors.None}{{server}}{Colors.SkyBlue}! {{random.welcome}}"; } } From 1643e9531d71145cec056801e000f7696cf3bf28 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Tue, 17 Oct 2023 07:21:24 +0200 Subject: [PATCH 13/22] make BasicProgression gr8 again --- BasicProgression.cs | 150 +++++++++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 66 deletions(-) diff --git a/BasicProgression.cs b/BasicProgression.cs index 60c2004..e2b03c6 100644 --- a/BasicProgression.cs +++ b/BasicProgression.cs @@ -2,91 +2,109 @@ using BBRAPIModules; using System; using System.IO; +using System.Text.Json; using System.Threading.Tasks; +using Bluscream; +using System.Text.Json.Serialization; +using System.ComponentModel.Design; -namespace BattleBitBaseModules; +namespace BattleBitBaseModules { -[Module("Provide basic persistent progression for players", "1.1.0")] -public class BasicProgression : BattleBitModule -{ - public BasicProgressionConfiguration Configuration { get; set; } = null!; + [RequireModule(typeof(BluscreamLib))] + [Module("Provide basic persistent progression for players", "1.1.0")] + public class BasicProgression : BattleBitModule { + [ModuleReference] + public BluscreamLib BluscreamLib { get; set; } = null!; - private string dataDir => this.Configuration.PerServer ? Path.Combine(this.Configuration.DataDirectory, $"{this.Server.GameIP}:{this.Server.GamePort}") : this.Configuration.DataDirectory; + public Configuration GlobalConfiguration { get; set; } = null!; - public override Task OnConnected() - { - if (!Directory.Exists(dataDir)) - { - Directory.CreateDirectory(dataDir); - } + public DirectoryInfo DataDir => new DirectoryInfo(GlobalConfiguration.PerServer ? Path.Combine(GlobalConfiguration.DataDirectory, $"{this.Server.GameIP}:{this.Server.GamePort}") : GlobalConfiguration.DataDirectory); - return Task.CompletedTask; - } + public override Task OnConnected() { + if (!DataDir.Exists) { + DataDir.Create(); + } - public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) - { - if (this.Configuration.ApplyInitialStatsOnEveryJoin) - { - args.Stats = this.Configuration.InitialStats ?? args.Stats; - return; + return Task.CompletedTask; } - string playerFileName = getPlayerFileName(steamID); - for (int i = 0; i < 5; i++) - { - try - { - args.Stats = File.Exists(playerFileName) ? new PlayerStats(File.ReadAllBytes(playerFileName)) : (this.Configuration.InitialStats ?? args.Stats); + public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { + Console.WriteLine("OnPlayerJoiningToServer"); + if (GlobalConfiguration.ApplyInitialStatsOnEveryJoin) { + this.Logger.Info(args.Stats.str()); + this.Logger.Info(args.Stats.ToJson()); + args.Stats = GlobalConfiguration.InitialStats ?? args.Stats; + this.Logger.Info($"Applied initial player stats for {steamID}"); + this.Logger.Info(args.Stats.str()); + this.Logger.Info(args.Stats.ToJson()); + args.Stats.Progress.Rank = 201; + this.Logger.Info(args.Stats.str()); + this.Logger.Info(args.Stats.ToJson()); return; } - catch (Exception ex) - { - this.Logger.Error($"Tried {i} times to read from file {playerFileName} but failed:{ex}"); + + var playerFile = getPlayerFile(steamID); + for (int i = 0; i < 5; i++) { + try { + if (playerFile.Exists) { + args.Stats = GlobalConfiguration.PlainText ? JsonUtils.FromJsonFile(playerFile) : new PlayerStats(File.ReadAllBytes(playerFile.FullName)); + this.Logger.Info($"Read player stats for {steamID} from \"{playerFile.FullName}\""); + } else { + args.Stats = (GlobalConfiguration.InitialStats ?? args.Stats); + this.Logger.Info($"Applied initial player stats for {steamID}"); + } + return; + } catch (Exception ex) { + this.Logger.Error($"Tried {i} times to read from file {playerFile.FullName} but failed:{ex}"); + } + await Task.Delay(250); } - await Task.Delay(250); + this.Logger.Error($"Giving up trying to read \"{playerFile.FullName}\""); } - this.Logger.Error("Giving up trying to read."); - } - public override async Task OnSavePlayerStats(ulong steamID, PlayerStats stats) - { - for (int i = 0; i < 5; i++) - { - try - { - File.WriteAllBytes(getPlayerFileName(steamID), stats.SerializeToByteArray()); - return; - } - catch (Exception ex) - { - this.Logger.Error($"Tried {i} times to write to file {getPlayerFileName(steamID)} but failed:{ex}"); + public override async Task OnSavePlayerStats(ulong steamID, PlayerStats stats) { + Console.WriteLine("OnSavePlayerStats"); + this.Logger.Info(stats.str()); + this.Logger.Info(stats.ToJson()); + for (int i = 0; i < 5; i++) { + try { + var playerFile = getPlayerFile(steamID); + if (GlobalConfiguration.PlainText) { + stats.ToJsonFile(playerFile, indented: true); + } else { + playerFile.WriteAllBytes(stats.SerializeToByteArray()); + } + this.Logger.Info($"Wrote player stats for {steamID} to \"{playerFile}\""); + return; + } catch (Exception ex) { + this.Logger.Error($"Tried {i} times to write to file {getPlayerFile(steamID)} but failed:{ex}"); + } + await Task.Delay(250); } - await Task.Delay(250); + this.Logger.Error("Giving up trying to save."); } - this.Logger.Error("Giving up trying to save."); - } - private string getPlayerFileName(ulong steamId) - { - return Path.Combine(dataDir, $"{steamId}.bin"); - } -} + private FileInfo getPlayerFile(ulong steamId) { + return new FileInfo(Path.Combine(DataDir.FullName, $"{steamId}.bin")); + } -public class BasicProgressionConfiguration : ModuleConfiguration -{ - public string DataDirectory { get; set; } = "./data/PersistentProgressionFiles"; + public class Configuration : ModuleConfiguration { + public string DataDirectory { get; set; } = "./data/PersistentProgressionFiles"; - public bool PerServer { get; set; } = false; + public bool PlainText { get; set; } = false; - public bool ApplyInitialStatsOnEveryJoin { get; set; } = false; + public bool PerServer { get; set; } = false; - public PlayerStats? InitialStats { get; set; } = new PlayerStats() - { - Achievements = new byte[0], - IsBanned = false, - Progress = new PlayerStats.PlayerProgess(), - Roles = Roles.None, - Selections = new byte[0], - ToolProgress = new byte[0] - }; + public bool ApplyInitialStatsOnEveryJoin { get; set; } = false; + + public PlayerStats InitialStats = new PlayerStats() { + Achievements = new byte[0], + IsBanned = false, + Progress = new PlayerStats.PlayerProgess(), + Roles = Roles.None, + Selections = new byte[0], + ToolProgress = new byte[0] + }; + } + } } \ No newline at end of file From fc8b3eb83309a174f2ece7d3649cc374dac97449 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Thu, 19 Oct 2023 02:30:57 +0200 Subject: [PATCH 14/22] rw chatoverwrite for timestamp --- ChatOverwrite.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ChatOverwrite.cs b/ChatOverwrite.cs index d3cdb41..478b4ed 100644 --- a/ChatOverwrite.cs +++ b/ChatOverwrite.cs @@ -4,7 +4,6 @@ using Permissions; using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -84,7 +83,9 @@ public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel var playerName = GetPlayerName(player); - chatTarget.SayToChat(string.Format(overwriteMessage.Text, nameColor, playerName, teamAndSquadIndicator, textColor, msg, gradientName)); + var now = string.IsNullOrWhiteSpace(Configuration.TimeStampFormat) ? "" : new DateTimeWithZone(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById(Configuration.TimeZone)).LocalTime.ToString(Configuration.TimeStampFormat); + + chatTarget.SayToChat(string.Format(overwriteMessage.Text, nameColor, playerName, teamAndSquadIndicator, textColor, msg, gradientName, now)); } return Task.FromResult(false); @@ -129,15 +130,17 @@ private static string FormatTextWithGradient(string text, string[] gradientColor } } -public class ChatOverwriteConfiguration : ModuleConfiguration -{ +public class ChatOverwriteConfiguration : ModuleConfiguration { + public string TimeStampFormat { get; set; } = "HH:mm:ss"; + [Obsolete] + public string TimeZone { get; set; } = System.TimeZone.CurrentTimeZone.StandardName; public Dictionary Overwrites { get; set; } = new() { - { "ChatOverwrite.Normal", new("{1}{2} : {4}") }, + { "ChatOverwrite.Normal", new("[6] {1}{2} : {4}") }, { "ChatOverwrite.Rainbow", new("{5}{2} : {4}", new string[] { "red", "orange", "yellow", "green", "blue", "purple" }) }, { "ChatOverwrite.Large", new("{1}{2} : {4}") }, { "ChatOverwrite.Sus", new("{1}{2} : I am an idiot and cheat in online games. Please go to my Steam profile and report me!") }, - { "ChatOverwrite.Admin", new("{1}{2}[Server Admin] : {4}") } + { "ChatOverwrite.Admin", new("[6] {1}{2}[Server Admin] : {4}") } }; } From bda33abbf29757391a922c7dee9584f795e2db94 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Thu, 19 Oct 2023 05:53:08 +0200 Subject: [PATCH 15/22] merge from base --- BasicProgression.cs | 222 ++++++++++++++--- BasicServerSettings.cs | 5 +- CommandHandler.cs | 337 +++++++++++++++++--------- DiscordWebhooks.cs | 2 +- GeoLimiter.cs | 13 +- GranularPermissionsCommands.cs | 137 ++++++----- MOTD.cs | 49 +++- ModeratorTools.cs | 256 ++++++++++++------- PasswordReservedSlots.cs | 91 +++++++ PermissionsCommands.cs | 23 +- PlayerRolesFromGranularPermissions.cs | 46 ++-- RichText.cs | 1 - Voting.cs | 10 +- 13 files changed, 833 insertions(+), 359 deletions(-) create mode 100644 PasswordReservedSlots.cs diff --git a/BasicProgression.cs b/BasicProgression.cs index e2b03c6..285db37 100644 --- a/BasicProgression.cs +++ b/BasicProgression.cs @@ -4,19 +4,14 @@ using System.IO; using System.Text.Json; using System.Threading.Tasks; -using Bluscream; -using System.Text.Json.Serialization; -using System.ComponentModel.Design; +using static BattleBitAPI.Common.PlayerStats; namespace BattleBitBaseModules { - [RequireModule(typeof(BluscreamLib))] - [Module("Provide basic persistent progression for players", "1.1.0")] - public class BasicProgression : BattleBitModule { - [ModuleReference] - public BluscreamLib BluscreamLib { get; set; } = null!; - - public Configuration GlobalConfiguration { get; set; } = null!; +[Module("Provide basic persistent progression for players", "1.1.1")] +public class BasicProgression : BattleBitModule +{ + public BasicProgressionConfiguration Configuration { get; set; } = null!; public DirectoryInfo DataDir => new DirectoryInfo(GlobalConfiguration.PerServer ? Path.Combine(GlobalConfiguration.DataDirectory, $"{this.Server.GameIP}:{this.Server.GamePort}") : GlobalConfiguration.DataDirectory); @@ -28,18 +23,20 @@ public override Task OnConnected() { return Task.CompletedTask; } - public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { - Console.WriteLine("OnPlayerJoiningToServer"); - if (GlobalConfiguration.ApplyInitialStatsOnEveryJoin) { - this.Logger.Info(args.Stats.str()); - this.Logger.Info(args.Stats.ToJson()); - args.Stats = GlobalConfiguration.InitialStats ?? args.Stats; - this.Logger.Info($"Applied initial player stats for {steamID}"); - this.Logger.Info(args.Stats.str()); - this.Logger.Info(args.Stats.ToJson()); - args.Stats.Progress.Rank = 201; - this.Logger.Info(args.Stats.str()); - this.Logger.Info(args.Stats.ToJson()); + public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) + { + if (this.Configuration.ApplyInitialStatsOnEveryJoin) + { + args.Stats = this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats; + return; + } + + string playerFileName = getPlayerFileName(steamID); + for (int i = 0; i < 5; i++) + { + try + { + args.Stats = File.Exists(playerFileName) ? new PlayerStats(File.ReadAllBytes(playerFileName)) : (this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats); return; } @@ -97,14 +94,177 @@ public class Configuration : ModuleConfiguration { public bool ApplyInitialStatsOnEveryJoin { get; set; } = false; - public PlayerStats InitialStats = new PlayerStats() { - Achievements = new byte[0], - IsBanned = false, - Progress = new PlayerStats.PlayerProgess(), - Roles = Roles.None, - Selections = new byte[0], - ToolProgress = new byte[0] - }; - } + public BasicPlayerStats? InitialStats { get; set; } = new BasicPlayerStats() + { + Achievements = new byte[0], + IsBanned = false, + Progress = new BasicPlayerProgress(), + Roles = Roles.None, + Selections = new byte[0], + ToolProgress = new byte[0] + }; +} + +public class BasicPlayerStats +{ + public bool IsBanned { get; set; } + + public Roles Roles { get; set; } + + public BasicPlayerProgress Progress { get; set; } = new(); + + public byte[] ToolProgress { get; set; } = Array.Empty(); + + public byte[] Achievements { get; set; } = Array.Empty(); + + public byte[] Selections { get; set; } = Array.Empty(); + + public PlayerStats ToPlayerStats() + { + return new() + { + IsBanned = this.IsBanned, + Roles = this.Roles, + Progress = this.Progress.ToPlayerProgress(), + ToolProgress = this.ToolProgress, + Achievements = this.Achievements, + Selections = this.Selections + }; + } +} + +public class BasicPlayerProgress +{ + public uint KillCount { get; set; } + + public uint LeaderKills { get; set; } + + public uint AssaultKills { get; set; } + + public uint MedicKills { get; set; } + + public uint EngineerKills { get; set; } + + public uint SupportKills { get; set; } + + public uint ReconKills { get; set; } + + public uint DeathCount { get; set; } + + public uint WinCount { get; set; } + + public uint LoseCount { get; set; } + + public uint FriendlyShots { get; set; } + + public uint FriendlyKills { get; set; } + + public uint Revived { get; set; } + + public uint RevivedTeamMates { get; set; } + + public uint Assists { get; set; } + + public uint Prestige { get; set; } + + public uint Rank { get; set; } + + public uint EXP { get; set; } + + public uint ShotsFired { get; set; } + + public uint ShotsHit { get; set; } + + public uint Headshots { get; set; } + + public uint ObjectivesComplated { get; set; } + + public uint HealedHPs { get; set; } + + public uint RoadKills { get; set; } + + public uint Suicides { get; set; } + + public uint VehiclesDestroyed { get; set; } + + public uint VehicleHPRepaired { get; set; } + + public uint LongestKill { get; set; } + + public uint PlayTimeSeconds { get; set; } + + public uint LeaderPlayTime { get; set; } + + public uint AssaultPlayTime { get; set; } + + public uint MedicPlayTime { get; set; } + + public uint EngineerPlayTime { get; set; } + + public uint SupportPlayTime { get; set; } + + public uint ReconPlayTime { get; set; } + + public uint LeaderScore { get; set; } + + public uint AssaultScore { get; set; } + + public uint MedicScore { get; set; } + + public uint EngineerScore { get; set; } + + public uint SupportScore { get; set; } + + public uint ReconScore { get; set; } + + public uint TotalScore { get; set; } + + public PlayerProgess ToPlayerProgress() + { + return new() + { + KillCount = this.KillCount, + LeaderKills = this.LeaderKills, + AssaultKills = this.AssaultKills, + MedicKills = this.MedicKills, + EngineerKills = this.EngineerKills, + SupportKills = this.SupportKills, + ReconKills = this.ReconKills, + DeathCount = this.DeathCount, + WinCount = this.WinCount, + LoseCount = this.LoseCount, + FriendlyShots = this.FriendlyShots, + FriendlyKills = this.FriendlyKills, + Revived = this.Revived, + RevivedTeamMates = this.RevivedTeamMates, + Assists = this.Assists, + Prestige = this.Prestige, + Rank = this.Rank, + EXP = this.EXP, + ShotsFired = this.ShotsFired, + ShotsHit = this.ShotsHit, + Headshots = this.Headshots, + ObjectivesComplated = this.ObjectivesComplated, + HealedHPs = this.HealedHPs, + RoadKills = this.RoadKills, + Suicides = this.Suicides, + VehiclesDestroyed = this.VehiclesDestroyed, + VehicleHPRepaired = this.VehicleHPRepaired, + LongestKill = this.LongestKill, + PlayTimeSeconds = this.PlayTimeSeconds, + LeaderPlayTime = this.LeaderPlayTime, + AssaultPlayTime = this.AssaultPlayTime, + MedicPlayTime = this.MedicPlayTime, + EngineerPlayTime = this.EngineerPlayTime, + SupportPlayTime = this.SupportPlayTime, + ReconPlayTime = this.ReconPlayTime, + LeaderScore = this.LeaderScore, + AssaultScore = this.AssaultScore, + MedicScore = this.MedicScore, + EngineerScore = this.EngineerScore, + SupportScore = this.SupportScore, + ReconScore = this.ReconScore, + TotalScore = this.TotalScore + }; } } \ No newline at end of file diff --git a/BasicServerSettings.cs b/BasicServerSettings.cs index e97a5e3..0dfa2b1 100644 --- a/BasicServerSettings.cs +++ b/BasicServerSettings.cs @@ -1,7 +1,6 @@ using BattleBitAPI.Common; using BBRAPIModules; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Threading.Tasks; namespace BattleBitBaseModules; @@ -166,13 +165,13 @@ public class BasicServerSettingsConfiguration : ModuleConfiguration public bool? Freeze { get; set; } = null; public float? ReviveHP { get; set; } = null; - public Dictionary RoundSettings { get; set; } = new(new Dictionary() + public Dictionary RoundSettings { get; set; } = new() { { GameState.WaitingForPlayers, new() }, { GameState.CountingDown, new() }, { GameState.Playing, new() }, { GameState.EndingGame, new() } - }); + }; } public class RoundSettingsConfiguration diff --git a/CommandHandler.cs b/CommandHandler.cs index 7c8f5ee..32e1d99 100644 --- a/CommandHandler.cs +++ b/CommandHandler.cs @@ -11,48 +11,11 @@ namespace Commands; -public enum CommandSource { - Unknown, - Chat, - Console, - Custom -} - -public struct CommandInvoker { - public RunnerPlayer? Player; - public string Name { get { - return Player?.Name ?? "Unknown"; - } } -} - -public struct CommandContext { - public CommandSource CommandSource { get; set; } - public string Target { get; set; } - public CommandInvoker Invoker { get; set; } - public RunnerServer? Server { get; set; } - - public bool Reply(string message) { - var success = false; - switch (CommandSource) { - case CommandSource.Chat: - try { Invoker.Player?.SayToChat(message); success = true; } catch (Exception ex) { Log("Could not respond to player!"); } - break; - case CommandSource.Custom: - // Custom Implementation with callbacks maybe - break; - default: - Log(message); success = true; - break; - } - return success; - } -} - -[Module("Basic in-game chat command handler library", "1.1.0")] +[Module("Basic in-game chat command handler library", "1.1.1")] public class CommandHandler : BattleBitModule { public static CommandConfiguration CommandConfiguration { get; set; } = null!; - public CommandPermissions CommandPermissions { get; set; } = null!; + public CommandSettings CommandSettings { get; set; } = null!; private Dictionary commandCallbacks = new(); @@ -95,16 +58,24 @@ public void Register(BattleBitModule module) } // Store command permissions - if (!this.CommandPermissions.Permissions.ContainsKey(attribute.Name)) + if (!this.CommandSettings.Settings.ContainsKey(attribute.Name)) { - this.CommandPermissions.Permissions.Add(attribute.Name, null); + this.CommandSettings.Settings.Add(attribute.Name, new()); } // Validate parameter ParameterInfo[] parameters = method.GetParameters(); - if (parameters.Length > 0 && parameters[0].ParameterType != typeof(RunnerPlayer)) + + if (parameters.Length == 0) { - throw new Exception($"Command callback method {method.Name} in module {module.GetType().Name} has invalid first parameter. Must be of type RunnerPlayer."); + this.Logger.Error($"Command callback method {method.Name} in module {module.GetType().Name} has no parameters. Must have at least one parameter of type Context."); + continue; + } + + if (parameters[0].ParameterType != typeof(Context)) + { + this.Logger.Error($"Command callback method {method.Name} in module {module.GetType().Name} has invalid first parameter. Must be of type Context."); + continue; } string command = attribute.Name.Trim().ToLower(); @@ -119,11 +90,13 @@ public void Register(BattleBitModule module) if (this.commandCallbacks[command].Module.GetType().Name == module.GetType().Name) { - throw new Exception($"Command callback method {method.Name} in module {module.GetType().Name} has the same command name {command} as another command callback method {this.commandCallbacks[command].Method.Name} in the same module."); + this.Logger.Error($"Command callback method {method.Name} in module {module.GetType().Name} has the same command name {command} as another command callback method {this.commandCallbacks[command].Method.Name} in the same module."); + continue; } else { - throw new Exception($"Command callback method {method.Name} in module {module.GetType().Name} has the same command name {command} as command callback method {this.commandCallbacks[command].Method.Name} in module {this.commandCallbacks[command].Module.GetType().Name}."); + this.Logger.Error($"Command callback method {method.Name} in module {module.GetType().Name} has the same command name {command} as command callback method {this.commandCallbacks[command].Method.Name} in module {this.commandCallbacks[command].Module.GetType().Name}."); + continue; } } @@ -135,7 +108,8 @@ public void Register(BattleBitModule module) continue; } - throw new Exception($"Command callback {command} in module {module.GetType().Name} conflicts with subcommand {subcommand}."); + this.Logger.Error($"Command callback {command} in module {module.GetType().Name} conflicts with subcommand {subcommand}."); + continue; } // Prevent subcommands of existing commands (!perm add and !perm remove do not allow !perm) @@ -148,7 +122,8 @@ public void Register(BattleBitModule module) subcommand += $"{subcommandChain[i]} "; if (this.commandCallbacks.ContainsKey(subcommand.Trim())) { - throw new Exception($"Command callback {command} in module {module.GetType().Name} conflicts with parent command {subcommand.Trim()}."); + this.Logger.Error($"Command callback {command} in module {module.GetType().Name} conflicts with parent command {subcommand.Trim()}."); + continue; } } } @@ -156,7 +131,7 @@ public void Register(BattleBitModule module) this.commandCallbacks.Add(command, (module, method)); } - this.CommandPermissions.Save(); + this.CommandSettings.Save(); } public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string message) @@ -166,7 +141,7 @@ public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel return Task.FromResult(true); } - Task.Run(() => this.handleCommand(player, message)); + Task.Run(() => this.HandleCommand(new ChatSource(player), message)); return Task.FromResult(false); } @@ -178,7 +153,7 @@ public override void OnConsoleCommand(string command) return; } - Task.Run(() => this.handleCommand(null, command)); + Task.Run(() => this.HandleCommand(new ConsoleSource(), command)); } public bool IsCommand(string message) @@ -226,14 +201,9 @@ public bool HasPermissionForCommand(RunnerPlayer player, CommandCallbackAttribut // Permission overwrites from configuration file string[] requiredPermissions = attribute.Permissions; - if (!this.CommandPermissions.Permissions.ContainsKey(attribute.Name)) - { - this.Logger.Error($"Command {attribute.Name} has no permissions stored in the CommandPermissions configuration file. This should not happen, report the bug."); - } - - if (this.CommandPermissions.Permissions.ContainsKey(attribute.Name) && this.CommandPermissions.Permissions[attribute.Name] is not null) + if (this.CommandSettings.Settings.ContainsKey(attribute.Name) && this.CommandSettings.Settings.ContainsKey(attribute.Name) && this.CommandSettings.Settings[attribute.Name]?.Permissions is not null) { - requiredPermissions = this.CommandPermissions.Permissions[attribute.Name]!; + requiredPermissions = this.CommandSettings.Settings[attribute.Name]!.Permissions!; } // PlayerPermissions module @@ -270,11 +240,14 @@ public bool HasPermissionForCommand(RunnerPlayer player, CommandCallbackAttribut return false; } - private void handleCommand(RunnerPlayer? player, string message) + public void HandleCommand(Source source, string message) { string[] fullCommand = parseCommandString(message); string command = fullCommand[0].Trim().ToLower()[CommandConfiguration.CommandPrefix.Length..]; + ChatSource? chatSource = source as ChatSource; + Context errorContext = new Context(source, message, command, Array.Empty(), Array.Empty(), null, this, null); + int subCommandSkip; for (subCommandSkip = 1; subCommandSkip < fullCommand.Length && !this.commandCallbacks.ContainsKey(command); subCommandSkip++) { @@ -283,13 +256,13 @@ private void handleCommand(RunnerPlayer? player, string message) if (!this.commandCallbacks.ContainsKey(command)) { - if (player is null) + if (chatSource is not null) { - this.Logger.Error($"Command not found: {command}"); + errorContext.Reply($"Command not found: {command}"); } else { - player.Message("Command not found"); + errorContext.Reply($"Command not found: {command}"); } return; } @@ -299,43 +272,41 @@ private void handleCommand(RunnerPlayer? player, string message) (BattleBitModule module, MethodInfo method) = this.commandCallbacks[command]; CommandCallbackAttribute commandCallbackAttribute = method.GetCustomAttribute()!; - if (player is null && !commandCallbackAttribute.ConsoleCommand) + if (source is ConsoleSource && !commandCallbackAttribute.ConsoleCommand) { this.Logger.Error($"Command {command} is not a console command."); return; } // Permissions - if (player is not null && !this.HasPermissionForCommand(player, commandCallbackAttribute)) + if (chatSource is not null && !this.HasPermissionForCommand(chatSource.Invoker, commandCallbackAttribute)) { - player.Message($"You don't have permission to use this command.{Environment.NewLine}Required permission: {string.Join(" or ", commandCallbackAttribute.Permissions)}"); - return; - } + bool hideInaccessible = CommandConfiguration.HideInaccessibleCommands; + if (this.CommandSettings.Settings[command]?.HideInaccessible is not null) + { + hideInaccessible = this.CommandSettings.Settings[command]!.HideInaccessible!.Value; + } - ParameterInfo[] parameters = method.GetParameters(); + if (hideInaccessible) + { + errorContext.Reply($"Command not found: {command}"); + return; + } - if (parameters.Length == 0) - { - method.Invoke(module, null); + errorContext.Reply($"You don't have permission to use this command.{Environment.NewLine}Required permission: {string.Join(" or ", commandCallbackAttribute.Permissions)}"); return; } + ParameterInfo[] parameters = method.GetParameters(); + bool hasOptional = parameters.Any(p => p.IsOptional); if (fullCommand.Length - 1 < parameters.Skip(1).Count(p => !p.IsOptional) || fullCommand.Length - 1 > parameters.Length - 1) { - if (player is not null) - { - messagePlayerCommandUsage(player, method, $"Require {(hasOptional ? $"between {parameters.Skip(1).Count(p => !p.IsOptional)} and {parameters.Length - 1}" : $"{parameters.Length - 1}")} but got {fullCommand.Length - 1} argument{((fullCommand.Length - 1) == 1 ? "" : "s")}."); - } - else - { - this.Logger.Error($"Command {command} requires {(hasOptional ? $"between {parameters.Skip(1).Count(p => !p.IsOptional)} and {parameters.Length - 1}" : $"{parameters.Length - 1}")} but got {fullCommand.Length - 1} argument{((fullCommand.Length - 1) == 1 ? "" : "s")}."); - } + sendCommandUsageMessage(errorContext, method, $"Require {(hasOptional ? $"between {parameters.Skip(1).Count(p => !p.IsOptional)} and {parameters.Length - 1}" : $"{parameters.Length - 1}")} but got {fullCommand.Length - 1} argument{((fullCommand.Length - 1) == 1 ? "" : "s")}."); return; } object?[] args = new object[parameters.Length]; - args[0] = player; for (int i = 1; i < parameters.Length; i++) { @@ -357,7 +328,8 @@ private void handleCommand(RunnerPlayer? player, string message) { RunnerPlayer? targetPlayer = null; - if (ulong.TryParse(argument, out ulong steamId) && this.Server.AllPlayers.FirstOrDefault(p => p.SteamID == steamId) is RunnerPlayer playerBySteamId) { + if (ulong.TryParse(argument, out ulong steamId) && this.Server.AllPlayers.FirstOrDefault(p => p.SteamID == steamId) is RunnerPlayer playerBySteamId) + { args[i] = targetPlayer; continue; } @@ -370,9 +342,9 @@ private void handleCommand(RunnerPlayer? player, string message) } catch (Exception ex) { - if (player is not null) + if (chatSource is not null) { - player.Message($"Error while searching for player name containing {argument}.{Environment.NewLine}{ex.Message}"); + errorContext.Reply($"Error while searching for player name containing {argument}.{Environment.NewLine}{ex.Message}"); } else { @@ -383,14 +355,7 @@ private void handleCommand(RunnerPlayer? player, string message) if (targetPlayer == null) { - if (player is not null) - { - player.Message($"Could not find player name containing {argument}."); - } - else - { - this.Logger.Error($"Could not find player name containing {argument}."); - } + errorContext.Reply($"Could not find player name containing {argument}."); return; } } @@ -401,14 +366,7 @@ private void handleCommand(RunnerPlayer? player, string message) if (targetPlayer == null) { - if (player is not null) - { - player.Message($"Could not find player {argument}."); - } - else - { - this.Logger.Error($"Could not find player {argument}."); - } + errorContext.Reply($"Could not find player {argument}."); return; } @@ -418,7 +376,7 @@ private void handleCommand(RunnerPlayer? player, string message) { if (!tryParseParameter(parameter, argument, out object? parsedValue)) { - messagePlayerCommandUsage(player, method, $"Couldn't parse value {argument} to type {parameter.ParameterType.Name}"); + sendCommandUsageMessage(errorContext, method, $"Couldn't parse value {argument} to type {parameter.ParameterType.Name}"); return; } @@ -426,20 +384,26 @@ private void handleCommand(RunnerPlayer? player, string message) } } - method.Invoke(module, args); + args[0] = new Context(source, message, command, fullCommand.Skip(1).ToArray(), args.Skip(1).ToArray(), module, this, commandCallbackAttribute); + + object? result = method.Invoke(module, args); + if (result is not null) + { + source.Reply((Context)args[0]!, result.ToString() ?? "No reply"); + } } - private void messagePlayerCommandUsage(RunnerPlayer? player, MethodInfo method, string? error = null) + private void sendCommandUsageMessage(Context context, MethodInfo method, string? error = null) { CommandCallbackAttribute commandCallbackAttribute = method.GetCustomAttribute()!; bool hasOptional = method.GetParameters().Any(p => p.IsOptional); - if (player is not null) + if (context.Source is ChatSource chatSource) { - player.Message($"Invalid command usage{(error == null ? "" : $" ({error})")}.
Usage: {CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name} {string.Join(' ', method.GetParameters().Skip(1).Select(s => $"{s.Name}{(s.IsOptional ? "*" : "")}"))}{(hasOptional ? "
* Parameter is optional." : "")}"); + context.Reply($"Invalid command usage{(error == null ? "" : $" ({error})")}.
Usage: {CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name} {string.Join(' ', method.GetParameters().Skip(1).Select(s => $"{s.Name}{(s.IsOptional ? "*" : "")}"))}{(hasOptional ? "
* Parameter is optional." : "")}"); } else { - this.Logger.Error($"Invalid command usage{(error == null ? "" : $" ({error})")}.{Environment.NewLine}Usage: {CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name} {string.Join(' ', method.GetParameters().Skip(1).Select(s => $"{s.Name}{(s.IsOptional ? "*" : "")}"))}{(hasOptional ? $"{Environment.NewLine}* Parameter is optional." : "")}"); + context.Reply($"Invalid command usage{(error == null ? "" : $" ({error})")}.{Environment.NewLine}Usage: {CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name} {string.Join(' ', method.GetParameters().Skip(1).Select(s => $"{s.Name}{(s.IsOptional ? "*" : "")}"))}{(hasOptional ? $"{Environment.NewLine}* Parameter is optional." : "")}"); } } @@ -523,52 +487,96 @@ private static string unescapeQuotes(string input) return input.Replace("\\\"", "\""); } - [CommandCallback("help", Description = "Shows this help message", Permissions = new[] { "CommandHandler.Help" })] - public void HelpCommand(RunnerPlayer player, int page = 1) + [CommandCallback("help", Description = "Shows this help message", Permissions = new[] { "CommandHandler.Help" }, ConsoleCommand = true)] + public string HelpCommand(Context context, int page = 1) { List helpLines = new(); foreach (var (commandKey, (module, method)) in this.commandCallbacks) { CommandCallbackAttribute commandCallbackAttribute = method.GetCustomAttribute()!; - if (!this.HasPermissionForCommand(player, commandCallbackAttribute)) + if (context.Source is ChatSource chatSource && !this.HasPermissionForCommand(chatSource.Invoker, commandCallbackAttribute)) { continue; } - helpLines.Add($"{CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name}{(string.IsNullOrEmpty(commandCallbackAttribute.Description) ? "" : $": {commandCallbackAttribute.Description}")}"); + if (context.Source is ChatSource) + { + helpLines.Add($"{CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name}{(string.IsNullOrEmpty(commandCallbackAttribute.Description) ? "" : $": {commandCallbackAttribute.Description}")}"); + } + else + { + helpLines.Add($"{CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name}{(string.IsNullOrEmpty(commandCallbackAttribute.Description) ? "" : $": {commandCallbackAttribute.Description}")}"); + } } int pages = (int)Math.Ceiling((double)helpLines.Count / CommandConfiguration.CommandsPerPage); if (page < 1 || page > pages) { - player.Message($"Invalid page number. Must be between 1 and {pages}."); - return; + if (context.Source is ChatSource) + { + return $"Invalid page number. Must be between 1 and {pages}."; + } + else + { + return $"Invalid page number. Must be between 1 and {pages}."; + } } - player.Message($"<#FFA500>Available commands
{Environment.NewLine}{string.Join(Environment.NewLine, helpLines.Skip((page - 1) * CommandConfiguration.CommandsPerPage).Take(CommandConfiguration.CommandsPerPage))}{(pages > 1 ? $"{Environment.NewLine}Page {page} of {pages}{(page < pages ? $" - type !help {page + 1} for next page" : "")}" : "")}"); + if (context.Source is ChatSource) + { + return $"<#FFA500>Available commands
{Environment.NewLine}{string.Join(Environment.NewLine, helpLines.Skip((page - 1) * CommandConfiguration.CommandsPerPage).Take(CommandConfiguration.CommandsPerPage))}{(pages > 1 ? $"{Environment.NewLine}Page {page} of {pages}{(page < pages ? $" - type !help {page + 1} for next page" : "")}" : "")}"; + } + else + { + return $"Available commands{Environment.NewLine}{string.Join(Environment.NewLine, helpLines.Skip((page - 1) * CommandConfiguration.CommandsPerPage).Take(CommandConfiguration.CommandsPerPage))}{(pages > 1 ? $"{Environment.NewLine}Page {page} of {pages}{(page < pages ? $" - type !help {page + 1} for next page" : "")}" : "")}"; + } } - [CommandCallback("cmdhelp", Description = "Shows help for a specific command", Permissions = new[] { "CommandHandler.CommandHelp" })] - public void CommandHelpCommand(RunnerPlayer player, string command) + [CommandCallback("cmdhelp", Description = "Shows help for a specific command", Permissions = new[] { "CommandHandler.CommandHelp" }, ConsoleCommand = true)] + public string CommandHelpCommand(Context context, string command) { if (!this.commandCallbacks.TryGetValue(command, out var commandCallback)) { - player.Message($"Command {command} not found."); - return; + if (context.Source is ChatSource) + { + return $"Command {command} not found."; + } + else + { + return $"Command {command} not found."; + } } CommandCallbackAttribute commandCallbackAttribute = commandCallback.Method.GetCustomAttribute()!; - if (!this.HasPermissionForCommand(player, commandCallbackAttribute)) + if (context.Source is ChatSource chatSource && !this.HasPermissionForCommand(chatSource.Invoker, commandCallbackAttribute)) { - player.Message($"You don't have permission to see help about this command."); - return; + bool hideInaccessible = CommandConfiguration.HideInaccessibleCommands; + if (this.CommandSettings.Settings[command]?.HideInaccessible is not null) + { + hideInaccessible = this.CommandSettings.Settings[command]!.HideInaccessible!.Value; + } + + if (hideInaccessible) + { + return $"Command {command} not found."; + } + + return $"You don't have permission to see help about this command."; } bool hasOptional = commandCallback.Method.GetParameters().Any(p => p.IsOptional); - player.Message($"{commandCallback.Module.GetType().Name} {commandCallbackAttribute.Name}
{commandCallbackAttribute.Description}
<#F5F5F5>{CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name} {string.Join(' ', commandCallback.Method.GetParameters().Skip(1).Select(s => $"{s.Name}{(s.IsOptional ? "*" : "")}"))}{(hasOptional ? "
* Parameter is optional." : "")}"); + + if (context.Source is ChatSource) + { + return $"{commandCallback.Module.GetType().Name} {commandCallbackAttribute.Name}
{commandCallbackAttribute.Description}
<#F5F5F5>{CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name} {string.Join(' ', commandCallback.Method.GetParameters().Skip(1).Select(s => $"{s.Name}{(s.IsOptional ? "*" : "")}"))}{(hasOptional ? "
* Parameter is optional." : "")}"; + } + else + { + return $"{commandCallback.Module.GetType().Name} {commandCallbackAttribute.Name}{Environment.NewLine}{commandCallbackAttribute.Description}{Environment.NewLine}{CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name} {string.Join(' ', commandCallback.Method.GetParameters().Skip(1).Select(s => $"{s.Name}{(s.IsOptional ? "*" : "")}"))}{(hasOptional ? $"{Environment.NewLine}* Parameter is optional." : "")}"; + } } } @@ -591,9 +599,96 @@ public class CommandConfiguration : ModuleConfiguration { public string CommandPrefix { get; set; } = "!"; public int CommandsPerPage { get; set; } = 6; + public int MessageTimeout { get; set; } = 15; + public bool HideInaccessibleCommands { get; set; } = false; + public bool ReplyToChat { get; set; } = false; } -public class CommandPermissions : ModuleConfiguration +public class CommandSettings : ModuleConfiguration { - public Dictionary Permissions { get; set; } = new(); + public Dictionary Settings { get; set; } = new(); +} + +public class CommandSetting +{ + public string[]? Permissions { get; set; } + public bool? ReplyToChat { get; set; } + public int? MessageTimeout { get; set; } + public bool? HideInaccessible { get; set; } +} + +public class Context +{ + public Source Source { get; set; } + public string Message { get; set; } + public string Command { get; set; } + public string[] RawParameters { get; set; } + public object?[] Parameters { get; set; } + public BattleBitModule? Module { get; set; } + public CommandHandler CommandHandler { get; set; } + public CommandCallbackAttribute? CommandCallbackAttribute { get; set; } + + public Context(Source source, string message, string command, string[] rawParameters, object?[] parameters, BattleBitModule? module, CommandHandler commandHandler, CommandCallbackAttribute? commandCallbackAttribute) + { + this.Source = source; + this.Message = message; + this.Command = command; + this.RawParameters = rawParameters; + this.Parameters = parameters; + this.Module = module; + this.CommandHandler = commandHandler; + this.CommandCallbackAttribute = commandCallbackAttribute; + } + + public virtual void Reply(string message) + { + this.Source.Reply(this, message); + } +} + +public abstract class Source +{ + public abstract void Reply(Context context, string message); +} + +public class ChatSource : Source +{ + public ChatSource(RunnerPlayer invoker) + { + this.Invoker = invoker; + } + + public RunnerPlayer Invoker { get; } + + public override void Reply(Context context, string message) + { + bool replyToChat = CommandHandler.CommandConfiguration.ReplyToChat; + if (context.CommandHandler.CommandSettings.Settings[context.Command]?.ReplyToChat is not null) + { + replyToChat = context.CommandHandler.CommandSettings.Settings[context.Command]!.ReplyToChat!.Value; + } + + if (replyToChat) + { + this.Invoker.SayToChat(message); + } + else + { + int messageTimeout = CommandHandler.CommandConfiguration.MessageTimeout; + if (context.CommandHandler.CommandSettings.Settings[context.Command]?.MessageTimeout is not null) + { + messageTimeout = context.CommandHandler.CommandSettings.Settings[context.Command]!.MessageTimeout!.Value; + } + + this.Invoker.Message(message, messageTimeout); + } + } +} + +public class ConsoleSource : Source +{ + public override void Reply(Context context, string message) + { + context.CommandHandler.Logger.Info(message); + } } diff --git a/DiscordWebhooks.cs b/DiscordWebhooks.cs index 7622fff..7659ca6 100644 --- a/DiscordWebhooks.cs +++ b/DiscordWebhooks.cs @@ -22,7 +22,7 @@ public override void OnModulesLoaded() if (string.IsNullOrEmpty(this.Configuration.WebhookURL)) { this.Unload(); - throw new Exception("Webhook URL is not set. Please set it in the configuration file."); + this.Logger.Error("Webhook URL is not set. Please set it in the configuration file."); } } diff --git a/GeoLimiter.cs b/GeoLimiter.cs index def01bb..d600529 100644 --- a/GeoLimiter.cs +++ b/GeoLimiter.cs @@ -1,6 +1,5 @@ using BBRAPIModules; using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; @@ -8,7 +7,7 @@ namespace GeoLimiter; -[Module("Kick users based on their country of origin", "1.1.0")] +[Module("Kick users based on their country of origin", "1.2.0")] public class GeoLimiter : BattleBitModule { public static GeoLimiterConfiguration Configuration { get; set; } = null!; @@ -68,15 +67,15 @@ public override Task OnPlayerConnected(RunnerPlayer player) this.Logger.Info($"Found geolocation for IP {player.IP}: {geolocation.CountryName} ({geolocation.CountryCode})"); - if (ServerConfiguration.AllowedCountries?.Contains(geolocation.CountryCode) == true) + if (this.ServerConfiguration.AllowCountryCodes && this.ServerConfiguration.CountryCodes.Contains(geolocation.CountryCode)) { this.Logger.Info($"Country {geolocation.CountryCode} is allowed, skipping..."); return Task.CompletedTask; } - if (ServerConfiguration.DisallowedCountries?.Contains(geolocation.CountryCode) == false) + if (!this.ServerConfiguration.AllowCountryCodes && !this.ServerConfiguration.CountryCodes.Contains(geolocation.CountryCode)) { - this.Logger.Info($"Country {geolocation.CountryCode} is not disallowed, skipping..."); + this.Logger.Info($"Country {geolocation.CountryCode} is not denied, skipping..."); return Task.CompletedTask; } @@ -95,8 +94,8 @@ public class GeoLimiterConfiguration : ModuleConfiguration public class GeoLimiterServerConfiguration : ModuleConfiguration { - public string[]? AllowedCountries { get; set; } = new string[] { "DE", "AT", "CH" }; - public string[]? DisallowedCountries { get; set; } = new string[] { "US", "RU", "CN" }; + public string[] CountryCodes { get; set; } = new string[] { "DE", "AT", "CH" }; + public bool AllowCountryCodes { get; set; } = true; public string KickMessage { get; set; } = "Your country {0} is not allowed on this server."; diff --git a/GranularPermissionsCommands.cs b/GranularPermissionsCommands.cs index 7681b4b..e28420f 100644 --- a/GranularPermissionsCommands.cs +++ b/GranularPermissionsCommands.cs @@ -25,27 +25,29 @@ public override void OnModulesLoaded() } [CommandCallback("addplayerperm", Description = "Adds a permission to a player", Permissions = new[] { "GranularPermissions.AddPlayerPerm" })] - public void AddPermissionCommand(RunnerPlayer commandSource, RunnerPlayer player, string permission) + public string AddPermissionCommand(Context context, RunnerPlayer player, string permission) { this.GranularPermissions.AddPlayerPermission(player.SteamID, permission); - - commandSource.Message($"Added permission {permission} to {player.Name}"); - this.GranularPermissions.Save(); + + this.Logger.Debug($"Added permission {permission} to {player.Name}"); + + return $"Added permission {permission} to {player.Name}"; } [CommandCallback("removeplayerperm", Description = "Removes a permission from a player", Permissions = new[] { "GranularPermissions.RemovePlayerPerm" })] - public void RemovePermissionCommand(RunnerPlayer commandSource, RunnerPlayer player, string permission) + public string RemovePermissionCommand(Context context, RunnerPlayer player, string permission) { this.GranularPermissions.RemovePlayerPermission(player.SteamID, permission); + this.GranularPermissions.Save(); - commandSource.Message($"Removed permission {permission} from {player.Name}"); + this.Logger.Debug($"Removed permission {permission} from {player.Name}"); - this.GranularPermissions.Save(); + return $"Removed permission {permission} from {player.Name}"; } [CommandCallback("clearplayerperms", Description = "Clears all permissions and groups from a player", Permissions = new[] { "GranularPermissions.ClearPlayerPerms" })] - public void ClearPermissionCommand(RunnerPlayer commandSource, RunnerPlayer player) + public string ClearPermissionCommand(Context context, RunnerPlayer player) { foreach (string group in this.GranularPermissions.GetPlayerGroups(player.SteamID)) { @@ -57,13 +59,15 @@ public void ClearPermissionCommand(RunnerPlayer commandSource, RunnerPlayer play this.GranularPermissions.RemovePlayerPermission(player.SteamID, permission); } - commandSource.Message($"Cleared permissions from {player.Name}"); - this.GranularPermissions.Save(); + + this.Logger.Debug($"Cleared permissions from {player.Name}"); + + return $"Cleared permissions from {player.Name}"; } [CommandCallback("listplayerperms", Description = "Lists player permissions", Permissions = new[] { "GranularPermissions.ListPlayerPerms" })] - public void ListPermissionCommand(RunnerPlayer commandSource, RunnerPlayer targetPlayer, int page = 1) + public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, int page = 1) { if (page < 1) { @@ -74,62 +78,65 @@ public void ListPermissionCommand(RunnerPlayer commandSource, RunnerPlayer targe int pageCount = (int)Math.Ceiling(permissions.Length / (double)this.Configuration.PermissionsPerPage); - commandSource.Message($"{targetPlayer.Name}:{Environment.NewLine}{string.Join("\n", permissions.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listperms \"{targetPlayer.Name}\" {page + 1} to see more")}" : "")}"); + this.Logger.Debug($"Listing permissions for {targetPlayer.Name}"); + + return $"{targetPlayer.Name}:{Environment.NewLine}{string.Join("\n", permissions.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listperms \"{targetPlayer.Name}\" {page + 1} to see more")}" : "")}"; } [CommandCallback("addplayergroup", Description = "Adds a group to a player", Permissions = new[] { "GranularPermissions.AddPlayerGroup" })] - public void AddGroupCommand(RunnerPlayer commandSource, RunnerPlayer player, string group) + public string AddGroupCommand(Context context, RunnerPlayer player, string group) { if (this.GranularPermissions.GetPlayerGroups(player.SteamID).Contains(group)) { - commandSource.Message($"{player.Name} already has group {group}"); - return; + return $"{player.Name} already has group {group}"; } if (!this.GranularPermissions.GetGroups().Contains(group)) { - commandSource.Message($"Group {group} does not exist"); - return; + return $"Group {group} does not exist"; } this.GranularPermissions.AddPlayerGroup(player.SteamID, group); + this.GranularPermissions.Save(); - commandSource.Message($"Added group {group} to {player.Name}"); + this.Logger.Debug($"Added group {group} to {player.Name}"); - this.GranularPermissions.Save(); + return $"Added group {group} to {player.Name}"; } [CommandCallback("removeplayergroup", Description = "Removes a group from a player", Permissions = new[] { "GranularPermissions.RemovePlayerGroup" })] - public void RemoveGroupCommand(RunnerPlayer commandSource, RunnerPlayer player, string group) + public string RemoveGroupCommand(Context context, RunnerPlayer player, string group) { if (!this.GranularPermissions.GetPlayerGroups(player.SteamID).Contains(group)) { - commandSource.Message($"{player.Name} does not have group {group}"); - return; + return $"{player.Name} does not have group {group}"; } this.GranularPermissions.RemovePlayerGroup(player.SteamID, group); + this.GranularPermissions.Save(); - commandSource.Message($"Removed group {group} from {player.Name}"); + this.Logger.Debug($"Removed group {group} from {player.Name}"); - this.GranularPermissions.Save(); + return $"Removed group {group} from {player.Name}"; } [CommandCallback("clearplayergroups", Description = "Clears all groups from a player", Permissions = new[] { "GranularPermissions.ClearPlayerGroups" })] - public void ClearGroupCommand(RunnerPlayer commandSource, RunnerPlayer player) + public string ClearGroupCommand(Context context, RunnerPlayer player) { foreach (string group in this.GranularPermissions.GetPlayerGroups(player.SteamID)) { this.GranularPermissions.RemovePlayerGroup(player.SteamID, group); } - commandSource.Message($"Cleared groups from {player.Name}"); - this.GranularPermissions.Save(); + + this.Logger.Debug($"Cleared groups from {player.Name}"); + + return $"Cleared groups from {player.Name}"; } [CommandCallback("listplayergroups", Description = "Lists player groups", Permissions = new[] { "GranularPermissions.ListPlayerGroups" })] - public void ListGroupCommand(RunnerPlayer commandSource, RunnerPlayer targetPlayer, int page = 1) + public string ListGroupCommand(Context context, RunnerPlayer targetPlayer, int page = 1) { if (page < 1) { @@ -142,43 +149,45 @@ public void ListGroupCommand(RunnerPlayer commandSource, RunnerPlayer targetPlay int pageCount = (int)Math.Ceiling(groups.Count / (double)this.Configuration.PermissionsPerPage); - commandSource.Message($"{targetPlayer.Name}:{Environment.NewLine}{string.Join("\n", groups.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroups \"{targetPlayer.Name}\" {page + 1} to see more")}" : "")}"); + this.Logger.Debug($"Listing groups for {targetPlayer.Name}"); + + return $"{targetPlayer.Name}:{Environment.NewLine}{string.Join("\n", groups.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroups \"{targetPlayer.Name}\" {page + 1} to see more")}" : "")}"; } [CommandCallback("addgroup", Description = "Adds a group", Permissions = new[] { "GranularPermissions.AddGroup" })] - public void AddGroupCommand(RunnerPlayer commandSource, string group) + public string AddGroupCommand(Context context, string group) { if (this.GranularPermissions.GetGroups().Contains(group)) { - commandSource.Message($"Group {group} already exists"); - return; + return $"Group {group} already exists"; } this.GranularPermissions.AddGroup(group); + this.GranularPermissions.Save(); - commandSource.Message($"Added group {group}"); + this.Logger.Debug($"Added group {group}"); - this.GranularPermissions.Save(); + return $"Added group {group}"; } [CommandCallback("removegroup", Description = "Removes a group", Permissions = new[] { "GranularPermissions.RemoveGroup" })] - public void RemoveGroupCommand(RunnerPlayer commandSource, string group) + public string RemoveGroupCommand(Context context, string group) { if (!this.GranularPermissions.GetGroups().Contains(group)) { - commandSource.Message($"Group {group} does not exist"); - return; + return $"Group {group} does not exist"; } this.GranularPermissions.RemoveGroup(group); + this.GranularPermissions.Save(); - commandSource.Message($"Removed group {group}"); + this.Logger.Debug($"Removed group {group}"); - this.GranularPermissions.Save(); + return $"Removed group {group}"; } [CommandCallback("listgroups", Description = "Lists groups", Permissions = new[] { "GranularPermissions.ListGroups" })] - public void ListGroupCommand(RunnerPlayer commandSource, int page = 1) + public string ListGroupCommand(Context context, int page = 1) { if (page < 1) { @@ -191,60 +200,59 @@ public void ListGroupCommand(RunnerPlayer commandSource, int page = 1) int pageCount = (int)Math.Ceiling(groups.Count / (double)this.Configuration.PermissionsPerPage); - commandSource.Message($"{Environment.NewLine}{string.Join("\n", groups.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroups {page + 1} to see more")}" : "")}"); + this.Logger.Debug($"Listing groups"); + + return $"{Environment.NewLine}{string.Join("\n", groups.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroups {page + 1} to see more")}" : "")}"; } [CommandCallback("addgroupperm", Description = "Adds a permission to a group", Permissions = new[] { "GranularPermissions.AddGroupPerm" })] - public void AddGroupPermissionCommand(RunnerPlayer commandSource, string group, string permission) + public string AddGroupPermissionCommand(Context context, string group, string permission) { if (!this.GranularPermissions.GetGroups().Contains(group)) { - commandSource.Message($"Group {group} does not exist"); - return; + return $"Group {group} does not exist"; } if (this.GranularPermissions.GetGroupPermissions(group).Contains(permission)) { - commandSource.Message($"{group} already has permission {permission}"); - return; + return $"{group} already has permission {permission}"; } this.GranularPermissions.AddGroupPermission(group, permission); + this.GranularPermissions.Save(); - commandSource.Message($"Added permission {permission} to {group}"); + this.Logger.Debug($"Added permission {permission} to {group}"); - this.GranularPermissions.Save(); + return $"Added permission {permission} to {group}"; } [CommandCallback("removegroupperm", Description = "Removes a permission from a group", Permissions = new[] { "GranularPermissions.RemoveGroupPerm" })] - public void RemoveGroupPermissionCommand(RunnerPlayer commandSource, string group, string permission) + public string RemoveGroupPermissionCommand(Context context, string group, string permission) { if (!this.GranularPermissions.GetGroups().Contains(group)) { - commandSource.Message($"Group {group} does not exist"); - return; + return $"Group {group} does not exist"; } if (!this.GranularPermissions.GetGroupPermissions(group).Contains(permission)) { - commandSource.Message($"{group} does not have permission {permission}"); - return; + return $"{group} does not have permission {permission}"; } this.GranularPermissions.RemoveGroupPermission(group, permission); + this.GranularPermissions.Save(); - commandSource.Message($"Removed permission {permission} from {group}"); + this.Logger.Debug($"Removed permission {permission} from {group}"); - this.GranularPermissions.Save(); + return $"Removed permission {permission} from {group}"; } [CommandCallback("cleargroupperms", Description = "Clears all permissions from a group", Permissions = new[] { "GranularPermissions.ClearGroupPerms" })] - public void ClearGroupPermissionCommand(RunnerPlayer commandSource, string group) + public string ClearGroupPermissionCommand(Context context, string group) { if (!this.GranularPermissions.GetGroups().Contains(group)) { - commandSource.Message($"Group {group} does not exist"); - return; + return $"Group {group} does not exist"; } foreach (string permission in this.GranularPermissions.GetGroupPermissions(group)) @@ -252,18 +260,19 @@ public void ClearGroupPermissionCommand(RunnerPlayer commandSource, string group this.GranularPermissions.RemoveGroupPermission(group, permission); } - commandSource.Message($"Cleared permissions from {group}"); - this.GranularPermissions.Save(); + + this.Logger.Debug($"Cleared permissions from {group}"); + + return $"Cleared permissions from {group}"; } [CommandCallback("listgroupperms", Description = "Lists group permissions", Permissions = new[] { "GranularPermissions.ListGroupPerms" })] - public void ListGroupPermissionCommand(RunnerPlayer commandSource, string group, int page = 1) + public string ListGroupPermissionCommand(Context context, string group, int page = 1) { if (!this.GranularPermissions.GetGroups().Contains(group)) { - commandSource.Message($"Group {group} does not exist"); - return; + return $"Group {group} does not exist"; } if (page < 1) @@ -277,7 +286,7 @@ public void ListGroupPermissionCommand(RunnerPlayer commandSource, string group, int pageCount = (int)Math.Ceiling(permissions.Count / (double)this.Configuration.PermissionsPerPage); - commandSource.Message($"{group}:{Environment.NewLine}{string.Join("\n", permissions.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroupperms \"{group}\" {page + 1} to see more")}" : "")}"); + return $"{group}:{Environment.NewLine}{string.Join("\n", permissions.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroupperms \"{group}\" {page + 1} to see more")}" : "")}"; } } diff --git a/MOTD.cs b/MOTD.cs index de63425..809548e 100644 --- a/MOTD.cs +++ b/MOTD.cs @@ -1,6 +1,8 @@ -using BattleBitAPI.Common; +using BattleBitAPI.Common; +using BattleBitAPI.Features; using BBRAPIModules; using Commands; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -16,13 +18,21 @@ public class MOTD : BattleBitModule [ModuleReference] public CommandHandler CommandHandler { get; set; } = null!; + [ModuleReference] + public dynamic? PlaceholderLib { get; set; } + + private List greetedPlayers = new(); + public override void OnModulesLoaded() { + if (this.PlaceholderLib is null) + { + this.Logger.Info("PlaceholderLib not found. MOTD will only support basic numbered placeholders."); + } + this.CommandHandler.Register(this); } - private List greetedPlayers = new(); - public override Task OnGameStateChanged(GameState oldState, GameState newState) { if (newState == GameState.EndingGame) @@ -41,28 +51,49 @@ public override Task OnPlayerConnected(RunnerPlayer player) return Task.CompletedTask; } - this.ShowMOTD(player); + this.ShowMOTD(new Context(new ChatSource(player), string.Empty, "motd", Array.Empty(), Array.Empty(), this, this.CommandHandler, null)); return Task.CompletedTask; } [CommandCallback("setmotd", Description = "Sets the MOTD", Permissions = new[] { "MOTD.Set" })] - public void SetMOTD(RunnerPlayer commandSource, string motd) + public void SetMOTD(Context context, string motd) { this.Configuration.MOTD = motd; this.Configuration.Save(); - this.ShowMOTD(commandSource); + this.ShowMOTD(context); } [CommandCallback("motd", Description = "Shows the MOTD")] - public void ShowMOTD(RunnerPlayer commandSource) + public string ShowMOTD(Context context) { - commandSource.Message(string.Format(this.Configuration.MOTD, commandSource.Name, commandSource.PingMs, this.Server.ServerName, this.Server.Gamemode, this.Server.Map, this.Server.DayNight, this.Server.MapSize.ToString().Trim('_'), this.Server.CurrentPlayerCount, this.Server.InQueuePlayerCount, this.Server.MaxPlayerCount), this.Configuration.MessageTimeout); + ChatSource? chatSource = context.Source as ChatSource; + + string message; + if (this.PlaceholderLib is not null) + { + message = new PlaceholderLib(this.Configuration.MOTD) + .AddParam("servername", this.Server.ServerName) + .AddParam("gamemode", this.Server.Gamemode) + .AddParam("map", this.Server.Map) + .AddParam("daynight", this.Server.DayNight) + .AddParam("mapsize", this.Server.MapSize.ToString().Trim('_')) + .AddParam("currentplayers", this.Server.CurrentPlayerCount) + .AddParam("inqueueplayers", this.Server.InQueuePlayerCount) + .AddParam("maxplayers", this.Server.MaxPlayerCount) + .AddParam("name", chatSource?.Invoker.Name ?? context.Source.GetType().Name) + .AddParam("ping", chatSource?.Invoker.PingMs ?? 0).Run(); + } + else + { + message = string.Format(this.Configuration.MOTD, chatSource?.Invoker.Name ?? context.Source.GetType().Name, chatSource?.Invoker.PingMs ?? 0, this.Server.ServerName, this.Server.Gamemode, this.Server.Map, this.Server.DayNight, this.Server.MapSize.ToString().Trim('_'), this.Server.CurrentPlayerCount, this.Server.InQueuePlayerCount, this.Server.MaxPlayerCount); + } + + return message; } } public class MOTDConfiguration : ModuleConfiguration { public string MOTD { get; set; } = "Welcome!"; - public int MessageTimeout { get; set; } = 30; } diff --git a/ModeratorTools.cs b/ModeratorTools.cs index ba7cefd..ce1e313 100644 --- a/ModeratorTools.cs +++ b/ModeratorTools.cs @@ -33,52 +33,69 @@ private async void playerInspection() { foreach (KeyValuePair inspection in this.inspectPlayers) { - RunnerPlayer target = inspection.Value; - - StringBuilder playerInfo = new(); - playerInfo.AppendLine($"{target.Name} ({target.SteamID} - {target.Role}"); - playerInfo.AppendLine($"Net: {target.IP} - {target.PingMs}ms"); - playerInfo.AppendLine($"Game: {target.Team} - {target.SquadName} - {(target.IsConnected ? "Connected" : "Disconnected")}"); - playerInfo.AppendLine($"Health: {target.HP} - {(target.IsAlive ? "Alive" : "Dead")} - {(target.IsDown ? "Down" : "Up")} - {(target.IsBleeding ? "Bleeding" : "Not bleeding")}"); - playerInfo.AppendLine($"State: {target.StandingState} - {target.LeaningState} - {(target.InVehicle ? "In vehicle" : "Not in vehicle")}"); - playerInfo.AppendLine($"Position: {target.Position}"); - playerInfo.AppendLine($"Loadout: {target.CurrentLoadout.PrimaryWeapon.ToolName} - {target.CurrentLoadout.SecondaryWeapon.ToolName} - {target.CurrentLoadout.ThrowableName}"); - playerInfo.AppendLine($"Loadout: {target.CurrentLoadout.HeavyGadgetName} - {target.CurrentLoadout.LightGadgetName}"); - - inspection.Key.Message(playerInfo.ToString()); + inspection.Key.Message(this.getPlayerInspectionText(inspection.Value)); } await Task.Delay(250); } } + private string getPlayerInspectionText(RunnerPlayer target) + { + StringBuilder playerInfo = new(); + playerInfo.AppendLine($"{target.Name} ({target.SteamID} - {target.Role}"); + playerInfo.AppendLine($"Net: {target.IP} - {target.PingMs}ms"); + playerInfo.AppendLine($"Game: {target.Team} - {target.SquadName} - {(target.IsConnected ? "Connected" : "Disconnected")}"); + playerInfo.AppendLine($"Health: {target.HP} - {(target.IsAlive ? "Alive" : "Dead")} - {(target.IsDown ? "Down" : "Up")} - {(target.IsBleeding ? "Bleeding" : "Not bleeding")}"); + playerInfo.AppendLine($"State: {target.StandingState} - {target.LeaningState} - {(target.InVehicle ? "In vehicle" : "Not in vehicle")}"); + playerInfo.AppendLine($"Position: {target.Position}"); + playerInfo.AppendLine($"Loadout: {target.CurrentLoadout.PrimaryWeapon.ToolName} - {target.CurrentLoadout.SecondaryWeapon.ToolName} - {target.CurrentLoadout.ThrowableName}"); + playerInfo.AppendLine($"Loadout: {target.CurrentLoadout.HeavyGadgetName} - {target.CurrentLoadout.LightGadgetName}"); + + return playerInfo.ToString(); + } + [CommandCallback("Say", Description = "Prints a message to all players", Permissions = new[] { "ModeratorTools.Say" })] - public void Say(RunnerPlayer commandSource, string message) + public string Say(Context context, string message) { + this.Logger.Info($"[Say] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)}: {message}"); this.Server.SayToAllChat(message); + + return $"Message sent to all players"; } [CommandCallback("SayToPlayer", Description = "Prints a message to all players", Permissions = new[] { "ModeratorTools.SayToPlayer" })] - public void SayToPlayer(RunnerPlayer commandSource, RunnerPlayer target, string message) + public string SayToPlayer(Context context, RunnerPlayer target, string message) { + this.Logger.Info($"[SayToPlayer] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}: {message}"); this.Server.SayToChat(message, target.SteamID); + + return $"Message sent to {target.Name}"; } [CommandCallback("AnnounceShort", Description = "Prints a short announce to all players", Permissions = new[] { "ModeratorTools.AnnounceShort" })] - public void AnnounceShort(RunnerPlayer commandSource, string message) + public string AnnounceShort(Context context, string message) { + this.Logger.Info($"[AnnounceShort] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)}: {message}"); this.Server.AnnounceShort(message); + + return $"Announce sent"; } [CommandCallback("AnnounceLong", Description = "Prints a long announce to all players", Permissions = new[] { "ModeratorTools.AnnounceLong" })] - public void AnnounceLong(RunnerPlayer commandSource, string message) + public string AnnounceLong(Context context, string message) { + this.Logger.Info($"[AnnounceLong] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)}: {message}"); this.Server.AnnounceLong(message); + + return $"Announce sent"; } [CommandCallback("Message", Description = "Messages a specific player", Permissions = new[] { "ModeratorTools.Message" })] - public void Message(RunnerPlayer commandSource, RunnerPlayer target, string message, float? timeout = null) + public string Message(Context context, RunnerPlayer target, string message, float? timeout = null) { + this.Logger.Info($"[Message] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}: {message}"); + if (timeout.HasValue) { target.Message(message, timeout.Value); @@ -88,283 +105,354 @@ public void Message(RunnerPlayer commandSource, RunnerPlayer target, string mess target.Message(message); } - commandSource.Message($"Message sent to {target.Name}", 10); + return $"Message sent to {target.Name}"; } [CommandCallback("Clear", Description = "Clears the chat", Permissions = new[] { "ModeratorTools.Clear" })] - public void Clear(RunnerPlayer commandSource) + public string Clear(Context context) { + this.Logger.Info($"[Clear] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)}"); this.Server.SayToAllChat("".PadLeft(30, '\n') + "Chat cleared"); + + return $"Chat cleared"; } [CommandCallback("Kick", Description = "Kicks a player", Permissions = new[] { "ModeratorTools.Kick" })] - public void Kick(RunnerPlayer commandSource, RunnerPlayer target, string? reason = null) + public string Kick(Context context, RunnerPlayer target, string? reason = null) { + this.Logger.Info($"[Kick] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}: {reason ?? string.Empty}"); target.Kick(reason ?? string.Empty); - commandSource.Message($"Player {target.Name} kicked", 10); + return $"Player {target.Name} kicked"; } [CommandCallback("Ban", Description = "Bans a player", Permissions = new[] { "ModeratorTools.Ban" })] - public void Ban(RunnerPlayer commandSource, RunnerPlayer target) + public string Ban(Context context, RunnerPlayer target) { + this.Logger.Info($"[Ban] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); this.Server.ExecuteCommand($"ban {target.SteamID}"); target.Kick(); - commandSource.Message($"Player {target.Name} banned", 10); + return $"Player {target.Name} banned"; } [CommandCallback("Kill", Description = "Kills a player", Permissions = new[] { "ModeratorTools.Kill" })] - public void Kill(RunnerPlayer commandSource, RunnerPlayer target, string? message = null) + public string Kill(Context context, RunnerPlayer target, string? message = null) { + this.Logger.Info($"[Kill] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); target.Kill(); - commandSource.Message($"Player {target.Name} killed", 10); - if (!string.IsNullOrEmpty(message)) { target.Message(message); } + + return $"Player {target.Name} killed"; } [CommandCallback("Gag", Description = "Gags a player", Permissions = new[] { "ModeratorTools.Gag" })] - public void Gag(RunnerPlayer commandSource, RunnerPlayer target, string? message = null) + public string Gag(Context context, RunnerPlayer target, string? message = null) { + this.Logger.Info($"[Gag] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); if (this.gaggedPlayers.Contains(target.SteamID)) { - commandSource.Message($"Player {target.Name} is already gagged"); - return; + return $"Player {target.Name} is already gagged"; } this.gaggedPlayers.Add(target.SteamID); - commandSource.Message($"Player {target.Name} gagged", 10); - if (!string.IsNullOrEmpty(message)) { target.Message(message); } + + return $"Player {target.Name} gagged"; } [CommandCallback("Ungag", Description = "Ungags a player", Permissions = new[] { "ModeratorTools.Ungag" })] - public void Ungag(RunnerPlayer commandSource, RunnerPlayer target, string? message = null) + public string Ungag(Context context, RunnerPlayer target, string? message = null) { + this.Logger.Info($"[Ungag] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); if (!this.gaggedPlayers.Contains(target.SteamID)) { - commandSource.Message($"Player {target.Name} is not gagged"); - return; + return $"Player {target.Name} is not gagged"; } this.gaggedPlayers.Remove(target.SteamID); - commandSource.Message($"Player {target.Name} ungagged", 10); - if (!string.IsNullOrEmpty(message)) { target.Message(message); } + + return $"Player {target.Name} ungagged"; } [CommandCallback("Mute", Description = "Mutes a player", Permissions = new[] { "ModeratorTools.Mute" })] - public void Mute(RunnerPlayer commandSource, RunnerPlayer target, string? message = null) + public string Mute(Context context, RunnerPlayer target, string? message = null) { + this.Logger.Info($"[Mute] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); if (target.Modifications.IsVoiceChatMuted) { - commandSource.Message($"Player {target.Name} is already muted"); - return; + return $"Player {target.Name} is already muted"; } target.Modifications.IsVoiceChatMuted = true; - commandSource.Message($"Player {target.Name} muted", 10); - if (!string.IsNullOrEmpty(message)) { target.Message(message); } + + return $"Player {target.Name} muted"; } [CommandCallback("Unmute", Description = "Unmutes a player", Permissions = new[] { "ModeratorTools.Unmute" })] - public void Unmute(RunnerPlayer commandSource, RunnerPlayer target, string? message = null) + public string Unmute(Context context, RunnerPlayer target, string? message = null) { + this.Logger.Info($"[Unmute] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); if (!target.Modifications.IsVoiceChatMuted) { - commandSource.Message($"Player {target.Name} is not muted"); - return; + return $"Player {target.Name} is not muted"; } target.Modifications.IsVoiceChatMuted = false; - commandSource.Message($"Player {target.Name} unmuted", 10); - if (!string.IsNullOrEmpty(message)) { target.Message(message); } + + return $"Player {target.Name} unmuted"; } [CommandCallback("Silence", Description = "Mutes and gags a player", Permissions = new[] { "ModeratorTools.Silence" })] - public void Silence(RunnerPlayer commandSource, RunnerPlayer target, string? message = null) + public string Silence(Context context, RunnerPlayer target, string? message = null) { - Mute(commandSource, target); - Gag(commandSource, target); - commandSource.Message($"Player {target.Name} silenced", 10); + this.Logger.Info($"[Silence] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); + Mute(context, target); + Gag(context, target); if (!string.IsNullOrEmpty(message)) { target.Message(message); } + + return $"Player {target.Name} silenced"; } [CommandCallback("Unsilence", Description = "Unmutes and ungags a player", Permissions = new[] { "ModeratorTools.Unsilence" })] - public void Unsilence(RunnerPlayer commandSource, RunnerPlayer target, string? message = null) + public string Unsilence(Context context, RunnerPlayer target, string? message = null) { - Unmute(commandSource, target); - Ungag(commandSource, target); - commandSource.Message($"Player {target.Name} unsilenced", 10); + this.Logger.Info($"[Unsilence] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); + Unmute(context, target); + Ungag(context, target); if (!string.IsNullOrEmpty(message)) { target.Message(message); } + + return $"Player {target.Name} unsilenced"; } [CommandCallback("LockSpawn", Description = "Prevents a player or all players from spawning", Permissions = new[] { "ModeratorTools.LockSpawn" })] - public void LockSpawn(RunnerPlayer commandSource, RunnerPlayer? target = null, string? message = null) + public string LockSpawn(Context context, RunnerPlayer? target = null, string? message = null) { if (target == null) { + this.Logger.Info($"[LockSpawn] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> All"); this.globalSpawnLock = true; foreach (RunnerPlayer player in this.Server.AllPlayers) { player.Modifications.CanDeploy = false; } - commandSource.Message("Spawn globally locked", 10); + + return "Spawn globally locked"; } else { + this.Logger.Info($"[LockSpawn] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); if (this.lockedSpawns.Contains(target.SteamID)) { - commandSource.Message($"Spawn already locked for {target.Name}", 10); - return; + return $"Spawn already locked for {target.Name}"; } target.Modifications.CanDeploy = false; this.lockedSpawns.Add(target.SteamID); - commandSource.Message($"Spawn locked for {target.Name}", 10); if (!string.IsNullOrEmpty(message)) { target.Message(message); } + + return $"Spawn locked for {target.Name}"; } } [CommandCallback("UnlockSpawn", Description = "Allows a player or all players to spawn", Permissions = new[] { "ModeratorTools.UnlockSpawn" })] - public void UnlockSpawn(RunnerPlayer commandSource, RunnerPlayer? target = null, string? message = null) + public string UnlockSpawn(Context context, RunnerPlayer? target = null, string? message = null) { if (target == null) { + this.Logger.Info($"[UnlockSpawn] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> All"); this.globalSpawnLock = false; foreach (RunnerPlayer player in this.Server.AllPlayers) { player.Modifications.CanDeploy = true; } - commandSource.Message("Spawn globally unlocked", 10); + + return "Spawn globally unlocked"; } else { + this.Logger.Info($"[UnlockSpawn] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); if (!this.lockedSpawns.Contains(target.SteamID)) { - commandSource.Message($"Spawn already unlocked for {target.Name}", 10); - return; + return $"Spawn already unlocked for {target.Name}"; } target.Modifications.CanDeploy = true; this.lockedSpawns.Remove(target.SteamID); - commandSource.Message($"Spawn unlocked for {target.Name}", 10); if (!string.IsNullOrEmpty(message)) { target.Message(message); } + + return $"Spawn unlocked for {target.Name}"; } } [CommandCallback("tp2me", Description = "Teleports a player to you", Permissions = new[] { "ModeratorTools.Teleport" })] - public void TeleportPlayerToMe(RunnerPlayer commandSource, RunnerPlayer target) + public string TeleportPlayerToMe(Context context, RunnerPlayer target) { - target.Teleport(new Vector3((int)commandSource.Position.X, (int)commandSource.Position.Y, (int)commandSource.Position.Z)); + if (context.Source is not ChatSource chatSource) + { + return "Teleport player to me can only work from chat"; + } + + this.Logger.Info($"[TeleportPlayerToMe] {chatSource.Invoker.Name} -> {target.Name}"); + target.Teleport(new Vector3((int)chatSource.Invoker.Position.X, (int)chatSource.Invoker.Position.Y, (int)chatSource.Invoker.Position.Z)); + + return $"Player {target.Name} teleported to you"; } [CommandCallback("tpme2", Description = "Teleports you to a player", Permissions = new[] { "ModeratorTools.Teleport" })] - public void TeleportMeToPlayer(RunnerPlayer commandSource, RunnerPlayer target) + public string TeleportMeToPlayer(Context context, RunnerPlayer target) { - commandSource.Teleport(new Vector3((int)target.Position.X, (int)target.Position.Y, (int)target.Position.Z)); + if (context.Source is not ChatSource chatSource) + { + return "Teleport me to player can only work from chat"; + } + + this.Logger.Info($"[TeleportMeToPlayer] {chatSource.Invoker.Name} -> {target.Name}"); + chatSource.Invoker.Teleport(new Vector3((int)target.Position.X, (int)target.Position.Y, (int)target.Position.Z)); + + return $"You teleported to {target.Name}"; } [CommandCallback("tp", Description = "Teleports a player to another player", Permissions = new[] { "ModeratorTools.Teleport" })] - public void TeleportPlayerToPlayer(RunnerPlayer commandSource, RunnerPlayer target, RunnerPlayer destination) + public string TeleportPlayerToPlayer(Context context, RunnerPlayer target, RunnerPlayer destination) { + this.Logger.Info($"[TeleportPlayerToPlayer] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name} -> {destination.Name}"); target.Teleport(new Vector3((int)destination.Position.X, (int)destination.Position.Y, (int)destination.Position.Z)); + + return $"Player {target.Name} teleported to {destination.Name}"; } [CommandCallback("tp2pos", Description = "Teleports a player to a position", Permissions = new[] { "ModeratorTools.Teleport" })] - public void TeleportPlayerToPos(RunnerPlayer commandSource, RunnerPlayer target, int x, int y, int z) + public string TeleportPlayerToPos(Context context, RunnerPlayer target, int x, int y, int z) { + this.Logger.Info($"[TeleportPlayerToPos] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name} -> {x} {y} {z}"); target.Teleport(new Vector3(x, y, z)); + + return $"Player {target.Name} teleported to {x} {y} {z}"; } [CommandCallback("tpme2pos", Description = "Teleports you to a position", Permissions = new[] { "ModeratorTools.Teleport" })] - public void TeleportMeToPos(RunnerPlayer commandSource, int x, int y, int z) + public string TeleportMeToPos(Context context, int x, int y, int z) { - commandSource.Teleport(new Vector3(x, y, z)); + if (context.Source is not ChatSource chatSource) + { + return "Teleport me to position can only work from chat"; + } + + this.Logger.Info($"[TeleportMeToPos] {chatSource.Invoker.Name} -> {x} {y} {z}"); + chatSource.Invoker.Teleport(new Vector3(x, y, z)); + + return $"You teleported to {x} {y} {z}"; } [CommandCallback("freeze", Description = "Freezes a player", Permissions = new[] { "ModeratorTools.Freeze" })] - public void Freeze(RunnerPlayer commandSource, RunnerPlayer target, string? message = null) + public string Freeze(Context context, RunnerPlayer target, string? message = null) { + this.Logger.Info($"[Freeze] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); target.Modifications.Freeze = true; - commandSource.Message($"Player {target.Name} frozen", 10); if (!string.IsNullOrEmpty(message)) { target.Message(message); } + + return $"Player {target.Name} frozen"; } [CommandCallback("unfreeze", Description = "Unfreezes a player", Permissions = new[] { "ModeratorTools.Unfreeze" })] - public void Unfreeze(RunnerPlayer commandSource, RunnerPlayer target, string? message = null) + public string Unfreeze(Context context, RunnerPlayer target, string? message = null) { + this.Logger.Info($"[Unfreeze] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); target.Modifications.Freeze = false; - commandSource.Message($"Player {target.Name} unfrozen", 10); if (!string.IsNullOrEmpty(message)) { target.Message(message); } + + return $"Player {target.Name} unfrozen"; } private Dictionary inspectPlayers = new(); [CommandCallback("Inspect", Description = "Inspects a player or stops inspection", Permissions = new[] { "ModeratorTools.Inspect" })] - public void Inspect(RunnerPlayer commandSource, RunnerPlayer? target = null) + public string? Inspect(Context context, RunnerPlayer? target = null) { + if (context.Source is not ChatSource chatSource) + { + if (target is null) + { + return "A target player to inspect is required."; + } + + return this.getPlayerInspectionText(target); + } + if (target is null) { - this.inspectPlayers.Remove(commandSource); - commandSource.Message("Inspection stopped", 2); - return; + this.inspectPlayers.Remove(chatSource.Invoker); + return "Inspection stopped"; } - if (this.inspectPlayers.ContainsKey(commandSource)) + if (this.inspectPlayers.ContainsKey(chatSource.Invoker)) { - this.inspectPlayers[commandSource] = target; + this.inspectPlayers[chatSource.Invoker] = target; } else { - this.inspectPlayers.Add(commandSource, target); + this.inspectPlayers.Add(chatSource.Invoker, target); } + + return null; + } + + [CommandCallback("warn", Description = "Warns a player", Permissions = new[] { "ModeratorTools.Warn" })] + public string Warn(Context context, RunnerPlayer target, string? message = null) + { + this.Logger.Info($"[Warn] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}: {message ?? "no reason"}"); + target.WarnPlayer(message ?? "no reason"); + target.Message($"You have been warned for\n{message ?? "no reason"}", 25); + + return $"Player {target.Name} warned"; } private List gaggedPlayers = new(); diff --git a/PasswordReservedSlots.cs b/PasswordReservedSlots.cs new file mode 100644 index 0000000..344945c --- /dev/null +++ b/PasswordReservedSlots.cs @@ -0,0 +1,91 @@ +using BBRAPIModules; +using Commands; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace BattleBitBaseModules; + +[RequireModule(typeof(CommandHandler))] +[Module("Add reserved slots by setting a password", "1.0.0")] +public class PasswordReservedSlots : BattleBitModule +{ + public PasswordReservedSlotsConfiguration Configuration { get; set; } = null!; + + [ModuleReference] + public CommandHandler CommandHandler { get; set; } = null!; + + public int getCurrentPlayerCount() + { + return Math.Max(this.Server.CurrentPlayerCount + this.Server.InQueuePlayerCount, this.Server.AllPlayers.Count()); + } + + public void handleSlots() + { + int currentPlayers = this.getCurrentPlayerCount(); + if (this.Server.MaxPlayerCount - this.Configuration.Slots < currentPlayers) + { + this.Server.SetNewPassword(""); + } + else + { + Server.SetNewPassword(this.Configuration.Password); + } + } + + public async Task slotHandler() + { + while (this.IsLoaded && this.Server.IsConnected) + { + this.handleSlots(); + await Task.Delay(1000); + } + } + + public override Task OnConnected() + { + _ = Task.Run(slotHandler); + + return Task.CompletedTask; + } + + public override Task OnPlayerConnected(RunnerPlayer player) + { + this.handleSlots(); + + return Task.CompletedTask; + } + + public override Task OnPlayerDisconnected(RunnerPlayer player) + { + this.handleSlots(); + + return Task.CompletedTask; + } + + [CommandCallback("setrspass", Description = "Sets the password for reserved slots", ConsoleCommand = true, Permissions = new[] { "PasswordReservedSlots.SetRSPass" })] + public string SetRSPassCommand(Context context, string password) + { + this.Configuration.Password = password; + this.Configuration.Save(); + this.handleSlots(); + + return "Password set."; + } + + [CommandCallback("setrsslots", Description = "Sets the number of reserved slots", ConsoleCommand = true, Permissions = new[] { "PasswordReservedSlots.SetRSSlots" })] + public string SetRSSlotsCommand(Context context, int slots) + { + this.Configuration.Slots = slots; + this.Configuration.Save(); + this.handleSlots(); + + return $"Slots set to {slots}."; + } +} + +public class PasswordReservedSlotsConfiguration : ModuleConfiguration +{ + public string Password { get; set; } = "changeme"; + public int Slots { get; set; } = 0; +} diff --git a/PermissionsCommands.cs b/PermissionsCommands.cs index de3aa38..bbdb675 100644 --- a/PermissionsCommands.cs +++ b/PermissionsCommands.cs @@ -26,7 +26,7 @@ public override void OnModulesLoaded() } [CommandCallback("addperm", Description = "Adds a permission to a player", Permissions = new[] { "Permissions.Add" })] - public void AddPermissionCommand(RunnerPlayer commandSource, RunnerPlayer player, string permission) + public string AddPermissionCommand(Context context, RunnerPlayer player, string permission) { bool success = false; @@ -51,17 +51,18 @@ public void AddPermissionCommand(RunnerPlayer commandSource, RunnerPlayer player if (success) { - commandSource.Message($"Added permission {permission} to {player.Name}"); + this.Logger.Info($"Added permission {permission} to {player.Name}"); + return $"Added permission {permission} to {player.Name}"; } else { this.Logger.Error($"Could not add permission {permission} to {player.Name}"); - commandSource.Message($"Could not add permission {permission} to {player.Name}"); + return $"Could not add permission {permission} to {player.Name}"; } } [CommandCallback("removeperm", Description = "Removes a permission from a player", Permissions = new[] { "Permissions.Remove" })] - public void RemovePermissionCommand(RunnerPlayer commandSource, RunnerPlayer player, string permission) + public string RemovePermissionCommand(Context context, RunnerPlayer player, string permission) { bool success = false; @@ -86,17 +87,18 @@ public void RemovePermissionCommand(RunnerPlayer commandSource, RunnerPlayer pla if (success) { - commandSource.Message($"Removed permission {permission} from {player.Name}"); + this.Logger.Info($"Removed permission {permission} from {player.Name}"); + return $"Removed permission {permission} from {player.Name}"; } else { this.Logger.Error($"Could not remove permission {permission} from {player.Name}"); - commandSource.Message($"Could not remove permission {permission} from {player.Name}"); + return $"Could not remove permission {permission} from {player.Name}"; } } [CommandCallback("clearperms", Description = "Clears all permissions and groups from a player", Permissions = new[] { "Permissions.Clear" })] - public void ClearPermissionCommand(RunnerPlayer commandSource, RunnerPlayer player) + public string ClearPermissionCommand(Context context, RunnerPlayer player) { if (this.GranularPermissions is not null) { @@ -119,11 +121,12 @@ public void ClearPermissionCommand(RunnerPlayer commandSource, RunnerPlayer play } } - commandSource.Message($"Cleared permissions from {player.Name}"); + this.Logger.Info($"Cleared permissions from {player.Name}"); + return $"Cleared permissions from {player.Name}"; } [CommandCallback("listperms", Description = "Lists player permissions", Permissions = new[] { "Permissions.List" })] - public void ListPermissionCommand(RunnerPlayer commandSource, RunnerPlayer targetPlayer, int page = 1) + public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, int page = 1) { List permissions = new(); @@ -144,7 +147,7 @@ public void ListPermissionCommand(RunnerPlayer commandSource, RunnerPlayer targe int pageCount = (int)Math.Ceiling(permissions.Count / (double)this.Configuration.PermissionsPerPage); - commandSource.Message($"{targetPlayer.Name}: {string.Join("\n", permissions.Skip(page * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listperms \"{targetPlayer.Name}\" {page + 1} to see more")}" : "")}"); + return $"{targetPlayer.Name}: {string.Join("\n", permissions.Skip(page * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listperms \"{targetPlayer.Name}\" {page + 1} to see more")}" : "")}"; } } diff --git a/PlayerRolesFromGranularPermissions.cs b/PlayerRolesFromGranularPermissions.cs index a22ac36..aed3f90 100644 --- a/PlayerRolesFromGranularPermissions.cs +++ b/PlayerRolesFromGranularPermissions.cs @@ -9,31 +9,31 @@ namespace Permissions; [Module("Provides player roles based on granular permissions", "1.0.0")] public class PlayerRolesFromGranularPermissions : BattleBitModule { - [ModuleReference] - public GranularPermissions GranularPermissions { get; set; } = null!; + [ModuleReference] + public GranularPermissions GranularPermissions { get; set; } = null!; - public PlayerRolesConfiguration Configuration { get; set; } = null!; + public PlayerRolesConfiguration Configuration { get; set; } = null!; - public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) - { - foreach (string permission in Configuration.PermissionRoles.Keys) - { - if (!this.GranularPermissions.HasPermission(steamID, permission)) - { - continue; - } - if (Configuration.AppendRoles) - { - args.Stats.Roles |= Configuration.PermissionRoles[permission]; - } - else - { - args.Stats.Roles = Configuration.PermissionRoles[permission]; - } - } + public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) + { + foreach (string permission in Configuration.PermissionRoles.Keys) + { + if (!this.GranularPermissions.HasPermission(steamID, permission)) + { + continue; + } + if (Configuration.AppendRoles) + { + args.Stats.Roles |= Configuration.PermissionRoles[permission]; + } + else + { + args.Stats.Roles = Configuration.PermissionRoles[permission]; + } + } - return Task.CompletedTask; - } + return Task.CompletedTask; + } } public class PlayerRolesConfiguration : ModuleConfiguration @@ -50,5 +50,5 @@ public class PlayerRolesConfiguration : ModuleConfiguration { "Role.All", Roles.Admin | Roles.Moderator | Roles.Special | Roles.Vip } }; - public bool AppendRoles { get; set; } = false; + public bool AppendRoles { get; set; } = false; } diff --git a/RichText.cs b/RichText.cs index 7c8a223..951e892 100644 --- a/RichText.cs +++ b/RichText.cs @@ -1,5 +1,4 @@ using BBRAPIModules; -using System; using System.Linq; using System.Reflection; diff --git a/Voting.cs b/Voting.cs index 068b296..7714f8a 100644 --- a/Voting.cs +++ b/Voting.cs @@ -33,12 +33,11 @@ public override void OnModulesLoaded() } [CommandCallback("vote", Description = "Votes for an option", Permissions = new[] { "Vote.Vote" })] - public void StartVoteCommand(RunnerPlayer commandSource, string text, string options) + public string? StartVoteCommand(Context context, string text, string options) { if (this.activeVote) { - commandSource.Message("There is already an active vote."); - return; + return "There is already an active vote."; } this.activeVote = true; @@ -47,9 +46,8 @@ public void StartVoteCommand(RunnerPlayer commandSource, string text, string opt if (this.voteOptions.Length >= 10) { - commandSource.Message("You can only have up to 9 options."); this.activeVote = false; - return; + return "You can only have up to 9 options."; } this.votes.Clear(); @@ -73,6 +71,8 @@ public void StartVoteCommand(RunnerPlayer commandSource, string text, string opt this.Server.SayToAllChat(messageText.ToString()); Task.Run(voteHandler); + + return null; } private void voteHandler() From f42bd11ddd93e2f07c6109ec9a8cdbf4093a42b8 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Thu, 19 Oct 2023 06:11:43 +0200 Subject: [PATCH 16/22] Code Cleanup (Profile 1) --- Announcements.cs | 51 ++-- BasicProgression.cs | 300 ++++++++++---------- BasicServerSettings.cs | 36 +-- ChatOverwrite.cs | 38 +-- CommandHandler.cs | 390 ++++++++------------------ DiscordWebhooks.cs | 110 +++----- GeoLimiter.cs | 39 +-- GranularPermissions.cs | 190 +++++-------- GranularPermissionsCommands.cs | 111 +++----- LoadingScreenText.cs | 4 +- MOTD.cs | 38 +-- ModeratorTools.cs | 214 +++++--------- ModuleUpdates.cs | 96 ++----- PasswordReservedSlots.cs | 40 +-- PermissionsCommands.cs | 85 ++---- PlayerFinder.cs | 36 +-- PlayerPermissions.cs | 56 ++-- PlayerRolesFromGranularPermissions.cs | 30 +- ProfanityFilter.cs | 54 ++-- RichText.cs | 60 ++-- Rotation.cs | 9 +- SpectateControl.cs | 44 +-- VacLimiter.cs | 105 +++---- Voting.cs | 63 ++--- 24 files changed, 763 insertions(+), 1436 deletions(-) diff --git a/Announcements.cs b/Announcements.cs index a972c8e..6a98ad2 100644 --- a/Announcements.cs +++ b/Announcements.cs @@ -5,59 +5,48 @@ namespace BattleBitBaseModules; [Module("Periodically execute announcements and messages based on configurable delays and conditions", "1.0.0")] -public class Announcements : BattleBitModule -{ +public class Announcements : BattleBitModule { public AnnouncementsConfiguration Configuration { get; set; } = null!; public AnnouncementStore Store { get; set; } = null!; - public override Task OnConnected() - { + public override Task OnConnected() { Task.Run(announcements); return Task.CompletedTask; } - private async void announcements() - { - while (this.IsLoaded && this.Server.IsConnected) - { + private async void announcements() { + while (this.IsLoaded && this.Server.IsConnected) { int lastItem = this.doAnnouncement(this.Configuration.AnnounceLongDelay, this.Store.lastAnnounceLong, this.Store.lastAnnounceLongItem, this.Configuration.AnnounceLong, this.Server.AnnounceLong); - if (lastItem != -1) - { + if (lastItem != -1) { this.Store.lastAnnounceLong = DateTime.Now; this.Store.lastAnnounceLongItem = lastItem; } lastItem = this.doAnnouncement(this.Configuration.AnnounceShortDelay, this.Store.lastAnnounceShort, this.Store.lastAnnounceShortItem, this.Configuration.AnnounceShort, this.Server.AnnounceShort); - if (lastItem != -1) - { + if (lastItem != -1) { this.Store.lastAnnounceShort = DateTime.Now; this.Store.lastAnnounceShortItem = lastItem; } lastItem = this.doAnnouncement(this.Configuration.UILogOnServerDelay, this.Store.lastUILogOnServer, this.Store.lastUILogOnServerItem, this.Configuration.UILogOnServer, message => this.Server.UILogOnServer(message, this.Configuration.UILogOnserverTimeout)); - if (lastItem != -1) - { + if (lastItem != -1) { this.Store.lastUILogOnServer = DateTime.Now; this.Store.lastUILogOnServerItem = lastItem; } - lastItem = this.doAnnouncement(this.Configuration.MessageToPlayerDelay, this.Store.lastMessageToPlayer, this.Store.lastMessageToPlayerItem, this.Configuration.MessageToPlayer, message => - { - foreach (RunnerPlayer player in this.Server.AllPlayers) - { + lastItem = this.doAnnouncement(this.Configuration.MessageToPlayerDelay, this.Store.lastMessageToPlayer, this.Store.lastMessageToPlayerItem, this.Configuration.MessageToPlayer, message => { + foreach (RunnerPlayer player in this.Server.AllPlayers) { player.Message(message, this.Configuration.MessageToPlayerTimeout); } }); - if (lastItem != -1) - { + if (lastItem != -1) { this.Store.lastMessageToPlayer = DateTime.Now; this.Store.lastMessageToPlayerItem = lastItem; } lastItem = this.doAnnouncement(this.Configuration.SayToAllChatDelay, this.Store.lastSayToAllChat, this.Store.lastSayToAllChatItem, this.Configuration.SayToAllChat, this.Server.SayToAllChat); - if (lastItem != -1) - { + if (lastItem != -1) { this.Store.lastSayToAllChat = DateTime.Now; this.Store.lastSayToAllChatItem = lastItem; } @@ -68,20 +57,16 @@ private async void announcements() } } - private int doAnnouncement(int delay, DateTime lastAnnounce, int lastItem, string[] messages, Action action) - { - if (messages.Length == 0) - { + private int doAnnouncement(int delay, DateTime lastAnnounce, int lastItem, string[] messages, Action action) { + if (messages.Length == 0) { return -1; } - if (DateTime.Now.Subtract(lastAnnounce).TotalSeconds < delay) - { + if (DateTime.Now.Subtract(lastAnnounce).TotalSeconds < delay) { return -1; } - if (lastItem >= messages.Length) - { + if (lastItem >= messages.Length) { lastItem = 0; } @@ -91,8 +76,7 @@ private int doAnnouncement(int delay, DateTime lastAnnounce, int lastItem, strin } } -public class AnnouncementsConfiguration : ModuleConfiguration -{ +public class AnnouncementsConfiguration : ModuleConfiguration { public int AnnounceLongDelay { get; set; } = 600; public int AnnounceShortDelay { get; set; } = 300; public int UILogOnServerDelay { get; set; } = 60; @@ -112,8 +96,7 @@ public class AnnouncementsConfiguration : ModuleConfiguration }; } -public class AnnouncementStore : ModuleConfiguration -{ +public class AnnouncementStore : ModuleConfiguration { public DateTime lastAnnounceLong { get; set; } = DateTime.MinValue; public DateTime lastAnnounceShort { get; set; } = DateTime.MinValue; public DateTime lastUILogOnServer { get; set; } = DateTime.MinValue; diff --git a/BasicProgression.cs b/BasicProgression.cs index 285db37..8e40f6e 100644 --- a/BasicProgression.cs +++ b/BasicProgression.cs @@ -2,16 +2,14 @@ using BBRAPIModules; using System; using System.IO; -using System.Text.Json; using System.Threading.Tasks; using static BattleBitAPI.Common.PlayerStats; namespace BattleBitBaseModules { -[Module("Provide basic persistent progression for players", "1.1.1")] -public class BasicProgression : BattleBitModule -{ - public BasicProgressionConfiguration Configuration { get; set; } = null!; + [Module("Provide basic persistent progression for players", "1.1.1")] + public class BasicProgression : BattleBitModule { + public BasicProgressionConfiguration Configuration { get; set; } = null!; public DirectoryInfo DataDir => new DirectoryInfo(GlobalConfiguration.PerServer ? Path.Combine(GlobalConfiguration.DataDirectory, $"{this.Server.GameIP}:{this.Server.GamePort}") : GlobalConfiguration.DataDirectory); @@ -23,41 +21,38 @@ public override Task OnConnected() { return Task.CompletedTask; } - public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) - { - if (this.Configuration.ApplyInitialStatsOnEveryJoin) - { - args.Stats = this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats; - return; - } - - string playerFileName = getPlayerFileName(steamID); - for (int i = 0; i < 5; i++) - { - try - { - args.Stats = File.Exists(playerFileName) ? new PlayerStats(File.ReadAllBytes(playerFileName)) : (this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats); + public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { + if (this.Configuration.ApplyInitialStatsOnEveryJoin) { + args.Stats = this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats; return; } - var playerFile = getPlayerFile(steamID); + string playerFileName = getPlayerFileName(steamID); for (int i = 0; i < 5; i++) { try { - if (playerFile.Exists) { - args.Stats = GlobalConfiguration.PlainText ? JsonUtils.FromJsonFile(playerFile) : new PlayerStats(File.ReadAllBytes(playerFile.FullName)); - this.Logger.Info($"Read player stats for {steamID} from \"{playerFile.FullName}\""); - } else { - args.Stats = (GlobalConfiguration.InitialStats ?? args.Stats); - this.Logger.Info($"Applied initial player stats for {steamID}"); - } + args.Stats = File.Exists(playerFileName) ? new PlayerStats(File.ReadAllBytes(playerFileName)) : (this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats); return; - } catch (Exception ex) { - this.Logger.Error($"Tried {i} times to read from file {playerFile.FullName} but failed:{ex}"); } - await Task.Delay(250); + + + var playerFile = getPlayerFile(steamID); + for (int i = 0; i < 5; i++) { + try { + if (playerFile.Exists) { + args.Stats = GlobalConfiguration.PlainText ? JsonUtils.FromJsonFile(playerFile) : new PlayerStats(File.ReadAllBytes(playerFile.FullName)); + this.Logger.Info($"Read player stats for {steamID} from \"{playerFile.FullName}\""); + } else { + args.Stats = (GlobalConfiguration.InitialStats ?? args.Stats); + this.Logger.Info($"Applied initial player stats for {steamID}"); + } + return; + } catch (Exception ex) { + this.Logger.Error($"Tried {i} times to read from file {playerFile.FullName} but failed:{ex}"); + } + await Task.Delay(250); + } + this.Logger.Error($"Giving up trying to read \"{playerFile.FullName}\""); } - this.Logger.Error($"Giving up trying to read \"{playerFile.FullName}\""); - } public override async Task OnSavePlayerStats(ulong steamID, PlayerStats stats) { Console.WriteLine("OnSavePlayerStats"); @@ -94,177 +89,170 @@ public class Configuration : ModuleConfiguration { public bool ApplyInitialStatsOnEveryJoin { get; set; } = false; - public BasicPlayerStats? InitialStats { get; set; } = new BasicPlayerStats() - { - Achievements = new byte[0], - IsBanned = false, - Progress = new BasicPlayerProgress(), - Roles = Roles.None, - Selections = new byte[0], - ToolProgress = new byte[0] - }; -} + public BasicPlayerStats? InitialStats { get; set; } = new BasicPlayerStats() { + Achievements = new byte[0], + IsBanned = false, + Progress = new BasicPlayerProgress(), + Roles = Roles.None, + Selections = new byte[0], + ToolProgress = new byte[0] + }; + } -public class BasicPlayerStats -{ - public bool IsBanned { get; set; } + public class BasicPlayerStats { + public bool IsBanned { get; set; } - public Roles Roles { get; set; } + public Roles Roles { get; set; } - public BasicPlayerProgress Progress { get; set; } = new(); + public BasicPlayerProgress Progress { get; set; } = new(); - public byte[] ToolProgress { get; set; } = Array.Empty(); + public byte[] ToolProgress { get; set; } = Array.Empty(); - public byte[] Achievements { get; set; } = Array.Empty(); + public byte[] Achievements { get; set; } = Array.Empty(); - public byte[] Selections { get; set; } = Array.Empty(); + public byte[] Selections { get; set; } = Array.Empty(); - public PlayerStats ToPlayerStats() - { - return new() - { - IsBanned = this.IsBanned, - Roles = this.Roles, - Progress = this.Progress.ToPlayerProgress(), - ToolProgress = this.ToolProgress, - Achievements = this.Achievements, - Selections = this.Selections - }; - } -} + public PlayerStats ToPlayerStats() { + return new() { + IsBanned = this.IsBanned, + Roles = this.Roles, + Progress = this.Progress.ToPlayerProgress(), + ToolProgress = this.ToolProgress, + Achievements = this.Achievements, + Selections = this.Selections + }; + } + } -public class BasicPlayerProgress -{ - public uint KillCount { get; set; } + public class BasicPlayerProgress { + public uint KillCount { get; set; } - public uint LeaderKills { get; set; } + public uint LeaderKills { get; set; } - public uint AssaultKills { get; set; } + public uint AssaultKills { get; set; } - public uint MedicKills { get; set; } + public uint MedicKills { get; set; } - public uint EngineerKills { get; set; } + public uint EngineerKills { get; set; } - public uint SupportKills { get; set; } + public uint SupportKills { get; set; } - public uint ReconKills { get; set; } + public uint ReconKills { get; set; } - public uint DeathCount { get; set; } + public uint DeathCount { get; set; } - public uint WinCount { get; set; } + public uint WinCount { get; set; } - public uint LoseCount { get; set; } + public uint LoseCount { get; set; } - public uint FriendlyShots { get; set; } + public uint FriendlyShots { get; set; } - public uint FriendlyKills { get; set; } + public uint FriendlyKills { get; set; } - public uint Revived { get; set; } + public uint Revived { get; set; } - public uint RevivedTeamMates { get; set; } + public uint RevivedTeamMates { get; set; } - public uint Assists { get; set; } + public uint Assists { get; set; } - public uint Prestige { get; set; } + public uint Prestige { get; set; } - public uint Rank { get; set; } + public uint Rank { get; set; } - public uint EXP { get; set; } + public uint EXP { get; set; } - public uint ShotsFired { get; set; } + public uint ShotsFired { get; set; } - public uint ShotsHit { get; set; } + public uint ShotsHit { get; set; } - public uint Headshots { get; set; } + public uint Headshots { get; set; } - public uint ObjectivesComplated { get; set; } + public uint ObjectivesComplated { get; set; } - public uint HealedHPs { get; set; } + public uint HealedHPs { get; set; } - public uint RoadKills { get; set; } + public uint RoadKills { get; set; } - public uint Suicides { get; set; } + public uint Suicides { get; set; } - public uint VehiclesDestroyed { get; set; } + public uint VehiclesDestroyed { get; set; } - public uint VehicleHPRepaired { get; set; } + public uint VehicleHPRepaired { get; set; } - public uint LongestKill { get; set; } + public uint LongestKill { get; set; } - public uint PlayTimeSeconds { get; set; } + public uint PlayTimeSeconds { get; set; } - public uint LeaderPlayTime { get; set; } + public uint LeaderPlayTime { get; set; } - public uint AssaultPlayTime { get; set; } + public uint AssaultPlayTime { get; set; } - public uint MedicPlayTime { get; set; } + public uint MedicPlayTime { get; set; } - public uint EngineerPlayTime { get; set; } + public uint EngineerPlayTime { get; set; } - public uint SupportPlayTime { get; set; } + public uint SupportPlayTime { get; set; } - public uint ReconPlayTime { get; set; } + public uint ReconPlayTime { get; set; } - public uint LeaderScore { get; set; } + public uint LeaderScore { get; set; } - public uint AssaultScore { get; set; } + public uint AssaultScore { get; set; } - public uint MedicScore { get; set; } + public uint MedicScore { get; set; } - public uint EngineerScore { get; set; } + public uint EngineerScore { get; set; } - public uint SupportScore { get; set; } + public uint SupportScore { get; set; } - public uint ReconScore { get; set; } + public uint ReconScore { get; set; } - public uint TotalScore { get; set; } + public uint TotalScore { get; set; } - public PlayerProgess ToPlayerProgress() - { - return new() - { - KillCount = this.KillCount, - LeaderKills = this.LeaderKills, - AssaultKills = this.AssaultKills, - MedicKills = this.MedicKills, - EngineerKills = this.EngineerKills, - SupportKills = this.SupportKills, - ReconKills = this.ReconKills, - DeathCount = this.DeathCount, - WinCount = this.WinCount, - LoseCount = this.LoseCount, - FriendlyShots = this.FriendlyShots, - FriendlyKills = this.FriendlyKills, - Revived = this.Revived, - RevivedTeamMates = this.RevivedTeamMates, - Assists = this.Assists, - Prestige = this.Prestige, - Rank = this.Rank, - EXP = this.EXP, - ShotsFired = this.ShotsFired, - ShotsHit = this.ShotsHit, - Headshots = this.Headshots, - ObjectivesComplated = this.ObjectivesComplated, - HealedHPs = this.HealedHPs, - RoadKills = this.RoadKills, - Suicides = this.Suicides, - VehiclesDestroyed = this.VehiclesDestroyed, - VehicleHPRepaired = this.VehicleHPRepaired, - LongestKill = this.LongestKill, - PlayTimeSeconds = this.PlayTimeSeconds, - LeaderPlayTime = this.LeaderPlayTime, - AssaultPlayTime = this.AssaultPlayTime, - MedicPlayTime = this.MedicPlayTime, - EngineerPlayTime = this.EngineerPlayTime, - SupportPlayTime = this.SupportPlayTime, - ReconPlayTime = this.ReconPlayTime, - LeaderScore = this.LeaderScore, - AssaultScore = this.AssaultScore, - MedicScore = this.MedicScore, - EngineerScore = this.EngineerScore, - SupportScore = this.SupportScore, - ReconScore = this.ReconScore, - TotalScore = this.TotalScore - }; - } -} \ No newline at end of file + public PlayerProgess ToPlayerProgress() { + return new() { + KillCount = this.KillCount, + LeaderKills = this.LeaderKills, + AssaultKills = this.AssaultKills, + MedicKills = this.MedicKills, + EngineerKills = this.EngineerKills, + SupportKills = this.SupportKills, + ReconKills = this.ReconKills, + DeathCount = this.DeathCount, + WinCount = this.WinCount, + LoseCount = this.LoseCount, + FriendlyShots = this.FriendlyShots, + FriendlyKills = this.FriendlyKills, + Revived = this.Revived, + RevivedTeamMates = this.RevivedTeamMates, + Assists = this.Assists, + Prestige = this.Prestige, + Rank = this.Rank, + EXP = this.EXP, + ShotsFired = this.ShotsFired, + ShotsHit = this.ShotsHit, + Headshots = this.Headshots, + ObjectivesComplated = this.ObjectivesComplated, + HealedHPs = this.HealedHPs, + RoadKills = this.RoadKills, + Suicides = this.Suicides, + VehiclesDestroyed = this.VehiclesDestroyed, + VehicleHPRepaired = this.VehicleHPRepaired, + LongestKill = this.LongestKill, + PlayTimeSeconds = this.PlayTimeSeconds, + LeaderPlayTime = this.LeaderPlayTime, + AssaultPlayTime = this.AssaultPlayTime, + MedicPlayTime = this.MedicPlayTime, + EngineerPlayTime = this.EngineerPlayTime, + SupportPlayTime = this.SupportPlayTime, + ReconPlayTime = this.ReconPlayTime, + LeaderScore = this.LeaderScore, + AssaultScore = this.AssaultScore, + MedicScore = this.MedicScore, + EngineerScore = this.EngineerScore, + SupportScore = this.SupportScore, + ReconScore = this.ReconScore, + TotalScore = this.TotalScore + }; + } + } \ No newline at end of file diff --git a/BasicServerSettings.cs b/BasicServerSettings.cs index 0dfa2b1..7ea87b1 100644 --- a/BasicServerSettings.cs +++ b/BasicServerSettings.cs @@ -6,26 +6,21 @@ namespace BattleBitBaseModules; [Module("Configure basic server settings", "1.0.2")] -public class BasicServerSettings : BattleBitModule -{ +public class BasicServerSettings : BattleBitModule { public BasicServerSettingsConfiguration Configuration { get; set; } = null!; - public override Task OnConnected() - { + public override Task OnConnected() { this.applyServerSettings(); - foreach (RunnerPlayer player in this.Server.AllPlayers) - { + foreach (RunnerPlayer player in this.Server.AllPlayers) { this.applyPlayerSettings(player); } return Task.CompletedTask; } - public override Task OnGameStateChanged(GameState oldState, GameState newState) - { - if (oldState == newState) - { + public override Task OnGameStateChanged(GameState oldState, GameState newState) { + if (oldState == newState) { return Task.CompletedTask; } @@ -34,15 +29,13 @@ public override Task OnGameStateChanged(GameState oldState, GameState newState) return Task.CompletedTask; } - public override Task OnPlayerConnected(RunnerPlayer player) - { + public override Task OnPlayerConnected(RunnerPlayer player) { this.applyPlayerSettings(player); return Task.CompletedTask; } - private void applyServerSettings() - { + private void applyServerSettings() { this.Server.ServerSettings.APCSpawnDelayMultipler = this.Configuration.APCSpawnDelayMultipler ?? this.Server.ServerSettings.APCSpawnDelayMultipler; this.Server.ServerSettings.CanVoteDay = this.Configuration.CanVoteDay ?? this.Server.ServerSettings.CanVoteDay; this.Server.ServerSettings.CanVoteNight = this.Configuration.CanVoteNight ?? this.Server.ServerSettings.CanVoteNight; @@ -62,10 +55,8 @@ private void applyServerSettings() this.Server.ServerSettings.TeamlessMode = this.Configuration.TeamlessMode ?? this.Server.ServerSettings.TeamlessMode; } - private void applyRoundSettings(GameState gameState) - { - if (!this.Configuration.RoundSettings.ContainsKey(gameState)) - { + private void applyRoundSettings(GameState gameState) { + if (!this.Configuration.RoundSettings.ContainsKey(gameState)) { return; } @@ -78,8 +69,7 @@ private void applyRoundSettings(GameState gameState) this.Server.RoundSettings.TeamBTickets = roundSettings.TeamBTickets ?? this.Server.RoundSettings.TeamBTickets; } - private void applyPlayerSettings(RunnerPlayer player) - { + private void applyPlayerSettings(RunnerPlayer player) { player.Modifications.AirStrafe = this.Configuration.AirStrafe ?? player.Modifications.AirStrafe; player.Modifications.AllowedVehicles = this.Configuration.AllowedVehicles ?? player.Modifications.AllowedVehicles; player.Modifications.CanDeploy = this.Configuration.CanDeploy ?? player.Modifications.CanDeploy; @@ -112,8 +102,7 @@ private void applyPlayerSettings(RunnerPlayer player) player.Modifications.ReviveHP = this.Configuration.ReviveHP ?? player.Modifications.ReviveHP; } } -public class BasicServerSettingsConfiguration : ModuleConfiguration -{ +public class BasicServerSettingsConfiguration : ModuleConfiguration { // Server public float? APCSpawnDelayMultipler { get; set; } = null; public float? HelicopterSpawnDelayMultipler { get; set; } = null; @@ -174,8 +163,7 @@ public class BasicServerSettingsConfiguration : ModuleConfiguration }; } -public class RoundSettingsConfiguration -{ +public class RoundSettingsConfiguration { public double? MaxTickets { get; set; } = null; public int? PlayersToStart { get; set; } = null; public int? SecondsLeft { get; set; } = null; diff --git a/ChatOverwrite.cs b/ChatOverwrite.cs index 478b4ed..75e354b 100644 --- a/ChatOverwrite.cs +++ b/ChatOverwrite.cs @@ -1,6 +1,5 @@ using BattleBitAPI.Common; using BBRAPIModules; -using Bluscream; using Permissions; using System; using System.Collections.Generic; @@ -16,7 +15,7 @@ public class ChatOverwrite : BattleBitModule { [ModuleReference] #if DEBUG - public SteamApi? SteamApi { get; set; } = null!; + public SteamApi? SteamApi { get; set; } = null!; #else public SteamApi? SteamApi { get; set; } #endif @@ -28,24 +27,20 @@ public class ChatOverwrite : BattleBitModule { [ModuleReference] public GranularPermissions GranularPermissions { get; set; } = null!; - public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string msg) - { - if (this.CommandHandler is not null && this.CommandHandler.IsCommand(msg)) - { + public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string msg) { + if (this.CommandHandler is not null && this.CommandHandler.IsCommand(msg)) { this.Logger.Debug($"Ignoring message {msg} from {player.Name} because it is a command"); return Task.FromResult(true); } - if (this.GranularPermissions.HasPermission(player.SteamID, "ChatOverwrite.Bypass")) - { + if (this.GranularPermissions.HasPermission(player.SteamID, "ChatOverwrite.Bypass")) { this.Logger.Debug($"Ignoring message {msg} from {player.Name} because they have the ChatOverwrite.Bypass permission"); return Task.FromResult(true); } string? permission = this.Configuration.Overwrites.Keys.FirstOrDefault(k => this.GranularPermissions.HasPermission(player.SteamID, k)); - if (String.IsNullOrEmpty(permission)) - { + if (String.IsNullOrEmpty(permission)) { this.Logger.Debug($"Ignoring message {msg} from {player.Name} because they do not have any ChatOverwrite permissions"); return Task.FromResult(true); } @@ -59,22 +54,18 @@ public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel string teamName = player.Team == Team.TeamA ? "US" : "RU"; char? squadLetter = player.InSquad ? player.SquadName.ToString()[0] : null; - foreach (RunnerPlayer chatTarget in this.Server.AllPlayers) - { - if (channel == ChatChannel.SquadChat && (chatTarget.Team != player.Team || !chatTarget.InSquad || !player.InSquad || chatTarget.SquadName != player.SquadName)) - { + foreach (RunnerPlayer chatTarget in this.Server.AllPlayers) { + if (channel == ChatChannel.SquadChat && (chatTarget.Team != player.Team || !chatTarget.InSquad || !player.InSquad || chatTarget.SquadName != player.SquadName)) { continue; } - if (channel == ChatChannel.TeamChat && chatTarget.Team != player.Team) - { + if (channel == ChatChannel.TeamChat && chatTarget.Team != player.Team) { continue; } string nameColor = player.Team == chatTarget.Team && player.InSquad && chatTarget.InSquad && player.SquadName == chatTarget.SquadName ? "green" : (player.Team == chatTarget.Team ? "blue" : "red"); string teamAndSquadIndicator = teamName; - if (squadLetter != null) - { + if (squadLetter != null) { teamAndSquadIndicator += $"-{squadLetter}"; } teamAndSquadIndicator = $"[{teamAndSquadIndicator}]"; @@ -98,14 +89,12 @@ public string GetPlayerName(RunnerPlayer player) { if (!string.IsNullOrWhiteSpace(steam.Summary.RealName)) return steam.Summary.RealName; else if (!string.IsNullOrWhiteSpace(steam.Summary.PersonaName)) return steam.Summary.PersonaName; } - } + } return string.IsNullOrWhiteSpace(player.Name) ? player.SteamID.ToString() : player.Name; } - private static string FormatTextWithGradient(string text, string[] gradientColors) - { - if (string.IsNullOrEmpty(text) || gradientColors.Length == 0) - { + private static string FormatTextWithGradient(string text, string[] gradientColors) { + if (string.IsNullOrEmpty(text) || gradientColors.Length == 0) { return text; } @@ -116,8 +105,7 @@ private static string FormatTextWithGradient(string text, string[] gradientColor StringBuilder formattedName = new StringBuilder(); int currentIndex = 0; - for (int i = 0; i < segmentCount; i++) - { + for (int i = 0; i < segmentCount; i++) { int currentSegmentLength = segmentLength + (i < remainder ? 1 : 0); string currentColor = gradientColors[i]; string segmentText = text.Substring(currentIndex, currentSegmentLength); diff --git a/CommandHandler.cs b/CommandHandler.cs index 32e1d99..55d3933 100644 --- a/CommandHandler.cs +++ b/CommandHandler.cs @@ -12,8 +12,7 @@ namespace Commands; [Module("Basic in-game chat command handler library", "1.1.1")] -public class CommandHandler : BattleBitModule -{ +public class CommandHandler : BattleBitModule { public static CommandConfiguration CommandConfiguration { get; set; } = null!; public CommandSettings CommandSettings { get; set; } = null!; @@ -28,52 +27,41 @@ public class CommandHandler : BattleBitModule [ModuleReference] public dynamic? PlayerPermissions { get; set; } - public override void OnModulesLoaded() - { - if (this.PlayerPermissions is null && this.GranularPermissions is null) - { + public override void OnModulesLoaded() { + if (this.PlayerPermissions is null && this.GranularPermissions is null) { this.Logger.Warn($"Neither PlayerPermissions nor GranularPermissions is loaded. This module will not be able to check permissions for commands."); } this.Register(this); } - public void Register(BattleBitModule module) - { - foreach (MethodInfo method in module.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) - { + public void Register(BattleBitModule module) { + foreach (MethodInfo method in module.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { CommandCallbackAttribute? attribute = method.GetCustomAttribute(); - if (attribute == null) - { + if (attribute == null) { continue; } - if (attribute.AllowedRoles != Roles.None) - { + if (attribute.AllowedRoles != Roles.None) { this.Logger.Warn($"Command callback method {method.Name} in module {module.GetType().Name} has the deprecated AllowedRoles property set. Use Permissions instead. If you did not make this module, report the issue to the module author."); - } - else if (attribute.Permissions.Length == 1 && attribute.Permissions[0] == "*") - { + } else if (attribute.Permissions.Length == 1 && attribute.Permissions[0] == "*") { this.Logger.Warn($"Command callback method {method.Name} in module {module.GetType().Name} has no permissions set. This is not recommended as it allows everyone to use the command. Commands should have at least one granular permission or a PlayerPermissions role."); } // Store command permissions - if (!this.CommandSettings.Settings.ContainsKey(attribute.Name)) - { + if (!this.CommandSettings.Settings.ContainsKey(attribute.Name)) { this.CommandSettings.Settings.Add(attribute.Name, new()); } // Validate parameter ParameterInfo[] parameters = method.GetParameters(); - if (parameters.Length == 0) - { + if (parameters.Length == 0) { this.Logger.Error($"Command callback method {method.Name} in module {module.GetType().Name} has no parameters. Must have at least one parameter of type Context."); continue; } - if (parameters[0].ParameterType != typeof(Context)) - { + if (parameters[0].ParameterType != typeof(Context)) { this.Logger.Error($"Command callback method {method.Name} in module {module.GetType().Name} has invalid first parameter. Must be of type Context."); continue; } @@ -81,30 +69,23 @@ public void Register(BattleBitModule module) string command = attribute.Name.Trim().ToLower(); // Prevent duplicate command names in different methods or modules - if (this.commandCallbacks.ContainsKey(command)) - { - if (this.commandCallbacks[command].Method == method) - { + if (this.commandCallbacks.ContainsKey(command)) { + if (this.commandCallbacks[command].Method == method) { continue; } - if (this.commandCallbacks[command].Module.GetType().Name == module.GetType().Name) - { + if (this.commandCallbacks[command].Module.GetType().Name == module.GetType().Name) { this.Logger.Error($"Command callback method {method.Name} in module {module.GetType().Name} has the same command name {command} as another command callback method {this.commandCallbacks[command].Method.Name} in the same module."); continue; - } - else - { + } else { this.Logger.Error($"Command callback method {method.Name} in module {module.GetType().Name} has the same command name {command} as command callback method {this.commandCallbacks[command].Method.Name} in module {this.commandCallbacks[command].Module.GetType().Name}."); continue; } } // Prevent parent commands of subcommands (!perm command does not allow !perm add and !perm remove) - foreach (string subcommand in this.commandCallbacks.Keys.Where(c => c.Contains(' '))) - { - if (!subcommand.StartsWith(command)) - { + foreach (string subcommand in this.commandCallbacks.Keys.Where(c => c.Contains(' '))) { + if (!subcommand.StartsWith(command)) { continue; } @@ -113,15 +94,12 @@ public void Register(BattleBitModule module) } // Prevent subcommands of existing commands (!perm add and !perm remove do not allow !perm) - if (command.Contains(' ')) - { + if (command.Contains(' ')) { string[] subcommandChain = command.Split(' '); string subcommand = ""; - for (int i = 0; i < subcommandChain.Length; i++) - { + for (int i = 0; i < subcommandChain.Length; i++) { subcommand += $"{subcommandChain[i]} "; - if (this.commandCallbacks.ContainsKey(subcommand.Trim())) - { + if (this.commandCallbacks.ContainsKey(subcommand.Trim())) { this.Logger.Error($"Command callback {command} in module {module.GetType().Name} conflicts with parent command {subcommand.Trim()}."); continue; } @@ -134,10 +112,8 @@ public void Register(BattleBitModule module) this.CommandSettings.Save(); } - public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string message) - { - if (!IsCommand(message)) - { + public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string message) { + if (!IsCommand(message)) { return Task.FromResult(true); } @@ -146,39 +122,30 @@ public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel return Task.FromResult(false); } - public override void OnConsoleCommand(string command) - { - if (!IsCommand(command)) - { + public override void OnConsoleCommand(string command) { + if (!IsCommand(command)) { return; } Task.Run(() => this.HandleCommand(new ConsoleSource(), command)); } - public bool IsCommand(string message) - { + public bool IsCommand(string message) { return message.StartsWith(CommandConfiguration.CommandPrefix) && message.Length > CommandConfiguration.CommandPrefix.Length; } - public bool HasPermissionForCommand(RunnerPlayer player, CommandCallbackAttribute attribute) - { - if (attribute.AllowedRoles != Roles.None) - { + public bool HasPermissionForCommand(RunnerPlayer player, CommandCallbackAttribute attribute) { + if (attribute.AllowedRoles != Roles.None) { this.Logger.Warn($"Command {attribute.Name} has the deprecated AllowedRoles property set. Use Permissions instead. If you did not make this module, report the issue to the module author."); - if (attribute.Permissions.Length == 1 && attribute.Permissions[0] == "*") - { + if (attribute.Permissions.Length == 1 && attribute.Permissions[0] == "*") { List roles = new(); - foreach (Roles role in Enum.GetValues(typeof(Roles))) - { - if (role == Roles.None) - { + foreach (Roles role in Enum.GetValues(typeof(Roles))) { + if (role == Roles.None) { continue; } - if ((attribute.AllowedRoles & role) == role) - { + if ((attribute.AllowedRoles & role) == role) { roles.Add(role); } } @@ -188,50 +155,40 @@ public bool HasPermissionForCommand(RunnerPlayer player, CommandCallbackAttribut } } - if (attribute.Permissions.Length == 0 || attribute.Permissions[0] == "*") - { + if (attribute.Permissions.Length == 0 || attribute.Permissions[0] == "*") { return true; } - if (this.PlayerPermissions is null && this.GranularPermissions is null) - { + if (this.PlayerPermissions is null && this.GranularPermissions is null) { this.Logger.Warn($"Command {attribute.Name} requires permissions but neither PlayerPermissions nor GranularPermissions is loaded."); return false; } // Permission overwrites from configuration file string[] requiredPermissions = attribute.Permissions; - if (this.CommandSettings.Settings.ContainsKey(attribute.Name) && this.CommandSettings.Settings.ContainsKey(attribute.Name) && this.CommandSettings.Settings[attribute.Name]?.Permissions is not null) - { + if (this.CommandSettings.Settings.ContainsKey(attribute.Name) && this.CommandSettings.Settings.ContainsKey(attribute.Name) && this.CommandSettings.Settings[attribute.Name]?.Permissions is not null) { requiredPermissions = this.CommandSettings.Settings[attribute.Name]!.Permissions!; } // PlayerPermissions module - if (this.PlayerPermissions is not null) - { - foreach (string requiredPermission in requiredPermissions) - { - if (!Enum.TryParse(requiredPermission, true, out Roles role)) - { + if (this.PlayerPermissions is not null) { + foreach (string requiredPermission in requiredPermissions) { + if (!Enum.TryParse(requiredPermission, true, out Roles role)) { this.Logger.Warn($"Command {attribute.Name} could not resolve {requiredPermission} to a Role for PlayerPermissions."); this.Logger.Info($"This warning can be ignored if you are also using the GranularPermissions module as the permission may be defined there."); continue; } - if (this.PlayerPermissions?.HasPlayerRole(player.SteamID, role)) - { + if (this.PlayerPermissions?.HasPlayerRole(player.SteamID, role)) { return true; } } } // GranularPermissions module - if (this.GranularPermissions is not null) - { - foreach (string requiredPermission in requiredPermissions) - { - if (this.GranularPermissions.HasPermission(player.SteamID, requiredPermission)) - { + if (this.GranularPermissions is not null) { + foreach (string requiredPermission in requiredPermissions) { + if (this.GranularPermissions.HasPermission(player.SteamID, requiredPermission)) { return true; } } @@ -240,8 +197,7 @@ public bool HasPermissionForCommand(RunnerPlayer player, CommandCallbackAttribut return false; } - public void HandleCommand(Source source, string message) - { + public void HandleCommand(Source source, string message) { string[] fullCommand = parseCommandString(message); string command = fullCommand[0].Trim().ToLower()[CommandConfiguration.CommandPrefix.Length..]; @@ -249,19 +205,14 @@ public void HandleCommand(Source source, string message) Context errorContext = new Context(source, message, command, Array.Empty(), Array.Empty(), null, this, null); int subCommandSkip; - for (subCommandSkip = 1; subCommandSkip < fullCommand.Length && !this.commandCallbacks.ContainsKey(command); subCommandSkip++) - { + for (subCommandSkip = 1; subCommandSkip < fullCommand.Length && !this.commandCallbacks.ContainsKey(command); subCommandSkip++) { command += $" {fullCommand[subCommandSkip]}"; } - if (!this.commandCallbacks.ContainsKey(command)) - { - if (chatSource is not null) - { + if (!this.commandCallbacks.ContainsKey(command)) { + if (chatSource is not null) { errorContext.Reply($"Command not found: {command}"); - } - else - { + } else { errorContext.Reply($"Command not found: {command}"); } return; @@ -272,23 +223,19 @@ public void HandleCommand(Source source, string message) (BattleBitModule module, MethodInfo method) = this.commandCallbacks[command]; CommandCallbackAttribute commandCallbackAttribute = method.GetCustomAttribute()!; - if (source is ConsoleSource && !commandCallbackAttribute.ConsoleCommand) - { + if (source is ConsoleSource && !commandCallbackAttribute.ConsoleCommand) { this.Logger.Error($"Command {command} is not a console command."); return; } // Permissions - if (chatSource is not null && !this.HasPermissionForCommand(chatSource.Invoker, commandCallbackAttribute)) - { + if (chatSource is not null && !this.HasPermissionForCommand(chatSource.Invoker, commandCallbackAttribute)) { bool hideInaccessible = CommandConfiguration.HideInaccessibleCommands; - if (this.CommandSettings.Settings[command]?.HideInaccessible is not null) - { + if (this.CommandSettings.Settings[command]?.HideInaccessible is not null) { hideInaccessible = this.CommandSettings.Settings[command]!.HideInaccessible!.Value; } - if (hideInaccessible) - { + if (hideInaccessible) { errorContext.Reply($"Command not found: {command}"); return; } @@ -300,82 +247,61 @@ public void HandleCommand(Source source, string message) ParameterInfo[] parameters = method.GetParameters(); bool hasOptional = parameters.Any(p => p.IsOptional); - if (fullCommand.Length - 1 < parameters.Skip(1).Count(p => !p.IsOptional) || fullCommand.Length - 1 > parameters.Length - 1) - { + if (fullCommand.Length - 1 < parameters.Skip(1).Count(p => !p.IsOptional) || fullCommand.Length - 1 > parameters.Length - 1) { sendCommandUsageMessage(errorContext, method, $"Require {(hasOptional ? $"between {parameters.Skip(1).Count(p => !p.IsOptional)} and {parameters.Length - 1}" : $"{parameters.Length - 1}")} but got {fullCommand.Length - 1} argument{((fullCommand.Length - 1) == 1 ? "" : "s")}."); return; } object?[] args = new object[parameters.Length]; - for (int i = 1; i < parameters.Length; i++) - { + for (int i = 1; i < parameters.Length; i++) { ParameterInfo parameter = parameters[i]; - if (parameter.IsOptional && i >= fullCommand.Length) - { + if (parameter.IsOptional && i >= fullCommand.Length) { args[i] = parameter.DefaultValue; continue; } string argument = fullCommand[i].Trim(); - if (parameter.ParameterType == typeof(string)) - { + if (parameter.ParameterType == typeof(string)) { args[i] = argument; - } - else if (parameter.ParameterType == typeof(RunnerPlayer)) - { + } else if (parameter.ParameterType == typeof(RunnerPlayer)) { RunnerPlayer? targetPlayer = null; - if (ulong.TryParse(argument, out ulong steamId) && this.Server.AllPlayers.FirstOrDefault(p => p.SteamID == steamId) is RunnerPlayer playerBySteamId) - { + if (ulong.TryParse(argument, out ulong steamId) && this.Server.AllPlayers.FirstOrDefault(p => p.SteamID == steamId) is RunnerPlayer playerBySteamId) { args[i] = targetPlayer; continue; } - if (this.PlayerFinder is not null) - { - try - { + if (this.PlayerFinder is not null) { + try { targetPlayer = this.PlayerFinder.ByNamePart(argument); - } - catch (Exception ex) - { - if (chatSource is not null) - { + } catch (Exception ex) { + if (chatSource is not null) { errorContext.Reply($"Error while searching for player name containing {argument}.{Environment.NewLine}{ex.Message}"); - } - else - { + } else { this.Logger.Error($"Error while searching for player name containing {argument}.{Environment.NewLine}{ex.Message}"); } return; } - if (targetPlayer == null) - { + if (targetPlayer == null) { errorContext.Reply($"Could not find player name containing {argument}."); return; } - } - else - { + } else { targetPlayer = this.Server.AllPlayers.FirstOrDefault(p => p.Name.Equals(argument, StringComparison.OrdinalIgnoreCase)); } - if (targetPlayer == null) - { + if (targetPlayer == null) { errorContext.Reply($"Could not find player {argument}."); return; } args[i] = targetPlayer; - } - else - { - if (!tryParseParameter(parameter, argument, out object? parsedValue)) - { + } else { + if (!tryParseParameter(parameter, argument, out object? parsedValue)) { sendCommandUsageMessage(errorContext, method, $"Couldn't parse value {argument} to type {parameter.ParameterType.Name}"); return; } @@ -387,93 +313,67 @@ public void HandleCommand(Source source, string message) args[0] = new Context(source, message, command, fullCommand.Skip(1).ToArray(), args.Skip(1).ToArray(), module, this, commandCallbackAttribute); object? result = method.Invoke(module, args); - if (result is not null) - { + if (result is not null) { source.Reply((Context)args[0]!, result.ToString() ?? "No reply"); } } - private void sendCommandUsageMessage(Context context, MethodInfo method, string? error = null) - { + private void sendCommandUsageMessage(Context context, MethodInfo method, string? error = null) { CommandCallbackAttribute commandCallbackAttribute = method.GetCustomAttribute()!; bool hasOptional = method.GetParameters().Any(p => p.IsOptional); - if (context.Source is ChatSource chatSource) - { + if (context.Source is ChatSource chatSource) { context.Reply($"Invalid command usage{(error == null ? "" : $" ({error})")}.
Usage: {CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name} {string.Join(' ', method.GetParameters().Skip(1).Select(s => $"{s.Name}{(s.IsOptional ? "*" : "")}"))}{(hasOptional ? "
* Parameter is optional." : "")}"); - } - else - { + } else { context.Reply($"Invalid command usage{(error == null ? "" : $" ({error})")}.{Environment.NewLine}Usage: {CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name} {string.Join(' ', method.GetParameters().Skip(1).Select(s => $"{s.Name}{(s.IsOptional ? "*" : "")}"))}{(hasOptional ? $"{Environment.NewLine}* Parameter is optional." : "")}"); } } - private static bool tryParseParameter(ParameterInfo parameterInfo, string input, out object? parsedValue) - { + private static bool tryParseParameter(ParameterInfo parameterInfo, string input, out object? parsedValue) { parsedValue = null; - try - { - if (parameterInfo.ParameterType.IsEnum) - { + try { + if (parameterInfo.ParameterType.IsEnum) { parsedValue = Enum.Parse(parameterInfo.ParameterType, input, true); - } - else - { + } else { Type? targetType = targetType = Nullable.GetUnderlyingType(parameterInfo.ParameterType); - if (targetType is null) - { + if (targetType is null) { targetType = parameterInfo.ParameterType; } parsedValue = Convert.ChangeType(input, targetType); } return true; - } - catch - { + } catch { return false; } } - private static string[] parseCommandString(string command) - { + private static string[] parseCommandString(string command) { List parameterValues = new(); string[] tokens = command.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); bool insideQuotes = false; StringBuilder currentValue = new(); - foreach (var token in tokens) - { - if (!insideQuotes) - { - if (token.StartsWith("\"") && token.EndsWith("\"")) - { + foreach (var token in tokens) { + if (!insideQuotes) { + if (token.StartsWith("\"") && token.EndsWith("\"")) { insideQuotes = false; currentValue.Clear(); parameterValues.Add(token.Substring(1, token.Length - 2)); - } - else if (token.StartsWith("\"")) - { + } else if (token.StartsWith("\"")) { insideQuotes = true; currentValue.Append(token.Substring(1)); - } - else - { + } else { parameterValues.Add(token); } - } - else - { - if (token.EndsWith("\"")) - { + } else { + if (token.EndsWith("\"")) { insideQuotes = false; currentValue.Append(" ").Append(token.Substring(0, token.Length - 1)); parameterValues.Add(currentValue.ToString()); currentValue.Clear(); - } - else - { + } else { currentValue.Append(" ").Append(token); } } @@ -482,85 +382,63 @@ private static string[] parseCommandString(string command) return parameterValues.Select(unescapeQuotes).ToArray(); } - private static string unescapeQuotes(string input) - { + private static string unescapeQuotes(string input) { return input.Replace("\\\"", "\""); } [CommandCallback("help", Description = "Shows this help message", Permissions = new[] { "CommandHandler.Help" }, ConsoleCommand = true)] - public string HelpCommand(Context context, int page = 1) - { + public string HelpCommand(Context context, int page = 1) { List helpLines = new(); - foreach (var (commandKey, (module, method)) in this.commandCallbacks) - { + foreach (var (commandKey, (module, method)) in this.commandCallbacks) { CommandCallbackAttribute commandCallbackAttribute = method.GetCustomAttribute()!; - if (context.Source is ChatSource chatSource && !this.HasPermissionForCommand(chatSource.Invoker, commandCallbackAttribute)) - { + if (context.Source is ChatSource chatSource && !this.HasPermissionForCommand(chatSource.Invoker, commandCallbackAttribute)) { continue; } - if (context.Source is ChatSource) - { + if (context.Source is ChatSource) { helpLines.Add($"{CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name}{(string.IsNullOrEmpty(commandCallbackAttribute.Description) ? "" : $": {commandCallbackAttribute.Description}")}"); - } - else - { + } else { helpLines.Add($"{CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name}{(string.IsNullOrEmpty(commandCallbackAttribute.Description) ? "" : $": {commandCallbackAttribute.Description}")}"); } } int pages = (int)Math.Ceiling((double)helpLines.Count / CommandConfiguration.CommandsPerPage); - if (page < 1 || page > pages) - { - if (context.Source is ChatSource) - { + if (page < 1 || page > pages) { + if (context.Source is ChatSource) { return $"Invalid page number. Must be between 1 and {pages}."; - } - else - { + } else { return $"Invalid page number. Must be between 1 and {pages}."; } } - if (context.Source is ChatSource) - { + if (context.Source is ChatSource) { return $"<#FFA500>Available commands
{Environment.NewLine}{string.Join(Environment.NewLine, helpLines.Skip((page - 1) * CommandConfiguration.CommandsPerPage).Take(CommandConfiguration.CommandsPerPage))}{(pages > 1 ? $"{Environment.NewLine}Page {page} of {pages}{(page < pages ? $" - type !help {page + 1} for next page" : "")}" : "")}"; - } - else - { + } else { return $"Available commands{Environment.NewLine}{string.Join(Environment.NewLine, helpLines.Skip((page - 1) * CommandConfiguration.CommandsPerPage).Take(CommandConfiguration.CommandsPerPage))}{(pages > 1 ? $"{Environment.NewLine}Page {page} of {pages}{(page < pages ? $" - type !help {page + 1} for next page" : "")}" : "")}"; } } [CommandCallback("cmdhelp", Description = "Shows help for a specific command", Permissions = new[] { "CommandHandler.CommandHelp" }, ConsoleCommand = true)] - public string CommandHelpCommand(Context context, string command) - { - if (!this.commandCallbacks.TryGetValue(command, out var commandCallback)) - { - if (context.Source is ChatSource) - { + public string CommandHelpCommand(Context context, string command) { + if (!this.commandCallbacks.TryGetValue(command, out var commandCallback)) { + if (context.Source is ChatSource) { return $"Command {command} not found."; - } - else - { + } else { return $"Command {command} not found."; } } CommandCallbackAttribute commandCallbackAttribute = commandCallback.Method.GetCustomAttribute()!; - if (context.Source is ChatSource chatSource && !this.HasPermissionForCommand(chatSource.Invoker, commandCallbackAttribute)) - { + if (context.Source is ChatSource chatSource && !this.HasPermissionForCommand(chatSource.Invoker, commandCallbackAttribute)) { bool hideInaccessible = CommandConfiguration.HideInaccessibleCommands; - if (this.CommandSettings.Settings[command]?.HideInaccessible is not null) - { + if (this.CommandSettings.Settings[command]?.HideInaccessible is not null) { hideInaccessible = this.CommandSettings.Settings[command]!.HideInaccessible!.Value; } - if (hideInaccessible) - { + if (hideInaccessible) { return $"Command {command} not found."; } @@ -569,19 +447,15 @@ public string CommandHelpCommand(Context context, string command) bool hasOptional = commandCallback.Method.GetParameters().Any(p => p.IsOptional); - if (context.Source is ChatSource) - { + if (context.Source is ChatSource) { return $"{commandCallback.Module.GetType().Name} {commandCallbackAttribute.Name}
{commandCallbackAttribute.Description}
<#F5F5F5>{CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name} {string.Join(' ', commandCallback.Method.GetParameters().Skip(1).Select(s => $"{s.Name}{(s.IsOptional ? "*" : "")}"))}{(hasOptional ? "
* Parameter is optional." : "")}"; - } - else - { + } else { return $"{commandCallback.Module.GetType().Name} {commandCallbackAttribute.Name}{Environment.NewLine}{commandCallbackAttribute.Description}{Environment.NewLine}{CommandConfiguration.CommandPrefix}{commandCallbackAttribute.Name} {string.Join(' ', commandCallback.Method.GetParameters().Skip(1).Select(s => $"{s.Name}{(s.IsOptional ? "*" : "")}"))}{(hasOptional ? $"{Environment.NewLine}* Parameter is optional." : "")}"; } } } -public class CommandCallbackAttribute : Attribute -{ +public class CommandCallbackAttribute : Attribute { public string Name { get; set; } public string Description { get; set; } = string.Empty; @@ -589,14 +463,12 @@ public class CommandCallbackAttribute : Attribute public string[] Permissions { get; set; } = new[] { "*" }; public bool ConsoleCommand { get; set; } = false; - public CommandCallbackAttribute(string name) - { + public CommandCallbackAttribute(string name) { this.Name = name; } } -public class CommandConfiguration : ModuleConfiguration -{ +public class CommandConfiguration : ModuleConfiguration { public string CommandPrefix { get; set; } = "!"; public int CommandsPerPage { get; set; } = 6; public int MessageTimeout { get; set; } = 15; @@ -604,21 +476,18 @@ public class CommandConfiguration : ModuleConfiguration public bool ReplyToChat { get; set; } = false; } -public class CommandSettings : ModuleConfiguration -{ +public class CommandSettings : ModuleConfiguration { public Dictionary Settings { get; set; } = new(); } -public class CommandSetting -{ +public class CommandSetting { public string[]? Permissions { get; set; } public bool? ReplyToChat { get; set; } public int? MessageTimeout { get; set; } public bool? HideInaccessible { get; set; } } -public class Context -{ +public class Context { public Source Source { get; set; } public string Message { get; set; } public string Command { get; set; } @@ -628,8 +497,7 @@ public class Context public CommandHandler CommandHandler { get; set; } public CommandCallbackAttribute? CommandCallbackAttribute { get; set; } - public Context(Source source, string message, string command, string[] rawParameters, object?[] parameters, BattleBitModule? module, CommandHandler commandHandler, CommandCallbackAttribute? commandCallbackAttribute) - { + public Context(Source source, string message, string command, string[] rawParameters, object?[] parameters, BattleBitModule? module, CommandHandler commandHandler, CommandCallbackAttribute? commandCallbackAttribute) { this.Source = source; this.Message = message; this.Command = command; @@ -640,43 +508,33 @@ public Context(Source source, string message, string command, string[] rawParame this.CommandCallbackAttribute = commandCallbackAttribute; } - public virtual void Reply(string message) - { + public virtual void Reply(string message) { this.Source.Reply(this, message); } } -public abstract class Source -{ +public abstract class Source { public abstract void Reply(Context context, string message); } -public class ChatSource : Source -{ - public ChatSource(RunnerPlayer invoker) - { +public class ChatSource : Source { + public ChatSource(RunnerPlayer invoker) { this.Invoker = invoker; } public RunnerPlayer Invoker { get; } - public override void Reply(Context context, string message) - { + public override void Reply(Context context, string message) { bool replyToChat = CommandHandler.CommandConfiguration.ReplyToChat; - if (context.CommandHandler.CommandSettings.Settings[context.Command]?.ReplyToChat is not null) - { + if (context.CommandHandler.CommandSettings.Settings[context.Command]?.ReplyToChat is not null) { replyToChat = context.CommandHandler.CommandSettings.Settings[context.Command]!.ReplyToChat!.Value; } - if (replyToChat) - { + if (replyToChat) { this.Invoker.SayToChat(message); - } - else - { + } else { int messageTimeout = CommandHandler.CommandConfiguration.MessageTimeout; - if (context.CommandHandler.CommandSettings.Settings[context.Command]?.MessageTimeout is not null) - { + if (context.CommandHandler.CommandSettings.Settings[context.Command]?.MessageTimeout is not null) { messageTimeout = context.CommandHandler.CommandSettings.Settings[context.Command]!.MessageTimeout!.Value; } @@ -685,10 +543,8 @@ public override void Reply(Context context, string message) } } -public class ConsoleSource : Source -{ - public override void Reply(Context context, string message) - { +public class ConsoleSource : Source { + public override void Reply(Context context, string message) { context.CommandHandler.Logger.Info(message); } } diff --git a/DiscordWebhooks.cs b/DiscordWebhooks.cs index 7659ca6..09dbbd7 100644 --- a/DiscordWebhooks.cs +++ b/DiscordWebhooks.cs @@ -11,72 +11,55 @@ namespace BattleBitDiscordWebhooks; [Module("Send some basic events to Discord and allow for other modules to send messages to Discord", "1.1.0")] -public class DiscordWebhooks : BattleBitModule -{ +public class DiscordWebhooks : BattleBitModule { private Queue discordMessageQueue = new(); private HttpClient httpClient = new HttpClient(); public WebhookConfiguration Configuration { get; set; } = null!; - public override void OnModulesLoaded() - { - if (string.IsNullOrEmpty(this.Configuration.WebhookURL)) - { + public override void OnModulesLoaded() { + if (string.IsNullOrEmpty(this.Configuration.WebhookURL)) { this.Unload(); this.Logger.Error("Webhook URL is not set. Please set it in the configuration file."); } } - public override Task OnConnected() - { + public override Task OnConnected() { discordMessageQueue.Enqueue(new WarningMessage("Server connected to API")); Task.Run(() => sendChatMessagesToDiscord()); return Task.CompletedTask; } - public override Task OnDisconnected() - { + public override Task OnDisconnected() { discordMessageQueue.Enqueue(new WarningMessage("Server disconnected from API")); return base.OnDisconnected(); } - public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string msg) - { + public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string msg) { discordMessageQueue.Enqueue(new ChatMessage(player.Name, player.SteamID, channel, msg)); return Task.FromResult(true); } - public override Task OnPlayerReported(RunnerPlayer from, RunnerPlayer to, ReportReason reason, string additional) - { + public override Task OnPlayerReported(RunnerPlayer from, RunnerPlayer to, ReportReason reason, string additional) { this.discordMessageQueue.Enqueue(new WarningMessage($"{from.Name} ({from.SteamID}) reported {to.Name} ({to.SteamID}) for {reason}:{Environment.NewLine}> {additional}")); return Task.CompletedTask; } - public void SendMessage(string message, string? webhookURL = null) - { - if (webhookURL is not null) - { + public void SendMessage(string message, string? webhookURL = null) { + if (webhookURL is not null) { Task.Run(() => sendWebhookMessage(webhookURL, message)); - } - else - { + } else { this.discordMessageQueue.Enqueue(new RawTextMessage(message)); } } - private async Task sendChatMessagesToDiscord() - { - do - { + private async Task sendChatMessagesToDiscord() { + do { List messages = new(); - do - { - try - { - while (this.discordMessageQueue.TryDequeue(out DiscordMessage? message)) - { - if (message == null) - { + do { + try { + while (this.discordMessageQueue.TryDequeue(out DiscordMessage? message)) { + if (message == null) { continue; } @@ -84,15 +67,12 @@ private async Task sendChatMessagesToDiscord() } - if (messages.Count > 0) - { + if (messages.Count > 0) { await sendWebhookMessage(this.Configuration.WebhookURL, string.Join(Environment.NewLine, messages.Select(message => message.ToString()))); } messages.Clear(); - } - catch (Exception ex) - { + } catch (Exception ex) { this.Logger.Error($"Failed to process message queue.", ex); await Task.Delay(500); } @@ -102,13 +82,10 @@ private async Task sendChatMessagesToDiscord() } while (this.Server?.IsConnected == true); } - private async Task sendWebhookMessage(string webhookUrl, string message) - { + private async Task sendWebhookMessage(string webhookUrl, string message) { bool success = false; - while (!success) - { - var payload = new - { + while (!success) { + var payload = new { content = message }; @@ -117,8 +94,7 @@ private async Task sendWebhookMessage(string webhookUrl, string message) var response = await this.httpClient.PostAsync(webhookUrl, content); - if (!response.IsSuccessStatusCode) - { + if (!response.IsSuccessStatusCode) { this.Logger.Error($"Error sending webhook message. Status Code: {response.StatusCode}"); } @@ -128,31 +104,25 @@ private async Task sendWebhookMessage(string webhookUrl, string message) } -internal class DiscordMessage -{ +internal class DiscordMessage { } -internal class RawTextMessage : DiscordMessage -{ +internal class RawTextMessage : DiscordMessage { public string Message { get; set; } - public RawTextMessage(string message) - { + public RawTextMessage(string message) { this.Message = message; } - public override string ToString() - { + public override string ToString() { return this.Message; } } -internal class ChatMessage : DiscordMessage -{ +internal class ChatMessage : DiscordMessage { public string PlayerName { get; set; } = string.Empty; - public ChatMessage(string playerName, ulong steamID, ChatChannel channel, string message) - { + public ChatMessage(string playerName, ulong steamID, ChatChannel channel, string message) { this.PlayerName = playerName; this.SteamID = steamID; this.Channel = channel; @@ -163,18 +133,15 @@ public ChatMessage(string playerName, ulong steamID, ChatChannel channel, string public ChatChannel Channel { get; set; } public string Message { get; set; } = string.Empty; - public override string ToString() - { + public override string ToString() { return $":speech_balloon: [{this.SteamID}] {this.PlayerName}: {this.Message}"; } } -internal class JoinAndLeaveMessage : DiscordMessage -{ +internal class JoinAndLeaveMessage : DiscordMessage { public int PlayerCount { get; set; } - public JoinAndLeaveMessage(int playerCount, string playerName, ulong steamID, bool joined) - { + public JoinAndLeaveMessage(int playerCount, string playerName, ulong steamID, bool joined) { this.PlayerCount = playerCount; this.PlayerName = playerName; this.SteamID = steamID; @@ -185,16 +152,13 @@ public JoinAndLeaveMessage(int playerCount, string playerName, ulong steamID, bo public ulong SteamID { get; set; } public bool Joined { get; set; } - public override string ToString() - { + public override string ToString() { return $"{(this.Joined ? ":arrow_right:" : ":arrow_left:")} [{this.SteamID}] {this.PlayerName} {(this.Joined ? "joined" : "left")} ({this.PlayerCount} players)"; } } -internal class WarningMessage : DiscordMessage -{ - public WarningMessage(string message) - { +internal class WarningMessage : DiscordMessage { + public WarningMessage(string message) { this.Message = message; } @@ -202,13 +166,11 @@ public WarningMessage(string message) public string Message { get; set; } - public override string ToString() - { + public override string ToString() { return $":warning: {this.Message}"; } } -public class WebhookConfiguration : ModuleConfiguration -{ +public class WebhookConfiguration : ModuleConfiguration { public string WebhookURL { get; set; } = string.Empty; } \ No newline at end of file diff --git a/GeoLimiter.cs b/GeoLimiter.cs index d600529..2534725 100644 --- a/GeoLimiter.cs +++ b/GeoLimiter.cs @@ -8,8 +8,7 @@ namespace GeoLimiter; [Module("Kick users based on their country of origin", "1.2.0")] -public class GeoLimiter : BattleBitModule -{ +public class GeoLimiter : BattleBitModule { public static GeoLimiterConfiguration Configuration { get; set; } = null!; public GeoLimiterServerConfiguration ServerConfiguration { get; set; } = null!; @@ -18,17 +17,14 @@ public class GeoLimiter : BattleBitModule private static Geolocation[] database = null!; - public override void OnModulesLoaded() - { - if (!File.Exists(Path.Combine(Configuration.DataDirectory, Configuration.DatabaseFileName))) - { + public override void OnModulesLoaded() { + if (!File.Exists(Path.Combine(Configuration.DataDirectory, Configuration.DatabaseFileName))) { this.Logger.Error($"Could not find geolocation database at {Path.GetFullPath(Path.Combine(Configuration.DataDirectory, Configuration.DatabaseFileName))}"); this.Unload(); return; } - if (database != null) - { + if (database != null) { return; } @@ -41,17 +37,14 @@ public override void OnModulesLoaded() this.Logger.Info($"Loaded {database.Length} geolocation entries, took {stopwatch.ElapsedMilliseconds}ms"); } - public override Task OnPlayerConnected(RunnerPlayer player) - { - if (this.GranularPermissions is not null && ServerConfiguration.IgnoredPermissions?.Any(p => this.GranularPermissions.HasPermission(player.SteamID, p)) == true) - { + public override Task OnPlayerConnected(RunnerPlayer player) { + if (this.GranularPermissions is not null && ServerConfiguration.IgnoredPermissions?.Any(p => this.GranularPermissions.HasPermission(player.SteamID, p)) == true) { this.Logger.Info($"Player {player.SteamID} has an ignored permission, skipping..."); return Task.CompletedTask; } byte[] ipBytes = player.IP.GetAddressBytes(); - if (BitConverter.IsLittleEndian) - { + if (BitConverter.IsLittleEndian) { Array.Reverse(ipBytes); } @@ -59,22 +52,19 @@ public override Task OnPlayerConnected(RunnerPlayer player) this.Logger.Debug($"IP address {player.IP} as integer: {ipNumber}"); Geolocation? geolocation = database.FirstOrDefault(x => x.FromIP <= ipNumber && x.ToIP >= ipNumber); - if (geolocation == null) - { + if (geolocation == null) { this.Logger.Warn($"Could not find geolocation for IP {player.IP}"); return Task.CompletedTask; } this.Logger.Info($"Found geolocation for IP {player.IP}: {geolocation.CountryName} ({geolocation.CountryCode})"); - if (this.ServerConfiguration.AllowCountryCodes && this.ServerConfiguration.CountryCodes.Contains(geolocation.CountryCode)) - { + if (this.ServerConfiguration.AllowCountryCodes && this.ServerConfiguration.CountryCodes.Contains(geolocation.CountryCode)) { this.Logger.Info($"Country {geolocation.CountryCode} is allowed, skipping..."); return Task.CompletedTask; } - if (!this.ServerConfiguration.AllowCountryCodes && !this.ServerConfiguration.CountryCodes.Contains(geolocation.CountryCode)) - { + if (!this.ServerConfiguration.AllowCountryCodes && !this.ServerConfiguration.CountryCodes.Contains(geolocation.CountryCode)) { this.Logger.Info($"Country {geolocation.CountryCode} is not denied, skipping..."); return Task.CompletedTask; } @@ -86,14 +76,12 @@ public override Task OnPlayerConnected(RunnerPlayer player) } } -public class GeoLimiterConfiguration : ModuleConfiguration -{ +public class GeoLimiterConfiguration : ModuleConfiguration { public string DataDirectory { get; set; } = "./data/GeoLimiter"; public string DatabaseFileName { get; set; } = "IP2LOCATION-LITE-DB1.CSV"; } -public class GeoLimiterServerConfiguration : ModuleConfiguration -{ +public class GeoLimiterServerConfiguration : ModuleConfiguration { public string[] CountryCodes { get; set; } = new string[] { "DE", "AT", "CH" }; public bool AllowCountryCodes { get; set; } = true; @@ -102,8 +90,7 @@ public class GeoLimiterServerConfiguration : ModuleConfiguration public string[] IgnoredPermissions { get; set; } = Array.Empty(); } -public class Geolocation -{ +public class Geolocation { public uint FromIP { get; set; } public uint ToIP { get; set; } public string CountryCode { get; set; } = null!; diff --git a/GranularPermissions.cs b/GranularPermissions.cs index e67e864..1b26e4e 100644 --- a/GranularPermissions.cs +++ b/GranularPermissions.cs @@ -6,8 +6,7 @@ namespace Permissions; [Module("Granular permissions for players and groups.", "1.0.0")] -public class GranularPermissions : BattleBitModule -{ +public class GranularPermissions : BattleBitModule { public const string CatchAll = "*"; public const string RevokePrefix = "-"; public const string PermissionSeparator = "."; @@ -15,81 +14,67 @@ public class GranularPermissions : BattleBitModule public static PermissionsConfiguration Configuration { get; set; } = null!; public PermissionsServerConfiguration ServerConfiguration { get; set; } = null!; - public void Save() - { + public void Save() { this.Logger.Debug("Saving permissions configuration."); this.ServerConfiguration.Save(); Configuration.Save(); } - public bool HasPermission(ulong steamId, string permission) - { + public bool HasPermission(ulong steamId, string permission) { this.Logger.Debug($"Checking if player {steamId} has permission {permission}."); - if (permission == CatchAll) - { + if (permission == CatchAll) { this.Logger.Debug($"Player {steamId} has permission {permission} because it is a catch-all permission."); return true; } string[] playerGroups = this.ServerConfiguration.PlayerGroups.ContainsKey(steamId) ? this.ServerConfiguration.PlayerGroups[steamId].ToArray() : Array.Empty(); - if (Configuration.Groups.ContainsKey(CatchAll)) - { + if (Configuration.Groups.ContainsKey(CatchAll)) { playerGroups = playerGroups.Append(CatchAll).ToArray(); } bool permitted = false; // Player permissions - if (this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) - { - if (this.ServerConfiguration.PlayerPermissions[steamId].Any(p => p.Equals(RevokePrefix + permission, StringComparison.InvariantCultureIgnoreCase))) - { + if (this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) { + if (this.ServerConfiguration.PlayerPermissions[steamId].Any(p => p.Equals(RevokePrefix + permission, StringComparison.InvariantCultureIgnoreCase))) { this.Logger.Debug($"Player {steamId} does not have permission {permission} because they have revoked permission {permission}."); return false; } - if (this.ServerConfiguration.PlayerPermissions[steamId].Any(p => p.Equals(permission, StringComparison.InvariantCultureIgnoreCase))) - { + if (this.ServerConfiguration.PlayerPermissions[steamId].Any(p => p.Equals(permission, StringComparison.InvariantCultureIgnoreCase))) { this.Logger.Debug($"Player {steamId} has permission {permission} because they have permission {permission}."); permitted = true; } - if (this.ServerConfiguration.PlayerPermissions[steamId].Any(p => p.Equals(CatchAll, StringComparison.InvariantCultureIgnoreCase))) - { + if (this.ServerConfiguration.PlayerPermissions[steamId].Any(p => p.Equals(CatchAll, StringComparison.InvariantCultureIgnoreCase))) { this.Logger.Debug($"Player {steamId} has permission {permission} because they have catch-all permission *."); permitted = true; } } // Group permissions - foreach (string group in playerGroups) - { - if (!Configuration.Groups.ContainsKey(group)) - { + foreach (string group in playerGroups) { + if (!Configuration.Groups.ContainsKey(group)) { this.Logger.Error($"Group {group} of player {steamId} does not exist."); continue; } - if (Configuration.Groups[group].Contains("-*")) - { + if (Configuration.Groups[group].Contains("-*")) { this.Logger.Debug($"Player {steamId} does not have permission {permission} because group {group} has revoked all permissions."); return false; } - if (Configuration.Groups[group].Any(p => p.Equals(RevokePrefix + permission, StringComparison.InvariantCultureIgnoreCase))) - { + if (Configuration.Groups[group].Any(p => p.Equals(RevokePrefix + permission, StringComparison.InvariantCultureIgnoreCase))) { this.Logger.Debug($"Player {steamId} does not have permission {permission} because group {group} has revoked permission {permission}."); return false; } - if (Configuration.Groups[group].Any(p => p.Equals(permission, StringComparison.InvariantCultureIgnoreCase))) - { + if (Configuration.Groups[group].Any(p => p.Equals(permission, StringComparison.InvariantCultureIgnoreCase))) { permitted = true; } - if (Configuration.Groups[group].Any(p => p.Equals(CatchAll, StringComparison.InvariantCultureIgnoreCase))) - { + if (Configuration.Groups[group].Any(p => p.Equals(CatchAll, StringComparison.InvariantCultureIgnoreCase))) { this.Logger.Debug($"Player {steamId} has permission {permission} because group {group} has catch-all permission *."); permitted = true; } @@ -98,22 +83,18 @@ public bool HasPermission(ulong steamId, string permission) // Partial permissions with catch-all string[] permissionPath = permission.Split(PermissionSeparator); string partialPermissionPath = string.Empty; - foreach (string permissionPart in permissionPath) - { + foreach (string permissionPart in permissionPath) { partialPermissionPath += $"{permissionPart}{PermissionSeparator}"; // Partial player permissions - if (this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) - { - if (this.ServerConfiguration.PlayerPermissions[steamId].Any(p => p.Equals(RevokePrefix + partialPermissionPath + CatchAll, StringComparison.InvariantCultureIgnoreCase))) - { + if (this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) { + if (this.ServerConfiguration.PlayerPermissions[steamId].Any(p => p.Equals(RevokePrefix + partialPermissionPath + CatchAll, StringComparison.InvariantCultureIgnoreCase))) { this.Logger.Debug($"Player {steamId} does not have permission {permission} because they have revoked permission {partialPermissionPath + CatchAll}."); return false; } - if (this.ServerConfiguration.PlayerPermissions[steamId].Any(p => p.Equals(partialPermissionPath + CatchAll, StringComparison.InvariantCultureIgnoreCase))) - { + if (this.ServerConfiguration.PlayerPermissions[steamId].Any(p => p.Equals(partialPermissionPath + CatchAll, StringComparison.InvariantCultureIgnoreCase))) { this.Logger.Debug($"Player {steamId} has permission {permission} because they have permission {partialPermissionPath + CatchAll}."); permitted = true; } @@ -121,22 +102,18 @@ public bool HasPermission(ulong steamId, string permission) // Partial group permissions - foreach (string group in playerGroups) - { - if (!Configuration.Groups.ContainsKey(group)) - { + foreach (string group in playerGroups) { + if (!Configuration.Groups.ContainsKey(group)) { // We already logged this error above. continue; } - if (Configuration.Groups[group].Any(p => p.Equals(RevokePrefix + partialPermissionPath + CatchAll, StringComparison.InvariantCultureIgnoreCase))) - { + if (Configuration.Groups[group].Any(p => p.Equals(RevokePrefix + partialPermissionPath + CatchAll, StringComparison.InvariantCultureIgnoreCase))) { this.Logger.Debug($"Player {steamId} does not have permission {permission} because group {group} has revoked permission {partialPermissionPath + CatchAll}."); return false; } - if (Configuration.Groups[group].Any(p => p.Equals(partialPermissionPath + CatchAll, StringComparison.InvariantCultureIgnoreCase))) - { + if (Configuration.Groups[group].Any(p => p.Equals(partialPermissionPath + CatchAll, StringComparison.InvariantCultureIgnoreCase))) { this.Logger.Debug($"Player {steamId} has permission {permission} because group {group} has permission {partialPermissionPath + CatchAll}."); permitted = true; } @@ -148,12 +125,10 @@ public bool HasPermission(ulong steamId, string permission) return permitted; } - public void AddGroup(string group) - { + public void AddGroup(string group) { this.Logger.Debug($"Adding group {group}."); - if (Configuration.Groups.ContainsKey(group)) - { + if (Configuration.Groups.ContainsKey(group)) { this.Logger.Error($"Group {group} already exists."); return; } @@ -161,12 +136,10 @@ public void AddGroup(string group) Configuration.Groups.Add(group, new()); } - public void RemoveGroup(string group) - { + public void RemoveGroup(string group) { this.Logger.Debug($"Removing group {group}."); - if (!Configuration.Groups.ContainsKey(group)) - { + if (!Configuration.Groups.ContainsKey(group)) { this.Logger.Error($"Group {group} does not exist."); return; } @@ -174,21 +147,15 @@ public void RemoveGroup(string group) Configuration.Groups.Remove(group); } - public string[] GetGroups() - { + public string[] GetGroups() { return Configuration.Groups.Keys.ToArray(); } - public string[] GetPlayerGroups(ulong steamId) - { - if (!ServerConfiguration.PlayerGroups.ContainsKey(steamId)) - { - if (Configuration.Groups.ContainsKey(CatchAll)) - { + public string[] GetPlayerGroups(ulong steamId) { + if (!ServerConfiguration.PlayerGroups.ContainsKey(steamId)) { + if (Configuration.Groups.ContainsKey(CatchAll)) { return new[] { CatchAll }; - } - else - { + } else { return Array.Empty(); } } @@ -196,18 +163,15 @@ public string[] GetPlayerGroups(ulong steamId) return ServerConfiguration.PlayerGroups[steamId].ToArray(); } - public void AddGroupPermission(string group, string permission) - { + public void AddGroupPermission(string group, string permission) { this.Logger.Debug($"Adding permission {permission} to group {group}."); - if (!Configuration.Groups.ContainsKey(group)) - { + if (!Configuration.Groups.ContainsKey(group)) { this.Logger.Error($"Group {group} does not exist."); return; } - if (Configuration.Groups[group].Contains(permission)) - { + if (Configuration.Groups[group].Contains(permission)) { this.Logger.Error($"Group {group} already has permission {permission}."); return; } @@ -215,18 +179,15 @@ public void AddGroupPermission(string group, string permission) Configuration.Groups[group].Add(permission); } - public void RemoveGroupPermission(string group, string permission) - { + public void RemoveGroupPermission(string group, string permission) { this.Logger.Debug($"Removing permission {permission} from group {group}."); - if (!Configuration.Groups.ContainsKey(group)) - { + if (!Configuration.Groups.ContainsKey(group)) { this.Logger.Error($"Group {group} does not exist."); return; } - if (!Configuration.Groups[group].Contains(permission)) - { + if (!Configuration.Groups[group].Contains(permission)) { this.Logger.Error($"Group {group} does not have permission {permission}."); return; } @@ -234,24 +195,20 @@ public void RemoveGroupPermission(string group, string permission) Configuration.Groups[group].Remove(permission); } - public void AddRevokedGroupPermission(string group, string permission) - { + public void AddRevokedGroupPermission(string group, string permission) { this.Logger.Debug($"Adding revoked permission {permission} to group {group}."); this.AddGroupPermission(group, $"{RevokePrefix}{permission}"); } - public void RemoveRevokedGroupPermission(string group, string permission) - { + public void RemoveRevokedGroupPermission(string group, string permission) { this.Logger.Debug($"Removing revoked permission {permission} from group {group}."); this.RemoveGroupPermission(group, $"{RevokePrefix}{permission}"); } - public string[] GetGroupPermissions(string group) - { - if (!Configuration.Groups.ContainsKey(group)) - { + public string[] GetGroupPermissions(string group) { + if (!Configuration.Groups.ContainsKey(group)) { this.Logger.Error($"Group {group} does not exist."); return Array.Empty(); } @@ -259,18 +216,15 @@ public string[] GetGroupPermissions(string group) return Configuration.Groups[group].ToArray(); } - public void AddPlayerGroup(ulong steamId, string group) - { + public void AddPlayerGroup(ulong steamId, string group) { this.Logger.Debug($"Adding player {steamId} to group {group}."); - if (!ServerConfiguration.PlayerGroups.ContainsKey(steamId)) - { + if (!ServerConfiguration.PlayerGroups.ContainsKey(steamId)) { this.Logger.Debug($"Player {steamId} does not have any groups."); ServerConfiguration.PlayerGroups.Add(steamId, new()); } - if (ServerConfiguration.PlayerGroups[steamId].Contains(group)) - { + if (ServerConfiguration.PlayerGroups[steamId].Contains(group)) { this.Logger.Error($"Player {steamId} already has group {group}."); return; } @@ -278,18 +232,15 @@ public void AddPlayerGroup(ulong steamId, string group) ServerConfiguration.PlayerGroups[steamId].Add(group); } - public void RemovePlayerGroup(ulong steamId, string group) - { + public void RemovePlayerGroup(ulong steamId, string group) { this.Logger.Debug($"Removing player {steamId} from group {group}."); - if (!ServerConfiguration.PlayerGroups.ContainsKey(steamId)) - { + if (!ServerConfiguration.PlayerGroups.ContainsKey(steamId)) { this.Logger.Error($"Player {steamId} does not have any groups."); return; } - if (!ServerConfiguration.PlayerGroups[steamId].Contains(group)) - { + if (!ServerConfiguration.PlayerGroups[steamId].Contains(group)) { this.Logger.Error($"Player {steamId} does not have group {group}."); return; } @@ -297,18 +248,15 @@ public void RemovePlayerGroup(ulong steamId, string group) ServerConfiguration.PlayerGroups[steamId].Remove(group); } - public void AddPlayerPermission(ulong steamId, string permission) - { + public void AddPlayerPermission(ulong steamId, string permission) { this.Logger.Debug($"Adding permission {permission} to player {steamId}."); - if (!this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) - { + if (!this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) { this.Logger.Debug($"Player {steamId} does not have any permissions."); this.ServerConfiguration.PlayerPermissions.Add(steamId, new()); } - if (this.ServerConfiguration.PlayerPermissions[steamId].Contains(permission)) - { + if (this.ServerConfiguration.PlayerPermissions[steamId].Contains(permission)) { this.Logger.Error($"Player {steamId} already has permission {permission}."); return; } @@ -316,18 +264,15 @@ public void AddPlayerPermission(ulong steamId, string permission) this.ServerConfiguration.PlayerPermissions[steamId].Add(permission); } - public void RemovePlayerPermission(ulong steamId, string permission) - { + public void RemovePlayerPermission(ulong steamId, string permission) { this.Logger.Debug($"Removing permission {permission} from player {steamId}."); - if (!this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) - { + if (!this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) { this.Logger.Error($"Player {steamId} does not have any permissions."); return; } - if (!this.ServerConfiguration.PlayerPermissions[steamId].Contains(permission)) - { + if (!this.ServerConfiguration.PlayerPermissions[steamId].Contains(permission)) { this.Logger.Error($"Player {steamId} does not have permission {permission}."); return; } @@ -335,24 +280,20 @@ public void RemovePlayerPermission(ulong steamId, string permission) this.ServerConfiguration.PlayerPermissions[steamId].Remove(permission); } - public void AddRevokedPlayerPermission(ulong steamId, string permission) - { + public void AddRevokedPlayerPermission(ulong steamId, string permission) { this.Logger.Debug($"Adding revoked permission {permission} to player {steamId}."); this.AddPlayerPermission(steamId, $"{RevokePrefix}{permission}"); } - public void RemoveRevokedPlayerPermission(ulong steamId, string permission) - { + public void RemoveRevokedPlayerPermission(ulong steamId, string permission) { this.Logger.Debug($"Removing revoked permission {permission} from player {steamId}."); this.RemovePlayerPermission(steamId, $"{RevokePrefix}{permission}"); } - public string[] GetPlayerPermissions(ulong steamId) - { - if (!this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) - { + public string[] GetPlayerPermissions(ulong steamId) { + if (!this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) { this.Logger.Debug($"Player {steamId} does not have any player-specific permissions."); return Array.Empty(); } @@ -360,17 +301,14 @@ public string[] GetPlayerPermissions(ulong steamId) return this.ServerConfiguration.PlayerPermissions[steamId].ToArray(); } - public string[] GetAllPlayerPermissions(ulong steamId) - { + public string[] GetAllPlayerPermissions(ulong steamId) { List permissions = new(); - if (this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) - { + if (this.ServerConfiguration.PlayerPermissions.ContainsKey(steamId)) { permissions.AddRange(this.ServerConfiguration.PlayerPermissions[steamId]); } - foreach (string group in this.GetPlayerGroups(steamId)) - { + foreach (string group in this.GetPlayerGroups(steamId)) { permissions.AddRange(this.GetGroupPermissions(group)); } @@ -378,15 +316,13 @@ public string[] GetAllPlayerPermissions(ulong steamId) } } -public class PermissionsConfiguration : ModuleConfiguration -{ +public class PermissionsConfiguration : ModuleConfiguration { public Dictionary> Groups { get; set; } = new() { { GranularPermissions.CatchAll, new() } }; } -public class PermissionsServerConfiguration : ModuleConfiguration -{ +public class PermissionsServerConfiguration : ModuleConfiguration { public Dictionary> PlayerGroups { get; set; } = new(); public Dictionary> PlayerPermissions { get; set; } = new(); } diff --git a/GranularPermissionsCommands.cs b/GranularPermissionsCommands.cs index e28420f..c3475fc 100644 --- a/GranularPermissionsCommands.cs +++ b/GranularPermissionsCommands.cs @@ -10,8 +10,7 @@ namespace PermissionsManager; [RequireModule(typeof(CommandHandler))] [RequireModule(typeof(GranularPermissions))] [Module("Provide commands for managing GranularPermissions", "1.0.0")] -public class GranularPermissionsCommands : BattleBitModule -{ +public class GranularPermissionsCommands : BattleBitModule { [ModuleReference] public GranularPermissions GranularPermissions { get; set; } = null!; [ModuleReference] @@ -19,14 +18,12 @@ public class GranularPermissionsCommands : BattleBitModule public GranularPermissionsCommandsConfiguration Configuration { get; set; } = null!; - public override void OnModulesLoaded() - { + public override void OnModulesLoaded() { this.CommandHandler.Register(this); } [CommandCallback("addplayerperm", Description = "Adds a permission to a player", Permissions = new[] { "GranularPermissions.AddPlayerPerm" })] - public string AddPermissionCommand(Context context, RunnerPlayer player, string permission) - { + public string AddPermissionCommand(Context context, RunnerPlayer player, string permission) { this.GranularPermissions.AddPlayerPermission(player.SteamID, permission); this.GranularPermissions.Save(); @@ -36,8 +33,7 @@ public string AddPermissionCommand(Context context, RunnerPlayer player, string } [CommandCallback("removeplayerperm", Description = "Removes a permission from a player", Permissions = new[] { "GranularPermissions.RemovePlayerPerm" })] - public string RemovePermissionCommand(Context context, RunnerPlayer player, string permission) - { + public string RemovePermissionCommand(Context context, RunnerPlayer player, string permission) { this.GranularPermissions.RemovePlayerPermission(player.SteamID, permission); this.GranularPermissions.Save(); @@ -47,15 +43,12 @@ public string RemovePermissionCommand(Context context, RunnerPlayer player, stri } [CommandCallback("clearplayerperms", Description = "Clears all permissions and groups from a player", Permissions = new[] { "GranularPermissions.ClearPlayerPerms" })] - public string ClearPermissionCommand(Context context, RunnerPlayer player) - { - foreach (string group in this.GranularPermissions.GetPlayerGroups(player.SteamID)) - { + public string ClearPermissionCommand(Context context, RunnerPlayer player) { + foreach (string group in this.GranularPermissions.GetPlayerGroups(player.SteamID)) { this.GranularPermissions.RemovePlayerGroup(player.SteamID, group); } - foreach (string permission in this.GranularPermissions.GetPlayerPermissions(player.SteamID)) - { + foreach (string permission in this.GranularPermissions.GetPlayerPermissions(player.SteamID)) { this.GranularPermissions.RemovePlayerPermission(player.SteamID, permission); } @@ -67,10 +60,8 @@ public string ClearPermissionCommand(Context context, RunnerPlayer player) } [CommandCallback("listplayerperms", Description = "Lists player permissions", Permissions = new[] { "GranularPermissions.ListPlayerPerms" })] - public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, int page = 1) - { - if (page < 1) - { + public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, int page = 1) { + if (page < 1) { page = 1; } @@ -84,15 +75,12 @@ public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, } [CommandCallback("addplayergroup", Description = "Adds a group to a player", Permissions = new[] { "GranularPermissions.AddPlayerGroup" })] - public string AddGroupCommand(Context context, RunnerPlayer player, string group) - { - if (this.GranularPermissions.GetPlayerGroups(player.SteamID).Contains(group)) - { + public string AddGroupCommand(Context context, RunnerPlayer player, string group) { + if (this.GranularPermissions.GetPlayerGroups(player.SteamID).Contains(group)) { return $"{player.Name} already has group {group}"; } - if (!this.GranularPermissions.GetGroups().Contains(group)) - { + if (!this.GranularPermissions.GetGroups().Contains(group)) { return $"Group {group} does not exist"; } @@ -105,10 +93,8 @@ public string AddGroupCommand(Context context, RunnerPlayer player, string group } [CommandCallback("removeplayergroup", Description = "Removes a group from a player", Permissions = new[] { "GranularPermissions.RemovePlayerGroup" })] - public string RemoveGroupCommand(Context context, RunnerPlayer player, string group) - { - if (!this.GranularPermissions.GetPlayerGroups(player.SteamID).Contains(group)) - { + public string RemoveGroupCommand(Context context, RunnerPlayer player, string group) { + if (!this.GranularPermissions.GetPlayerGroups(player.SteamID).Contains(group)) { return $"{player.Name} does not have group {group}"; } @@ -121,10 +107,8 @@ public string RemoveGroupCommand(Context context, RunnerPlayer player, string gr } [CommandCallback("clearplayergroups", Description = "Clears all groups from a player", Permissions = new[] { "GranularPermissions.ClearPlayerGroups" })] - public string ClearGroupCommand(Context context, RunnerPlayer player) - { - foreach (string group in this.GranularPermissions.GetPlayerGroups(player.SteamID)) - { + public string ClearGroupCommand(Context context, RunnerPlayer player) { + foreach (string group in this.GranularPermissions.GetPlayerGroups(player.SteamID)) { this.GranularPermissions.RemovePlayerGroup(player.SteamID, group); } @@ -136,10 +120,8 @@ public string ClearGroupCommand(Context context, RunnerPlayer player) } [CommandCallback("listplayergroups", Description = "Lists player groups", Permissions = new[] { "GranularPermissions.ListPlayerGroups" })] - public string ListGroupCommand(Context context, RunnerPlayer targetPlayer, int page = 1) - { - if (page < 1) - { + public string ListGroupCommand(Context context, RunnerPlayer targetPlayer, int page = 1) { + if (page < 1) { page = 1; } @@ -155,10 +137,8 @@ public string ListGroupCommand(Context context, RunnerPlayer targetPlayer, int p } [CommandCallback("addgroup", Description = "Adds a group", Permissions = new[] { "GranularPermissions.AddGroup" })] - public string AddGroupCommand(Context context, string group) - { - if (this.GranularPermissions.GetGroups().Contains(group)) - { + public string AddGroupCommand(Context context, string group) { + if (this.GranularPermissions.GetGroups().Contains(group)) { return $"Group {group} already exists"; } @@ -171,10 +151,8 @@ public string AddGroupCommand(Context context, string group) } [CommandCallback("removegroup", Description = "Removes a group", Permissions = new[] { "GranularPermissions.RemoveGroup" })] - public string RemoveGroupCommand(Context context, string group) - { - if (!this.GranularPermissions.GetGroups().Contains(group)) - { + public string RemoveGroupCommand(Context context, string group) { + if (!this.GranularPermissions.GetGroups().Contains(group)) { return $"Group {group} does not exist"; } @@ -187,10 +165,8 @@ public string RemoveGroupCommand(Context context, string group) } [CommandCallback("listgroups", Description = "Lists groups", Permissions = new[] { "GranularPermissions.ListGroups" })] - public string ListGroupCommand(Context context, int page = 1) - { - if (page < 1) - { + public string ListGroupCommand(Context context, int page = 1) { + if (page < 1) { page = 1; } @@ -206,15 +182,12 @@ public string ListGroupCommand(Context context, int page = 1) } [CommandCallback("addgroupperm", Description = "Adds a permission to a group", Permissions = new[] { "GranularPermissions.AddGroupPerm" })] - public string AddGroupPermissionCommand(Context context, string group, string permission) - { - if (!this.GranularPermissions.GetGroups().Contains(group)) - { + public string AddGroupPermissionCommand(Context context, string group, string permission) { + if (!this.GranularPermissions.GetGroups().Contains(group)) { return $"Group {group} does not exist"; } - if (this.GranularPermissions.GetGroupPermissions(group).Contains(permission)) - { + if (this.GranularPermissions.GetGroupPermissions(group).Contains(permission)) { return $"{group} already has permission {permission}"; } @@ -227,15 +200,12 @@ public string AddGroupPermissionCommand(Context context, string group, string pe } [CommandCallback("removegroupperm", Description = "Removes a permission from a group", Permissions = new[] { "GranularPermissions.RemoveGroupPerm" })] - public string RemoveGroupPermissionCommand(Context context, string group, string permission) - { - if (!this.GranularPermissions.GetGroups().Contains(group)) - { + public string RemoveGroupPermissionCommand(Context context, string group, string permission) { + if (!this.GranularPermissions.GetGroups().Contains(group)) { return $"Group {group} does not exist"; } - if (!this.GranularPermissions.GetGroupPermissions(group).Contains(permission)) - { + if (!this.GranularPermissions.GetGroupPermissions(group).Contains(permission)) { return $"{group} does not have permission {permission}"; } @@ -248,15 +218,12 @@ public string RemoveGroupPermissionCommand(Context context, string group, string } [CommandCallback("cleargroupperms", Description = "Clears all permissions from a group", Permissions = new[] { "GranularPermissions.ClearGroupPerms" })] - public string ClearGroupPermissionCommand(Context context, string group) - { - if (!this.GranularPermissions.GetGroups().Contains(group)) - { + public string ClearGroupPermissionCommand(Context context, string group) { + if (!this.GranularPermissions.GetGroups().Contains(group)) { return $"Group {group} does not exist"; } - foreach (string permission in this.GranularPermissions.GetGroupPermissions(group)) - { + foreach (string permission in this.GranularPermissions.GetGroupPermissions(group)) { this.GranularPermissions.RemoveGroupPermission(group, permission); } @@ -268,15 +235,12 @@ public string ClearGroupPermissionCommand(Context context, string group) } [CommandCallback("listgroupperms", Description = "Lists group permissions", Permissions = new[] { "GranularPermissions.ListGroupPerms" })] - public string ListGroupPermissionCommand(Context context, string group, int page = 1) - { - if (!this.GranularPermissions.GetGroups().Contains(group)) - { + public string ListGroupPermissionCommand(Context context, string group, int page = 1) { + if (!this.GranularPermissions.GetGroups().Contains(group)) { return $"Group {group} does not exist"; } - if (page < 1) - { + if (page < 1) { page = 1; } @@ -290,7 +254,6 @@ public string ListGroupPermissionCommand(Context context, string group, int page } } -public class GranularPermissionsCommandsConfiguration : ModuleConfiguration -{ +public class GranularPermissionsCommandsConfiguration : ModuleConfiguration { public int PermissionsPerPage { get; set; } = 6; } diff --git a/LoadingScreenText.cs b/LoadingScreenText.cs index 3eb41ed..ec5ec31 100644 --- a/LoadingScreenText.cs +++ b/LoadingScreenText.cs @@ -1,6 +1,5 @@ using BattleBitAPI.Common; using BBRAPIModules; -using Bluscream; using System; using System.Collections.Generic; using System.Linq; @@ -11,8 +10,7 @@ namespace BattleBitBaseModules; [RequireModule(typeof(Bluscream.BluscreamLib))] [RequireModule(typeof(BattleBitBaseModules.RichText))] [Module("Configure the loading screen text of your server", "1.0.0")] -public class LoadingScreenText : BattleBitModule -{ +public class LoadingScreenText : BattleBitModule { [ModuleReference] public LoadingScreenTextConfiguration Config { get; set; } = null!; diff --git a/MOTD.cs b/MOTD.cs index 809548e..a847e40 100644 --- a/MOTD.cs +++ b/MOTD.cs @@ -1,5 +1,4 @@ using BattleBitAPI.Common; -using BattleBitAPI.Features; using BBRAPIModules; using Commands; using System; @@ -11,8 +10,7 @@ namespace BattleBitBaseModules; [RequireModule(typeof(CommandHandler))] [Module("Show a message of the day to players who join the server", "1.1.0")] -public class MOTD : BattleBitModule -{ +public class MOTD : BattleBitModule { public MOTDConfiguration Configuration { get; set; } = null!; [ModuleReference] @@ -23,20 +21,16 @@ public class MOTD : BattleBitModule private List greetedPlayers = new(); - public override void OnModulesLoaded() - { - if (this.PlaceholderLib is null) - { + public override void OnModulesLoaded() { + if (this.PlaceholderLib is null) { this.Logger.Info("PlaceholderLib not found. MOTD will only support basic numbered placeholders."); } this.CommandHandler.Register(this); } - public override Task OnGameStateChanged(GameState oldState, GameState newState) - { - if (newState == GameState.EndingGame) - { + public override Task OnGameStateChanged(GameState oldState, GameState newState) { + if (newState == GameState.EndingGame) { greetedPlayers.Clear(); greetedPlayers.AddRange(this.Server.AllPlayers.Select(p => p.SteamID)); } @@ -44,10 +38,8 @@ public override Task OnGameStateChanged(GameState oldState, GameState newState) return Task.CompletedTask; } - public override Task OnPlayerConnected(RunnerPlayer player) - { - if (this.greetedPlayers.Contains(player.SteamID)) - { + public override Task OnPlayerConnected(RunnerPlayer player) { + if (this.greetedPlayers.Contains(player.SteamID)) { return Task.CompletedTask; } @@ -57,21 +49,18 @@ public override Task OnPlayerConnected(RunnerPlayer player) } [CommandCallback("setmotd", Description = "Sets the MOTD", Permissions = new[] { "MOTD.Set" })] - public void SetMOTD(Context context, string motd) - { + public void SetMOTD(Context context, string motd) { this.Configuration.MOTD = motd; this.Configuration.Save(); this.ShowMOTD(context); } [CommandCallback("motd", Description = "Shows the MOTD")] - public string ShowMOTD(Context context) - { + public string ShowMOTD(Context context) { ChatSource? chatSource = context.Source as ChatSource; string message; - if (this.PlaceholderLib is not null) - { + if (this.PlaceholderLib is not null) { message = new PlaceholderLib(this.Configuration.MOTD) .AddParam("servername", this.Server.ServerName) .AddParam("gamemode", this.Server.Gamemode) @@ -83,9 +72,7 @@ public string ShowMOTD(Context context) .AddParam("maxplayers", this.Server.MaxPlayerCount) .AddParam("name", chatSource?.Invoker.Name ?? context.Source.GetType().Name) .AddParam("ping", chatSource?.Invoker.PingMs ?? 0).Run(); - } - else - { + } else { message = string.Format(this.Configuration.MOTD, chatSource?.Invoker.Name ?? context.Source.GetType().Name, chatSource?.Invoker.PingMs ?? 0, this.Server.ServerName, this.Server.Gamemode, this.Server.Map, this.Server.DayNight, this.Server.MapSize.ToString().Trim('_'), this.Server.CurrentPlayerCount, this.Server.InQueuePlayerCount, this.Server.MaxPlayerCount); } @@ -93,7 +80,6 @@ public string ShowMOTD(Context context) } } -public class MOTDConfiguration : ModuleConfiguration -{ +public class MOTDConfiguration : ModuleConfiguration { public string MOTD { get; set; } = "Welcome!"; } diff --git a/ModeratorTools.cs b/ModeratorTools.cs index ce1e313..f97d9f1 100644 --- a/ModeratorTools.cs +++ b/ModeratorTools.cs @@ -10,29 +10,23 @@ namespace BattleBitBaseModules; [RequireModule(typeof(CommandHandler))] [Module("Basic moderator tools", "1.1.0")] -public class ModeratorTools : BattleBitModule -{ +public class ModeratorTools : BattleBitModule { [ModuleReference] public CommandHandler CommandHandler { get; set; } = null!; - public override void OnModulesLoaded() - { + public override void OnModulesLoaded() { this.CommandHandler.Register(this); } - public override Task OnConnected() - { + public override Task OnConnected() { Task.Run(playerInspection); return Task.CompletedTask; } - private async void playerInspection() - { - while (this.IsLoaded && this.Server.IsConnected) - { - foreach (KeyValuePair inspection in this.inspectPlayers) - { + private async void playerInspection() { + while (this.IsLoaded && this.Server.IsConnected) { + foreach (KeyValuePair inspection in this.inspectPlayers) { inspection.Key.Message(this.getPlayerInspectionText(inspection.Value)); } @@ -40,8 +34,7 @@ private async void playerInspection() } } - private string getPlayerInspectionText(RunnerPlayer target) - { + private string getPlayerInspectionText(RunnerPlayer target) { StringBuilder playerInfo = new(); playerInfo.AppendLine($"{target.Name} ({target.SteamID} - {target.Role}"); playerInfo.AppendLine($"Net: {target.IP} - {target.PingMs}ms"); @@ -56,8 +49,7 @@ private string getPlayerInspectionText(RunnerPlayer target) } [CommandCallback("Say", Description = "Prints a message to all players", Permissions = new[] { "ModeratorTools.Say" })] - public string Say(Context context, string message) - { + public string Say(Context context, string message) { this.Logger.Info($"[Say] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)}: {message}"); this.Server.SayToAllChat(message); @@ -65,8 +57,7 @@ public string Say(Context context, string message) } [CommandCallback("SayToPlayer", Description = "Prints a message to all players", Permissions = new[] { "ModeratorTools.SayToPlayer" })] - public string SayToPlayer(Context context, RunnerPlayer target, string message) - { + public string SayToPlayer(Context context, RunnerPlayer target, string message) { this.Logger.Info($"[SayToPlayer] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}: {message}"); this.Server.SayToChat(message, target.SteamID); @@ -74,8 +65,7 @@ public string SayToPlayer(Context context, RunnerPlayer target, string message) } [CommandCallback("AnnounceShort", Description = "Prints a short announce to all players", Permissions = new[] { "ModeratorTools.AnnounceShort" })] - public string AnnounceShort(Context context, string message) - { + public string AnnounceShort(Context context, string message) { this.Logger.Info($"[AnnounceShort] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)}: {message}"); this.Server.AnnounceShort(message); @@ -83,8 +73,7 @@ public string AnnounceShort(Context context, string message) } [CommandCallback("AnnounceLong", Description = "Prints a long announce to all players", Permissions = new[] { "ModeratorTools.AnnounceLong" })] - public string AnnounceLong(Context context, string message) - { + public string AnnounceLong(Context context, string message) { this.Logger.Info($"[AnnounceLong] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)}: {message}"); this.Server.AnnounceLong(message); @@ -92,16 +81,12 @@ public string AnnounceLong(Context context, string message) } [CommandCallback("Message", Description = "Messages a specific player", Permissions = new[] { "ModeratorTools.Message" })] - public string Message(Context context, RunnerPlayer target, string message, float? timeout = null) - { + public string Message(Context context, RunnerPlayer target, string message, float? timeout = null) { this.Logger.Info($"[Message] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}: {message}"); - if (timeout.HasValue) - { + if (timeout.HasValue) { target.Message(message, timeout.Value); - } - else - { + } else { target.Message(message); } @@ -109,8 +94,7 @@ public string Message(Context context, RunnerPlayer target, string message, floa } [CommandCallback("Clear", Description = "Clears the chat", Permissions = new[] { "ModeratorTools.Clear" })] - public string Clear(Context context) - { + public string Clear(Context context) { this.Logger.Info($"[Clear] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)}"); this.Server.SayToAllChat("".PadLeft(30, '\n') + "Chat cleared"); @@ -118,8 +102,7 @@ public string Clear(Context context) } [CommandCallback("Kick", Description = "Kicks a player", Permissions = new[] { "ModeratorTools.Kick" })] - public string Kick(Context context, RunnerPlayer target, string? reason = null) - { + public string Kick(Context context, RunnerPlayer target, string? reason = null) { this.Logger.Info($"[Kick] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}: {reason ?? string.Empty}"); target.Kick(reason ?? string.Empty); @@ -127,8 +110,7 @@ public string Kick(Context context, RunnerPlayer target, string? reason = null) } [CommandCallback("Ban", Description = "Bans a player", Permissions = new[] { "ModeratorTools.Ban" })] - public string Ban(Context context, RunnerPlayer target) - { + public string Ban(Context context, RunnerPlayer target) { this.Logger.Info($"[Ban] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); this.Server.ExecuteCommand($"ban {target.SteamID}"); target.Kick(); @@ -137,13 +119,11 @@ public string Ban(Context context, RunnerPlayer target) } [CommandCallback("Kill", Description = "Kills a player", Permissions = new[] { "ModeratorTools.Kill" })] - public string Kill(Context context, RunnerPlayer target, string? message = null) - { + public string Kill(Context context, RunnerPlayer target, string? message = null) { this.Logger.Info($"[Kill] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); target.Kill(); - if (!string.IsNullOrEmpty(message)) - { + if (!string.IsNullOrEmpty(message)) { target.Message(message); } @@ -151,18 +131,15 @@ public string Kill(Context context, RunnerPlayer target, string? message = null) } [CommandCallback("Gag", Description = "Gags a player", Permissions = new[] { "ModeratorTools.Gag" })] - public string Gag(Context context, RunnerPlayer target, string? message = null) - { + public string Gag(Context context, RunnerPlayer target, string? message = null) { this.Logger.Info($"[Gag] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); - if (this.gaggedPlayers.Contains(target.SteamID)) - { + if (this.gaggedPlayers.Contains(target.SteamID)) { return $"Player {target.Name} is already gagged"; } this.gaggedPlayers.Add(target.SteamID); - if (!string.IsNullOrEmpty(message)) - { + if (!string.IsNullOrEmpty(message)) { target.Message(message); } @@ -170,18 +147,15 @@ public string Gag(Context context, RunnerPlayer target, string? message = null) } [CommandCallback("Ungag", Description = "Ungags a player", Permissions = new[] { "ModeratorTools.Ungag" })] - public string Ungag(Context context, RunnerPlayer target, string? message = null) - { + public string Ungag(Context context, RunnerPlayer target, string? message = null) { this.Logger.Info($"[Ungag] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); - if (!this.gaggedPlayers.Contains(target.SteamID)) - { + if (!this.gaggedPlayers.Contains(target.SteamID)) { return $"Player {target.Name} is not gagged"; } this.gaggedPlayers.Remove(target.SteamID); - if (!string.IsNullOrEmpty(message)) - { + if (!string.IsNullOrEmpty(message)) { target.Message(message); } @@ -189,18 +163,15 @@ public string Ungag(Context context, RunnerPlayer target, string? message = null } [CommandCallback("Mute", Description = "Mutes a player", Permissions = new[] { "ModeratorTools.Mute" })] - public string Mute(Context context, RunnerPlayer target, string? message = null) - { + public string Mute(Context context, RunnerPlayer target, string? message = null) { this.Logger.Info($"[Mute] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); - if (target.Modifications.IsVoiceChatMuted) - { + if (target.Modifications.IsVoiceChatMuted) { return $"Player {target.Name} is already muted"; } target.Modifications.IsVoiceChatMuted = true; - if (!string.IsNullOrEmpty(message)) - { + if (!string.IsNullOrEmpty(message)) { target.Message(message); } @@ -208,18 +179,15 @@ public string Mute(Context context, RunnerPlayer target, string? message = null) } [CommandCallback("Unmute", Description = "Unmutes a player", Permissions = new[] { "ModeratorTools.Unmute" })] - public string Unmute(Context context, RunnerPlayer target, string? message = null) - { + public string Unmute(Context context, RunnerPlayer target, string? message = null) { this.Logger.Info($"[Unmute] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); - if (!target.Modifications.IsVoiceChatMuted) - { + if (!target.Modifications.IsVoiceChatMuted) { return $"Player {target.Name} is not muted"; } target.Modifications.IsVoiceChatMuted = false; - if (!string.IsNullOrEmpty(message)) - { + if (!string.IsNullOrEmpty(message)) { target.Message(message); } @@ -227,14 +195,12 @@ public string Unmute(Context context, RunnerPlayer target, string? message = nul } [CommandCallback("Silence", Description = "Mutes and gags a player", Permissions = new[] { "ModeratorTools.Silence" })] - public string Silence(Context context, RunnerPlayer target, string? message = null) - { + public string Silence(Context context, RunnerPlayer target, string? message = null) { this.Logger.Info($"[Silence] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); Mute(context, target); Gag(context, target); - if (!string.IsNullOrEmpty(message)) - { + if (!string.IsNullOrEmpty(message)) { target.Message(message); } @@ -242,14 +208,12 @@ public string Silence(Context context, RunnerPlayer target, string? message = nu } [CommandCallback("Unsilence", Description = "Unmutes and ungags a player", Permissions = new[] { "ModeratorTools.Unsilence" })] - public string Unsilence(Context context, RunnerPlayer target, string? message = null) - { + public string Unsilence(Context context, RunnerPlayer target, string? message = null) { this.Logger.Info($"[Unsilence] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); Unmute(context, target); Ungag(context, target); - if (!string.IsNullOrEmpty(message)) - { + if (!string.IsNullOrEmpty(message)) { target.Message(message); } @@ -257,32 +221,25 @@ public string Unsilence(Context context, RunnerPlayer target, string? message = } [CommandCallback("LockSpawn", Description = "Prevents a player or all players from spawning", Permissions = new[] { "ModeratorTools.LockSpawn" })] - public string LockSpawn(Context context, RunnerPlayer? target = null, string? message = null) - { - if (target == null) - { + public string LockSpawn(Context context, RunnerPlayer? target = null, string? message = null) { + if (target == null) { this.Logger.Info($"[LockSpawn] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> All"); this.globalSpawnLock = true; - foreach (RunnerPlayer player in this.Server.AllPlayers) - { + foreach (RunnerPlayer player in this.Server.AllPlayers) { player.Modifications.CanDeploy = false; } return "Spawn globally locked"; - } - else - { + } else { this.Logger.Info($"[LockSpawn] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); - if (this.lockedSpawns.Contains(target.SteamID)) - { + if (this.lockedSpawns.Contains(target.SteamID)) { return $"Spawn already locked for {target.Name}"; } target.Modifications.CanDeploy = false; this.lockedSpawns.Add(target.SteamID); - if (!string.IsNullOrEmpty(message)) - { + if (!string.IsNullOrEmpty(message)) { target.Message(message); } @@ -291,32 +248,25 @@ public string LockSpawn(Context context, RunnerPlayer? target = null, string? me } [CommandCallback("UnlockSpawn", Description = "Allows a player or all players to spawn", Permissions = new[] { "ModeratorTools.UnlockSpawn" })] - public string UnlockSpawn(Context context, RunnerPlayer? target = null, string? message = null) - { - if (target == null) - { + public string UnlockSpawn(Context context, RunnerPlayer? target = null, string? message = null) { + if (target == null) { this.Logger.Info($"[UnlockSpawn] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> All"); this.globalSpawnLock = false; - foreach (RunnerPlayer player in this.Server.AllPlayers) - { + foreach (RunnerPlayer player in this.Server.AllPlayers) { player.Modifications.CanDeploy = true; } return "Spawn globally unlocked"; - } - else - { + } else { this.Logger.Info($"[UnlockSpawn] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); - if (!this.lockedSpawns.Contains(target.SteamID)) - { + if (!this.lockedSpawns.Contains(target.SteamID)) { return $"Spawn already unlocked for {target.Name}"; } target.Modifications.CanDeploy = true; this.lockedSpawns.Remove(target.SteamID); - if (!string.IsNullOrEmpty(message)) - { + if (!string.IsNullOrEmpty(message)) { target.Message(message); } @@ -325,10 +275,8 @@ public string UnlockSpawn(Context context, RunnerPlayer? target = null, string? } [CommandCallback("tp2me", Description = "Teleports a player to you", Permissions = new[] { "ModeratorTools.Teleport" })] - public string TeleportPlayerToMe(Context context, RunnerPlayer target) - { - if (context.Source is not ChatSource chatSource) - { + public string TeleportPlayerToMe(Context context, RunnerPlayer target) { + if (context.Source is not ChatSource chatSource) { return "Teleport player to me can only work from chat"; } @@ -339,10 +287,8 @@ public string TeleportPlayerToMe(Context context, RunnerPlayer target) } [CommandCallback("tpme2", Description = "Teleports you to a player", Permissions = new[] { "ModeratorTools.Teleport" })] - public string TeleportMeToPlayer(Context context, RunnerPlayer target) - { - if (context.Source is not ChatSource chatSource) - { + public string TeleportMeToPlayer(Context context, RunnerPlayer target) { + if (context.Source is not ChatSource chatSource) { return "Teleport me to player can only work from chat"; } @@ -353,8 +299,7 @@ public string TeleportMeToPlayer(Context context, RunnerPlayer target) } [CommandCallback("tp", Description = "Teleports a player to another player", Permissions = new[] { "ModeratorTools.Teleport" })] - public string TeleportPlayerToPlayer(Context context, RunnerPlayer target, RunnerPlayer destination) - { + public string TeleportPlayerToPlayer(Context context, RunnerPlayer target, RunnerPlayer destination) { this.Logger.Info($"[TeleportPlayerToPlayer] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name} -> {destination.Name}"); target.Teleport(new Vector3((int)destination.Position.X, (int)destination.Position.Y, (int)destination.Position.Z)); @@ -362,8 +307,7 @@ public string TeleportPlayerToPlayer(Context context, RunnerPlayer target, Runne } [CommandCallback("tp2pos", Description = "Teleports a player to a position", Permissions = new[] { "ModeratorTools.Teleport" })] - public string TeleportPlayerToPos(Context context, RunnerPlayer target, int x, int y, int z) - { + public string TeleportPlayerToPos(Context context, RunnerPlayer target, int x, int y, int z) { this.Logger.Info($"[TeleportPlayerToPos] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name} -> {x} {y} {z}"); target.Teleport(new Vector3(x, y, z)); @@ -371,10 +315,8 @@ public string TeleportPlayerToPos(Context context, RunnerPlayer target, int x, i } [CommandCallback("tpme2pos", Description = "Teleports you to a position", Permissions = new[] { "ModeratorTools.Teleport" })] - public string TeleportMeToPos(Context context, int x, int y, int z) - { - if (context.Source is not ChatSource chatSource) - { + public string TeleportMeToPos(Context context, int x, int y, int z) { + if (context.Source is not ChatSource chatSource) { return "Teleport me to position can only work from chat"; } @@ -385,13 +327,11 @@ public string TeleportMeToPos(Context context, int x, int y, int z) } [CommandCallback("freeze", Description = "Freezes a player", Permissions = new[] { "ModeratorTools.Freeze" })] - public string Freeze(Context context, RunnerPlayer target, string? message = null) - { + public string Freeze(Context context, RunnerPlayer target, string? message = null) { this.Logger.Info($"[Freeze] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); target.Modifications.Freeze = true; - if (!string.IsNullOrEmpty(message)) - { + if (!string.IsNullOrEmpty(message)) { target.Message(message); } @@ -399,13 +339,11 @@ public string Freeze(Context context, RunnerPlayer target, string? message = nul } [CommandCallback("unfreeze", Description = "Unfreezes a player", Permissions = new[] { "ModeratorTools.Unfreeze" })] - public string Unfreeze(Context context, RunnerPlayer target, string? message = null) - { + public string Unfreeze(Context context, RunnerPlayer target, string? message = null) { this.Logger.Info($"[Unfreeze] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}"); target.Modifications.Freeze = false; - if (!string.IsNullOrEmpty(message)) - { + if (!string.IsNullOrEmpty(message)) { target.Message(message); } @@ -415,30 +353,23 @@ public string Unfreeze(Context context, RunnerPlayer target, string? message = n private Dictionary inspectPlayers = new(); [CommandCallback("Inspect", Description = "Inspects a player or stops inspection", Permissions = new[] { "ModeratorTools.Inspect" })] - public string? Inspect(Context context, RunnerPlayer? target = null) - { - if (context.Source is not ChatSource chatSource) - { - if (target is null) - { + public string? Inspect(Context context, RunnerPlayer? target = null) { + if (context.Source is not ChatSource chatSource) { + if (target is null) { return "A target player to inspect is required."; } return this.getPlayerInspectionText(target); } - if (target is null) - { + if (target is null) { this.inspectPlayers.Remove(chatSource.Invoker); return "Inspection stopped"; } - if (this.inspectPlayers.ContainsKey(chatSource.Invoker)) - { + if (this.inspectPlayers.ContainsKey(chatSource.Invoker)) { this.inspectPlayers[chatSource.Invoker] = target; - } - else - { + } else { this.inspectPlayers.Add(chatSource.Invoker, target); } @@ -446,8 +377,7 @@ public string Unfreeze(Context context, RunnerPlayer target, string? message = n } [CommandCallback("warn", Description = "Warns a player", Permissions = new[] { "ModeratorTools.Warn" })] - public string Warn(Context context, RunnerPlayer target, string? message = null) - { + public string Warn(Context context, RunnerPlayer target, string? message = null) { this.Logger.Info($"[Warn] {(context.Source is ChatSource chatSource ? chatSource.Invoker.Name : context.Source.GetType().Name)} -> {target.Name}: {message ?? "no reason"}"); target.WarnPlayer(message ?? "no reason"); target.Message($"You have been warned for\n{message ?? "no reason"}", 25); @@ -459,20 +389,16 @@ public string Warn(Context context, RunnerPlayer target, string? message = null) private List lockedSpawns = new(); private bool globalSpawnLock = false; - public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string msg) - { - if (this.gaggedPlayers.Contains(player.SteamID)) - { + public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string msg) { + if (this.gaggedPlayers.Contains(player.SteamID)) { return Task.FromResult(false); } return Task.FromResult(true); } - public override Task OnPlayerSpawning(RunnerPlayer player, OnPlayerSpawnArguments request) - { - if (this.globalSpawnLock || this.lockedSpawns.Contains(player.SteamID)) - { + public override Task OnPlayerSpawning(RunnerPlayer player, OnPlayerSpawnArguments request) { + if (this.globalSpawnLock || this.lockedSpawns.Contains(player.SteamID)) { return Task.FromResult(null); } diff --git a/ModuleUpdates.cs b/ModuleUpdates.cs index 1b95f06..b08d16b 100644 --- a/ModuleUpdates.cs +++ b/ModuleUpdates.cs @@ -11,8 +11,7 @@ namespace BattleBitBaseModules; [Module("Check for and download module updates from the module repository", "1.0.0")] -public class ModuleUpdates : BattleBitModule -{ +public class ModuleUpdates : BattleBitModule { public static ModuleUpdatesConfiguration Configuration { get; set; } = null!; PropertyInfo nameProperty = null!; @@ -22,28 +21,22 @@ public class ModuleUpdates : BattleBitModule private static dynamic[] modulesToUpdate = Array.Empty(); private static bool running = false; - public override void OnModulesLoaded() - { - if (!running) - { + public override void OnModulesLoaded() { + if (!running) { running = true; Task.Run(versionChecker); } } - public override void OnModuleUnloading() - { + public override void OnModuleUnloading() { running = false; } private static DateTime lastChecked = DateTime.MinValue; - private async Task versionChecker() - { - while (running) - { - if (lastChecked.AddMinutes(Configuration.CheckDelay) < DateTime.Now) - { + private async Task versionChecker() { + while (running) { + if (lastChecked.AddMinutes(Configuration.CheckDelay) < DateTime.Now) { await doVersionCheck(); } @@ -51,14 +44,12 @@ private async Task versionChecker() } } - private async Task doVersionCheck() - { + private async Task doVersionCheck() { lastChecked = DateTime.Now; IReadOnlyList collection = null!; - try - { + try { Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetTypes().Any(t => t.Namespace == "BattleBitAPIRunner"))!; Type moduleType = assembly.GetTypes().FirstOrDefault(t => t.Name == "Module")!; PropertyInfo modulesProperty = moduleType.GetProperty("Modules")!; @@ -67,85 +58,67 @@ private async Task doVersionCheck() this.nameProperty = moduleType.GetProperty("Name")!; this.versionProperty = moduleType.GetProperty("Version")!; this.moduleFilePathProperty = moduleType.GetProperty("ModuleFilePath")!; - } - catch (Exception ex) - { + } catch (Exception ex) { this.Logger.Error($"Error retrieving loaded modules: {ex.Message}"); return; } List modulesToUpdate = new(); - foreach (dynamic item in collection) - { + foreach (dynamic item in collection) { string? moduleName = null; string? moduleVersion = null; - try - { + try { moduleName = this.nameProperty.GetValue(item).ToString(); moduleVersion = this.versionProperty.GetValue(item).ToString(); - } - catch (Exception ex) - { + } catch (Exception ex) { this.Logger.Error($"Error retrieving module name and version: {ex.Message}"); continue; } - if (moduleName == null || moduleVersion == null) - { + if (moduleName == null || moduleVersion == null) { continue; } string? latestVersion = null; - try - { + try { HttpClient client = new HttpClient(); client.DefaultRequestHeaders.Add("User-Agent", "BattleBitAPIRunner"); string response = await client.GetStringAsync($"{Configuration.APIEndpoint}/Modules/GetModule/{moduleName}"); - using (JsonDocument responseDocument = JsonDocument.Parse(response)) - { + using (JsonDocument responseDocument = JsonDocument.Parse(response)) { latestVersion = responseDocument.RootElement.GetProperty("versions").EnumerateArray().First().GetProperty("Version_v_number").GetString(); } - } - catch (Exception ex) - { + } catch (Exception ex) { this.Logger.Error($"Error checking for module {moduleName} updates: {ex.Message}"); continue; } - if (latestVersion == null) - { + if (latestVersion == null) { continue; } - if (moduleVersion != latestVersion) - { + if (moduleVersion != latestVersion) { this.Logger.Warn($"Module {moduleName} is out of date! Installed version: {moduleVersion}, Latest version: {latestVersion}"); modulesToUpdate.Add(item); } } - if (modulesToUpdate.Count > 0) - { + if (modulesToUpdate.Count > 0) { ModuleUpdates.modulesToUpdate = modulesToUpdate.ToArray(); this.Logger.Warn($"There are {modulesToUpdate.Count} modules out of date. Run 'updateall' to update all modules or 'update modulename' to update an individual module."); } } - private async Task doUpdate(string? module = null) - { - if (module is null) - { - if (modulesToUpdate.Length == 0) - { + private async Task doUpdate(string? module = null) { + if (module is null) { + if (modulesToUpdate.Length == 0) { this.Logger.Info("There are no modules to update. Run 'update' to fetch latest versions."); return; } - foreach (dynamic item in modulesToUpdate) - { + foreach (dynamic item in modulesToUpdate) { await doUpdate(this.nameProperty.GetValue(item).ToString()); } @@ -153,8 +126,7 @@ private async Task doUpdate(string? module = null) } dynamic? moduleToUpdate = modulesToUpdate.FirstOrDefault(m => module.Equals(this.nameProperty.GetValue(m).ToString(), StringComparison.InvariantCultureIgnoreCase)); - if (moduleToUpdate is null) - { + if (moduleToUpdate is null) { this.Logger.Error($"Module {module} is not out of date."); return; } @@ -168,28 +140,23 @@ private async Task doUpdate(string? module = null) this.Logger.Info($"Module {module} updated successfully."); } - public override void OnConsoleCommand(string command) - { - if (!command.Trim().ToLower().StartsWith("update")) - { + public override void OnConsoleCommand(string command) { + if (!command.Trim().ToLower().StartsWith("update")) { return; } - if (command.Trim().ToLower() == "updateall") - { + if (command.Trim().ToLower() == "updateall") { Task.Run(() => doUpdate()).ContinueWith(t => this.Logger.Error($"Error updating modules: {t.Exception!.Message}"), TaskContinuationOptions.OnlyOnFaulted); return; } string[] args = command.Split(' '); - if (args.Length > 2) - { + if (args.Length > 2) { this.Logger.Error("Usage: update [module name]"); return; } - if (args.Length == 1) - { + if (args.Length == 1) { doVersionCheck().ContinueWith(t => this.Logger.Error($"Error checking for module updates: {t.Exception!.Message}"), TaskContinuationOptions.OnlyOnFaulted); return; } @@ -198,8 +165,7 @@ public override void OnConsoleCommand(string command) } } -public class ModuleUpdatesConfiguration : ModuleConfiguration -{ +public class ModuleUpdatesConfiguration : ModuleConfiguration { public string APIEndpoint { get; set; } = "https://modules.battlebit.community/api"; public int CheckDelay { get; set; } = 30; } diff --git a/PasswordReservedSlots.cs b/PasswordReservedSlots.cs index 344945c..a29236b 100644 --- a/PasswordReservedSlots.cs +++ b/PasswordReservedSlots.cs @@ -8,64 +8,52 @@ namespace BattleBitBaseModules; [RequireModule(typeof(CommandHandler))] [Module("Add reserved slots by setting a password", "1.0.0")] -public class PasswordReservedSlots : BattleBitModule -{ +public class PasswordReservedSlots : BattleBitModule { public PasswordReservedSlotsConfiguration Configuration { get; set; } = null!; [ModuleReference] public CommandHandler CommandHandler { get; set; } = null!; - public int getCurrentPlayerCount() - { + public int getCurrentPlayerCount() { return Math.Max(this.Server.CurrentPlayerCount + this.Server.InQueuePlayerCount, this.Server.AllPlayers.Count()); } - public void handleSlots() - { + public void handleSlots() { int currentPlayers = this.getCurrentPlayerCount(); - if (this.Server.MaxPlayerCount - this.Configuration.Slots < currentPlayers) - { + if (this.Server.MaxPlayerCount - this.Configuration.Slots < currentPlayers) { this.Server.SetNewPassword(""); - } - else - { + } else { Server.SetNewPassword(this.Configuration.Password); } } - public async Task slotHandler() - { - while (this.IsLoaded && this.Server.IsConnected) - { + public async Task slotHandler() { + while (this.IsLoaded && this.Server.IsConnected) { this.handleSlots(); await Task.Delay(1000); } } - public override Task OnConnected() - { + public override Task OnConnected() { _ = Task.Run(slotHandler); return Task.CompletedTask; } - public override Task OnPlayerConnected(RunnerPlayer player) - { + public override Task OnPlayerConnected(RunnerPlayer player) { this.handleSlots(); return Task.CompletedTask; } - public override Task OnPlayerDisconnected(RunnerPlayer player) - { + public override Task OnPlayerDisconnected(RunnerPlayer player) { this.handleSlots(); return Task.CompletedTask; } [CommandCallback("setrspass", Description = "Sets the password for reserved slots", ConsoleCommand = true, Permissions = new[] { "PasswordReservedSlots.SetRSPass" })] - public string SetRSPassCommand(Context context, string password) - { + public string SetRSPassCommand(Context context, string password) { this.Configuration.Password = password; this.Configuration.Save(); this.handleSlots(); @@ -74,8 +62,7 @@ public string SetRSPassCommand(Context context, string password) } [CommandCallback("setrsslots", Description = "Sets the number of reserved slots", ConsoleCommand = true, Permissions = new[] { "PasswordReservedSlots.SetRSSlots" })] - public string SetRSSlotsCommand(Context context, int slots) - { + public string SetRSSlotsCommand(Context context, int slots) { this.Configuration.Slots = slots; this.Configuration.Save(); this.handleSlots(); @@ -84,8 +71,7 @@ public string SetRSSlotsCommand(Context context, int slots) } } -public class PasswordReservedSlotsConfiguration : ModuleConfiguration -{ +public class PasswordReservedSlotsConfiguration : ModuleConfiguration { public string Password { get; set; } = "changeme"; public int Slots { get; set; } = 0; } diff --git a/PermissionsCommands.cs b/PermissionsCommands.cs index bbdb675..65c2b6c 100644 --- a/PermissionsCommands.cs +++ b/PermissionsCommands.cs @@ -9,8 +9,7 @@ namespace PermissionsManager; [RequireModule(typeof(CommandHandler))] [Module("Provide addperm and removeperm commands for PlayerPermissions", "1.1.0")] -public class PermissionsCommands : BattleBitModule -{ +public class PermissionsCommands : BattleBitModule { [ModuleReference] public dynamic? PlayerPermissions { get; set; } [ModuleReference] @@ -20,103 +19,78 @@ public class PermissionsCommands : BattleBitModule public PermissionsCommandsConfiguration Configuration { get; set; } = null!; - public override void OnModulesLoaded() - { + public override void OnModulesLoaded() { this.CommandHandler.Register(this); } [CommandCallback("addperm", Description = "Adds a permission to a player", Permissions = new[] { "Permissions.Add" })] - public string AddPermissionCommand(Context context, RunnerPlayer player, string permission) - { + public string AddPermissionCommand(Context context, RunnerPlayer player, string permission) { bool success = false; - if (this.PlayerPermissions is not null) - { - if (!Enum.TryParse(permission, out Roles roles)) - { + if (this.PlayerPermissions is not null) { + if (!Enum.TryParse(permission, out Roles roles)) { this.Logger.Error($"Could not parse {permission} to a role"); - } - else - { + } else { this.PlayerPermissions.AddPlayerRoles(player.SteamID, roles); success = true; } } - if (this.GranularPermissions is not null) - { + if (this.GranularPermissions is not null) { this.GranularPermissions.AddPlayerPermission(player.SteamID, permission); success = true; } - if (success) - { + if (success) { this.Logger.Info($"Added permission {permission} to {player.Name}"); return $"Added permission {permission} to {player.Name}"; - } - else - { + } else { this.Logger.Error($"Could not add permission {permission} to {player.Name}"); return $"Could not add permission {permission} to {player.Name}"; } } [CommandCallback("removeperm", Description = "Removes a permission from a player", Permissions = new[] { "Permissions.Remove" })] - public string RemovePermissionCommand(Context context, RunnerPlayer player, string permission) - { + public string RemovePermissionCommand(Context context, RunnerPlayer player, string permission) { bool success = false; - if (this.PlayerPermissions is not null) - { - if (!Enum.TryParse(permission, out Roles roles)) - { + if (this.PlayerPermissions is not null) { + if (!Enum.TryParse(permission, out Roles roles)) { this.Logger.Error($"Colud not parse {permission} to a role"); - } - else - { + } else { this.PlayerPermissions.RemovePlayerRoles(player.SteamID, roles); success = true; } } - if (this.GranularPermissions is not null) - { + if (this.GranularPermissions is not null) { this.GranularPermissions.RemovePlayerPermission(player.SteamID, permission); success = true; } - if (success) - { + if (success) { this.Logger.Info($"Removed permission {permission} from {player.Name}"); return $"Removed permission {permission} from {player.Name}"; - } - else - { + } else { this.Logger.Error($"Could not remove permission {permission} from {player.Name}"); return $"Could not remove permission {permission} from {player.Name}"; } } [CommandCallback("clearperms", Description = "Clears all permissions and groups from a player", Permissions = new[] { "Permissions.Clear" })] - public string ClearPermissionCommand(Context context, RunnerPlayer player) - { - if (this.GranularPermissions is not null) - { - foreach (string group in this.GranularPermissions.GetPlayerGroups(player.SteamID)) - { + public string ClearPermissionCommand(Context context, RunnerPlayer player) { + if (this.GranularPermissions is not null) { + foreach (string group in this.GranularPermissions.GetPlayerGroups(player.SteamID)) { this.GranularPermissions.RemovePlayerGroup(player.SteamID, group); } - foreach (string permission in this.GranularPermissions.GetPlayerPermissions(player.SteamID)) - { + foreach (string permission in this.GranularPermissions.GetPlayerPermissions(player.SteamID)) { this.GranularPermissions.RemovePlayerPermission(player.SteamID, permission); } } - if (this.PlayerPermissions is not null) - { - foreach (Roles role in Enum.GetValues()) - { + if (this.PlayerPermissions is not null) { + foreach (Roles role in Enum.GetValues()) { this.PlayerPermissions.RemovePlayerRoles(player.SteamID, role); } } @@ -126,21 +100,17 @@ public string ClearPermissionCommand(Context context, RunnerPlayer player) } [CommandCallback("listperms", Description = "Lists player permissions", Permissions = new[] { "Permissions.List" })] - public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, int page = 1) - { + public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, int page = 1) { List permissions = new(); - if (this.GranularPermissions is not null) - { + if (this.GranularPermissions is not null) { permissions.AddRange(this.GranularPermissions.GetPlayerPermissions(targetPlayer.SteamID)); - foreach (string group in this.GranularPermissions.GetPlayerGroups(targetPlayer.SteamID)) - { + foreach (string group in this.GranularPermissions.GetPlayerGroups(targetPlayer.SteamID)) { permissions.AddRange(((string[])this.GranularPermissions.GetGroupPermissions(group)).Select(p => $"{p} from {group}")); } } - if (this.PlayerPermissions is not null) - { + if (this.PlayerPermissions is not null) { Roles playerRoles = PlayerPermissions.Configuration.PlayerRoles.GetValueOrDefault(targetPlayer.SteamID); permissions.AddRange(Enum.GetValues().Where(r => (r & playerRoles) > 0).Select(r => r.ToString())); } @@ -151,7 +121,6 @@ public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, } } -public class PermissionsCommandsConfiguration : ModuleConfiguration -{ +public class PermissionsCommandsConfiguration : ModuleConfiguration { public int PermissionsPerPage { get; set; } = 6; } diff --git a/PlayerFinder.cs b/PlayerFinder.cs index 843b0d9..4f3404a 100644 --- a/PlayerFinder.cs +++ b/PlayerFinder.cs @@ -5,64 +5,52 @@ namespace PlayerFinder; [Module("Library functions for finding players by partial names or SteamID", "1.0.0")] -public class PlayerFinder : BattleBitModule -{ - public RunnerPlayer? ByExactName(string exactName, bool caseSensitive) - { +public class PlayerFinder : BattleBitModule { + public RunnerPlayer? ByExactName(string exactName, bool caseSensitive) { return this.Server.AllPlayers.FirstOrDefault(p => p.Name.Equals(exactName, caseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase)); } - public RunnerPlayer? ByNamePart(string namePart) - { + public RunnerPlayer? ByNamePart(string namePart) { RunnerPlayer? exactMatch = this.ByExactName(namePart, true); - if (exactMatch != null) - { + if (exactMatch != null) { return exactMatch; } exactMatch = this.ByExactName(namePart, false); - if (exactMatch != null) - { + if (exactMatch != null) { return exactMatch; } RunnerPlayer[] playerList = this.AllByNamePart(namePart); - if (playerList.Length > 1) - { + if (playerList.Length > 1) { throw new ManyPlayersMatchException(playerList); } - if (playerList.Length == 0) - { + if (playerList.Length == 0) { return null; } return playerList[0]; } - public RunnerPlayer? BySteamId(ulong steamId) - { + public RunnerPlayer? BySteamId(ulong steamId) { return this.Server.AllPlayers.FirstOrDefault(p => p.SteamID == steamId); } - public RunnerPlayer[] AllByNamePart(string namePart) - { + public RunnerPlayer[] AllByNamePart(string namePart) { return this.Server.AllPlayers.Where(p => p.Name.ToLower().Contains(namePart.ToLower())).ToArray(); } } -public class ManyPlayersMatchException : Exception -{ +public class ManyPlayersMatchException : Exception { public RunnerPlayer[] Players { get; } - public ManyPlayersMatchException(RunnerPlayer[] players) - { + public ManyPlayersMatchException(RunnerPlayer[] players) { this.Players = players; } - public override string ToString() - { + public override string ToString() { return $"Multiple players match: {string.Join(", ", this.Players.Select(p => p.Name))}"; } } \ No newline at end of file diff --git a/PlayerPermissions.cs b/PlayerPermissions.cs index 63bbd29..161a66b 100644 --- a/PlayerPermissions.cs +++ b/PlayerPermissions.cs @@ -6,30 +6,22 @@ namespace Permissions; [Module("Library for persistent server roles for players", "1.1.0")] -public class PlayerPermissions : BattleBitModule -{ +public class PlayerPermissions : BattleBitModule { public static PlayerPermissionsConfiguration Configuration { get; set; } = null!; - public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) - { - if (Configuration.OverrideRoles) - { + public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { + if (Configuration.OverrideRoles) { args.Stats.Roles = this.GetPlayerRoles(steamID); - } - else - { + } else { args.Stats.Roles |= this.GetPlayerRoles(steamID); } return Task.CompletedTask; } - public override Task OnPlayerConnected(RunnerPlayer player) - { - lock (Configuration.PlayerRoles) - { - if (!Configuration.PlayerRoles.ContainsKey(player.SteamID)) - { + public override Task OnPlayerConnected(RunnerPlayer player) { + lock (Configuration.PlayerRoles) { + if (!Configuration.PlayerRoles.ContainsKey(player.SteamID)) { Configuration.PlayerRoles.Add(player.SteamID, Roles.None); } } @@ -37,17 +29,13 @@ public override Task OnPlayerConnected(RunnerPlayer player) return Task.CompletedTask; } - public bool HasPlayerRole(ulong steamID, Roles role) - { + public bool HasPlayerRole(ulong steamID, Roles role) { return (this.GetPlayerRoles(steamID) & role) == role; } - public Roles GetPlayerRoles(ulong steamID) - { - lock (Configuration.PlayerRoles) - { - if (Configuration.PlayerRoles.ContainsKey(steamID)) - { + public Roles GetPlayerRoles(ulong steamID) { + lock (Configuration.PlayerRoles) { + if (Configuration.PlayerRoles.ContainsKey(steamID)) { return Configuration.PlayerRoles[steamID]; } } @@ -55,16 +43,11 @@ public Roles GetPlayerRoles(ulong steamID) return Roles.None; } - public void SetPlayerRoles(ulong steamID, Roles roles) - { - lock (Configuration.PlayerRoles) - { - if (Configuration.PlayerRoles.ContainsKey(steamID)) - { + public void SetPlayerRoles(ulong steamID, Roles roles) { + lock (Configuration.PlayerRoles) { + if (Configuration.PlayerRoles.ContainsKey(steamID)) { Configuration.PlayerRoles[steamID] = roles; - } - else - { + } else { Configuration.PlayerRoles.Add(steamID, roles); } } @@ -72,19 +55,16 @@ public void SetPlayerRoles(ulong steamID, Roles roles) Configuration.Save(); } - public void AddPlayerRoles(ulong steamID, Roles role) - { + public void AddPlayerRoles(ulong steamID, Roles role) { this.SetPlayerRoles(steamID, this.GetPlayerRoles(steamID) | role); } - public void RemovePlayerRoles(ulong steamID, Roles role) - { + public void RemovePlayerRoles(ulong steamID, Roles role) { this.SetPlayerRoles(steamID, this.GetPlayerRoles(steamID) & ~role); } } -public class PlayerPermissionsConfiguration : ModuleConfiguration -{ +public class PlayerPermissionsConfiguration : ModuleConfiguration { public bool OverrideRoles { get; set; } = true; public Dictionary PlayerRoles { get; set; } = new(); } \ No newline at end of file diff --git a/PlayerRolesFromGranularPermissions.cs b/PlayerRolesFromGranularPermissions.cs index aed3f90..123fb1b 100644 --- a/PlayerRolesFromGranularPermissions.cs +++ b/PlayerRolesFromGranularPermissions.cs @@ -7,27 +7,20 @@ namespace Permissions; [RequireModule(typeof(GranularPermissions))] [Module("Provides player roles based on granular permissions", "1.0.0")] -public class PlayerRolesFromGranularPermissions : BattleBitModule -{ +public class PlayerRolesFromGranularPermissions : BattleBitModule { [ModuleReference] public GranularPermissions GranularPermissions { get; set; } = null!; public PlayerRolesConfiguration Configuration { get; set; } = null!; - public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) - { - foreach (string permission in Configuration.PermissionRoles.Keys) - { - if (!this.GranularPermissions.HasPermission(steamID, permission)) - { + public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { + foreach (string permission in Configuration.PermissionRoles.Keys) { + if (!this.GranularPermissions.HasPermission(steamID, permission)) { continue; } - if (Configuration.AppendRoles) - { + if (Configuration.AppendRoles) { args.Stats.Roles |= Configuration.PermissionRoles[permission]; - } - else - { + } else { args.Stats.Roles = Configuration.PermissionRoles[permission]; } } @@ -36,12 +29,11 @@ public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArgumen } } -public class PlayerRolesConfiguration : ModuleConfiguration -{ - public Dictionary PermissionRoles { get; set; } = new() - { - { "Role.Admin", Roles.Admin }, - { "Role.Moderator", Roles.Moderator }, +public class PlayerRolesConfiguration : ModuleConfiguration { + public Dictionary PermissionRoles { get; set; } = new() + { + { "Role.Admin", Roles.Admin }, + { "Role.Moderator", Roles.Moderator }, { "Role.Staff", Roles.Admin | Roles.Moderator }, { "Role.Vip", Roles.Vip }, { "Role.Special", Roles.Special }, diff --git a/ProfanityFilter.cs b/ProfanityFilter.cs index f7b6e3c..215a833 100644 --- a/ProfanityFilter.cs +++ b/ProfanityFilter.cs @@ -5,42 +5,33 @@ namespace BattleBitBaseModules; -public class DFAState -{ +public class DFAState { public Dictionary Transitions { get; set; } public bool IsEndOfWord { get; set; } - public DFAState() - { + public DFAState() { Transitions = new Dictionary(); IsEndOfWord = false; } } -public class ProfanityDFAFilter -{ +public class ProfanityDFAFilter { private DFAState root; - public ProfanityDFAFilter() - { + public ProfanityDFAFilter() { root = new DFAState(); } - public void LoadDictionary(string[] words) - { + public void LoadDictionary(string[] words) { root = BuildDFA(words); } - private DFAState BuildDFA(string[] words) - { + private DFAState BuildDFA(string[] words) { DFAState root = new DFAState(); - foreach (string word in words) - { + foreach (string word in words) { DFAState currentState = root; - foreach (char c in word) - { - if (!currentState.Transitions.ContainsKey(c)) - { + foreach (char c in word) { + if (!currentState.Transitions.ContainsKey(c)) { currentState.Transitions.Add(c, new DFAState()); } currentState = currentState.Transitions[c]; @@ -50,19 +41,15 @@ private DFAState BuildDFA(string[] words) return root; } - public bool ContainsProfanity(string text) - { + public bool ContainsProfanity(string text) { DFAState currentState = root; - foreach (char c in text) - { - if (!currentState.Transitions.ContainsKey(c)) - { + foreach (char c in text) { + if (!currentState.Transitions.ContainsKey(c)) { currentState = root; continue; } currentState = currentState.Transitions[c]; - if (currentState.IsEndOfWord) - { + if (currentState.IsEndOfWord) { return true; } } @@ -71,21 +58,17 @@ public bool ContainsProfanity(string text) } [Module("Bad word filter to remove chat messages", "1.0.0")] -public class ProfanityFilter : BattleBitModule -{ +public class ProfanityFilter : BattleBitModule { public static ProfanityFilterConfiguration Configuration { get; set; } = null!; public static ProfanityDFAFilter filter = new(); - public override void OnModulesLoaded() - { + public override void OnModulesLoaded() { // Load dictionary filter.LoadDictionary(Configuration.Profanity.ToArray()); } - public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string message) - { - if (filter.ContainsProfanity(message)) - { + public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string message) { + if (filter.ContainsProfanity(message)) { player.Message(Configuration.Message, Configuration.MessageTimeout); return Task.FromResult(false); } @@ -94,8 +77,7 @@ public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel } } -public class ProfanityFilterConfiguration : ModuleConfiguration -{ +public class ProfanityFilterConfiguration : ModuleConfiguration { public List Profanity { get; set; } = new(); public float MessageTimeout { get; set; } = 10f; public string Message { get; set; } = "Please do not use profanity in chat."; diff --git a/RichText.cs b/RichText.cs index 951e892..dfeab4a 100644 --- a/RichText.cs +++ b/RichText.cs @@ -5,25 +5,20 @@ namespace BattleBitBaseModules; [Module("Library for easily using Rich Text", "1.1.0")] -public class RichText : BattleBitModule -{ +public class RichText : BattleBitModule { public string NewLine() => "
"; - public string Color(string? color = null) - { - if (color is null) - { + public string Color(string? color = null) { + if (color is null) { return Colors.White; } return $"<{color}>"; } - public string FromColorName(string colorName) - { + public string FromColorName(string colorName) { FieldInfo? color = typeof(Colors).GetFields().FirstOrDefault(x => x.Name.ToLower() == colorName.ToLower()); - if (color == null) - { + if (color == null) { this.Logger.Error($"No color found with name {colorName}"); return "<#FFFFFF>"; } @@ -31,21 +26,17 @@ public string FromColorName(string colorName) return color.GetValue(null)!.ToString()!; } - public string Align(string? alignment = null) - { - if (alignment is null) - { + public string Align(string? alignment = null) { + if (alignment is null) { return Alignments.None; } return $""; } - public string FromAlignmentName(string alignmentName) - { + public string FromAlignmentName(string alignmentName) { FieldInfo? alignment = typeof(Alignments).GetFields().FirstOrDefault(x => x.Name.ToLower() == alignmentName.ToLower()); - if (alignment == null) - { + if (alignment == null) { this.Logger.Error($"No alignment found with name {alignmentName}"); return Alignments.None; } @@ -53,10 +44,8 @@ public string FromAlignmentName(string alignmentName) return alignment.GetValue(null)!.ToString()!; } - public string Alpha(string? alpha = null) - { - if (alpha is null) - { + public string Alpha(string? alpha = null) { + if (alpha is null) { return ""; } @@ -66,20 +55,16 @@ public string Alpha(string? alpha = null) public string CharacterSpacing(int pixels) => $""; public string CharacterSpacing(float em) => $""; - public string Font(string? fontName) - { - if (fontName is null) - { + public string Font(string? fontName) { + if (fontName is null) { return ""; } return $""; } - public string Indent(int? percentage = null) - { - if (percentage is null) - { + public string Indent(int? percentage = null) { + if (percentage is null) { return ""; } @@ -114,18 +99,15 @@ public string Indent(int? percentage = null) public string TextWidth(int percentage) => $""; - public string Sprite(string spriteName, string? color = null) - { + public string Sprite(string spriteName, string? color = null) { FieldInfo? sprite = typeof(Sprites).GetFields().FirstOrDefault(x => x.Name.ToLower() == spriteName.ToLower()); - if (sprite == null) - { + if (sprite == null) { this.Logger.Error($"No sprite found with name {spriteName}"); return string.Empty; } string spriteText = sprite.GetValue(null)!.ToString()!; - if (!string.IsNullOrEmpty(color)) - { + if (!string.IsNullOrEmpty(color)) { spriteText = spriteText.Replace(" superscript ? "" : ""; } -public static class Alignments -{ +public static class Alignments { public static readonly string Left = ""; public static readonly string Center = ""; public static readonly string Right = ""; @@ -303,8 +284,7 @@ public static class Colors { public static readonly string Gainsboro = "<#DCDCDC>"; } -public static class Sprites -{ +public static class Sprites { public static readonly string Moderator = ""; public static readonly string Patreon = ""; public static readonly string Creator = ""; diff --git a/Rotation.cs b/Rotation.cs index d741e03..1b1c1a0 100644 --- a/Rotation.cs +++ b/Rotation.cs @@ -4,12 +4,10 @@ namespace BattleBitBaseModules; [Module("Configure the map and game mode rotation of the server", "1.0.0")] -public class Rotation : BattleBitModule -{ +public class Rotation : BattleBitModule { public RotationConfiguration Configuration { get; set; } = null!; - public override Task OnConnected() - { + public override Task OnConnected() { this.Logger.Info($"Setting up game mode rotation to {string.Join(", ", this.Configuration.GameModes)}"); this.Server.GamemodeRotation.SetRotation(this.Configuration.GameModes); this.Logger.Debug($"New game mode rotation: {string.Join(", ", this.Server.GamemodeRotation.GetGamemodeRotation())}"); @@ -21,8 +19,7 @@ public override Task OnConnected() } } -public class RotationConfiguration : ModuleConfiguration -{ +public class RotationConfiguration : ModuleConfiguration { public string[] GameModes { get; set; } = new[] { "TDM", diff --git a/SpectateControl.cs b/SpectateControl.cs index cbd8ca5..086b200 100644 --- a/SpectateControl.cs +++ b/SpectateControl.cs @@ -8,8 +8,7 @@ namespace BattleBitBaseModules; [Module("Allow only specific Roles to spectate", "1.1.1")] -public class SpectateControl : BattleBitModule -{ +public class SpectateControl : BattleBitModule { public static SpectateControlConfiguration Configuration { get; set; } = null!; [ModuleReference] @@ -18,12 +17,9 @@ public class SpectateControl : BattleBitModule [ModuleReference] public dynamic? PlayerPermissions { get; set; } - public override void OnModulesLoaded() - { - if (this.GranularPermissions is null) - { - if (this.PlayerPermissions is null) - { + public override void OnModulesLoaded() { + if (this.GranularPermissions is null) { + if (this.PlayerPermissions is null) { this.Logger.Error("GranularPermissions or PlayerPermissions not found, unloading module"); this.Unload(); return; @@ -31,39 +27,28 @@ public override void OnModulesLoaded() this.Logger.Info("PlayerPermissions found, using roles"); - foreach (string permission in Configuration.SpectatorPermissions) - { - if (!Enum.TryParse(permission, out Roles role)) - { + foreach (string permission in Configuration.SpectatorPermissions) { + if (!Enum.TryParse(permission, out Roles role)) { this.Logger.Error($"Invalid role {permission}"); } } } } - public override Task OnPlayerConnected(RunnerPlayer player) - { - if (this.GranularPermissions is null) - { - foreach (string permission in Configuration.SpectatorPermissions) - { - if (!Enum.TryParse(permission, out Roles role)) - { + public override Task OnPlayerConnected(RunnerPlayer player) { + if (this.GranularPermissions is null) { + foreach (string permission in Configuration.SpectatorPermissions) { + if (!Enum.TryParse(permission, out Roles role)) { this.Logger.Error($"Invalid role {permission}"); - } - else - { - if (this.PlayerPermissions!.HasPlayerRole(player.SteamID, role)) - { + } else { + if (this.PlayerPermissions!.HasPlayerRole(player.SteamID, role)) { player.Modifications.CanSpectate = true; this.Logger.Info($"Player {player.Name} ({player.SteamID}) has role {role} and can spectate"); return Task.CompletedTask; } } } - } - else - { + } else { player.Modifications.CanSpectate = Configuration.SpectatorPermissions.Any(p => this.GranularPermissions.HasPermission(player.SteamID, p)); } @@ -71,7 +56,6 @@ public override Task OnPlayerConnected(RunnerPlayer player) } } -public class SpectateControlConfiguration : ModuleConfiguration -{ +public class SpectateControlConfiguration : ModuleConfiguration { public List SpectatorPermissions { get; set; } = new(); } diff --git a/VacLimiter.cs b/VacLimiter.cs index 873fa89..ed36f36 100644 --- a/VacLimiter.cs +++ b/VacLimiter.cs @@ -11,8 +11,7 @@ namespace VacLimiter; [Module("Kick users with VAC bans", "1.1.0")] -public class VacLimiter : BattleBitModule -{ +public class VacLimiter : BattleBitModule { public static VacLimiterConfiguration Configuration { get; set; } = null!; public static VacLimiterCache Cache { get; set; } = null!; @@ -25,19 +24,15 @@ public class VacLimiter : BattleBitModule private static bool isLoaded = false; private static HttpClient httpClient = null!; - public override void OnModulesLoaded() - { - if (string.IsNullOrWhiteSpace(Configuration.SteamAPIKey)) - { + public override void OnModulesLoaded() { + if (string.IsNullOrWhiteSpace(Configuration.SteamAPIKey)) { this.Logger.Error("Steam API token is not set. Please set it in the configuration file."); this.Unload(); return; } - if (httpClient == null) - { - httpClient = new() - { + if (httpClient == null) { + httpClient = new() { Timeout = TimeSpan.FromSeconds(10) }; httpClient.DefaultRequestHeaders.Add("User-Agent", "BattleBit"); @@ -49,22 +44,18 @@ public override void OnModulesLoaded() isLoaded = true; } - public override void OnModuleUnloading() - { + public override void OnModuleUnloading() { isLoaded = false; } - private static async Task playerChecker() - { + private static async Task playerChecker() { ILog logger = LogManager.GetLogger(typeof(VacLimiter).Name); - while (isLoaded) - { + while (isLoaded) { CacheRequest[] playerBatch = playersToCheck.ToArray(); playersToCheck.Clear(); - if (playerBatch.Length == 0) - { + if (playerBatch.Length == 0) { await Task.Delay(Configuration.BatchDelay); continue; } @@ -74,21 +65,16 @@ private static async Task playerChecker() HttpResponseMessage? response = null; - do - { - try - { + do { + try { response = await httpClient.GetAsync("https://api.steampowered.com/ISteamUser/GetPlayerBans/v1/?key=" + Configuration.SteamAPIKey + "&steamids=" + string.Join(",", playerBatch.Select(x => x.Player.SteamID))); - if (!response.IsSuccessStatusCode) - { + if (!response.IsSuccessStatusCode) { logger.Error($"Failed to get player bans: {response.StatusCode} {response.ReasonPhrase}"); await Task.Delay(Configuration.RetryDelay); continue; } - } - catch (Exception e) - { + } catch (Exception e) { logger.Error($"Failed to get player bans: {e.Message}"); await Task.Delay(Configuration.RetryDelay); continue; @@ -96,28 +82,22 @@ private static async Task playerChecker() } while (response == null || !response.IsSuccessStatusCode); PlayerBanResponseModel? playerBanResponse = null; - try - { + try { playerBanResponse = JsonSerializer.Deserialize(await response.Content.ReadAsStringAsync()); - } - catch (Exception e) - { + } catch (Exception e) { logger.Error($"Failed to parse player bans: {e.Message}"); await Task.Delay(Configuration.RetryDelay); continue; } - if (playerBanResponse == null) - { + if (playerBanResponse == null) { logger.Error($"Failed to parse player bans."); await Task.Delay(Configuration.RetryDelay); continue; } - foreach (PlayerBansModel playerBans in playerBanResponse.players) - { - if (!ulong.TryParse(playerBans.SteamId, out ulong steamId)) - { + foreach (PlayerBansModel playerBans in playerBanResponse.players) { + if (!ulong.TryParse(playerBans.SteamId, out ulong steamId)) { logger.Error($"Failed to parse Steam ID {playerBans.SteamId}."); continue; } @@ -127,8 +107,7 @@ private static async Task playerChecker() logger.Debug($"Player {steamId} with {playerBans.NumberOfVACBans} VAC bans and {playerBans.NumberOfGameBans} game bans has been cached."); - foreach (CacheRequest request in playerBatch.Where(x => x.Player.SteamID == steamId)) - { + foreach (CacheRequest request in playerBatch.Where(x => x.Player.SteamID == steamId)) { request.VacLimiter.CheckBans(request.Player, playerBans); } } @@ -138,24 +117,18 @@ private static async Task playerChecker() } } - public override Task OnConnected() - { + public override Task OnConnected() { this.Logger.Info($"Setting up VAC limiter with age threshold of {this.ServerConfiguration.VACAgeThreshold} days which will {(this.ServerConfiguration.Kick ? "kick" : "")}{(this.ServerConfiguration.Kick && this.ServerConfiguration.Ban ? " and " : "")}{(this.ServerConfiguration.Ban ? "ban" : "")} players with VAC bans."); return Task.CompletedTask; } - public override Task OnPlayerConnected(RunnerPlayer player) - { - if (Cache.LastCached.TryGetValue(player.SteamID, out DateTime lastCached) && lastCached.AddDays(this.ServerConfiguration.CacheAge) > DateTime.UtcNow && Cache.PlayerBans.TryGetValue(player.SteamID, out PlayerBansModel? playerBans)) - { + public override Task OnPlayerConnected(RunnerPlayer player) { + if (Cache.LastCached.TryGetValue(player.SteamID, out DateTime lastCached) && lastCached.AddDays(this.ServerConfiguration.CacheAge) > DateTime.UtcNow && Cache.PlayerBans.TryGetValue(player.SteamID, out PlayerBansModel? playerBans)) { this.Logger.Debug($"Player {player.Name} ({player.SteamID}) is in cache. Last cached {lastCached}."); this.CheckBans(player, playerBans); - } - else - { - if (playersToCheck.Any(p => p.Player.SteamID == player.SteamID)) - { + } else { + if (playersToCheck.Any(p => p.Player.SteamID == player.SteamID)) { this.Logger.Debug($"Player {player.Name} ({player.SteamID}) is already queued for VAC ban check."); return Task.CompletedTask; } @@ -167,55 +140,46 @@ public override Task OnPlayerConnected(RunnerPlayer player) return Task.CompletedTask; } - private void CheckBans(RunnerPlayer player, PlayerBansModel playerBans) - { - if (!this.Server.IsConnected || !this.IsLoaded) - { + private void CheckBans(RunnerPlayer player, PlayerBansModel playerBans) { + if (!this.Server.IsConnected || !this.IsLoaded) { this.Logger?.Info($"Server is not connected or module is not loaded anymore. Skipping VAC ban check for player {player.Name} ({player.SteamID})."); return; } - if (!playerBans.VACBanned || playerBans.NumberOfVACBans == 0) - { + if (!playerBans.VACBanned || playerBans.NumberOfVACBans == 0) { this.Logger.Info($"Player {player.Name} ({player.SteamID}) has no VAC ban record."); return; } - if (this.GranularPermissions is not null && ServerConfiguration.IgnoredPermissions?.Any(p => this.GranularPermissions.HasPermission(player.SteamID, p)) == true) - { + if (this.GranularPermissions is not null && ServerConfiguration.IgnoredPermissions?.Any(p => this.GranularPermissions.HasPermission(player.SteamID, p)) == true) { this.Logger.Info($"Player {player.Name} ({player.SteamID}) has an ignored permission, skipping..."); return; } - if (playerBans.DaysSinceLastBan >= this.ServerConfiguration.VACAgeThreshold) - { + if (playerBans.DaysSinceLastBan >= this.ServerConfiguration.VACAgeThreshold) { this.Logger.Info($"Player {player.Name} ({player.SteamID}) has a VAC ban from {playerBans.DaysSinceLastBan} days ago on record, but it is older than the threshold of {this.ServerConfiguration.VACAgeThreshold} days."); return; } this.Logger.Info($"Player {player.Name} ({player.SteamID}) has a VAC ban from {playerBans.DaysSinceLastBan} days ago on record. {(this.ServerConfiguration.Kick ? "Kicking" : "")}{(this.ServerConfiguration.Kick && this.ServerConfiguration.Ban ? " and " : "")}{(this.ServerConfiguration.Ban ? "banning" : "")} player."); - if (this.ServerConfiguration.Kick) - { + if (this.ServerConfiguration.Kick) { this.Server.Kick(player, string.Format(this.ServerConfiguration.KickMessage, playerBans.DaysSinceLastBan, this.ServerConfiguration.VACAgeThreshold)); } - if (this.ServerConfiguration.Ban) - { + if (this.ServerConfiguration.Ban) { this.Server.ExecuteCommand($"ban {player.SteamID}"); } } } -public class VacLimiterConfiguration : ModuleConfiguration -{ +public class VacLimiterConfiguration : ModuleConfiguration { public string SteamAPIKey { get; set; } = string.Empty; public int RetryDelay { get; set; } = 5000; public int BatchDelay { get; set; } = 5000; } -public class VacLimiterServerConfiguration : ModuleConfiguration -{ +public class VacLimiterServerConfiguration : ModuleConfiguration { public int VACAgeThreshold { get; set; } = 365; public bool Kick { get; set; } = true; public bool Ban { get; set; } = false; @@ -224,8 +188,7 @@ public class VacLimiterServerConfiguration : ModuleConfiguration public string[] IgnoredPermissions { get; set; } = Array.Empty(); } -public class VacLimiterCache : ModuleConfiguration -{ +public class VacLimiterCache : ModuleConfiguration { public Dictionary LastCached { get; set; } = new(); public Dictionary PlayerBans { get; set; } = new(); } diff --git a/Voting.cs b/Voting.cs index 7714f8a..18283b8 100644 --- a/Voting.cs +++ b/Voting.cs @@ -11,8 +11,7 @@ namespace BattleBitBaseModules; [Module("Simple chat voting system", "1.1.0")] [RequireModule(typeof(CommandHandler))] -public class Voting : BattleBitModule -{ +public class Voting : BattleBitModule { private bool activeVote = false; private string voteText = ""; private string[] voteOptions = new string[0]; @@ -27,16 +26,13 @@ public class Voting : BattleBitModule [ModuleReference] public CommandHandler CommandHandler { get; set; } = null!; - public override void OnModulesLoaded() - { + public override void OnModulesLoaded() { this.CommandHandler.Register(this); } [CommandCallback("vote", Description = "Votes for an option", Permissions = new[] { "Vote.Vote" })] - public string? StartVoteCommand(Context context, string text, string options) - { - if (this.activeVote) - { + public string? StartVoteCommand(Context context, string text, string options) { + if (this.activeVote) { return "There is already an active vote."; } @@ -44,8 +40,7 @@ public override void OnModulesLoaded() this.voteText = text; this.voteOptions = options.Split('|'); - if (this.voteOptions.Length >= 10) - { + if (this.voteOptions.Length >= 10) { this.activeVote = false; return "You can only have up to 9 options."; } @@ -56,15 +51,13 @@ public override void OnModulesLoaded() this.Server.SayToAllChat($"{this.RichText?.Size(125)}A vote has been started!"); StringBuilder messageText = new($"{this.RichText?.Size(125)}{this.voteText}{this.RichText?.Size(100)}{Environment.NewLine}"); - for (int i = 0; i < this.voteOptions.Length; i++) - { + for (int i = 0; i < this.voteOptions.Length; i++) { messageText.AppendLine($"Type {i + 1} in chat for {this.RichText?.FromColorName("yellow")}{this.voteOptions[i]}{this.RichText?.Color()}"); } messageText.AppendLine($"{this.RichText?.Size(125)}You have {this.Configuration.VoteDuration} seconds to vote."); - foreach (RunnerPlayer player in this.Server.AllPlayers) - { + foreach (RunnerPlayer player in this.Server.AllPlayers) { player.Message($"{this.RichText?.Size(125)}{messageText}", this.Configuration.VoteDuration); } @@ -75,34 +68,28 @@ public override void OnModulesLoaded() return null; } - private void voteHandler() - { - while (this.IsLoaded && this.Server?.IsConnected == true && this.activeVote) - { - if (DateTime.Now > this.endOfVote) - { + private void voteHandler() { + while (this.IsLoaded && this.Server?.IsConnected == true && this.activeVote) { + if (DateTime.Now > this.endOfVote) { break; } Task.Delay(1000).Wait(); } - if (!this.IsLoaded || this.Server?.IsConnected != true || !this.activeVote) - { + if (!this.IsLoaded || this.Server?.IsConnected != true || !this.activeVote) { return; } this.activeVote = false; - if (this.votes.Count == 0) - { + if (this.votes.Count == 0) { this.Server.SayToAllChat($"{this.RichText?.Size(125)}The vote has ended!{Environment.NewLine}Nobody voted."); return; } int[] voteCounts = new int[this.voteOptions.Length]; - foreach (int vote in this.votes.Values) - { + foreach (int vote in this.votes.Values) { voteCounts[vote - 1]++; } @@ -112,37 +99,30 @@ private void voteHandler() this.Server.SayToAllChat($"{this.RichText?.Size(125)}The vote has ended!{Environment.NewLine}{this.RichText?.FromColorName("yellow")}{this.voteOptions[maxVoteIndex]}{this.RichText?.Color()} won with {maxVotes} votes."); } - public override async Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string msg) - { - if (!this.activeVote) - { + public override async Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string msg) { + if (!this.activeVote) { return true; } msg = new string(msg.Where(c => char.IsDigit(c)).Distinct().ToArray()); - if (msg.Length == 0) - { + if (msg.Length == 0) { return true; } - if (msg.Length > 1) - { + if (msg.Length > 1) { player.SayToChat("Could not find a unique vote option in your message."); return true; } - if (!int.TryParse(msg, out int vote)) - { + if (!int.TryParse(msg, out int vote)) { return true; } - if (vote < 1 || vote > this.voteOptions.Length) - { + if (vote < 1 || vote > this.voteOptions.Length) { return true; } - if (this.votes.ContainsKey(player.SteamID)) - { + if (this.votes.ContainsKey(player.SteamID)) { this.votes.Remove(player.SteamID); } @@ -156,7 +136,6 @@ public override async Task OnPlayerTypedMessage(RunnerPlayer player, ChatC } } -public class VoteConfiguration : ModuleConfiguration -{ +public class VoteConfiguration : ModuleConfiguration { public int VoteDuration { get; set; } = 60; } From 3b4d8bd1e0350aca2ccbc2d615603a76ef45a614 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Thu, 19 Oct 2023 06:40:37 +0200 Subject: [PATCH 17/22] Code Cleanup (Code Maid) --- Announcements.cs | 3 ++- BasicProgression.cs | 2 +- BasicServerSettings.cs | 4 ++++ ChatOverwrite.cs | 6 ++++-- CommandHandler.cs | 5 ++++- DiscordWebhooks.cs | 3 +-- GeoLimiter.cs | 2 +- GranularPermissions.cs | 3 ++- GranularPermissionsCommands.cs | 4 +++- LoadingScreenText.cs | 9 ++++++++- MOTD.cs | 2 +- ModeratorTools.cs | 3 ++- ModuleUpdates.cs | 8 ++++---- PasswordReservedSlots.cs | 2 +- PermissionsCommands.cs | 5 ++++- PlayerFinder.cs | 1 + PlayerRolesFromGranularPermissions.cs | 4 +++- ProfanityFilter.cs | 2 +- RichText.cs | 8 ++++++++ Rotation.cs | 4 +++- SpectateControl.cs | 2 +- VacLimiter.cs | 2 +- Voting.cs | 2 +- 23 files changed, 61 insertions(+), 25 deletions(-) diff --git a/Announcements.cs b/Announcements.cs index 6a98ad2..27272d0 100644 --- a/Announcements.cs +++ b/Announcements.cs @@ -89,6 +89,7 @@ public class AnnouncementsConfiguration : ModuleConfiguration { public string[] AnnounceShort { get; set; } = Array.Empty(); public string[] UILogOnServer { get; set; } = Array.Empty(); public string[] MessageToPlayer { get; set; } = Array.Empty(); + public string[] SayToAllChat { get; set; } = new[] { "We hope you enjoy our server!", @@ -108,4 +109,4 @@ public class AnnouncementStore : ModuleConfiguration { public int lastUILogOnServerItem { get; set; } = 0; public int lastMessageToPlayerItem { get; set; } = 0; public int lastSayToAllChatItem { get; set; } = 0; -} +} \ No newline at end of file diff --git a/BasicProgression.cs b/BasicProgression.cs index 8e40f6e..a343589 100644 --- a/BasicProgression.cs +++ b/BasicProgression.cs @@ -34,7 +34,6 @@ public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningA return; } - var playerFile = getPlayerFile(steamID); for (int i = 0; i < 5; i++) { try { @@ -54,6 +53,7 @@ public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningA this.Logger.Error($"Giving up trying to read \"{playerFile.FullName}\""); } + public override async Task OnSavePlayerStats(ulong steamID, PlayerStats stats) { Console.WriteLine("OnSavePlayerStats"); this.Logger.Info(stats.str()); diff --git a/BasicServerSettings.cs b/BasicServerSettings.cs index 7ea87b1..d977f2e 100644 --- a/BasicServerSettings.cs +++ b/BasicServerSettings.cs @@ -102,9 +102,12 @@ private void applyPlayerSettings(RunnerPlayer player) { player.Modifications.ReviveHP = this.Configuration.ReviveHP ?? player.Modifications.ReviveHP; } } + public class BasicServerSettingsConfiguration : ModuleConfiguration { + // Server public float? APCSpawnDelayMultipler { get; set; } = null; + public float? HelicopterSpawnDelayMultipler { get; set; } = null; public float? SeaVehicleSpawnDelayMultipler { get; set; } = null; public float? TankSpawnDelayMultipler { get; set; } = null; @@ -124,6 +127,7 @@ public class BasicServerSettingsConfiguration : ModuleConfiguration { // Player public bool? AirStrafe { get; set; } = null; + public VehicleType? AllowedVehicles { get; set; } = null; public bool? CanDeploy { get; set; } = null; public bool? CanSpectate { get; set; } = null; diff --git a/ChatOverwrite.cs b/ChatOverwrite.cs index 75e354b..6cfcaaa 100644 --- a/ChatOverwrite.cs +++ b/ChatOverwrite.cs @@ -14,10 +14,10 @@ namespace ChatOverwrite; public class ChatOverwrite : BattleBitModule { [ModuleReference] -#if DEBUG public SteamApi? SteamApi { get; set; } = null!; + #else - public SteamApi? SteamApi { get; set; } + public SteamApi? SteamApi { get; set; } #endif public ChatOverwriteConfiguration Configuration { get; set; } = null!; @@ -120,8 +120,10 @@ private static string FormatTextWithGradient(string text, string[] gradientColor public class ChatOverwriteConfiguration : ModuleConfiguration { public string TimeStampFormat { get; set; } = "HH:mm:ss"; + [Obsolete] public string TimeZone { get; set; } = System.TimeZone.CurrentTimeZone.StandardName; + public Dictionary Overwrites { get; set; } = new() { { "ChatOverwrite.Normal", new("[6] {1}{2} : {4}") }, diff --git a/CommandHandler.cs b/CommandHandler.cs index 55d3933..60f77aa 100644 --- a/CommandHandler.cs +++ b/CommandHandler.cs @@ -514,10 +514,12 @@ public virtual void Reply(string message) { } public abstract class Source { + public abstract void Reply(Context context, string message); } public class ChatSource : Source { + public ChatSource(RunnerPlayer invoker) { this.Invoker = invoker; } @@ -544,7 +546,8 @@ public override void Reply(Context context, string message) { } public class ConsoleSource : Source { + public override void Reply(Context context, string message) { context.CommandHandler.Logger.Info(message); } -} +} \ No newline at end of file diff --git a/DiscordWebhooks.cs b/DiscordWebhooks.cs index 09dbbd7..05ad999 100644 --- a/DiscordWebhooks.cs +++ b/DiscordWebhooks.cs @@ -66,7 +66,6 @@ private async Task sendChatMessagesToDiscord() { messages.Add(message); } - if (messages.Count > 0) { await sendWebhookMessage(this.Configuration.WebhookURL, string.Join(Environment.NewLine, messages.Select(message => message.ToString()))); } @@ -101,7 +100,6 @@ private async Task sendWebhookMessage(string webhookUrl, string message) { success = response.IsSuccessStatusCode; } } - } internal class DiscordMessage { @@ -158,6 +156,7 @@ public override string ToString() { } internal class WarningMessage : DiscordMessage { + public WarningMessage(string message) { this.Message = message; } diff --git a/GeoLimiter.cs b/GeoLimiter.cs index 2534725..76e6030 100644 --- a/GeoLimiter.cs +++ b/GeoLimiter.cs @@ -95,4 +95,4 @@ public class Geolocation { public uint ToIP { get; set; } public string CountryCode { get; set; } = null!; public string CountryName { get; set; } = null!; -} +} \ No newline at end of file diff --git a/GranularPermissions.cs b/GranularPermissions.cs index 1b26e4e..29f6fe1 100644 --- a/GranularPermissions.cs +++ b/GranularPermissions.cs @@ -317,6 +317,7 @@ public string[] GetAllPlayerPermissions(ulong steamId) { } public class PermissionsConfiguration : ModuleConfiguration { + public Dictionary> Groups { get; set; } = new() { { GranularPermissions.CatchAll, new() } }; @@ -325,4 +326,4 @@ public class PermissionsConfiguration : ModuleConfiguration { public class PermissionsServerConfiguration : ModuleConfiguration { public Dictionary> PlayerGroups { get; set; } = new(); public Dictionary> PlayerPermissions { get; set; } = new(); -} +} \ No newline at end of file diff --git a/GranularPermissionsCommands.cs b/GranularPermissionsCommands.cs index c3475fc..773149f 100644 --- a/GranularPermissionsCommands.cs +++ b/GranularPermissionsCommands.cs @@ -11,8 +11,10 @@ namespace PermissionsManager; [RequireModule(typeof(GranularPermissions))] [Module("Provide commands for managing GranularPermissions", "1.0.0")] public class GranularPermissionsCommands : BattleBitModule { + [ModuleReference] public GranularPermissions GranularPermissions { get; set; } = null!; + [ModuleReference] public CommandHandler CommandHandler { get; set; } = null!; @@ -256,4 +258,4 @@ public string ListGroupPermissionCommand(Context context, string group, int page public class GranularPermissionsCommandsConfiguration : ModuleConfiguration { public int PermissionsPerPage { get; set; } = 6; -} +} \ No newline at end of file diff --git a/LoadingScreenText.cs b/LoadingScreenText.cs index ec5ec31..c7e7f36 100644 --- a/LoadingScreenText.cs +++ b/LoadingScreenText.cs @@ -11,18 +11,22 @@ namespace BattleBitBaseModules; [RequireModule(typeof(BattleBitBaseModules.RichText))] [Module("Configure the loading screen text of your server", "1.0.0")] public class LoadingScreenText : BattleBitModule { + [ModuleReference] public LoadingScreenTextConfiguration Config { get; set; } = null!; public override Task OnConnected() { UpdateLoadingScreenText(this.Config.ConnectLoadingScreenText); return Task.CompletedTask; } + public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { UpdateLoadingScreenText(this.Config.ConnectLoadingScreenText); return Task.CompletedTask; } + public override Task OnRoundEnded() { UpdateLoadingScreenText(this.Config.MapChangeLoadingScreenText); return Task.CompletedTask; } + //public override Task OnSessionChanged(long oldSessionID, long newSessionID) { // UpdateLoadingScreenText(this.Config.MapChangeLoadingScreenText); return Task.CompletedTask; //} @@ -56,15 +60,18 @@ public void UpdateLoadingScreenText(string template) { } public class LoadingScreenTextConfiguration : ModuleConfiguration { + public Dictionary randomReplacements = new Dictionary() { { "welcome", new string[] { "Enjoy your stay!", "Have a good one!", "Get Ready for battle!" } }, }; + public string ConnectLoadingScreenText { get; set; } = @$"{Colors.SkyBlue}Welcome to {Colors.None}{{server}}{Colors.SkyBlue}! We are currently playing {Colors.None}{{gamemode}}{Colors.SkyBlue} on {Colors.None}{{map}}{Colors.SkyBlue} at {Colors.None}{{maptime}}{Colors.SkyBlue} with {Colors.None}{{players}}{Colors.SkyBlue}/{Colors.None}{{slots}}{Colors.SkyBlue} players! {{random.welcome}}"; + public string MapChangeLoadingScreenText { get; set; } = @$"{Colors.SkyBlue}Welcome to {Colors.None}{{server}}{Colors.SkyBlue}! {{random.welcome}}"; } -} +} \ No newline at end of file diff --git a/MOTD.cs b/MOTD.cs index a847e40..309e561 100644 --- a/MOTD.cs +++ b/MOTD.cs @@ -82,4 +82,4 @@ public string ShowMOTD(Context context) { public class MOTDConfiguration : ModuleConfiguration { public string MOTD { get; set; } = "Welcome!"; -} +} \ No newline at end of file diff --git a/ModeratorTools.cs b/ModeratorTools.cs index f97d9f1..1f4ca97 100644 --- a/ModeratorTools.cs +++ b/ModeratorTools.cs @@ -11,6 +11,7 @@ namespace BattleBitBaseModules; [RequireModule(typeof(CommandHandler))] [Module("Basic moderator tools", "1.1.0")] public class ModeratorTools : BattleBitModule { + [ModuleReference] public CommandHandler CommandHandler { get; set; } = null!; @@ -404,4 +405,4 @@ public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel return Task.FromResult(request as OnPlayerSpawnArguments?); } -} +} \ No newline at end of file diff --git a/ModuleUpdates.cs b/ModuleUpdates.cs index b08d16b..23b96e3 100644 --- a/ModuleUpdates.cs +++ b/ModuleUpdates.cs @@ -14,9 +14,9 @@ namespace BattleBitBaseModules; public class ModuleUpdates : BattleBitModule { public static ModuleUpdatesConfiguration Configuration { get; set; } = null!; - PropertyInfo nameProperty = null!; - PropertyInfo versionProperty = null!; - PropertyInfo moduleFilePathProperty = null!; + private PropertyInfo nameProperty = null!; + private PropertyInfo versionProperty = null!; + private PropertyInfo moduleFilePathProperty = null!; private static dynamic[] modulesToUpdate = Array.Empty(); private static bool running = false; @@ -168,4 +168,4 @@ public override void OnConsoleCommand(string command) { public class ModuleUpdatesConfiguration : ModuleConfiguration { public string APIEndpoint { get; set; } = "https://modules.battlebit.community/api"; public int CheckDelay { get; set; } = 30; -} +} \ No newline at end of file diff --git a/PasswordReservedSlots.cs b/PasswordReservedSlots.cs index a29236b..85dd4a7 100644 --- a/PasswordReservedSlots.cs +++ b/PasswordReservedSlots.cs @@ -74,4 +74,4 @@ public string SetRSSlotsCommand(Context context, int slots) { public class PasswordReservedSlotsConfiguration : ModuleConfiguration { public string Password { get; set; } = "changeme"; public int Slots { get; set; } = 0; -} +} \ No newline at end of file diff --git a/PermissionsCommands.cs b/PermissionsCommands.cs index 65c2b6c..97e4e48 100644 --- a/PermissionsCommands.cs +++ b/PermissionsCommands.cs @@ -10,10 +10,13 @@ namespace PermissionsManager; [RequireModule(typeof(CommandHandler))] [Module("Provide addperm and removeperm commands for PlayerPermissions", "1.1.0")] public class PermissionsCommands : BattleBitModule { + [ModuleReference] public dynamic? PlayerPermissions { get; set; } + [ModuleReference] public dynamic? GranularPermissions { get; set; } + [ModuleReference] public CommandHandler CommandHandler { get; set; } = null!; @@ -123,4 +126,4 @@ public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, public class PermissionsCommandsConfiguration : ModuleConfiguration { public int PermissionsPerPage { get; set; } = 6; -} +} \ No newline at end of file diff --git a/PlayerFinder.cs b/PlayerFinder.cs index 4f3404a..00e6ddf 100644 --- a/PlayerFinder.cs +++ b/PlayerFinder.cs @@ -6,6 +6,7 @@ namespace PlayerFinder; [Module("Library functions for finding players by partial names or SteamID", "1.0.0")] public class PlayerFinder : BattleBitModule { + public RunnerPlayer? ByExactName(string exactName, bool caseSensitive) { return this.Server.AllPlayers.FirstOrDefault(p => p.Name.Equals(exactName, caseSensitive ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase)); } diff --git a/PlayerRolesFromGranularPermissions.cs b/PlayerRolesFromGranularPermissions.cs index 123fb1b..f95d3a5 100644 --- a/PlayerRolesFromGranularPermissions.cs +++ b/PlayerRolesFromGranularPermissions.cs @@ -8,6 +8,7 @@ namespace Permissions; [RequireModule(typeof(GranularPermissions))] [Module("Provides player roles based on granular permissions", "1.0.0")] public class PlayerRolesFromGranularPermissions : BattleBitModule { + [ModuleReference] public GranularPermissions GranularPermissions { get; set; } = null!; @@ -30,6 +31,7 @@ public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArgumen } public class PlayerRolesConfiguration : ModuleConfiguration { + public Dictionary PermissionRoles { get; set; } = new() { { "Role.Admin", Roles.Admin }, @@ -43,4 +45,4 @@ public class PlayerRolesConfiguration : ModuleConfiguration { }; public bool AppendRoles { get; set; } = false; -} +} \ No newline at end of file diff --git a/ProfanityFilter.cs b/ProfanityFilter.cs index 215a833..288d902 100644 --- a/ProfanityFilter.cs +++ b/ProfanityFilter.cs @@ -81,4 +81,4 @@ public class ProfanityFilterConfiguration : ModuleConfiguration { public List Profanity { get; set; } = new(); public float MessageTimeout { get; set; } = 10f; public string Message { get; set; } = "Please do not use profanity in chat."; -} +} \ No newline at end of file diff --git a/RichText.cs b/RichText.cs index dfeab4a..3b950a9 100644 --- a/RichText.cs +++ b/RichText.cs @@ -6,6 +6,7 @@ namespace BattleBitBaseModules; [Module("Library for easily using Rich Text", "1.1.0")] public class RichText : BattleBitModule { + public string NewLine() => "
"; public string Color(string? color = null) { @@ -53,6 +54,7 @@ public string Alpha(string? alpha = null) { } public string CharacterSpacing(int pixels) => $""; + public string CharacterSpacing(float em) => $""; public string Font(string? fontName) { @@ -76,14 +78,19 @@ public string Indent(int? percentage = null) { public string LineIndentation(int percentage) => $""; public string Lowercase(bool lowercase) => lowercase ? "" : ""; + public string Uppercase(bool uppercase) => uppercase ? "" : ""; + public string Smallcaps(bool smallcaps) => smallcaps ? "" : ""; public string Margin(int pixels) => $""; + public string Margin(float em) => $""; public string Monospacing(int pixels) => $""; + public string Monospacing(float em) => $""; + public string Monospacing() => ""; public string Noparse(bool noparse) => noparse ? "" : ""; @@ -93,6 +100,7 @@ public string Indent(int? percentage = null) { public string HorizontalPosition(int percentage) => $""; public string HorizontalSpace(int pixels) => $""; + public string HorizontalSpace(float em) => $""; public string VerticalOffset(float em) => $""; diff --git a/Rotation.cs b/Rotation.cs index 1b1c1a0..93c13ab 100644 --- a/Rotation.cs +++ b/Rotation.cs @@ -20,6 +20,7 @@ public override Task OnConnected() { } public class RotationConfiguration : ModuleConfiguration { + public string[] GameModes { get; set; } = new[] { "TDM", @@ -41,6 +42,7 @@ public class RotationConfiguration : ModuleConfiguration { "VoxelTrench", "CaptureTheFlag" }; + public string[] Maps { get; set; } = new[] { "Azagor", @@ -63,4 +65,4 @@ public class RotationConfiguration : ModuleConfiguration { "Wakistan", "WineParadise" }; -} +} \ No newline at end of file diff --git a/SpectateControl.cs b/SpectateControl.cs index 086b200..1859f4a 100644 --- a/SpectateControl.cs +++ b/SpectateControl.cs @@ -58,4 +58,4 @@ public override Task OnPlayerConnected(RunnerPlayer player) { public class SpectateControlConfiguration : ModuleConfiguration { public List SpectatorPermissions { get; set; } = new(); -} +} \ No newline at end of file diff --git a/VacLimiter.cs b/VacLimiter.cs index ed36f36..55ee47d 100644 --- a/VacLimiter.cs +++ b/VacLimiter.cs @@ -196,4 +196,4 @@ public class VacLimiterCache : ModuleConfiguration { record CacheRequest(VacLimiter VacLimiter, RunnerPlayer Player); public record PlayerBansModel(string SteamId, bool CommunityBanned, bool VACBanned, uint NumberOfVACBans, uint DaysSinceLastBan, uint NumberOfGameBans, string EconomyBan); -public record PlayerBanResponseModel(PlayerBansModel[] players); +public record PlayerBanResponseModel(PlayerBansModel[] players); \ No newline at end of file diff --git a/Voting.cs b/Voting.cs index 18283b8..29f4479 100644 --- a/Voting.cs +++ b/Voting.cs @@ -138,4 +138,4 @@ public override async Task OnPlayerTypedMessage(RunnerPlayer player, ChatC public class VoteConfiguration : ModuleConfiguration { public int VoteDuration { get; set; } = 60; -} +} \ No newline at end of file From 362483b26b795668df9e86b84dbcb15757d5cc31 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Thu, 19 Oct 2023 09:51:15 +0200 Subject: [PATCH 18/22] fix basic progression --- BasicProgression.cs | 346 +++++++++++++++++++++----------------------- ChatOverwrite.cs | 6 +- 2 files changed, 163 insertions(+), 189 deletions(-) diff --git a/BasicProgression.cs b/BasicProgression.cs index a343589..2266f9e 100644 --- a/BasicProgression.cs +++ b/BasicProgression.cs @@ -5,254 +5,230 @@ using System.Threading.Tasks; using static BattleBitAPI.Common.PlayerStats; -namespace BattleBitBaseModules { +namespace BattleBitBaseModules; - [Module("Provide basic persistent progression for players", "1.1.1")] - public class BasicProgression : BattleBitModule { - public BasicProgressionConfiguration Configuration { get; set; } = null!; +[Module("Provide basic persistent progression for players", "1.1.1")] +public class BasicProgression : BattleBitModule { + public BasicProgressionConfiguration Configuration { get; set; } = null!; - public DirectoryInfo DataDir => new DirectoryInfo(GlobalConfiguration.PerServer ? Path.Combine(GlobalConfiguration.DataDirectory, $"{this.Server.GameIP}:{this.Server.GamePort}") : GlobalConfiguration.DataDirectory); + private string dataDir => this.Configuration.PerServer ? Path.Combine(this.Configuration.DataDirectory, $"{this.Server.GameIP}:{this.Server.GamePort}") : this.Configuration.DataDirectory; - public override Task OnConnected() { - if (!DataDir.Exists) { - DataDir.Create(); - } - - return Task.CompletedTask; + public override Task OnConnected() { + if (!Directory.Exists(dataDir)) { + Directory.CreateDirectory(dataDir); } - public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { - if (this.Configuration.ApplyInitialStatsOnEveryJoin) { - args.Stats = this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats; - return; - } - - string playerFileName = getPlayerFileName(steamID); - for (int i = 0; i < 5; i++) { - try { - args.Stats = File.Exists(playerFileName) ? new PlayerStats(File.ReadAllBytes(playerFileName)) : (this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats); - return; - } - - var playerFile = getPlayerFile(steamID); - for (int i = 0; i < 5; i++) { - try { - if (playerFile.Exists) { - args.Stats = GlobalConfiguration.PlainText ? JsonUtils.FromJsonFile(playerFile) : new PlayerStats(File.ReadAllBytes(playerFile.FullName)); - this.Logger.Info($"Read player stats for {steamID} from \"{playerFile.FullName}\""); - } else { - args.Stats = (GlobalConfiguration.InitialStats ?? args.Stats); - this.Logger.Info($"Applied initial player stats for {steamID}"); - } - return; - } catch (Exception ex) { - this.Logger.Error($"Tried {i} times to read from file {playerFile.FullName} but failed:{ex}"); - } - await Task.Delay(250); - } - this.Logger.Error($"Giving up trying to read \"{playerFile.FullName}\""); - } + return Task.CompletedTask; + } + public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { + if (this.Configuration.ApplyInitialStatsOnEveryJoin) { + args.Stats = this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats; + return; + } - public override async Task OnSavePlayerStats(ulong steamID, PlayerStats stats) { - Console.WriteLine("OnSavePlayerStats"); - this.Logger.Info(stats.str()); - this.Logger.Info(stats.ToJson()); - for (int i = 0; i < 5; i++) { - try { - var playerFile = getPlayerFile(steamID); - if (GlobalConfiguration.PlainText) { - stats.ToJsonFile(playerFile, indented: true); - } else { - playerFile.WriteAllBytes(stats.SerializeToByteArray()); - } - this.Logger.Info($"Wrote player stats for {steamID} to \"{playerFile}\""); - return; - } catch (Exception ex) { - this.Logger.Error($"Tried {i} times to write to file {getPlayerFile(steamID)} but failed:{ex}"); - } - await Task.Delay(250); + string playerFileName = getPlayerFileName(steamID); + for (int i = 0; i < 5; i++) { + try { + args.Stats = File.Exists(playerFileName) ? new PlayerStats(File.ReadAllBytes(playerFileName)) : (this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats); + return; + } catch (Exception ex) { + this.Logger.Error($"Tried {i} times to read from file {playerFileName} but failed:{ex}"); } - this.Logger.Error("Giving up trying to save."); + await Task.Delay(250); } + this.Logger.Error("Giving up trying to read."); + } - private FileInfo getPlayerFile(ulong steamId) { - return new FileInfo(Path.Combine(DataDir.FullName, $"{steamId}.bin")); + public override async Task OnSavePlayerStats(ulong steamID, PlayerStats stats) { + for (int i = 0; i < 5; i++) { + try { + File.WriteAllBytes(getPlayerFileName(steamID), stats.SerializeToByteArray()); + return; + } catch (Exception ex) { + this.Logger.Error($"Tried {i} times to write to file {getPlayerFileName(steamID)} but failed:{ex}"); + } + await Task.Delay(250); } + this.Logger.Error("Giving up trying to save."); + } - public class Configuration : ModuleConfiguration { - public string DataDirectory { get; set; } = "./data/PersistentProgressionFiles"; + private string getPlayerFileName(ulong steamId) { + return Path.Combine(dataDir, $"{steamId}.bin"); + } +} - public bool PlainText { get; set; } = false; +public class BasicProgressionConfiguration : ModuleConfiguration { + public string DataDirectory { get; set; } = "./data/PersistentProgressionFiles"; - public bool PerServer { get; set; } = false; + public bool PerServer { get; set; } = false; - public bool ApplyInitialStatsOnEveryJoin { get; set; } = false; + public bool ApplyInitialStatsOnEveryJoin { get; set; } = false; - public BasicPlayerStats? InitialStats { get; set; } = new BasicPlayerStats() { - Achievements = new byte[0], - IsBanned = false, - Progress = new BasicPlayerProgress(), - Roles = Roles.None, - Selections = new byte[0], - ToolProgress = new byte[0] - }; - } + public BasicPlayerStats? InitialStats { get; set; } = new BasicPlayerStats() { + Achievements = new byte[0], + IsBanned = false, + Progress = new BasicPlayerProgress(), + Roles = Roles.None, + Selections = new byte[0], + ToolProgress = new byte[0] + }; +} - public class BasicPlayerStats { - public bool IsBanned { get; set; } +public class BasicPlayerStats { + public bool IsBanned { get; set; } - public Roles Roles { get; set; } + public Roles Roles { get; set; } - public BasicPlayerProgress Progress { get; set; } = new(); + public BasicPlayerProgress Progress { get; set; } = new(); - public byte[] ToolProgress { get; set; } = Array.Empty(); + public byte[] ToolProgress { get; set; } = Array.Empty(); - public byte[] Achievements { get; set; } = Array.Empty(); + public byte[] Achievements { get; set; } = Array.Empty(); - public byte[] Selections { get; set; } = Array.Empty(); + public byte[] Selections { get; set; } = Array.Empty(); - public PlayerStats ToPlayerStats() { - return new() { - IsBanned = this.IsBanned, - Roles = this.Roles, - Progress = this.Progress.ToPlayerProgress(), - ToolProgress = this.ToolProgress, - Achievements = this.Achievements, - Selections = this.Selections - }; - } - } + public PlayerStats ToPlayerStats() { + return new() { + IsBanned = this.IsBanned, + Roles = this.Roles, + Progress = this.Progress.ToPlayerProgress(), + ToolProgress = this.ToolProgress, + Achievements = this.Achievements, + Selections = this.Selections + }; + } +} - public class BasicPlayerProgress { - public uint KillCount { get; set; } +public class BasicPlayerProgress { + public uint KillCount { get; set; } - public uint LeaderKills { get; set; } + public uint LeaderKills { get; set; } - public uint AssaultKills { get; set; } + public uint AssaultKills { get; set; } - public uint MedicKills { get; set; } + public uint MedicKills { get; set; } - public uint EngineerKills { get; set; } + public uint EngineerKills { get; set; } - public uint SupportKills { get; set; } + public uint SupportKills { get; set; } - public uint ReconKills { get; set; } + public uint ReconKills { get; set; } - public uint DeathCount { get; set; } + public uint DeathCount { get; set; } - public uint WinCount { get; set; } + public uint WinCount { get; set; } - public uint LoseCount { get; set; } + public uint LoseCount { get; set; } - public uint FriendlyShots { get; set; } + public uint FriendlyShots { get; set; } - public uint FriendlyKills { get; set; } + public uint FriendlyKills { get; set; } - public uint Revived { get; set; } + public uint Revived { get; set; } - public uint RevivedTeamMates { get; set; } + public uint RevivedTeamMates { get; set; } - public uint Assists { get; set; } + public uint Assists { get; set; } - public uint Prestige { get; set; } + public uint Prestige { get; set; } - public uint Rank { get; set; } + public uint Rank { get; set; } - public uint EXP { get; set; } + public uint EXP { get; set; } - public uint ShotsFired { get; set; } + public uint ShotsFired { get; set; } - public uint ShotsHit { get; set; } + public uint ShotsHit { get; set; } - public uint Headshots { get; set; } + public uint Headshots { get; set; } - public uint ObjectivesComplated { get; set; } + public uint ObjectivesComplated { get; set; } - public uint HealedHPs { get; set; } + public uint HealedHPs { get; set; } - public uint RoadKills { get; set; } + public uint RoadKills { get; set; } - public uint Suicides { get; set; } + public uint Suicides { get; set; } - public uint VehiclesDestroyed { get; set; } + public uint VehiclesDestroyed { get; set; } - public uint VehicleHPRepaired { get; set; } + public uint VehicleHPRepaired { get; set; } - public uint LongestKill { get; set; } + public uint LongestKill { get; set; } - public uint PlayTimeSeconds { get; set; } + public uint PlayTimeSeconds { get; set; } - public uint LeaderPlayTime { get; set; } + public uint LeaderPlayTime { get; set; } - public uint AssaultPlayTime { get; set; } + public uint AssaultPlayTime { get; set; } - public uint MedicPlayTime { get; set; } + public uint MedicPlayTime { get; set; } - public uint EngineerPlayTime { get; set; } + public uint EngineerPlayTime { get; set; } - public uint SupportPlayTime { get; set; } + public uint SupportPlayTime { get; set; } - public uint ReconPlayTime { get; set; } + public uint ReconPlayTime { get; set; } - public uint LeaderScore { get; set; } + public uint LeaderScore { get; set; } - public uint AssaultScore { get; set; } + public uint AssaultScore { get; set; } - public uint MedicScore { get; set; } + public uint MedicScore { get; set; } - public uint EngineerScore { get; set; } + public uint EngineerScore { get; set; } - public uint SupportScore { get; set; } + public uint SupportScore { get; set; } - public uint ReconScore { get; set; } + public uint ReconScore { get; set; } - public uint TotalScore { get; set; } + public uint TotalScore { get; set; } - public PlayerProgess ToPlayerProgress() { - return new() { - KillCount = this.KillCount, - LeaderKills = this.LeaderKills, - AssaultKills = this.AssaultKills, - MedicKills = this.MedicKills, - EngineerKills = this.EngineerKills, - SupportKills = this.SupportKills, - ReconKills = this.ReconKills, - DeathCount = this.DeathCount, - WinCount = this.WinCount, - LoseCount = this.LoseCount, - FriendlyShots = this.FriendlyShots, - FriendlyKills = this.FriendlyKills, - Revived = this.Revived, - RevivedTeamMates = this.RevivedTeamMates, - Assists = this.Assists, - Prestige = this.Prestige, - Rank = this.Rank, - EXP = this.EXP, - ShotsFired = this.ShotsFired, - ShotsHit = this.ShotsHit, - Headshots = this.Headshots, - ObjectivesComplated = this.ObjectivesComplated, - HealedHPs = this.HealedHPs, - RoadKills = this.RoadKills, - Suicides = this.Suicides, - VehiclesDestroyed = this.VehiclesDestroyed, - VehicleHPRepaired = this.VehicleHPRepaired, - LongestKill = this.LongestKill, - PlayTimeSeconds = this.PlayTimeSeconds, - LeaderPlayTime = this.LeaderPlayTime, - AssaultPlayTime = this.AssaultPlayTime, - MedicPlayTime = this.MedicPlayTime, - EngineerPlayTime = this.EngineerPlayTime, - SupportPlayTime = this.SupportPlayTime, - ReconPlayTime = this.ReconPlayTime, - LeaderScore = this.LeaderScore, - AssaultScore = this.AssaultScore, - MedicScore = this.MedicScore, - EngineerScore = this.EngineerScore, - SupportScore = this.SupportScore, - ReconScore = this.ReconScore, - TotalScore = this.TotalScore - }; - } - } \ No newline at end of file + public PlayerProgess ToPlayerProgress() { + return new() { + KillCount = this.KillCount, + LeaderKills = this.LeaderKills, + AssaultKills = this.AssaultKills, + MedicKills = this.MedicKills, + EngineerKills = this.EngineerKills, + SupportKills = this.SupportKills, + ReconKills = this.ReconKills, + DeathCount = this.DeathCount, + WinCount = this.WinCount, + LoseCount = this.LoseCount, + FriendlyShots = this.FriendlyShots, + FriendlyKills = this.FriendlyKills, + Revived = this.Revived, + RevivedTeamMates = this.RevivedTeamMates, + Assists = this.Assists, + Prestige = this.Prestige, + Rank = this.Rank, + EXP = this.EXP, + ShotsFired = this.ShotsFired, + ShotsHit = this.ShotsHit, + Headshots = this.Headshots, + ObjectivesComplated = this.ObjectivesComplated, + HealedHPs = this.HealedHPs, + RoadKills = this.RoadKills, + Suicides = this.Suicides, + VehiclesDestroyed = this.VehiclesDestroyed, + VehicleHPRepaired = this.VehicleHPRepaired, + LongestKill = this.LongestKill, + PlayTimeSeconds = this.PlayTimeSeconds, + LeaderPlayTime = this.LeaderPlayTime, + AssaultPlayTime = this.AssaultPlayTime, + MedicPlayTime = this.MedicPlayTime, + EngineerPlayTime = this.EngineerPlayTime, + SupportPlayTime = this.SupportPlayTime, + ReconPlayTime = this.ReconPlayTime, + LeaderScore = this.LeaderScore, + AssaultScore = this.AssaultScore, + MedicScore = this.MedicScore, + EngineerScore = this.EngineerScore, + SupportScore = this.SupportScore, + ReconScore = this.ReconScore, + TotalScore = this.TotalScore + }; + } +} \ No newline at end of file diff --git a/ChatOverwrite.cs b/ChatOverwrite.cs index 6cfcaaa..ed7b072 100644 --- a/ChatOverwrite.cs +++ b/ChatOverwrite.cs @@ -10,15 +10,13 @@ namespace ChatOverwrite; [RequireModule(typeof(GranularPermissions))] +[RequireModule(typeof(SteamApi))] [Module("Overwrite chat messages", "1.0.0")] public class ChatOverwrite : BattleBitModule { [ModuleReference] public SteamApi? SteamApi { get; set; } = null!; -#else - public SteamApi? SteamApi { get; set; } -#endif public ChatOverwriteConfiguration Configuration { get; set; } = null!; [ModuleReference] @@ -84,7 +82,7 @@ public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel public string GetPlayerName(RunnerPlayer player) { if (SteamApi is not null) { - var steam = SteamApi.GetData(player)?.Result; + var steam = player.Get()?.Result; if (steam?.Summary is not null) { if (!string.IsNullOrWhiteSpace(steam.Summary.RealName)) return steam.Summary.RealName; else if (!string.IsNullOrWhiteSpace(steam.Summary.PersonaName)) return steam.Summary.PersonaName; From 24c092408e72481154eda5ee82e11a341a077f33 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sat, 21 Oct 2023 23:49:03 +0200 Subject: [PATCH 19/22] merge pr --- CommandHandler.cs | 9 +++++ DiscordWebhooks.cs | 1 + GranularPermissionsCommands.cs | 56 ++++++++++++++++++++++++++- MOTD.cs | 45 +++++++++++++++------ ModeratorTools.cs | 2 +- PasswordReservedSlots.cs | 45 ++++++++++++++------- PermissionsCommands.cs | 46 ++++++++++++++-------- PlayerRolesFromGranularPermissions.cs | 31 ++++++++------- Voting.cs | 14 ++++--- 9 files changed, 183 insertions(+), 66 deletions(-) diff --git a/CommandHandler.cs b/CommandHandler.cs index 60f77aa..d499e52 100644 --- a/CommandHandler.cs +++ b/CommandHandler.cs @@ -15,6 +15,7 @@ namespace Commands; public class CommandHandler : BattleBitModule { public static CommandConfiguration CommandConfiguration { get; set; } = null!; public CommandSettings CommandSettings { get; set; } = null!; + public CommandSettings CommandSettings { get; set; } = null!; private Dictionary commandCallbacks = new(); @@ -91,6 +92,8 @@ public void Register(BattleBitModule module) { this.Logger.Error($"Command callback {command} in module {module.GetType().Name} conflicts with subcommand {subcommand}."); continue; + this.Logger.Error($"Command callback {command} in module {module.GetType().Name} conflicts with subcommand {subcommand}."); + continue; } // Prevent subcommands of existing commands (!perm add and !perm remove do not allow !perm) @@ -110,6 +113,7 @@ public void Register(BattleBitModule module) { } this.CommandSettings.Save(); + this.CommandSettings.Save(); } public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string message) { @@ -117,6 +121,7 @@ public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel return Task.FromResult(true); } + Task.Run(() => this.HandleCommand(new ChatSource(player), message)); Task.Run(() => this.HandleCommand(new ChatSource(player), message)); return Task.FromResult(false); @@ -128,6 +133,7 @@ public override void OnConsoleCommand(string command) { } Task.Run(() => this.HandleCommand(new ConsoleSource(), command)); + Task.Run(() => this.HandleCommand(new ConsoleSource(), command)); } public bool IsCommand(string message) { @@ -204,6 +210,9 @@ public void HandleCommand(Source source, string message) { ChatSource? chatSource = source as ChatSource; Context errorContext = new Context(source, message, command, Array.Empty(), Array.Empty(), null, this, null); + ChatSource? chatSource = source as ChatSource; + Context errorContext = new Context(source, message, command, Array.Empty(), Array.Empty(), null, this, null); + int subCommandSkip; for (subCommandSkip = 1; subCommandSkip < fullCommand.Length && !this.commandCallbacks.ContainsKey(command); subCommandSkip++) { command += $" {fullCommand[subCommandSkip]}"; diff --git a/DiscordWebhooks.cs b/DiscordWebhooks.cs index 05ad999..f502e91 100644 --- a/DiscordWebhooks.cs +++ b/DiscordWebhooks.cs @@ -20,6 +20,7 @@ public override void OnModulesLoaded() { if (string.IsNullOrEmpty(this.Configuration.WebhookURL)) { this.Unload(); this.Logger.Error("Webhook URL is not set. Please set it in the configuration file."); + this.Logger.Error("Webhook URL is not set. Please set it in the configuration file."); } } diff --git a/GranularPermissionsCommands.cs b/GranularPermissionsCommands.cs index 773149f..d35dbd7 100644 --- a/GranularPermissionsCommands.cs +++ b/GranularPermissionsCommands.cs @@ -9,7 +9,7 @@ namespace PermissionsManager; [RequireModule(typeof(CommandHandler))] [RequireModule(typeof(GranularPermissions))] -[Module("Provide commands for managing GranularPermissions", "1.0.0")] +[Module("Provide commands for managing GranularPermissions", "1.0.1")] public class GranularPermissionsCommands : BattleBitModule { [ModuleReference] @@ -32,6 +32,10 @@ public string AddPermissionCommand(Context context, RunnerPlayer player, string this.Logger.Debug($"Added permission {permission} to {player.Name}"); return $"Added permission {permission} to {player.Name}"; + + this.Logger.Debug($"Added permission {permission} to {player.Name}"); + + return $"Added permission {permission} to {player.Name}"; } [CommandCallback("removeplayerperm", Description = "Removes a permission from a player", Permissions = new[] { "GranularPermissions.RemovePlayerPerm" })] @@ -42,6 +46,10 @@ public string RemovePermissionCommand(Context context, RunnerPlayer player, stri this.Logger.Debug($"Removed permission {permission} from {player.Name}"); return $"Removed permission {permission} from {player.Name}"; + + this.Logger.Debug($"Removed permission {permission} from {player.Name}"); + + return $"Removed permission {permission} from {player.Name}"; } [CommandCallback("clearplayerperms", Description = "Clears all permissions and groups from a player", Permissions = new[] { "GranularPermissions.ClearPlayerPerms" })] @@ -59,6 +67,10 @@ public string ClearPermissionCommand(Context context, RunnerPlayer player) { this.Logger.Debug($"Cleared permissions from {player.Name}"); return $"Cleared permissions from {player.Name}"; + + this.Logger.Debug($"Cleared permissions from {player.Name}"); + + return $"Cleared permissions from {player.Name}"; } [CommandCallback("listplayerperms", Description = "Lists player permissions", Permissions = new[] { "GranularPermissions.ListPlayerPerms" })] @@ -73,6 +85,9 @@ public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, this.Logger.Debug($"Listing permissions for {targetPlayer.Name}"); + return $"{targetPlayer.Name}:{Environment.NewLine}{string.Join("\n", permissions.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listperms \"{targetPlayer.Name}\" {page + 1} to see more")}" : "")}"; + this.Logger.Debug($"Listing permissions for {targetPlayer.Name}"); + return $"{targetPlayer.Name}:{Environment.NewLine}{string.Join("\n", permissions.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listperms \"{targetPlayer.Name}\" {page + 1} to see more")}" : "")}"; } @@ -92,6 +107,10 @@ public string AddGroupCommand(Context context, RunnerPlayer player, string group this.Logger.Debug($"Added group {group} to {player.Name}"); return $"Added group {group} to {player.Name}"; + + this.Logger.Debug($"Added group {group} to {player.Name}"); + + return $"Added group {group} to {player.Name}"; } [CommandCallback("removeplayergroup", Description = "Removes a group from a player", Permissions = new[] { "GranularPermissions.RemovePlayerGroup" })] @@ -106,6 +125,10 @@ public string RemoveGroupCommand(Context context, RunnerPlayer player, string gr this.Logger.Debug($"Removed group {group} from {player.Name}"); return $"Removed group {group} from {player.Name}"; + + this.Logger.Debug($"Removed group {group} from {player.Name}"); + + return $"Removed group {group} from {player.Name}"; } [CommandCallback("clearplayergroups", Description = "Clears all groups from a player", Permissions = new[] { "GranularPermissions.ClearPlayerGroups" })] @@ -119,6 +142,10 @@ public string ClearGroupCommand(Context context, RunnerPlayer player) { this.Logger.Debug($"Cleared groups from {player.Name}"); return $"Cleared groups from {player.Name}"; + + this.Logger.Debug($"Cleared groups from {player.Name}"); + + return $"Cleared groups from {player.Name}"; } [CommandCallback("listplayergroups", Description = "Lists player groups", Permissions = new[] { "GranularPermissions.ListPlayerGroups" })] @@ -135,6 +162,9 @@ public string ListGroupCommand(Context context, RunnerPlayer targetPlayer, int p this.Logger.Debug($"Listing groups for {targetPlayer.Name}"); + return $"{targetPlayer.Name}:{Environment.NewLine}{string.Join("\n", groups.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroups \"{targetPlayer.Name}\" {page + 1} to see more")}" : "")}"; + this.Logger.Debug($"Listing groups for {targetPlayer.Name}"); + return $"{targetPlayer.Name}:{Environment.NewLine}{string.Join("\n", groups.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroups \"{targetPlayer.Name}\" {page + 1} to see more")}" : "")}"; } @@ -150,6 +180,10 @@ public string AddGroupCommand(Context context, string group) { this.Logger.Debug($"Added group {group}"); return $"Added group {group}"; + + this.Logger.Debug($"Added group {group}"); + + return $"Added group {group}"; } [CommandCallback("removegroup", Description = "Removes a group", Permissions = new[] { "GranularPermissions.RemoveGroup" })] @@ -164,6 +198,10 @@ public string RemoveGroupCommand(Context context, string group) { this.Logger.Debug($"Removed group {group}"); return $"Removed group {group}"; + + this.Logger.Debug($"Removed group {group}"); + + return $"Removed group {group}"; } [CommandCallback("listgroups", Description = "Lists groups", Permissions = new[] { "GranularPermissions.ListGroups" })] @@ -180,6 +218,9 @@ public string ListGroupCommand(Context context, int page = 1) { this.Logger.Debug($"Listing groups"); + return $"{Environment.NewLine}{string.Join("\n", groups.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroups {page + 1} to see more")}" : "")}"; + this.Logger.Debug($"Listing groups"); + return $"{Environment.NewLine}{string.Join("\n", groups.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroups {page + 1} to see more")}" : "")}"; } @@ -199,6 +240,10 @@ public string AddGroupPermissionCommand(Context context, string group, string pe this.Logger.Debug($"Added permission {permission} to {group}"); return $"Added permission {permission} to {group}"; + + this.Logger.Debug($"Added permission {permission} to {group}"); + + return $"Added permission {permission} to {group}"; } [CommandCallback("removegroupperm", Description = "Removes a permission from a group", Permissions = new[] { "GranularPermissions.RemoveGroupPerm" })] @@ -217,6 +262,10 @@ public string RemoveGroupPermissionCommand(Context context, string group, string this.Logger.Debug($"Removed permission {permission} from {group}"); return $"Removed permission {permission} from {group}"; + + this.Logger.Debug($"Removed permission {permission} from {group}"); + + return $"Removed permission {permission} from {group}"; } [CommandCallback("cleargroupperms", Description = "Clears all permissions from a group", Permissions = new[] { "GranularPermissions.ClearGroupPerms" })] @@ -234,6 +283,10 @@ public string ClearGroupPermissionCommand(Context context, string group) { this.Logger.Debug($"Cleared permissions from {group}"); return $"Cleared permissions from {group}"; + + this.Logger.Debug($"Cleared permissions from {group}"); + + return $"Cleared permissions from {group}"; } [CommandCallback("listgroupperms", Description = "Lists group permissions", Permissions = new[] { "GranularPermissions.ListGroupPerms" })] @@ -253,6 +306,7 @@ public string ListGroupPermissionCommand(Context context, string group, int page int pageCount = (int)Math.Ceiling(permissions.Count / (double)this.Configuration.PermissionsPerPage); return $"{group}:{Environment.NewLine}{string.Join("\n", permissions.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroupperms \"{group}\" {page + 1} to see more")}" : "")}"; + return $"{group}:{Environment.NewLine}{string.Join("\n", permissions.Skip((page - 1) * this.Configuration.PermissionsPerPage).Take(this.Configuration.PermissionsPerPage))}{(pageCount > 1 ? $"{Environment.NewLine}Page {page} of {pageCount}{(page == pageCount ? "" : $", use listgroupperms \"{group}\" {page + 1} to see more")}" : "")}"; } } diff --git a/MOTD.cs b/MOTD.cs index 309e561..fcb99c1 100644 --- a/MOTD.cs +++ b/MOTD.cs @@ -1,6 +1,8 @@ using BattleBitAPI.Common; +using BattleBitAPI.Features; using BBRAPIModules; using Commands; +using Permissions; using System; using System.Collections.Generic; using System.Linq; @@ -9,8 +11,9 @@ namespace BattleBitBaseModules; [RequireModule(typeof(CommandHandler))] -[Module("Show a message of the day to players who join the server", "1.1.0")] -public class MOTD : BattleBitModule { +[Module("Show a message of the day to players who join the server", "1.1.1")] +public class MOTD : BattleBitModule +{ public MOTDConfiguration Configuration { get; set; } = null!; [ModuleReference] @@ -19,18 +22,25 @@ public class MOTD : BattleBitModule { [ModuleReference] public dynamic? PlaceholderLib { get; set; } + [ModuleReference] + public GranularPermissions GranularPermissions { get; set; } + private List greetedPlayers = new(); - public override void OnModulesLoaded() { - if (this.PlaceholderLib is null) { + public override void OnModulesLoaded() + { + if (this.PlaceholderLib is null) + { this.Logger.Info("PlaceholderLib not found. MOTD will only support basic numbered placeholders."); } this.CommandHandler.Register(this); } - public override Task OnGameStateChanged(GameState oldState, GameState newState) { - if (newState == GameState.EndingGame) { + public override Task OnGameStateChanged(GameState oldState, GameState newState) + { + if (newState == GameState.EndingGame) + { greetedPlayers.Clear(); greetedPlayers.AddRange(this.Server.AllPlayers.Select(p => p.SteamID)); } @@ -43,24 +53,33 @@ public override Task OnPlayerConnected(RunnerPlayer player) { return Task.CompletedTask; } + if (this.GranularPermissions is not null && !this.GranularPermissions.HasPermission(player.SteamID, "MOTD.View")) + { + this.Logger.Debug($"Player {player.Name} ({player.SteamID}) does not have permission to view the MOTD."); + return Task.CompletedTask; + } + this.ShowMOTD(new Context(new ChatSource(player), string.Empty, "motd", Array.Empty(), Array.Empty(), this, this.CommandHandler, null)); return Task.CompletedTask; } - [CommandCallback("setmotd", Description = "Sets the MOTD", Permissions = new[] { "MOTD.Set" })] - public void SetMOTD(Context context, string motd) { + [CommandCallback("setmotd", Description = "Sets the MOTD", Permissions = new[] { "MOTD.Set" }, ConsoleCommand = true)] + public void SetMOTD(Context context, string motd) + { this.Configuration.MOTD = motd; this.Configuration.Save(); this.ShowMOTD(context); } - [CommandCallback("motd", Description = "Shows the MOTD")] - public string ShowMOTD(Context context) { + [CommandCallback("motd", Description = "Shows the MOTD", Permissions = new[] { "MOTD.View" })] + public string ShowMOTD(Context context) + { ChatSource? chatSource = context.Source as ChatSource; string message; - if (this.PlaceholderLib is not null) { + if (this.PlaceholderLib is not null) + { message = new PlaceholderLib(this.Configuration.MOTD) .AddParam("servername", this.Server.ServerName) .AddParam("gamemode", this.Server.Gamemode) @@ -72,7 +91,9 @@ public string ShowMOTD(Context context) { .AddParam("maxplayers", this.Server.MaxPlayerCount) .AddParam("name", chatSource?.Invoker.Name ?? context.Source.GetType().Name) .AddParam("ping", chatSource?.Invoker.PingMs ?? 0).Run(); - } else { + } + else + { message = string.Format(this.Configuration.MOTD, chatSource?.Invoker.Name ?? context.Source.GetType().Name, chatSource?.Invoker.PingMs ?? 0, this.Server.ServerName, this.Server.Gamemode, this.Server.Map, this.Server.DayNight, this.Server.MapSize.ToString().Trim('_'), this.Server.CurrentPlayerCount, this.Server.InQueuePlayerCount, this.Server.MaxPlayerCount); } diff --git a/ModeratorTools.cs b/ModeratorTools.cs index 1f4ca97..678af26 100644 --- a/ModeratorTools.cs +++ b/ModeratorTools.cs @@ -9,7 +9,7 @@ namespace BattleBitBaseModules; [RequireModule(typeof(CommandHandler))] -[Module("Basic moderator tools", "1.1.0")] +[Module("Basic moderator tools", "1.1.1")] public class ModeratorTools : BattleBitModule { [ModuleReference] diff --git a/PasswordReservedSlots.cs b/PasswordReservedSlots.cs index 85dd4a7..f25cd99 100644 --- a/PasswordReservedSlots.cs +++ b/PasswordReservedSlots.cs @@ -8,52 +8,64 @@ namespace BattleBitBaseModules; [RequireModule(typeof(CommandHandler))] [Module("Add reserved slots by setting a password", "1.0.0")] -public class PasswordReservedSlots : BattleBitModule { +public class PasswordReservedSlots : BattleBitModule +{ public PasswordReservedSlotsConfiguration Configuration { get; set; } = null!; [ModuleReference] public CommandHandler CommandHandler { get; set; } = null!; - public int getCurrentPlayerCount() { + public int getCurrentPlayerCount() + { return Math.Max(this.Server.CurrentPlayerCount + this.Server.InQueuePlayerCount, this.Server.AllPlayers.Count()); } - public void handleSlots() { + public void handleSlots() + { int currentPlayers = this.getCurrentPlayerCount(); - if (this.Server.MaxPlayerCount - this.Configuration.Slots < currentPlayers) { + if (this.Server.MaxPlayerCount - this.Configuration.Slots > currentPlayers) + { this.Server.SetNewPassword(""); - } else { + } + else + { Server.SetNewPassword(this.Configuration.Password); } } - public async Task slotHandler() { - while (this.IsLoaded && this.Server.IsConnected) { + public async Task slotHandler() + { + while (this.IsLoaded && this.Server.IsConnected) + { this.handleSlots(); - await Task.Delay(1000); + await Task.Delay(this.Configuration.SlotCheckInterval); } } - public override Task OnConnected() { + public override Task OnConnected() + { _ = Task.Run(slotHandler); return Task.CompletedTask; } - public override Task OnPlayerConnected(RunnerPlayer player) { + public override Task OnPlayerConnected(RunnerPlayer player) + { this.handleSlots(); return Task.CompletedTask; } - public override Task OnPlayerDisconnected(RunnerPlayer player) { + public override Task OnPlayerDisconnected(RunnerPlayer player) + { this.handleSlots(); return Task.CompletedTask; } [CommandCallback("setrspass", Description = "Sets the password for reserved slots", ConsoleCommand = true, Permissions = new[] { "PasswordReservedSlots.SetRSPass" })] - public string SetRSPassCommand(Context context, string password) { + public string SetRSPassCommand(Context context, string password) + { this.Configuration.Password = password; this.Configuration.Save(); this.handleSlots(); @@ -62,7 +74,8 @@ public string SetRSPassCommand(Context context, string password) { } [CommandCallback("setrsslots", Description = "Sets the number of reserved slots", ConsoleCommand = true, Permissions = new[] { "PasswordReservedSlots.SetRSSlots" })] - public string SetRSSlotsCommand(Context context, int slots) { + public string SetRSSlotsCommand(Context context, int slots) + { this.Configuration.Slots = slots; this.Configuration.Save(); this.handleSlots(); @@ -71,7 +84,9 @@ public string SetRSSlotsCommand(Context context, int slots) { } } -public class PasswordReservedSlotsConfiguration : ModuleConfiguration { +public class PasswordReservedSlotsConfiguration : ModuleConfiguration +{ public string Password { get; set; } = "changeme"; public int Slots { get; set; } = 0; -} \ No newline at end of file + public int SlotCheckInterval { get; set; } = 3000; +} diff --git a/PermissionsCommands.cs b/PermissionsCommands.cs index 97e4e48..eb17f54 100644 --- a/PermissionsCommands.cs +++ b/PermissionsCommands.cs @@ -8,9 +8,9 @@ namespace PermissionsManager; [RequireModule(typeof(CommandHandler))] -[Module("Provide addperm and removeperm commands for PlayerPermissions", "1.1.0")] -public class PermissionsCommands : BattleBitModule { - +[Module("Provide addperm and removeperm commands for PlayerPermissions", "1.1.1")] +public class PermissionsCommands : BattleBitModule +{ [ModuleReference] public dynamic? PlayerPermissions { get; set; } @@ -26,8 +26,9 @@ public override void OnModulesLoaded() { this.CommandHandler.Register(this); } - [CommandCallback("addperm", Description = "Adds a permission to a player", Permissions = new[] { "Permissions.Add" })] - public string AddPermissionCommand(Context context, RunnerPlayer player, string permission) { + [CommandCallback("addperm", Description = "Adds a permission to a player", Permissions = new[] { "Permissions.Add" }, ConsoleCommand = true)] + public string AddPermissionCommand(Context context, RunnerPlayer player, string permission) + { bool success = false; if (this.PlayerPermissions is not null) { @@ -44,17 +45,21 @@ public string AddPermissionCommand(Context context, RunnerPlayer player, string success = true; } - if (success) { + if (success) + { this.Logger.Info($"Added permission {permission} to {player.Name}"); return $"Added permission {permission} to {player.Name}"; - } else { + } + else + { this.Logger.Error($"Could not add permission {permission} to {player.Name}"); return $"Could not add permission {permission} to {player.Name}"; } } - [CommandCallback("removeperm", Description = "Removes a permission from a player", Permissions = new[] { "Permissions.Remove" })] - public string RemovePermissionCommand(Context context, RunnerPlayer player, string permission) { + [CommandCallback("removeperm", Description = "Removes a permission from a player", Permissions = new[] { "Permissions.Remove" }, ConsoleCommand = true)] + public string RemovePermissionCommand(Context context, RunnerPlayer player, string permission) + { bool success = false; if (this.PlayerPermissions is not null) { @@ -71,19 +76,25 @@ public string RemovePermissionCommand(Context context, RunnerPlayer player, stri success = true; } - if (success) { + if (success) + { this.Logger.Info($"Removed permission {permission} from {player.Name}"); return $"Removed permission {permission} from {player.Name}"; - } else { + } + else + { this.Logger.Error($"Could not remove permission {permission} from {player.Name}"); return $"Could not remove permission {permission} from {player.Name}"; } } - [CommandCallback("clearperms", Description = "Clears all permissions and groups from a player", Permissions = new[] { "Permissions.Clear" })] - public string ClearPermissionCommand(Context context, RunnerPlayer player) { - if (this.GranularPermissions is not null) { - foreach (string group in this.GranularPermissions.GetPlayerGroups(player.SteamID)) { + [CommandCallback("clearperms", Description = "Clears all permissions and groups from a player", Permissions = new[] { "Permissions.Clear" }, ConsoleCommand = true)] + public string ClearPermissionCommand(Context context, RunnerPlayer player) + { + if (this.GranularPermissions is not null) + { + foreach (string group in this.GranularPermissions.GetPlayerGroups(player.SteamID)) + { this.GranularPermissions.RemovePlayerGroup(player.SteamID, group); } @@ -102,8 +113,9 @@ public string ClearPermissionCommand(Context context, RunnerPlayer player) { return $"Cleared permissions from {player.Name}"; } - [CommandCallback("listperms", Description = "Lists player permissions", Permissions = new[] { "Permissions.List" })] - public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, int page = 1) { + [CommandCallback("listperms", Description = "Lists player permissions", Permissions = new[] { "Permissions.List" }, ConsoleCommand = true)] + public string ListPermissionCommand(Context context, RunnerPlayer targetPlayer, int page = 1) + { List permissions = new(); if (this.GranularPermissions is not null) { diff --git a/PlayerRolesFromGranularPermissions.cs b/PlayerRolesFromGranularPermissions.cs index f95d3a5..685af95 100644 --- a/PlayerRolesFromGranularPermissions.cs +++ b/PlayerRolesFromGranularPermissions.cs @@ -7,21 +7,27 @@ namespace Permissions; [RequireModule(typeof(GranularPermissions))] [Module("Provides player roles based on granular permissions", "1.0.0")] -public class PlayerRolesFromGranularPermissions : BattleBitModule { - +public class PlayerRolesFromGranularPermissions : BattleBitModule +{ [ModuleReference] public GranularPermissions GranularPermissions { get; set; } = null!; public PlayerRolesConfiguration Configuration { get; set; } = null!; - public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { - foreach (string permission in Configuration.PermissionRoles.Keys) { - if (!this.GranularPermissions.HasPermission(steamID, permission)) { + public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) + { + foreach (string permission in Configuration.PermissionRoles.Keys) + { + if (!this.GranularPermissions.HasPermission(steamID, permission)) + { continue; } - if (Configuration.AppendRoles) { + if (Configuration.AppendRoles) + { args.Stats.Roles |= Configuration.PermissionRoles[permission]; - } else { + } + else + { args.Stats.Roles = Configuration.PermissionRoles[permission]; } } @@ -30,18 +36,13 @@ public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArgumen } } -public class PlayerRolesConfiguration : ModuleConfiguration { - +public class PlayerRolesConfiguration : ModuleConfiguration +{ public Dictionary PermissionRoles { get; set; } = new() { { "Role.Admin", Roles.Admin }, { "Role.Moderator", Roles.Moderator }, - { "Role.Staff", Roles.Admin | Roles.Moderator }, - { "Role.Vip", Roles.Vip }, - { "Role.Special", Roles.Special }, - { "Role.None", 0 }, - { "Role.Member", Roles.Admin | Roles.Moderator | Roles.Vip }, - { "Role.All", Roles.Admin | Roles.Moderator | Roles.Special | Roles.Vip } + { "Role.Modmin", Roles.Admin | Roles.Moderator } }; public bool AppendRoles { get; set; } = false; diff --git a/Voting.cs b/Voting.cs index 29f4479..7ca46d5 100644 --- a/Voting.cs +++ b/Voting.cs @@ -9,7 +9,7 @@ namespace BattleBitBaseModules; -[Module("Simple chat voting system", "1.1.0")] +[Module("Simple chat voting system", "1.1.1")] [RequireModule(typeof(CommandHandler))] public class Voting : BattleBitModule { private bool activeVote = false; @@ -30,9 +30,11 @@ public override void OnModulesLoaded() { this.CommandHandler.Register(this); } - [CommandCallback("vote", Description = "Votes for an option", Permissions = new[] { "Vote.Vote" })] - public string? StartVoteCommand(Context context, string text, string options) { - if (this.activeVote) { + [CommandCallback("vote", Description = "Votes for an option", Permissions = new[] { "Vote.Vote" }, ConsoleCommand = true)] + public string? StartVoteCommand(Context context, string text, string options) + { + if (this.activeVote) + { return "There is already an active vote."; } @@ -40,7 +42,8 @@ public override void OnModulesLoaded() { this.voteText = text; this.voteOptions = options.Split('|'); - if (this.voteOptions.Length >= 10) { + if (this.voteOptions.Length >= 10) + { this.activeVote = false; return "You can only have up to 9 options."; } @@ -97,6 +100,7 @@ private void voteHandler() { int maxVoteIndex = voteCounts.ToList().IndexOf(maxVotes); this.Server.SayToAllChat($"{this.RichText?.Size(125)}The vote has ended!{Environment.NewLine}{this.RichText?.FromColorName("yellow")}{this.voteOptions[maxVoteIndex]}{this.RichText?.Color()} won with {maxVotes} votes."); + this.Logger.Info($"The vote has ended! {this.voteOptions[maxVoteIndex]} won with {maxVotes} votes."); } public override async Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string msg) { From 261097a9303508ecb3312548c980f494106f8f0a Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sun, 22 Oct 2023 02:17:05 +0200 Subject: [PATCH 20/22] a fix --- CommandHandler.cs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/CommandHandler.cs b/CommandHandler.cs index d499e52..6d1cef9 100644 --- a/CommandHandler.cs +++ b/CommandHandler.cs @@ -11,11 +11,10 @@ namespace Commands; -[Module("Basic in-game chat command handler library", "1.1.1")] +[Module("Basic in-game chat command handler library", "1.2.0")] public class CommandHandler : BattleBitModule { public static CommandConfiguration CommandConfiguration { get; set; } = null!; public CommandSettings CommandSettings { get; set; } = null!; - public CommandSettings CommandSettings { get; set; } = null!; private Dictionary commandCallbacks = new(); @@ -92,8 +91,6 @@ public void Register(BattleBitModule module) { this.Logger.Error($"Command callback {command} in module {module.GetType().Name} conflicts with subcommand {subcommand}."); continue; - this.Logger.Error($"Command callback {command} in module {module.GetType().Name} conflicts with subcommand {subcommand}."); - continue; } // Prevent subcommands of existing commands (!perm add and !perm remove do not allow !perm) @@ -113,7 +110,6 @@ public void Register(BattleBitModule module) { } this.CommandSettings.Save(); - this.CommandSettings.Save(); } public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string message) { @@ -121,7 +117,6 @@ public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel return Task.FromResult(true); } - Task.Run(() => this.HandleCommand(new ChatSource(player), message)); Task.Run(() => this.HandleCommand(new ChatSource(player), message)); return Task.FromResult(false); @@ -133,7 +128,6 @@ public override void OnConsoleCommand(string command) { } Task.Run(() => this.HandleCommand(new ConsoleSource(), command)); - Task.Run(() => this.HandleCommand(new ConsoleSource(), command)); } public bool IsCommand(string message) { @@ -210,9 +204,6 @@ public void HandleCommand(Source source, string message) { ChatSource? chatSource = source as ChatSource; Context errorContext = new Context(source, message, command, Array.Empty(), Array.Empty(), null, this, null); - ChatSource? chatSource = source as ChatSource; - Context errorContext = new Context(source, message, command, Array.Empty(), Array.Empty(), null, this, null); - int subCommandSkip; for (subCommandSkip = 1; subCommandSkip < fullCommand.Length && !this.commandCallbacks.ContainsKey(command); subCommandSkip++) { command += $" {fullCommand[subCommandSkip]}"; @@ -523,12 +514,10 @@ public virtual void Reply(string message) { } public abstract class Source { - public abstract void Reply(Context context, string message); } public class ChatSource : Source { - public ChatSource(RunnerPlayer invoker) { this.Invoker = invoker; } @@ -555,7 +544,6 @@ public override void Reply(Context context, string message) { } public class ConsoleSource : Source { - public override void Reply(Context context, string message) { context.CommandHandler.Logger.Info(message); } From 2750c09c83baa40348463572eca1449184ac02e7 Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sun, 22 Oct 2023 02:45:06 +0200 Subject: [PATCH 21/22] update from website --- MOTD.cs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/MOTD.cs b/MOTD.cs index fcb99c1..b53052d 100644 --- a/MOTD.cs +++ b/MOTD.cs @@ -1,8 +1,6 @@ using BattleBitAPI.Common; -using BattleBitAPI.Features; using BBRAPIModules; using Commands; -using Permissions; using System; using System.Collections.Generic; using System.Linq; @@ -11,7 +9,7 @@ namespace BattleBitBaseModules; [RequireModule(typeof(CommandHandler))] -[Module("Show a message of the day to players who join the server", "1.1.1")] +[Module("Show a message of the day to players who join the server", "1.2.0")] public class MOTD : BattleBitModule { public MOTDConfiguration Configuration { get; set; } = null!; @@ -23,7 +21,7 @@ public class MOTD : BattleBitModule public dynamic? PlaceholderLib { get; set; } [ModuleReference] - public GranularPermissions GranularPermissions { get; set; } + public dynamic? GranularPermissions { get; set; } private List greetedPlayers = new(); @@ -48,8 +46,10 @@ public override Task OnGameStateChanged(GameState oldState, GameState newState) return Task.CompletedTask; } - public override Task OnPlayerConnected(RunnerPlayer player) { - if (this.greetedPlayers.Contains(player.SteamID)) { + public override Task OnPlayerConnected(RunnerPlayer player) + { + if (this.greetedPlayers.Contains(player.SteamID)) + { return Task.CompletedTask; } @@ -80,7 +80,7 @@ public string ShowMOTD(Context context) string message; if (this.PlaceholderLib is not null) { - message = new PlaceholderLib(this.Configuration.MOTD) + message = this.PlaceholderLib.Create(this.Configuration.MOTD) .AddParam("servername", this.Server.ServerName) .AddParam("gamemode", this.Server.Gamemode) .AddParam("map", this.Server.Map) @@ -90,7 +90,7 @@ public string ShowMOTD(Context context) .AddParam("inqueueplayers", this.Server.InQueuePlayerCount) .AddParam("maxplayers", this.Server.MaxPlayerCount) .AddParam("name", chatSource?.Invoker.Name ?? context.Source.GetType().Name) - .AddParam("ping", chatSource?.Invoker.PingMs ?? 0).Run(); + .AddParam("ping", chatSource?.Invoker.PingMs ?? 0).Build(); } else { @@ -101,6 +101,7 @@ public string ShowMOTD(Context context) } } -public class MOTDConfiguration : ModuleConfiguration { +public class MOTDConfiguration : ModuleConfiguration +{ public string MOTD { get; set; } = "Welcome!"; -} \ No newline at end of file +} From 183058520248b248a6ebc693ab1a744f4a30436b Mon Sep 17 00:00:00 2001 From: Bluscream Date: Sun, 22 Oct 2023 06:53:55 +0200 Subject: [PATCH 22/22] #BasicProgression add public readonly Cache add GetPlayerStats(ulong steamid) add GetPlayerStats(RunnerPlayer player) add private RemovePlayerStats(ulong steamID) add OnStatsRecieved event add BasicProgressionConfiguration.RemoveEntriesFromCacheDelay --- BasicProgression.cs | 39 +++++++++++ BattleBitBaseModules.csproj | 4 ++ ChatOverwrite.cs | 135 ------------------------------------ LoadingScreenText.cs | 77 -------------------- 4 files changed, 43 insertions(+), 212 deletions(-) delete mode 100644 ChatOverwrite.cs delete mode 100644 LoadingScreenText.cs diff --git a/BasicProgression.cs b/BasicProgression.cs index 2266f9e..04403cf 100644 --- a/BasicProgression.cs +++ b/BasicProgression.cs @@ -1,6 +1,7 @@ using BattleBitAPI.Common; using BBRAPIModules; using System; +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using static BattleBitAPI.Common.PlayerStats; @@ -10,6 +11,11 @@ namespace BattleBitBaseModules; [Module("Provide basic persistent progression for players", "1.1.1")] public class BasicProgression : BattleBitModule { public BasicProgressionConfiguration Configuration { get; set; } = null!; + private IReadOnlyDictionary Cache { get { return _Cache; } } + private Dictionary _Cache { get; set; } = new(); + + public delegate void StatsRecievedHandler(ulong steamID, PlayerStats stats); + public event StatsRecievedHandler? OnStatsRecieved; private string dataDir => this.Configuration.PerServer ? Path.Combine(this.Configuration.DataDirectory, $"{this.Server.GameIP}:{this.Server.GamePort}") : this.Configuration.DataDirectory; @@ -21,9 +27,37 @@ public override Task OnConnected() { return Task.CompletedTask; } + + public async Task GetPlayerStats(RunnerPlayer player) => await GetPlayerStats(player.SteamID); + public async Task GetPlayerStats(ulong steamId) { + if (this.Cache.TryGetValue(steamId, out PlayerStats? stats)) { + return stats; + } + string playerFileName = getPlayerFileName(steamId); + for (int i = 0; i < 5; i++) { + try { + stats = new PlayerStats(File.ReadAllBytes(playerFileName)); + _Cache[steamId] = stats; + return stats; + } catch (Exception ex) { + this.Logger.Error($"Tried {i} times to read from file {playerFileName} but failed:{ex}"); + } + await Task.Delay(250); + } + + return this.Configuration.InitialStats?.ToPlayerStats() ?? new PlayerStats(); + } + + private void SetPlayerStats(ulong steamID, PlayerStats stats) { + _Cache[steamID] = stats; + OnStatsRecieved?.Invoke(steamID, stats); + } + private void RemovePlayerStats(ulong steamID) => _Cache.Remove(steamID); + public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { if (this.Configuration.ApplyInitialStatsOnEveryJoin) { args.Stats = this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats; + SetPlayerStats(steamID, args.Stats); return; } @@ -31,6 +65,7 @@ public override async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningA for (int i = 0; i < 5; i++) { try { args.Stats = File.Exists(playerFileName) ? new PlayerStats(File.ReadAllBytes(playerFileName)) : (this.Configuration.InitialStats?.ToPlayerStats() ?? args.Stats); + SetPlayerStats(steamID, args.Stats); return; } catch (Exception ex) { this.Logger.Error($"Tried {i} times to read from file {playerFileName} but failed:{ex}"); @@ -44,6 +79,8 @@ public override async Task OnSavePlayerStats(ulong steamID, PlayerStats stats) { for (int i = 0; i < 5; i++) { try { File.WriteAllBytes(getPlayerFileName(steamID), stats.SerializeToByteArray()); + await Task.Delay(Configuration.RemoveEntriesFromCacheDelay); + RemovePlayerStats(steamID); return; } catch (Exception ex) { this.Logger.Error($"Tried {i} times to write to file {getPlayerFileName(steamID)} but failed:{ex}"); @@ -65,6 +102,8 @@ public class BasicProgressionConfiguration : ModuleConfiguration { public bool ApplyInitialStatsOnEveryJoin { get; set; } = false; + public TimeSpan RemoveEntriesFromCacheDelay { get; set; } = TimeSpan.FromMinutes(1); + public BasicPlayerStats? InitialStats { get; set; } = new BasicPlayerStats() { Achievements = new byte[0], IsBanned = false, diff --git a/BattleBitBaseModules.csproj b/BattleBitBaseModules.csproj index 50a9d10..d1bee59 100644 --- a/BattleBitBaseModules.csproj +++ b/BattleBitBaseModules.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/ChatOverwrite.cs b/ChatOverwrite.cs deleted file mode 100644 index ed7b072..0000000 --- a/ChatOverwrite.cs +++ /dev/null @@ -1,135 +0,0 @@ -using BattleBitAPI.Common; -using BBRAPIModules; -using Permissions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ChatOverwrite; - -[RequireModule(typeof(GranularPermissions))] -[RequireModule(typeof(SteamApi))] -[Module("Overwrite chat messages", "1.0.0")] -public class ChatOverwrite : BattleBitModule { - - [ModuleReference] - public SteamApi? SteamApi { get; set; } = null!; - - public ChatOverwriteConfiguration Configuration { get; set; } = null!; - - [ModuleReference] - public dynamic? CommandHandler { get; set; } - - [ModuleReference] - public GranularPermissions GranularPermissions { get; set; } = null!; - - public override Task OnPlayerTypedMessage(RunnerPlayer player, ChatChannel channel, string msg) { - if (this.CommandHandler is not null && this.CommandHandler.IsCommand(msg)) { - this.Logger.Debug($"Ignoring message {msg} from {player.Name} because it is a command"); - return Task.FromResult(true); - } - - if (this.GranularPermissions.HasPermission(player.SteamID, "ChatOverwrite.Bypass")) { - this.Logger.Debug($"Ignoring message {msg} from {player.Name} because they have the ChatOverwrite.Bypass permission"); - return Task.FromResult(true); - } - - string? permission = this.Configuration.Overwrites.Keys.FirstOrDefault(k => this.GranularPermissions.HasPermission(player.SteamID, k)); - - if (String.IsNullOrEmpty(permission)) { - this.Logger.Debug($"Ignoring message {msg} from {player.Name} because they do not have any ChatOverwrite permissions"); - return Task.FromResult(true); - } - - OverwriteMessage overwriteMessage = this.Configuration.Overwrites[permission]; - - this.Logger.Debug($"Overwriting message {msg} from {player.Name} with permission {permission}"); - - string gradientName = FormatTextWithGradient(player.Name, overwriteMessage.GradientColors ?? Array.Empty()); - - string teamName = player.Team == Team.TeamA ? "US" : "RU"; - char? squadLetter = player.InSquad ? player.SquadName.ToString()[0] : null; - - foreach (RunnerPlayer chatTarget in this.Server.AllPlayers) { - if (channel == ChatChannel.SquadChat && (chatTarget.Team != player.Team || !chatTarget.InSquad || !player.InSquad || chatTarget.SquadName != player.SquadName)) { - continue; - } - - if (channel == ChatChannel.TeamChat && chatTarget.Team != player.Team) { - continue; - } - - string nameColor = player.Team == chatTarget.Team && player.InSquad && chatTarget.InSquad && player.SquadName == chatTarget.SquadName ? "green" : (player.Team == chatTarget.Team ? "blue" : "red"); - string teamAndSquadIndicator = teamName; - if (squadLetter != null) { - teamAndSquadIndicator += $"-{squadLetter}"; - } - teamAndSquadIndicator = $"[{teamAndSquadIndicator}]"; - - string textColor = channel == ChatChannel.TeamChat ? "blue" : (channel == ChatChannel.SquadChat ? "green" : "white"); - - var playerName = GetPlayerName(player); - - var now = string.IsNullOrWhiteSpace(Configuration.TimeStampFormat) ? "" : new DateTimeWithZone(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById(Configuration.TimeZone)).LocalTime.ToString(Configuration.TimeStampFormat); - - chatTarget.SayToChat(string.Format(overwriteMessage.Text, nameColor, playerName, teamAndSquadIndicator, textColor, msg, gradientName, now)); - } - - return Task.FromResult(false); - } - - public string GetPlayerName(RunnerPlayer player) { - if (SteamApi is not null) { - var steam = player.Get()?.Result; - if (steam?.Summary is not null) { - if (!string.IsNullOrWhiteSpace(steam.Summary.RealName)) return steam.Summary.RealName; - else if (!string.IsNullOrWhiteSpace(steam.Summary.PersonaName)) return steam.Summary.PersonaName; - } - } - return string.IsNullOrWhiteSpace(player.Name) ? player.SteamID.ToString() : player.Name; - } - - private static string FormatTextWithGradient(string text, string[] gradientColors) { - if (string.IsNullOrEmpty(text) || gradientColors.Length == 0) { - return text; - } - - int segmentCount = gradientColors.Length; - int segmentLength = text.Length / segmentCount; - int remainder = text.Length % segmentCount; - - StringBuilder formattedName = new StringBuilder(); - int currentIndex = 0; - - for (int i = 0; i < segmentCount; i++) { - int currentSegmentLength = segmentLength + (i < remainder ? 1 : 0); - string currentColor = gradientColors[i]; - string segmentText = text.Substring(currentIndex, currentSegmentLength); - - formattedName.Append($"{segmentText}"); - currentIndex += currentSegmentLength; - } - - return formattedName.ToString(); - } -} - -public class ChatOverwriteConfiguration : ModuleConfiguration { - public string TimeStampFormat { get; set; } = "HH:mm:ss"; - - [Obsolete] - public string TimeZone { get; set; } = System.TimeZone.CurrentTimeZone.StandardName; - - public Dictionary Overwrites { get; set; } = new() - { - { "ChatOverwrite.Normal", new("[6] {1}{2} : {4}") }, - { "ChatOverwrite.Rainbow", new("{5}{2} : {4}", new string[] { "red", "orange", "yellow", "green", "blue", "purple" }) }, - { "ChatOverwrite.Large", new("{1}{2} : {4}") }, - { "ChatOverwrite.Sus", new("{1}{2} : I am an idiot and cheat in online games. Please go to my Steam profile and report me!") }, - { "ChatOverwrite.Admin", new("[6] {1}{2}[Server Admin] : {4}") } - }; -} - -public record OverwriteMessage(string Text, string[]? GradientColors = null); \ No newline at end of file diff --git a/LoadingScreenText.cs b/LoadingScreenText.cs deleted file mode 100644 index c7e7f36..0000000 --- a/LoadingScreenText.cs +++ /dev/null @@ -1,77 +0,0 @@ -using BattleBitAPI.Common; -using BBRAPIModules; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace BattleBitBaseModules; - -[RequireModule(typeof(Bluscream.BluscreamLib))] -[RequireModule(typeof(BattleBitBaseModules.RichText))] -[Module("Configure the loading screen text of your server", "1.0.0")] -public class LoadingScreenText : BattleBitModule { - - [ModuleReference] - public LoadingScreenTextConfiguration Config { get; set; } = null!; - - public override Task OnConnected() { - UpdateLoadingScreenText(this.Config.ConnectLoadingScreenText); return Task.CompletedTask; - } - - public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) { - UpdateLoadingScreenText(this.Config.ConnectLoadingScreenText); return Task.CompletedTask; - } - - public override Task OnRoundEnded() { - UpdateLoadingScreenText(this.Config.MapChangeLoadingScreenText); return Task.CompletedTask; - } - - //public override Task OnSessionChanged(long oldSessionID, long newSessionID) { - // UpdateLoadingScreenText(this.Config.MapChangeLoadingScreenText); return Task.CompletedTask; - //} - //public override Task OnGameStateChanged(GameState oldState, GameState newState) { - // switch (newState) { - // case GameState.EndingGame: - // UpdateLoadingScreenText(this.Config.MapChangeLoadingScreenText); - // break; - // default: - // UpdateLoadingScreenText(this.Config.ConnectLoadingScreenText); - // break; - // } - // return Task.CompletedTask; - //} - - public string FormatText(string input) => input - .Replace("{server}", this.Server.ServerName) - .Replace("{gamemode}", this.Server.GetCurrentGameMode().DisplayName) - .Replace("{map}", this.Server.GetCurrentMap().DisplayName) - .Replace("{maptime}", this.Server.DayNight.ToString().ToTitleCase()) - .Replace("{players}", this.Server.AllPlayers.Count().ToString()) - .Replace("{slots}", this.Server.MaxPlayerCount.ToString()); - - public void UpdateLoadingScreenText(string template) { - var newText = FormatText(template); - foreach (var replacement in Config.randomReplacements) { - newText = newText.Replace($"{{random.{replacement.Key}}}", FormatText(replacement.Value[Random.Shared.Next(replacement.Value.Length)])); - } - this.Server.LoadingScreenText = newText; - this.Logger.Warn($"Changed Loading Screen Text:\n{this.Server.LoadingScreenText}"); - } - - public class LoadingScreenTextConfiguration : ModuleConfiguration { - - public Dictionary randomReplacements = new Dictionary() { - { "welcome", new string[] { "Enjoy your stay!", "Have a good one!", "Get Ready for battle!" } }, - }; - - public string ConnectLoadingScreenText { get; set; } = -@$"{Colors.SkyBlue}Welcome to {Colors.None}{{server}}{Colors.SkyBlue}! -We are currently playing {Colors.None}{{gamemode}}{Colors.SkyBlue} on {Colors.None}{{map}}{Colors.SkyBlue} at {Colors.None}{{maptime}}{Colors.SkyBlue} with {Colors.None}{{players}}{Colors.SkyBlue}/{Colors.None}{{slots}}{Colors.SkyBlue} players! -{{random.welcome}}"; - - public string MapChangeLoadingScreenText { get; set; } = -@$"{Colors.SkyBlue}Welcome to {Colors.None}{{server}}{Colors.SkyBlue}! -{{random.welcome}}"; - } -} \ No newline at end of file