From 7ad6c141fabd302cc3debc8218248ad2c97adb0a Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Thu, 4 Apr 2024 21:22:10 -0400 Subject: [PATCH 01/86] Update README.md Version 1.0.3 changes --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 298253d..dff73af 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,14 @@ Server Only - `css_mapgroup ` - Sets the map group and updates the map list. Client Only +- `!map ` - Changes the map to the map specified. + + > The map id is optional and only required if not already specified in an existing map group. + +- `!mode (css_mode)` - Changes the game mode to the mode specified. + + > Only the mode name is required. For example, for mg_surf you would do !mode surf. + - `!modes (css_modes)` - Displays an admin menu with game mode options. ![Screenshot 2024-03-21 161458](https://github.com/nickj609/GameModeManager/assets/32173425/db33fe48-21f3-455c-9987-5406fca99c4f) From bf4c54f8e25cc9e7d7125807cd9b5a2c6651c315 Mon Sep 17 00:00:00 2001 From: Nick M Date: Fri, 5 Apr 2024 22:41:36 -0400 Subject: [PATCH 02/86] UPDATE: Separated event logic --- Classes.cs | 103 ++++++++++++++++++++++----------------------- Events.cs | 34 +++++++++++++++ Functions.cs | 21 --------- GameModeManager.cs | 2 +- 4 files changed, 85 insertions(+), 75 deletions(-) create mode 100644 Events.cs diff --git a/Classes.cs b/Classes.cs index f349959..3a8a700 100644 --- a/Classes.cs +++ b/Classes.cs @@ -7,73 +7,70 @@ // Declare namespace namespace GameModeManager { - public partial class Plugin : BasePlugin + public class Map : IEquatable { - public class Map : IEquatable - { - public string Name { get; set; } - public string WorkshopId { get; set; } - - public Map(string name) - { - Name = name; - WorkshopId = ""; - } - - public Map(string name, string workshopId) - { - Name = name; - WorkshopId = workshopId; - } + public string Name { get; set; } + public string WorkshopId { get; set; } - public bool Equals(Map? other) - { - if (other == null) return false; // Handle null + public Map(string name) + { + Name = name; + WorkshopId = ""; + } + + public Map(string name, string workshopId) + { + Name = name; + WorkshopId = workshopId; + } - // Implement your equality logic, e.g.; - return Name == other.Name && WorkshopId == other.WorkshopId; - } + public bool Equals(Map? other) + { + if (other == null) return false; // Handle null - public void Clear() - { - Name = ""; - WorkshopId = ""; - } + // Implement your equality logic, e.g.; + return Name == other.Name && WorkshopId == other.WorkshopId; } - public class MapGroup : IEquatable + public void Clear() { - public string Name { get; set; } - public List Maps { get; set; } + Name = ""; + WorkshopId = ""; + } + } - public MapGroup(string name) - { - Name = name; - Maps = new List(); - } + public class MapGroup : IEquatable + { + public string Name { get; set; } + public List Maps { get; set; } - public MapGroup(string name, List maps) - { - Name = name; - Maps = maps; - } + public MapGroup(string name) + { + Name = name; + Maps = new List(); + } + + public MapGroup(string name, List maps) + { + Name = name; + Maps = maps; + } - public bool Equals(MapGroup? other) + public bool Equals(MapGroup? other) + { + if (other == null) { - if (other == null) - { - return false; // Handle null - } - else - { - return Name == other.Name && Maps.SequenceEqual(other.Maps); - } + return false; // Handle null } - public void Clear() + else { - Name = ""; - Maps = new List(); + return Name == other.Name && Maps.SequenceEqual(other.Maps); } } + public void Clear() + { + Name = ""; + Maps = new List(); + } } } \ No newline at end of file diff --git a/Events.cs b/Events.cs new file mode 100644 index 0000000..db7932e --- /dev/null +++ b/Events.cs @@ -0,0 +1,34 @@ +// Included libraries +using CounterStrikeSharp.API; +using System.Collections.Generic; +using CounterStrikeSharp.API.Core; +using Microsoft.Extensions.Logging; +using CounterStrikeSharp.API.Core.Translations; + +// Declare namespace +namespace GameModeManager +{ + public partial class Plugin : BasePlugin + { + // Construct EventGameEnd Handler to automatically change map + private HookResult EventGameEnd(EventCsIntermission @event, GameEventInfo info) + { + Logger.LogInformation("Game has ended. Picking random map from current map group..."); + Server.PrintToChatAll(Localizer["plugin.prefix"] + " Game has ended. Changing map..."); + + if(currentMapGroup == null) + { + currentMapGroup = defaultMapGroup; + } + // Get a random map + Random rnd = new Random(); + int randomIndex = rnd.Next(0, currentMapGroup.Maps.Count); + Map randomMap = currentMapGroup.Maps[randomIndex]; + + // Use the random map ID in the server command + ChangeMap(randomMap); + + return HookResult.Continue; + } + } +} diff --git a/Functions.cs b/Functions.cs index 8e66e0f..3e29416 100644 --- a/Functions.cs +++ b/Functions.cs @@ -288,26 +288,5 @@ private void ChangeMap(Map nextMap) currentMap = nextMap; return; } - - // Construct EventGameEnd Handler to automatically change map - private HookResult EventGameEnd(EventCsIntermission @event, GameEventInfo info) - { - Logger.LogInformation("Game has ended. Picking random map from current map group..."); - Server.PrintToChatAll(Localizer["plugin.prefix"] + " Game has ended. Changing map..."); - - if(currentMapGroup == null) - { - currentMapGroup = defaultMapGroup; - } - // Get a random map - Random rnd = new Random(); - int randomIndex = rnd.Next(0, currentMapGroup.Maps.Count); - Map randomMap = currentMapGroup.Maps[randomIndex]; - - // Use the random map ID in the server command - ChangeMap(randomMap); - - return HookResult.Continue; - } } } \ No newline at end of file diff --git a/GameModeManager.cs b/GameModeManager.cs index b6ece83..39b5cea 100644 --- a/GameModeManager.cs +++ b/GameModeManager.cs @@ -13,7 +13,7 @@ public partial class Plugin : BasePlugin { // Define plugin details public override string ModuleName => "GameModeManager"; - public override string ModuleVersion => "1.0.1"; + public override string ModuleVersion => "1.0.3"; public override string ModuleAuthor => "Striker-Nick"; public override string ModuleDescription => "A simple plugin/module that dynamically updates any maplist.txt file based on the current mapgroup."; From 9306f0b291d544ea9172b7d6944e6c57296aea06 Mon Sep 17 00:00:00 2001 From: Nick M Date: Fri, 5 Apr 2024 23:19:47 -0400 Subject: [PATCH 03/86] Structural changes --- Classes.cs | 8 ++------ Commands.cs | 1 - Config.cs | 2 -- Events.cs | 1 - Functions.cs | 12 +----------- GameModeManager.cs | 4 ++-- 6 files changed, 5 insertions(+), 23 deletions(-) diff --git a/Classes.cs b/Classes.cs index 3a8a700..9ee5a3a 100644 --- a/Classes.cs +++ b/Classes.cs @@ -1,12 +1,7 @@ -// Included libraries -using CounterStrikeSharp.API; -using System.Collections.Generic; -using CounterStrikeSharp.API.Core; -using Microsoft.Extensions.Logging; - // Declare namespace namespace GameModeManager { + // Define map class public class Map : IEquatable { public string Name { get; set; } @@ -39,6 +34,7 @@ public void Clear() } } + // Define map group class public class MapGroup : IEquatable { public string Name { get; set; } diff --git a/Commands.cs b/Commands.cs index f8a9d40..5abe72b 100644 --- a/Commands.cs +++ b/Commands.cs @@ -1,5 +1,4 @@ // Included libraries -using System.Globalization; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; diff --git a/Config.cs b/Config.cs index 89851d2..2819311 100644 --- a/Config.cs +++ b/Config.cs @@ -1,9 +1,7 @@ // Included libraries -using System.Text.Json; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; using System.Text.Json.Serialization; -using CounterStrikeSharp.API.Core.Attributes; // Declare namespace namespace GameModeManager diff --git a/Events.cs b/Events.cs index db7932e..8e536c3 100644 --- a/Events.cs +++ b/Events.cs @@ -1,6 +1,5 @@ // Included libraries using CounterStrikeSharp.API; -using System.Collections.Generic; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; using CounterStrikeSharp.API.Core.Translations; diff --git a/Functions.cs b/Functions.cs index 3e29416..d61771a 100644 --- a/Functions.cs +++ b/Functions.cs @@ -1,12 +1,8 @@ // Included libraries -using System; -using System.IO; using System.Text; using Gameloop.Vdf; using Gameloop.Vdf.Linq; -using System.Globalization; using CounterStrikeSharp.API; -using System.Collections.Generic; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; using CounterStrikeSharp.API.Modules.Menu; @@ -34,8 +30,8 @@ public partial class Plugin : BasePlugin // Define current map group, current map, and map group list public static List mapGroups = new List(); public static MapGroup currentMapGroup = defaultMapGroup; - public static Map? currentMap; public static List allMaps = new List(); + public static Map? currentMap; // Define function to parse map groups private void ParseMapGroups() @@ -157,7 +153,6 @@ private void UpdateMapList(MapGroup newMapGroup) { Logger.LogError("Unable to update maplist.txt."); Logger.LogError($"{ex.Message}"); - throw; } // Reload RTV Plugin @@ -174,7 +169,6 @@ private void UpdateMapList(MapGroup newMapGroup) { Logger.LogError($"{ex.Message}"); } - return; } // Define menus private static CenterHtmlMenu mapMenu = new CenterHtmlMenu("Map List"); @@ -205,7 +199,6 @@ private void UpdateMapMenu(MapGroup newMapGroup) MenuManager.CloseActiveMenu(player); }); } - return; } // Create mode menu private void SetupModeMenu() @@ -230,7 +223,6 @@ private void SetupModeMenu() MenuManager.CloseActiveMenu(player); }); } - return; } else { @@ -262,7 +254,6 @@ private void SetupModeMenu() }); } } - return; } } // Define function to change map @@ -286,7 +277,6 @@ private void ChangeMap(Map nextMap) // Set current map currentMap = nextMap; - return; } } } \ No newline at end of file diff --git a/GameModeManager.cs b/GameModeManager.cs index 39b5cea..3a93120 100644 --- a/GameModeManager.cs +++ b/GameModeManager.cs @@ -2,8 +2,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; -using CounterStrikeSharp.API.Modules.Cvars; -using static CounterStrikeSharp.API.Core.Listeners; // Declare namespace namespace GameModeManager @@ -35,6 +33,7 @@ public override void Load(bool hotReload) { Logger.LogError($"{ex.Message}"); } + // Setup mode admin menu try { @@ -44,6 +43,7 @@ public override void Load(bool hotReload) { Logger.LogError($"{ex.Message}"); } + // Enable default map cycle if(!Config.RTV.Enabled) { From a3c0c2f82da6955d0d8a523339e944f26eff4768 Mon Sep 17 00:00:00 2001 From: Nick M Date: Fri, 5 Apr 2024 23:30:04 -0400 Subject: [PATCH 04/86] Update .gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c5d3ff9..cbbd0b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ bin/ -obj/ -*.md \ No newline at end of file +obj/ \ No newline at end of file From 3cb01555bd34c7befd9720b200804b602e62937c Mon Sep 17 00:00:00 2001 From: Nick M Date: Sat, 6 Apr 2024 00:09:58 -0400 Subject: [PATCH 05/86] ADDED: Credits for GameLoop.Vdf --- Functions.cs | 7 +++++-- README.md | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Functions.cs b/Functions.cs index d61771a..8688ae8 100644 --- a/Functions.cs +++ b/Functions.cs @@ -1,7 +1,5 @@ // Included libraries using System.Text; -using Gameloop.Vdf; -using Gameloop.Vdf.Linq; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; @@ -9,6 +7,11 @@ using CounterStrikeSharp.API.Modules.Timers; using CounterStrikeSharp.API.Core.Translations; +// Copyright (c) 2016 Shravan Rajinikanth +// https://github.com/shravan2x/Gameloop.Vdf/blob/master/LICENSE +using Gameloop.Vdf; +using Gameloop.Vdf.Linq; + // Declare namespace namespace GameModeManager { diff --git a/README.md b/README.md index dff73af..3e39dc8 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ GameModeManager streamlines your Counter-Strike 2 server administration with the - **Default Map Cycles:** Automatically changes the map to a random map within the current map group. - **RTV Compatibility:** Works seamlessly with your chosen RTV plugin, ensuring smooth rock-the-vote functionality. +## Credits +This plugin utilizes the [GameLoop.Vdf library](https://github.com/shravan2x/Gameloop.Vdf/) (licensed under the [MIT License](https://github.com/shravan2x/Gameloop.Vdf/blob/master/LICENSE)). + ## Requirements - Counter-Strike 2 - Metamod:Source v1282+ From 28ac3145dbe607f4bc02d449ea1118c4f8cd6b60 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 6 Apr 2024 00:17:26 -0400 Subject: [PATCH 06/86] ADDED: Credits Added reason for utilizing plugin and sourced VDF. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3e39dc8..e826192 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ GameModeManager streamlines your Counter-Strike 2 server administration with the - **RTV Compatibility:** Works seamlessly with your chosen RTV plugin, ensuring smooth rock-the-vote functionality. ## Credits -This plugin utilizes the [GameLoop.Vdf library](https://github.com/shravan2x/Gameloop.Vdf/) (licensed under the [MIT License](https://github.com/shravan2x/Gameloop.Vdf/blob/master/LICENSE)). +This plugin utilizes the [GameLoop.Vdf library](https://github.com/shravan2x/Gameloop.Vdf/) (licensed under the [MIT License](https://github.com/shravan2x/Gameloop.Vdf/blob/master/LICENSE)) for parsing the `gamemodes_server.txt` file, which is in [Valve Data Format](https://developer.valvesoftware.com/wiki/VDF). ## Requirements - Counter-Strike 2 @@ -18,7 +18,7 @@ This plugin utilizes the [GameLoop.Vdf library](https://github.com/shravan2x/Gam - Counter Strike Sharp v.197+ > [!NOTE] -> If you are using the [CS2 Modded Dedicated Server by Kus](https://github.com/kus/cs2-modded-server) you should remove the `Ultimate Map Chooser` plugin until the pull request is approved/finalized. +> If you are using the [CS2 Modded Dedicated Server by Kus](https://github.com/kus/cs2-modded-server) you should remove the [Ultimate Map Chooser](https://github.com/kus/cs2-modded-server/tree/master/game/csgo/addons/counterstrikesharp/plugins/CS2-Ultimate-Mapchooser) plugin until the pull request is approved/finalized. ## Commands From 4f4581fe201838cf4f4c1cabb1189c6e4c27c56a Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 6 Apr 2024 00:28:32 -0400 Subject: [PATCH 07/86] ADDED: Links to requirements --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e826192..0c17282 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ GameModeManager streamlines your Counter-Strike 2 server administration with the This plugin utilizes the [GameLoop.Vdf library](https://github.com/shravan2x/Gameloop.Vdf/) (licensed under the [MIT License](https://github.com/shravan2x/Gameloop.Vdf/blob/master/LICENSE)) for parsing the `gamemodes_server.txt` file, which is in [Valve Data Format](https://developer.valvesoftware.com/wiki/VDF). ## Requirements -- Counter-Strike 2 -- Metamod:Source v1282+ -- Counter Strike Sharp v.197+ +- [Counter-Strike 2](https://www.counter-strike.net/cs2) +- [Metamod:Source](https://github.com/alliedmodders/metamod-source/) (v1282+) +- [Counter Strike Sharp](https://github.com/roflmuffin/CounterStrikeSharp) (v.197+) > [!NOTE] > If you are using the [CS2 Modded Dedicated Server by Kus](https://github.com/kus/cs2-modded-server) you should remove the [Ultimate Map Chooser](https://github.com/kus/cs2-modded-server/tree/master/game/csgo/addons/counterstrikesharp/plugins/CS2-Ultimate-Mapchooser) plugin until the pull request is approved/finalized. From a57ca97d1670bed40d4bb548c318c474763003e7 Mon Sep 17 00:00:00 2001 From: Nick M Date: Sat, 6 Apr 2024 00:35:13 -0400 Subject: [PATCH 08/86] Update Functions.cs --- Functions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Functions.cs b/Functions.cs index 8688ae8..3c194be 100644 --- a/Functions.cs +++ b/Functions.cs @@ -42,7 +42,7 @@ private void ParseMapGroups() Logger.LogInformation($"Parsing map group file {Config.MapGroup.File}."); try { - // Deserialize gamemodes_server.txt (VDF) to VProperty + // Deserialize gamemodes_server.txt (VDF) to VProperty with GameLoop.Vdf VProperty vdfObject = VdfConvert.Deserialize(File.ReadAllText(Config.MapGroup.File, Encoding.UTF8)); if (vdfObject == null) From f9e6d09979e8784be77399ecbbf6d7e4ee97c9de Mon Sep 17 00:00:00 2001 From: Nick M Date: Sat, 6 Apr 2024 11:10:35 -0400 Subject: [PATCH 09/86] Reduced verbosity of logging --- Commands.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Commands.cs b/Commands.cs index 5abe72b..15a3353 100644 --- a/Commands.cs +++ b/Commands.cs @@ -22,18 +22,16 @@ public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) { if (player == null) { - Logger.LogInformation($"Map group command detected!"); - // Get map group MapGroup? newMapGroup = mapGroups.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); if (newMapGroup == null || newMapGroup.Name == null || newMapGroup.Maps == null) { - Logger.LogInformation("New mapgroup could not be found. Setting default map group."); + Logger.LogWarning("New map group could not be found. Setting default map group."); newMapGroup = defaultMapGroup; } - - Logger.LogInformation($"New MapGroup is {newMapGroup.Name}."); + Logger.LogInformation($"Current map group is {currentMapGroup.Name}."); + Logger.LogInformation($"New map group is {newMapGroup.Name}."); // Update map list and map menu try From 9b4126714b7d07985a751b89f7afd9ef4e0dd646 Mon Sep 17 00:00:00 2001 From: Nick M Date: Sat, 6 Apr 2024 11:11:00 -0400 Subject: [PATCH 10/86] Reduced verbosity of logging --- Functions.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Functions.cs b/Functions.cs index 3c194be..2f3afd3 100644 --- a/Functions.cs +++ b/Functions.cs @@ -39,7 +39,6 @@ public partial class Plugin : BasePlugin // Define function to parse map groups private void ParseMapGroups() { - Logger.LogInformation($"Parsing map group file {Config.MapGroup.File}."); try { // Deserialize gamemodes_server.txt (VDF) to VProperty with GameLoop.Vdf @@ -48,6 +47,7 @@ private void ParseMapGroups() if (vdfObject == null) { Logger.LogError($"Incomplete VDF data."); + throw; } else { @@ -127,7 +127,6 @@ private void UpdateMapList(MapGroup newMapGroup) if(Config.RTV.Enabled) { // Update map list for RTV Plugin - Logger.LogInformation("Updating map list for RTV plugin."); try { using (StreamWriter writer = new StreamWriter(Config.RTV.MapListFile)) @@ -149,23 +148,21 @@ private void UpdateMapList(MapGroup newMapGroup) writer.WriteLine($"{map.Name}:{map.WorkshopId}"); } } - } + } } } catch (IOException ex) { - Logger.LogError("Unable to update maplist.txt."); + Logger.LogError("Could not update map list."); Logger.LogError($"{ex.Message}"); } // Reload RTV Plugin - Logger.LogInformation("Reloading RTV plugin."); Server.ExecuteCommand($"css_plugins reload {Config.RTV.Plugin}"); } - // Update map menu + // Update map list for map menu try { - Logger.LogInformation("Updating map menu."); UpdateMapMenu(newMapGroup); } catch(Exception ex) @@ -177,12 +174,12 @@ private void UpdateMapList(MapGroup newMapGroup) private static CenterHtmlMenu mapMenu = new CenterHtmlMenu("Map List"); private static CenterHtmlMenu modeMenu = new CenterHtmlMenu("Game Mode List"); - // Create and update map menu + // Update map menu private void UpdateMapMenu(MapGroup newMapGroup) { mapMenu = new CenterHtmlMenu("Map List"); - // Create menu options for each map in the maplist + // Create menu options for each map in the new map list foreach (Map map in newMapGroup.Maps) { mapMenu.AddMenuOption(map.Name, (player, option) => @@ -196,8 +193,10 @@ private void UpdateMapMenu(MapGroup newMapGroup) } // Write to chat Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, nextMap.Name]); + // Change map AddTimer(5.0f, () => ChangeMap(nextMap)); + // Close menu MenuManager.CloseActiveMenu(player); }); @@ -206,7 +205,6 @@ private void UpdateMapMenu(MapGroup newMapGroup) // Create mode menu private void SetupModeMenu() { - Logger.LogInformation("Creating mode menu."); modeMenu = new CenterHtmlMenu("Game Mode List"); if (Config.GameMode.ListEnabled) From 385dedfcdc564a4fff42f9b80c8aa31cbfb5a446 Mon Sep 17 00:00:00 2001 From: Nick M Date: Sat, 6 Apr 2024 11:11:49 -0400 Subject: [PATCH 11/86] Reduced verbosity of logging --- GameModeManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GameModeManager.cs b/GameModeManager.cs index 3a93120..20c1cff 100644 --- a/GameModeManager.cs +++ b/GameModeManager.cs @@ -27,6 +27,7 @@ public override void Load(bool hotReload) // Parse map groups and set default map list and game modes try { + Logger.LogInformation($"Loading map groups..."); ParseMapGroups(); } catch(Exception ex) @@ -37,6 +38,7 @@ public override void Load(bool hotReload) // Setup mode admin menu try { + Logger.LogInformation($"Creating game modes..."); SetupModeMenu(); } catch (Exception ex) From db01a417aa3729d1e101a6e8b5eade51ae81f9e7 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 6 Apr 2024 11:17:31 -0400 Subject: [PATCH 12/86] Update README.md Logging verbosity changes --- README.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 0c17282..f4e345d 100644 --- a/README.md +++ b/README.md @@ -148,15 +148,10 @@ This plugin will display all in-game menus and messaging within the language of ### Example ``` -2024-04-01 03:26:13.249 +00:00 [INFO] plugin:GameModeManager Parsing map group file /home/steam/cs2/game/csgo/gamemodes_server.txt. -2024-04-01 03:26:13.263 +00:00 [INFO] plugin:GameModeManager Updating map menu. -2024-04-01 03:26:13.264 +00:00 [INFO] plugin:GameModeManager Creating mode menu. -2024-04-01 03:27:05.147 +00:00 [INFO] plugin:GameModeManager OnMapsCommand execution started. -2024-04-01 03:27:16.704 +00:00 [INFO] plugin:GameModeManager OnModesCommand execution started. -2024-04-01 03:27:20.767 +00:00 [INFO] plugin:GameModeManager Map group command detected! -2024-04-01 03:27:20.767 +00:00 [INFO] plugin:GameModeManager Current MapGroup is mg_active. -2024-04-01 03:27:20.768 +00:00 [INFO] plugin:GameModeManager New MapGroup is mg_aim. -2024-04-01 03:27:20.768 +00:00 [INFO] plugin:GameModeManager Updating map menu. +2024-04-01 03:26:13.249 +00:00 [INFO] plugin:GameModeManager Loading map groups... +2024-04-01 03:26:13.264 +00:00 [INFO] plugin:GameModeManager Creating game modes... +2024-04-01 03:27:20.767 +00:00 [INFO] plugin:GameModeManager Current map group is mg_active. +2024-04-01 03:27:20.768 +00:00 [INFO] plugin:GameModeManager New map group is mg_aim. ``` ### Common Error Messages From 8106e6c8119750e4072f557d7819db8e52aa599d Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 6 Apr 2024 11:18:37 -0400 Subject: [PATCH 13/86] Update README.md Removed spaces --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f4e345d..068aa94 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This plugin utilizes the [GameLoop.Vdf library](https://github.com/shravan2x/Gam ## Requirements - [Counter-Strike 2](https://www.counter-strike.net/cs2) - [Metamod:Source](https://github.com/alliedmodders/metamod-source/) (v1282+) -- [Counter Strike Sharp](https://github.com/roflmuffin/CounterStrikeSharp) (v.197+) +- [CounterStrikeSharp](https://github.com/roflmuffin/CounterStrikeSharp) (v.197+) > [!NOTE] > If you are using the [CS2 Modded Dedicated Server by Kus](https://github.com/kus/cs2-modded-server) you should remove the [Ultimate Map Chooser](https://github.com/kus/cs2-modded-server/tree/master/game/csgo/addons/counterstrikesharp/plugins/CS2-Ultimate-Mapchooser) plugin until the pull request is approved/finalized. From cde620e566aa419cd5f522528cd99cc10ce88e89 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 6 Apr 2024 11:38:58 -0400 Subject: [PATCH 14/86] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 3b9d42b..f411398 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Nick M +Copyright (c) 2024 Striker-Nick Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 2a419a61cc430f8ae788ba00ae7ec0bf58a1de6f Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 6 Apr 2024 11:42:15 -0400 Subject: [PATCH 15/86] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index f411398..7ffb2ce 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Striker-Nick +Copyright (c) 2024 Nickj609 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 7f1e9d6f09758b476ac77c68b75b08831db5c1ec Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 6 Apr 2024 11:44:32 -0400 Subject: [PATCH 16/86] Update README.md Added badges --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 068aa94..7dc026d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +![Copyright Nickj609l](https://img.shields.io/badge/Copyright-Nickj609-red) ![GitHub License](https://img.shields.io/github/license/nickj609/GameModeManager) ![Issues](https://img.shields.io/github/issues/nickj609/GameModeManager) ![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/nickj609/GameModeManager/total) ![GitHub commits since latest release](https://img.shields.io/github/commits-since/nickj609/GameModeManager/latest) + + + # GameModeManager A Counter-Strike 2 server plugin inspired by the [CS2 Modded Dedicated Server by Kus](https://github.com/kus/cs2-modded-server) and the [CS2 Rock The Vote plugin by Abnerfs](https://github.com/abnerfs/cs2-rockthevote). From 9ba096279eba6fa321769fa0081e1888a0cc0875 Mon Sep 17 00:00:00 2001 From: Nick M Date: Sat, 6 Apr 2024 11:48:58 -0400 Subject: [PATCH 17/86] Reduced verbosity of logging --- Functions.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Functions.cs b/Functions.cs index 2f3afd3..a77daa5 100644 --- a/Functions.cs +++ b/Functions.cs @@ -196,7 +196,7 @@ private void UpdateMapMenu(MapGroup newMapGroup) // Change map AddTimer(5.0f, () => ChangeMap(nextMap)); - + // Close menu MenuManager.CloseActiveMenu(player); }); @@ -260,8 +260,6 @@ private void SetupModeMenu() // Define function to change map private void ChangeMap(Map nextMap) { - Logger.LogInformation("Changing map..."); - // If map valid, change map based on map type if (Server.IsMapValid(nextMap.Name)) { From 9b5c64a2fb6b2202d90be0f261fb8828f5683e5a Mon Sep 17 00:00:00 2001 From: Nick M Date: Sat, 6 Apr 2024 11:59:00 -0400 Subject: [PATCH 18/86] Updated exception handling --- Functions.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Functions.cs b/Functions.cs index a77daa5..d1977b3 100644 --- a/Functions.cs +++ b/Functions.cs @@ -8,7 +8,7 @@ using CounterStrikeSharp.API.Core.Translations; // Copyright (c) 2016 Shravan Rajinikanth -// https://github.com/shravan2x/Gameloop.Vdf/blob/master/LICENSE +// https://github.com/shravan2x/Gameloop.Vdf/ using Gameloop.Vdf; using Gameloop.Vdf.Linq; @@ -46,8 +46,7 @@ private void ParseMapGroups() if (vdfObject == null) { - Logger.LogError($"Incomplete VDF data."); - throw; + throw new IOException("Incomplete VDF data."); } else { From 7032476828dd72d579d0a772564431e520d0f8b0 Mon Sep 17 00:00:00 2001 From: Nick M Date: Sat, 13 Apr 2024 04:07:47 -0400 Subject: [PATCH 19/86] Version 1.0.4 --- Classes.cs | 72 -- Commands.cs | 111 --- Config.cs | 60 +- Core/MapGroupManager.cs | 192 ++++ Core/MapManager.cs | 227 +++++ Core/ModeManager.cs | 111 +++ Core/VoteManager.cs | 89 ++ Events.cs | 33 - Functions.cs | 280 ------ GameModeManager.csproj | 16 +- GameModeManager.cs => Plugin.cs | 39 +- lib/{net7.0 => Gameloop.Vdf}/Gameloop.Vdf.dll | Bin lib/{net7.0 => Gameloop.Vdf}/Gameloop.Vdf.xml | 0 .../CS2-CustomVotes/CS2-CustomVotes.json | 36 + .../CS2-CustomVotes.Shared.dll | Bin 0 -> 5632 bytes .../CS2-CustomVotes.Shared.pdb | Bin 0 -> 10928 bytes .../CS2-CustomVotes/CS2-CustomVotes.deps.json | 830 ++++++++++++++++++ .../CS2-CustomVotes/CS2-CustomVotes.dll | Bin 0 -> 30720 bytes .../CS2-CustomVotes/CS2-CustomVotes.pdb | Bin 0 -> 19960 bytes .../plugins/CS2-CustomVotes/lang/cz.json | 9 + .../plugins/CS2-CustomVotes/lang/de.json | 9 + .../plugins/CS2-CustomVotes/lang/en.json | 9 + .../plugins/CS2-CustomVotes/lang/pt-br.json | 9 + .../plugins/CS2-CustomVotes/lang/pt-pt.json | 9 + .../plugins/CS2-CustomVotes/lang/ru.json | 9 + .../CS2-CustomVotes.Shared.deps.json | 23 + .../CS2-CustomVotes.Shared.dll | Bin 0 -> 6144 bytes .../CS2-CustomVotes.Shared.pdb | Bin 0 -> 11896 bytes 28 files changed, 1652 insertions(+), 521 deletions(-) delete mode 100644 Classes.cs delete mode 100644 Commands.cs create mode 100644 Core/MapGroupManager.cs create mode 100644 Core/MapManager.cs create mode 100644 Core/ModeManager.cs create mode 100644 Core/VoteManager.cs delete mode 100644 Events.cs delete mode 100644 Functions.cs rename GameModeManager.cs => Plugin.cs (55%) rename lib/{net7.0 => Gameloop.Vdf}/Gameloop.Vdf.dll (100%) rename lib/{net7.0 => Gameloop.Vdf}/Gameloop.Vdf.xml (100%) create mode 100644 lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json create mode 100644 lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.dll create mode 100644 lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.pdb create mode 100644 lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.deps.json create mode 100644 lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.dll create mode 100644 lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.pdb create mode 100644 lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/cz.json create mode 100644 lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/de.json create mode 100644 lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/en.json create mode 100644 lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-br.json create mode 100644 lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-pt.json create mode 100644 lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/ru.json create mode 100644 lib/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.deps.json create mode 100644 lib/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.dll create mode 100644 lib/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.pdb diff --git a/Classes.cs b/Classes.cs deleted file mode 100644 index 9ee5a3a..0000000 --- a/Classes.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Declare namespace -namespace GameModeManager -{ - // Define map class - public class Map : IEquatable - { - public string Name { get; set; } - public string WorkshopId { get; set; } - - public Map(string name) - { - Name = name; - WorkshopId = ""; - } - - public Map(string name, string workshopId) - { - Name = name; - WorkshopId = workshopId; - } - - public bool Equals(Map? other) - { - if (other == null) return false; // Handle null - - // Implement your equality logic, e.g.; - return Name == other.Name && WorkshopId == other.WorkshopId; - } - - public void Clear() - { - Name = ""; - WorkshopId = ""; - } - } - - // Define map group class - public class MapGroup : IEquatable - { - public string Name { get; set; } - public List Maps { get; set; } - - public MapGroup(string name) - { - Name = name; - Maps = new List(); - } - - public MapGroup(string name, List maps) - { - Name = name; - Maps = maps; - } - - public bool Equals(MapGroup? other) - { - if (other == null) - { - return false; // Handle null - } - else - { - return Name == other.Name && Maps.SequenceEqual(other.Maps); - } - } - public void Clear() - { - Name = ""; - Maps = new List(); - } - } -} \ No newline at end of file diff --git a/Commands.cs b/Commands.cs deleted file mode 100644 index 15a3353..0000000 --- a/Commands.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Included libraries -using CounterStrikeSharp.API; -using CounterStrikeSharp.API.Core; -using Microsoft.Extensions.Logging; -using CounterStrikeSharp.API.Modules.Menu; -using CounterStrikeSharp.API.Modules.Admin; -using CounterStrikeSharp.API.Modules.Timers; -using CounterStrikeSharp.API.Core.Attributes; -using CounterStrikeSharp.API.Modules.Commands; -using CounterStrikeSharp.API.Core.Translations; -using CounterStrikeSharp.API.Core.Attributes.Registration; - -// Declare namespace -namespace GameModeManager -{ - public partial class Plugin : BasePlugin - { - // Construct server map group command handler - [ConsoleCommand("css_mapgroup", "Sets the mapgroup for the MapListUpdater plugin.")] - [CommandHelper(minArgs: 1, usage: "mg_active", whoCanExecute: CommandUsage.SERVER_ONLY)] - public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) - { - if (player == null) - { - // Get map group - MapGroup? newMapGroup = mapGroups.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); - - if (newMapGroup == null || newMapGroup.Name == null || newMapGroup.Maps == null) - { - Logger.LogWarning("New map group could not be found. Setting default map group."); - newMapGroup = defaultMapGroup; - } - Logger.LogInformation($"Current map group is {currentMapGroup.Name}."); - Logger.LogInformation($"New map group is {newMapGroup.Name}."); - - // Update map list and map menu - try - { - UpdateMapList(newMapGroup); - } - catch(Exception ex) - { - Logger.LogError($"{ex.Message}"); - } - } - } - - // Construct change map command - [RequiresPermissions("@css/changemap")] - [CommandHelper(minArgs: 1, usage: "[map name] optional: [id]", whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_map", "Changes the map to the map specified in the command argument.")] - public void OnMapCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null) - { - Map newMap = new Map($"{command.ArgByIndex(1)}",$"{command.ArgByIndex(2)}"); - Map? foundMap = allMaps.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); - - if (foundMap != null) - { - newMap = foundMap; - } - // Write to chat - Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, newMap.Name]); - // Change map - AddTimer(5.0f, () => ChangeMap(newMap)); - } - } - // Construct admin map menu command handler - [RequiresPermissions("@css/changemap")] - [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_maps", "Provides a list of maps for the current game mode.")] - public void OnMapsCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null) - { - mapMenu.Title = Localizer["maps.hud.menu-title"]; - MenuManager.OpenCenterHtmlMenu(_plugin, player, mapMenu); - } - } - // Construct change mode command - [RequiresPermissions("@css/changemap")] - [CommandHelper(minArgs: 1, usage: "[mode]", whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_mode", "Changes the game mode to the mode specified in the command argument.")] - public void OnModeCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null) - { - // Write to chat - Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, command.ArgByIndex(1)]); - - // Change game mode - string newMode = $"{command.ArgByIndex(1)}".ToLower(); - AddTimer(5.0f, () => Server.ExecuteCommand($"exec {newMode}.cfg")); - } - } - - // Construct admin mode menu command handler - [RequiresPermissions("@css/changemap")] - [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_modes", "Provides a list of game modes.")] - public void OnModesCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null) - { - modeMenu.Title = Localizer["mode.hud.menu-title"]; - MenuManager.OpenCenterHtmlMenu(_plugin, player, modeMenu); - } - } - } -} \ No newline at end of file diff --git a/Config.cs b/Config.cs index 2819311..35c30c9 100644 --- a/Config.cs +++ b/Config.cs @@ -12,54 +12,69 @@ public partial class Plugin : BasePlugin, IPluginConfig public required Config Config { get; set; } // Parse configuration object data and perform error checking - public void OnConfigParsed(Config config) + public void OnConfigParsed(Config _config) { // RTV Settings - if (config.RTV.Enabled != true && config.RTV.Enabled != false) + if (_config.RTV.Enabled != true && _config.RTV.Enabled != false) { throw new Exception($"Invalid: RTV 'Enabled' should be 'true' or 'false'."); } - else if(config.RTV.Enabled == true) + else if(_config.RTV.Enabled == true) { if (!File.Exists(config.RTV.Plugin)) { - throw new Exception($"Cannot find RTV 'Plugin': {config.RTV.Plugin}"); + throw new Exception($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); } - if (!File.Exists(config.RTV.MapListFile)) + if (!File.Exists(_config.RTV.MapListFile)) { - throw new Exception($"Cannot find RTV 'MapListFile': {config.RTV.MapListFile}"); + throw new Exception($"Cannot find RTV 'MapListFile': {_config.RTV.MapListFile}"); } - if (config.RTV.DefaultMapFormat != true && config.RTV.DefaultMapFormat != false) + if (_config.RTV.DefaultMapFormat != true && _config.RTV.DefaultMapFormat != false) { throw new Exception($"Invalid: RTV 'DefaultMapFormat' should be 'true' or 'false'."); } } // Map Group Settings - if (config.MapGroup.Default == null) + if (!float.TryParse(_config.MapGroup.Delay.ToString(), out _)) { - throw new Exception($"Undefined: MapGroup 'Default' can not be empty."); + throw new Exception("Map group delay must be a number."); + } + if (_config.MapGroup.Default == null) + { + throw new Exception($"Undefined: Default map group can not be empty."); } - if (!File.Exists(config.MapGroup.File)) + if (!File.Exists(_config.MapGroup.File)) { - throw new Exception($"Cannot find MapGroup 'File': {config.MapGroup.File}"); + throw new Exception($"Cannot find map group file: {config.MapGroup.File}"); } // Game Mode Settings - if (config.GameMode.ListEnabled != true && config.GameMode.ListEnabled != false) + if (_config.GameMode.Rotation != true && _config.GameMode.Rotation != false) + { + throw new Exception($"Invalid: Game mode rotation should be 'true' or 'false'."); + } + if (!float.TryParse(_config.GameMode.Delay.ToString(), out _)) + { + throw new Exception("Game mode delay must be a number."); + } + if (!int.TryParse(_config.GameMode.Interval.ToString(), out _)) + { + throw new Exception("Game mode interval must be a number."); + } + if (config.GameMode.ListEnabled != true && _config.GameMode.ListEnabled != false) { - throw new Exception($"Invalid: GameMode 'ListEnabled' should be 'true' or 'false'."); + throw new Exception($"Invalid: Game mode list enabled should be 'true' or 'false'."); } - else if (config.GameMode.ListEnabled == true) + else if (_config.GameMode.ListEnabled == true) { - - if(config.GameMode.List == null || config.GameMode.List.Count == 0) + if(_config.GameMode.List == null || _config.GameMode.List.Count == 0) { - throw new Exception($"Undefined: GameMode 'List' cannot be empty."); + throw new Exception($"Undefined: Game mode list cannot be empty."); } } - Config = config; + Config = _config; } } public class Config : BasePluginConfig @@ -75,14 +90,18 @@ public class RTVSettings public class MapGroupSettings { + [JsonPropertyName("Delay")] public float Delay { get; set; } = 5.0f; // Map change delay in seconds [JsonPropertyName("Default")] public string Default { get; set; } = "mg_active"; // Default map group on server start [JsonPropertyName("File")] public string File { get; set; } = "/home/steam/cs2/game/csgo/gamemodes_server.txt"; // Default game modes and map groups file } public class GameModeSettings { - [JsonPropertyName("ListEnabled")] public bool ListEnabled { get; set; } = true; // Enables custom game mode list. Default list is generated from map groups. - [JsonPropertyName("List")] public List List { get; set; } = new List + [JsonPropertyName("Rotation")] public bool Rotation { get; set; } = true; // Enables game mode rotation + [JsonPropertyName("Interval")] public int Interval { get; set; } = 4; // Changes game mode every x map rotations + [JsonPropertyName("Delay")] public float Delay { get; set; } = 5.0f; // Game mode change delay in seconds + [JsonPropertyName("ListEnabled")] public bool ListEnabled { get; set; } = true; // Enables custom game mode list. If set to false, generated from map groups. + [JsonPropertyName("List")] public List List { get; set; } = new List // Custom game mode list { "comp", "1v1", @@ -101,6 +120,7 @@ public class GameModeSettings }; // Default Game Mode List } + // Create config [JsonPropertyName("RTV")] public RTVSettings RTV { get; set; } = new RTVSettings(); [JsonPropertyName("MapGroup")] public MapGroupSettings MapGroup { get; set; } = new MapGroupSettings(); [JsonPropertyName("GameMode")] public GameModeSettings GameMode { get; set; } = new GameModeSettings(); diff --git a/Core/MapGroupManager.cs b/Core/MapGroupManager.cs new file mode 100644 index 0000000..cafa450 --- /dev/null +++ b/Core/MapGroupManager.cs @@ -0,0 +1,192 @@ +// Included libraries +using System.Text; +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using Microsoft.Extensions.Logging; +using CounterStrikeSharp.API.Modules.Menu; +using CounterStrikeSharp.API.Modules.Timers; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Core.Translations; + +// Copyright (c) 2016 Shravan Rajinikanth +// https://github.com/shravan2x/Gameloop.Vdf/ +using Gameloop.Vdf; +using Gameloop.Vdf.Linq; + +// Declare namespace +namespace GameModeManager +{ + // Define map group class + public class MapGroup : IEquatable + { + public string Name { get; set; } + public List Maps { get; set; } + + public MapGroup(string _name) + { + Name = _name; + Maps = new List(); + } + + public MapGroup(string _name, List _maps) + { + Name = _name; + Maps = _maps; + } + + public bool Equals(MapGroup? _other) + { + if (_other == null) + { + return false; // Handle null + } + else + { + return Name == _other.Name && Maps.SequenceEqual(_other.Maps); + } + } + public void Clear() + { + Name = ""; + Maps = new List(); + } + } + + // Define plugin class + public partial class Plugin : BasePlugin + { + // Define default maps and map group + private static List _defaultMaps = new List() + { + new Map("de_ancient"), + new Map("de_anubis"), + new Map("de_inferno"), + new Map("de_mirage"), + new Map("de_nuke"), + new Map("de_overpass"), + new Map("de_vertigo") + }; + private static MapGroup _defaultMapGroup = new MapGroup("mg_active", _defaultMaps); + + // Define current map group, current map, and map group list + public static List MapGroups = new List(); + public static MapGroup CurrentMapGroup = _defaultMapGroup; + public static List Maps = new List(); + public static Map? CurrentMap; + + // Define function to parse map groups + private MapGroup ParseMapGroups() + { + try + { + // Deserialize gamemodes_server.txt (VDF) to VProperty with GameLoop.Vdf + VProperty vdfObject = VdfConvert.Deserialize(File.ReadAllText(Config.MapGroup.File, Encoding.UTF8)); + + if (vdfObject == null) + { + throw new IOException("VDF is empty or incomplete."); + return; + } + else + { + // Create an array of only map groups + var _mapGroups = vdfObject.Value.OfType() + .Where(p => p.Key == "mapgroups") + .Select(p => p.Value) + .FirstOrDefault(); + + // Parse array to populate map group list + if (_mapGroups != null) + { + foreach (VProperty _mapGroup in _mapGroups.OfType()) + { + // Create map group + MapGroup _group = new MapGroup(_mapGroup.Key); + + // Create an array of maps + var _maps = _mapGroup.Value.OfType() + .Where(p => p.Key == "maps") + .Select(p => p.Value) + .FirstOrDefault(); + + // Parse array to add maps to map group + if (_maps != null) + { + foreach (VProperty _map in _maps) + { + string _mapName = _map.Key; + + if (_mapName.StartsWith("workshop/")) + { + string[] parts = _mapName.Split('/'); + string _mapNameFormatted = parts[parts.Length - 1]; + string _mapWorkshopId = parts[1]; + _group.Maps.Add(new Map(_mapNameFormatted, _mapWorkshopId)); + Maps.Add(new Map(_mapNameFormatted, _mapWorkshopId)); + } + else + { + _group.Maps.Add(new Map(_mapName)); + Maps.Add(new Map(_mapName)); + } + } + } + else + { + Logger.LogWarning("Mapgroup found, but the 'maps' property is missing or incomplete. Setting default maps."); + _group.Maps = _defaultMaps; + } + // Add map group to map group list + mapGroups.Add(_group); + } + } + else + { + Logger.LogWarning($"The mapgroup property doesn't exist. Using default map group."); + MapGroups.Add(_defaultMapGroup); + } + } + // Set default map group from configuration file. If not found, use plugin default. + _defaultMapGroup = MapGroups.FirstOrDefault(g => g.Name == $"{Config.MapGroup}") ?? new MapGroup("mg_active", _defaultMaps); + CurrentMapGroup = _defaultMapGroup; + + // Update map list + UpdateMapList(_defaultMapGroup); + } + catch (Exception ex) + { + Logger.LogError($"{ex.Message}"); + } + } + + // Construct server map group command handler + [ConsoleCommand("css_mapgroup", "Sets the mapgroup for the MapListUpdater plugin.")] + [CommandHelper(minArgs: 1, usage: "mg_active", whoCanExecute: CommandUsage.SERVER_ONLY)] + public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) + { + if (player == null) + { + // Get map group + MapGroup? newMapGroup = mapGroups.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); + + if (newMapGroup == null || newMapGroup.Name == null || newMapGroup.Maps == null) + { + Logger.LogWarning("New map group could not be found. Setting default map group."); + newMapGroup = defaultMapGroup; + } + Logger.LogInformation($"Current map group is {currentMapGroup.Name}."); + Logger.LogInformation($"New map group is {newMapGroup.Name}."); + + // Update map list and map menu + try + { + UpdateMapList(newMapGroup); + } + catch(Exception ex) + { + Logger.LogError($"{ex.Message}"); + } + } + } + } +} \ No newline at end of file diff --git a/Core/MapManager.cs b/Core/MapManager.cs new file mode 100644 index 0000000..3d30d3b --- /dev/null +++ b/Core/MapManager.cs @@ -0,0 +1,227 @@ +// Included libraries +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using Microsoft.Extensions.Logging; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Core.Translations; + +// Declare namespace +namespace GameModeManager +{ + // Define Map class + public class Map : IEquatable + { + public string Name { get; set; } + public string WorkshopId { get; set; } + + public Map(string name) + { + Name = name; + WorkshopId = ""; + } + + public Map(string name, string workshopId) + { + Name = name; + WorkshopId = workshopId; + } + + public bool Equals(Map? other) + { + if (other == null) return false; // Handle null + + // Implement your equality logic, e.g.; + return Name == other.Name && WorkshopId == other.WorkshopId; + } + + public void Clear() + { + Name = ""; + WorkshopId = ""; + } + } + + // Plugin class + public partial class Plugin : BasePlugin + { + + // Define function to update map list + private void UpdateMapList(MapGroup _group) + { + // If using RTV Plugin + if(Config.RTV.Enabled) + { + // Update map list for RTV Plugin + try + { + using (StreamWriter writer = new StreamWriter(Config.RTV.MapListFile)) + { + foreach (Map _map in _group.Maps) + { + if (string.IsNullOrEmpty(_map.WorkshopId)) + { + writer.WriteLine(_map.Name); + } + else + { + if(Config.RTV.DefaultMapFormat) + { + writer.WriteLine($"ws:{_map.WorkshopId}"); + } + else + { + writer.WriteLine($"{_map.Name}:{_map.WorkshopId}"); + } + } + } + } + } + catch (IOException ex) + { + Logger.LogError("Could not update map list."); + Logger.LogError($"{ex.Message}"); + } + + // Reload RTV Plugin + Server.ExecuteCommand($"css_plugins reload {Config.RTV.Plugin}"); + } + // Update map list for map menu + try + { + UpdateMapMenu(_group); + } + catch(Exception ex) + { + Logger.LogError($"{ex.Message}"); + } + } + + // Create map menu + private static CenterHtmlMenu _mapMenu = new CenterHtmlMenu("Map List"); + + // Define update map menu function + private void UpdateMapMenu(MapGroup _mapGroup) + { + _mapMenu = new CenterHtmlMenu("Map List"); + + // Create menu options for each map in the new map list + foreach (Map _map in _mapGroup.Maps) + { + _mapMenu.AddMenuOption(_map.Name, (player, option) => + { + Map? _nextMap = map; + + if (_nextMap == null) + { + Logger.LogWarning("Map not found when updating map menu. Using de_dust2 for next map."); + _nextMap = new Map("de_dust2"); + } + // Write to chat + Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, _nextMap.Name]); + + // Change map + AddTimer(Config.MapGroup.Delay, () => ChangeMap(_nextMap)); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + } + + // Define change map function + private void ChangeMap(Map _nextMap) + { + // If map valid, change map based on map type + if (Server.IsMapValid(_nextMap.Name)) + { + Server.ExecuteCommand($"changelevel \"{_nextMap.Name}\""); + } + else if (nextMap.WorkshopId != null) + { + Server.ExecuteCommand($"host_workshop_map \"{_nextMap.WorkshopId}\""); + } + else + { + Server.ExecuteCommand($"ds_workshop_changelevel \"{_nextMap.Name}\""); + } + + // Set current map + CurrentMap = _nextMap; + } + + // Construct EventGameEnd Handler to automatically change map at game end + int _counter = 0; + private HookResult EventGameEnd(EventCsIntermission @event, GameEventInfo info) + { + Logger.LogInformation("Game has ended. Picking random map from current map group..."); + Server.PrintToChatAll(Localizer["plugin.prefix"] + " Game has ended. Changing map..."); + + if(!Config.RTV.Enabled) + { + if(CurrentMapGroup == null) + { + CurrentMapGroup = _defaultMapGroup; + } + + // Use the random map ID in the server command. If divisible by x change mode + if(Config.GameMode.Rotation && (float)_counter % Config.GameMode.Interval == 0) + { + // Get random game mode + Random _rnd = new Random(); + int _randomIndex = _rnd.Next(0, MapGroups.Count); + MapGroup _randomMode = MapGroups[_randomIndex]; + + // Change mode + Server.ExecuteCommand($"exec {_randomMode.Name}.cfg"); + } + else + { + // Get a random map + Random _rnd = new Random(); + int _randomIndex = _rnd.Next(0, CurrentMapGroup.Maps.Count); + Map _randomMap = CurrentMapGroup.Maps[_randomIndex]; + + // Change map + ChangeMap(_randomMap); + } + } + _counter++; + return HookResult.Continue; + } + } + + // Construct change map command handler + [RequiresPermissions("@css/changemap")] + [CommandHelper(minArgs: 1, usage: "[map name] optional: [id]", whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_map", "Changes the map to the map specified in the command argument.")] + public void OnMapCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null) + { + Map _newMap = new Map($"{command.ArgByIndex(1)}",$"{command.ArgByIndex(2)}"); + Map? _foundMap = allMaps.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); + + if (_foundMap != null) + { + _newMap = _foundMap; + } + // Write to chat + Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, _newMap.Name]); + // Change map + AddTimer(5.0f, () => ChangeMap(_newMap)); + } + } + + // Construct admin map menu command handler + [RequiresPermissions("@css/changemap")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_maps", "Provides a list of maps for the current game mode.")] + public void OnMapsCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null) + { + _mapMenu.Title = Localizer["maps.hud.menu-title"]; + MenuManager.OpenCenterHtmlMenu(_plugin, player, _mapMenu); + } + } +} \ No newline at end of file diff --git a/Core/ModeManager.cs b/Core/ModeManager.cs new file mode 100644 index 0000000..3d5e2e9 --- /dev/null +++ b/Core/ModeManager.cs @@ -0,0 +1,111 @@ +// Included libraries +using System.Text; +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using Microsoft.Extensions.Logging; +using CounterStrikeSharp.API.Modules.Menu; +using CounterStrikeSharp.API.Modules.Timers; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Core.Translations; + +// Copyright (c) 2016 Shravan Rajinikanth +// https://github.com/shravan2x/Gameloop.Vdf/ +using Gameloop.Vdf; +using Gameloop.Vdf.Linq; + +// Declare namespace +namespace GameModeManager +{ + public partial class Plugin : BasePlugin + { + // Create mode menu + private static CenterHtmlMenu _modeMenu = new CenterHtmlMenu("Game Mode List"); + + // Setup mode menu + private void SetupModeMenu() + { + _modeMenu = new CenterHtmlMenu("Game Mode List"); + + if (Config.GameMode.ListEnabled) + { + // Add menu option for each game mode in game mode list + foreach (string _mode in Config.GameMode.List) + { + _modeMenu.AddMenuOption(_mode, (player, option) => + { + // Write to chat + Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); + + // Change game mode + _mode = option.Text.ToLower(); + AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_mode}.cfg")); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + } + else + { + // Create menu options for each map group parsed + foreach (MapGroup _mapGroup in _mapGroups) + { + // Split the string into parts by the underscore + string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); + + // Get the last part (the actual map group name) + string _tempName = _nameParts[nameParts.Length - 1]; + + // Combine the capitalized first letter with the rest + string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); + + if(_mapGroupName != null) + { + _modeMenu.AddMenuOption(_mapGroupName, (player, option) => + { + // Write to chat + Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); + + // Change game mode + string _mode = option.Text.ToLower(); + AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_mode}.cfg")); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + } + } + } + + // Construct change mode command handler + [RequiresPermissions("@css/changemap")] + [CommandHelper(minArgs: 1, usage: "[mode]", whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_mode", "Changes the game mode to the mode specified in the command argument.")] + public void OnModeCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null) + { + // Write to chat + Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, command.ArgByIndex(1)]); + + // Change game mode + string newMode = $"{command.ArgByIndex(1)}".ToLower(); + AddTimer(5.0f, () => Server.ExecuteCommand($"exec {newMode}.cfg")); + } + } + + // Construct admin mode menu command handler + [RequiresPermissions("@css/changemap")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_modes", "Provides a list of game modes.")] + public void OnModesCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null) + { + modeMenu.Title = Localizer["mode.hud.menu-title"]; + MenuManager.OpenCenterHtmlMenu(_plugin, player, modeMenu); + } + } + } +} \ No newline at end of file diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs new file mode 100644 index 0000000..a611c76 --- /dev/null +++ b/Core/VoteManager.cs @@ -0,0 +1,89 @@ +// Included libraries +using System.Text; +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using Microsoft.Extensions.Logging; +using CS2_CustomVotes.Shared.Models; + +// Declare namespace +namespace GameModeManager +{ + public partial class Plugin : BasePlugin + { + private void RegisterCustomVotes() + { + // Define mode options + var _options = new Dictionary(); + + // Create mode options + if (Config.GameMode.ListEnabled) + { + // Add menu option for each game mode in game mode list + foreach (string mode in Config.GameMode.List) + { + if(mode != null) + { + string _mode=mode.ToLower(); + _options.Add(mode, new VoteOption(mode, new List { $"exec {_mode}.cfg" })); + } + } + } + else + { + _options.Add("Stay", new VoteOption("Keep current game mode", new List { "" })); + + // Create mode options for each map group + foreach (MapGroup _mapGroup in _mapGroups) + { + // Split the string into parts by the underscore + string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); + + // Get the last part (the actual map group name) + string _tempName = _nameParts[nameParts.Length - 1]; + + // Combine the capitalized first letter with the rest + string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); + + if(_mapGroupName != null) + { + string _mode=_mapGroupName.ToLower(); + _options.Add(_mapGroupName, new VoteOption(_mapGroupName, new List { $"exec {_mode}.cfg" })); + } + } + } + + // Add custom game modes vote + Plugin.CustomVotesApi.Get()?.AddCustomVote( + "gamemode", // Command to trigger the vote + new List {"gm", "changemode", "changegame"}, // aliases for the command (optional) + "Vote to change game mode.", // Description + "Stay", + 30, // Time to vote + _options, + "center", // Menu style - "center" or "chat" + 51); // Minimum percentage of votes required + + // Add extend map vote + Plugin.CustomVotesApi.Get()?.AddCustomVote( + "extend", // Command to trigger the vote + new List{"extendmap", "mapextend", "em"}, // aliases for the command (optional) + "Vote to extend map.", // Description + "No", + 30, // Time to vote + new Dictionary // vote options + { + { "5", new VoteOption("5 minutes", new List { "sv_cheats 0" })}, + { "10", new VoteOption("10 minutes", new List { "sv_cheats 0" })}, + { "15", new VoteOption("15 minutes", new List { "sv_cheats 0" })}, + { "20", new VoteOption("20 minutes", new List { "sv_cheats 0" })}, + { "No", new VoteOption("Don't extend", new List {""})} + }, + "center", // Menu style - "center" or "chat" + 51); // Minimum percentage of votes required + } + private void DeregisterCustomVotes() + { + Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamemode"); + } + } +} \ No newline at end of file diff --git a/Events.cs b/Events.cs deleted file mode 100644 index 8e536c3..0000000 --- a/Events.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Included libraries -using CounterStrikeSharp.API; -using CounterStrikeSharp.API.Core; -using Microsoft.Extensions.Logging; -using CounterStrikeSharp.API.Core.Translations; - -// Declare namespace -namespace GameModeManager -{ - public partial class Plugin : BasePlugin - { - // Construct EventGameEnd Handler to automatically change map - private HookResult EventGameEnd(EventCsIntermission @event, GameEventInfo info) - { - Logger.LogInformation("Game has ended. Picking random map from current map group..."); - Server.PrintToChatAll(Localizer["plugin.prefix"] + " Game has ended. Changing map..."); - - if(currentMapGroup == null) - { - currentMapGroup = defaultMapGroup; - } - // Get a random map - Random rnd = new Random(); - int randomIndex = rnd.Next(0, currentMapGroup.Maps.Count); - Map randomMap = currentMapGroup.Maps[randomIndex]; - - // Use the random map ID in the server command - ChangeMap(randomMap); - - return HookResult.Continue; - } - } -} diff --git a/Functions.cs b/Functions.cs deleted file mode 100644 index d1977b3..0000000 --- a/Functions.cs +++ /dev/null @@ -1,280 +0,0 @@ -// Included libraries -using System.Text; -using CounterStrikeSharp.API; -using CounterStrikeSharp.API.Core; -using Microsoft.Extensions.Logging; -using CounterStrikeSharp.API.Modules.Menu; -using CounterStrikeSharp.API.Modules.Timers; -using CounterStrikeSharp.API.Core.Translations; - -// Copyright (c) 2016 Shravan Rajinikanth -// https://github.com/shravan2x/Gameloop.Vdf/ -using Gameloop.Vdf; -using Gameloop.Vdf.Linq; - -// Declare namespace -namespace GameModeManager -{ - public partial class Plugin : BasePlugin - { - // Define default maps and map group - private static List defaultMaps = new List() - { - new Map("de_ancient"), - new Map("de_anubis"), - new Map("de_inferno"), - new Map("de_mirage"), - new Map("de_nuke"), - new Map("de_overpass"), - new Map("de_vertigo") - }; - private static MapGroup defaultMapGroup = new MapGroup("mg_active", defaultMaps); - - // Define current map group, current map, and map group list - public static List mapGroups = new List(); - public static MapGroup currentMapGroup = defaultMapGroup; - public static List allMaps = new List(); - public static Map? currentMap; - - // Define function to parse map groups - private void ParseMapGroups() - { - try - { - // Deserialize gamemodes_server.txt (VDF) to VProperty with GameLoop.Vdf - VProperty vdfObject = VdfConvert.Deserialize(File.ReadAllText(Config.MapGroup.File, Encoding.UTF8)); - - if (vdfObject == null) - { - throw new IOException("Incomplete VDF data."); - } - else - { - // Create an array of only map groups - var mapGroupsData = vdfObject.Value.OfType() - .Where(p => p.Key == "mapgroups") - .Select(p => p.Value) - .FirstOrDefault(); - - // Parse array to populate map group list - if (mapGroupsData != null) - { - foreach (VProperty group in mapGroupsData.OfType()) - { - // Create map group - MapGroup newMapGroup = new MapGroup(group.Key); - - // Create an array of maps - var mapsProperty = group.Value.OfType() - .Where(p => p.Key == "maps") - .Select(p => p.Value) - .FirstOrDefault(); - - // Parse array to add maps to map group - if (mapsProperty != null) - { - foreach (VProperty mapEntry in mapsProperty) - { - string mapName = mapEntry.Key; - - if (mapName.StartsWith("workshop/")) - { - string[] parts = mapName.Split('/'); - string mapNameFormatted = parts[parts.Length - 1]; - string mapWorkshopId = parts[1]; - newMapGroup.Maps.Add(new Map(mapNameFormatted, mapWorkshopId)); - allMaps.Add(new Map(mapNameFormatted, mapWorkshopId)); - } - else - { - newMapGroup.Maps.Add(new Map(mapName)); - allMaps.Add(new Map(mapName)); - } - } - } - else - { - Logger.LogWarning("Mapgroup found, but the 'maps' property is missing or incomplete. Setting default maps."); - newMapGroup.Maps = defaultMaps; - } - // Add map group to map group list - mapGroups.Add(newMapGroup); - } - } - else - { - Logger.LogWarning($"The mapgroup property doesn't exist. Using default map group."); - mapGroups.Add(defaultMapGroup); - } - } - // Set default map group from configuration file. If not found, use plugin default. - defaultMapGroup = mapGroups.FirstOrDefault(g => g.Name == $"{Config.MapGroup}") ?? new MapGroup("mg_active", defaultMaps); - currentMapGroup = defaultMapGroup; - - // Update map list - UpdateMapList(defaultMapGroup); - } - catch (Exception ex) - { - Logger.LogError($"{ex.Message}"); - } - } - // Define function to update map list - private void UpdateMapList(MapGroup newMapGroup) - { - // If using RTV Plugin - if(Config.RTV.Enabled) - { - // Update map list for RTV Plugin - try - { - using (StreamWriter writer = new StreamWriter(Config.RTV.MapListFile)) - { - foreach (Map map in newMapGroup.Maps) - { - if (string.IsNullOrEmpty(map.WorkshopId)) - { - writer.WriteLine(map.Name); - } - else - { - if(Config.RTV.DefaultMapFormat) - { - writer.WriteLine($"ws:{map.WorkshopId}"); - } - else - { - writer.WriteLine($"{map.Name}:{map.WorkshopId}"); - } - } - } - } - } - catch (IOException ex) - { - Logger.LogError("Could not update map list."); - Logger.LogError($"{ex.Message}"); - } - - // Reload RTV Plugin - Server.ExecuteCommand($"css_plugins reload {Config.RTV.Plugin}"); - } - // Update map list for map menu - try - { - UpdateMapMenu(newMapGroup); - } - catch(Exception ex) - { - Logger.LogError($"{ex.Message}"); - } - } - // Define menus - private static CenterHtmlMenu mapMenu = new CenterHtmlMenu("Map List"); - private static CenterHtmlMenu modeMenu = new CenterHtmlMenu("Game Mode List"); - - // Update map menu - private void UpdateMapMenu(MapGroup newMapGroup) - { - mapMenu = new CenterHtmlMenu("Map List"); - - // Create menu options for each map in the new map list - foreach (Map map in newMapGroup.Maps) - { - mapMenu.AddMenuOption(map.Name, (player, option) => - { - Map? nextMap = map; - - if (nextMap == null) - { - Logger.LogWarning("Map not found when updating map menu. Using de_dust2 for next map."); - nextMap = new Map("de_dust2"); - } - // Write to chat - Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, nextMap.Name]); - - // Change map - AddTimer(5.0f, () => ChangeMap(nextMap)); - - // Close menu - MenuManager.CloseActiveMenu(player); - }); - } - } - // Create mode menu - private void SetupModeMenu() - { - modeMenu = new CenterHtmlMenu("Game Mode List"); - - if (Config.GameMode.ListEnabled) - { - // Add menu option for each game mode in game mode list - foreach (string mode in Config.GameMode.List) - { - modeMenu.AddMenuOption(mode, (player, option) => - { - // Write to chat - Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); - - // Change game mode - AddTimer(5.0f, () => Server.ExecuteCommand($"exec {option.Text}.cfg")); - - // Close menu - MenuManager.CloseActiveMenu(player); - }); - } - } - else - { - // Create menu options for each map group parsed - foreach (MapGroup mapGroup in mapGroups) - { - // Split the string into parts by the underscore - string[] nameParts = (mapGroup.Name ?? defaultMapGroup.Name).Split('_'); - - // Get the last part (the actual map group name) - string tempName = nameParts[nameParts.Length - 1]; - - // Combine the capitalized first letter with the rest - string mapGroupName = tempName.Substring(0, 1).ToUpper() + tempName.Substring(1); - - if(mapGroupName != null) - { - modeMenu.AddMenuOption(mapGroupName, (player, option) => - { - // Write to chat - Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); - - // Change game mode - string newMode = option.Text.ToLower(); - AddTimer(5.0f, () => Server.ExecuteCommand($"exec {newMode}.cfg")); - - // Close menu - MenuManager.CloseActiveMenu(player); - }); - } - } - } - } - // Define function to change map - private void ChangeMap(Map nextMap) - { - // If map valid, change map based on map type - if (Server.IsMapValid(nextMap.Name)) - { - Server.ExecuteCommand($"changelevel \"{nextMap.Name}\""); - } - else if (nextMap.WorkshopId != null) - { - Server.ExecuteCommand($"host_workshop_map \"{nextMap.WorkshopId}\""); - } - else - { - Server.ExecuteCommand($"ds_workshop_changelevel \"{nextMap.Name}\""); - } - - // Set current map - currentMap = nextMap; - } - } -} \ No newline at end of file diff --git a/GameModeManager.csproj b/GameModeManager.csproj index 32d9487..b7321a9 100644 --- a/GameModeManager.csproj +++ b/GameModeManager.csproj @@ -7,12 +7,20 @@ - - + + + false + lib\counterstrikesharp\shared\CS2-CustomVotes.Shared\CS2-CustomVotes.Shared.dll + - - + + + + + + + \ No newline at end of file diff --git a/GameModeManager.cs b/Plugin.cs similarity index 55% rename from GameModeManager.cs rename to Plugin.cs index 20c1cff..7f19221 100644 --- a/GameModeManager.cs +++ b/Plugin.cs @@ -1,7 +1,9 @@ // Included libraries using CounterStrikeSharp.API; +using CS2_CustomVotes.Shared; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; +using CounterStrikeSharp.API.Core.Capabilities; // Declare namespace namespace GameModeManager @@ -18,10 +20,16 @@ public partial class Plugin : BasePlugin // Define plugin private BasePlugin? _plugin; + // Define custom vote API and signal + public static PluginCapability CustomVotesApi { get; } = new("custom_votes:api"); + private bool _isCustomVotesLoaded = false; + // Construct On Load behavior public override void Load(bool hotReload) { - // Set plugin + base.Load(hotReload); + + // Define plugin context _plugin = this; // Parse map groups and set default map list and game modes @@ -52,5 +60,34 @@ public override void Load(bool hotReload) RegisterEventHandler(EventGameEnd); } } + public override void OnAllPluginsLoaded(bool hotReload) + { + base.OnAllPluginsLoaded(hotReload); + + try + { + if (CustomVotesApi.Get() is null) + return; + } + catch (Exception) + { + Logger.LogWarning("CS2-CustomVotes plugin not found. Custom votes will not be registered."); + return; + } + + _isCustomVotesLoaded = true; + Logger.LogInformation("Registering custom votes..."); + RegisterCustomVotes(); + } + public override void Unload(bool hotReload) + { + // Deregister votes and game events + if (_isCustomVotesLoaded) + { + Logger.LogInformation("Deregistering custom votes..."); + DeregisterCustomVotes(); + } + base.Unload(hotReload); + } } } \ No newline at end of file diff --git a/lib/net7.0/Gameloop.Vdf.dll b/lib/Gameloop.Vdf/Gameloop.Vdf.dll similarity index 100% rename from lib/net7.0/Gameloop.Vdf.dll rename to lib/Gameloop.Vdf/Gameloop.Vdf.dll diff --git a/lib/net7.0/Gameloop.Vdf.xml b/lib/Gameloop.Vdf/Gameloop.Vdf.xml similarity index 100% rename from lib/net7.0/Gameloop.Vdf.xml rename to lib/Gameloop.Vdf/Gameloop.Vdf.xml diff --git a/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json b/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json new file mode 100644 index 0000000..5ba2d7e --- /dev/null +++ b/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json @@ -0,0 +1,36 @@ +{ + "CustomVotesEnabled": true, + "VoteCooldown": 60, + "ChatPrefix": "[{DarkBlue}CustomVotes{Default}]", + "ForceStyle": "none", + "CustomVotes": [ + { + "Command": "cheats", + "CommandAliases": [], + "Description": "Vote to enable sv_cheats", + "TimeToVote": 30, + "Options": { + "Enable": { + "Text": "{Green}Enable", + "Commands": [ + "sv_cheats 1" + ] + }, + "Disable": { + "Text": "{Red}Disable", + "Commands": [ + "sv_cheats 0" + ] + } + }, + "DefaultOption": "Disable", + "Style": "chat", + "MinVotePercentage": -1, + "Permission": { + "RequiresAll": false, + "Permissions": [] + } + } + ], + "ConfigVersion": 2 +} \ No newline at end of file diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.dll b/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.dll new file mode 100644 index 0000000000000000000000000000000000000000..25be084a99d7fd042a8b4c58f99cc45a6b08cbf8 GIT binary patch literal 5632 zcmeHLYit}>6+UxpM) zRx`6smMX1FTN++f03nDdRoW_2p_Pb4Dpg3Opo&PSjRL3$2|*PV`m>@1@got!eCO`$ z!_EUzsS-ap&OP^@$36Ev?%cgM17A2p0U`>b&CC$JhMu8Y;@hKXh@+qRX_PKDUtaZ^ z*nfFddcttkqGRVBt)ON#%d$N+qpMEIQVmN@9!#kPJEzB5TU+k&O%L`G?H2)h^_L%D z^$J|2)#^Oa1>>N@72dn+(W_|PXhdyttW^AF2Kz5z8W?lOKvad9T#{JMZ(t)U3 zlt2d(7FL2C5QIBdDvux^!Oqo6;FKJI!OD^$2R*5MJ;INMb2GI$))m{-wQ0k44lYC{ z@EJ^9^C;0j(HD7~@*Km;yR2b0!yNiGhf`Fin7$%jRl;N`>mYq!Fn&SeHzeLE`A6k=hSM6)8~zA7TBG)YD%Pm| zpdPDHEPJL#RclXlDfA`{K~@2#GO{8}Gj&3Kf>r9YA2-W>1CLkG4^)=1FV7)YKdVrY zqrsO*rAt1g1^HmQ;!~#sub{ra_o?p$F8bB}F>$?zP`>~rd85;N;Dl%!5*MZ)Vl1el z^9QNJnn9@c^KP34n-~>HPW#AUzepp+iWF;pnIa$imqvCPN zdBVr6`2_gq#q*N$qK}#XBKU8MH)%EfUHsX{i|Cq|7QD(iiGMEfRf(JAZqtLWBl~9q zzd#n}qvC>Effb6P;sR$u2r&hxIj@bt#}l6yRaiwA<#0A{Eow7cual0UQa89^ zCNxLSF?;kT?41d_P|&QLyL)nUv`5QM;_U1*bTdag)A*6Qfm<*vHan<0S>5uqyiTrH zHg&SJf?oA%sAPEt$apSSUy+9Nf<2`-FjyyTvo-21Wb|B4&&53)-kB0OaI0vTx+9~~ zyhc$?>9C9SYZN8*Oevq&GG+tsK*=;`bK$) zltEX;$dvyf5O1i1MNT;7^l`0ZdNs<;Iz~m}e?K*=6w7+HQ?-^fw7g}zo{@D4wI45$FCbEF97bKk5T=dmqaOPYZFtU#A+T$MP=k&Ox znPt~-Z}Hj2*plg1{cSh~$d&=RR4ZX+|GIQAa~wy7jEBRPvB-hPl!T8i{d(Wj+2x4=ogu%jvOh)B!d#HU;uZTu2>=}J*;qO{@MBaX6@yzA*e>xNh zuLvn&{EH~zXgDmjcv^_3tq3hp!y+1u&Tn57SE7sVjxJG~L{us@Fx!~fKu6lu$cxXI@G#n>QpF{#BL{&FFgtvv@bB|0`AU&imL74m;sM+0J(<;IzS0wpeZmzHfwP@q zm!M^_1HI{l?db7h@d1A~?wZ;f>w# z#}>eaAH)XSY4L~qv7nG7aADxzlY0d{ImtiYX{9x8n)ZnS>}8{f!#1rn_gfSA4sb5A z+J0P6{|hw^?LVo7D~*qj%t`rN+W#dSu`|a<{0fX%x`%q*LNiv(WhnJveB+kS zlJC;D-uGQX*nMqZeR%TQZ+-oGe%^=4pZHHP4&^eBRUX|4)hAm;f|JEbn&yCJSX6Mc z*lfBy1Eq9kEsV@f&y5yq9KM?qEhCz)vE-m~i|)D!pT+!kJlc(SeEsHu@n&#`DMh2e zy|{U&s2?xw1EBkX`zo()dOi5pe^u^2Tp@-^zo$ar-pd^fM#o`((arK{GsTFar&nPg8L^cr$kkL*s?k0CY_e+(U{AWj(A%u9=$ zxguTwocTO*!9N`;+A+EQL7&f6;q|L|VXBhhkLyRJZiBFI!@Cl0^Ik)AcV4$H`I?<= zZ*G?BIVRdB>k&r{T;!sF-DDyQD)K(NGW9uJpHCQ&c>aHptGhnob^dSue=-CA2HO3} AjsO4v literal 0 HcmV?d00001 diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.pdb b/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.pdb new file mode 100644 index 0000000000000000000000000000000000000000..c0f666ce48c1fb27827840b119ade02b3c3ef339 GIT binary patch literal 10928 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 literal 0 HcmV?d00001 diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.deps.json b/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.deps.json new file mode 100644 index 0000000..3612e5d --- /dev/null +++ b/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.deps.json @@ -0,0 +1,830 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v7.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v7.0": { + "CS2-CustomVotes/1.0.0": { + "dependencies": { + "CS2-CustomVotes.Shared": "1.0.0", + "CounterStrikeSharp.API": "1.0.191" + }, + "runtime": { + "CS2-CustomVotes.dll": {} + } + }, + "CounterStrikeSharp.API/1.0.191": { + "dependencies": { + "McMaster.NETCore.Plugins": "1.4.0", + "Microsoft.CSharp": "4.7.0", + "Microsoft.DotNet.ApiCompat.Task": "7.0.404", + "Microsoft.Extensions.Hosting": "7.0.0", + "Microsoft.Extensions.Hosting.Abstractions": "7.0.0", + "Microsoft.Extensions.Localization.Abstractions": "7.0.3", + "Microsoft.Extensions.Logging": "7.0.0", + "Scrutor": "4.2.2", + "Serilog.Extensions.Logging": "7.0.0", + "Serilog.Sinks.Console": "5.0.0", + "Serilog.Sinks.File": "5.0.0", + "System.Data.DataSetExtensions": "4.5.0" + }, + "runtime": { + "lib/net7.0/CounterStrikeSharp.API.dll": { + "assemblyVersion": "1.0.191.0", + "fileVersion": "1.0.191.0" + } + } + }, + "McMaster.NETCore.Plugins/1.4.0": { + "dependencies": { + "Microsoft.DotNet.PlatformAbstractions": "3.1.6", + "Microsoft.Extensions.DependencyModel": "6.0.0" + }, + "runtime": { + "lib/netcoreapp3.1/McMaster.NETCore.Plugins.dll": { + "assemblyVersion": "1.4.0.0", + "fileVersion": "1.4.0.0" + } + } + }, + "Microsoft.CSharp/4.7.0": {}, + "Microsoft.DotNet.ApiCompat.Task/7.0.404": {}, + "Microsoft.DotNet.PlatformAbstractions/3.1.6": { + "runtime": { + "lib/netstandard2.0/Microsoft.DotNet.PlatformAbstractions.dll": { + "assemblyVersion": "3.1.6.0", + "fileVersion": "3.100.620.31604" + } + } + }, + "Microsoft.Extensions.Configuration/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Configuration.Binder/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Configuration.Binder.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Configuration.CommandLine/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Configuration.CommandLine.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Configuration.EnvironmentVariables/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Configuration.EnvironmentVariables.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Physical": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Configuration.Json/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", + "System.Text.Json": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Configuration.UserSecrets/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Configuration.Json": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Physical": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Configuration.UserSecrets.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.DependencyInjection.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "runtime": { + "lib/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.DependencyModel/6.0.0": { + "dependencies": { + "System.Buffers": "4.5.1", + "System.Memory": "4.5.4", + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Encodings.Web": "7.0.0", + "System.Text.Json": "7.0.0" + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.DependencyModel.dll": { + "assemblyVersion": "6.0.0.0", + "fileVersion": "6.0.21.52210" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/7.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/7.0.0": { + "runtime": { + "lib/net7.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Hosting/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Configuration.Binder": "7.0.0", + "Microsoft.Extensions.Configuration.CommandLine": "7.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "7.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "7.0.0", + "Microsoft.Extensions.Configuration.Json": "7.0.0", + "Microsoft.Extensions.Configuration.UserSecrets": "7.0.0", + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Physical": "7.0.0", + "Microsoft.Extensions.Hosting.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Configuration": "7.0.0", + "Microsoft.Extensions.Logging.Console": "7.0.0", + "Microsoft.Extensions.Logging.Debug": "7.0.0", + "Microsoft.Extensions.Logging.EventLog": "7.0.0", + "Microsoft.Extensions.Logging.EventSource": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Hosting.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Hosting.Abstractions/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Hosting.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Localization.Abstractions/7.0.3": { + "runtime": { + "lib/net7.0/Microsoft.Extensions.Localization.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.323.8009" + } + } + }, + "Microsoft.Extensions.Logging/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Logging.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "runtime": { + "lib/net7.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Logging.Configuration/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Configuration.Binder": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Logging.Configuration.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Logging.Console/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Configuration": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "System.Text.Json": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Logging.Console.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Logging.Debug/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Logging.Debug.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Logging.EventLog/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "System.Diagnostics.EventLog": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Logging.EventLog.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Logging.EventSource/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0", + "System.Text.Json": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Logging.EventSource.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Options/7.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Options.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Options.ConfigurationExtensions/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Configuration.Binder": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + }, + "runtime": { + "lib/net7.0/Microsoft.Extensions.Options.ConfigurationExtensions.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Microsoft.Extensions.Primitives/7.0.0": { + "runtime": { + "lib/net7.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Scrutor/4.2.2": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.DependencyModel": "6.0.0" + }, + "runtime": { + "lib/net6.0/Scrutor.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "4.0.0.0" + } + } + }, + "Serilog/3.1.0": { + "runtime": { + "lib/net7.0/Serilog.dll": { + "assemblyVersion": "2.0.0.0", + "fileVersion": "3.1.0.0" + } + } + }, + "Serilog.Extensions.Logging/7.0.0": { + "dependencies": { + "Microsoft.Extensions.Logging": "7.0.0", + "Serilog": "3.1.0" + }, + "runtime": { + "lib/net7.0/Serilog.Extensions.Logging.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.0.0" + } + } + }, + "Serilog.Sinks.Console/5.0.0": { + "dependencies": { + "Serilog": "3.1.0" + }, + "runtime": { + "lib/net7.0/Serilog.Sinks.Console.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.0.0" + } + } + }, + "Serilog.Sinks.File/5.0.0": { + "dependencies": { + "Serilog": "3.1.0" + }, + "runtime": { + "lib/net5.0/Serilog.Sinks.File.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.0.0.0" + } + } + }, + "System.Buffers/4.5.1": {}, + "System.Data.DataSetExtensions/4.5.0": {}, + "System.Diagnostics.EventLog/7.0.0": { + "runtime": { + "lib/net7.0/System.Diagnostics.EventLog.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/System.Diagnostics.EventLog.Messages.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "0.0.0.0" + }, + "runtimes/win/lib/net7.0/System.Diagnostics.EventLog.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "System.Memory/4.5.4": {}, + "System.Runtime.CompilerServices.Unsafe/6.0.0": {}, + "System.Text.Encodings.Web/7.0.0": {}, + "System.Text.Json/7.0.0": { + "dependencies": { + "System.Text.Encodings.Web": "7.0.0" + } + }, + "CS2-CustomVotes.Shared/1.0.0": { + "runtime": { + "CS2-CustomVotes.Shared.dll": {} + } + } + } + }, + "libraries": { + "CS2-CustomVotes/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CounterStrikeSharp.API/1.0.191": { + "type": "package", + "serviceable": true, + "sha512": "sha512-nBmw1nCgIVwFNU8dCviVXWcA9ZpC8mXt43Q+Xms8PbfPkeKMZHU3Qr2P97PoBiX1gxaNBZYoqPPbl7/4cFNT/Q==", + "path": "counterstrikesharp.api/1.0.191", + "hashPath": "counterstrikesharp.api.1.0.191.nupkg.sha512" + }, + "McMaster.NETCore.Plugins/1.4.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UKw5Z2/QHhkR7kiAJmqdCwVDMQV0lwsfj10+FG676r8DsJWIpxtachtEjE0qBs9WoK5GUQIqxgyFeYUSwuPszg==", + "path": "mcmaster.netcore.plugins/1.4.0", + "hashPath": "mcmaster.netcore.plugins.1.4.0.nupkg.sha512" + }, + "Microsoft.CSharp/4.7.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==", + "path": "microsoft.csharp/4.7.0", + "hashPath": "microsoft.csharp.4.7.0.nupkg.sha512" + }, + "Microsoft.DotNet.ApiCompat.Task/7.0.404": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ahSvImDcyjf6QwE9zg/HU3A+7LeoCnPWmJdk7pK557BrEtRXQ58oLuK2ANZeQT3GSydIYeRlolHtJ5gSKSw/lg==", + "path": "microsoft.dotnet.apicompat.task/7.0.404", + "hashPath": "microsoft.dotnet.apicompat.task.7.0.404.nupkg.sha512" + }, + "Microsoft.DotNet.PlatformAbstractions/3.1.6": { + "type": "package", + "serviceable": true, + "sha512": "sha512-jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg==", + "path": "microsoft.dotnet.platformabstractions/3.1.6", + "hashPath": "microsoft.dotnet.platformabstractions.3.1.6.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-tldQUBWt/xeH2K7/hMPPo5g8zuLc3Ro9I5d4o/XrxvxOCA2EZBtW7bCHHTc49fcBtvB8tLAb/Qsmfrq+2SJ4vA==", + "path": "microsoft.extensions.configuration/7.0.0", + "hashPath": "microsoft.extensions.configuration.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-f34u2eaqIjNO9YLHBz8rozVZ+TcFiFs0F3r7nUJd7FRkVSxk8u4OpoK226mi49MwexHOR2ibP9MFvRUaLilcQQ==", + "path": "microsoft.extensions.configuration.abstractions/7.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Binder/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-tgU4u7bZsoS9MKVRiotVMAwHtbREHr5/5zSEV+JPhg46+ox47Au84E3D2IacAaB0bk5ePNaNieTlPrfjbbRJkg==", + "path": "microsoft.extensions.configuration.binder/7.0.0", + "hashPath": "microsoft.extensions.configuration.binder.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.CommandLine/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-a8Iq8SCw5m8W5pZJcPCgBpBO4E89+NaObPng+ApIhrGSv9X4JPrcFAaGM4sDgR0X83uhLgsNJq8VnGP/wqhr8A==", + "path": "microsoft.extensions.configuration.commandline/7.0.0", + "hashPath": "microsoft.extensions.configuration.commandline.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.EnvironmentVariables/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-RIkfqCkvrAogirjsqSrG1E1FxgrLsOZU2nhRbl07lrajnxzSU2isj2lwQah0CtCbLWo/pOIukQzM1GfneBUnxA==", + "path": "microsoft.extensions.configuration.environmentvariables/7.0.0", + "hashPath": "microsoft.extensions.configuration.environmentvariables.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-xk2lRJ1RDuqe57BmgvRPyCt6zyePKUmvT6iuXqiHR+/OIIgWVR8Ff5k2p6DwmqY8a17hx/OnrekEhziEIeQP6Q==", + "path": "microsoft.extensions.configuration.fileextensions/7.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-LDNYe3uw76W35Jci+be4LDf2lkQZe0A7EEYQVChFbc509CpZ4Iupod8li4PUXPBhEUOFI/rlQNf5xkzJRQGvtA==", + "path": "microsoft.extensions.configuration.json/7.0.0", + "hashPath": "microsoft.extensions.configuration.json.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.UserSecrets/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-33HPW1PmB2RS0ietBQyvOxjp4O3wlt+4tIs8KPyMn1kqp04goiZGa7+3mc69NRLv6bphkLDy0YR7Uw3aZyf8Zw==", + "path": "microsoft.extensions.configuration.usersecrets/7.0.0", + "hashPath": "microsoft.extensions.configuration.usersecrets.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==", + "path": "microsoft.extensions.dependencyinjection/7.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==", + "path": "microsoft.extensions.dependencyinjection.abstractions/7.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyModel/6.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-TD5QHg98m3+QhgEV1YVoNMl5KtBw/4rjfxLHO0e/YV9bPUBDKntApP4xdrVtGgCeQZHVfC2EXIGsdpRNrr87Pg==", + "path": "microsoft.extensions.dependencymodel/6.0.0", + "hashPath": "microsoft.extensions.dependencymodel.6.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-NyawiW9ZT/liQb34k9YqBSNPLuuPkrjMgQZ24Y/xXX1RoiBkLUdPMaQTmxhZ5TYu8ZKZ9qayzil75JX95vGQUg==", + "path": "microsoft.extensions.fileproviders.abstractions/7.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-K8D2MTR+EtzkbZ8z80LrG7Ur64R7ZZdRLt1J5cgpc/pUWl0C6IkAUapPuK28oionHueCPELUqq0oYEvZfalNdg==", + "path": "microsoft.extensions.fileproviders.physical/7.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2jONjKHiF+E92ynz2ZFcr9OvxIw+rTGMPEH+UZGeHTEComVav93jQUWGkso8yWwVBcEJGcNcZAaqY01FFJcj7w==", + "path": "microsoft.extensions.filesystemglobbing/7.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Hosting/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4nFc8xCfK26G524ioreZvz/IeIKN/gY1LApoGpaIThKqBdTwauUo4ETCf12lQcoefijqe3Imnfvnk31IezFatg==", + "path": "microsoft.extensions.hosting/7.0.0", + "hashPath": "microsoft.extensions.hosting.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Hosting.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-43n9Je09z0p/7ViPxfRqs5BUItRLNVh5b6JH40F2Agkh2NBsY/jpNYTtbCcxrHCsA3oRmbR6RJBzUutB4VZvNQ==", + "path": "microsoft.extensions.hosting.abstractions/7.0.0", + "hashPath": "microsoft.extensions.hosting.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Localization.Abstractions/7.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2sEhpRPiWY3iJ+nxHnLUqM8qNoGqQQqduk0QXd3iEt0fc4fw8EwFElqtT4OJMV0qnGGAwYykdOtrzZ1BIqdvpQ==", + "path": "microsoft.extensions.localization.abstractions/7.0.3", + "hashPath": "microsoft.extensions.localization.abstractions.7.0.3.nupkg.sha512" + }, + "Microsoft.Extensions.Logging/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==", + "path": "microsoft.extensions.logging/7.0.0", + "hashPath": "microsoft.extensions.logging.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==", + "path": "microsoft.extensions.logging.abstractions/7.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Configuration/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-FLDA0HcffKA8ycoDQLJuCNGIE42cLWPxgdQGRBaSzZrYTkMBjnf9zrr8pGT06psLq9Q+RKWmmZczQ9bCrXEBcA==", + "path": "microsoft.extensions.logging.configuration/7.0.0", + "hashPath": "microsoft.extensions.logging.configuration.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Console/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qt5n8bHLZPUfuRnFxJKW5q9ZwOTncdh96rtWzWpX3Y/064MlxzCSw2ELF5Jlwdo+Y4wK3I47NmUTFsV7Sg8rqg==", + "path": "microsoft.extensions.logging.console/7.0.0", + "hashPath": "microsoft.extensions.logging.console.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Debug/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-tFGGyPDpJ8ZdQdeckCArP7nZuoY3am9zJWuvp4OD1bHq65S0epW9BNHzAWeaIO4eYwWnGm1jRNt3vRciH8H6MA==", + "path": "microsoft.extensions.logging.debug/7.0.0", + "hashPath": "microsoft.extensions.logging.debug.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.EventLog/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rp7cYL9xQRVTgjMl77H5YDxszAaO+mlA+KT0BnLSVhuCoKQQOOs1sSK2/x8BK2dZ/lKeAC/CVF+20Ef2dpKXwg==", + "path": "microsoft.extensions.logging.eventlog/7.0.0", + "hashPath": "microsoft.extensions.logging.eventlog.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.EventSource/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-MxQXndQFviIyOPqyMeLNshXnmqcfzEHE2wWcr7BF1unSisJgouZ3tItnq+aJLGPojrW8OZSC/ZdRoR6wAq+c7w==", + "path": "microsoft.extensions.logging.eventsource/7.0.0", + "hashPath": "microsoft.extensions.logging.eventsource.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Options/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==", + "path": "microsoft.extensions.options/7.0.0", + "hashPath": "microsoft.extensions.options.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Options.ConfigurationExtensions/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-95UnxZkkFdXxF6vSrtJsMHCzkDeSMuUWGs2hDT54cX+U5eVajrCJ3qLyQRW+CtpTt5OJ8bmTvpQVHu1DLhH+cA==", + "path": "microsoft.extensions.options.configurationextensions/7.0.0", + "hashPath": "microsoft.extensions.options.configurationextensions.7.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==", + "path": "microsoft.extensions.primitives/7.0.0", + "hashPath": "microsoft.extensions.primitives.7.0.0.nupkg.sha512" + }, + "Scrutor/4.2.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-t5VIYA7WJXoJJo7s4DoHakMGwTu+MeEnZumMOhTCH7kz9xWha24G7dJNxWrHPlu0ZdZAS4jDZCxxAnyaBh7uYw==", + "path": "scrutor/4.2.2", + "hashPath": "scrutor.4.2.2.nupkg.sha512" + }, + "Serilog/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UPJGG8Hz12obhtAELHb0q83j0YpO1vGCypUbH0P4wMZnrpcqmrSLhHkZ/4Ojc+iNVpLwZ/wPBVC3lwSzzoZ/MQ==", + "path": "serilog/3.1.0", + "hashPath": "serilog.3.1.0.nupkg.sha512" + }, + "Serilog.Extensions.Logging/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9faU0zNQqU7I6soVhLUMYaGNpgWv6cKlKb2S5AnS8gXxzW/em5Ladm/6FMrWTnX41cdbdGPOWNAo6adi4WaJ6A==", + "path": "serilog.extensions.logging/7.0.0", + "hashPath": "serilog.extensions.logging.7.0.0.nupkg.sha512" + }, + "Serilog.Sinks.Console/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-IZ6bn79k+3SRXOBpwSOClUHikSkp2toGPCZ0teUkscv4dpDg9E2R2xVsNkLmwddE4OpNVO3N0xiYsAH556vN8Q==", + "path": "serilog.sinks.console/5.0.0", + "hashPath": "serilog.sinks.console.5.0.0.nupkg.sha512" + }, + "Serilog.Sinks.File/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==", + "path": "serilog.sinks.file/5.0.0", + "hashPath": "serilog.sinks.file.5.0.0.nupkg.sha512" + }, + "System.Buffers/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "path": "system.buffers/4.5.1", + "hashPath": "system.buffers.4.5.1.nupkg.sha512" + }, + "System.Data.DataSetExtensions/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-221clPs1445HkTBZPL+K9sDBdJRB8UN8rgjO3ztB0CQ26z//fmJXtlsr6whGatscsKGBrhJl5bwJuKSA8mwFOw==", + "path": "system.data.datasetextensions/4.5.0", + "hashPath": "system.data.datasetextensions.4.5.0.nupkg.sha512" + }, + "System.Diagnostics.EventLog/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-eUDP47obqQm3SFJfP6z+Fx2nJ4KKTQbXB4Q9Uesnzw9SbYdhjyoGXuvDn/gEmFY6N5Z3bFFbpAQGA7m6hrYJCw==", + "path": "system.diagnostics.eventlog/7.0.0", + "hashPath": "system.diagnostics.eventlog.7.0.0.nupkg.sha512" + }, + "System.Memory/4.5.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==", + "path": "system.memory/4.5.4", + "hashPath": "system.memory.4.5.4.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==", + "path": "system.runtime.compilerservices.unsafe/6.0.0", + "hashPath": "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512" + }, + "System.Text.Encodings.Web/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OP6umVGxc0Z0MvZQBVigj4/U31Pw72ITihDWP9WiWDm+q5aoe0GaJivsfYGq53o6dxH7DcXWiCTl7+0o2CGdmg==", + "path": "system.text.encodings.web/7.0.0", + "hashPath": "system.text.encodings.web.7.0.0.nupkg.sha512" + }, + "System.Text.Json/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-DaGSsVqKsn/ia6RG8frjwmJonfos0srquhw09TlT8KRw5I43E+4gs+/bZj4K0vShJ5H9imCuXupb4RmS+dBy3w==", + "path": "system.text.json/7.0.0", + "hashPath": "system.text.json.7.0.0.nupkg.sha512" + }, + "CS2-CustomVotes.Shared/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.dll b/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.dll new file mode 100644 index 0000000000000000000000000000000000000000..d713b65c35a2af82047cdb631d44b88d1cbe3070 GIT binary patch literal 30720 zcmeHw33y!9k#604yKgV*ZmC)^r;p_U$C7S0V1$~MA ziVxeSlb2SUhw)fNqzU&w560_>3Zh`cbV zV?m2)O+dAh#?qLUhyx3me(MadK~4nO^sApmV%mu+_+pGT35?f_1aP!~zGEKfG=;{_ zr3gs0>7|QsMOUKx8o8H~Q6Z?Cxhc5TS6lVCBoM`oiBh!iv)U3*c9BLsK5j6WNB~%8 z0{n~`L^n|h)zwpN98Jy3{xu|XXf`;2_Avq^V=y0A{up{90L4=c?igRtW4^%8xa@;} zJoQc0Q}@Ano)ac!ikSm1SUk=WjJ!>gYYb%3uLH4sd^qPKlf}WTS4o_ls zJmy#g%!cxo0AYs8N8igVLk#zLBc6yiVpduR6_e*+fH1q~iuYFO*oX~>|#nzQ2iUe=v`10Juw9aEE&ptT$Vk0d_9PE^u{ zwE?UcS?7b-bf#TtsX;w8g-R^(NPYE?+A;#BVi^{4Y_Q2`@dZ>KwMAQbrDtS0h6S0B zz2K-^g+}!gCN!J53sGtzQv?lbC1`6d(2~ZfNI9**LaL(Qutu!|sdvE6mu61X5IibRARMt8Ay>=9G1R2-SeK$gy;sefh(`r=#H%Jx#8mN)5RnK+ z6mWzipCvGN&<>B)KS3`tZq)H#8=F>VduEN>GisP@rws7~au^aa0to(J0KDjwU}HQ+ z;*=6q(Kn(Z%EcWo!yR;@s^|_!<3hJZUl`3IiL3uJw1fw+0ew@xTt`hes2tDpPQb>-P)tu;45GyAYceVt zO<#gTxxUGqx(`DYTru18R)`b@UC5!xURVT!)uu$$2ICNP=7W`0%<1HBT8{i7n8v4>M8icFqEF!rTpub6ZhR zKfomkB*jJ~90@J%jkS#{O&?lm4_87yMI|ob9b03f3;?^C6Bq6;i=naPndg=+2OjXsk}MA2Ao_s>eq+* zneR`Oqq~*`PD$ewpVb2-95WJE;i|N|0wN3MRG*c@rRm2%3;L#+KDB?YYEU_KE4AFk zrt-Y?({FGs`PkUD2d$m^=AJ|~V2sFj&mmB1?M2_NSeWow{;_c6VcaA2HNdzFRxiM9 z2;|WdVPY4GU3%>LvgX=B{RUcewizx-wM!|qDD(3XIT!IB&QH@ZudykNx_eZC9yP7` z_}S3rKh12g&DsJPSMoFdj9ETy?#DO%)ajaT&<#(Og_#$GpUy>Rrmb{$Z`1+%dnk0= zXQ-S|Uu}-MD#>6V<->no!onmUS!#I~jTH@>(8OFct4rE5_njkgjRVlxKu(y~qA0fq z*3}Pi$v#-9GKMN1;9{)qDCQDAf;aLu!{kkDH8`?~6$A`)Mll2dqt;;v0!E#~5M&JU z!kw@f`+%rQShGaeQm_>{6YCDQ)}%Ekqvs4Y`nsag zTr$GwkZp7V&gGyG3*H%N0p=gFpH3H0?OJEgWzcJ|p;T<(Jhkt

1E!ZA+#a;F1JJ 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 MZs2{0{@-Na-!@GNNB{r; literal 0 HcmV?d00001 diff --git a/lib/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.pdb b/lib/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.pdb new file mode 100644 index 0000000000000000000000000000000000000000..edcbdf68226bd345472cfbe5cfc152f61b4889a3 GIT binary patch literal 11896 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 xOR9>oq&#O*o+l|Ugp?;B Date: Sat, 13 Apr 2024 17:49:19 -0400 Subject: [PATCH 20/86] Version 1.0.4 --- Config.cs | 17 +++++++--- Core/MapGroupManager.cs | 34 +++++++++----------- Core/MapManager.cs | 69 +++++++++++++++++++++++------------------ Core/ModeManager.cs | 28 +++++++---------- Core/VoteManager.cs | 8 +++-- README.md | 2 -- 6 files changed, 81 insertions(+), 77 deletions(-) diff --git a/Config.cs b/Config.cs index 35c30c9..9b7243f 100644 --- a/Config.cs +++ b/Config.cs @@ -21,7 +21,7 @@ public void OnConfigParsed(Config _config) } else if(_config.RTV.Enabled == true) { - if (!File.Exists(config.RTV.Plugin)) + if (!File.Exists(_config.RTV.Plugin)) { throw new Exception($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); } @@ -47,7 +47,7 @@ public void OnConfigParsed(Config _config) if (!File.Exists(_config.MapGroup.File)) { - throw new Exception($"Cannot find map group file: {config.MapGroup.File}"); + throw new Exception($"Cannot find map group file: {_config.MapGroup.File}"); } // Game Mode Settings @@ -63,18 +63,25 @@ public void OnConfigParsed(Config _config) { throw new Exception("Game mode interval must be a number."); } - if (config.GameMode.ListEnabled != true && _config.GameMode.ListEnabled != false) + if (_config.GameMode.ListEnabled != true && _config.GameMode.ListEnabled != false) { - throw new Exception($"Invalid: Game mode list enabled should be 'true' or 'false'."); + throw new Exception("Invalid: Game mode list enabled should be 'true' or 'false'."); } else if (_config.GameMode.ListEnabled == true) { if(_config.GameMode.List == null || _config.GameMode.List.Count == 0) { - throw new Exception($"Undefined: Game mode list cannot be empty."); + throw new Exception("Undefined: Game mode list cannot be empty."); } } + + // Set config Config = _config; + + if (Config.Version < 2) + { + throw new Exception("Your config file is too old, please delete it from addons/counterstrikesharp/configs/plugins/GameModeManager and let the plugin recreate it on load."); + } } } public class Config : BasePluginConfig diff --git a/Core/MapGroupManager.cs b/Core/MapGroupManager.cs index cafa450..b5b8ea2 100644 --- a/Core/MapGroupManager.cs +++ b/Core/MapGroupManager.cs @@ -1,12 +1,9 @@ // Included libraries using System.Text; -using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; -using CounterStrikeSharp.API.Modules.Menu; -using CounterStrikeSharp.API.Modules.Timers; using CounterStrikeSharp.API.Modules.Commands; -using CounterStrikeSharp.API.Core.Translations; +using CounterStrikeSharp.API.Core.Attributes.Registration; // Copyright (c) 2016 Shravan Rajinikanth // https://github.com/shravan2x/Gameloop.Vdf/ @@ -55,7 +52,7 @@ public void Clear() // Define plugin class public partial class Plugin : BasePlugin { - // Define default maps and map group + // Define default map group and default maps private static List _defaultMaps = new List() { new Map("de_ancient"), @@ -67,15 +64,13 @@ public partial class Plugin : BasePlugin new Map("de_vertigo") }; private static MapGroup _defaultMapGroup = new MapGroup("mg_active", _defaultMaps); - - // Define current map group, current map, and map group list - public static List MapGroups = new List(); + + // Define current map group and map group list public static MapGroup CurrentMapGroup = _defaultMapGroup; - public static List Maps = new List(); - public static Map? CurrentMap; - + public static List MapGroups = new List(); + // Define function to parse map groups - private MapGroup ParseMapGroups() + private void ParseMapGroups() { try { @@ -85,7 +80,6 @@ private MapGroup ParseMapGroups() if (vdfObject == null) { throw new IOException("VDF is empty or incomplete."); - return; } else { @@ -137,7 +131,7 @@ private MapGroup ParseMapGroups() _group.Maps = _defaultMaps; } // Add map group to map group list - mapGroups.Add(_group); + MapGroups.Add(_group); } } else @@ -167,20 +161,20 @@ public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) if (player == null) { // Get map group - MapGroup? newMapGroup = mapGroups.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); + MapGroup? _mapGroup = MapGroups.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); - if (newMapGroup == null || newMapGroup.Name == null || newMapGroup.Maps == null) + if (_mapGroup == null || _mapGroup.Name == null || _mapGroup.Maps == null) { Logger.LogWarning("New map group could not be found. Setting default map group."); - newMapGroup = defaultMapGroup; + _mapGroup = _defaultMapGroup; } - Logger.LogInformation($"Current map group is {currentMapGroup.Name}."); - Logger.LogInformation($"New map group is {newMapGroup.Name}."); + Logger.LogInformation($"Current map group is {CurrentMapGroup.Name}."); + Logger.LogInformation($"New map group is {_mapGroup.Name}."); // Update map list and map menu try { - UpdateMapList(newMapGroup); + UpdateMapList(_mapGroup); } catch(Exception ex) { diff --git a/Core/MapManager.cs b/Core/MapManager.cs index 3d30d3b..d73e990 100644 --- a/Core/MapManager.cs +++ b/Core/MapManager.cs @@ -2,8 +2,12 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; +using CounterStrikeSharp.API.Modules.Menu; +using CounterStrikeSharp.API.Modules.Admin; +using CounterStrikeSharp.API.Modules.Timers; using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Core.Translations; +using CounterStrikeSharp.API.Core.Attributes.Registration; // Declare namespace namespace GameModeManager @@ -44,7 +48,10 @@ public void Clear() // Plugin class public partial class Plugin : BasePlugin { - + // Define current map and map list + public static Map? CurrentMap; + public static List Maps = new List(); + // Define function to update map list private void UpdateMapList(MapGroup _group) { @@ -109,7 +116,7 @@ private void UpdateMapMenu(MapGroup _mapGroup) { _mapMenu.AddMenuOption(_map.Name, (player, option) => { - Map? _nextMap = map; + Map? _nextMap = _map; if (_nextMap == null) { @@ -136,7 +143,7 @@ private void ChangeMap(Map _nextMap) { Server.ExecuteCommand($"changelevel \"{_nextMap.Name}\""); } - else if (nextMap.WorkshopId != null) + else if (_nextMap.WorkshopId != null) { Server.ExecuteCommand($"host_workshop_map \"{_nextMap.WorkshopId}\""); } @@ -188,40 +195,40 @@ private HookResult EventGameEnd(EventCsIntermission @event, GameEventInfo info) _counter++; return HookResult.Continue; } - } - - // Construct change map command handler - [RequiresPermissions("@css/changemap")] - [CommandHelper(minArgs: 1, usage: "[map name] optional: [id]", whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_map", "Changes the map to the map specified in the command argument.")] - public void OnMapCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null) + + // Construct change map command handler + [RequiresPermissions("@css/changemap")] + [CommandHelper(minArgs: 1, usage: "[map name] optional: [id]", whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_map", "Changes the map to the map specified in the command argument.")] + public void OnMapCommand(CCSPlayerController? player, CommandInfo command) { - Map _newMap = new Map($"{command.ArgByIndex(1)}",$"{command.ArgByIndex(2)}"); - Map? _foundMap = allMaps.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); - - if (_foundMap != null) + if(player != null && _plugin != null) { - _newMap = _foundMap; + Map _newMap = new Map($"{command.ArgByIndex(1)}",$"{command.ArgByIndex(2)}"); + Map? _foundMap = Maps.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); + + if (_foundMap != null) + { + _newMap = _foundMap; + } + // Write to chat + Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, _newMap.Name]); + // Change map + AddTimer(5.0f, () => ChangeMap(_newMap)); } - // Write to chat - Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, _newMap.Name]); - // Change map - AddTimer(5.0f, () => ChangeMap(_newMap)); } - } - // Construct admin map menu command handler - [RequiresPermissions("@css/changemap")] - [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_maps", "Provides a list of maps for the current game mode.")] - public void OnMapsCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null) + // Construct admin map menu command handler + [RequiresPermissions("@css/changemap")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_maps", "Provides a list of maps for the current game mode.")] + public void OnMapsCommand(CCSPlayerController? player, CommandInfo command) { - _mapMenu.Title = Localizer["maps.hud.menu-title"]; - MenuManager.OpenCenterHtmlMenu(_plugin, player, _mapMenu); + if(player != null && _plugin != null) + { + _mapMenu.Title = Localizer["maps.hud.menu-title"]; + MenuManager.OpenCenterHtmlMenu(_plugin, player, _mapMenu); + } } } } \ No newline at end of file diff --git a/Core/ModeManager.cs b/Core/ModeManager.cs index 3d5e2e9..df6a087 100644 --- a/Core/ModeManager.cs +++ b/Core/ModeManager.cs @@ -1,17 +1,13 @@ // Included libraries -using System.Text; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; using CounterStrikeSharp.API.Modules.Menu; +using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Timers; using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Core.Translations; - -// Copyright (c) 2016 Shravan Rajinikanth -// https://github.com/shravan2x/Gameloop.Vdf/ -using Gameloop.Vdf; -using Gameloop.Vdf.Linq; +using CounterStrikeSharp.API.Core.Attributes.Registration; // Declare namespace namespace GameModeManager @@ -37,8 +33,8 @@ private void SetupModeMenu() Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); // Change game mode - _mode = option.Text.ToLower(); - AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_mode}.cfg")); + string _option = option.Text.ToLower(); + AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_option}.cfg")); // Close menu MenuManager.CloseActiveMenu(player); @@ -48,13 +44,13 @@ private void SetupModeMenu() else { // Create menu options for each map group parsed - foreach (MapGroup _mapGroup in _mapGroups) + foreach (MapGroup _mapGroup in MapGroups) { // Split the string into parts by the underscore string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); // Get the last part (the actual map group name) - string _tempName = _nameParts[nameParts.Length - 1]; + string _tempName = _nameParts[_nameParts.Length - 1]; // Combine the capitalized first letter with the rest string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); @@ -67,8 +63,8 @@ private void SetupModeMenu() Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); // Change game mode - string _mode = option.Text.ToLower(); - AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_mode}.cfg")); + string _option = option.Text.ToLower(); + AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_option}.cfg")); // Close menu MenuManager.CloseActiveMenu(player); @@ -90,8 +86,8 @@ public void OnModeCommand(CCSPlayerController? player, CommandInfo command) Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, command.ArgByIndex(1)]); // Change game mode - string newMode = $"{command.ArgByIndex(1)}".ToLower(); - AddTimer(5.0f, () => Server.ExecuteCommand($"exec {newMode}.cfg")); + string _option = $"{command.ArgByIndex(1)}".ToLower(); + AddTimer(5.0f, () => Server.ExecuteCommand($"exec {_option}.cfg")); } } @@ -103,8 +99,8 @@ public void OnModesCommand(CCSPlayerController? player, CommandInfo command) { if(player != null && _plugin != null) { - modeMenu.Title = Localizer["mode.hud.menu-title"]; - MenuManager.OpenCenterHtmlMenu(_plugin, player, modeMenu); + _modeMenu.Title = Localizer["mode.hud.menu-title"]; + MenuManager.OpenCenterHtmlMenu(_plugin, player, _modeMenu); } } } diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs index a611c76..aca0806 100644 --- a/Core/VoteManager.cs +++ b/Core/VoteManager.cs @@ -1,8 +1,10 @@ // Included libraries using System.Text; -using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; + +// Copyright (c) 2024 imi-tat0r +// https://github.com/imi-tat0r/CS2-CustomVotes/ using CS2_CustomVotes.Shared.Models; // Declare namespace @@ -33,13 +35,13 @@ private void RegisterCustomVotes() _options.Add("Stay", new VoteOption("Keep current game mode", new List { "" })); // Create mode options for each map group - foreach (MapGroup _mapGroup in _mapGroups) + foreach (MapGroup _mapGroup in MapGroups) { // Split the string into parts by the underscore string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); // Get the last part (the actual map group name) - string _tempName = _nameParts[nameParts.Length - 1]; + string _tempName = _nameParts[_nameParts.Length - 1]; // Combine the capitalized first letter with the rest string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); diff --git a/README.md b/README.md index 7dc026d..dbbfaab 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ ![Copyright Nickj609l](https://img.shields.io/badge/Copyright-Nickj609-red) ![GitHub License](https://img.shields.io/github/license/nickj609/GameModeManager) ![Issues](https://img.shields.io/github/issues/nickj609/GameModeManager) ![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/nickj609/GameModeManager/total) ![GitHub commits since latest release](https://img.shields.io/github/commits-since/nickj609/GameModeManager/latest) - - # GameModeManager A Counter-Strike 2 server plugin inspired by the [CS2 Modded Dedicated Server by Kus](https://github.com/kus/cs2-modded-server) and the [CS2 Rock The Vote plugin by Abnerfs](https://github.com/abnerfs/cs2-rockthevote). From 4061608f79bf3ff438c78da0bc08e1a8c2d7067b Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 26 Apr 2024 20:14:08 -0400 Subject: [PATCH 21/86] Config changes --- Config.cs | 8 ++++ Core/SettingsManager.cs | 100 ++++++++++++++++++++++++++++++++++++++++ Core/VoteManager.cs | 57 ++++++++++++++++------- lang/en.json | 2 + 4 files changed, 150 insertions(+), 17 deletions(-) create mode 100644 Core/SettingsManager.cs diff --git a/Config.cs b/Config.cs index 9b7243f..bb06f22 100644 --- a/Config.cs +++ b/Config.cs @@ -95,6 +95,13 @@ public class RTVSettings } + public class GameSettings + { + [JsonPropertyName("Enabled")] public bool Enabled { get; set; } = true; // Enable game settings + [JsonPropertyName("Home")] public string Home { get; set; } = "/home/steam/cs2/game/csgo/cfg"; // Enable game settings + [JsonPropertyName("Folder")] public string Folder { get; set; } = "settings"; // Default settings folder path + } + public class MapGroupSettings { [JsonPropertyName("Delay")] public float Delay { get; set; } = 5.0f; // Map change delay in seconds @@ -130,6 +137,7 @@ public class GameModeSettings // Create config [JsonPropertyName("RTV")] public RTVSettings RTV { get; set; } = new RTVSettings(); [JsonPropertyName("MapGroup")] public MapGroupSettings MapGroup { get; set; } = new MapGroupSettings(); + [JsonPropertyName("GameSettings")] public GameSettings Settings { get; set; } = new GameSettings(); [JsonPropertyName("GameMode")] public GameModeSettings GameMode { get; set; } = new GameModeSettings(); } } \ No newline at end of file diff --git a/Core/SettingsManager.cs b/Core/SettingsManager.cs new file mode 100644 index 0000000..e43be56 --- /dev/null +++ b/Core/SettingsManager.cs @@ -0,0 +1,100 @@ +// Included libraries +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using Microsoft.Extensions.Logging; +using CounterStrikeSharp.API.Modules.Menu; +using CounterStrikeSharp.API.Modules.Admin; +using CounterStrikeSharp.API.Modules.Timers; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Core.Translations; +using CounterStrikeSharp.API.Core.Attributes.Registration; + +// Declare namespace +namespace GameModeManager +{ + public partial class Plugin : BasePlugin + { + // Define settings list and folder + public static List Settings = new List(); + + // Create settings list + private void ParseSettings() + { + // Check if the directory exists + if (Directory.Exists(Config.Settings.Folder)) + { + // Get all .cfg files + string[] _cfgFiles = Directory.GetFiles($"{Config.Settings.Home}/{Config.Settings.Folder}/", "*.cfg"); + + // Process each file + foreach (string _file in _cfgFiles) + { + string _fileName = Path.GetFileNameWithoutExtension(_file); // Extract file name without .cfg + string _capitalizedName = char.ToUpper(_fileName[0]) + _fileName.Substring(1); // Capitalize the first letter + Settings.Add(_capitalizedName); + } + } + else + { + Console.WriteLine("Settings folder not found."); + } + } + + // Create settings menu + private static CenterHtmlMenu _settingsMenu = new CenterHtmlMenu("Settings List"); + + // Setup settings menu + private void SetupSettingsMenu() + { + // Define settings menu + _settingsMenu = new CenterHtmlMenu("Settings List"); + + // Add menu option for each game setting + foreach (string _setting in Settings) + { + _settingsMenu.AddMenuOption(_setting, (player, option) => + { + // Write to chat + Server.PrintToChatAll(Localizer["changesetting.message", player.PlayerName, option.Text]); + + // Change game setting + string _option = option.Text.ToLower(); + Server.ExecuteCommand($"exec {_option}.cfg"); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + } + + // Construct change setting command handler + [RequiresPermissions("@css/cvar")] + [CommandHelper(minArgs: 1, usage: "[setting]", whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_setting", "Changes the game setting specified.")] + public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null) + { + // Write to chat + Server.PrintToChatAll(Localizer["changesetting.message", player.PlayerName, command.ArgByIndex(1)]); + + // Change game setting + string _option = $"{command.ArgByIndex(1)}".ToLower(); + Server.ExecuteCommand($"exec /settings/{_option}.cfg"); + } + } + + // Construct admin setting menu command handler + [RequiresPermissions("@css/cvar")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_settings", "Provides a list of game settings.")] + public void OnSettingsCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null) + { + _modeMenu.Title = Localizer["settings.hud.menu-title"]; + MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsMenu); + } + } + } +} diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs index aca0806..9b3c495 100644 --- a/Core/VoteManager.cs +++ b/Core/VoteManager.cs @@ -15,55 +15,75 @@ public partial class Plugin : BasePlugin private void RegisterCustomVotes() { // Define mode options - var _options = new Dictionary(); + var _modeOptions = new Dictionary(); // Create mode options if (Config.GameMode.ListEnabled) { // Add menu option for each game mode in game mode list - foreach (string mode in Config.GameMode.List) + foreach (string _mode in Config.GameMode.List) { - if(mode != null) + if(_mode != null) { - string _mode=mode.ToLower(); - _options.Add(mode, new VoteOption(mode, new List { $"exec {_mode}.cfg" })); + string _option=_mode.ToLower(); + _modeOptions.Add(_mode, new VoteOption(_mode, new List { $"exec {_option}.cfg" })); } } } else { - _options.Add("Stay", new VoteOption("Keep current game mode", new List { "" })); + _modeOptions.Add("Stay", new VoteOption("Keep current game mode", new List { "" })); // Create mode options for each map group foreach (MapGroup _mapGroup in MapGroups) { - // Split the string into parts by the underscore + // Capitalize game mode name string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); - - // Get the last part (the actual map group name) string _tempName = _nameParts[_nameParts.Length - 1]; - - // Combine the capitalized first letter with the rest string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); + // Add game mode to vote if(_mapGroupName != null) { - string _mode=_mapGroupName.ToLower(); - _options.Add(_mapGroupName, new VoteOption(_mapGroupName, new List { $"exec {_mode}.cfg" })); + string _option=_mapGroupName.ToLower(); + _modeOptions.Add(_mapGroupName, new VoteOption(_mapGroupName, new List { $"exec {_option}.cfg" })); } } } - // Add custom game modes vote + // Add game modes vote Plugin.CustomVotesApi.Get()?.AddCustomVote( "gamemode", // Command to trigger the vote new List {"gm", "changemode", "changegame"}, // aliases for the command (optional) "Vote to change game mode.", // Description "Stay", 30, // Time to vote - _options, + _modeOptions, + "center", // Menu style - "center" or "chat" + 51 // Minimum percentage of votes required + ); + + // Define setiing options + var _settingOptions = new Dictionary(); + + // Create setting options + foreach (string _setting in Settings) + { + string _option = _setting.ToLower(); + _settingOptions.Add(_setting, new VoteOption(_setting, new List { $"exec {Config.Settings.Folder}/{_option}.cfg" })); + } + + // Add game settings vote + Plugin.CustomVotesApi.Get()?.AddCustomVote( + "gamesetting", // Command to trigger the vote + new List {"gs", "changesetting", "settingchange"}, // aliases for the command (optional) + "Vote to change a game setting.", // Description + "Stay", + 30, // Time to vote + _settingOptions, "center", // Menu style - "center" or "chat" - 51); // Minimum percentage of votes required + 51 // Minimum percentage of votes required + ); // Add extend map vote Plugin.CustomVotesApi.Get()?.AddCustomVote( @@ -81,11 +101,14 @@ private void RegisterCustomVotes() { "No", new VoteOption("Don't extend", new List {""})} }, "center", // Menu style - "center" or "chat" - 51); // Minimum percentage of votes required + 51 // Minimum percentage of votes required + ); } private void DeregisterCustomVotes() { Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamemode"); + Plugin.CustomVotesApi.Get()?.RemoveCustomVote("extendmap"); + Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamesettings"); } } } \ No newline at end of file diff --git a/lang/en.json b/lang/en.json index 7987b48..02eccf5 100644 --- a/lang/en.json +++ b/lang/en.json @@ -2,6 +2,8 @@ "plugin.prefix": "[{GREEN}Server{DEFAULT}]", "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} has changed the map to {LIGHTRED}{1}{DEFAULT}.", "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} has changed the game mode to {LIGHTRED}{1}{DEFAULT}.", + "changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} has changed the game setting {LIGHTRED}{1}{DEFAULT}.", + "setting.hud.menu-title": "Settings List", "mode.hud.menu-title": "Game Mode List", "maps.hud.menu-title": "Map List" } From 28a11e1b4b7b65561b365e75e706376bfb703422 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 28 Apr 2024 18:54:48 -0400 Subject: [PATCH 22/86] ADDED: Config version checking --- Config.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Config.cs b/Config.cs index bb06f22..e5b9815 100644 --- a/Config.cs +++ b/Config.cs @@ -74,14 +74,14 @@ public void OnConfigParsed(Config _config) throw new Exception("Undefined: Game mode list cannot be empty."); } } - - // Set config - Config = _config; - - if (Config.Version < 2) + + if (_config.Version < 2) { throw new Exception("Your config file is too old, please delete it from addons/counterstrikesharp/configs/plugins/GameModeManager and let the plugin recreate it on load."); } + + // Set config + Config = _config; } } public class Config : BasePluginConfig @@ -135,6 +135,7 @@ public class GameModeSettings } // Create config + public override int Version { get; set; } = 2; [JsonPropertyName("RTV")] public RTVSettings RTV { get; set; } = new RTVSettings(); [JsonPropertyName("MapGroup")] public MapGroupSettings MapGroup { get; set; } = new MapGroupSettings(); [JsonPropertyName("GameSettings")] public GameSettings Settings { get; set; } = new GameSettings(); From fb09b18b531adb4d2a8255a968ce530153b0c1ae Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 28 Apr 2024 18:55:34 -0400 Subject: [PATCH 23/86] ADDED: Logging for parsing --- Core/SettingsManager.cs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Core/SettingsManager.cs b/Core/SettingsManager.cs index e43be56..e554293 100644 --- a/Core/SettingsManager.cs +++ b/Core/SettingsManager.cs @@ -20,23 +20,31 @@ public partial class Plugin : BasePlugin // Create settings list private void ParseSettings() { + string settingsDirectory = $"{Config.Settings.Home}/{Config.Settings.Folder}/"; // Check if the directory exists - if (Directory.Exists(Config.Settings.Folder)) + if (Directory.Exists(settingsDirectory)) { // Get all .cfg files - string[] _cfgFiles = Directory.GetFiles($"{Config.Settings.Home}/{Config.Settings.Folder}/", "*.cfg"); + string[] _cfgFiles = Directory.GetFiles(settingsDirectory, "*.cfg"); - // Process each file - foreach (string _file in _cfgFiles) + if (_cfgFiles.Length != 0) { - string _fileName = Path.GetFileNameWithoutExtension(_file); // Extract file name without .cfg - string _capitalizedName = char.ToUpper(_fileName[0]) + _fileName.Substring(1); // Capitalize the first letter - Settings.Add(_capitalizedName); + // Process each file + foreach (string _file in _cfgFiles) + { + string _fileName = Path.GetFileNameWithoutExtension(_file); // Extract file name without .cfg + string _capitalizedName = char.ToUpper(_fileName[0]) + _fileName.Substring(1); // Capitalize the first letter + Settings.Add(_capitalizedName); + } + } + else + { + Logger.LogError("Setting config files not found."); } } else { - Console.WriteLine("Settings folder not found."); + Logger.LogError("Settings folder not found."); } } From aeb52b1def869cd70b138b4d447e5ee275296efa Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 28 Apr 2024 18:56:05 -0400 Subject: [PATCH 24/86] UPDATED: Default vote options --- Core/VoteManager.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs index 9b3c495..65e3cf4 100644 --- a/Core/VoteManager.cs +++ b/Core/VoteManager.cs @@ -16,6 +16,7 @@ private void RegisterCustomVotes() { // Define mode options var _modeOptions = new Dictionary(); + _modeOptions.Add("No", new VoteOption("No", new List { "clear;" })); // Create mode options if (Config.GameMode.ListEnabled) @@ -32,8 +33,6 @@ private void RegisterCustomVotes() } else { - _modeOptions.Add("Stay", new VoteOption("Keep current game mode", new List { "" })); - // Create mode options for each map group foreach (MapGroup _mapGroup in MapGroups) { @@ -56,7 +55,7 @@ private void RegisterCustomVotes() "gamemode", // Command to trigger the vote new List {"gm", "changemode", "changegame"}, // aliases for the command (optional) "Vote to change game mode.", // Description - "Stay", + "No", 30, // Time to vote _modeOptions, "center", // Menu style - "center" or "chat" @@ -65,6 +64,7 @@ private void RegisterCustomVotes() // Define setiing options var _settingOptions = new Dictionary(); + _settingOptions.Add("No", new VoteOption("No", new List { "clear;" })); // Create setting options foreach (string _setting in Settings) @@ -78,7 +78,7 @@ private void RegisterCustomVotes() "gamesetting", // Command to trigger the vote new List {"gs", "changesetting", "settingchange"}, // aliases for the command (optional) "Vote to change a game setting.", // Description - "Stay", + "No", 30, // Time to vote _settingOptions, "center", // Menu style - "center" or "chat" @@ -90,7 +90,7 @@ private void RegisterCustomVotes() "extend", // Command to trigger the vote new List{"extendmap", "mapextend", "em"}, // aliases for the command (optional) "Vote to extend map.", // Description - "No", + "None", 30, // Time to vote new Dictionary // vote options { @@ -98,7 +98,7 @@ private void RegisterCustomVotes() { "10", new VoteOption("10 minutes", new List { "sv_cheats 0" })}, { "15", new VoteOption("15 minutes", new List { "sv_cheats 0" })}, { "20", new VoteOption("20 minutes", new List { "sv_cheats 0" })}, - { "No", new VoteOption("Don't extend", new List {""})} + { "None", new VoteOption("None", new List {"clear;"})} }, "center", // Menu style - "center" or "chat" 51 // Minimum percentage of votes required @@ -106,9 +106,9 @@ private void RegisterCustomVotes() } private void DeregisterCustomVotes() { + Plugin.CustomVotesApi.Get()?.RemoveCustomVote("extend"); Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamemode"); - Plugin.CustomVotesApi.Get()?.RemoveCustomVote("extendmap"); - Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamesettings"); + Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamesetting"); } } } \ No newline at end of file From 7b76dd3562fa03e0c69c96ad78aa0d8e85e620b1 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 28 Apr 2024 18:56:26 -0400 Subject: [PATCH 25/86] ADDED: Load setting event --- Plugin.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Plugin.cs b/Plugin.cs index 7f19221..18b38d2 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -54,12 +54,25 @@ public override void Load(bool hotReload) Logger.LogError($"{ex.Message}"); } + // Setup settings admin menu + try + { + Logger.LogInformation($"Loading settings..."); + ParseSettings(); + SetupSettingsMenu(); + } + catch(Exception ex) + { + Logger.LogError($"{ex.Message}"); + } + // Enable default map cycle if(!Config.RTV.Enabled) { RegisterEventHandler(EventGameEnd); } } + public override void OnAllPluginsLoaded(bool hotReload) { base.OnAllPluginsLoaded(hotReload); From 6c71ef843b9173828a7481a18d708379700bc442 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 28 Apr 2024 19:54:35 -0400 Subject: [PATCH 26/86] UPDATE: Restrict Cheats --- .../configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json b/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json index 5ba2d7e..58a4d79 100644 --- a/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json +++ b/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json @@ -28,7 +28,7 @@ "MinVotePercentage": -1, "Permission": { "RequiresAll": false, - "Permissions": [] + "Permissions": ["@css/cheats"] } } ], From 1104047c1249c3c00229b340a91e238e2fd90a14 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 3 May 2024 22:43:25 -0400 Subject: [PATCH 27/86] ADDED: Configs for game settings and voting --- Config.cs | 86 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/Config.cs b/Config.cs index e5b9815..3d1c8ce 100644 --- a/Config.cs +++ b/Config.cs @@ -1,7 +1,6 @@ // Included libraries using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; -using System.Text.Json.Serialization; // Declare namespace namespace GameModeManager @@ -14,7 +13,7 @@ public partial class Plugin : BasePlugin, IPluginConfig // Parse configuration object data and perform error checking public void OnConfigParsed(Config _config) { - // RTV Settings + // RTV settings if (_config.RTV.Enabled != true && _config.RTV.Enabled != false) { throw new Exception($"Invalid: RTV 'Enabled' should be 'true' or 'false'."); @@ -34,8 +33,7 @@ public void OnConfigParsed(Config _config) throw new Exception($"Invalid: RTV 'DefaultMapFormat' should be 'true' or 'false'."); } } - - // Map Group Settings + // Map group settings if (!float.TryParse(_config.MapGroup.Delay.ToString(), out _)) { throw new Exception("Map group delay must be a number."); @@ -44,13 +42,11 @@ public void OnConfigParsed(Config _config) { throw new Exception($"Undefined: Default map group can not be empty."); } - if (!File.Exists(_config.MapGroup.File)) { throw new Exception($"Cannot find map group file: {_config.MapGroup.File}"); } - - // Game Mode Settings + // Game mode settings if (_config.GameMode.Rotation != true && _config.GameMode.Rotation != false) { throw new Exception($"Invalid: Game mode rotation should be 'true' or 'false'."); @@ -74,7 +70,29 @@ public void OnConfigParsed(Config _config) throw new Exception("Undefined: Game mode list cannot be empty."); } } - + // Game Settings + if (_config.Settings.Enabled != true && _config.Settings.Enabled != false) + { + throw new Exception($"Invalid: Game setting should be 'true' or 'false'."); + } + if (!File.Exists($"{_config.Settings.Home}/{_config.Settings.Folder}")) + { + throw new Exception($"Cannot find 'Home Folder': {_config.Settings.Home}/{_config.Settings.Folder}"); + } + // Vote Settings + if (_config.Votes.Enabled != true && _config.Votes.Enabled != false) + { + throw new Exception($"Invalid: votes enabled should be 'true' or 'false'."); + } + if (_config.Votes.GameMode != true && _config.Votes.Enabled != false) + { + throw new Exception($"Invalid: gane nide should be 'true' or 'false'."); + } + if (_config.Votes.GameSetting != true && _config.Votes.Enabled != false) + { + throw new Exception($"Invalid: game settings should be 'true' or 'false'."); + } + // Config version check if (_config.Version < 2) { throw new Exception("Your config file is too old, please delete it from addons/counterstrikesharp/configs/plugins/GameModeManager and let the plugin recreate it on load."); @@ -86,36 +104,34 @@ public void OnConfigParsed(Config _config) } public class Config : BasePluginConfig { + // Define settings classes public class RTVSettings { - [JsonPropertyName("Enabled")] public bool Enabled { get; set; } = false; // Enable RTV Compatibility - [JsonPropertyName("Plugin")] public string Plugin { get; set; } = "/home/steam/cs2/game/csgo/addons/counterstrikesharp/plugins/RockTheVote/RockTheVote.dll"; // RTV plugin path - [JsonPropertyName("MapListFile")] public string MapListFile { get; set; } = "/home/steam/cs2/game/csgo/addons/counterstrikesharp/plugins/RockTheVote/maplist.txt"; // Default map list file - [JsonPropertyName("DefaultMapFormat")] public bool DefaultMapFormat { get; set; } = false; // Default file format (ws:). When set to false, uses format :. + public bool Enabled { get; set; } = false; // Enable RTV Compatibility + public string Plugin { get; set; } = "/home/steam/cs2/game/csgo/addons/counterstrikesharp/plugins/RockTheVote/RockTheVote.dll"; // RTV plugin path + public string MapListFile { get; set; } = "/home/steam/cs2/game/csgo/addons/counterstrikesharp/plugins/RockTheVote/maplist.txt"; // Default map list file + public bool DefaultMapFormat { get; set; } = false; // Default file format (ws:). When set to false, uses format :. } - public class GameSettings { - [JsonPropertyName("Enabled")] public bool Enabled { get; set; } = true; // Enable game settings - [JsonPropertyName("Home")] public string Home { get; set; } = "/home/steam/cs2/game/csgo/cfg"; // Enable game settings - [JsonPropertyName("Folder")] public string Folder { get; set; } = "settings"; // Default settings folder path + public bool Enabled { get; set; } = true; // Enable game settings + public string Home { get; set; } = "/home/steam/cs2/game/csgo/cfg"; // Enable game settings + public string Folder { get; set; } = "settings"; // Default settings folder path } - public class MapGroupSettings { - [JsonPropertyName("Delay")] public float Delay { get; set; } = 5.0f; // Map change delay in seconds - [JsonPropertyName("Default")] public string Default { get; set; } = "mg_active"; // Default map group on server start - [JsonPropertyName("File")] public string File { get; set; } = "/home/steam/cs2/game/csgo/gamemodes_server.txt"; // Default game modes and map groups file + public float Delay { get; set; } = 5.0f; // Map change delay in seconds + public string Default { get; set; } = "mg_active"; // Default map group on server start + public string File { get; set; } = "/home/steam/cs2/game/csgo/gamemodes_server.txt"; // Default game modes and map groups file } - public class GameModeSettings { - [JsonPropertyName("Rotation")] public bool Rotation { get; set; } = true; // Enables game mode rotation - [JsonPropertyName("Interval")] public int Interval { get; set; } = 4; // Changes game mode every x map rotations - [JsonPropertyName("Delay")] public float Delay { get; set; } = 5.0f; // Game mode change delay in seconds - [JsonPropertyName("ListEnabled")] public bool ListEnabled { get; set; } = true; // Enables custom game mode list. If set to false, generated from map groups. - [JsonPropertyName("List")] public List List { get; set; } = new List // Custom game mode list + public bool Rotation { get; set; } = true; // Enables game mode rotation + public int Interval { get; set; } = 4; // Changes game mode every x map rotations + public float Delay { get; set; } = 5.0f; // Game mode change delay in seconds + public bool ListEnabled { get; set; } = true; // Enables custom game mode list. If set to false, generated from map groups. + public List List { get; set; } = new List // Custom game mode list { "comp", "1v1", @@ -133,12 +149,20 @@ public class GameModeSettings "minigames" }; // Default Game Mode List } + public class VoteSettings + { + public bool Enabled { get; set; } = false; // Enables CS2-CustomVotes compatibility + public bool GameMode { get; set; } = false; // Enables vote to change game mode + public bool GameSetting { get; set; } = false; // Enables vote to change game setting + + } - // Create config + // Create config from classes public override int Version { get; set; } = 2; - [JsonPropertyName("RTV")] public RTVSettings RTV { get; set; } = new RTVSettings(); - [JsonPropertyName("MapGroup")] public MapGroupSettings MapGroup { get; set; } = new MapGroupSettings(); - [JsonPropertyName("GameSettings")] public GameSettings Settings { get; set; } = new GameSettings(); - [JsonPropertyName("GameMode")] public GameModeSettings GameMode { get; set; } = new GameModeSettings(); + public RTVSettings RTV { get; set; } = new RTVSettings(); + public MapGroupSettings MapGroup { get; set; } = new MapGroupSettings(); + public GameSettings Settings { get; set; } = new GameSettings(); + public GameModeSettings GameMode { get; set; } = new GameModeSettings(); + public VoteSettings Votes { get; set; } = new VoteSettings(); } } \ No newline at end of file From ca744261f83792157743b308c7210b744c516daa Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 3 May 2024 22:43:47 -0400 Subject: [PATCH 28/86] ADDED: Line to make things pretty --- Core/MapGroupManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/MapGroupManager.cs b/Core/MapGroupManager.cs index b5b8ea2..60c38e2 100644 --- a/Core/MapGroupManager.cs +++ b/Core/MapGroupManager.cs @@ -9,6 +9,7 @@ // https://github.com/shravan2x/Gameloop.Vdf/ using Gameloop.Vdf; using Gameloop.Vdf.Linq; +// ------------------------------------------ // Declare namespace namespace GameModeManager From 5b32dd5972f4e83431a47fb254cc1d92aa1e0a82 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 3 May 2024 22:44:25 -0400 Subject: [PATCH 29/86] ADDED: Handling with new configs --- Core/SettingsManager.cs | 198 +++++++++++++++++++++++++++++++++++----- Core/VoteManager.cs | 159 ++++++++++++++++---------------- Plugin.cs | 44 +++++---- 3 files changed, 282 insertions(+), 119 deletions(-) diff --git a/Core/SettingsManager.cs b/Core/SettingsManager.cs index e554293..8010e6a 100644 --- a/Core/SettingsManager.cs +++ b/Core/SettingsManager.cs @@ -1,7 +1,9 @@ // Included libraries +using System.Globalization; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; +using System.Text.RegularExpressions; using CounterStrikeSharp.API.Modules.Menu; using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Timers; @@ -12,15 +14,67 @@ // Declare namespace namespace GameModeManager { + public class Setting : IEquatable + { + public string Name { get; set; } + public string ConfigEnable { get; set; } + public string ConfigDisable { get; set; } + + public Setting(string name) + { + Name = name; + ConfigEnable = ""; + ConfigDisable = ""; + } + public Setting(string name, string configEnable, string configDisable) + { + Name = name; + ConfigEnable = configEnable; + ConfigDisable = configDisable; + } + + public bool Equals(Setting? other) + { + if (other == null) return false; // Handle null + return Name == other.Name && ConfigEnable == other.ConfigEnable && ConfigDisable == other.ConfigDisable; + } + + public void Clear() + { + Name = ""; + ConfigEnable = ""; + ConfigDisable = ""; + } + } public partial class Plugin : BasePlugin { - // Define settings list and folder - public static List Settings = new List(); + // Define settings list + public static List Settings = new List(); + string settingsDirectory = ""; + private string FormatSettingName(string settingName) + { + + var _name = Path.GetFileNameWithoutExtension(settingName); + var _regex = new Regex(@"^(enable_|disable_)(.*)"); + var _match = _regex.Match(_name); + + if (_match.Success) + { + _name = _match.Groups[2].Value; + _name = _name.Replace("_", " "); + return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(_name); + } + else + { + return null!; + } + } // Create settings list private void ParseSettings() { - string settingsDirectory = $"{Config.Settings.Home}/{Config.Settings.Folder}/"; + settingsDirectory = $"{Config.Settings.Home}/{Config.Settings.Folder}/"; + // Check if the directory exists if (Directory.Exists(settingsDirectory)) { @@ -29,12 +83,37 @@ private void ParseSettings() if (_cfgFiles.Length != 0) { - // Process each file + // Process each file foreach (string _file in _cfgFiles) { - string _fileName = Path.GetFileNameWithoutExtension(_file); // Extract file name without .cfg - string _capitalizedName = char.ToUpper(_fileName[0]) + _fileName.Substring(1); // Capitalize the first letter - Settings.Add(_capitalizedName); + string _fileName = FormatSettingName(_file); + + if (_fileName != null) + { + // Find existing setting if it's already in the list + var setting = Settings.FirstOrDefault(s => s.Name == _fileName); + + if (setting == null) + { + // Create a new setting if not found + setting = new Setting(_fileName); + Settings.Add(setting); + } + + // Assign config path based on prefix + if (_file.StartsWith("enable_")) + { + setting.ConfigEnable = _file; + } + else + { + setting.ConfigDisable = _file; + } + } + else + { + Logger.LogWarning($"Skipping {_file} because its missing the correct prefix."); + } } } else @@ -50,48 +129,124 @@ private void ParseSettings() // Create settings menu private static CenterHtmlMenu _settingsMenu = new CenterHtmlMenu("Settings List"); + private static CenterHtmlMenu _settingsEnableMenu = new CenterHtmlMenu("Settings List"); + private static CenterHtmlMenu _settingsDisableMenu = new CenterHtmlMenu("Settings List"); // Setup settings menu private void SetupSettingsMenu() { // Define settings menu _settingsMenu = new CenterHtmlMenu("Settings List"); + _settingsEnableMenu = new CenterHtmlMenu("Enable Settings"); + _settingsDisableMenu = new CenterHtmlMenu("Disable Settings"); + + // Add Main Menu options + _settingsMenu.AddMenuOption("Enable settings", (player, option) => + { + _settingsEnableMenu.Title = Localizer["settings.enable.hud.menu-title"]; + + if(player != null && _plugin != null) + { + // Open sub menu + MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsEnableMenu); + } + }); - // Add menu option for each game setting - foreach (string _setting in Settings) + _settingsMenu.AddMenuOption("Disable settings", (player, option) => { - _settingsMenu.AddMenuOption(_setting, (player, option) => + _settingsDisableMenu.Title = Localizer["settings.disable.hud.menu-title"]; + + if(player != null && _plugin != null) + { + // Open sub menu + MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsDisableMenu); + } + }); + + foreach (Setting _setting in Settings) + { + _settingsEnableMenu.AddMenuOption(_setting.Name, (player, option) => { // Write to chat - Server.PrintToChatAll(Localizer["changesetting.message", player.PlayerName, option.Text]); + Server.PrintToChatAll(Localizer["enable.changesetting.message", player.PlayerName, option.Text]); // Change game setting - string _option = option.Text.ToLower(); - Server.ExecuteCommand($"exec {_option}.cfg"); + Server.ExecuteCommand($"exec {settingsDirectory}{_setting.ConfigEnable}"); // Close menu MenuManager.CloseActiveMenu(player); }); } - } + foreach (Setting _setting in Settings) + { + _settingsDisableMenu.AddMenuOption(_setting.Name, (player, option) => + { + // Write to chat + Server.PrintToChatAll(Localizer["disable.changesetting.message", player.PlayerName, option.Text]); + + // Change game setting + Server.ExecuteCommand($"exec {settingsDirectory}{_setting.ConfigDisable}"); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + } // Construct change setting command handler [RequiresPermissions("@css/cvar")] - [CommandHelper(minArgs: 1, usage: "[setting]", whoCanExecute: CommandUsage.CLIENT_ONLY)] + [CommandHelper(minArgs: 2, usage: "[enable/disable] [setting name]", whoCanExecute: CommandUsage.CLIENT_ONLY)] [ConsoleCommand("css_setting", "Changes the game setting specified.")] public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) { if(player != null && _plugin != null) { - // Write to chat - Server.PrintToChatAll(Localizer["changesetting.message", player.PlayerName, command.ArgByIndex(1)]); + // Set vars + string _status = $"{command.ArgByIndex(1).ToLower()}"; + string _settingName = $"{command.ArgByIndex(2)}"; + + if (_status == "enable" && _settingName != null) + { + // Find game setting + Setting? _option = Settings.FirstOrDefault(s => s.Name == _settingName); + + if (_option == null) + { + command.ReplyToCommand($"Can't find setting: {command.ArgByIndex(2)}"); + } + else + { + // Write to chat + Server.PrintToChatAll(Localizer["enable.changesetting.message", player.PlayerName, command.ArgByIndex(2)]); + + // Change game setting + Server.ExecuteCommand($"exec settings/{_option.ConfigDisable}"); + } + } + else if (_status == "disable" && _settingName != null) + { + // Find game setting + Setting? _option = Settings.FirstOrDefault(s => s.Name == _settingName); + + if (_option == null) + { + command.ReplyToCommand($"Can't find setting: {command.ArgByIndex(2)}"); + } + else + { + // Write to chat + Server.PrintToChatAll(Localizer["disable.changesetting.message", player.PlayerName, command.ArgByIndex(2)]); - // Change game setting - string _option = $"{command.ArgByIndex(1)}".ToLower(); - Server.ExecuteCommand($"exec /settings/{_option}.cfg"); + // Change game setting + Server.ExecuteCommand($"exec settings/{_option.ConfigDisable}"); + } + } + else + { + command.ReplyToCommand($"Unexpected argument: {command.ArgByIndex(1)}"); + } } } - // Construct admin setting menu command handler [RequiresPermissions("@css/cvar")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] @@ -100,6 +255,7 @@ public void OnSettingsCommand(CCSPlayerController? player, CommandInfo command) { if(player != null && _plugin != null) { + // Open menu _modeMenu.Title = Localizer["settings.hud.menu-title"]; MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsMenu); } diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs index 65e3cf4..8c67dc9 100644 --- a/Core/VoteManager.cs +++ b/Core/VoteManager.cs @@ -6,109 +6,112 @@ // Copyright (c) 2024 imi-tat0r // https://github.com/imi-tat0r/CS2-CustomVotes/ using CS2_CustomVotes.Shared.Models; +// --------------------------------------------- // Declare namespace namespace GameModeManager { public partial class Plugin : BasePlugin { + // Create vote flags for deregistration + bool _gamemodeVote = false; + bool _settingVote = false; + + // Create register custom votes function private void RegisterCustomVotes() { - // Define mode options - var _modeOptions = new Dictionary(); - _modeOptions.Add("No", new VoteOption("No", new List { "clear;" })); - - // Create mode options - if (Config.GameMode.ListEnabled) + if(Config.Votes.GameMode) { - // Add menu option for each game mode in game mode list - foreach (string _mode in Config.GameMode.List) + // Define mode options + var _modeOptions = new Dictionary(); + _modeOptions.Add("No", new VoteOption("No", new List { "clear;" })); + + // Create mode options + if (Config.GameMode.ListEnabled) { - if(_mode != null) + // Add menu option for each game mode in game mode list + foreach (string _mode in Config.GameMode.List) { - string _option=_mode.ToLower(); - _modeOptions.Add(_mode, new VoteOption(_mode, new List { $"exec {_option}.cfg" })); + if(_mode != null) + { + string _option=_mode.ToLower(); + _modeOptions.Add(_mode, new VoteOption(_mode, new List { $"exec {_option}.cfg" })); + } } } - } - else - { - // Create mode options for each map group - foreach (MapGroup _mapGroup in MapGroups) + else { - // Capitalize game mode name - string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); - string _tempName = _nameParts[_nameParts.Length - 1]; - string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); + // Create mode options for each map group + foreach (MapGroup _mapGroup in MapGroups) + { + // Capitalize game mode name + string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); + string _tempName = _nameParts[_nameParts.Length - 1]; + string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); - // Add game mode to vote - if(_mapGroupName != null) - { - string _option=_mapGroupName.ToLower(); - _modeOptions.Add(_mapGroupName, new VoteOption(_mapGroupName, new List { $"exec {_option}.cfg" })); + // Add game mode to vote + if(_mapGroupName != null) + { + string _option=_mapGroupName.ToLower(); + _modeOptions.Add(_mapGroupName, new VoteOption(_mapGroupName, new List { $"exec {_option}.cfg" })); + } } } + // Add game modes vote + Plugin.CustomVotesApi.Get()?.AddCustomVote( + "gamemode", // Command to trigger the vote + new List {"gm", "changemode", "changegame"}, // aliases for the command (optional) + "Vote to change game mode.", // Description + "No", + 30, // Time to vote + _modeOptions, + "center", // Menu style - "center" or "chat" + 51 // Minimum percentage of votes required + ); + + // Set game mode vote flag + _gamemodeVote = true; } + if(Config.Votes.GameSetting) + { + // Define setiing options + var _settingOptions = new Dictionary(); + _settingOptions.Add("No", new VoteOption("No", new List { "clear;" })); - // Add game modes vote - Plugin.CustomVotesApi.Get()?.AddCustomVote( - "gamemode", // Command to trigger the vote - new List {"gm", "changemode", "changegame"}, // aliases for the command (optional) - "Vote to change game mode.", // Description - "No", - 30, // Time to vote - _modeOptions, - "center", // Menu style - "center" or "chat" - 51 // Minimum percentage of votes required - ); + // Create setting options + foreach (Setting _setting in Settings) + { + _settingOptions.Add($"Enable {_setting.Name}", new VoteOption($"Enable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigEnable}" })); + _settingOptions.Add($"Disable {_setting.Name}", new VoteOption($"Disable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigDisable}" })); + } - // Define setiing options - var _settingOptions = new Dictionary(); - _settingOptions.Add("No", new VoteOption("No", new List { "clear;" })); + // Add game settings vote + Plugin.CustomVotesApi.Get()?.AddCustomVote( + "gamesetting", // Command to trigger the vote + new List {"gs", "changesetting", "settingchange"}, // aliases for the command (optional) + "Vote to change a game setting.", // Description + "No", + 30, // Time to vote + _settingOptions, + "center", // Menu style - "center" or "chat" + 51 // Minimum percentage of votes required + ); - // Create setting options - foreach (string _setting in Settings) - { - string _option = _setting.ToLower(); - _settingOptions.Add(_setting, new VoteOption(_setting, new List { $"exec {Config.Settings.Folder}/{_option}.cfg" })); + // Set game setting vote flag + _settingVote = true; } - - // Add game settings vote - Plugin.CustomVotesApi.Get()?.AddCustomVote( - "gamesetting", // Command to trigger the vote - new List {"gs", "changesetting", "settingchange"}, // aliases for the command (optional) - "Vote to change a game setting.", // Description - "No", - 30, // Time to vote - _settingOptions, - "center", // Menu style - "center" or "chat" - 51 // Minimum percentage of votes required - ); - - // Add extend map vote - Plugin.CustomVotesApi.Get()?.AddCustomVote( - "extend", // Command to trigger the vote - new List{"extendmap", "mapextend", "em"}, // aliases for the command (optional) - "Vote to extend map.", // Description - "None", - 30, // Time to vote - new Dictionary // vote options - { - { "5", new VoteOption("5 minutes", new List { "sv_cheats 0" })}, - { "10", new VoteOption("10 minutes", new List { "sv_cheats 0" })}, - { "15", new VoteOption("15 minutes", new List { "sv_cheats 0" })}, - { "20", new VoteOption("20 minutes", new List { "sv_cheats 0" })}, - { "None", new VoteOption("None", new List {"clear;"})} - }, - "center", // Menu style - "center" or "chat" - 51 // Minimum percentage of votes required - ); } + // Create deregister custom votes function private void DeregisterCustomVotes() { - Plugin.CustomVotesApi.Get()?.RemoveCustomVote("extend"); - Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamemode"); - Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamesetting"); + if (_gamemodeVote == true) + { + Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamemode"); + } + if (_settingVote == true) + { + Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamesetting"); + } } } } \ No newline at end of file diff --git a/Plugin.cs b/Plugin.cs index 18b38d2..00fa1e9 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -13,7 +13,7 @@ public partial class Plugin : BasePlugin { // Define plugin details public override string ModuleName => "GameModeManager"; - public override string ModuleVersion => "1.0.3"; + public override string ModuleVersion => "1.0.4"; public override string ModuleAuthor => "Striker-Nick"; public override string ModuleDescription => "A simple plugin/module that dynamically updates any maplist.txt file based on the current mapgroup."; @@ -42,7 +42,6 @@ public override void Load(bool hotReload) { Logger.LogError($"{ex.Message}"); } - // Setup mode admin menu try { @@ -53,45 +52,50 @@ public override void Load(bool hotReload) { Logger.LogError($"{ex.Message}"); } - // Setup settings admin menu try { - Logger.LogInformation($"Loading settings..."); - ParseSettings(); - SetupSettingsMenu(); + if (Config.Settings.Enabled) + { + Logger.LogInformation($"Loading settings..."); + ParseSettings(); + SetupSettingsMenu(); + } } catch(Exception ex) { Logger.LogError($"{ex.Message}"); } - // Enable default map cycle if(!Config.RTV.Enabled) { RegisterEventHandler(EventGameEnd); } } - + // On all plugins loaded, register CS2-CustomVotes plugin if enabled in config public override void OnAllPluginsLoaded(bool hotReload) { base.OnAllPluginsLoaded(hotReload); - - try + + if (Config.Votes.Enabled) { - if (CustomVotesApi.Get() is null) + try + { + if (CustomVotesApi.Get() is null) + return; + } + catch (Exception) + { + Logger.LogWarning("CS2-CustomVotes plugin not found. Custom votes will not be registered."); return; + } + + _isCustomVotesLoaded = true; + Logger.LogInformation("Registering custom votes..."); + RegisterCustomVotes(); } - catch (Exception) - { - Logger.LogWarning("CS2-CustomVotes plugin not found. Custom votes will not be registered."); - return; - } - - _isCustomVotesLoaded = true; - Logger.LogInformation("Registering custom votes..."); - RegisterCustomVotes(); } + // Constuct unload behavior to deregister votes public override void Unload(bool hotReload) { // Deregister votes and game events From 93759cd309ea4b183e414a10d60b8fffd3e703c0 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 3 May 2024 22:45:16 -0400 Subject: [PATCH 30/86] ADDED: Game setting translations --- lang/en.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lang/en.json b/lang/en.json index 02eccf5..614958a 100644 --- a/lang/en.json +++ b/lang/en.json @@ -2,8 +2,11 @@ "plugin.prefix": "[{GREEN}Server{DEFAULT}]", "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} has changed the map to {LIGHTRED}{1}{DEFAULT}.", "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} has changed the game mode to {LIGHTRED}{1}{DEFAULT}.", - "changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} has changed the game setting {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} has {LIGHTRED}Enabled{DEFAULT} setting {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} has {LIGHTRED}Disabled{DEFAULT} setting {LIGHTRED}{1}{DEFAULT}.", "setting.hud.menu-title": "Settings List", "mode.hud.menu-title": "Game Mode List", - "maps.hud.menu-title": "Map List" + "maps.hud.menu-title": "Map List", + "settings.enable.hud.menu-title": "Enable Settings", + "settings.disable.hud.menu-title": "Disable Settings" } From a98a363ea671d2ee795bbc3b9eb2e462e211a484 Mon Sep 17 00:00:00 2001 From: Blake Kus Date: Mon, 6 May 2024 12:50:58 +1000 Subject: [PATCH 31/86] - UPDATED: Use relative paths for files to make configuration easier --- Config.cs | 59 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/Config.cs b/Config.cs index e5b9815..8fa7dd9 100644 --- a/Config.cs +++ b/Config.cs @@ -1,4 +1,5 @@ // Included libraries +using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; using System.Text.Json.Serialization; @@ -23,18 +24,52 @@ public void OnConfigParsed(Config _config) { if (!File.Exists(_config.RTV.Plugin)) { - throw new Exception($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); + string localRTVPluginPath = Path.Join(Server.GameDirectory + "/csgo/", _config.RTV.Plugin); + if (File.Exists(localRTVPluginPath)) + { + _config.RTV.Plugin = localRTVPluginPath; + } + else + { + throw new Exception($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); + } } if (!File.Exists(_config.RTV.MapListFile)) { - throw new Exception($"Cannot find RTV 'MapListFile': {_config.RTV.MapListFile}"); + string localRTVMapListFilePath = Path.Join(Server.GameDirectory + "/csgo/", _config.RTV.MapListFile); + if (File.Exists(localRTVMapListFilePath)) + { + _config.RTV.MapListFile = localRTVMapListFilePath; + } + else + { + throw new Exception($"Cannot find RTV 'MapListFile': {_config.RTV.MapListFile}"); + } } if (_config.RTV.DefaultMapFormat != true && _config.RTV.DefaultMapFormat != false) { throw new Exception($"Invalid: RTV 'DefaultMapFormat' should be 'true' or 'false'."); } } - + + // Game Settings Settings + if (_config.Settings.Enabled != true && _config.Settings.Enabled != false) + { + throw new Exception($"Invalid: Game settings 'Enabled' should be 'true' or 'false'."); + } + if (!Directory.Exists(_config.Settings.Home)) + { + string localSettingsHomePath = Path.Join(Server.GameDirectory + "/csgo/", _config.Settings.Home); + if (Directory.Exists(localSettingsHomePath)) + { + _config.Settings.Home = localSettingsHomePath; + } + else + { + throw new Exception($"Cannot find Settings 'Home': {_config.Settings.Home}"); + } + } + // Map Group Settings if (!float.TryParse(_config.MapGroup.Delay.ToString(), out _)) { @@ -47,7 +82,15 @@ public void OnConfigParsed(Config _config) if (!File.Exists(_config.MapGroup.File)) { - throw new Exception($"Cannot find map group file: {_config.MapGroup.File}"); + string localMapGroupFilePath = Path.Join(Server.GameDirectory + "/csgo/", _config.MapGroup.File); + if (File.Exists(localMapGroupFilePath)) + { + _config.MapGroup.File = localMapGroupFilePath; + } + else + { + throw new Exception($"Cannot find map group file: {_config.MapGroup.File}"); + } } // Game Mode Settings @@ -89,8 +132,8 @@ public class Config : BasePluginConfig public class RTVSettings { [JsonPropertyName("Enabled")] public bool Enabled { get; set; } = false; // Enable RTV Compatibility - [JsonPropertyName("Plugin")] public string Plugin { get; set; } = "/home/steam/cs2/game/csgo/addons/counterstrikesharp/plugins/RockTheVote/RockTheVote.dll"; // RTV plugin path - [JsonPropertyName("MapListFile")] public string MapListFile { get; set; } = "/home/steam/cs2/game/csgo/addons/counterstrikesharp/plugins/RockTheVote/maplist.txt"; // Default map list file + [JsonPropertyName("Plugin")] public string Plugin { get; set; } = "addons/counterstrikesharp/plugins/RockTheVote/RockTheVote.dll"; // RTV plugin path + [JsonPropertyName("MapListFile")] public string MapListFile { get; set; } = "addons/counterstrikesharp/plugins/RockTheVote/maplist.txt"; // Default map list file [JsonPropertyName("DefaultMapFormat")] public bool DefaultMapFormat { get; set; } = false; // Default file format (ws:). When set to false, uses format :. } @@ -98,7 +141,7 @@ public class RTVSettings public class GameSettings { [JsonPropertyName("Enabled")] public bool Enabled { get; set; } = true; // Enable game settings - [JsonPropertyName("Home")] public string Home { get; set; } = "/home/steam/cs2/game/csgo/cfg"; // Enable game settings + [JsonPropertyName("Home")] public string Home { get; set; } = "cfg"; // Enable game settings [JsonPropertyName("Folder")] public string Folder { get; set; } = "settings"; // Default settings folder path } @@ -106,7 +149,7 @@ public class MapGroupSettings { [JsonPropertyName("Delay")] public float Delay { get; set; } = 5.0f; // Map change delay in seconds [JsonPropertyName("Default")] public string Default { get; set; } = "mg_active"; // Default map group on server start - [JsonPropertyName("File")] public string File { get; set; } = "/home/steam/cs2/game/csgo/gamemodes_server.txt"; // Default game modes and map groups file + [JsonPropertyName("File")] public string File { get; set; } = "gamemodes_server.txt"; // Default game modes and map groups file } public class GameModeSettings From 0340227254a0ba277da7a932492d4304e655464a Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Mon, 27 May 2024 18:04:09 -0400 Subject: [PATCH 32/86] UPDATE: Formatting change --- Core/MapManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/MapManager.cs b/Core/MapManager.cs index d73e990..8a2c04b 100644 --- a/Core/MapManager.cs +++ b/Core/MapManager.cs @@ -226,7 +226,7 @@ public void OnMapsCommand(CCSPlayerController? player, CommandInfo command) { if(player != null && _plugin != null) { - _mapMenu.Title = Localizer["maps.hud.menu-title"]; + _mapMenu.Title = Localizer["maps.hud.menu-title"]; MenuManager.OpenCenterHtmlMenu(_plugin, player, _mapMenu); } } From 5dd1baf6b8bd35263bdbda09fbec0e5f06afef10 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Mon, 27 May 2024 18:04:47 -0400 Subject: [PATCH 33/86] UPDATE: Config changes (Thanks Kus!) --- Config.cs | 45 +++++++++--- Core/SettingsManager.cs | 150 +++++++++++++++++++++++----------------- 2 files changed, 121 insertions(+), 74 deletions(-) diff --git a/Config.cs b/Config.cs index 3d1c8ce..00eaf5c 100644 --- a/Config.cs +++ b/Config.cs @@ -9,6 +9,9 @@ public partial class Plugin : BasePlugin, IPluginConfig { // Define configuration object public required Config Config { get; set; } + public required string GameDirectory = Path.Join(Server.GameDirectory + "/csgo/"); + public required string ConfigDirectory = Path.Join(GameDirectory + "/cfg/"); + public required string SettingsDirectory = Path.Join(ConfigDirectory + "/settings/"); // Parse configuration object data and perform error checking public void OnConfigParsed(Config _config) @@ -20,11 +23,19 @@ public void OnConfigParsed(Config _config) } else if(_config.RTV.Enabled == true) { - if (!File.Exists(_config.RTV.Plugin)) + if (File.Exists(Path.Join(GameDirectory, _config.RTV.Plugin))) + { + _config.RTV.Plugin = Path.Join(GameDirectory, _config.RTV.Plugin); + } + else { throw new Exception($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); } - if (!File.Exists(_config.RTV.MapListFile)) + if (File.Exists(Path.Join(GameDirectory, _config.RTV.MapListFile))) + { + _config.RTV.MapListFile = Path.Join(GameDirectory, _config.RTV.MapListFile); + } + else { throw new Exception($"Cannot find RTV 'MapListFile': {_config.RTV.MapListFile}"); } @@ -33,6 +44,7 @@ public void OnConfigParsed(Config _config) throw new Exception($"Invalid: RTV 'DefaultMapFormat' should be 'true' or 'false'."); } } + // Map group settings if (!float.TryParse(_config.MapGroup.Delay.ToString(), out _)) { @@ -42,10 +54,15 @@ public void OnConfigParsed(Config _config) { throw new Exception($"Undefined: Default map group can not be empty."); } - if (!File.Exists(_config.MapGroup.File)) + if (File.Exists(Path.Join(GameDirectory, _config.MapGroup.File))) + { + _config.MapGroup.File = Path.Join(GameDirectory, _config.MapGroup.File); + } + else { throw new Exception($"Cannot find map group file: {_config.MapGroup.File}"); } + // Game mode settings if (_config.GameMode.Rotation != true && _config.GameMode.Rotation != false) { @@ -70,15 +87,21 @@ public void OnConfigParsed(Config _config) throw new Exception("Undefined: Game mode list cannot be empty."); } } + // Game Settings if (_config.Settings.Enabled != true && _config.Settings.Enabled != false) { throw new Exception($"Invalid: Game setting should be 'true' or 'false'."); } - if (!File.Exists($"{_config.Settings.Home}/{_config.Settings.Folder}")) + if (File.Exists(Path.Join(ConfigDirectory, _config.Settings.Folder))) + { + SettingsDirectory = Path.Join(ConfigDirectory, _config.Settings.Folder); + } + else { - throw new Exception($"Cannot find 'Home Folder': {_config.Settings.Home}/{_config.Settings.Folder}"); + throw new Exception($"Cannot find 'Settings Folder': {ConfigDirectory}{_config.Settings.Folder}"); } + // Vote Settings if (_config.Votes.Enabled != true && _config.Votes.Enabled != false) { @@ -92,6 +115,7 @@ public void OnConfigParsed(Config _config) { throw new Exception($"Invalid: game settings should be 'true' or 'false'."); } + // Config version check if (_config.Version < 2) { @@ -108,28 +132,30 @@ public class Config : BasePluginConfig public class RTVSettings { public bool Enabled { get; set; } = false; // Enable RTV Compatibility - public string Plugin { get; set; } = "/home/steam/cs2/game/csgo/addons/counterstrikesharp/plugins/RockTheVote/RockTheVote.dll"; // RTV plugin path - public string MapListFile { get; set; } = "/home/steam/cs2/game/csgo/addons/counterstrikesharp/plugins/RockTheVote/maplist.txt"; // Default map list file + public string Plugin { get; set; } = "addons/counterstrikesharp/plugins/RockTheVote/RockTheVote.dll"; // RTV plugin path + public string MapListFile { get; set; } = "addons/counterstrikesharp/plugins/RockTheVote/maplist.txt"; // Default map list file public bool DefaultMapFormat { get; set; } = false; // Default file format (ws:). When set to false, uses format :. } public class GameSettings { + public bool Enabled { get; set; } = true; // Enable game settings - public string Home { get; set; } = "/home/steam/cs2/game/csgo/cfg"; // Enable game settings public string Folder { get; set; } = "settings"; // Default settings folder path + public string Style { get; set; } = "center"; // Changes admin menu type (i.e. "chat" or "center") } public class MapGroupSettings { public float Delay { get; set; } = 5.0f; // Map change delay in seconds public string Default { get; set; } = "mg_active"; // Default map group on server start - public string File { get; set; } = "/home/steam/cs2/game/csgo/gamemodes_server.txt"; // Default game modes and map groups file + public string File { get; set; } = "gamemodes_server.txt"; // Default game modes and map groups file } public class GameModeSettings { public bool Rotation { get; set; } = true; // Enables game mode rotation public int Interval { get; set; } = 4; // Changes game mode every x map rotations public float Delay { get; set; } = 5.0f; // Game mode change delay in seconds + public string Style { get; set; } = "center"; // Changes admin menu type (i.e. "chat" or "center") public bool ListEnabled { get; set; } = true; // Enables custom game mode list. If set to false, generated from map groups. public List List { get; set; } = new List // Custom game mode list { @@ -154,6 +180,7 @@ public class VoteSettings public bool Enabled { get; set; } = false; // Enables CS2-CustomVotes compatibility public bool GameMode { get; set; } = false; // Enables vote to change game mode public bool GameSetting { get; set; } = false; // Enables vote to change game setting + public string Style { get; set; } = "center"; // Changes vote menu type (i.e. "chat" or "center") } diff --git a/Core/SettingsManager.cs b/Core/SettingsManager.cs index 8010e6a..51ac52e 100644 --- a/Core/SettingsManager.cs +++ b/Core/SettingsManager.cs @@ -46,11 +46,22 @@ public void Clear() ConfigDisable = ""; } } + + public class SettingsMenuFactory + { + public BaseMenu CreateMenu(string style) + { + if (style == "center") { + return new CenterHtmlMenu("Settings List"); + } else { + return new ChatMenu("Settings List"); + } + } + } public partial class Plugin : BasePlugin { // Define settings list public static List Settings = new List(); - string settingsDirectory = ""; private string FormatSettingName(string settingName) { @@ -73,13 +84,13 @@ private string FormatSettingName(string settingName) // Create settings list private void ParseSettings() { - settingsDirectory = $"{Config.Settings.Home}/{Config.Settings.Folder}/"; + SettingsDirectory = $"{ConfigDirectory}{Config.Settings.Folder}"; // Check if the directory exists - if (Directory.Exists(settingsDirectory)) + if (Directory.Exists(SettingsDirectory)) { // Get all .cfg files - string[] _cfgFiles = Directory.GetFiles(settingsDirectory, "*.cfg"); + string[] _cfgFiles = Directory.GetFiles(SettingsDirectory, "*.cfg"); if (_cfgFiles.Length != 0) { @@ -127,42 +138,16 @@ private void ParseSettings() } } - // Create settings menu - private static CenterHtmlMenu _settingsMenu = new CenterHtmlMenu("Settings List"); - private static CenterHtmlMenu _settingsEnableMenu = new CenterHtmlMenu("Settings List"); - private static CenterHtmlMenu _settingsDisableMenu = new CenterHtmlMenu("Settings List"); - // Setup settings menu - private void SetupSettingsMenu() + public void SetupSettingsMenu() { - // Define settings menu - _settingsMenu = new CenterHtmlMenu("Settings List"); - _settingsEnableMenu = new CenterHtmlMenu("Enable Settings"); - _settingsDisableMenu = new CenterHtmlMenu("Disable Settings"); - - // Add Main Menu options - _settingsMenu.AddMenuOption("Enable settings", (player, option) => - { - _settingsEnableMenu.Title = Localizer["settings.enable.hud.menu-title"]; - - if(player != null && _plugin != null) - { - // Open sub menu - MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsEnableMenu); - } - }); - - _settingsMenu.AddMenuOption("Disable settings", (player, option) => - { - _settingsDisableMenu.Title = Localizer["settings.disable.hud.menu-title"]; - - if(player != null && _plugin != null) - { - // Open sub menu - MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsDisableMenu); - } - }); + // Create menus + var menuFactory = new SettingsMenuFactory(); + var _settingsMenu = menuFactory.CreateMenu(Config.Settings.Style); + var _settingsEnableMenu = menuFactory.CreateMenu(Config.Settings.Style); + var _settingsDisableMenu = menuFactory.CreateMenu(Config.Settings.Style); + // Create enable menu options foreach (Setting _setting in Settings) { _settingsEnableMenu.AddMenuOption(_setting.Name, (player, option) => @@ -171,13 +156,14 @@ private void SetupSettingsMenu() Server.PrintToChatAll(Localizer["enable.changesetting.message", player.PlayerName, option.Text]); // Change game setting - Server.ExecuteCommand($"exec {settingsDirectory}{_setting.ConfigEnable}"); + Server.ExecuteCommand($"exec {SettingsDirectory}{_setting.ConfigEnable}"); // Close menu MenuManager.CloseActiveMenu(player); }); } + // Create disable menu options foreach (Setting _setting in Settings) { _settingsDisableMenu.AddMenuOption(_setting.Name, (player, option) => @@ -186,12 +172,47 @@ private void SetupSettingsMenu() Server.PrintToChatAll(Localizer["disable.changesetting.message", player.PlayerName, option.Text]); // Change game setting - Server.ExecuteCommand($"exec {settingsDirectory}{_setting.ConfigDisable}"); + Server.ExecuteCommand($"exec {SettingsDirectory}{_setting.ConfigDisable}"); // Close menu MenuManager.CloseActiveMenu(player); }); } + + // Create main menu options + _settingsMenu.AddMenuOption("Enable settings", (player, option) => + { + _settingsEnableMenu.Title = Localizer["settings.enable.hud.menu-title"]; + + if(player != null && _plugin != null) + { + if(_settingsEnableMenu is CenterHtmlMenu) + { + MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsEnableMenu); + } + else if (_settingsEnableMenu is ChatMenu) + { + MenuManager.OpenChatMenu(player, _settingsEnableMenu); + } + } + }); + _settingsMenu.AddMenuOption("Disable settings", (player, option) => + { + _settingsDisableMenu.Title = Localizer["settings.disable.hud.menu-title"]; + + if(player != null && _plugin != null) + { + // Open sub menu + if(_settingsDisableMenu is CenterHtmlMenu) + { + MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsDisableMenu); + } + else if (_settingsEnableMenu is ChatMenu) + { + MenuManager.OpenChatMenu(player, _settingsDisableMenu); + } + } + }); } // Construct change setting command handler [RequiresPermissions("@css/cvar")] @@ -201,20 +222,16 @@ public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) { if(player != null && _plugin != null) { - // Set vars + // Get args string _status = $"{command.ArgByIndex(1).ToLower()}"; string _settingName = $"{command.ArgByIndex(2)}"; - if (_status == "enable" && _settingName != null) - { - // Find game setting - Setting? _option = Settings.FirstOrDefault(s => s.Name == _settingName); + // Find game setting + Setting? _option = Settings.FirstOrDefault(s => s.Name == _settingName); - if (_option == null) - { - command.ReplyToCommand($"Can't find setting: {command.ArgByIndex(2)}"); - } - else + if(_option != null) + { + if (_status == "enable") { // Write to chat Server.PrintToChatAll(Localizer["enable.changesetting.message", player.PlayerName, command.ArgByIndex(2)]); @@ -222,17 +239,7 @@ public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) // Change game setting Server.ExecuteCommand($"exec settings/{_option.ConfigDisable}"); } - } - else if (_status == "disable" && _settingName != null) - { - // Find game setting - Setting? _option = Settings.FirstOrDefault(s => s.Name == _settingName); - - if (_option == null) - { - command.ReplyToCommand($"Can't find setting: {command.ArgByIndex(2)}"); - } - else + else if (_status == "disable") { // Write to chat Server.PrintToChatAll(Localizer["disable.changesetting.message", player.PlayerName, command.ArgByIndex(2)]); @@ -240,11 +247,16 @@ public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) // Change game setting Server.ExecuteCommand($"exec settings/{_option.ConfigDisable}"); } + else + { + + command.ReplyToCommand($"Unexpected argument: {command.ArgByIndex(1)}"); + } } else { - command.ReplyToCommand($"Unexpected argument: {command.ArgByIndex(1)}"); - } + command.ReplyToCommand($"Can't find setting: {command.ArgByIndex(2)}"); + } } } // Construct admin setting menu command handler @@ -253,11 +265,19 @@ public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) [ConsoleCommand("css_settings", "Provides a list of game settings.")] public void OnSettingsCommand(CCSPlayerController? player, CommandInfo command) { - if(player != null && _plugin != null) + if(player != null && _plugin != null && _settingsMenu != null) { // Open menu - _modeMenu.Title = Localizer["settings.hud.menu-title"]; - MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsMenu); + _settingsMenu.Title = Localizer["settings.hud.menu-title"]; + + if(_settingsMenu is CenterHtmlMenu) + { + MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsMenu); + } + else if (_settingsMenu is ChatMenu) + { + MenuManager.OpenChatMenu(player, _settingsMenu); + } } } } From 2e5309653cdba1ced3e5f5bcff04ec8fed2fb8a2 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Mon, 27 May 2024 18:06:42 -0400 Subject: [PATCH 34/86] ADDED: Language support for new huds --- lang/de.json | 17 +++++++++++------ lang/es.json | 17 +++++++++++------ lang/fr.json | 17 +++++++++++------ lang/hu.json | 17 +++++++++++------ lang/lv.json | 17 +++++++++++------ lang/nl.json | 15 ++++++++++----- lang/pl.json | 17 +++++++++++------ lang/pt-BR.json | 17 +++++++++++------ lang/ru.json | 17 +++++++++++------ lang/tr.json | 11 ++++++++--- lang/ua.json | 17 +++++++++++------ 11 files changed, 117 insertions(+), 62 deletions(-) diff --git a/lang/de.json b/lang/de.json index 2932834..8a58de1 100644 --- a/lang/de.json +++ b/lang/de.json @@ -1,7 +1,12 @@ { - "plugin.prefix": "[{GREEN}Server{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} hat die Karte zu {LIGHTRED}{1}{DEFAULT} geändert.", - "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} hat den Spielmodus zu {LIGHTRED}{1}{DEFAULT} geändert.", - "mode.hud.menu-title": "Liste der Spielmodi", - "maps.hud.menu-title": "Kartenliste" - } \ No newline at end of file + "plugin.prefix": "[{GREEN}Server{DEFAULT}]", + "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} hat die Karte zu {LIGHTRED}{1}{DEFAULT} geändert.", + "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} hat den Spielmodus zu {LIGHTRED}{1}{DEFAULT} geändert.", + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} hat die Einstellung {LIGHTRED}{1}{DEFAULT} {LIGHTRED}aktiviert{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} hat die Einstellung {LIGHTRED}{1}{DEFAULT} {LIGHTRED}deaktiviert{DEFAULT}.", + "setting.hud.menu-title": "Einstellungenliste", + "mode.hud.menu-title": "Spielmodiliste", + "maps.hud.menu-title": "Kartenliste", + "settings.enable.hud.menu-title": "Einstellungen aktivieren", + "settings.disable.hud.menu-title": "Einstellungen deaktivieren" +} \ No newline at end of file diff --git a/lang/es.json b/lang/es.json index fe3e6fa..022b51d 100644 --- a/lang/es.json +++ b/lang/es.json @@ -1,7 +1,12 @@ { - "plugin.prefix": "[{GREEN}Servidor{DEFAULT}]", - "changemap.message": "El administrador {LIGHTRED}{0}{DEFAULT} ha cambiado el mapa a {LIGHTRED}{1}{DEFAULT}.", - "changemode.message": "El administrador {LIGHTRED}{0}{DEFAULT} ha cambiado el modo de juego a {LIGHTRED}{1}{DEFAULT}.", - "mode.hud.menu-title": "Lista de modos de juego", - "maps.hud.menu-title": "Lista de mapas" - } \ No newline at end of file + "plugin.prefix": "[{GREEN}Servidor{DEFAULT}]", + "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} ha cambiado el mapa a {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} ha cambiado el modo de juego a {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} ha {LIGHTRED}habilitado{DEFAULT} la configuración {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} ha {LIGHTRED}deshabilitado{DEFAULT} la configuración {LIGHTRED}{1}{DEFAULT}.", + "setting.hud.menu-title": "Lista de ajustes", + "mode.hud.menu-title": "Lista de modos de juego", + "maps.hud.menu-title": "Lista de mapas", + "settings.enable.hud.menu-title": "Habilitar ajustes", + "settings.disable.hud.menu-title": "Deshabilitar ajustes" +} \ No newline at end of file diff --git a/lang/fr.json b/lang/fr.json index 21dfe3e..92c429c 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -1,7 +1,12 @@ { - "plugin.prefix": "[{GREEN}Serveur{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} a changé la carte en {LIGHTRED}{1}{DEFAULT}.", - "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} a changé le mode de jeu en {LIGHTRED}{1}{DEFAULT}.", - "mode.hud.menu-title": "Liste des modes de jeu", - "maps.hud.menu-title": "Liste des cartes" - } \ No newline at end of file + "plugin.prefix": "[{GREEN}Serveur{DEFAULT}]", + "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} a changé la carte en {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} a changé le mode de jeu en {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} a {LIGHTRED}activé{DEFAULT} le paramètre {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} a {LIGHTRED}désactivé{DEFAULT} le paramètre {LIGHTRED}{1}{DEFAULT}.", + "setting.hud.menu-title": "Liste des paramètres", + "mode.hud.menu-title": "Liste des modes de jeu", + "maps.hud.menu-title": "Liste des cartes", + "settings.enable.hud.menu-title": "Activer les paramètres", + "settings.disable.hud.menu-title": "Désactiver les paramètres" +} \ No newline at end of file diff --git a/lang/hu.json b/lang/hu.json index 50536df..6d14808 100644 --- a/lang/hu.json +++ b/lang/hu.json @@ -1,7 +1,12 @@ { - "plugin.prefix": "[{GREEN}Szerver{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} megváltoztatta a pályát erre: {LIGHTRED}{1}{DEFAULT}.", - "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} megváltoztatta a játékmódot erre: {LIGHTRED}{1}{DEFAULT}.", - "mode.hud.menu-title": "Játékmód-lista", - "maps.hud.menu-title": "Pályalista" - } \ No newline at end of file + "plugin.prefix": "[{GREEN}Szerver{DEFAULT}]", + "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} megváltoztatta a pályát {LIGHTRED}{1}{DEFAULT}-re.", + "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} megváltoztatta a játékmódot {LIGHTRED}{1}{DEFAULT}-re.", + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}bekapcsolta{DEFAULT} a(z) {LIGHTRED}{1}{DEFAULT} beállítást.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}kikapcsolta{DEFAULT} a(z) {LIGHTRED}{1}{DEFAULT} beállítást.", + "setting.hud.menu-title": "Beállítások listája", + "mode.hud.menu-title": "Játékmód lista", + "maps.hud.menu-title": "Pálya lista", + "settings.enable.hud.menu-title": "Beállítások engedélyezése", + "settings.disable.hud.menu-title": "Beállítások letiltása" +} \ No newline at end of file diff --git a/lang/lv.json b/lang/lv.json index 451e7b7..369f357 100644 --- a/lang/lv.json +++ b/lang/lv.json @@ -1,7 +1,12 @@ { - "plugin.prefix": "[{GREEN}Serveris{DEFAULT}]", - "changemap.message": "Admins {LIGHTRED}{0}{DEFAULT} ir nomainījis karti uz {LIGHTRED}{1}{DEFAULT}.", - "changemode.message": "Admins {LIGHTRED}{0}{DEFAULT} ir nomainījis spēles režīmu uz {LIGHTRED}{1}{DEFAULT}.", - "mode.hud.menu-title": "Spēles režīmu saraksts", - "maps.hud.menu-title": "Karšu Saraksts" - } \ No newline at end of file + "plugin.prefix": "[{GREEN}Serveris{DEFAULT}]", + "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} ir mainījis karti uz {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} ir mainījis spēles režīmu uz {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} ir {LIGHTRED}ieslēdzis{DEFAULT} iestatījumu {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} ir {LIGHTRED}atslēdzis{DEFAULT} iestatījumu {LIGHTRED}{1}{DEFAULT}.", + "setting.hud.menu-title": "Iestatījumu saraksts", + "mode.hud.menu-title": "Spēles režīmu saraksts", + "maps.hud.menu-title": "Karšu saraksts", + "settings.enable.hud.menu-title": "Iespējot iestatījumus", + "settings.disable.hud.menu-title": "Atspējot iestatījumus" +} \ No newline at end of file diff --git a/lang/nl.json b/lang/nl.json index 3eef81a..1493f65 100644 --- a/lang/nl.json +++ b/lang/nl.json @@ -1,7 +1,12 @@ { - "plugin.prefix": "[{GREEN}Server{DEFAULT}]", // Server = Server - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de map gewijzigd in {LIGHTRED}{1}{DEFAULT}.", // Admin changed map to... - "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de spelmodus gewijzigd in {LIGHTRED}{1}{DEFAULT}.", // Admin changed game mode to... - "mode.hud.menu-title": "Lijst met spelmodi", // List of game modes - "maps.hud.menu-title": "Kaartlijst" // List of maps + "plugin.prefix": "[{GREEN}Server{DEFAULT}]", + "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de map veranderd naar {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de spelmodus veranderd naar {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de instelling {LIGHTRED}{1}{DEFAULT} {LIGHTRED}ingeschakeld{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de instelling {LIGHTRED}{1}{DEFAULT} {LIGHTRED}uitgeschakeld{DEFAULT}.", + "setting.hud.menu-title": "Instellingenlijst", + "mode.hud.menu-title": "Spelmoduslijst", + "maps.hud.menu-title": "Kaartenlijst", + "settings.enable.hud.menu-title": "Instellingen inschakelen", + "settings.disable.hud.menu-title": "Instellingen uitschakelen" } \ No newline at end of file diff --git a/lang/pl.json b/lang/pl.json index 19f7c8e..52fc665 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -1,7 +1,12 @@ { - "plugin.prefix": "[{GREEN}Serwer{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} zmienił mapę na {LIGHTRED}{1}{DEFAULT}.", - "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} zmienił tryb gry na {LIGHTRED}{1}{DEFAULT}.", - "mode.hud.menu-title": "Lista trybów gry", - "maps.hud.menu-title": "Lista map" - } \ No newline at end of file + "plugin.prefix": "[{GREEN}Serwer{DEFAULT}]", + "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} zmienił mapę na {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} zmienił tryb gry na {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}włączył{DEFAULT} ustawienie {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}wyłączył{DEFAULT} ustawienie {LIGHTRED}{1}{DEFAULT}.", + "setting.hud.menu-title": "Lista ustawień", + "mode.hud.menu-title": "Lista trybów gry", + "maps.hud.menu-title": "Lista map", + "settings.enable.hud.menu-title": "Włącz ustawienia", + "settings.disable.hud.menu-title": "Wyłącz ustawienia" +} \ No newline at end of file diff --git a/lang/pt-BR.json b/lang/pt-BR.json index 75f13ca..18a9286 100644 --- a/lang/pt-BR.json +++ b/lang/pt-BR.json @@ -1,7 +1,12 @@ { - "plugin.prefix": "[{GREEN}Servidor{DEFAULT}]", // Server = Servidor - "changemap.message": "O administrador {LIGHTRED}{0}{DEFAULT} alterou o mapa para {LIGHTRED}{1}{DEFAULT}.", // Admin changed map to... - "changemode.message": "O administrador {LIGHTRED}{0}{DEFAULT} alterou o modo de jogo para {LIGHTRED}{1}{DEFAULT}.", // Admin changed game mode to... - "mode.hud.menu-title": "Lista de modos de jogo", // List of game modes - "maps.hud.menu-title": "Lista de mapas" // List of maps - } \ No newline at end of file + "plugin.prefix": "[{GREEN}Servidor{DEFAULT}]", + "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} mudou o mapa para {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} mudou o modo de jogo para {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}ativou{DEFAULT} a configuração {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}desativou{DEFAULT} a configuração {LIGHTRED}{1}{DEFAULT}.", + "setting.hud.menu-title": "Lista de Configurações", + "mode.hud.menu-title": "Lista de Modos de Jogo", + "maps.hud.menu-title": "Lista de Mapas", + "settings.enable.hud.menu-title": "Ativar Configurações", + "settings.disable.hud.menu-title": "Desativar Configurações" +} \ No newline at end of file diff --git a/lang/ru.json b/lang/ru.json index 011c968..09e6349 100644 --- a/lang/ru.json +++ b/lang/ru.json @@ -1,7 +1,12 @@ { - "plugin.prefix": "[{GREEN}Сервер{DEFAULT}]", // Server = Сервер - "changemap.message": "Администратор {LIGHTRED}{0}{DEFAULT} сменил карту на {LIGHTRED}{1}{DEFAULT}.", // Admin changed map to... - "changemode.message": "Администратор {LIGHTRED}{0}{DEFAULT} сменил игровой режим на {LIGHTRED}{1}{DEFAULT}.", // Admin changed game mode to... - "mode.hud.menu-title": "Список режимов игры", // List of game modes - "maps.hud.menu-title": "Список карт" // List of maps - } \ No newline at end of file + "plugin.prefix": "[{GREEN}Сервер{DEFAULT}]", + "changemap.message": "Администратор {LIGHTRED}{0}{DEFAULT} сменил карту на {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Администратор {LIGHTRED}{0}{DEFAULT} изменил режим игры на {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Администратор {LIGHTRED}{0}{DEFAULT} {LIGHTRED}включил{DEFAULT} настройку {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Администратор {LIGHTRED}{0}{DEFAULT} {LIGHTRED}выключил{DEFAULT} настройку {LIGHTRED}{1}{DEFAULT}.", + "setting.hud.menu-title": "Список настроек", + "mode.hud.menu-title": "Список игровых режимов", + "maps.hud.menu-title": "Список карт", + "settings.enable.hud.menu-title": "Включить настройки", + "settings.disable.hud.menu-title": "Отключить настройки" +} \ No newline at end of file diff --git a/lang/tr.json b/lang/tr.json index 33c3817..cce32db 100644 --- a/lang/tr.json +++ b/lang/tr.json @@ -1,7 +1,12 @@ { "plugin.prefix": "[{GREEN}Sunucu{DEFAULT}]", - "changemap.message": "Yönetici {LIGHTRED}{0}{DEFAULT} haritayı {LIGHTRED}{1}{DEFAULT} olarak değiştirdi.", - "changemode.message": "Yönetici {LIGHTRED}{0}{DEFAULT} oyun modunu {LIGHTRED}{1}{DEFAULT} olarak değiştirdi.", + "changemap.message": "Yönetici {LIGHTRED}{0}{DEFAULT}, haritayı {LIGHTRED}{1}{DEFAULT} olarak değiştirdi.", + "changemode.message": "Yönetici {LIGHTRED}{0}{DEFAULT}, oyun modunu {LIGHTRED}{1}{DEFAULT} olarak değiştirdi.", + "enable.changesetting.message": "Yönetici {LIGHTRED}{0}{DEFAULT}, {LIGHTRED}etkinleştirdi{DEFAULT} ayarı {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Yönetici {LIGHTRED}{0}{DEFAULT}, {LIGHTRED}devre dışı bıraktı{DEFAULT} ayarı {LIGHTRED}{1}{DEFAULT}.", + "setting.hud.menu-title": "Ayar Listesi", "mode.hud.menu-title": "Oyun Modu Listesi", - "maps.hud.menu-title": "Harita Listesi" + "maps.hud.menu-title": "Harita Listesi", + "settings.enable.hud.menu-title": "Ayarları Etkinleştir", + "settings.disable.hud.menu-title": "Ayarları Devre Dışı Bırak" } \ No newline at end of file diff --git a/lang/ua.json b/lang/ua.json index cae40b3..7a24eeb 100644 --- a/lang/ua.json +++ b/lang/ua.json @@ -1,7 +1,12 @@ { - "plugin.prefix": "[{GREEN}Сервер{DEFAULT}]", - "changemap.message": "Адмін {LIGHTRED}{0}{DEFAULT} змінив карту на {LIGHTRED}{1}{DEFAULT}.", - "changemode.message": "Адмін {LIGHTRED}{0}{DEFAULT} змінив ігровий режим на {LIGHTRED}{1}{DEFAULT}.", - "mode.hud.menu-title": "Список ігрових режимів", - "maps.hud.menu-title": "Список карт" - } \ No newline at end of file + "plugin.prefix": "[{GREEN}Сервер{DEFAULT}]", + "changemap.message": "Адміністратор {LIGHTRED}{0}{DEFAULT} змінив карту на {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Адміністратор {LIGHTRED}{0}{DEFAULT} змінив режим гри на {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Адміністратор {LIGHTRED}{0}{DEFAULT} {LIGHTRED}увімкнув{DEFAULT} налаштування {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Адміністратор {LIGHTRED}{0}{DEFAULT} {LIGHTRED}вимкнув{DEFAULT} налаштування {LIGHTRED}{1}{DEFAULT}.", + "setting.hud.menu-title": "Список налаштувань", + "mode.hud.menu-title": "Список ігрових режимів", + "maps.hud.menu-title": "Список карт", + "settings.enable.hud.menu-title": "Увімкнути налаштування", + "settings.disable.hud.menu-title": "Вимкнути налаштування" +} \ No newline at end of file From 771a0bcf0a6c94617d6528222e99d95f73f6f1e4 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Mon, 27 May 2024 18:06:50 -0400 Subject: [PATCH 35/86] Update CS2-CustomVotes.json --- .../configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json b/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json index 58a4d79..c9b9010 100644 --- a/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json +++ b/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json @@ -1,7 +1,7 @@ { "CustomVotesEnabled": true, "VoteCooldown": 60, - "ChatPrefix": "[{DarkBlue}CustomVotes{Default}]", + "ChatPrefix": "[{Green}Server{Default}]", "ForceStyle": "none", "CustomVotes": [ { From 5f3e1f6f4a192f90acf5c5e07ab20de758eeef30 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Tue, 4 Jun 2024 20:10:07 -0400 Subject: [PATCH 36/86] Version 1.0.4 Final version 1.0.4 commits. --- Config.cs | 41 +++- Core/CommandManager.cs | 169 +++++++++++++ Core/MapGroupManager.cs | 36 +-- Core/MapManager.cs | 80 +------ Core/MenuManager.cs | 224 ++++++++++++++++++ Core/ModeManager.cs | 107 --------- Core/SettingsManager.cs | 172 +------------- Core/VoteManager.cs | 78 +++++- GameModeManager.csproj | 12 +- GameModeManager.sln | 25 ++ Plugin.cs | 14 +- .../CS2-CustomVotes/CS2-CustomVotes.json | 0 .../CS2-CustomVotes.Shared.dll | Bin .../CS2-CustomVotes.Shared.pdb | Bin .../CS2-CustomVotes/CS2-CustomVotes.deps.json | 0 .../CS2-CustomVotes/CS2-CustomVotes.dll | Bin .../CS2-CustomVotes/CS2-CustomVotes.pdb | Bin .../plugins/CS2-CustomVotes/lang/cz.json | 0 .../plugins/CS2-CustomVotes/lang/de.json | 0 .../plugins/CS2-CustomVotes/lang/en.json | 0 .../plugins/CS2-CustomVotes/lang/pt-br.json | 0 .../plugins/CS2-CustomVotes/lang/pt-pt.json | 0 .../plugins/CS2-CustomVotes/lang/ru.json | 0 .../CS2-CustomVotes.Shared.deps.json | 0 .../CS2-CustomVotes.Shared.dll | Bin .../CS2-CustomVotes.Shared.pdb | Bin lib/csgo/cfg/settings/disable_bhop.cfg | 12 + lib/csgo/cfg/settings/disable_bots.cfg | 6 + lib/csgo/cfg/settings/disable_buying.cfg | 16 ++ lib/csgo/cfg/settings/disable_course.cfg | 18 ++ .../cfg/settings/disable_drop_weapons.cfg | 10 + lib/csgo/cfg/settings/disable_knifedrop.cfg | 2 + lib/csgo/cfg/settings/disable_map_voting.cfg | 9 + .../cfg/settings/disable_movement_unlock.cfg | 27 +++ lib/csgo/cfg/settings/disable_one_round.cfg | 29 +++ lib/csgo/cfg/settings/disable_scoutz.cfg | 11 + lib/csgo/cfg/settings/enable_alltalk.cfg | 15 ++ lib/csgo/cfg/settings/enable_bhop.cfg | 12 + lib/csgo/cfg/settings/enable_bots.cfg | 6 + lib/csgo/cfg/settings/enable_buying.cfg | 14 ++ lib/csgo/cfg/settings/enable_course.cfg | 20 ++ lib/csgo/cfg/settings/enable_knifedrop.cfg | 8 + .../cfg/settings/enable_movement_unlock.cfg | 28 +++ lib/csgo/cfg/settings/enable_one_round.cfg | 29 +++ lib/csgo/cfg/settings/enable_scoutz.cfg | 11 + 45 files changed, 823 insertions(+), 418 deletions(-) create mode 100644 Core/CommandManager.cs create mode 100644 Core/MenuManager.cs delete mode 100644 Core/ModeManager.cs create mode 100644 GameModeManager.sln rename lib/{ => csgo/addons}/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json (100%) rename lib/{ => csgo/addons}/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.dll (100%) rename lib/{ => csgo/addons}/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.pdb (100%) rename lib/{ => csgo/addons}/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.deps.json (100%) rename lib/{ => csgo/addons}/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.dll (100%) rename lib/{ => csgo/addons}/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.pdb (100%) rename lib/{ => csgo/addons}/counterstrikesharp/plugins/CS2-CustomVotes/lang/cz.json (100%) rename lib/{ => csgo/addons}/counterstrikesharp/plugins/CS2-CustomVotes/lang/de.json (100%) rename lib/{ => csgo/addons}/counterstrikesharp/plugins/CS2-CustomVotes/lang/en.json (100%) rename lib/{ => csgo/addons}/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-br.json (100%) rename lib/{ => csgo/addons}/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-pt.json (100%) rename lib/{ => csgo/addons}/counterstrikesharp/plugins/CS2-CustomVotes/lang/ru.json (100%) rename lib/{ => csgo/addons}/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.deps.json (100%) rename lib/{ => csgo/addons}/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.dll (100%) rename lib/{ => csgo/addons}/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.pdb (100%) create mode 100644 lib/csgo/cfg/settings/disable_bhop.cfg create mode 100644 lib/csgo/cfg/settings/disable_bots.cfg create mode 100644 lib/csgo/cfg/settings/disable_buying.cfg create mode 100644 lib/csgo/cfg/settings/disable_course.cfg create mode 100644 lib/csgo/cfg/settings/disable_drop_weapons.cfg create mode 100644 lib/csgo/cfg/settings/disable_knifedrop.cfg create mode 100644 lib/csgo/cfg/settings/disable_map_voting.cfg create mode 100644 lib/csgo/cfg/settings/disable_movement_unlock.cfg create mode 100644 lib/csgo/cfg/settings/disable_one_round.cfg create mode 100644 lib/csgo/cfg/settings/disable_scoutz.cfg create mode 100644 lib/csgo/cfg/settings/enable_alltalk.cfg create mode 100644 lib/csgo/cfg/settings/enable_bhop.cfg create mode 100644 lib/csgo/cfg/settings/enable_bots.cfg create mode 100644 lib/csgo/cfg/settings/enable_buying.cfg create mode 100644 lib/csgo/cfg/settings/enable_course.cfg create mode 100644 lib/csgo/cfg/settings/enable_knifedrop.cfg create mode 100644 lib/csgo/cfg/settings/enable_movement_unlock.cfg create mode 100644 lib/csgo/cfg/settings/enable_one_round.cfg create mode 100644 lib/csgo/cfg/settings/enable_scoutz.cfg diff --git a/Config.cs b/Config.cs index 00eaf5c..38cc58e 100644 --- a/Config.cs +++ b/Config.cs @@ -1,4 +1,5 @@ // Included libraries +using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; @@ -9,9 +10,9 @@ public partial class Plugin : BasePlugin, IPluginConfig { // Define configuration object public required Config Config { get; set; } - public required string GameDirectory = Path.Join(Server.GameDirectory + "/csgo/"); - public required string ConfigDirectory = Path.Join(GameDirectory + "/cfg/"); - public required string SettingsDirectory = Path.Join(ConfigDirectory + "/settings/"); + public static string GameDirectory = Path.Join(Server.GameDirectory + "/csgo/"); + public static string ConfigDirectory = Path.Join(GameDirectory + "/cfg/"); + public static string SettingsDirectory = Path.Join(ConfigDirectory + "/settings/"); // Parse configuration object data and perform error checking public void OnConfigParsed(Config _config) @@ -19,7 +20,8 @@ public void OnConfigParsed(Config _config) // RTV settings if (_config.RTV.Enabled != true && _config.RTV.Enabled != false) { - throw new Exception($"Invalid: RTV 'Enabled' should be 'true' or 'false'."); + Logger.LogError("Invalid: RTV 'Enabled' should be 'true' or 'false'."); + throw new Exception("Invalid: RTV 'Enabled' should be 'true' or 'false'."); } else if(_config.RTV.Enabled == true) { @@ -29,6 +31,7 @@ public void OnConfigParsed(Config _config) } else { + Logger.LogError($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); throw new Exception($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); } if (File.Exists(Path.Join(GameDirectory, _config.RTV.MapListFile))) @@ -37,22 +40,26 @@ public void OnConfigParsed(Config _config) } else { + Logger.LogError($"Cannot find RTV 'MapListFile': {_config.RTV.MapListFile}"); throw new Exception($"Cannot find RTV 'MapListFile': {_config.RTV.MapListFile}"); } if (_config.RTV.DefaultMapFormat != true && _config.RTV.DefaultMapFormat != false) { - throw new Exception($"Invalid: RTV 'DefaultMapFormat' should be 'true' or 'false'."); + Logger.LogError("Invalid: RTV 'DefaultMapFormat' should be 'true' or 'false'."); + throw new Exception("Invalid: RTV 'DefaultMapFormat' should be 'true' or 'false'."); } } // Map group settings if (!float.TryParse(_config.MapGroup.Delay.ToString(), out _)) { + Logger.LogError("Map group delay must be a number."); throw new Exception("Map group delay must be a number."); } if (_config.MapGroup.Default == null) { - throw new Exception($"Undefined: Default map group can not be empty."); + Logger.LogError("Undefined: Default map group can not be empty."); + throw new Exception("Undefined: Default map group can not be empty."); } if (File.Exists(Path.Join(GameDirectory, _config.MapGroup.File))) { @@ -60,30 +67,36 @@ public void OnConfigParsed(Config _config) } else { + Logger.LogError($"Cannot find map group file: {_config.MapGroup.File}"); throw new Exception($"Cannot find map group file: {_config.MapGroup.File}"); } // Game mode settings if (_config.GameMode.Rotation != true && _config.GameMode.Rotation != false) { - throw new Exception($"Invalid: Game mode rotation should be 'true' or 'false'."); + Logger.LogError("Invalid: Game mode rotation should be 'true' or 'false'."); + throw new Exception("Invalid: Game mode rotation should be 'true' or 'false'."); } if (!float.TryParse(_config.GameMode.Delay.ToString(), out _)) { + Logger.LogError("Game mode delay must be a number."); throw new Exception("Game mode delay must be a number."); } if (!int.TryParse(_config.GameMode.Interval.ToString(), out _)) { + Logger.LogError("Game mode interval must be a number."); throw new Exception("Game mode interval must be a number."); } if (_config.GameMode.ListEnabled != true && _config.GameMode.ListEnabled != false) { + Logger.LogError("Invalid: Game mode list enabled should be 'true' or 'false'."); throw new Exception("Invalid: Game mode list enabled should be 'true' or 'false'."); } else if (_config.GameMode.ListEnabled == true) { if(_config.GameMode.List == null || _config.GameMode.List.Count == 0) { + Logger.LogError("Undefined: Game mode list cannot be empty."); throw new Exception("Undefined: Game mode list cannot be empty."); } } @@ -91,7 +104,8 @@ public void OnConfigParsed(Config _config) // Game Settings if (_config.Settings.Enabled != true && _config.Settings.Enabled != false) { - throw new Exception($"Invalid: Game setting should be 'true' or 'false'."); + Logger.LogError("Invalid: Game setting should be 'true' or 'false'."); + throw new Exception("Invalid: Game setting should be 'true' or 'false'."); } if (File.Exists(Path.Join(ConfigDirectory, _config.Settings.Folder))) { @@ -99,26 +113,31 @@ public void OnConfigParsed(Config _config) } else { + Logger.LogError($"Cannot find 'Settings Folder': {ConfigDirectory}{_config.Settings.Folder}"); throw new Exception($"Cannot find 'Settings Folder': {ConfigDirectory}{_config.Settings.Folder}"); } // Vote Settings if (_config.Votes.Enabled != true && _config.Votes.Enabled != false) { - throw new Exception($"Invalid: votes enabled should be 'true' or 'false'."); + Logger.LogError("Invalid: votes enabled should be 'true' or 'false'."); + throw new Exception("Invalid: votes enabled should be 'true' or 'false'."); } if (_config.Votes.GameMode != true && _config.Votes.Enabled != false) { - throw new Exception($"Invalid: gane nide should be 'true' or 'false'."); + Logger.LogError("Invalid: gane nide should be 'true' or 'false'."); + throw new Exception("Invalid: gane nide should be 'true' or 'false'."); } if (_config.Votes.GameSetting != true && _config.Votes.Enabled != false) { - throw new Exception($"Invalid: game settings should be 'true' or 'false'."); + Logger.LogError("Invalid: game settings should be 'true' or 'false'."); + throw new Exception("Invalid: game settings should be 'true' or 'false'."); } // Config version check if (_config.Version < 2) { + Logger.LogError("Your config file is too old, please delete it from addons/counterstrikesharp/configs/plugins/GameModeManager and let the plugin recreate it on load."); throw new Exception("Your config file is too old, please delete it from addons/counterstrikesharp/configs/plugins/GameModeManager and let the plugin recreate it on load."); } diff --git a/Core/CommandManager.cs b/Core/CommandManager.cs new file mode 100644 index 0000000..c52284d --- /dev/null +++ b/Core/CommandManager.cs @@ -0,0 +1,169 @@ +// Included libraries +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using Microsoft.Extensions.Logging; +using CounterStrikeSharp.API.Modules.Admin; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Core.Attributes.Registration; + +// Declare namespace +namespace GameModeManager +{ + public partial class Plugin : BasePlugin + { + // Construct server map group command handler + [ConsoleCommand("css_mapgroup", "Sets the mapgroup for the MapListUpdater plugin.")] + [CommandHelper(minArgs: 1, usage: "mg_active", whoCanExecute: CommandUsage.SERVER_ONLY)] + public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) + { + if (player == null) + { + // Get map group + MapGroup? _mapGroup = MapGroups.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); + + if (_mapGroup == null || _mapGroup.Name == null || _mapGroup.Maps == null) + { + Logger.LogWarning("New map group could not be found. Setting default map group."); + _mapGroup = _defaultMapGroup; + } + Logger.LogInformation($"Current map group is {CurrentMapGroup.Name}."); + Logger.LogInformation($"New map group is {_mapGroup.Name}."); + + // Update map list and map menu + try + { + UpdateMapList(_mapGroup); + } + catch(Exception ex) + { + Logger.LogError($"{ex.Message}"); + } + } + } + + // Construct admin map menu command handler + [RequiresPermissions("@css/changemap")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_maps", "Provides a list of maps for the current game mode.")] + public void OnMapsCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null && MapMenu != null) + { + MapMenu.Title = Localizer["maps.hud.menu-title"]; + OpenMenu(MapMenu, Config.GameMode.Style, player); + } + } + + // Construct change map command handler + [RequiresPermissions("@css/changemap")] + [CommandHelper(minArgs: 1, usage: "[map name] optional: [id]", whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_map", "Changes the map to the map specified in the command argument.")] + public void OnMapCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null) + { + Map _newMap = new Map($"{command.ArgByIndex(1)}",$"{command.ArgByIndex(2)}"); + Map? _foundMap = Maps.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); + + if (_foundMap != null) + { + _newMap = _foundMap; + } + // Write to chat + Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, _newMap.Name]); + // Change map + AddTimer(5.0f, () => ChangeMap(_newMap)); + } + } + + // Construct change mode command handler + [RequiresPermissions("@css/changemap")] + [CommandHelper(minArgs: 1, usage: "[mode]", whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_mode", "Changes the game mode to the mode specified in the command argument.")] + public void OnModeCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null) + { + // Write to chat + Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, command.ArgByIndex(1)]); + + // Change game mode + string _option = $"{command.ArgByIndex(1)}".ToLower(); + AddTimer(5.0f, () => Server.ExecuteCommand($"exec {_option}.cfg")); + } + } + + // Construct admin mode menu command handler + [RequiresPermissions("@css/changemap")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_modes", "Provides a list of game modes.")] + public void OnModesCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null && ModeMenu != null) + { + ModeMenu.Title = Localizer["mode.hud.menu-title"]; + OpenMenu(ModeMenu, Config.GameMode.Style, player); + } + } + + // Construct change setting command handler + [RequiresPermissions("@css/cvar")] + [CommandHelper(minArgs: 2, usage: "[enable/disable] [setting name]", whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_setting", "Changes the game setting specified.")] + public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null) + { + // Get args + string _status = $"{command.ArgByIndex(1).ToLower()}"; + string _settingName = $"{command.ArgByIndex(2)}"; + + // Find game setting + Setting? _option = Settings.FirstOrDefault(s => s.Name == _settingName); + + if(_option != null) + { + if (_status == "enable") + { + // Write to chat + Server.PrintToChatAll(Localizer["enable.changesetting.message", player.PlayerName, command.ArgByIndex(2)]); + + // Change game setting + Server.ExecuteCommand($"exec settings/{_option.ConfigDisable}"); + } + else if (_status == "disable") + { + // Write to chat + Server.PrintToChatAll(Localizer["disable.changesetting.message", player.PlayerName, command.ArgByIndex(2)]); + + // Change game setting + Server.ExecuteCommand($"exec settings/{_option.ConfigDisable}"); + } + else + { + + command.ReplyToCommand($"Unexpected argument: {command.ArgByIndex(1)}"); + } + } + else + { + command.ReplyToCommand($"Can't find setting: {command.ArgByIndex(2)}"); + } + } + } + + // Construct admin setting menu command handler + [RequiresPermissions("@css/cvar")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_settings", "Provides a list of game settings.")] + public void OnSettingsCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null && SettingsMenu != null) + { + // Open menu + SettingsMenu.Title = Localizer["settings.hud.menu-title"]; + OpenMenu(SettingsMenu, Config.Settings.Style, player); + } + } + } +} \ No newline at end of file diff --git a/Core/MapGroupManager.cs b/Core/MapGroupManager.cs index 60c38e2..0898365 100644 --- a/Core/MapGroupManager.cs +++ b/Core/MapGroupManager.cs @@ -2,8 +2,6 @@ using System.Text; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; -using CounterStrikeSharp.API.Modules.Commands; -using CounterStrikeSharp.API.Core.Attributes.Registration; // Copyright (c) 2016 Shravan Rajinikanth // https://github.com/shravan2x/Gameloop.Vdf/ @@ -70,7 +68,7 @@ public partial class Plugin : BasePlugin public static MapGroup CurrentMapGroup = _defaultMapGroup; public static List MapGroups = new List(); - // Define function to parse map groups + // Construct reusable function to parse map groups private void ParseMapGroups() { try @@ -95,7 +93,7 @@ private void ParseMapGroups() { foreach (VProperty _mapGroup in _mapGroups.OfType()) { - // Create map group + // Set map group MapGroup _group = new MapGroup(_mapGroup.Key); // Create an array of maps @@ -153,35 +151,5 @@ private void ParseMapGroups() Logger.LogError($"{ex.Message}"); } } - - // Construct server map group command handler - [ConsoleCommand("css_mapgroup", "Sets the mapgroup for the MapListUpdater plugin.")] - [CommandHelper(minArgs: 1, usage: "mg_active", whoCanExecute: CommandUsage.SERVER_ONLY)] - public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) - { - if (player == null) - { - // Get map group - MapGroup? _mapGroup = MapGroups.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); - - if (_mapGroup == null || _mapGroup.Name == null || _mapGroup.Maps == null) - { - Logger.LogWarning("New map group could not be found. Setting default map group."); - _mapGroup = _defaultMapGroup; - } - Logger.LogInformation($"Current map group is {CurrentMapGroup.Name}."); - Logger.LogInformation($"New map group is {_mapGroup.Name}."); - - // Update map list and map menu - try - { - UpdateMapList(_mapGroup); - } - catch(Exception ex) - { - Logger.LogError($"{ex.Message}"); - } - } - } } } \ No newline at end of file diff --git a/Core/MapManager.cs b/Core/MapManager.cs index 8a2c04b..5385590 100644 --- a/Core/MapManager.cs +++ b/Core/MapManager.cs @@ -2,12 +2,6 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; -using CounterStrikeSharp.API.Modules.Menu; -using CounterStrikeSharp.API.Modules.Admin; -using CounterStrikeSharp.API.Modules.Timers; -using CounterStrikeSharp.API.Modules.Commands; -using CounterStrikeSharp.API.Core.Translations; -using CounterStrikeSharp.API.Core.Attributes.Registration; // Declare namespace namespace GameModeManager @@ -52,7 +46,7 @@ public partial class Plugin : BasePlugin public static Map? CurrentMap; public static List Maps = new List(); - // Define function to update map list + // Construct reusable function to update map list private void UpdateMapList(MapGroup _group) { // If using RTV Plugin @@ -103,39 +97,7 @@ private void UpdateMapList(MapGroup _group) } } - // Create map menu - private static CenterHtmlMenu _mapMenu = new CenterHtmlMenu("Map List"); - - // Define update map menu function - private void UpdateMapMenu(MapGroup _mapGroup) - { - _mapMenu = new CenterHtmlMenu("Map List"); - - // Create menu options for each map in the new map list - foreach (Map _map in _mapGroup.Maps) - { - _mapMenu.AddMenuOption(_map.Name, (player, option) => - { - Map? _nextMap = _map; - - if (_nextMap == null) - { - Logger.LogWarning("Map not found when updating map menu. Using de_dust2 for next map."); - _nextMap = new Map("de_dust2"); - } - // Write to chat - Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, _nextMap.Name]); - - // Change map - AddTimer(Config.MapGroup.Delay, () => ChangeMap(_nextMap)); - - // Close menu - MenuManager.CloseActiveMenu(player); - }); - } - } - - // Define change map function + // Construct reusable function to change map private void ChangeMap(Map _nextMap) { // If map valid, change map based on map type @@ -163,6 +125,7 @@ private HookResult EventGameEnd(EventCsIntermission @event, GameEventInfo info) Logger.LogInformation("Game has ended. Picking random map from current map group..."); Server.PrintToChatAll(Localizer["plugin.prefix"] + " Game has ended. Changing map..."); + // Check if RTV is disabled in config and if so enable randomization if(!Config.RTV.Enabled) { if(CurrentMapGroup == null) @@ -170,7 +133,7 @@ private HookResult EventGameEnd(EventCsIntermission @event, GameEventInfo info) CurrentMapGroup = _defaultMapGroup; } - // Use the random map ID in the server command. If divisible by x change mode + // Check if game mode rotation is enabled if(Config.GameMode.Rotation && (float)_counter % Config.GameMode.Interval == 0) { // Get random game mode @@ -195,40 +158,5 @@ private HookResult EventGameEnd(EventCsIntermission @event, GameEventInfo info) _counter++; return HookResult.Continue; } - - // Construct change map command handler - [RequiresPermissions("@css/changemap")] - [CommandHelper(minArgs: 1, usage: "[map name] optional: [id]", whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_map", "Changes the map to the map specified in the command argument.")] - public void OnMapCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null) - { - Map _newMap = new Map($"{command.ArgByIndex(1)}",$"{command.ArgByIndex(2)}"); - Map? _foundMap = Maps.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); - - if (_foundMap != null) - { - _newMap = _foundMap; - } - // Write to chat - Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, _newMap.Name]); - // Change map - AddTimer(5.0f, () => ChangeMap(_newMap)); - } - } - - // Construct admin map menu command handler - [RequiresPermissions("@css/changemap")] - [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_maps", "Provides a list of maps for the current game mode.")] - public void OnMapsCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null) - { - _mapMenu.Title = Localizer["maps.hud.menu-title"]; - MenuManager.OpenCenterHtmlMenu(_plugin, player, _mapMenu); - } - } } } \ No newline at end of file diff --git a/Core/MenuManager.cs b/Core/MenuManager.cs new file mode 100644 index 0000000..36ac6c9 --- /dev/null +++ b/Core/MenuManager.cs @@ -0,0 +1,224 @@ +// Included libraries +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using Microsoft.Extensions.Logging; +using CounterStrikeSharp.API.Modules.Menu; + +// Declare namespace +namespace GameModeManager +{ + public partial class Plugin : BasePlugin + { + // Construct reusable function to assign menus + private BaseMenu AssignMenu(string _menuType, string _menuName) + { + // Create base menu + BaseMenu _baseMenu; + + // Assign chat or hud menu based on config + if (_menuType == "center") + { + _baseMenu = new CenterHtmlMenu(_menuName); + } + else + { + _baseMenu = new ChatMenu(_menuName); + } + + // Return assigned menu + return _baseMenu; + } + + // Construct reusable function to open each type of menu + private void OpenMenu(BaseMenu _menu, string _menuType, CCSPlayerController _player) + { + if (_plugin != null) + { + // Check if menu type from config is hud or chat menu + if (_menuType == "center") + { + // Create tmp menu + CenterHtmlMenu? _hudMenu = _menu as CenterHtmlMenu; + + // Open menu + if (_hudMenu != null) + { + MenuManager.OpenCenterHtmlMenu(_plugin, _player, _hudMenu); + } + } + else + { + // Create tmp menu + ChatMenu? _chatMenu = _menu as ChatMenu; + + // Open menu + if (_chatMenu != null) + { + MenuManager.OpenChatMenu(_player, _chatMenu); + } + } + } + } + + // Define settings menus + public static BaseMenu? SettingsMenu; + public static BaseMenu? SettingsEnableMenu; + public static BaseMenu? SettingsDisableMenu; + + // Construct reusable function to setup settings menu + public void SetupSettingsMenu() + { + // Assign menus + SettingsMenu = AssignMenu(Config.Settings.Style, "Settings Menu"); + SettingsEnableMenu = AssignMenu(Config.Settings.Style, "Settings Menu"); + SettingsDisableMenu = AssignMenu(Config.Settings.Style, "Settings Menu"); + + // Add enable menu options + foreach (Setting _setting in Settings) + { + SettingsEnableMenu.AddMenuOption(_setting.Name, (player, option) => + { + // Write to chat + Server.PrintToChatAll(Localizer["enable.changesetting.message", player.PlayerName, option.Text]); + + // Change game setting + Server.ExecuteCommand($"exec {SettingsDirectory}{_setting.ConfigEnable}"); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + + // Add disable menu options + foreach (Setting _setting in Settings) + { + SettingsDisableMenu.AddMenuOption(_setting.Name, (player, option) => + { + // Write to chat + Server.PrintToChatAll(Localizer["disable.changesetting.message", player.PlayerName, option.Text]); + + // Change game setting + Server.ExecuteCommand($"exec {SettingsDirectory}{_setting.ConfigDisable}"); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + + // Add settings menu options + SettingsMenu.AddMenuOption("Enable settings", (player, option) => + { + SettingsEnableMenu.Title = Localizer["settings.enable.hud.menu-title"]; + + if(player != null && _plugin != null) + { + OpenMenu(SettingsEnableMenu, Config.GameMode.Style, player); + } + }); + SettingsMenu.AddMenuOption("Disable settings", (player, option) => + { + SettingsDisableMenu.Title = Localizer["settings.disable.hud.menu-title"]; + + if(player != null && _plugin != null) + { + // Open sub menu + OpenMenu(SettingsDisableMenu, Config.GameMode.Style, player); + + } + }); + } + + // Define mode menu + public static BaseMenu? ModeMenu; + + // Construct resuable function to set up mode menu + private void SetupModeMenu() + { + // Assign menu + ModeMenu = AssignMenu(Config.GameMode.Style, "Game Mode List"); + + if (Config.GameMode.ListEnabled) + { + // Add menu option for each game mode in game mode list + foreach (string _mode in Config.GameMode.List) + { + ModeMenu.AddMenuOption(_mode, (player, option) => + { + // Write to chat + Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); + + // Change game mode + string _option = option.Text.ToLower(); + AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_option}.cfg")); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + } + else + { + // Create menu options for each map group parsed + foreach (MapGroup _mapGroup in MapGroups) + { + // Split the string into parts by the underscore + string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); + + // Get the last part (the actual map group name) + string _tempName = _nameParts[_nameParts.Length - 1]; + + // Combine the capitalized first letter with the rest + string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); + + if(_mapGroupName != null) + { + ModeMenu.AddMenuOption(_mapGroupName, (player, option) => + { + // Write to chat + Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); + + // Change game mode + string _option = option.Text.ToLower(); + AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_option}.cfg")); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + } + } + } + + // Define map menu + public static BaseMenu? MapMenu; + + // Construct reusable function to update the map menu + private void UpdateMapMenu(MapGroup _mapGroup) + { + MapMenu = new CenterHtmlMenu("Map List"); + + // Add menu options for each map in the new map list + foreach (Map _map in _mapGroup.Maps) + { + MapMenu.AddMenuOption(_map.Name, (player, option) => + { + Map? _nextMap = _map; + + if (_nextMap == null) + { + Logger.LogWarning("Map not found when updating map menu. Using de_dust2 for next map."); + _nextMap = new Map("de_dust2"); + } + // Write to chat + Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, _nextMap.Name]); + + // Change map + AddTimer(Config.MapGroup.Delay, () => ChangeMap(_nextMap)); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + } + } +} \ No newline at end of file diff --git a/Core/ModeManager.cs b/Core/ModeManager.cs deleted file mode 100644 index df6a087..0000000 --- a/Core/ModeManager.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Included libraries -using CounterStrikeSharp.API; -using CounterStrikeSharp.API.Core; -using Microsoft.Extensions.Logging; -using CounterStrikeSharp.API.Modules.Menu; -using CounterStrikeSharp.API.Modules.Admin; -using CounterStrikeSharp.API.Modules.Timers; -using CounterStrikeSharp.API.Modules.Commands; -using CounterStrikeSharp.API.Core.Translations; -using CounterStrikeSharp.API.Core.Attributes.Registration; - -// Declare namespace -namespace GameModeManager -{ - public partial class Plugin : BasePlugin - { - // Create mode menu - private static CenterHtmlMenu _modeMenu = new CenterHtmlMenu("Game Mode List"); - - // Setup mode menu - private void SetupModeMenu() - { - _modeMenu = new CenterHtmlMenu("Game Mode List"); - - if (Config.GameMode.ListEnabled) - { - // Add menu option for each game mode in game mode list - foreach (string _mode in Config.GameMode.List) - { - _modeMenu.AddMenuOption(_mode, (player, option) => - { - // Write to chat - Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); - - // Change game mode - string _option = option.Text.ToLower(); - AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_option}.cfg")); - - // Close menu - MenuManager.CloseActiveMenu(player); - }); - } - } - else - { - // Create menu options for each map group parsed - foreach (MapGroup _mapGroup in MapGroups) - { - // Split the string into parts by the underscore - string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); - - // Get the last part (the actual map group name) - string _tempName = _nameParts[_nameParts.Length - 1]; - - // Combine the capitalized first letter with the rest - string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); - - if(_mapGroupName != null) - { - _modeMenu.AddMenuOption(_mapGroupName, (player, option) => - { - // Write to chat - Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); - - // Change game mode - string _option = option.Text.ToLower(); - AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_option}.cfg")); - - // Close menu - MenuManager.CloseActiveMenu(player); - }); - } - } - } - } - - // Construct change mode command handler - [RequiresPermissions("@css/changemap")] - [CommandHelper(minArgs: 1, usage: "[mode]", whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_mode", "Changes the game mode to the mode specified in the command argument.")] - public void OnModeCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null) - { - // Write to chat - Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, command.ArgByIndex(1)]); - - // Change game mode - string _option = $"{command.ArgByIndex(1)}".ToLower(); - AddTimer(5.0f, () => Server.ExecuteCommand($"exec {_option}.cfg")); - } - } - - // Construct admin mode menu command handler - [RequiresPermissions("@css/changemap")] - [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_modes", "Provides a list of game modes.")] - public void OnModesCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null) - { - _modeMenu.Title = Localizer["mode.hud.menu-title"]; - MenuManager.OpenCenterHtmlMenu(_plugin, player, _modeMenu); - } - } - } -} \ No newline at end of file diff --git a/Core/SettingsManager.cs b/Core/SettingsManager.cs index 51ac52e..dd9d745 100644 --- a/Core/SettingsManager.cs +++ b/Core/SettingsManager.cs @@ -1,19 +1,13 @@ // Included libraries using System.Globalization; -using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; using System.Text.RegularExpressions; -using CounterStrikeSharp.API.Modules.Menu; -using CounterStrikeSharp.API.Modules.Admin; -using CounterStrikeSharp.API.Modules.Timers; -using CounterStrikeSharp.API.Modules.Commands; -using CounterStrikeSharp.API.Core.Translations; -using CounterStrikeSharp.API.Core.Attributes.Registration; // Declare namespace namespace GameModeManager { + // Define setting class public class Setting : IEquatable { public string Name { get; set; } @@ -47,28 +41,21 @@ public void Clear() } } - public class SettingsMenuFactory - { - public BaseMenu CreateMenu(string style) - { - if (style == "center") { - return new CenterHtmlMenu("Settings List"); - } else { - return new ChatMenu("Settings List"); - } - } - } + // Plugin class public partial class Plugin : BasePlugin { // Define settings list public static List Settings = new List(); + + // Construct reusable function to format settings names private string FormatSettingName(string settingName) { - + // Get setting name var _name = Path.GetFileNameWithoutExtension(settingName); var _regex = new Regex(@"^(enable_|disable_)(.*)"); var _match = _regex.Match(_name); + // Format setting name if (_match.Success) { _name = _match.Groups[2].Value; @@ -81,11 +68,9 @@ private string FormatSettingName(string settingName) } } - // Create settings list + // Constuct reusable function to parse settings private void ParseSettings() { - SettingsDirectory = $"{ConfigDirectory}{Config.Settings.Folder}"; - // Check if the directory exists if (Directory.Exists(SettingsDirectory)) { @@ -137,148 +122,5 @@ private void ParseSettings() Logger.LogError("Settings folder not found."); } } - - // Setup settings menu - public void SetupSettingsMenu() - { - // Create menus - var menuFactory = new SettingsMenuFactory(); - var _settingsMenu = menuFactory.CreateMenu(Config.Settings.Style); - var _settingsEnableMenu = menuFactory.CreateMenu(Config.Settings.Style); - var _settingsDisableMenu = menuFactory.CreateMenu(Config.Settings.Style); - - // Create enable menu options - foreach (Setting _setting in Settings) - { - _settingsEnableMenu.AddMenuOption(_setting.Name, (player, option) => - { - // Write to chat - Server.PrintToChatAll(Localizer["enable.changesetting.message", player.PlayerName, option.Text]); - - // Change game setting - Server.ExecuteCommand($"exec {SettingsDirectory}{_setting.ConfigEnable}"); - - // Close menu - MenuManager.CloseActiveMenu(player); - }); - } - - // Create disable menu options - foreach (Setting _setting in Settings) - { - _settingsDisableMenu.AddMenuOption(_setting.Name, (player, option) => - { - // Write to chat - Server.PrintToChatAll(Localizer["disable.changesetting.message", player.PlayerName, option.Text]); - - // Change game setting - Server.ExecuteCommand($"exec {SettingsDirectory}{_setting.ConfigDisable}"); - - // Close menu - MenuManager.CloseActiveMenu(player); - }); - } - - // Create main menu options - _settingsMenu.AddMenuOption("Enable settings", (player, option) => - { - _settingsEnableMenu.Title = Localizer["settings.enable.hud.menu-title"]; - - if(player != null && _plugin != null) - { - if(_settingsEnableMenu is CenterHtmlMenu) - { - MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsEnableMenu); - } - else if (_settingsEnableMenu is ChatMenu) - { - MenuManager.OpenChatMenu(player, _settingsEnableMenu); - } - } - }); - _settingsMenu.AddMenuOption("Disable settings", (player, option) => - { - _settingsDisableMenu.Title = Localizer["settings.disable.hud.menu-title"]; - - if(player != null && _plugin != null) - { - // Open sub menu - if(_settingsDisableMenu is CenterHtmlMenu) - { - MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsDisableMenu); - } - else if (_settingsEnableMenu is ChatMenu) - { - MenuManager.OpenChatMenu(player, _settingsDisableMenu); - } - } - }); - } - // Construct change setting command handler - [RequiresPermissions("@css/cvar")] - [CommandHelper(minArgs: 2, usage: "[enable/disable] [setting name]", whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_setting", "Changes the game setting specified.")] - public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null) - { - // Get args - string _status = $"{command.ArgByIndex(1).ToLower()}"; - string _settingName = $"{command.ArgByIndex(2)}"; - - // Find game setting - Setting? _option = Settings.FirstOrDefault(s => s.Name == _settingName); - - if(_option != null) - { - if (_status == "enable") - { - // Write to chat - Server.PrintToChatAll(Localizer["enable.changesetting.message", player.PlayerName, command.ArgByIndex(2)]); - - // Change game setting - Server.ExecuteCommand($"exec settings/{_option.ConfigDisable}"); - } - else if (_status == "disable") - { - // Write to chat - Server.PrintToChatAll(Localizer["disable.changesetting.message", player.PlayerName, command.ArgByIndex(2)]); - - // Change game setting - Server.ExecuteCommand($"exec settings/{_option.ConfigDisable}"); - } - else - { - - command.ReplyToCommand($"Unexpected argument: {command.ArgByIndex(1)}"); - } - } - else - { - command.ReplyToCommand($"Can't find setting: {command.ArgByIndex(2)}"); - } - } - } - // Construct admin setting menu command handler - [RequiresPermissions("@css/cvar")] - [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] - [ConsoleCommand("css_settings", "Provides a list of game settings.")] - public void OnSettingsCommand(CCSPlayerController? player, CommandInfo command) - { - if(player != null && _plugin != null && _settingsMenu != null) - { - // Open menu - _settingsMenu.Title = Localizer["settings.hud.menu-title"]; - - if(_settingsMenu is CenterHtmlMenu) - { - MenuManager.OpenCenterHtmlMenu(_plugin, player, _settingsMenu); - } - else if (_settingsMenu is ChatMenu) - { - MenuManager.OpenChatMenu(player, _settingsMenu); - } - } - } } } diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs index 8c67dc9..ee2b1ea 100644 --- a/Core/VoteManager.cs +++ b/Core/VoteManager.cs @@ -1,7 +1,5 @@ // Included libraries -using System.Text; using CounterStrikeSharp.API.Core; -using Microsoft.Extensions.Logging; // Copyright (c) 2024 imi-tat0r // https://github.com/imi-tat0r/CS2-CustomVotes/ @@ -13,11 +11,11 @@ namespace GameModeManager { public partial class Plugin : BasePlugin { - // Create vote flags for deregistration + // Define vote flags for deregistration bool _gamemodeVote = false; bool _settingVote = false; - // Create register custom votes function + // Construct reusable function to register custom votes private void RegisterCustomVotes() { if(Config.Votes.GameMode) @@ -26,7 +24,7 @@ private void RegisterCustomVotes() var _modeOptions = new Dictionary(); _modeOptions.Add("No", new VoteOption("No", new List { "clear;" })); - // Create mode options + // Set mode options if (Config.GameMode.ListEnabled) { // Add menu option for each game mode in game mode list @@ -34,14 +32,31 @@ private void RegisterCustomVotes() { if(_mode != null) { + // Add mode to all modes vote string _option=_mode.ToLower(); _modeOptions.Add(_mode, new VoteOption(_mode, new List { $"exec {_option}.cfg" })); + + // Create per mode vote + Plugin.CustomVotesApi.Get()?.AddCustomVote( + _option, // Command to trigger the vote + new List(), // Aliases for the command (optional) + $"Change game mode to {_option}?", // Description + "No", + 30, // Time to vote + new Dictionary // vote options + { + { "Yes", new VoteOption("{Green}Yes", new List { $"exec {_option}.cfg" })}, + { "No", new VoteOption("{Red}No", new List { "clear;" })}, + }, + "center", // Menu style - "center" or "chat" + -1 // Minimum percentage of votes required (-1 behaves like 50%) + ); } } } else { - // Create mode options for each map group + // Add menu option for each map group foreach (MapGroup _mapGroup in MapGroups) { // Capitalize game mode name @@ -49,15 +64,33 @@ private void RegisterCustomVotes() string _tempName = _nameParts[_nameParts.Length - 1]; string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); - // Add game mode to vote if(_mapGroupName != null) { + // Add game mode to all game modes vote string _option=_mapGroupName.ToLower(); _modeOptions.Add(_mapGroupName, new VoteOption(_mapGroupName, new List { $"exec {_option}.cfg" })); + + // Create per mode vote + Plugin.CustomVotesApi.Get()?.AddCustomVote( + _option, // Command to trigger the vote + new List(), // Aliases for the command (optional) + $"Change game mode to {_option}?", // Description + "No", + 30, // Time to vote + new Dictionary // vote options + { + { "Yes", new VoteOption("{Green}Yes", new List { $"exec {_option}.cfg" })}, + { "No", new VoteOption("{Red}No", new List { "clear;" })}, + }, + "center", // Menu style - "center" or "chat" + -1 // Minimum percentage of votes required (-1 behaves like 50%) + ); } + } } - // Add game modes vote + + // Register game modes vote Plugin.CustomVotesApi.Get()?.AddCustomVote( "gamemode", // Command to trigger the vote new List {"gm", "changemode", "changegame"}, // aliases for the command (optional) @@ -66,7 +99,7 @@ private void RegisterCustomVotes() 30, // Time to vote _modeOptions, "center", // Menu style - "center" or "chat" - 51 // Minimum percentage of votes required + -1 // Minimum percentage of votes required (-1 behaves like 50%) ); // Set game mode vote flag @@ -78,14 +111,32 @@ private void RegisterCustomVotes() var _settingOptions = new Dictionary(); _settingOptions.Add("No", new VoteOption("No", new List { "clear;" })); - // Create setting options + // Set setting options foreach (Setting _setting in Settings) { + // Add options to all game settings vote _settingOptions.Add($"Enable {_setting.Name}", new VoteOption($"Enable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigEnable}" })); _settingOptions.Add($"Disable {_setting.Name}", new VoteOption($"Disable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigDisable}" })); + + // Register per game setting vote + Plugin.CustomVotesApi.Get()?.AddCustomVote( + _setting.Name, // Command to trigger the vote + new List(), // Aliases for the command (optional) + $"Change {_setting.Name}?", // Description + "No", + 30, // Time to vote + new Dictionary // vote options + { + { "Enable", new VoteOption("{Green}Enable", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigEnable}" })}, + { "Disable", new VoteOption("{Red}Disable", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigDisable}" })}, + }, + "center", // Menu style - "center" or "chat" + -1 // Minimum percentage of votes required (-1 behaves like 50%) + ); + } - // Add game settings vote + // Register all game settings vote Plugin.CustomVotesApi.Get()?.AddCustomVote( "gamesetting", // Command to trigger the vote new List {"gs", "changesetting", "settingchange"}, // aliases for the command (optional) @@ -94,14 +145,15 @@ private void RegisterCustomVotes() 30, // Time to vote _settingOptions, "center", // Menu style - "center" or "chat" - 51 // Minimum percentage of votes required + -1 // Minimum percentage of votes required (-1 behaves like 50%) ); // Set game setting vote flag _settingVote = true; } } - // Create deregister custom votes function + + // Construct reusable function to deregister custom votes private void DeregisterCustomVotes() { if (_gamemodeVote == true) diff --git a/GameModeManager.csproj b/GameModeManager.csproj index b7321a9..51e4706 100644 --- a/GameModeManager.csproj +++ b/GameModeManager.csproj @@ -16,11 +16,11 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/GameModeManager.sln b/GameModeManager.sln new file mode 100644 index 0000000..cdbde2a --- /dev/null +++ b/GameModeManager.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameModeManager", "GameModeManager.csproj", "{B0F050EF-23D3-4424-9745-741042122EAF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B0F050EF-23D3-4424-9745-741042122EAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0F050EF-23D3-4424-9745-741042122EAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0F050EF-23D3-4424-9745-741042122EAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0F050EF-23D3-4424-9745-741042122EAF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B4CE33F4-A897-45D7-91ED-45050C310202} + EndGlobalSection +EndGlobal diff --git a/Plugin.cs b/Plugin.cs index 00fa1e9..666091c 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -1,5 +1,4 @@ // Included libraries -using CounterStrikeSharp.API; using CS2_CustomVotes.Shared; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; @@ -15,7 +14,7 @@ public partial class Plugin : BasePlugin public override string ModuleName => "GameModeManager"; public override string ModuleVersion => "1.0.4"; public override string ModuleAuthor => "Striker-Nick"; - public override string ModuleDescription => "A simple plugin/module that dynamically updates any maplist.txt file based on the current mapgroup."; + public override string ModuleDescription => "A simple plugin to manage custom game modes and map rotations."; // Define plugin private BasePlugin? _plugin; @@ -42,7 +41,8 @@ public override void Load(bool hotReload) { Logger.LogError($"{ex.Message}"); } - // Setup mode admin menu + + // Create mode menu try { Logger.LogInformation($"Creating game modes..."); @@ -52,7 +52,8 @@ public override void Load(bool hotReload) { Logger.LogError($"{ex.Message}"); } - // Setup settings admin menu + + // Create settings menu try { if (Config.Settings.Enabled) @@ -66,13 +67,14 @@ public override void Load(bool hotReload) { Logger.LogError($"{ex.Message}"); } - // Enable default map cycle + + // Register EvenGameEnd handler if RTV is not enabled to perform map and game mode rotations if(!Config.RTV.Enabled) { RegisterEventHandler(EventGameEnd); } } - // On all plugins loaded, register CS2-CustomVotes plugin if enabled in config + // When all plugins are loaded, register the CS2-CustomVotes plugin if it is enabled in the config public override void OnAllPluginsLoaded(bool hotReload) { base.OnAllPluginsLoaded(hotReload); diff --git a/lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json b/lib/csgo/addons/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json similarity index 100% rename from lib/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json rename to lib/csgo/addons/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.dll b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.dll similarity index 100% rename from lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.dll rename to lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.dll diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.pdb b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.pdb similarity index 100% rename from lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.pdb rename to lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.Shared.pdb diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.deps.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.deps.json similarity index 100% rename from lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.deps.json rename to lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.deps.json diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.dll b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.dll similarity index 100% rename from lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.dll rename to lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.dll diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.pdb b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.pdb similarity index 100% rename from lib/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.pdb rename to lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/CS2-CustomVotes.pdb diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/cz.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/cz.json similarity index 100% rename from lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/cz.json rename to lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/cz.json diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/de.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/de.json similarity index 100% rename from lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/de.json rename to lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/de.json diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/en.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/en.json similarity index 100% rename from lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/en.json rename to lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/en.json diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-br.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-br.json similarity index 100% rename from lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-br.json rename to lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-br.json diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-pt.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-pt.json similarity index 100% rename from lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-pt.json rename to lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-pt.json diff --git a/lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/ru.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/ru.json similarity index 100% rename from lib/counterstrikesharp/plugins/CS2-CustomVotes/lang/ru.json rename to lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/ru.json diff --git a/lib/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.deps.json b/lib/csgo/addons/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.deps.json similarity index 100% rename from lib/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.deps.json rename to lib/csgo/addons/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.deps.json diff --git a/lib/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.dll b/lib/csgo/addons/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.dll similarity index 100% rename from lib/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.dll rename to lib/csgo/addons/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.dll diff --git a/lib/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.pdb b/lib/csgo/addons/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.pdb similarity index 100% rename from lib/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.pdb rename to lib/csgo/addons/counterstrikesharp/shared/CS2-CustomVotes.Shared/CS2-CustomVotes.Shared.pdb diff --git a/lib/csgo/cfg/settings/disable_bhop.cfg b/lib/csgo/cfg/settings/disable_bhop.cfg new file mode 100644 index 0000000..596060c --- /dev/null +++ b/lib/csgo/cfg/settings/disable_bhop.cfg @@ -0,0 +1,12 @@ +// Enable Movement Unlock +exec settings/disable_dropknife.cfg +exec settings/disable_movement_unlock.cfg + +// Set BHOP Settings +sv_autobunnyhopping 0 + +// Viewmodel +r_drawviewmodel 1 +sv_falldamage_scale 1 + +echo "settings/enable_bhop.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_bots.cfg b/lib/csgo/cfg/settings/disable_bots.cfg new file mode 100644 index 0000000..c107ffe --- /dev/null +++ b/lib/csgo/cfg/settings/disable_bots.cfg @@ -0,0 +1,6 @@ +// Disable Bots +bot_kick +bot_quota 0 +bot_join_after_player 0 + +echo "settings/disable_bots.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_buying.cfg b/lib/csgo/cfg/settings/disable_buying.cfg new file mode 100644 index 0000000..af73ec0 --- /dev/null +++ b/lib/csgo/cfg/settings/disable_buying.cfg @@ -0,0 +1,16 @@ +// Disable Buying +mp_afterroundmoney 0 +mp_buy_during_immunity 0 +mp_buy_anywhere 0 +mp_buytime 0 +mp_give_player_c4 0 +mp_playercashawards 0 +mp_teamcashawards 0 +mp_weapons_allow_zeus 0 +mp_buy_allow_grenades 0 +mp_max_armor 0 +mp_maxmoney 0 +mp_startmoney 0 +mp_promoted_item_enabled 0 + +echo "settings/disable_buying.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_course.cfg b/lib/csgo/cfg/settings/disable_course.cfg new file mode 100644 index 0000000..6d35f43 --- /dev/null +++ b/lib/csgo/cfg/settings/disable_course.cfg @@ -0,0 +1,18 @@ +// Revert settings/enable_course.cfg +mp_respawn_on_death_ct 0 // When set to 1, counter-terrorists will respawn after dying. +mp_respawn_on_death_t 0 // When set to 1, terrorists will respawn after dying. +mp_respawn_immunitytime -1 // How many seconds after respawn immunity lasts. Set to negative value to disable warmup immunity. +mp_roundtime 1.92 // How many minutes each round takes. +mp_timelimit 0 // Game time per map in minutes +mp_roundtime_defuse 1.92 // How many minutes each round of Bomb Defuse takes. If 0 then use mp_roundtime instead. +mp_roundtime_deployment 5 // How many minutes deployment for coop mission takes. +mp_roundtime_hostage 1.92 // How many minutes each round of Hostage Rescue takes. If 0 then use mp_roundtime instead. +mp_ignore_round_win_conditions 0 // Ignore conditions which would end the current round +mp_warmuptime_all_players_connected 60 // Warmup time to use when all players have connected. 0 to disable. +mp_freezetime 15 // how many seconds to keep players frozen when the round starts +mp_team_intro_time 6.5 // How many seconds for team intro +mp_warmuptime 45 // How long the warmup period lasts. Changing this value resets warmup. +mp_maxrounds 15 // max number of rounds to play before server changes maps +mp_playercashawards 1 // Players can earn money by performing in-game actions +mp_teamcashawards 1 // Teams can earn money by performing in-game actions +mp_round_restart_delay 7 // Number of seconds to delay before restarting a round after a win diff --git a/lib/csgo/cfg/settings/disable_drop_weapons.cfg b/lib/csgo/cfg/settings/disable_drop_weapons.cfg new file mode 100644 index 0000000..303ae8d --- /dev/null +++ b/lib/csgo/cfg/settings/disable_drop_weapons.cfg @@ -0,0 +1,10 @@ +// Disable Dropping Weapons +mp_death_drop_c4 0 +mp_death_drop_defuser 0 +mp_death_drop_grenade 0 +mp_death_drop_gun 0 +mp_drop_knife_enable 0 +mp_weapons_allow_map_placed 0 +mp_disconnect_kills_players 1 + +echo "settings/disable_drop_weapons.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_knifedrop.cfg b/lib/csgo/cfg/settings/disable_knifedrop.cfg new file mode 100644 index 0000000..f01ad3e --- /dev/null +++ b/lib/csgo/cfg/settings/disable_knifedrop.cfg @@ -0,0 +1,2 @@ +// Disables Dropping Knife +mp_drop_knife_enable 0 \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_map_voting.cfg b/lib/csgo/cfg/settings/disable_map_voting.cfg new file mode 100644 index 0000000..64c0572 --- /dev/null +++ b/lib/csgo/cfg/settings/disable_map_voting.cfg @@ -0,0 +1,9 @@ +// Disable map voting +sv_allow_votes 0 +mp_endmatch_votenextmap 0 +mp_match_end_changelevel 0 +mp_match_end_restart 0 +mp_endmatch_votenextleveltime 0 +mp_endmatch_votenextmap_keepcurrent 0 + +echo "settings/disable_map_voting.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_movement_unlock.cfg b/lib/csgo/cfg/settings/disable_movement_unlock.cfg new file mode 100644 index 0000000..84bc7b7 --- /dev/null +++ b/lib/csgo/cfg/settings/disable_movement_unlock.cfg @@ -0,0 +1,27 @@ +// https://github.com/KZGlobalTeam/gokz/blob/master/addons/sourcemod/scripting/gokz-mode-kztimer.sp#L37 +sv_accelerate 5.5 +sv_accelerate_use_weapon_speed true +sv_airaccelerate 12 +sv_air_max_wishspeed 30 +sv_enablebunnyhopping 0 +sv_friction 5.2 +sv_gravity 800 +sv_jump_impulse 301.993377 +sv_ladder_scale_speed .78 +sv_maxspeed 320 +sv_maxvelocity 3500 +sv_staminajumpcost 0.08 +sv_staminalandcost 0.05 +sv_staminamax 80 +sv_staminarecoveryrate 60 +sv_standable_normal 0.7 +sv_timebetweenducks 0.4 +sv_walkable_normal 0.7 +sv_wateraccelerate 10 +sv_water_slow_amount 0.9 +sv_water_swim_mode 0 +sv_weapon_encumbrance_per_item 0 +sv_weapon_encumbrance_scale 0 +sv_clamp_unsafe_velocities 0 + +echo "settings/enable_movement_unlock.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_one_round.cfg b/lib/csgo/cfg/settings/disable_one_round.cfg new file mode 100644 index 0000000..128e8f4 --- /dev/null +++ b/lib/csgo/cfg/settings/disable_one_round.cfg @@ -0,0 +1,29 @@ +// Round convars +mp_respawn_on_death_ct 0 +mp_respawn_on_death_t 0 +mp_respawn_immunitytime -1 +mp_roundtime 1.92 +mp_timelimit 0 +mp_roundtime_defuse 1.92 +mp_roundtime_deployment 5 +mp_roundtime_hostage 1.92 +mp_ignore_round_win_conditions 0 +mp_warmuptime_all_players_connected 15 +mp_freezetime 15 +mp_team_intro_time 6.5 +mp_warmup_end +mp_warmuptime 120 +mp_maxrounds 24 +mp_halftime 1 +mp_halftime_duration 15 +mp_match_can_clinch 1 +mp_overtime_enable 0 + +// Hide money +mp_playercashawards 1 +mp_teamcashawards 1 + +// Allow time for vote map +mp_round_restart_delay 7 + +echo "settings/one_round.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_scoutz.cfg b/lib/csgo/cfg/settings/disable_scoutz.cfg new file mode 100644 index 0000000..14cdd8c --- /dev/null +++ b/lib/csgo/cfg/settings/disable_scoutz.cfg @@ -0,0 +1,11 @@ +// Enable buying and dropping weapons +exec settings/enable_buying.cfg +exec settings/enable_drop_weapons.cfg + +// Set Default Weapons +mp_t_default_melee "weapon_knife" +mp_ct_default_melee "weapon_knife" +mp_ct_default_secondary "weapon_usp_silencer" +mp_t_default_secondary "weapon_glock" +mp_t_default_primary "" +mp_ct_default_primary "" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_alltalk.cfg b/lib/csgo/cfg/settings/enable_alltalk.cfg new file mode 100644 index 0000000..979cc10 --- /dev/null +++ b/lib/csgo/cfg/settings/enable_alltalk.cfg @@ -0,0 +1,15 @@ +// Enable all talk +sv_alltalk 1 +sv_deadtalk 1 +sv_full_alltalk 1 +sv_talk_enemy_dead 1 +sv_talk_enemy_living 1 +sv_allchat 1 +sv_spec_hear 1 +sv_voiceenable 1 +tv_relayvoice 1 + +// Enable after round start +exec_after_round_start "exec settings/enable_alltalk.cfg" + +echo "settings/enable_alltalk.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_bhop.cfg b/lib/csgo/cfg/settings/enable_bhop.cfg new file mode 100644 index 0000000..47facc7 --- /dev/null +++ b/lib/csgo/cfg/settings/enable_bhop.cfg @@ -0,0 +1,12 @@ +// Enable Movement Unlock +exec settings/enable_dropknife.cfg +exec settings/enable_movement_unlock.cfg + +// Set BHOP Settings +sv_autobunnyhopping 1 + +// Viewmodel +r_drawviewmodel 0 +sv_falldamage_scale 0 + +echo "settings/enable_bhop.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_bots.cfg b/lib/csgo/cfg/settings/enable_bots.cfg new file mode 100644 index 0000000..ee682eb --- /dev/null +++ b/lib/csgo/cfg/settings/enable_bots.cfg @@ -0,0 +1,6 @@ +// Enables Bots +bot_chatter "off" +bot_join_after_player 1 +bot_quota 2 +bot_quota_mode "fill" +bot_difficulty 3 \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_buying.cfg b/lib/csgo/cfg/settings/enable_buying.cfg new file mode 100644 index 0000000..8bf116e --- /dev/null +++ b/lib/csgo/cfg/settings/enable_buying.cfg @@ -0,0 +1,14 @@ +// Enable Buying +mp_afterroundmoney 1 +mp_buy_during_immunity 1 +mp_buy_anywhere 1 +mp_buytime 1 +mp_give_player_c4 1 +mp_playercashawards 1 +mp_teamcashawards 1 +mp_weapons_allow_zeus 1 +mp_buy_allow_grenades 1 +mp_max_armor 1 +mp_maxmoney 1 +mp_startmoney 1 +mp_promoted_item_enabled 1 \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_course.cfg b/lib/csgo/cfg/settings/enable_course.cfg new file mode 100644 index 0000000..86c9fc8 --- /dev/null +++ b/lib/csgo/cfg/settings/enable_course.cfg @@ -0,0 +1,20 @@ +// Round convars +mp_solid_teammates 0 +mp_ct_default_secondary weapon_usp_silencer +mp_t_default_secondary weapon_usp_silencer +sv_holiday_mode 0 +sv_party_mode 0 +mp_friendlyfire 0 +bot_quota 0 +mp_autoteambalance 0 +mp_limitteams 0 +mp_humanteam CT +mp_spectators_max 64 +sv_disable_radar 1 +sv_ignoregrenaderadio 1 +mp_buytime 0 +mp_free_armor 2 +mp_buy_anywhere 0 +mp_give_player_c4 0 + +echo "settings/enable_course.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_knifedrop.cfg b/lib/csgo/cfg/settings/enable_knifedrop.cfg new file mode 100644 index 0000000..5dc03c9 --- /dev/null +++ b/lib/csgo/cfg/settings/enable_knifedrop.cfg @@ -0,0 +1,8 @@ +// Enables Dropping Knife +mp_death_drop_gun 1 +mp_drop_knife_enable 1 +mp_weapons_allow_map_placed 1 + +exec_after_round_start "exec settings/enable_knifedrop.cfg" + +echo "settings/enable_knifedrop.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_movement_unlock.cfg b/lib/csgo/cfg/settings/enable_movement_unlock.cfg new file mode 100644 index 0000000..ece0269 --- /dev/null +++ b/lib/csgo/cfg/settings/enable_movement_unlock.cfg @@ -0,0 +1,28 @@ +// https://github.com/KZGlobalTeam/gokz/blob/master/addons/sourcemod/scripting/gokz-mode-kztimer.sp#L37 +sv_accelerate 6.5 +sv_accelerate_use_weapon_speed 0 +sv_airaccelerate 100 +sv_air_max_wishspeed 30 +sv_enablebunnyhopping 1 +sv_friction 5 +sv_gravity 800 +sv_jump_impulse 301.993377 +sv_ladder_scale_speed 1 +sv_ledge_mantle_helper 0 +sv_maxspeed 320 +sv_maxvelocity 2000 +sv_staminajumpcost 0 +sv_staminalandcost 0 +sv_staminamax 0 +sv_staminarecoveryrate 120 +sv_standable_normal 0.7 +sv_timebetweenducks 0 +sv_walkable_normal 0.7 +sv_wateraccelerate 10 +sv_water_movespeed_multiplier 0.8 +sv_water_swim_mode 0 +sv_weapon_encumbrance_per_item 0 +sv_weapon_encumbrance_scale 0 +sv_clamp_unsafe_velocities 0 + +echo "settings/movement_unlock.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_one_round.cfg b/lib/csgo/cfg/settings/enable_one_round.cfg new file mode 100644 index 0000000..048c25f --- /dev/null +++ b/lib/csgo/cfg/settings/enable_one_round.cfg @@ -0,0 +1,29 @@ +// Round convars +mp_respawn_on_death_ct 1 +mp_respawn_on_death_t 1 +mp_respawn_immunitytime -1 +mp_roundtime 30 +mp_timelimit 30 +mp_roundtime_defuse 30 +mp_roundtime_deployment 30 +mp_roundtime_hostage 30 +mp_ignore_round_win_conditions 1 +mp_warmuptime_all_players_connected 0 +mp_freezetime 0 +mp_team_intro_time 0 +mp_warmup_end +mp_warmuptime 0 +mp_maxrounds 0 +mp_halftime 0 +mp_halftime_duration 0 +mp_match_can_clinch 0 +mp_overtime_enable 0 + +// Hide money +mp_playercashawards 0 +mp_teamcashawards 0 + +// Allow time for vote map +mp_round_restart_delay 10 + +echo "settings/one_round.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_scoutz.cfg b/lib/csgo/cfg/settings/enable_scoutz.cfg new file mode 100644 index 0000000..ebcd4cb --- /dev/null +++ b/lib/csgo/cfg/settings/enable_scoutz.cfg @@ -0,0 +1,11 @@ +// Disable buying and dropping weapons +exec settings/disable_buying.cfg +exec settings/disable_drop_weapons.cfg + +// Set Default Weapons to SSG +mp_t_default_secondary "" +mp_ct_default_secondary "" +mp_t_default_melee "weapon_knife" +mp_ct_default_melee "weapon_knife" +mp_t_default_primary "weapon_ssg08" +mp_ct_default_primary "weapon_ssg08" \ No newline at end of file From bfe0fd222296fac6ebe5436269a3cbe37246de0d Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Tue, 4 Jun 2024 20:44:26 -0400 Subject: [PATCH 37/86] UPDATE: Use of relative paths. Thanks, Kus! --- Config.cs | 79 +------------------------------------------------------ 1 file changed, 1 insertion(+), 78 deletions(-) diff --git a/Config.cs b/Config.cs index c7f1dcf..5685bf7 100644 --- a/Config.cs +++ b/Config.cs @@ -27,45 +27,21 @@ public void OnConfigParsed(Config _config) { if (File.Exists(Path.Join(GameDirectory, _config.RTV.Plugin))) { -<<<<<<< main - string localRTVPluginPath = Path.Join(Server.GameDirectory + "/csgo/", _config.RTV.Plugin); - if (File.Exists(localRTVPluginPath)) - { - _config.RTV.Plugin = localRTVPluginPath; - } - else - { - throw new Exception($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); - } -======= _config.RTV.Plugin = Path.Join(GameDirectory, _config.RTV.Plugin); } else { Logger.LogError($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); throw new Exception($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); ->>>>>>> main } if (File.Exists(Path.Join(GameDirectory, _config.RTV.MapListFile))) { -<<<<<<< main - string localRTVMapListFilePath = Path.Join(Server.GameDirectory + "/csgo/", _config.RTV.MapListFile); - if (File.Exists(localRTVMapListFilePath)) - { - _config.RTV.MapListFile = localRTVMapListFilePath; - } - else - { - throw new Exception($"Cannot find RTV 'MapListFile': {_config.RTV.MapListFile}"); - } -======= _config.RTV.MapListFile = Path.Join(GameDirectory, _config.RTV.MapListFile); } else { Logger.LogError($"Cannot find RTV 'MapListFile': {_config.RTV.MapListFile}"); throw new Exception($"Cannot find RTV 'MapListFile': {_config.RTV.MapListFile}"); ->>>>>>> main } if (_config.RTV.DefaultMapFormat != true && _config.RTV.DefaultMapFormat != false) { @@ -74,29 +50,7 @@ public void OnConfigParsed(Config _config) } } -<<<<<<< main - // Game Settings Settings - if (_config.Settings.Enabled != true && _config.Settings.Enabled != false) - { - throw new Exception($"Invalid: Game settings 'Enabled' should be 'true' or 'false'."); - } - if (!Directory.Exists(_config.Settings.Home)) - { - string localSettingsHomePath = Path.Join(Server.GameDirectory + "/csgo/", _config.Settings.Home); - if (Directory.Exists(localSettingsHomePath)) - { - _config.Settings.Home = localSettingsHomePath; - } - else - { - throw new Exception($"Cannot find Settings 'Home': {_config.Settings.Home}"); - } - } - - // Map Group Settings -======= // Map group settings ->>>>>>> main if (!float.TryParse(_config.MapGroup.Delay.ToString(), out _)) { Logger.LogError("Map group delay must be a number."); @@ -113,20 +67,8 @@ public void OnConfigParsed(Config _config) } else { -<<<<<<< main - string localMapGroupFilePath = Path.Join(Server.GameDirectory + "/csgo/", _config.MapGroup.File); - if (File.Exists(localMapGroupFilePath)) - { - _config.MapGroup.File = localMapGroupFilePath; - } - else - { - throw new Exception($"Cannot find map group file: {_config.MapGroup.File}"); - } -======= Logger.LogError($"Cannot find map group file: {_config.MapGroup.File}"); throw new Exception($"Cannot find map group file: {_config.MapGroup.File}"); ->>>>>>> main } // Game mode settings @@ -208,43 +150,24 @@ public class Config : BasePluginConfig // Define settings classes public class RTVSettings { -<<<<<<< main - [JsonPropertyName("Enabled")] public bool Enabled { get; set; } = false; // Enable RTV Compatibility - [JsonPropertyName("Plugin")] public string Plugin { get; set; } = "addons/counterstrikesharp/plugins/RockTheVote/RockTheVote.dll"; // RTV plugin path - [JsonPropertyName("MapListFile")] public string MapListFile { get; set; } = "addons/counterstrikesharp/plugins/RockTheVote/maplist.txt"; // Default map list file - [JsonPropertyName("DefaultMapFormat")] public bool DefaultMapFormat { get; set; } = false; // Default file format (ws:). When set to false, uses format :. -======= public bool Enabled { get; set; } = false; // Enable RTV Compatibility public string Plugin { get; set; } = "addons/counterstrikesharp/plugins/RockTheVote/RockTheVote.dll"; // RTV plugin path public string MapListFile { get; set; } = "addons/counterstrikesharp/plugins/RockTheVote/maplist.txt"; // Default map list file public bool DefaultMapFormat { get; set; } = false; // Default file format (ws:). When set to false, uses format :. ->>>>>>> main } public class GameSettings { -<<<<<<< main - [JsonPropertyName("Enabled")] public bool Enabled { get; set; } = true; // Enable game settings - [JsonPropertyName("Home")] public string Home { get; set; } = "cfg"; // Enable game settings - [JsonPropertyName("Folder")] public string Folder { get; set; } = "settings"; // Default settings folder path -======= public bool Enabled { get; set; } = true; // Enable game settings public string Folder { get; set; } = "settings"; // Default settings folder path public string Style { get; set; } = "center"; // Changes admin menu type (i.e. "chat" or "center") ->>>>>>> main } public class MapGroupSettings { -<<<<<<< main - [JsonPropertyName("Delay")] public float Delay { get; set; } = 5.0f; // Map change delay in seconds - [JsonPropertyName("Default")] public string Default { get; set; } = "mg_active"; // Default map group on server start - [JsonPropertyName("File")] public string File { get; set; } = "gamemodes_server.txt"; // Default game modes and map groups file -======= public float Delay { get; set; } = 5.0f; // Map change delay in seconds public string Default { get; set; } = "mg_active"; // Default map group on server start public string File { get; set; } = "gamemodes_server.txt"; // Default game modes and map groups file ->>>>>>> main } public class GameModeSettings { @@ -288,4 +211,4 @@ public class VoteSettings public GameModeSettings GameMode { get; set; } = new GameModeSettings(); public VoteSettings Votes { get; set; } = new VoteSettings(); } -} \ No newline at end of file +} From 5825683062082ab1514e2f60c963d1bb66754bd1 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Wed, 5 Jun 2024 19:37:42 -0400 Subject: [PATCH 38/86] UPDATE: Fixed relative URLs --- Config.cs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Config.cs b/Config.cs index 38cc58e..a965e73 100644 --- a/Config.cs +++ b/Config.cs @@ -11,8 +11,8 @@ public partial class Plugin : BasePlugin, IPluginConfig // Define configuration object public required Config Config { get; set; } public static string GameDirectory = Path.Join(Server.GameDirectory + "/csgo/"); - public static string ConfigDirectory = Path.Join(GameDirectory + "/cfg/"); - public static string SettingsDirectory = Path.Join(ConfigDirectory + "/settings/"); + public static string ConfigDirectory = Path.Join(GameDirectory + "cfg/"); + public static string SettingsDirectory = Path.Join(ConfigDirectory + "settings/"); // Parse configuration object data and perform error checking public void OnConfigParsed(Config _config) @@ -102,19 +102,22 @@ public void OnConfigParsed(Config _config) } // Game Settings - if (_config.Settings.Enabled != true && _config.Settings.Enabled != false) + if (_config.Settings.Enabled != true && _config.Settings.Enabled != false) { Logger.LogError("Invalid: Game setting should be 'true' or 'false'."); throw new Exception("Invalid: Game setting should be 'true' or 'false'."); } - if (File.Exists(Path.Join(ConfigDirectory, _config.Settings.Folder))) + else if (_config.Settings.Enabled == true) { - SettingsDirectory = Path.Join(ConfigDirectory, _config.Settings.Folder); - } - else - { - Logger.LogError($"Cannot find 'Settings Folder': {ConfigDirectory}{_config.Settings.Folder}"); - throw new Exception($"Cannot find 'Settings Folder': {ConfigDirectory}{_config.Settings.Folder}"); + if (System.IO.Directory.Exists(Path.Combine(ConfigDirectory, _config.Settings.Folder))) + { + SettingsDirectory = Path.Join(ConfigDirectory, _config.Settings.Folder); + } + else + { + Logger.LogError($"Cannot find 'Settings Folder': {SettingsDirectory}"); + throw new Exception($"Cannot find 'Settings Folder': {SettingsDirectory}"); + } } // Vote Settings From 726546d03e97129e23cc1bc3b1739f86fd871e90 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Wed, 5 Jun 2024 19:38:16 -0400 Subject: [PATCH 39/86] UPDATE: Fixed setting name issue --- Core/SettingsManager.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Core/SettingsManager.cs b/Core/SettingsManager.cs index dd9d745..5287e04 100644 --- a/Core/SettingsManager.cs +++ b/Core/SettingsManager.cs @@ -83,28 +83,30 @@ private void ParseSettings() foreach (string _file in _cfgFiles) { string _fileName = FormatSettingName(_file); + string _fileNameFull = Path.GetFileName(_file); if (_fileName != null) { // Find existing setting if it's already in the list - var setting = Settings.FirstOrDefault(s => s.Name == _fileName); + var _setting = Settings.FirstOrDefault(s => s.Name == _fileName); - if (setting == null) + if (_setting == null) { // Create a new setting if not found - setting = new Setting(_fileName); - Settings.Add(setting); + _setting = new Setting(_fileName); + Settings.Add(_setting); } // Assign config path based on prefix - if (_file.StartsWith("enable_")) + if (_fileNameFull.StartsWith("enable_")) { - setting.ConfigEnable = _file; + _setting.ConfigEnable = _fileNameFull; } else { - setting.ConfigDisable = _file; + _setting.ConfigDisable = _fileNameFull; } + } else { From eda46955ab557dc43247d67a2ca31178782d9598 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Wed, 5 Jun 2024 19:38:49 -0400 Subject: [PATCH 40/86] UPDATE: Added dergistration for all votes --- Core/VoteManager.cs | 69 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs index ee2b1ea..d8da83d 100644 --- a/Core/VoteManager.cs +++ b/Core/VoteManager.cs @@ -117,23 +117,22 @@ private void RegisterCustomVotes() // Add options to all game settings vote _settingOptions.Add($"Enable {_setting.Name}", new VoteOption($"Enable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigEnable}" })); _settingOptions.Add($"Disable {_setting.Name}", new VoteOption($"Disable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigDisable}" })); - - // Register per game setting vote - Plugin.CustomVotesApi.Get()?.AddCustomVote( - _setting.Name, // Command to trigger the vote - new List(), // Aliases for the command (optional) - $"Change {_setting.Name}?", // Description - "No", - 30, // Time to vote - new Dictionary // vote options - { - { "Enable", new VoteOption("{Green}Enable", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigEnable}" })}, - { "Disable", new VoteOption("{Red}Disable", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigDisable}" })}, - }, - "center", // Menu style - "center" or "chat" - -1 // Minimum percentage of votes required (-1 behaves like 50%) - ); + var _perSettingOptions = new Dictionary(); + _perSettingOptions.Add($"Enable", new VoteOption($"Enable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigEnable}" })); + _perSettingOptions.Add($"Disable", new VoteOption($"Disable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigDisable}" })); + + // Register per setting vote + Plugin.CustomVotesApi.Get()?.AddCustomVote( + _setting.Name, // Command to trigger the vote + new List(), // Aliases for the command (optional) + $"Change setting {_setting.Name}?", // Description + "Disable", + 30, // Time to vote + _perSettingOptions, + "center", // Menu style - "center" or "chat" + -1 // Minimum percentage of votes required (-1 behaves like 50%) + ); } // Register all game settings vote @@ -158,11 +157,49 @@ private void DeregisterCustomVotes() { if (_gamemodeVote == true) { + // Deregister all gamemodes vote Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamemode"); + + // Deregister per gamemode votes + if (Config.GameMode.ListEnabled) + { + foreach (string _mode in Config.GameMode.List) + { + if(_mode != null) + { + string _vote=_mode.ToLower(); + Plugin.CustomVotesApi.Get()?.RemoveCustomVote(_vote); + } + } + } + else + { + foreach (MapGroup _mapGroup in MapGroups) + { + // Capitalize game mode name + string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); + string _tempName = _nameParts[_nameParts.Length - 1]; + string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); + + if(_mapGroupName != null) + { + string _vote=_mapGroupName.ToLower(); + Plugin.CustomVotesApi.Get()?.RemoveCustomVote(_vote); + } + } + } } + if (_settingVote == true) { + // Deregister all settings vote Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamesetting"); + + // Deregister per settings votes + foreach (Setting _setting in Settings) + { + Plugin.CustomVotesApi.Get()?.RemoveCustomVote(_setting.Name); + } } } } From c6adebf1510b5004ca46a77a36e8679edc806e8f Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Wed, 5 Jun 2024 19:39:03 -0400 Subject: [PATCH 41/86] UPDATE: Added logging --- Plugin.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Plugin.cs b/Plugin.cs index 666091c..51d5729 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -71,6 +71,7 @@ public override void Load(bool hotReload) // Register EvenGameEnd handler if RTV is not enabled to perform map and game mode rotations if(!Config.RTV.Enabled) { + Logger.LogInformation($"Enabling game mode and map rotations..."); RegisterEventHandler(EventGameEnd); } } From a3017468f85e38d54ccfabe5eeefb2e65ca5305f Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Wed, 5 Jun 2024 19:41:26 -0400 Subject: [PATCH 42/86] UPDATE: Config.cs --- Config.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Config.cs b/Config.cs index 7303e72..a965e73 100644 --- a/Config.cs +++ b/Config.cs @@ -214,4 +214,4 @@ public class VoteSettings public GameModeSettings GameMode { get; set; } = new GameModeSettings(); public VoteSettings Votes { get; set; } = new VoteSettings(); } -} +} \ No newline at end of file From 69cb57ef5cfd5dc7a4ea1fd56c06310e86fa1dc7 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 7 Jun 2024 23:29:30 -0400 Subject: [PATCH 43/86] ADDED: Friendly names Friendly names for game modes --- Config.cs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Config.cs b/Config.cs index a965e73..c830699 100644 --- a/Config.cs +++ b/Config.cs @@ -10,6 +10,8 @@ public partial class Plugin : BasePlugin, IPluginConfig { // Define configuration object public required Config Config { get; set; } + + // Define directories (Thanks Kus!) public static string GameDirectory = Path.Join(Server.GameDirectory + "/csgo/"); public static string ConfigDirectory = Path.Join(GameDirectory + "cfg/"); public static string SettingsDirectory = Path.Join(ConfigDirectory + "settings/"); @@ -179,22 +181,22 @@ public class GameModeSettings public float Delay { get; set; } = 5.0f; // Game mode change delay in seconds public string Style { get; set; } = "center"; // Changes admin menu type (i.e. "chat" or "center") public bool ListEnabled { get; set; } = true; // Enables custom game mode list. If set to false, generated from map groups. - public List List { get; set; } = new List // Custom game mode list + public Dictionary List { get; set; } = new Dictionary() // Custom game mode list { - "comp", - "1v1", - "aim", - "awp", - "scoutzknivez", - "wingman", - "gungame", - "surf", - "dm", - "dm-multicfg", - "course", - "hns", - "kz", - "minigames" + {"comp", "Competitive"}, + {"1v1", "1 vs 1"}, + {"aim","Aim"}, + {"awp", "AWP Only"}, + {"scoutzknivez", "ScoutzKnives"}, + {"wingman", "Wingman"}, + {"gungame", "Gun Game"}, + {"surf", "Surf"}, + {"dm", "Deathmatch"}, + {"dm-multicfg", "Deathmatch Multicfg"}, + {"course", "Course"}, + {"hns", "Hide N Seek"}, + {"kz", "Kreedz"}, + {"minigames", "Mini Games"} }; // Default Game Mode List } public class VoteSettings From 82dfc5fab87ddbb9fa91e33871817f84c89ed184 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 7 Jun 2024 23:31:08 -0400 Subject: [PATCH 44/86] UPDATE: Replaced hard-coded settings folder Replaced hard-coded settings folder with dynamic config value. --- Core/CommandManager.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Core/CommandManager.cs b/Core/CommandManager.cs index c52284d..329d3ba 100644 --- a/Core/CommandManager.cs +++ b/Core/CommandManager.cs @@ -54,7 +54,7 @@ public void OnMapsCommand(CCSPlayerController? player, CommandInfo command) } } - // Construct change map command handler + // Construct admin change map command handler [RequiresPermissions("@css/changemap")] [CommandHelper(minArgs: 1, usage: "[map name] optional: [id]", whoCanExecute: CommandUsage.CLIENT_ONLY)] [ConsoleCommand("css_map", "Changes the map to the map specified in the command argument.")] @@ -76,7 +76,7 @@ public void OnMapCommand(CCSPlayerController? player, CommandInfo command) } } - // Construct change mode command handler + // Construct admin change mode command handler [RequiresPermissions("@css/changemap")] [CommandHelper(minArgs: 1, usage: "[mode]", whoCanExecute: CommandUsage.CLIENT_ONLY)] [ConsoleCommand("css_mode", "Changes the game mode to the mode specified in the command argument.")] @@ -106,7 +106,7 @@ public void OnModesCommand(CCSPlayerController? player, CommandInfo command) } } - // Construct change setting command handler + // Construct admin change setting command handler [RequiresPermissions("@css/cvar")] [CommandHelper(minArgs: 2, usage: "[enable/disable] [setting name]", whoCanExecute: CommandUsage.CLIENT_ONLY)] [ConsoleCommand("css_setting", "Changes the game setting specified.")] @@ -129,7 +129,7 @@ public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) Server.PrintToChatAll(Localizer["enable.changesetting.message", player.PlayerName, command.ArgByIndex(2)]); // Change game setting - Server.ExecuteCommand($"exec settings/{_option.ConfigDisable}"); + Server.ExecuteCommand($"exec {Config.Settings.Folder}/{_option.Enable}"); } else if (_status == "disable") { @@ -137,7 +137,7 @@ public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) Server.PrintToChatAll(Localizer["disable.changesetting.message", player.PlayerName, command.ArgByIndex(2)]); // Change game setting - Server.ExecuteCommand($"exec settings/{_option.ConfigDisable}"); + Server.ExecuteCommand($"exec {Config.Settings.Folder}/{_option.Disable}"); } else { @@ -151,7 +151,7 @@ public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) } } } - + // Construct admin setting menu command handler [RequiresPermissions("@css/cvar")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] @@ -164,6 +164,7 @@ public void OnSettingsCommand(CCSPlayerController? player, CommandInfo command) SettingsMenu.Title = Localizer["settings.hud.menu-title"]; OpenMenu(SettingsMenu, Config.Settings.Style, player); } + } } } \ No newline at end of file From 914a5afca1aa7b65c88d5df612ae398f42ac7b1b Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 7 Jun 2024 23:32:10 -0400 Subject: [PATCH 45/86] ADDED: Friendly name Added DisplayName property to map group class. Requires "displayname" property to exist for each mapgroup in gamemodes_server.txt --- Core/MapGroupManager.cs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Core/MapGroupManager.cs b/Core/MapGroupManager.cs index 0898365..9cee22c 100644 --- a/Core/MapGroupManager.cs +++ b/Core/MapGroupManager.cs @@ -16,17 +16,27 @@ namespace GameModeManager public class MapGroup : IEquatable { public string Name { get; set; } + public string DisplayName { get; set; } public List Maps { get; set; } public MapGroup(string _name) { Name = _name; + DisplayName = _name; Maps = new List(); } public MapGroup(string _name, List _maps) { Name = _name; + DisplayName = _name; + Maps = _maps; + } + + public MapGroup(string _name, string _displayName, List _maps) + { + Name = _name; + DisplayName = _displayName; Maps = _maps; } @@ -93,9 +103,20 @@ private void ParseMapGroups() { foreach (VProperty _mapGroup in _mapGroups.OfType()) { - // Set map group + // Set map group name MapGroup _group = new MapGroup(_mapGroup.Key); + // Set display name + var _displayName = _mapGroup.Value.OfType() + .Where(p => p.Key == "displayname") + .Select(p => p.Value) + .FirstOrDefault(); + + if (_displayName != null) + { + _group.DisplayName = _displayName.ToString(); + } + // Create an array of maps var _maps = _mapGroup.Value.OfType() .Where(p => p.Key == "maps") From d88388adde63b62a17f06b8b32e12c6ebcbe3327 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 7 Jun 2024 23:32:59 -0400 Subject: [PATCH 46/86] UPDATE: Refactoring --- Core/MapManager.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Core/MapManager.cs b/Core/MapManager.cs index 5385590..5e3bdf0 100644 --- a/Core/MapManager.cs +++ b/Core/MapManager.cs @@ -12,24 +12,24 @@ public class Map : IEquatable public string Name { get; set; } public string WorkshopId { get; set; } - public Map(string name) + public Map(string _name) { - Name = name; + Name = _name; WorkshopId = ""; } - public Map(string name, string workshopId) + public Map(string _name, string _workshopId) { - Name = name; - WorkshopId = workshopId; + Name = _name; + WorkshopId = _workshopId; } - public bool Equals(Map? other) + public bool Equals(Map? _other) { - if (other == null) return false; // Handle null + if (_other == null) return false; // Handle null // Implement your equality logic, e.g.; - return Name == other.Name && WorkshopId == other.WorkshopId; + return Name == _other.Name && WorkshopId == _other.WorkshopId; } public void Clear() From 1f38e6f331ed59eed8f8e815b9fc9a180c148ed5 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 7 Jun 2024 23:33:50 -0400 Subject: [PATCH 47/86] ADDED: Friendly names Added support for friendly names for menu options. This effects both settings and map groups/game modes. --- Core/MenuManager.cs | 51 ++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/Core/MenuManager.cs b/Core/MenuManager.cs index 36ac6c9..c58bf1f 100644 --- a/Core/MenuManager.cs +++ b/Core/MenuManager.cs @@ -3,7 +3,7 @@ using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; using CounterStrikeSharp.API.Modules.Menu; - +using CS2_CustomVotes.Shared.Models; // Declare namespace namespace GameModeManager { @@ -76,13 +76,13 @@ public void SetupSettingsMenu() // Add enable menu options foreach (Setting _setting in Settings) { - SettingsEnableMenu.AddMenuOption(_setting.Name, (player, option) => + SettingsEnableMenu.AddMenuOption(_setting.DisplayName, (player, option) => { // Write to chat Server.PrintToChatAll(Localizer["enable.changesetting.message", player.PlayerName, option.Text]); // Change game setting - Server.ExecuteCommand($"exec {SettingsDirectory}{_setting.ConfigEnable}"); + Server.ExecuteCommand($"exec {Config.Settings.Folder}/{_setting.Enable}"); // Close menu MenuManager.CloseActiveMenu(player); @@ -92,13 +92,13 @@ public void SetupSettingsMenu() // Add disable menu options foreach (Setting _setting in Settings) { - SettingsDisableMenu.AddMenuOption(_setting.Name, (player, option) => + SettingsDisableMenu.AddMenuOption(_setting.DisplayName, (player, option) => { // Write to chat Server.PrintToChatAll(Localizer["disable.changesetting.message", player.PlayerName, option.Text]); // Change game setting - Server.ExecuteCommand($"exec {SettingsDirectory}{_setting.ConfigDisable}"); + Server.ExecuteCommand($"exec {Config.Settings.Folder}/{_setting.Disable}"); // Close menu MenuManager.CloseActiveMenu(player); @@ -127,7 +127,7 @@ public void SetupSettingsMenu() } }); } - + // Define mode menu public static BaseMenu? ModeMenu; @@ -135,20 +135,20 @@ public void SetupSettingsMenu() private void SetupModeMenu() { // Assign menu - ModeMenu = AssignMenu(Config.GameMode.Style, "Game Mode List"); + ModeMenu = AssignMenu(Config.GameMode.Style, "Game Mode Menu"); if (Config.GameMode.ListEnabled) { // Add menu option for each game mode in game mode list - foreach (string _mode in Config.GameMode.List) + foreach (KeyValuePair _entry in Config.GameMode.List) { - ModeMenu.AddMenuOption(_mode, (player, option) => + ModeMenu.AddMenuOption(_entry.Value, (player, option) => { // Write to chat Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); // Change game mode - string _option = option.Text.ToLower(); + string _option = _entry.Key.ToLower(); AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_option}.cfg")); // Close menu @@ -161,17 +161,33 @@ private void SetupModeMenu() // Create menu options for each map group parsed foreach (MapGroup _mapGroup in MapGroups) { - // Split the string into parts by the underscore - string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); - // Get the last part (the actual map group name) - string _tempName = _nameParts[_nameParts.Length - 1]; + if(_mapGroup.DisplayName != null) + { + ModeMenu.AddMenuOption(_mapGroup.DisplayName, (player, option) => + { + // Write to chat + Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); - // Combine the capitalized first letter with the rest - string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); + // Change game mode + string _option = option.Text.ToLower(); + AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_option}.cfg")); - if(_mapGroupName != null) + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + else { + // Split the string into parts by the underscore + string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); + + // Get the last part (the actual map group name) + string _tempName = _nameParts[_nameParts.Length - 1]; + + // Combine the capitalized first letter with the rest + string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); + ModeMenu.AddMenuOption(_mapGroupName, (player, option) => { // Write to chat @@ -184,6 +200,7 @@ private void SetupModeMenu() // Close menu MenuManager.CloseActiveMenu(player); }); + } } } From 6e8b3dde472e510ea24477606bcf94e2755291f6 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 7 Jun 2024 23:34:48 -0400 Subject: [PATCH 48/86] ADDED: Friendly names Added DisplayName property to settings object. Did some minor refactoring for readability --- Core/SettingsManager.cs | 92 +++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/Core/SettingsManager.cs b/Core/SettingsManager.cs index 5287e04..719970d 100644 --- a/Core/SettingsManager.cs +++ b/Core/SettingsManager.cs @@ -10,34 +10,48 @@ namespace GameModeManager // Define setting class public class Setting : IEquatable { + // Define setting variables public string Name { get; set; } - public string ConfigEnable { get; set; } - public string ConfigDisable { get; set; } + public string Enable { get; set; } + public string Disable { get; set; } + public string DisplayName { get; set; } + + // Construct reusable function to format settings names + private string FormatSettingName(string _settingName) + { + _settingName = _settingName.Replace("_", " "); + return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(_settingName); + } - public Setting(string name) + // Construct class instances + public Setting(string _name) { - Name = name; - ConfigEnable = ""; - ConfigDisable = ""; + Name = _name; + Enable = ""; + Disable = ""; + DisplayName = FormatSettingName(_name); } - public Setting(string name, string configEnable, string configDisable) + public Setting(string _name, string _enable, string _disable) { - Name = name; - ConfigEnable = configEnable; - ConfigDisable = configDisable; + Name = _name; + Enable = _enable; + Disable = _disable; + DisplayName = FormatSettingName(_name); } - public bool Equals(Setting? other) + // Construct function for comparisons + public bool Equals(Setting? _other) { - if (other == null) return false; // Handle null - return Name == other.Name && ConfigEnable == other.ConfigEnable && ConfigDisable == other.ConfigDisable; + if (_other == null) return false; // Handle null + return Name == _other.Name && Enable == _other.Enable && Disable == _other.Disable && DisplayName == _other.DisplayName; } + // Construct function to clear values public void Clear() { Name = ""; - ConfigEnable = ""; - ConfigDisable = ""; + Enable = ""; + Disable = ""; } } @@ -47,27 +61,6 @@ public partial class Plugin : BasePlugin // Define settings list public static List Settings = new List(); - // Construct reusable function to format settings names - private string FormatSettingName(string settingName) - { - // Get setting name - var _name = Path.GetFileNameWithoutExtension(settingName); - var _regex = new Regex(@"^(enable_|disable_)(.*)"); - var _match = _regex.Match(_name); - - // Format setting name - if (_match.Success) - { - _name = _match.Groups[2].Value; - _name = _name.Replace("_", " "); - return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(_name); - } - else - { - return null!; - } - } - // Constuct reusable function to parse settings private void ParseSettings() { @@ -82,35 +75,44 @@ private void ParseSettings() // Process each file foreach (string _file in _cfgFiles) { - string _fileName = FormatSettingName(_file); - string _fileNameFull = Path.GetFileName(_file); + // Get setting name + string _name = Path.GetFileNameWithoutExtension(_file); + string _fileName = Path.GetFileName(_file); + + // Format setting name + var _regex = new Regex(@"^(enable_|disable_)"); + var _match = _regex.Match(_name); - if (_fileName != null) + if (_match.Success) { + + // Create new setting name + _name = _name.Substring(_match.Length); + // Find existing setting if it's already in the list - var _setting = Settings.FirstOrDefault(s => s.Name == _fileName); + var _setting = Settings.FirstOrDefault(s => s.Name == _name); if (_setting == null) { // Create a new setting if not found - _setting = new Setting(_fileName); + _setting = new Setting(_name); Settings.Add(_setting); } // Assign config path based on prefix - if (_fileNameFull.StartsWith("enable_")) + if (_fileName.StartsWith("enable_")) { - _setting.ConfigEnable = _fileNameFull; + _setting.Enable = _fileName; } else { - _setting.ConfigDisable = _fileNameFull; + _setting.Disable = _fileName; } } else { - Logger.LogWarning($"Skipping {_file} because its missing the correct prefix."); + Logger.LogWarning($"Skipping {_fileName} because its missing the correct prefix."); } } } From 9eff134da34c4293d748278d24632ddf32a9e51e Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 7 Jun 2024 23:35:35 -0400 Subject: [PATCH 49/86] ADDED: Friendly names Added friendly name support for both settings and mapgroups/game modes with custom votes. --- Core/VoteManager.cs | 95 ++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 62 deletions(-) diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs index d8da83d..3be65bb 100644 --- a/Core/VoteManager.cs +++ b/Core/VoteManager.cs @@ -16,37 +16,37 @@ public partial class Plugin : BasePlugin bool _settingVote = false; // Construct reusable function to register custom votes - private void RegisterCustomVotes() + private void RegisterCustomVotes() { if(Config.Votes.GameMode) { // Define mode options var _modeOptions = new Dictionary(); - _modeOptions.Add("No", new VoteOption("No", new List { "clear;" })); + _modeOptions.Add("No", new VoteOption("No", new List())); // Set mode options if (Config.GameMode.ListEnabled) { // Add menu option for each game mode in game mode list - foreach (string _mode in Config.GameMode.List) + foreach (KeyValuePair _entry in Config.GameMode.List) { - if(_mode != null) + if(_entry.Key != null) { // Add mode to all modes vote - string _option=_mode.ToLower(); - _modeOptions.Add(_mode, new VoteOption(_mode, new List { $"exec {_option}.cfg" })); + string _option=_entry.Key.ToLower(); + _modeOptions.Add(_entry.Value, new VoteOption(_entry.Value, new List { $"exec {_option}.cfg" })); // Create per mode vote Plugin.CustomVotesApi.Get()?.AddCustomVote( _option, // Command to trigger the vote new List(), // Aliases for the command (optional) - $"Change game mode to {_option}?", // Description - "No", + $"Change game mode to {_entry.Value}?", // Description + "No", // Default 30, // Time to vote new Dictionary // vote options { { "Yes", new VoteOption("{Green}Yes", new List { $"exec {_option}.cfg" })}, - { "No", new VoteOption("{Red}No", new List { "clear;" })}, + { "No", new VoteOption("{Red}No", new List())}, }, "center", // Menu style - "center" or "chat" -1 // Minimum percentage of votes required (-1 behaves like 50%) @@ -59,16 +59,12 @@ private void RegisterCustomVotes() // Add menu option for each map group foreach (MapGroup _mapGroup in MapGroups) { - // Capitalize game mode name - string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); - string _tempName = _nameParts[_nameParts.Length - 1]; - string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); - if(_mapGroupName != null) + if(_mapGroup.DisplayName != null) { // Add game mode to all game modes vote - string _option=_mapGroupName.ToLower(); - _modeOptions.Add(_mapGroupName, new VoteOption(_mapGroupName, new List { $"exec {_option}.cfg" })); + string _option=_mapGroup.Name.ToLower(); + _modeOptions.Add(_mapGroup.DisplayName, new VoteOption(_mapGroup.DisplayName, new List { $"exec {_option}.cfg" })); // Create per mode vote Plugin.CustomVotesApi.Get()?.AddCustomVote( @@ -80,7 +76,7 @@ private void RegisterCustomVotes() new Dictionary // vote options { { "Yes", new VoteOption("{Green}Yes", new List { $"exec {_option}.cfg" })}, - { "No", new VoteOption("{Red}No", new List { "clear;" })}, + { "No", new VoteOption("{Red}No", new List())}, }, "center", // Menu style - "center" or "chat" -1 // Minimum percentage of votes required (-1 behaves like 50%) @@ -92,12 +88,12 @@ private void RegisterCustomVotes() // Register game modes vote Plugin.CustomVotesApi.Get()?.AddCustomVote( - "gamemode", // Command to trigger the vote - new List {"gm", "changemode", "changegame"}, // aliases for the command (optional) + "changemode", // Command to trigger the vote + new List {"cm"}, // aliases for the command (optional) "Vote to change game mode.", // Description - "No", + "No", // Default option 30, // Time to vote - _modeOptions, + _modeOptions, // All options "center", // Menu style - "center" or "chat" -1 // Minimum percentage of votes required (-1 behaves like 50%) ); @@ -105,69 +101,51 @@ private void RegisterCustomVotes() // Set game mode vote flag _gamemodeVote = true; } + if(Config.Votes.GameSetting) { - // Define setiing options - var _settingOptions = new Dictionary(); - _settingOptions.Add("No", new VoteOption("No", new List { "clear;" })); - - // Set setting options foreach (Setting _setting in Settings) { - // Add options to all game settings vote - _settingOptions.Add($"Enable {_setting.Name}", new VoteOption($"Enable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigEnable}" })); - _settingOptions.Add($"Disable {_setting.Name}", new VoteOption($"Disable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigDisable}" })); - - var _perSettingOptions = new Dictionary(); - _perSettingOptions.Add($"Enable", new VoteOption($"Enable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigEnable}" })); - _perSettingOptions.Add($"Disable", new VoteOption($"Disable {_setting.Name}", new List { $"exec {Config.Settings.Folder}/{_setting.ConfigDisable}" })); // Register per setting vote Plugin.CustomVotesApi.Get()?.AddCustomVote( _setting.Name, // Command to trigger the vote new List(), // Aliases for the command (optional) - $"Change setting {_setting.Name}?", // Description - "Disable", + $"Change setting {_setting.DisplayName}?", // Description + "No", // Default option 30, // Time to vote - _perSettingOptions, + new Dictionary // vote options + { + { "No", new VoteOption("No", new List())}, + { "Enable", new VoteOption("Enable", new List { $"exec {Config.Settings.Folder}/{_setting.Enable}" })}, + { "Disable", new VoteOption("Disable", new List{ $"exec {Config.Settings.Folder}/{_setting.Disable}" })}, + }, "center", // Menu style - "center" or "chat" -1 // Minimum percentage of votes required (-1 behaves like 50%) ); } - // Register all game settings vote - Plugin.CustomVotesApi.Get()?.AddCustomVote( - "gamesetting", // Command to trigger the vote - new List {"gs", "changesetting", "settingchange"}, // aliases for the command (optional) - "Vote to change a game setting.", // Description - "No", - 30, // Time to vote - _settingOptions, - "center", // Menu style - "center" or "chat" - -1 // Minimum percentage of votes required (-1 behaves like 50%) - ); - // Set game setting vote flag _settingVote = true; } } - + // Construct reusable function to deregister custom votes private void DeregisterCustomVotes() { if (_gamemodeVote == true) { // Deregister all gamemodes vote - Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamemode"); + Plugin.CustomVotesApi.Get()?.RemoveCustomVote("changemode"); // Deregister per gamemode votes if (Config.GameMode.ListEnabled) { - foreach (string _mode in Config.GameMode.List) + foreach (KeyValuePair _entry in Config.GameMode.List) { - if(_mode != null) + if(_entry.Key != null) { - string _vote=_mode.ToLower(); + string _vote=_entry.Key.ToLower(); Plugin.CustomVotesApi.Get()?.RemoveCustomVote(_vote); } } @@ -176,14 +154,10 @@ private void DeregisterCustomVotes() { foreach (MapGroup _mapGroup in MapGroups) { - // Capitalize game mode name - string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); - string _tempName = _nameParts[_nameParts.Length - 1]; - string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); - if(_mapGroupName != null) + if(_mapGroup.Name != null) { - string _vote=_mapGroupName.ToLower(); + string _vote=_mapGroup.Name.ToLower(); Plugin.CustomVotesApi.Get()?.RemoveCustomVote(_vote); } } @@ -192,9 +166,6 @@ private void DeregisterCustomVotes() if (_settingVote == true) { - // Deregister all settings vote - Plugin.CustomVotesApi.Get()?.RemoveCustomVote("gamesetting"); - // Deregister per settings votes foreach (Setting _setting in Settings) { From d8bc506a19651ded8aa0d25e96fd5993ee9b6bf2 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 7 Jun 2024 23:36:13 -0400 Subject: [PATCH 50/86] UPDATE: Logging --- Plugin.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Plugin.cs b/Plugin.cs index 51d5729..4e9ba81 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -1,5 +1,6 @@ // Included libraries using CS2_CustomVotes.Shared; + using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; using CounterStrikeSharp.API.Core.Capabilities; @@ -60,6 +61,7 @@ public override void Load(bool hotReload) { Logger.LogInformation($"Loading settings..."); ParseSettings(); + Logger.LogInformation($"Creating settings menu..."); SetupSettingsMenu(); } } @@ -93,6 +95,7 @@ public override void OnAllPluginsLoaded(bool hotReload) return; } + var votes = CustomVotesApi.Get(); _isCustomVotesLoaded = true; Logger.LogInformation("Registering custom votes..."); RegisterCustomVotes(); From 6eea516c333d12715e37ad6dd0ff5e3581716c28 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Fri, 7 Jun 2024 23:38:58 -0400 Subject: [PATCH 51/86] UPDATE: Refactoring Removed unnecessary line. --- Plugin.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Plugin.cs b/Plugin.cs index 4e9ba81..1ed9137 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -95,7 +95,6 @@ public override void OnAllPluginsLoaded(bool hotReload) return; } - var votes = CustomVotesApi.Get(); _isCustomVotesLoaded = true; Logger.LogInformation("Registering custom votes..."); RegisterCustomVotes(); From 32869258b7b35a0da87817151064e94f306a60dc Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sat, 8 Jun 2024 00:12:07 -0400 Subject: [PATCH 52/86] UPDATE: Fixed map groups Executing map groups was not working because the prefix mg_ wasn't being removed. --- Core/VoteManager.cs | 55 +++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs index 3be65bb..c73941f 100644 --- a/Core/VoteManager.cs +++ b/Core/VoteManager.cs @@ -1,5 +1,6 @@ // Included libraries using CounterStrikeSharp.API.Core; +using System.Text.RegularExpressions; // Copyright (c) 2024 imi-tat0r // https://github.com/imi-tat0r/CS2-CustomVotes/ @@ -30,28 +31,25 @@ private void RegisterCustomVotes() // Add menu option for each game mode in game mode list foreach (KeyValuePair _entry in Config.GameMode.List) { - if(_entry.Key != null) - { - // Add mode to all modes vote - string _option=_entry.Key.ToLower(); - _modeOptions.Add(_entry.Value, new VoteOption(_entry.Value, new List { $"exec {_option}.cfg" })); + // Add mode to all modes vote + string _option=_entry.Key.ToLower(); + _modeOptions.Add(_entry.Value, new VoteOption(_entry.Value, new List { $"exec {_option}.cfg" })); - // Create per mode vote - Plugin.CustomVotesApi.Get()?.AddCustomVote( - _option, // Command to trigger the vote - new List(), // Aliases for the command (optional) - $"Change game mode to {_entry.Value}?", // Description - "No", // Default - 30, // Time to vote - new Dictionary // vote options - { - { "Yes", new VoteOption("{Green}Yes", new List { $"exec {_option}.cfg" })}, - { "No", new VoteOption("{Red}No", new List())}, - }, - "center", // Menu style - "center" or "chat" - -1 // Minimum percentage of votes required (-1 behaves like 50%) - ); - } + // Create per mode vote + Plugin.CustomVotesApi.Get()?.AddCustomVote( + _option, // Command to trigger the vote + new List(), // Aliases for the command (optional) + $"Change game mode to {_entry.Value}?", // Description + "No", // Default + 30, // Time to vote + new Dictionary // vote options + { + { "Yes", new VoteOption("{Green}Yes", new List { $"exec {_option}.cfg" })}, + { "No", new VoteOption("{Red}No", new List())}, + }, + "center", // Menu style - "center" or "chat" + -1 // Minimum percentage of votes required (-1 behaves like 50%) + ); } } else @@ -59,14 +57,18 @@ private void RegisterCustomVotes() // Add menu option for each map group foreach (MapGroup _mapGroup in MapGroups) { + // Add game mode to all game modes vote + var _regex = new Regex(@"^(mg_)"); + var _match = _regex.Match(_mapGroup.Name); - if(_mapGroup.DisplayName != null) - { - // Add game mode to all game modes vote - string _option=_mapGroup.Name.ToLower(); + if (_match.Success) + { + // Create new setting name + string _option = _mapGroup.Name.Substring(_match.Length); + _modeOptions.Add(_mapGroup.DisplayName, new VoteOption(_mapGroup.DisplayName, new List { $"exec {_option}.cfg" })); - // Create per mode vote + // Create per mode vote Plugin.CustomVotesApi.Get()?.AddCustomVote( _option, // Command to trigger the vote new List(), // Aliases for the command (optional) @@ -82,7 +84,6 @@ private void RegisterCustomVotes() -1 // Minimum percentage of votes required (-1 behaves like 50%) ); } - } } From d13feb1774f3d7b23b1f1d4441de28d4041c3ed3 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sat, 8 Jun 2024 00:13:41 -0400 Subject: [PATCH 53/86] UPDATE: CS2 Custom Vote Customization Updated lang files to desired color scheme. Removed sv_cheats vote from default configuration. --- .../CS2-CustomVotes/CS2-CustomVotes.json | 30 +------------------ .../plugins/CS2-CustomVotes/lang/cz.json | 8 ++--- .../plugins/CS2-CustomVotes/lang/de.json | 8 ++--- .../plugins/CS2-CustomVotes/lang/en.json | 8 ++--- .../plugins/CS2-CustomVotes/lang/pt-br.json | 8 ++--- .../plugins/CS2-CustomVotes/lang/pt-pt.json | 8 ++--- .../plugins/CS2-CustomVotes/lang/ru.json | 8 ++--- 7 files changed, 25 insertions(+), 53 deletions(-) diff --git a/lib/csgo/addons/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json b/lib/csgo/addons/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json index c9b9010..1771c52 100644 --- a/lib/csgo/addons/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json +++ b/lib/csgo/addons/counterstrikesharp/configs/plugins/CS2-CustomVotes/CS2-CustomVotes.json @@ -3,34 +3,6 @@ "VoteCooldown": 60, "ChatPrefix": "[{Green}Server{Default}]", "ForceStyle": "none", - "CustomVotes": [ - { - "Command": "cheats", - "CommandAliases": [], - "Description": "Vote to enable sv_cheats", - "TimeToVote": 30, - "Options": { - "Enable": { - "Text": "{Green}Enable", - "Commands": [ - "sv_cheats 1" - ] - }, - "Disable": { - "Text": "{Red}Disable", - "Commands": [ - "sv_cheats 0" - ] - } - }, - "DefaultOption": "Disable", - "Style": "chat", - "MinVotePercentage": -1, - "Permission": { - "RequiresAll": false, - "Permissions": ["@css/cheats"] - } - } - ], + "CustomVotes": [{}], "ConfigVersion": 2 } \ No newline at end of file diff --git a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/cz.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/cz.json index 84079f4..8b3df9a 100644 --- a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/cz.json +++ b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/cz.json @@ -1,9 +1,9 @@ { - "vote.disabled": "Speciální hlasování jsou {DarkBlue}vypnuta{Default}.", + "vote.disabled": "Speciální hlasování jsou {LightRed}vypnuta{Default}.", "vote.active": "Hlasování již probíhá.", - "vote.started": "Hráč {DarkBlue}{0}{Default} spustil hlasování pro {DarkBlue}{1}{Default}.", - "vote.cooldown": "Prosím, počkejte {DarkBlue}{0}{Default} sekund mezi hlasováním.", + "vote.started": "Hráč {Green}{0}{Default} spustil hlasování pro {Green}{1}{Default}.", + "vote.cooldown": "Prosím, počkejte {LightRed}{0}{Default} sekund mezi hlasováním.", "vote.already_voted": "Již jste hlasovali.", - "vote.finished_with": "Hlasování pro {DarkBlue}{0}{Default} skončilo s výsledkem {DarkBlue}{1}{Default} ({2} hlasy).", + "vote.finished_with": "Hlasování pro {Green}{0}{Default} skončilo s výsledkem {Green}{1}{Default} ({2} hlasy).", "vote.no_permission": "Nemáte potřebné oprávnění k zahájení tohoto hlasování." } \ No newline at end of file diff --git a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/de.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/de.json index e7c8b35..58ad93b 100644 --- a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/de.json +++ b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/de.json @@ -1,9 +1,9 @@ { - "vote.disabled": "Custom Votes sind {DarkBlue}deaktiviert{Default}.", + "vote.disabled": "Custom Votes sind {LightRed}deaktiviert{Default}.", "vote.active": "Es läuft bereits eine Abstimmung.", - "vote.started": "Spieler {DarkBlue}{0}{Default} hat eine Abstimmung über {DarkBlue}{1}{Default} gestartet.", - "vote.cooldown": "Bitte warte {DarkBlue}{0}{Default} Sekunden zwischen den Abstimmungen.", + "vote.started": "Spieler {Green}{0}{Default} hat eine Abstimmung über {Green}{1}{Default} gestartet.", + "vote.cooldown": "Bitte warte {LightRed}{0}{Default} Sekunden zwischen den Abstimmungen.", "vote.already_voted": "Du hast bereits abgestimmt.", - "vote.finished_with": "Abstimmung für {DarkBlue}{0}{Default} wurde mit {DarkBlue}{1}{Default} ({2} Stimmen) beendet.", + "vote.finished_with": "Abstimmung für {Green}{0}{Default} wurde mit {Green}{1}{Default} ({2} Stimmen) beendet.", "vote.no_permission": "Du hast nicht die nötigen Berechtigungen, um diese Abstimmung zu starten." } \ No newline at end of file diff --git a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/en.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/en.json index 61b27f3..69959b5 100644 --- a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/en.json +++ b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/en.json @@ -1,9 +1,9 @@ { - "vote.disabled": "Custom Votes are {DarkBlue}disabled{Default}.", + "vote.disabled": "Custom Votes are {LightRed}disabled{Default}.", "vote.active": "A vote is already in progress.", - "vote.started": "Player {DarkBlue}{0}{Default} started vote for {DarkBlue}{1}{Default}.", - "vote.cooldown": "Please wait {DarkBlue}{0}{Default} seconds between votes.", + "vote.started": "Player {Green}{0}{Default} started vote for {Green}{1}{Default}.", + "vote.cooldown": "Please wait {LightRed}{0}{Default} seconds between votes.", "vote.already_voted": "You have already voted.", - "vote.finished_with": "Vote for {DarkBlue}{0}{Default} ended with {DarkBlue}{1}{Default} ({2} votes).", + "vote.finished_with": "Vote for {Green}{0}{Default} ended with {Green}{1}{Default} ({2} votes).", "vote.no_permission": "You do not have the required permission to start this vote." } \ No newline at end of file diff --git a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-br.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-br.json index aabf24e..c957a1c 100644 --- a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-br.json +++ b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-br.json @@ -1,9 +1,9 @@ { - "vote.disabled": "As Votações Customizadas estão {DarkBlue}desabilitadas{Default}.", + "vote.disabled": "As Votações Customizadas estão {LightRed}desabilitadas{Default}.", "vote.active": "Uma votação está em progresso.", - "vote.started": "O Player {DarkBlue}{0}{Default} iniciou uma votação para {DarkBlue}{1}{Default}.", - "vote.cooldown": "Espere {DarkBlue}{0}{Default} segundos entre votações.", + "vote.started": "O Player {Green}{0}{Default} iniciou uma votação para {Green}{1}{Default}.", + "vote.cooldown": "Espere {LightRed}{0}{Default} segundos entre votações.", "vote.already_voted": "Você ja votou!", - "vote.finished_with": "Vote para {DarkBlue}{0}{Default}. Acaba em {DarkBlue}{1}{Default} ({2} votos).", + "vote.finished_with": "Vote para {Green}{0}{Default}. Acaba em {Green}{1}{Default} ({2} votos).", "vote.no_permission": "Você não tem permissões suficientes para iniciar uma votação." } diff --git a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-pt.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-pt.json index 0c53895..d3ed58d 100644 --- a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-pt.json +++ b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/pt-pt.json @@ -1,9 +1,9 @@ { - "vote.disabled": "Os votos personalizados estão {DarkBlue}DESATIVADOS{Default}!", + "vote.disabled": "Os votos personalizados estão {LightRed}DESATIVADOS{Default}!", "vote.active": "Já está a decorrer uma votação!", - "vote.started": "O jogador {DarkBlue}{0}{Default} começou uma votação para {DarkBlue}{1}{Default}", - "vote.cooldown": "Por favor espere {DarkBlue}{0}{Default} segundos entre as votações!", + "vote.started": "O jogador {Green}{0}{Default} começou uma votação para {Green}{1}{Default}", + "vote.cooldown": "Por favor espere {LightRed}{0}{Default} segundos entre as votações!", "vote.already_voted": "Já votou!", - "vote.finished_with": "Votar para {DarkBlue}{0}{Default} acaba em {DarkBlue}{1}{Default} ({2} votos).", + "vote.finished_with": "Votar para {Green}{0}{Default} acaba em {Green}{1}{Default} ({2} votos).", "vote.no_permission": "Não tem a permissão necessária para iniciar esta votação..." } \ No newline at end of file diff --git a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/ru.json b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/ru.json index 6c025f5..87dc910 100644 --- a/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/ru.json +++ b/lib/csgo/addons/counterstrikesharp/plugins/CS2-CustomVotes/lang/ru.json @@ -1,9 +1,9 @@ { - "vote.disabled": "Custom Votes {DarkBlue}отключен{Default}.", + "vote.disabled": "Custom Votes {LightRed}отключен{Default}.", "vote.active": "Голосование уже началось.", - "vote.started": "Игрок {DarkBlue}{0}{Default} начал голосование {DarkBlue}{1}{Default}.", - "vote.cooldown": "Пожалуйста, подождите {DarkBlue}{0}{Default} секунд между голосованиями.", + "vote.started": "Игрок {Green}{0}{Default} начал голосование {Green}{1}{Default}.", + "vote.cooldown": "Пожалуйста, подождите {LightRed}{0}{Default} секунд между голосованиями.", "vote.already_voted": "Вы уже проголосовали.", - "vote.finished_with": "Голосование {DarkBlue}{0}{Default} закончилось с {DarkBlue}{1}{Default} ({2} голосов).", + "vote.finished_with": "Голосование {Green}{0}{Default} закончилось с {Green}{1}{Default} ({2} голосов).", "vote.no_permission": "У вас нет прав для начала этого голосования." } From c5e110f233cc14bad74bff7a6faee4ac0fd24781 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 8 Jun 2024 21:43:48 -0400 Subject: [PATCH 54/86] Update README.md (v1.0.4) Includes all new features, commands, and settings from version 1.0.4. --- README.md | 267 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 206 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index dbbfaab..0bc65d0 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ ![Copyright Nickj609l](https://img.shields.io/badge/Copyright-Nickj609-red) ![GitHub License](https://img.shields.io/github/license/nickj609/GameModeManager) ![Issues](https://img.shields.io/github/issues/nickj609/GameModeManager) ![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/nickj609/GameModeManager/total) ![GitHub commits since latest release](https://img.shields.io/github/commits-since/nickj609/GameModeManager/latest) # GameModeManager -A Counter-Strike 2 server plugin inspired by the [CS2 Modded Dedicated Server by Kus](https://github.com/kus/cs2-modded-server) and the [CS2 Rock The Vote plugin by Abnerfs](https://github.com/abnerfs/cs2-rockthevote). +A Counter-Strike 2 server plugin to help administrators manage custom game modes, settings, and map rotations. + +Inspired by [CS2 Modded Dedicated Server by Kus](https://github.com/kus/cs2-modded-server) and the [CS2 Rock The Vote plugin by Abnerfs](https://github.com/abnerfs/cs2-rockthevote). ## Description -GameModeManager streamlines your Counter-Strike 2 server administration with these features: +GameModeManager streamlines server administration with these features: - **Admin Game Mode Menu:** Effortlessly switch between game modes. - **Admin Map List Menu:** Effortlessly switch between maps within the current game mode. @@ -14,151 +16,294 @@ GameModeManager streamlines your Counter-Strike 2 server administration with the ## Credits This plugin utilizes the [GameLoop.Vdf library](https://github.com/shravan2x/Gameloop.Vdf/) (licensed under the [MIT License](https://github.com/shravan2x/Gameloop.Vdf/blob/master/LICENSE)) for parsing the `gamemodes_server.txt` file, which is in [Valve Data Format](https://developer.valvesoftware.com/wiki/VDF). +For creating custom votes, this plugin utilizes the [CS2-CustomVotes](https://github.com/imi-tat0r/CS2-CustomVotes) shared plugin API (licensed under the [MIT License](https://github.com/imi-tat0r/CS2-CustomVotes?tab=MIT-1-ov-file)). + ## Requirements - [Counter-Strike 2](https://www.counter-strike.net/cs2) - [Metamod:Source](https://github.com/alliedmodders/metamod-source/) (v1282+) - [CounterStrikeSharp](https://github.com/roflmuffin/CounterStrikeSharp) (v.197+) -> [!NOTE] -> If you are using the [CS2 Modded Dedicated Server by Kus](https://github.com/kus/cs2-modded-server) you should remove the [Ultimate Map Chooser](https://github.com/kus/cs2-modded-server/tree/master/game/csgo/addons/counterstrikesharp/plugins/CS2-Ultimate-Mapchooser) plugin until the pull request is approved/finalized. +## Server Commands +- `css_mapgroup ` - Sets the map group and updates the map list and menus. -## Commands +## Admin Commands +The below commands require the ***@css/changemap*** role. -Server Only -- `css_mapgroup ` - Sets the map group and updates the map list. - -Client Only +### Maps - `!map ` - Changes the map to the map specified. - > The map id is optional and only required if not already specified in an existing map group. + > The map ID is *optional* and only required for maps that aren't explicitly set in `gamemodes_server.txt` for a given map group. + +- `!maps (css_maps)` - Displays an admin menu for changing the map. It only shows maps for the current game mode/map group. + + ![Screenshot 2024-06-08 212858](https://github.com/nickj609/GameModeManager/assets/32173425/e3f4dfa8-a151-48b3-8c70-c866274a11cd) + +### Game Modes +- `!mode (css_mode)` - Changes the game mode to the mode specified. + + > Only the mode name is required. For example, for **mg_surf** you would do **!mode surf**. + +- `!modes (css_modes)` - Displays an admin menu for changing the game mode. + + ![Screenshot 2024-06-08 211937](https://github.com/nickj609/GameModeManager/assets/32173425/7f9c46f1-4ed3-47a9-b135-3a0d1e5cabed) -- `!mode (css_mode)` - Changes the game mode to the mode specified. +## Game Settings +- `!setting (css_setting)` - Enables or disables a custom game setting. - > Only the mode name is required. For example, for mg_surf you would do !mode surf. + > Only the setting name is required. For example, **enable_movement_unlock.cfg** would be **!setting movement_unlock**. -- `!modes (css_modes)` - Displays an admin menu with game mode options. +- `!settings (css_settings)` - Displays an admin menu for enabling or disabling custom game settings. + + ![Screenshot 2024-06-08 212010](https://github.com/nickj609/GameModeManager/assets/32173425/75fb865f-63ec-498c-84f8-b451d1edea45) + + ![Screenshot 2024-06-08 212046](https://github.com/nickj609/GameModeManager/assets/32173425/34206829-f570-4b00-a025-795d8431057c) + +## User Commands +The below commands require the ***@css/cvar*** role. + +## Vote settings +- `!changemode` - Creates a vote to change the game mode (all modes). + + ![Screenshot 2024-06-08 212539](https://github.com/nickj609/GameModeManager/assets/32173425/f5e3d915-4c01-45d5-95a2-a40b693e17bb) + + ![Screenshot 2024-06-08 212613](https://github.com/nickj609/GameModeManager/assets/32173425/fa6473c6-5372-4c4b-afb6-2ef5087ea550) + +- `!showmodes` - Menu to display all per mode votes that can be created. + + ![Screenshot 2024-06-08 212831](https://github.com/nickj609/GameModeManager/assets/32173425/8fd7e73f-c2e9-459d-bf33-9878de227f55) + + ![Screenshot 2024-06-08 213033](https://github.com/nickj609/GameModeManager/assets/32173425/4b252eb5-69ef-4973-89b8-b48c2f6f7019) + + ![image](https://github.com/nickj609/GameModeManager/assets/32173425/9e5ccb36-ff93-424d-887e-309fcc3b9012) + +- `!showsettings` - Menu to display all per setting votes that can be created. + + ![Screenshot 2024-06-08 212803](https://github.com/nickj609/GameModeManager/assets/32173425/16a907d1-3bd9-4416-bda6-4d6cc4c55030) + + ![Screenshot 2024-06-08 213008](https://github.com/nickj609/GameModeManager/assets/32173425/b6a34ec1-277f-4361-bd1c-0e405b20834f) + + ![Screenshot 2024-06-08 213124](https://github.com/nickj609/GameModeManager/assets/32173425/3c704378-5c89-4e49-9fcc-750f7e61d628) + +- `!showmaps` - Menu to display all per map votes that can be created. This only shows maps from the current map group/game mode. + + ![Screenshot 2024-06-08 212858](https://github.com/nickj609/GameModeManager/assets/32173425/1ba2a65a-8867-420c-9576-5549fa5e5469) + + ![Screenshot 2024-06-08 212923](https://github.com/nickj609/GameModeManager/assets/32173425/eb6a198a-a2cf-477b-ba02-ca6469bd38fc) + + ![Screenshot 2024-06-08 213358](https://github.com/nickj609/GameModeManager/assets/32173425/0e188f9d-3c50-47bf-9f48-57ff0cb286e0) - ![Screenshot 2024-03-21 161458](https://github.com/nickj609/GameModeManager/assets/32173425/db33fe48-21f3-455c-9987-5406fca99c4f) -- `!maps (css_maps)` - Displays an admin menu with maps for the current game mode/map group. - ![Screenshot 2024-03-21 161416](https://github.com/nickj609/GameModeManager/assets/32173425/f9c193b0-2ad3-4fa1-8a83-eaac812d2f21) ## RTV Plugin Compatibility > [!IMPORTANT] -> You will need to manually enable RTV Plugin Compatibility within the configuration file after the first load. +> After the first load, enable RTV Plugin Compatibility within the configuration file. -This plugin is compatible with any RTV plugin as long as it uses a maplist.txt file. +This plugin is compatible with any RTV plugin using a maplist.txt file. ![Screenshot 2024-03-21 161846](https://github.com/nickj609/GameModeManager/assets/32173425/1e291efb-fe7f-4f0d-bb2c-e21d042bd153) ## Installation 1. Install Metamod:Source and Counter Strike Sharp. 2. Copy DLLs to `csgo/addons/counterstrikesharp/plugins/GameModeManager`. -3. Make sure your `gamemodes_server.txt` file is in VDF format and contains a list of map groups. -4. If needed, update your custom configuration files for each game mode to include `css_mapgroup `. -5. After the first run, update the configuration file `GameModeManager.json` as detailed below. +3. Make sure your `gamemodes_server.txt` or custom map group file is in[VDF Format](https://developer.valvesoftware.com/wiki/VDF) and contains a list of map groups. +4. If you are not using the JSON configuration file for specifying game modes, include the "displayname" property within your `gamemodes_server.txt` or custom map group file for each map group. + + Example: + ``` + "mg_dm" + { + "imagename" "mapgroup-bomb" + "displayname" "Deathmatch" + "nameID" "#SFUI_Mapgroup_allclassic" + "tooltipID" "#SFUI_MapGroup_Tooltip_Desc_DeathMatch" + "name" "mg_dm" + "icon_image_path" "map_icons/mapgroup_icon_deathmatch" + "maps" + { + "ar_shoots" "" + "ar_baggage" "" + "workshop/3070550406/de_safehouse" "" + "workshop/3070563536/de_lake" "" + "workshop/3070581293/de_bank" "" + "workshop/3070923343/fy_pool_day" "" + "workshop/3070238628/fy_iceworld" "" + "workshop/3070291913/ar_churches_s2r" "" + "workshop/3082113929/aim_ag_texture_city_advanced" "" + "workshop/3074961197/aim_ag_texture2" "" + "workshop/3095778105/aim_ag_texture_jungle" "" + "workshop/3109232789/gg_simpsons_vs_flanders_v2" "" + "workshop/3086555291/shipment_version_1_0" "" + "workshop/3131645522/de_rust" "" + "workshop/3133577140/nuketown" "" + "workshop/3080114822/mansion" "" + } + } + ``` + +5. If needed, update each game mode configuration file (i.e. comp.cfg) to include `css_mapgroup `. +6. After the first run, update the configuration file `GameModeManager.json` as detailed below. ## Configuration > [!IMPORTANT] > On the first load, a configuration file will be created in `csgo/addons/counterstrikesharp/configs/plugins/GameModeManager/GameModeManager.json`. -GameModeManager offers flexible configuration options. See below for details and customization instructions. +GameModeManager offers the following configuration options within the `GameModeManager.json` file: ### RTV Settings | Setting | Description | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| Enabled | When enabled, the RTV plugin specified will be reloaded after updating the maplist.txt file. | -| Plugin | This is the default path to the RTV Plugin you are using. This can also just be the module name. | -| MapListFile | This is the default path for the maplist.txt file that will be updated when the map group or game mode changes. | -| DefaultMapFormat | When enabled, the format for adding maps to the maplist.txt file will be `ws:{workshopid}` instead of `{mapname}:{workshopid}`. | +| Enabled | Enables RTV Compatibility. The RTV plugin specified will be reloaded after updating the maplist.txt file. | +| Plugin | Default path for the desired RTV plugin. This can also be the module name. | +| MapListFile | Default path for the maplist.txt file to update when the map group or game mode changes. | +| DefaultMapFormat | Enables the default format for adding maps to the map list file: `ws:{workshopid}`. When disabled: `{mapname}:{workshopid}`. | + +### Game Settings +| Setting | Description | +| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| Enabled | Enables game settings. | +| Folder | Default settings folder. | +| Style | Changes setting menus type (i.e. "chat" or "center") | ### Map Group Settings | Setting | Description | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| Default | Default map group on server start (i.e. mg_active). | -| File | Default path for the gamemodes_server.txt file used to specify game modes and map groups. | +| Delay | Map change change delay in seconds. | +| Default | Default map group on server start (i.e. mg_active). | +| File | Map groups file name. The file must be in [VDF Format](https://developer.valvesoftware.com/wiki/VDF) and within the `csgo` directory. | ### Game Mode Settings | Setting | Description | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| ListEnabled | When enabled, the game mode list specified will be used. Otherwise, the list will be generated based on the map groups discovered. | -| List | A list of game modes for your server. | +| Rotation | Enables game mode rotation. | +| Interval | Changes game mode every x map rotations. | +| Delay | Delay for changing game modes in seconds. | +| Style | Changes setting menus type (i.e. "chat" or "center") | +| ListEnabled | Uses the game mode list specified. Otherwise, the list will be generated based on the map groups discovered. | +| List | A customizable list of game modes for your server with friendly names. | + +### Vote Settings +| Setting | Description | +| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| Enabled | Enables game | +| Folder | Default settings folder. | +| Style | Changes setting menus type (i.e. "chat" or "center") | > [!NOTE] -> - All game mode configuration files must be located in the `csgo/cfg` directory and include `css_mapgroup` to set the current map group. -> - If `ListEnabled` is set to `false`, the Game Mode List will be created based on the discovered map groups. For example, `mg_surf` would display as `surf` and the `surf.cfg` would be executed. +> - All game mode configuration files must be in the `csgo/cfg` directory and include `css_mapgroup` to specify the current map group. +> - If `ListEnabled` is set to `false`, the game mode list will be created based on the discovered map groups. For example, `mg_surf` would display as `Surf` and the `surf.cfg` would be executed. ### Default Values ``` -// This configuration was automatically generated by CounterStrikeSharp for plugin 'GameModeManager', at 2024/04/01 04:22:02 +// This configuration was automatically generated by CounterStrikeSharp for plugin 'GameModeManager', at 2024/06/08 09:52:11 { + "Version": 2, "RTV": { "Enabled": false, - "Plugin": "/home/steam/cs2/game/csgo/addons/counterstrikesharp/plugins/RockTheVote/RockTheVote.dll", - "MapListFile": "/home/steam/cs2/game/csgo/addons/counterstrikesharp/plugins/RockTheVote/maplist.txt", + "Plugin": "addons/counterstrikesharp/plugins/RockTheVote/RockTheVote.dll", + "MapListFile": "addons/counterstrikesharp/plugins/RockTheVote/maplist.txt", "DefaultMapFormat": false }, "MapGroup": { + "Delay": 5, "Default": "mg_active", - "File": "/home/steam/cs2/game/csgo/gamemodes_server.txt" + "File": "gamemodes_server.txt" + }, + "Settings": { + "Enabled": true, + "Folder": "settings", + "Style": "center" }, "GameMode": { + "Rotation": true, + "Interval": 4, + "Delay": 5, + "Style": "center", "ListEnabled": true, - "List": [ - "comp", - "1v1", - "aim", - "awp", - "scoutzknivez", - "wingman", - "gungame", - "surf", - "dm", - "dm-multicfg", - "course", - "hns", - "kz", - "minigames" - ] + "List": { + "comp": "Competitive", + "1v1": "1 vs 1", + "aim": "Aim", + "awp": "AWP Only", + "scoutzknivez": "ScoutzKnives", + "wingman": "Wingman", + "gungame": "Gun Game", + "surf": "Surf", + "dm": "Deathmatch", + "dm-multicfg": "Deathmatch Multicfg", + "course": "Course", + "hns": "Hide N Seek", + "kz": "Kreedz", + "minigames": "Mini Games" + } + }, + "Votes": { + "Enabled": false, + "Map": false, + "GameMode": false, + "GameSetting": false, + "Style": "center" }, - "ConfigVersion": 1 + "ConfigVersion": 2 } ``` ### Languages -This plugin will display all in-game menus and messaging within the language of the player. Below is an example language configuration you can customize to your liking. +This plugin will display all in-game menus and messaging based on the player's preferred language. Below is an example language configuration file you can customize to your liking. The [CS2-CustomVotes](https://github.com/imi-tat0r/CS2-CustomVotes) plugin also has additional language files you can configure. /lang/en.json ``` { "plugin.prefix": "[{GREEN}Server{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} has changed the map to {LIGHTRED}{1}{DEFAULT}.", + "changemap.message": "{LIGHTRED}{0}{DEFAULT} has changed the map to {LIGHTRED}{1}{DEFAULT}.", "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} has changed the game mode to {LIGHTRED}{1}{DEFAULT}.", - "mode.hud.menu-title": "Game Mode List", - "maps.hud.menu-title": "Map List" + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} has {LIGHTRED}Enabled{DEFAULT} setting {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} has {LIGHTRED}Disabled{DEFAULT} setting {LIGHTRED}{1}{DEFAULT}.", + "menu.yes": "Yes", + "menu.no": "No", + "menu.enable": "Enable", + "menu.disable": "Disable", + "mode.show.menu-response": "Say {GREEN}!{0}{DEFAULT} to create a vote.", + "mode.vote.menu-title": "Change game mode to {GOLD}{0}{DEFAULT}?", + "modes.menu-title": "Game Mode List", + "modes.vote.menu-title": "Change game mode?", + "map.vote.menu-title": "Change map to {0}?", + "maps.menu-title": "Map List", + "maps.show.menu-response": "Say {GREEN}!{0}{DEFAULT} to create a vote.", + "setting.vote.menu-title": "Change setting {GOLD}{0}{DEFAULT}?", + "setting.show.menu-response": "Say {GREEN}!{0}{DEFAULT} to create a vote.", + "settings.menu-actions": "Setting Actions", + "settings.menu-title": "Setting List" } + ``` ## Logging >[!WARNING] -> Due to the heavy use of the above configuration file to specify paths to files and plugins, you may run into several issues upon the initial deployment. All logs associated with this plugin can be found in the below location. +> Due to the need to parse map groups and settings, you may have difficulties initially configuring the plugin, especially if your gamemodes_server.txt is not configured properly. All logs associated with this plugin can be found in the below location. > > `csgo/addons/counterstrikesharp/logs` ### Example ``` -2024-04-01 03:26:13.249 +00:00 [INFO] plugin:GameModeManager Loading map groups... -2024-04-01 03:26:13.264 +00:00 [INFO] plugin:GameModeManager Creating game modes... +2024-06-08 02:01:09.232 +00:00 [INFO] plugin:GameModeManager Loading map groups... +2024-06-08 02:01:09.245 +00:00 [INFO] plugin:GameModeManager Creating game modes... +2024-06-08 02:01:09.246 +00:00 [INFO] plugin:GameModeManager Loading settings... +2024-06-08 02:01:09.247 +00:00 [WARN] plugin:GameModeManager Skipping allow_drop_knife.cfg because its missing the correct prefix. +2024-06-08 02:01:09.250 +00:00 [INFO] plugin:GameModeManager Creating settings menu... +2024-06-08 02:01:09.251 +00:00 [INFO] plugin:GameModeManager Enabling game mode and map rotations... +2024-06-08 02:01:09.252 +00:00 [INFO] plugin:GameModeManager Registering custom votes... 2024-04-01 03:27:20.767 +00:00 [INFO] plugin:GameModeManager Current map group is mg_active. 2024-04-01 03:27:20.768 +00:00 [INFO] plugin:GameModeManager New map group is mg_aim. +2024-06-08 02:04:44.973 +00:00 [INFO] plugin:GameModeManager Deregistering custom votes... ``` ### Common Error Messages -| Error Message | Description | +| Error/Warning Message | Description | | ---------------------------------------------------------------| ------------------------------------------------------------------------------------------------------------------------ | | `Cannot Find` | Unable to locate the file specified from `GameModeManager.json` config. | | `Incomplete VDF data` | Your `gamemodes_server.txt` file is not formatted properly in [VDF Format](https://developer.valvesoftware.com/wiki/VDF).| | `The mapgroup property doesn't exist` | The "mapgroup" property cannot be found in your `gamemodes_server.txt` file. | +| `Mapgroup found, but the 'maps' property is missing or incomplete` | The "maps" property cannot be found in your `gamemodes_server.txt` file for one of your map groups. | From a373ecd3455aa3533aef6432ff66688789f8cf62 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 8 Jun 2024 22:00:10 -0400 Subject: [PATCH 55/86] Update README.md Added additional information for clarity. --- README.md | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 0bc65d0..1ae5d35 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,12 @@ Inspired by [CS2 Modded Dedicated Server by Kus](https://github.com/kus/cs2-modd ## Description GameModeManager streamlines server administration with these features: -- **Admin Game Mode Menu:** Effortlessly switch between game modes. -- **Admin Map List Menu:** Effortlessly switch between maps within the current game mode. +- **Admin Game Mode Menu:** Switch between game modes. +- **Admin Setting Menu:** Enable or disable custom settings. +- **Admin Map List Menu:** Switch between maps within the current game mode. +- **Player Voting:** Voting for custom game modes, game settings, and maps. - **Default Map Cycles:** Automatically changes the map to a random map within the current map group. +- **Game Mode Rotations:** Specify how often you want the game mode to change. - **RTV Compatibility:** Works seamlessly with your chosen RTV plugin, ensuring smooth rock-the-vote functionality. ## Credits @@ -58,7 +61,7 @@ The below commands require the ***@css/changemap*** role. ![Screenshot 2024-06-08 212046](https://github.com/nickj609/GameModeManager/assets/32173425/34206829-f570-4b00-a025-795d8431057c) -## User Commands +## Player Commands The below commands require the ***@css/cvar*** role. ## Vote settings @@ -92,9 +95,6 @@ The below commands require the ***@css/cvar*** role. ![Screenshot 2024-06-08 213358](https://github.com/nickj609/GameModeManager/assets/32173425/0e188f9d-3c50-47bf-9f48-57ff0cb286e0) - - - ## RTV Plugin Compatibility > [!IMPORTANT] @@ -162,9 +162,9 @@ GameModeManager offers the following configuration options within the `GameModeM ### Game Settings | Setting | Description | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| Enabled | Enables game settings. | -| Folder | Default settings folder. | -| Style | Changes setting menus type (i.e. "chat" or "center") | +| Enabled | Enables game settings. Settings are parsed on plugin load. | +| Folder | Default settings folder in `csgo` directory. Add custom configuration files with `enable_` and `disable_` prefixes. | +| Style | Changes setting menu type (i.e. "chat" or "center"). | ### Map Group Settings | Setting | Description | @@ -179,23 +179,25 @@ GameModeManager offers the following configuration options within the `GameModeM | Rotation | Enables game mode rotation. | | Interval | Changes game mode every x map rotations. | | Delay | Delay for changing game modes in seconds. | -| Style | Changes setting menus type (i.e. "chat" or "center") | +| Style | Changes setting menus type (i.e. "chat" or "center"). | | ListEnabled | Uses the game mode list specified. Otherwise, the list will be generated based on the map groups discovered. | | List | A customizable list of game modes for your server with friendly names. | ### Vote Settings | Setting | Description | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| Enabled | Enables game | -| Folder | Default settings folder. | -| Style | Changes setting menus type (i.e. "chat" or "center") | +| Enabled | Enables voting. Votes are registered when all plugins have been loaded. | +| Map | Enabled map vote. | +| GameMode | Enabled game mode votes (all modes and per mode votes) | +| GameSetting | Enables game setting votes (per mode votes only) | +| Style | Changes vote menu type (i.e. "chat" or "center"). | > [!NOTE] > - All game mode configuration files must be in the `csgo/cfg` directory and include `css_mapgroup` to specify the current map group. +> - All game setting configuration files must be in the `csgo/` directory and include `css_mapgroup` to specify the current map group. > - If `ListEnabled` is set to `false`, the game mode list will be created based on the discovered map groups. For example, `mg_surf` would display as `Surf` and the `surf.cfg` would be executed. ### Default Values - ``` // This configuration was automatically generated by CounterStrikeSharp for plugin 'GameModeManager', at 2024/06/08 09:52:11 { @@ -277,7 +279,6 @@ This plugin will display all in-game menus and messaging based on the player's p "settings.menu-actions": "Setting Actions", "settings.menu-title": "Setting List" } - ``` ## Logging @@ -301,9 +302,9 @@ This plugin will display all in-game menus and messaging based on the player's p ``` ### Common Error Messages -| Error/Warning Message | Description | -| ---------------------------------------------------------------| ------------------------------------------------------------------------------------------------------------------------ | -| `Cannot Find` | Unable to locate the file specified from `GameModeManager.json` config. | -| `Incomplete VDF data` | Your `gamemodes_server.txt` file is not formatted properly in [VDF Format](https://developer.valvesoftware.com/wiki/VDF).| -| `The mapgroup property doesn't exist` | The "mapgroup" property cannot be found in your `gamemodes_server.txt` file. | -| `Mapgroup found, but the 'maps' property is missing or incomplete` | The "maps" property cannot be found in your `gamemodes_server.txt` file for one of your map groups. | +| Error/Warning Message | Description | +| -------------------------------------------------------------------| ------------------------------------------------------------------------------------------------------------------------ | +| `Cannot Find` | Unable to locate the file specified from `GameModeManager.json` config. | +| `Incomplete VDF data` | Your `gamemodes_server.txt` file is not formatted properly in [VDF Format](https://developer.valvesoftware.com/wiki/VDF).| +| `The mapgroup property doesn't exist` | The "mapgroup" property cannot be found in your `gamemodes_server.txt` file. | +| `Mapgroup found, but the 'maps' property is missing or incomplete` | The "maps" property cannot be found in your `gamemodes_server.txt` file for one of your map groups. | From 07f0bec57b2bf03f82528e38c2e286b96c6a0dea Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 8 Jun 2024 22:06:30 -0400 Subject: [PATCH 56/86] UPDATE: README.md Added config file error message. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1ae5d35..55920fc 100644 --- a/README.md +++ b/README.md @@ -306,5 +306,6 @@ This plugin will display all in-game menus and messaging based on the player's p | -------------------------------------------------------------------| ------------------------------------------------------------------------------------------------------------------------ | | `Cannot Find` | Unable to locate the file specified from `GameModeManager.json` config. | | `Incomplete VDF data` | Your `gamemodes_server.txt` file is not formatted properly in [VDF Format](https://developer.valvesoftware.com/wiki/VDF).| +| `Your config file is too old` | Please delete it from `addons/counterstrikesharp/configs/plugins/GameModeManager` and let the plugin recreate it on load.| | `The mapgroup property doesn't exist` | The "mapgroup" property cannot be found in your `gamemodes_server.txt` file. | | `Mapgroup found, but the 'maps' property is missing or incomplete` | The "maps" property cannot be found in your `gamemodes_server.txt` file for one of your map groups. | From b14285a988c315b2e16d28a3fc635f5baa2c58d2 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sat, 8 Jun 2024 22:23:11 -0400 Subject: [PATCH 57/86] UPDATE: Error checking logic --- Config.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Config.cs b/Config.cs index c830699..c25cf76 100644 --- a/Config.cs +++ b/Config.cs @@ -128,15 +128,21 @@ public void OnConfigParsed(Config _config) Logger.LogError("Invalid: votes enabled should be 'true' or 'false'."); throw new Exception("Invalid: votes enabled should be 'true' or 'false'."); } - if (_config.Votes.GameMode != true && _config.Votes.Enabled != false) + if (_config.Votes.GameMode != true &&_config.Votes.GameMode != false) { - Logger.LogError("Invalid: gane nide should be 'true' or 'false'."); - throw new Exception("Invalid: gane nide should be 'true' or 'false'."); + Logger.LogError("Invalid: game mode votes should be 'true' or 'false'."); + throw new Exception("Invalid: game mode vote should be 'true' or 'false'."); } - if (_config.Votes.GameSetting != true && _config.Votes.Enabled != false) + if (_config.Votes.GameSetting != true && _config.Votes.GameSetting != false) { - Logger.LogError("Invalid: game settings should be 'true' or 'false'."); - throw new Exception("Invalid: game settings should be 'true' or 'false'."); + Logger.LogError("Invalid: game setting votes should be 'true' or 'false'."); + throw new Exception("Invalid: game setting vote should be 'true' or 'false'."); + } + + if (_config.Votes.Map != true && _config.Votes.Map != false) + { + Logger.LogError("Invalid: map vote should be 'true' or 'false'."); + throw new Exception("Invalid: map vote should be 'true' or 'false'."); } // Config version check @@ -202,6 +208,7 @@ public class GameModeSettings public class VoteSettings { public bool Enabled { get; set; } = false; // Enables CS2-CustomVotes compatibility + public bool Map { get; set; } = false; // Enables vote to change game to a specific map public bool GameMode { get; set; } = false; // Enables vote to change game mode public bool GameSetting { get; set; } = false; // Enables vote to change game setting public string Style { get; set; } = "center"; // Changes vote menu type (i.e. "chat" or "center") From 667cef5c665248f1065fd706a533e8b5554f2b07 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sat, 8 Jun 2024 22:23:44 -0400 Subject: [PATCH 58/86] ADDED: Show commands Added show commands for displaying menus of map list, mode list, and setting list. --- Core/CommandManager.cs | 59 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/Core/CommandManager.cs b/Core/CommandManager.cs index 329d3ba..f214b9a 100644 --- a/Core/CommandManager.cs +++ b/Core/CommandManager.cs @@ -18,6 +18,9 @@ public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) { if (player == null) { + // Deregister map votes + DeregisterMapVotes(); + // Get map group MapGroup? _mapGroup = MapGroups.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); @@ -38,6 +41,9 @@ public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) { Logger.LogError($"{ex.Message}"); } + + // Register map votes + RegisterMapVotes(); } } @@ -49,7 +55,7 @@ public void OnMapsCommand(CCSPlayerController? player, CommandInfo command) { if(player != null && _plugin != null && MapMenu != null) { - MapMenu.Title = Localizer["maps.hud.menu-title"]; + MapMenu.Title = Localizer["maps.menu-title"]; OpenMenu(MapMenu, Config.GameMode.Style, player); } } @@ -101,13 +107,13 @@ public void OnModesCommand(CCSPlayerController? player, CommandInfo command) { if(player != null && _plugin != null && ModeMenu != null) { - ModeMenu.Title = Localizer["mode.hud.menu-title"]; + ModeMenu.Title = Localizer["modes.menu-title"]; OpenMenu(ModeMenu, Config.GameMode.Style, player); } } // Construct admin change setting command handler - [RequiresPermissions("@css/cvar")] + [RequiresPermissions("@css/changemap")] [CommandHelper(minArgs: 2, usage: "[enable/disable] [setting name]", whoCanExecute: CommandUsage.CLIENT_ONLY)] [ConsoleCommand("css_setting", "Changes the game setting specified.")] public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) @@ -153,7 +159,7 @@ public void OnSettingCommand(CCSPlayerController? player, CommandInfo command) } // Construct admin setting menu command handler - [RequiresPermissions("@css/cvar")] + [RequiresPermissions("@css/changemap")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] [ConsoleCommand("css_settings", "Provides a list of game settings.")] public void OnSettingsCommand(CCSPlayerController? player, CommandInfo command) @@ -161,10 +167,53 @@ public void OnSettingsCommand(CCSPlayerController? player, CommandInfo command) if(player != null && _plugin != null && SettingsMenu != null) { // Open menu - SettingsMenu.Title = Localizer["settings.hud.menu-title"]; + SettingsMenu.Title = Localizer["settings.menu-actions"]; OpenMenu(SettingsMenu, Config.Settings.Style, player); } } + + // Construct show maps menu command handler + [RequiresPermissions("@css/cvar")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_showmaps", "Provides a list of maps from current mode.")] + public void OnShowMapsCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null && ShowMapsMenu != null) + { + // Open menu + ShowMapsMenu.Title = Localizer["maps.menu-title"]; + OpenMenu(ShowMapsMenu, Config.GameMode.Style, player); + } + + } + // Construct show maps menu command handler + [RequiresPermissions("@css/cvar")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_showmodes", "Provides a list of game modes.")] + public void OnShowModesCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null && ShowModesMenu != null) + { + // Open menu + ShowModesMenu.Title = Localizer["modes.menu-title"]; + OpenMenu(ShowModesMenu, Config.GameMode.Style, player); + } + + } + // Construct show maps menu command handler + [RequiresPermissions("@css/cvar")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + [ConsoleCommand("css_showsettings", "Provides a list of game settings.")] + public void OnShowSettingsCommand(CCSPlayerController? player, CommandInfo command) + { + if(player != null && _plugin != null && ShowSettingsMenu != null) + { + // Open menu + ShowSettingsMenu.Title = Localizer["settings.menu-title"]; + OpenMenu(ShowSettingsMenu, Config.Settings.Style, player); + } + + } } } \ No newline at end of file From 0077dd1a77c4c791cdd43f82b92a653b34f7650f Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sat, 8 Jun 2024 22:24:51 -0400 Subject: [PATCH 59/86] ADDED: New menus and localization Added new menus and updated localization. --- Core/MenuManager.cs | 213 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 197 insertions(+), 16 deletions(-) diff --git a/Core/MenuManager.cs b/Core/MenuManager.cs index c58bf1f..484d4db 100644 --- a/Core/MenuManager.cs +++ b/Core/MenuManager.cs @@ -2,8 +2,9 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using Microsoft.Extensions.Logging; +using System.Text.RegularExpressions; using CounterStrikeSharp.API.Modules.Menu; -using CS2_CustomVotes.Shared.Models; + // Declare namespace namespace GameModeManager { @@ -69,17 +70,19 @@ private void OpenMenu(BaseMenu _menu, string _menuType, CCSPlayerController _pla public void SetupSettingsMenu() { // Assign menus - SettingsMenu = AssignMenu(Config.Settings.Style, "Settings Menu"); - SettingsEnableMenu = AssignMenu(Config.Settings.Style, "Settings Menu"); - SettingsDisableMenu = AssignMenu(Config.Settings.Style, "Settings Menu"); + SettingsMenu = AssignMenu(Config.Settings.Style, "Setting Actions"); + SettingsEnableMenu = AssignMenu(Config.Settings.Style, "Settings List"); + SettingsDisableMenu = AssignMenu(Config.Settings.Style, "Settings List"); // Add enable menu options foreach (Setting _setting in Settings) { SettingsEnableMenu.AddMenuOption(_setting.DisplayName, (player, option) => { + // Create message + string _message = Localizer["plugin.prefix", player.PlayerName, option.Text] + " " + Localizer["enable.changesetting.message", player.PlayerName, option.Text]; // Write to chat - Server.PrintToChatAll(Localizer["enable.changesetting.message", player.PlayerName, option.Text]); + Server.PrintToChatAll(_message); // Change game setting Server.ExecuteCommand($"exec {Config.Settings.Folder}/{_setting.Enable}"); @@ -94,8 +97,11 @@ public void SetupSettingsMenu() { SettingsDisableMenu.AddMenuOption(_setting.DisplayName, (player, option) => { + // Create message + string _message = Localizer["plugin.prefix", player.PlayerName, option.Text] + " " + Localizer["disable.changesetting.message", player.PlayerName, option.Text]; + // Write to chat - Server.PrintToChatAll(Localizer["disable.changesetting.message", player.PlayerName, option.Text]); + Server.PrintToChatAll(_message); // Change game setting Server.ExecuteCommand($"exec {Config.Settings.Folder}/{_setting.Disable}"); @@ -106,18 +112,18 @@ public void SetupSettingsMenu() } // Add settings menu options - SettingsMenu.AddMenuOption("Enable settings", (player, option) => + SettingsMenu.AddMenuOption(Localizer["menu.enable"], (player, option) => { - SettingsEnableMenu.Title = Localizer["settings.enable.hud.menu-title"]; + SettingsEnableMenu.Title = Localizer["settings.menu-title"]; if(player != null && _plugin != null) { OpenMenu(SettingsEnableMenu, Config.GameMode.Style, player); } }); - SettingsMenu.AddMenuOption("Disable settings", (player, option) => + SettingsMenu.AddMenuOption(Localizer["menu.disable"], (player, option) => { - SettingsDisableMenu.Title = Localizer["settings.disable.hud.menu-title"]; + SettingsDisableMenu.Title = Localizer["settings.menu-title"]; if(player != null && _plugin != null) { @@ -126,6 +132,12 @@ public void SetupSettingsMenu() } }); + + // Setup show settings menu + if(Config.Votes.GameSetting) + { + SetupShowSettingsMenu(); + } } // Define mode menu @@ -135,7 +147,7 @@ public void SetupSettingsMenu() private void SetupModeMenu() { // Assign menu - ModeMenu = AssignMenu(Config.GameMode.Style, "Game Mode Menu"); + ModeMenu = AssignMenu(Config.GameMode.Style, "Game Mode List"); if (Config.GameMode.ListEnabled) { @@ -144,8 +156,11 @@ private void SetupModeMenu() { ModeMenu.AddMenuOption(_entry.Value, (player, option) => { + // Create message + string _message = Localizer["plugin.prefix", player.PlayerName, option.Text] + " " + Localizer["changemode.message", player.PlayerName, option.Text]; + // Write to chat - Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); + Server.PrintToChatAll(_message); // Change game mode string _option = _entry.Key.ToLower(); @@ -166,8 +181,11 @@ private void SetupModeMenu() { ModeMenu.AddMenuOption(_mapGroup.DisplayName, (player, option) => { + // Create message + string _message = Localizer["plugin.prefix", player.PlayerName, option.Text] + " " + Localizer["changemode.message", player.PlayerName, option.Text]; + // Write to chat - Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); + Server.PrintToChatAll(_message); // Change game mode string _option = option.Text.ToLower(); @@ -190,8 +208,11 @@ private void SetupModeMenu() ModeMenu.AddMenuOption(_mapGroupName, (player, option) => { + // Create message + string _message = Localizer["plugin.prefix", player.PlayerName, option.Text] + "" + Localizer["changemode.message", player.PlayerName, option.Text]; + // Write to chat - Server.PrintToChatAll(Localizer["changemode.message", player.PlayerName, option.Text]); + Server.PrintToChatAll(_message); // Change game mode string _option = option.Text.ToLower(); @@ -204,6 +225,12 @@ private void SetupModeMenu() } } } + + // Setup show modes menu + if(Config.Votes.GameMode) + { + SetupShowModesMenu(); + } } // Define map menu @@ -212,7 +239,8 @@ private void SetupModeMenu() // Construct reusable function to update the map menu private void UpdateMapMenu(MapGroup _mapGroup) { - MapMenu = new CenterHtmlMenu("Map List"); + // Assign menu + MapMenu = AssignMenu(Config.GameMode.Style, "Map List"); // Add menu options for each map in the new map list foreach (Map _map in _mapGroup.Maps) @@ -226,8 +254,12 @@ private void UpdateMapMenu(MapGroup _mapGroup) Logger.LogWarning("Map not found when updating map menu. Using de_dust2 for next map."); _nextMap = new Map("de_dust2"); } + + // Create message + string _message = Localizer["plugin.prefix", player.PlayerName, option.Text] + " " + Localizer["changemap.message", player.PlayerName, _nextMap.Name]; + // Write to chat - Server.PrintToChatAll(Localizer["changemap.message", player.PlayerName, _nextMap.Name]); + Server.PrintToChatAll(_message); // Change map AddTimer(Config.MapGroup.Delay, () => ChangeMap(_nextMap)); @@ -236,6 +268,155 @@ private void UpdateMapMenu(MapGroup _mapGroup) MenuManager.CloseActiveMenu(player); }); } + + // Update show maps menu with new map list + if(Config.Votes.Map) + { + UpdateShowMapsMenu(); + } + } + + // Define show map menu + public static BaseMenu? ShowMapsMenu; + + // Construct resuable function to set up show maps menu + private void UpdateShowMapsMenu() + { + // Assign menu + ShowMapsMenu = AssignMenu(Config.GameMode.Style, "Map List"); + + foreach (Map _map in CurrentMapGroup.Maps) + { + // Add menu option + ShowMapsMenu.AddMenuOption(_map.Name, (player, option) => + { + // Create message + string _message = Localizer["maps.show.menu-response", _map.Name]; + + // Write to chat + player.PrintToChat(_message); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + } + + // Define show map menu + public static BaseMenu? ShowModesMenu; + + // Construct resuable function to set up show maps menu + private void SetupShowModesMenu() + { + // Assign menu + ShowModesMenu = AssignMenu(Config.GameMode.Style, "Game Mode List"); + + if (Config.GameMode.ListEnabled) + { + foreach (KeyValuePair _entry in Config.GameMode.List) + { + // Add menu option + ShowModesMenu.AddMenuOption(_entry.Value, (player, option) => + { + // Create message + string _message = Localizer["mode.show.menu-response", _entry.Key]; + + // Write to chat + Server.PrintToChatAll(_message); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + } + else + { + foreach (MapGroup _mapGroup in MapGroups) + { + if(_mapGroup.Name != null) + { + + // Remove mode prefix + var _regex = new Regex(@"^(mg_)"); + var _match = _regex.Match(_mapGroup.Name); + string _mode = _mapGroup.Name; + + if (_match.Success) + { + // Create new mode name + _mode = _mapGroup.Name.Substring(_match.Length); + } + + // Add menu option + ShowModesMenu.AddMenuOption(_mapGroup.DisplayName, (player, option) => + { + // Create message + string _message = Localizer["mode.show.menu-response", _mode]; + + // Write to chat + Server.PrintToChatAll(_message); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + else + { + // Split the string into parts by the underscore + string[] _nameParts = (_mapGroup.Name ?? _defaultMapGroup.Name).Split('_'); + + // Get the last part (the actual map group name) + string _tempName = _nameParts[_nameParts.Length - 1]; + + // Combine the capitalized first letter with the rest + string _mapGroupName = _tempName.Substring(0, 1).ToUpper() + _tempName.Substring(1); + + ShowModesMenu.AddMenuOption(_mapGroupName, (player, option) => + { + // Create message + string _message = Localizer["plugin.prefix", player.PlayerName, option.Text] + "" + Localizer["changemode.message", player.PlayerName, option.Text]; + + // Write to chat + Server.PrintToChatAll(_message); + + // Change game mode + string _option = option.Text.ToLower(); + AddTimer(Config.GameMode.Delay, () => Server.ExecuteCommand($"exec {_option}.cfg")); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + + } + } + } + } + + // Define show map menu + public static BaseMenu? ShowSettingsMenu; + + // Construct resuable function to set up show maps menu + private void SetupShowSettingsMenu() + { + // Assign menu + ShowSettingsMenu = AssignMenu(Config.Settings.Style, "Setting List"); + + foreach (Setting _setting in Settings) + { + // Add menu option + ShowSettingsMenu.AddMenuOption(_setting.DisplayName, (player, option) => + { + // Create message + string _message = Localizer["setting.show.menu-response", _setting.Name]; + + // Write to chat + player.PrintToChat(_message); + + // Close menu + MenuManager.CloseActiveMenu(player); + }); + } + } } } \ No newline at end of file From 04fb721c2b02e1f661a0eb0f8c205e70a5c9be95 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sat, 8 Jun 2024 22:25:11 -0400 Subject: [PATCH 60/86] UPDATE: Localization Updated localization --- Core/VoteManager.cs | 90 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 17 deletions(-) diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs index c73941f..9e7ee9c 100644 --- a/Core/VoteManager.cs +++ b/Core/VoteManager.cs @@ -15,20 +15,22 @@ public partial class Plugin : BasePlugin // Define vote flags for deregistration bool _gamemodeVote = false; bool _settingVote = false; + bool _mapVote = false; // Construct reusable function to register custom votes private void RegisterCustomVotes() { + // Check if game mode votes are enable if(Config.Votes.GameMode) { // Define mode options var _modeOptions = new Dictionary(); - _modeOptions.Add("No", new VoteOption("No", new List())); + _modeOptions.Add("No", new VoteOption(Localizer["menu.no"], new List())); - // Set mode options + // Check if using game mode list or map group list if (Config.GameMode.ListEnabled) { - // Add menu option for each game mode in game mode list + // Add vote menu option for each game mode in game mode list foreach (KeyValuePair _entry in Config.GameMode.List) { // Add mode to all modes vote @@ -39,13 +41,13 @@ private void RegisterCustomVotes() Plugin.CustomVotesApi.Get()?.AddCustomVote( _option, // Command to trigger the vote new List(), // Aliases for the command (optional) - $"Change game mode to {_entry.Value}?", // Description + Localizer["modes.vote.menu-title", _entry.Value], // Description "No", // Default 30, // Time to vote new Dictionary // vote options { - { "Yes", new VoteOption("{Green}Yes", new List { $"exec {_option}.cfg" })}, - { "No", new VoteOption("{Red}No", new List())}, + { "Yes", new VoteOption(Localizer["menu.yes"], new List { $"exec {_option}.cfg" })}, + { "No", new VoteOption(Localizer["menu.no"], new List())}, }, "center", // Menu style - "center" or "chat" -1 // Minimum percentage of votes required (-1 behaves like 50%) @@ -54,31 +56,33 @@ private void RegisterCustomVotes() } else { - // Add menu option for each map group + // Add vote menu option for each map group foreach (MapGroup _mapGroup in MapGroups) { - // Add game mode to all game modes vote + // Define regex for map group prefix var _regex = new Regex(@"^(mg_)"); var _match = _regex.Match(_mapGroup.Name); + // Add game mode to all game modes vote if (_match.Success) { - // Create new setting name + // Remove mode prefix string _option = _mapGroup.Name.Substring(_match.Length); + // Add mode as vote menu option for all modes vote _modeOptions.Add(_mapGroup.DisplayName, new VoteOption(_mapGroup.DisplayName, new List { $"exec {_option}.cfg" })); // Create per mode vote Plugin.CustomVotesApi.Get()?.AddCustomVote( _option, // Command to trigger the vote new List(), // Aliases for the command (optional) - $"Change game mode to {_option}?", // Description + Localizer["mode.vote.menu-title", _mapGroup.DisplayName], // Description "No", 30, // Time to vote new Dictionary // vote options { - { "Yes", new VoteOption("{Green}Yes", new List { $"exec {_option}.cfg" })}, - { "No", new VoteOption("{Red}No", new List())}, + { "Yes", new VoteOption(Localizer["menu.yes"], new List { $"exec {_option}.cfg" })}, + { "No", new VoteOption(Localizer["menu.no"], new List())}, }, "center", // Menu style - "center" or "chat" -1 // Minimum percentage of votes required (-1 behaves like 50%) @@ -91,7 +95,7 @@ private void RegisterCustomVotes() Plugin.CustomVotesApi.Get()?.AddCustomVote( "changemode", // Command to trigger the vote new List {"cm"}, // aliases for the command (optional) - "Vote to change game mode.", // Description + Localizer["modes.vote.menu-title"], // Description "No", // Default option 30, // Time to vote _modeOptions, // All options @@ -101,6 +105,14 @@ private void RegisterCustomVotes() // Set game mode vote flag _gamemodeVote = true; + + // Register map votes + if(Config.Votes.Map == true) + { + RegisterMapVotes(); + // Set map vote flag + _mapVote = true; + } } if(Config.Votes.GameSetting) @@ -112,14 +124,14 @@ private void RegisterCustomVotes() Plugin.CustomVotesApi.Get()?.AddCustomVote( _setting.Name, // Command to trigger the vote new List(), // Aliases for the command (optional) - $"Change setting {_setting.DisplayName}?", // Description + Localizer["setting.vote.menu-title", _setting.DisplayName], // Description "No", // Default option 30, // Time to vote new Dictionary // vote options { - { "No", new VoteOption("No", new List())}, - { "Enable", new VoteOption("Enable", new List { $"exec {Config.Settings.Folder}/{_setting.Enable}" })}, - { "Disable", new VoteOption("Disable", new List{ $"exec {Config.Settings.Folder}/{_setting.Disable}" })}, + { "No", new VoteOption(Localizer["menu.no"], new List())}, + { "Enable", new VoteOption(Localizer["menu.enable"], new List { $"exec {Config.Settings.Folder}/{_setting.Enable}" })}, + { "Disable", new VoteOption(Localizer["menu.disable"], new List{ $"exec {Config.Settings.Folder}/{_setting.Disable}" })}, }, "center", // Menu style - "center" or "chat" -1 // Minimum percentage of votes required (-1 behaves like 50%) @@ -131,6 +143,47 @@ private void RegisterCustomVotes() } } + private void RegisterMapVotes() + { + // Get maps from current map group + List _maps = CurrentMapGroup.Maps; + + // Register per map vote + foreach (Map _map in _maps) + { + Plugin.CustomVotesApi.Get()?.AddCustomVote( + _map.Name, // Command to trigger the vote + new List(), // Aliases for the command (optional) + Localizer["map.vote.menu-title", _map.Name], // Description + "No", + 30, // Time to vote + new Dictionary // vote options + { + { "Yes", new VoteOption(Localizer["menu.yes"], new List { $"css_map {_map.Name} {_map.WorkshopId}" })}, + { "No", new VoteOption(Localizer["menu.no"], new List())}, + }, + "center", // Menu style - "center" or "chat" + -1 // Minimum percentage of votes required (-1 behaves like 50%) + ); + } + // Set map vote flag + _mapVote = true; + } + + private void DeregisterMapVotes() + { + if (_mapVote == true) + { + // Deregister per map vote + foreach (Map _map in Maps) + { + Plugin.CustomVotesApi.Get()?.RemoveCustomVote(_map.Name); + } + // Set map vote flag + _mapVote = false; + } + } + // Construct reusable function to deregister custom votes private void DeregisterCustomVotes() { @@ -173,6 +226,9 @@ private void DeregisterCustomVotes() Plugin.CustomVotesApi.Get()?.RemoveCustomVote(_setting.Name); } } + + // Deregister map votes + DeregisterMapVotes(); } } } \ No newline at end of file From a073660d54e4b6b2305fa06034d9f1fb0ce1f0bb Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sat, 8 Jun 2024 22:25:43 -0400 Subject: [PATCH 61/86] ADDED: Localization for new menus Added localization for new menus --- lang/de.json | 28 +++++++++++++++++++--------- lang/en.json | 22 ++++++++++++++++------ lang/es.json | 30 ++++++++++++++++++++---------- lang/fr.json | 28 +++++++++++++++++++--------- lang/hu.json | 28 +++++++++++++++++++--------- lang/lv.json | 30 ++++++++++++++++++++---------- lang/nl.json | 30 ++++++++++++++++++++---------- lang/pl.json | 30 ++++++++++++++++++++---------- lang/pt-BR.json | 28 +++++++++++++++++++--------- lang/ru.json | 32 +++++++++++++++++++++----------- lang/tr.json | 30 ++++++++++++++++++++---------- lang/ua.json | 32 +++++++++++++++++++++----------- lang/zh-Hans.json | 25 ++++++++++++++++++++----- 13 files changed, 254 insertions(+), 119 deletions(-) diff --git a/lang/de.json b/lang/de.json index 8a58de1..ffd1790 100644 --- a/lang/de.json +++ b/lang/de.json @@ -1,12 +1,22 @@ { "plugin.prefix": "[{GREEN}Server{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} hat die Karte zu {LIGHTRED}{1}{DEFAULT} geändert.", + "changemap.message": "{LIGHTRED}{0}{DEFAULT} hat die Karte zu {LIGHTRED}{1}{DEFAULT} geändert.", "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} hat den Spielmodus zu {LIGHTRED}{1}{DEFAULT} geändert.", - "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} hat die Einstellung {LIGHTRED}{1}{DEFAULT} {LIGHTRED}aktiviert{DEFAULT}.", - "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} hat die Einstellung {LIGHTRED}{1}{DEFAULT} {LIGHTRED}deaktiviert{DEFAULT}.", - "setting.hud.menu-title": "Einstellungenliste", - "mode.hud.menu-title": "Spielmodiliste", - "maps.hud.menu-title": "Kartenliste", - "settings.enable.hud.menu-title": "Einstellungen aktivieren", - "settings.disable.hud.menu-title": "Einstellungen deaktivieren" -} \ No newline at end of file + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} hat die Einstellung {LIGHTRED}{1}{DEFAULT} {LIGHTRED}Aktiviert{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} hat die Einstellung {LIGHTRED}{1}{DEFAULT} {LIGHTRED}Deaktiviert{DEFAULT}.", + "menu.yes": "Ja", + "menu.no": "Nein", + "menu.enable": "Aktivieren", + "menu.disable": "Deaktivieren", + "mode.show.menu-response": "Sage {GREEN}!{0}{DEFAULT} um eine Abstimmung zu erstellen.", + "mode.vote.menu-title": "Spielmodus zu {GOLD}{0}{DEFAULT} ändern?", + "modes.menu-title": "Spielmodi-Liste", + "modes.vote.menu-title": "Spielmodus ändern?", + "map.vote.menu-title": "Karte zu {0} ändern?", + "maps.menu-title": "Kartenliste", + "maps.show.menu-response": "Sage {GREEN}!{0}{DEFAULT} um eine Abstimmung zu erstellen.", + "setting.vote.menu-title": "Einstellung {GOLD}{0}{DEFAULT} ändern?", + "setting.show.menu-response": "Sage {GREEN}!{0}{DEFAULT} um eine Abstimmung zu erstellen.", + "settings.menu-actions": "Einstellungen-Aktionen", + "settings.menu-title": "Einstellungsliste" + } \ No newline at end of file diff --git a/lang/en.json b/lang/en.json index 614958a..7b90810 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1,12 +1,22 @@ { "plugin.prefix": "[{GREEN}Server{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} has changed the map to {LIGHTRED}{1}{DEFAULT}.", + "changemap.message": "{LIGHTRED}{0}{DEFAULT} has changed the map to {LIGHTRED}{1}{DEFAULT}.", "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} has changed the game mode to {LIGHTRED}{1}{DEFAULT}.", "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} has {LIGHTRED}Enabled{DEFAULT} setting {LIGHTRED}{1}{DEFAULT}.", "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} has {LIGHTRED}Disabled{DEFAULT} setting {LIGHTRED}{1}{DEFAULT}.", - "setting.hud.menu-title": "Settings List", - "mode.hud.menu-title": "Game Mode List", - "maps.hud.menu-title": "Map List", - "settings.enable.hud.menu-title": "Enable Settings", - "settings.disable.hud.menu-title": "Disable Settings" + "menu.yes": "Yes", + "menu.no": "No", + "menu.enable": "Enable", + "menu.disable": "Disable", + "mode.show.menu-response": "Say {GREEN}!{0}{DEFAULT} to create a vote.", + "mode.vote.menu-title": "Change game mode to {GOLD}{0}{DEFAULT}?", + "modes.menu-title": "Game Mode List", + "modes.vote.menu-title": "Change game mode?", + "map.vote.menu-title": "Change map to {0}?", + "maps.menu-title": "Map List", + "maps.show.menu-response": "Say {GREEN}!{0}{DEFAULT} to create a vote.", + "setting.vote.menu-title": "Change setting {GOLD}{0}{DEFAULT}?", + "setting.show.menu-response": "Say {GREEN}!{0}{DEFAULT} to create a vote.", + "settings.menu-actions": "Setting Actions", + "settings.menu-title": "Setting List" } diff --git a/lang/es.json b/lang/es.json index 022b51d..805caa5 100644 --- a/lang/es.json +++ b/lang/es.json @@ -1,12 +1,22 @@ { - "plugin.prefix": "[{GREEN}Servidor{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} ha cambiado el mapa a {LIGHTRED}{1}{DEFAULT}.", + "plugin.prefix": "[{GREEN}Servidor{DEFAULT}]", + "changemap.message": "{LIGHTRED}{0}{DEFAULT} ha cambiado el mapa a {LIGHTRED}{1}{DEFAULT}.", "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} ha cambiado el modo de juego a {LIGHTRED}{1}{DEFAULT}.", - "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} ha {LIGHTRED}habilitado{DEFAULT} la configuración {LIGHTRED}{1}{DEFAULT}.", - "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} ha {LIGHTRED}deshabilitado{DEFAULT} la configuración {LIGHTRED}{1}{DEFAULT}.", - "setting.hud.menu-title": "Lista de ajustes", - "mode.hud.menu-title": "Lista de modos de juego", - "maps.hud.menu-title": "Lista de mapas", - "settings.enable.hud.menu-title": "Habilitar ajustes", - "settings.disable.hud.menu-title": "Deshabilitar ajustes" -} \ No newline at end of file + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} ha {LIGHTRED}Habilitado{DEFAULT} el ajuste {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} ha {LIGHTRED}Deshabilitado{DEFAULT} el ajuste {LIGHTRED}{1}{DEFAULT}.", + "menu.yes": "Sí", + "menu.no": "No", + "menu.enable": "Habilitar", + "menu.disable": "Deshabilitar", + "mode.show.menu-response": "Di {GREEN}!{0}{DEFAULT} para crear una votación.", + "mode.vote.menu-title": "¿Cambiar el modo de juego a {GOLD}{0}{DEFAULT}?", + "modes.menu-title": "Lista de modos de juego", + "modes.vote.menu-title": "¿Cambiar modo de juego?", + "map.vote.menu-title": "¿Cambiar mapa a {0}?", + "maps.menu-title": "Lista de mapas", + "maps.show.menu-response": "Di {GREEN}!{0}{DEFAULT} para crear una votación.", + "setting.vote.menu-title": "¿Cambiar ajuste {GOLD}{0}{DEFAULT}?", + "setting.show.menu-response": "Di {GREEN}!{0}{DEFAULT} para crear una votación.", + "settings.menu-actions": "Acciones de ajustes", + "settings.menu-title": "Lista de ajustes" + } \ No newline at end of file diff --git a/lang/fr.json b/lang/fr.json index 92c429c..d8fe083 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -1,12 +1,22 @@ { "plugin.prefix": "[{GREEN}Serveur{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} a changé la carte en {LIGHTRED}{1}{DEFAULT}.", + "changemap.message": "{LIGHTRED}{0}{DEFAULT} a changé la carte en {LIGHTRED}{1}{DEFAULT}.", "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} a changé le mode de jeu en {LIGHTRED}{1}{DEFAULT}.", - "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} a {LIGHTRED}activé{DEFAULT} le paramètre {LIGHTRED}{1}{DEFAULT}.", - "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} a {LIGHTRED}désactivé{DEFAULT} le paramètre {LIGHTRED}{1}{DEFAULT}.", - "setting.hud.menu-title": "Liste des paramètres", - "mode.hud.menu-title": "Liste des modes de jeu", - "maps.hud.menu-title": "Liste des cartes", - "settings.enable.hud.menu-title": "Activer les paramètres", - "settings.disable.hud.menu-title": "Désactiver les paramètres" -} \ No newline at end of file + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} a {LIGHTRED}Activé{DEFAULT} le paramètre {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} a {LIGHTRED}Désactivé{DEFAULT} le paramètre {LIGHTRED}{1}{DEFAULT}.", + "menu.yes": "Oui", + "menu.no": "Non", + "menu.enable": "Activer", + "menu.disable": "Désactiver", + "mode.show.menu-response": "Dites {GREEN}!{0}{DEFAULT} pour créer un vote.", + "mode.vote.menu-title": "Changer le mode de jeu en {GOLD}{0}{DEFAULT} ?", + "modes.menu-title": "Liste des modes de jeu", + "modes.vote.menu-title": "Changer de mode de jeu ?", + "map.vote.menu-title": "Changer la carte en {0} ?", + "maps.menu-title": "Liste des cartes", + "maps.show.menu-response": "Dites {GREEN}!{0}{DEFAULT} pour créer un vote.", + "setting.vote.menu-title": "Changer le paramètre {GOLD}{0}{DEFAULT} ?", + "setting.show.menu-response": "Dites {GREEN}!{0}{DEFAULT} pour créer un vote.", + "settings.menu-actions": "Actions des paramètres", + "settings.menu-title": "Liste des paramètres" + } \ No newline at end of file diff --git a/lang/hu.json b/lang/hu.json index 6d14808..7a1d45a 100644 --- a/lang/hu.json +++ b/lang/hu.json @@ -1,12 +1,22 @@ { "plugin.prefix": "[{GREEN}Szerver{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} megváltoztatta a pályát {LIGHTRED}{1}{DEFAULT}-re.", + "changemap.message": "{LIGHTRED}{0}{DEFAULT} megváltoztatta a pályát {LIGHTRED}{1}{DEFAULT}-re.", "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} megváltoztatta a játékmódot {LIGHTRED}{1}{DEFAULT}-re.", - "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}bekapcsolta{DEFAULT} a(z) {LIGHTRED}{1}{DEFAULT} beállítást.", - "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}kikapcsolta{DEFAULT} a(z) {LIGHTRED}{1}{DEFAULT} beállítást.", - "setting.hud.menu-title": "Beállítások listája", - "mode.hud.menu-title": "Játékmód lista", - "maps.hud.menu-title": "Pálya lista", - "settings.enable.hud.menu-title": "Beállítások engedélyezése", - "settings.disable.hud.menu-title": "Beállítások letiltása" -} \ No newline at end of file + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Engedélyezte{DEFAULT} a {LIGHTRED}{1}{DEFAULT} beállítást.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Letiltotta{DEFAULT} a {LIGHTRED}{1}{DEFAULT} beállítást.", + "menu.yes": "Igen", + "menu.no": "Nem", + "menu.enable": "Engedélyezés", + "menu.disable": "Letiltás", + "mode.show.menu-response": "Írj {GREEN}!{0}{DEFAULT} a szavazás létrehozásához.", + "mode.vote.menu-title": "Játékmód váltása {GOLD}{0}{DEFAULT}-re?", + "modes.menu-title": "Játékmód lista", + "modes.vote.menu-title": "Játékmód váltása?", + "map.vote.menu-title": "Pálya váltása {0}-ra?", + "maps.menu-title": "Pálya lista", + "maps.show.menu-response": "Írj {GREEN}!{0}{DEFAULT} a szavazás létrehozásához.", + "setting.vote.menu-title": "{GOLD}{0}{DEFAULT} beállítás módosítása?", + "setting.show.menu-response": "Írj {GREEN}!{0}{DEFAULT} a szavazás létrehozásához.", + "settings.menu-actions": "Beállítások műveletei", + "settings.menu-title": "Beállítások listája" + } \ No newline at end of file diff --git a/lang/lv.json b/lang/lv.json index 369f357..8ff7079 100644 --- a/lang/lv.json +++ b/lang/lv.json @@ -1,12 +1,22 @@ { "plugin.prefix": "[{GREEN}Serveris{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} ir mainījis karti uz {LIGHTRED}{1}{DEFAULT}.", - "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} ir mainījis spēles režīmu uz {LIGHTRED}{1}{DEFAULT}.", - "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} ir {LIGHTRED}ieslēdzis{DEFAULT} iestatījumu {LIGHTRED}{1}{DEFAULT}.", - "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} ir {LIGHTRED}atslēdzis{DEFAULT} iestatījumu {LIGHTRED}{1}{DEFAULT}.", - "setting.hud.menu-title": "Iestatījumu saraksts", - "mode.hud.menu-title": "Spēles režīmu saraksts", - "maps.hud.menu-title": "Karšu saraksts", - "settings.enable.hud.menu-title": "Iespējot iestatījumus", - "settings.disable.hud.menu-title": "Atspējot iestatījumus" -} \ No newline at end of file + "changemap.message": "{LIGHTRED}{0}{DEFAULT} ir mainījis karti uz {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Administrators {LIGHTRED}{0}{DEFAULT} ir mainījis spēles režīmu uz {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Administrators {LIGHTRED}{0}{DEFAULT} ir {LIGHTRED}iespējojis{DEFAULT} iestatījumu {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Administrators {LIGHTRED}{0}{DEFAULT} ir {LIGHTRED}atspējojis{DEFAULT} iestatījumu {LIGHTRED}{1}{DEFAULT}.", + "menu.yes": "Jā", + "menu.no": "Nē", + "menu.enable": "Iespējot", + "menu.disable": "Atspējot", + "mode.show.menu-response": "Saki {GREEN}!{0}{DEFAULT}, lai izveidotu balsojumu.", + "mode.vote.menu-title": "Mainīt spēles režīmu uz {GOLD}{0}{DEFAULT}?", + "modes.menu-title": "Spēles režīmu saraksts", + "modes.vote.menu-title": "Mainīt spēles režīmu?", + "map.vote.menu-title": "Mainīt karti uz {0}?", + "maps.menu-title": "Karšu saraksts", + "maps.show.menu-response": "Saki {GREEN}!{0}{DEFAULT}, lai izveidotu balsojumu.", + "setting.vote.menu-title": "Mainīt iestatījumu {GOLD}{0}{DEFAULT}?", + "setting.show.menu-response": "Saki {GREEN}!{0}{DEFAULT}, lai izveidotu balsojumu.", + "settings.menu-actions": "Iestatījumu darbības", + "settings.menu-title": "Iestatījumu saraksts" + } \ No newline at end of file diff --git a/lang/nl.json b/lang/nl.json index 1493f65..4154cd1 100644 --- a/lang/nl.json +++ b/lang/nl.json @@ -1,12 +1,22 @@ { "plugin.prefix": "[{GREEN}Server{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de map veranderd naar {LIGHTRED}{1}{DEFAULT}.", - "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de spelmodus veranderd naar {LIGHTRED}{1}{DEFAULT}.", - "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de instelling {LIGHTRED}{1}{DEFAULT} {LIGHTRED}ingeschakeld{DEFAULT}.", - "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de instelling {LIGHTRED}{1}{DEFAULT} {LIGHTRED}uitgeschakeld{DEFAULT}.", - "setting.hud.menu-title": "Instellingenlijst", - "mode.hud.menu-title": "Spelmoduslijst", - "maps.hud.menu-title": "Kaartenlijst", - "settings.enable.hud.menu-title": "Instellingen inschakelen", - "settings.disable.hud.menu-title": "Instellingen uitschakelen" -} \ No newline at end of file + "changemap.message": "{LIGHTRED}{0}{DEFAULT} heeft de kaart gewijzigd naar {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de spelmodus gewijzigd naar {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de instelling {LIGHTRED}{1}{DEFAULT} {LIGHTRED}Ingeschakeld{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} heeft de instelling {LIGHTRED}{1}{DEFAULT} {LIGHTRED}Uitgeschakeld{DEFAULT}.", + "menu.yes": "Ja", + "menu.no": "Nee", + "menu.enable": "Inschakelen", + "menu.disable": "Uitschakelen", + "mode.show.menu-response": "Zeg {GREEN}!{0}{DEFAULT} om een stemming te creëren.", + "mode.vote.menu-title": "Spelmodus wijzigen naar {GOLD}{0}{DEFAULT}?", + "modes.menu-title": "Lijst met spelmodi", + "modes.vote.menu-title": "Spelmodus wijzigen?", + "map.vote.menu-title": "Kaart wijzigen naar {0}?", + "maps.menu-title": "Lijst met kaarten", + "maps.show.menu-response": "Zeg {GREEN}!{0}{DEFAULT} om een stemming te creëren.", + "setting.vote.menu-title": "Instelling {GOLD}{0}{DEFAULT} wijzigen?", + "setting.show.menu-response": "Zeg {GREEN}!{0}{DEFAULT} om een stemming te creëren.", + "settings.menu-actions": "Instellingsacties", + "settings.menu-title": "Lijst met instellingen" + } \ No newline at end of file diff --git a/lang/pl.json b/lang/pl.json index 52fc665..f83003a 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -1,12 +1,22 @@ { "plugin.prefix": "[{GREEN}Serwer{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} zmienił mapę na {LIGHTRED}{1}{DEFAULT}.", - "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} zmienił tryb gry na {LIGHTRED}{1}{DEFAULT}.", - "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}włączył{DEFAULT} ustawienie {LIGHTRED}{1}{DEFAULT}.", - "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}wyłączył{DEFAULT} ustawienie {LIGHTRED}{1}{DEFAULT}.", - "setting.hud.menu-title": "Lista ustawień", - "mode.hud.menu-title": "Lista trybów gry", - "maps.hud.menu-title": "Lista map", - "settings.enable.hud.menu-title": "Włącz ustawienia", - "settings.disable.hud.menu-title": "Wyłącz ustawienia" -} \ No newline at end of file + "changemap.message": "{LIGHTRED}{0}{DEFAULT} zmienił mapę na {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Administrator {LIGHTRED}{0}{DEFAULT} zmienił tryb gry na {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Administrator {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Włączył{DEFAULT} ustawienie {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Administrator {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Wyłączył{DEFAULT} ustawienie {LIGHTRED}{1}{DEFAULT}.", + "menu.yes": "Tak", + "menu.no": "Nie", + "menu.enable": "Włącz", + "menu.disable": "Wyłącz", + "mode.show.menu-response": "Powiedz {GREEN}!{0}{DEFAULT}, aby utworzyć głosowanie.", + "mode.vote.menu-title": "Zmienić tryb gry na {GOLD}{0}{DEFAULT}?", + "modes.menu-title": "Lista trybów gry", + "modes.vote.menu-title": "Zmienić tryb gry?", + "map.vote.menu-title": "Zmienić mapę na {0}?", + "maps.menu-title": "Lista map", + "maps.show.menu-response": "Powiedz {GREEN}!{0}{DEFAULT}, aby utworzyć głosowanie.", + "setting.vote.menu-title": "Zmienić ustawienie {GOLD}{0}{DEFAULT}?", + "setting.show.menu-response": "Powiedz {GREEN}!{0}{DEFAULT}, aby utworzyć głosowanie.", + "settings.menu-actions": "Akcje ustawień", + "settings.menu-title": "Lista ustawień" + } \ No newline at end of file diff --git a/lang/pt-BR.json b/lang/pt-BR.json index 18a9286..cb90a20 100644 --- a/lang/pt-BR.json +++ b/lang/pt-BR.json @@ -1,12 +1,22 @@ { "plugin.prefix": "[{GREEN}Servidor{DEFAULT}]", - "changemap.message": "Admin {LIGHTRED}{0}{DEFAULT} mudou o mapa para {LIGHTRED}{1}{DEFAULT}.", + "changemap.message": "{LIGHTRED}{0}{DEFAULT} mudou o mapa para {LIGHTRED}{1}{DEFAULT}.", "changemode.message": "Admin {LIGHTRED}{0}{DEFAULT} mudou o modo de jogo para {LIGHTRED}{1}{DEFAULT}.", - "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}ativou{DEFAULT} a configuração {LIGHTRED}{1}{DEFAULT}.", - "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}desativou{DEFAULT} a configuração {LIGHTRED}{1}{DEFAULT}.", - "setting.hud.menu-title": "Lista de Configurações", - "mode.hud.menu-title": "Lista de Modos de Jogo", - "maps.hud.menu-title": "Lista de Mapas", - "settings.enable.hud.menu-title": "Ativar Configurações", - "settings.disable.hud.menu-title": "Desativar Configurações" -} \ No newline at end of file + "enable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Habilitou{DEFAULT} a configuração {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Admin {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Desabilitou{DEFAULT} a configuração {LIGHTRED}{1}{DEFAULT}.", + "menu.yes": "Sim", + "menu.no": "Não", + "menu.enable": "Habilitar", + "menu.disable": "Desabilitar", + "mode.show.menu-response": "Digite {GREEN}!{0}{DEFAULT} para criar uma votação.", + "mode.vote.menu-title": "Mudar o modo de jogo para {GOLD}{0}{DEFAULT}?", + "modes.menu-title": "Lista de modos de jogo", + "modes.vote.menu-title": "Mudar o modo de jogo?", + "map.vote.menu-title": "Mudar o mapa para {0}?", + "maps.menu-title": "Lista de mapas", + "maps.show.menu-response": "Digite {GREEN}!{0}{DEFAULT} para criar uma votação.", + "setting.vote.menu-title": "Mudar a configuração {GOLD}{0}{DEFAULT}?", + "setting.show.menu-response": "Digite {GREEN}!{0}{DEFAULT} para criar uma votação.", + "settings.menu-actions": "Ações das configurações", + "settings.menu-title": "Lista de configurações" + } \ No newline at end of file diff --git a/lang/ru.json b/lang/ru.json index 09e6349..a6b7f54 100644 --- a/lang/ru.json +++ b/lang/ru.json @@ -1,12 +1,22 @@ { - "plugin.prefix": "[{GREEN}Сервер{DEFAULT}]", - "changemap.message": "Администратор {LIGHTRED}{0}{DEFAULT} сменил карту на {LIGHTRED}{1}{DEFAULT}.", - "changemode.message": "Администратор {LIGHTRED}{0}{DEFAULT} изменил режим игры на {LIGHTRED}{1}{DEFAULT}.", - "enable.changesetting.message": "Администратор {LIGHTRED}{0}{DEFAULT} {LIGHTRED}включил{DEFAULT} настройку {LIGHTRED}{1}{DEFAULT}.", - "disable.changesetting.message": "Администратор {LIGHTRED}{0}{DEFAULT} {LIGHTRED}выключил{DEFAULT} настройку {LIGHTRED}{1}{DEFAULT}.", - "setting.hud.menu-title": "Список настроек", - "mode.hud.menu-title": "Список игровых режимов", - "maps.hud.menu-title": "Список карт", - "settings.enable.hud.menu-title": "Включить настройки", - "settings.disable.hud.menu-title": "Отключить настройки" -} \ No newline at end of file + "plugin.prefix": "[{GREEN}Сервер{DEFAULT}]", + "changemap.message": "{LIGHTRED}{0}{DEFAULT} сменил карту на {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Админ {LIGHTRED}{0}{DEFAULT} сменил режим игры на {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Админ {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Включил{DEFAULT} настройку {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Админ {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Выключил{DEFAULT} настройку {LIGHTRED}{1}{DEFAULT}.", + "menu.yes": "Да", + "menu.no": "Нет", + "menu.enable": "Включить", + "menu.disable": "Выключить", + "mode.show.menu-response": "Скажите {GREEN}!{0}{DEFAULT}, чтобы создать голосование.", + "mode.vote.menu-title": "Сменить режим игры на {GOLD}{0}{DEFAULT}?", + "modes.menu-title": "Список режимов игры", + "modes.vote.menu-title": "Сменить режим игры?", + "map.vote.menu-title": "Сменить карту на {0}?", + "maps.menu-title": "Список карт", + "maps.show.menu-response": "Скажите {GREEN}!{0}{DEFAULT}, чтобы создать голосование.", + "setting.vote.menu-title": "Сменить настройку {GOLD}{0}{DEFAULT}?", + "setting.show.menu-response": "Скажите {GREEN}!{0}{DEFAULT}, чтобы создать голосование.", + "settings.menu-actions": "Действия настроек", + "settings.menu-title": "Список настроек" + } \ No newline at end of file diff --git a/lang/tr.json b/lang/tr.json index cce32db..da87895 100644 --- a/lang/tr.json +++ b/lang/tr.json @@ -1,12 +1,22 @@ { "plugin.prefix": "[{GREEN}Sunucu{DEFAULT}]", - "changemap.message": "Yönetici {LIGHTRED}{0}{DEFAULT}, haritayı {LIGHTRED}{1}{DEFAULT} olarak değiştirdi.", - "changemode.message": "Yönetici {LIGHTRED}{0}{DEFAULT}, oyun modunu {LIGHTRED}{1}{DEFAULT} olarak değiştirdi.", - "enable.changesetting.message": "Yönetici {LIGHTRED}{0}{DEFAULT}, {LIGHTRED}etkinleştirdi{DEFAULT} ayarı {LIGHTRED}{1}{DEFAULT}.", - "disable.changesetting.message": "Yönetici {LIGHTRED}{0}{DEFAULT}, {LIGHTRED}devre dışı bıraktı{DEFAULT} ayarı {LIGHTRED}{1}{DEFAULT}.", - "setting.hud.menu-title": "Ayar Listesi", - "mode.hud.menu-title": "Oyun Modu Listesi", - "maps.hud.menu-title": "Harita Listesi", - "settings.enable.hud.menu-title": "Ayarları Etkinleştir", - "settings.disable.hud.menu-title": "Ayarları Devre Dışı Bırak" -} \ No newline at end of file + "changemap.message": "{LIGHTRED}{0}{DEFAULT} haritayı {LIGHTRED}{1}{DEFAULT} olarak değiştirdi.", + "changemode.message": "Yönetici {LIGHTRED}{0}{DEFAULT} oyun modunu {LIGHTRED}{1}{DEFAULT} olarak değiştirdi.", + "enable.changesetting.message": "Yönetici {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Etkinleştirdi{DEFAULT} {LIGHTRED}{1}{DEFAULT} ayarını.", + "disable.changesetting.message": "Yönetici {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Devre Dışı Bıraktı{DEFAULT} {LIGHTRED}{1}{DEFAULT} ayarını.", + "menu.yes": "Evet", + "menu.no": "Hayır", + "menu.enable": "Etkinleştir", + "menu.disable": "Devre Dışı Bırak", + "mode.show.menu-response": "Oylama oluşturmak için {GREEN}!{0}{DEFAULT} yazın.", + "mode.vote.menu-title": "Oyun modu {GOLD}{0}{DEFAULT} olarak değiştirilsin mi?", + "modes.menu-title": "Oyun Modları Listesi", + "modes.vote.menu-title": "Oyun modu değiştirilsin mi?", + "map.vote.menu-title": "Harita {0} olarak değiştirilsin mi?", + "maps.menu-title": "Haritalar Listesi", + "maps.show.menu-response": "Oylama oluşturmak için {GREEN}!{0}{DEFAULT} yazın.", + "setting.vote.menu-title": "{GOLD}{0}{DEFAULT} ayarı değiştirilsin mi?", + "setting.show.menu-response": "Oylama oluşturmak için {GREEN}!{0}{DEFAULT} yazın.", + "settings.menu-actions": "Ayar İşlemleri", + "settings.menu-title": "Ayarlar Listesi" + } \ No newline at end of file diff --git a/lang/ua.json b/lang/ua.json index 7a24eeb..d592249 100644 --- a/lang/ua.json +++ b/lang/ua.json @@ -1,12 +1,22 @@ { - "plugin.prefix": "[{GREEN}Сервер{DEFAULT}]", - "changemap.message": "Адміністратор {LIGHTRED}{0}{DEFAULT} змінив карту на {LIGHTRED}{1}{DEFAULT}.", - "changemode.message": "Адміністратор {LIGHTRED}{0}{DEFAULT} змінив режим гри на {LIGHTRED}{1}{DEFAULT}.", - "enable.changesetting.message": "Адміністратор {LIGHTRED}{0}{DEFAULT} {LIGHTRED}увімкнув{DEFAULT} налаштування {LIGHTRED}{1}{DEFAULT}.", - "disable.changesetting.message": "Адміністратор {LIGHTRED}{0}{DEFAULT} {LIGHTRED}вимкнув{DEFAULT} налаштування {LIGHTRED}{1}{DEFAULT}.", - "setting.hud.menu-title": "Список налаштувань", - "mode.hud.menu-title": "Список ігрових режимів", - "maps.hud.menu-title": "Список карт", - "settings.enable.hud.menu-title": "Увімкнути налаштування", - "settings.disable.hud.menu-title": "Вимкнути налаштування" -} \ No newline at end of file + "plugin.prefix": "[{GREEN}Сервер{DEFAULT}]", + "changemap.message": "{LIGHTRED}{0}{DEFAULT} змінив карту на {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "Адміністратор {LIGHTRED}{0}{DEFAULT} змінив режим гри на {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "Адміністратор {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Увімкнув{DEFAULT} налаштування {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "Адміністратор {LIGHTRED}{0}{DEFAULT} {LIGHTRED}Вимкнув{DEFAULT} налаштування {LIGHTRED}{1}{DEFAULT}.", + "menu.yes": "Так", + "menu.no": "Ні", + "menu.enable": "Увімкнути", + "menu.disable": "Вимкнути", + "mode.show.menu-response": "Скажіть {GREEN}!{0}{DEFAULT}, щоб створити голосування.", + "mode.vote.menu-title": "Змінити режим гри на {GOLD}{0}{DEFAULT}?", + "modes.menu-title": "Список режимів гри", + "modes.vote.menu-title": "Змінити режим гри?", + "map.vote.menu-title": "Змінити карту на {0}?", + "maps.menu-title": "Список карт", + "maps.show.menu-response": "Скажіть {GREEN}!{0}{DEFAULT}, щоб створити голосування.", + "setting.vote.menu-title": "Змінити налаштування {GOLD}{0}{DEFAULT}?", + "setting.show.menu-response": "Скажіть {GREEN}!{0}{DEFAULT}, щоб створити голосування.", + "settings.menu-actions": "Дії налаштувань", + "settings.menu-title": "Список налаштувань" + } \ No newline at end of file diff --git a/lang/zh-Hans.json b/lang/zh-Hans.json index 200cdd5..b474d9a 100644 --- a/lang/zh-Hans.json +++ b/lang/zh-Hans.json @@ -1,7 +1,22 @@ { - "plugin.prefix": "[{GREEN}服务器{DEFAULT}]", // Server = 服务器 - "changemap.message": "管理员 {LIGHTRED}{0}{DEFAULT} 将地图更改为 {LIGHTRED}{1}{DEFAULT}.", // Admin changed map to... - "changemode.message": "管理员 {LIGHTRED}{0}{DEFAULT} 将游戏模式更改为 {LIGHTRED}{1}{DEFAULT}.", // Admin changed game mode to... - "mode.hud.menu-title": "游戏模式列表", // List of game modes - "maps.hud.menu-title": "地图列表" // List of maps + "plugin.prefix": "[{GREEN}服务器{DEFAULT}]", + "changemap.message": "{LIGHTRED}{0}{DEFAULT} 将地图更改为 {LIGHTRED}{1}{DEFAULT}.", + "changemode.message": "管理员 {LIGHTRED}{0}{DEFAULT} 将游戏模式更改为 {LIGHTRED}{1}{DEFAULT}.", + "enable.changesetting.message": "管理员 {LIGHTRED}{0}{DEFAULT} {LIGHTRED}启用{DEFAULT} 设置 {LIGHTRED}{1}{DEFAULT}.", + "disable.changesetting.message": "管理员 {LIGHTRED}{0}{DEFAULT} {LIGHTRED}禁用{DEFAULT} 设置 {LIGHTRED}{1}{DEFAULT}.", + "menu.yes": "是", + "menu.no": "否", + "menu.enable": "启用", + "menu.disable": "禁用", + "mode.show.menu-response": "说 {GREEN}!{0}{DEFAULT} 以创建投票.", + "mode.vote.menu-title": "将游戏模式更改为 {GOLD}{0}{DEFAULT} 吗?", + "modes.menu-title": "游戏模式列表", + "modes.vote.menu-title": "更改游戏模式吗?", + "map.vote.menu-title": "将地图更改为 {0} 吗?", + "maps.menu-title": "地图列表", + "maps.show.menu-response": "说 {GREEN}!{0}{DEFAULT} 以创建投票.", + "setting.vote.menu-title": "更改设置 {GOLD}{0}{DEFAULT} 吗?", + "setting.show.menu-response": "说 {GREEN}!{0}{DEFAULT} 以创建投票.", + "settings.menu-actions": "设置操作", + "settings.menu-title": "设置列表" } \ No newline at end of file From 1f953f86570f69698d809a08eeccab00cf20998a Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sat, 8 Jun 2024 22:26:06 -0400 Subject: [PATCH 62/86] Create GameModeManager.json Created config file for v1.0.4 --- .../GameModeManager/GameModeManager.json | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 lib/csgo/addons/counterstrikesharp/configs/plugins/GameModeManager/GameModeManager.json diff --git a/lib/csgo/addons/counterstrikesharp/configs/plugins/GameModeManager/GameModeManager.json b/lib/csgo/addons/counterstrikesharp/configs/plugins/GameModeManager/GameModeManager.json new file mode 100644 index 0000000..6460c16 --- /dev/null +++ b/lib/csgo/addons/counterstrikesharp/configs/plugins/GameModeManager/GameModeManager.json @@ -0,0 +1,51 @@ +// This configuration was automatically generated by CounterStrikeSharp for plugin 'GameModeManager', at 2024/06/08 09:52:11 +{ + "Version": 2, + "RTV": { + "Enabled": false, + "Plugin": "addons/counterstrikesharp/plugins/RockTheVote/RockTheVote.dll", + "MapListFile": "addons/counterstrikesharp/plugins/RockTheVote/maplist.txt", + "DefaultMapFormat": false + }, + "MapGroup": { + "Delay": 5, + "Default": "mg_active", + "File": "gamemodes_server.txt" + }, + "Settings": { + "Enabled": true, + "Folder": "settings", + "Style": "center" + }, + "GameMode": { + "Rotation": true, + "Interval": 4, + "Delay": 5, + "Style": "center", + "ListEnabled": true, + "List": { + "comp": "Competitive", + "1v1": "1 vs 1", + "aim": "Aim", + "awp": "AWP Only", + "scoutzknivez": "ScoutzKnives", + "wingman": "Wingman", + "gungame": "Gun Game", + "surf": "Surf", + "dm": "Deathmatch", + "dm-multicfg": "Deathmatch Multicfg", + "course": "Course", + "hns": "Hide N Seek", + "kz": "Kreedz", + "minigames": "Mini Games" + } + }, + "Votes": { + "Enabled": false, + "Map": false, + "GameMode": false, + "GameSetting": false, + "Style": "center" + }, + "ConfigVersion": 2 +} \ No newline at end of file From 9e375c728fac7361a2f5234a1df9f8934ad22129 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sat, 8 Jun 2024 22:27:37 -0400 Subject: [PATCH 63/86] UPDATE: Setting fixes Updated setting config files to fix issues with sv cheats requirement and/or per vote conflicts. --- ...{disable_bhop.cfg => disable_autobhop.cfg} | 8 +++++++- lib/csgo/cfg/settings/disable_course.cfg | 2 ++ lib/csgo/cfg/settings/disable_knifedrop.cfg | 4 +++- lib/csgo/cfg/settings/disable_map_voting.cfg | 6 ++++++ .../cfg/settings/disable_movement_unlock.cfg | 8 +++++++- lib/csgo/cfg/settings/disable_one_round.cfg | 2 +- lib/csgo/cfg/settings/disable_scoutz.cfg | 4 +++- lib/csgo/cfg/settings/enable_alltalk.cfg | 6 ++++++ .../{enable_bhop.cfg => enable_autobhop.cfg} | 6 ++++++ lib/csgo/cfg/settings/enable_bots.cfg | 19 ++++++++++++++----- lib/csgo/cfg/settings/enable_buying.cfg | 4 +++- lib/csgo/cfg/settings/enable_course.cfg | 6 ++++++ lib/csgo/cfg/settings/enable_knifedrop.cfg | 2 +- .../cfg/settings/enable_movement_unlock.cfg | 8 +++++++- lib/csgo/cfg/settings/enable_one_round.cfg | 2 +- lib/csgo/cfg/settings/enable_scoutz.cfg | 4 +++- 16 files changed, 76 insertions(+), 15 deletions(-) rename lib/csgo/cfg/settings/{disable_bhop.cfg => disable_autobhop.cfg} (65%) rename lib/csgo/cfg/settings/{enable_bhop.cfg => enable_autobhop.cfg} (78%) diff --git a/lib/csgo/cfg/settings/disable_bhop.cfg b/lib/csgo/cfg/settings/disable_autobhop.cfg similarity index 65% rename from lib/csgo/cfg/settings/disable_bhop.cfg rename to lib/csgo/cfg/settings/disable_autobhop.cfg index 596060c..d810797 100644 --- a/lib/csgo/cfg/settings/disable_bhop.cfg +++ b/lib/csgo/cfg/settings/disable_autobhop.cfg @@ -1,3 +1,6 @@ +// Enable SV Cheats +sv_cheats 1 + // Enable Movement Unlock exec settings/disable_dropknife.cfg exec settings/disable_movement_unlock.cfg @@ -9,4 +12,7 @@ sv_autobunnyhopping 0 r_drawviewmodel 1 sv_falldamage_scale 1 -echo "settings/enable_bhop.cfg executed" \ No newline at end of file +// Disable SV Cheats +sv_cheats 0 + +echo "settings/disable_bhop.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_course.cfg b/lib/csgo/cfg/settings/disable_course.cfg index 6d35f43..913fd9d 100644 --- a/lib/csgo/cfg/settings/disable_course.cfg +++ b/lib/csgo/cfg/settings/disable_course.cfg @@ -16,3 +16,5 @@ mp_maxrounds 15 // max number of rounds to play before server changes ma mp_playercashawards 1 // Players can earn money by performing in-game actions mp_teamcashawards 1 // Teams can earn money by performing in-game actions mp_round_restart_delay 7 // Number of seconds to delay before restarting a round after a win + +echo "settings/disable_course.cfg executed" diff --git a/lib/csgo/cfg/settings/disable_knifedrop.cfg b/lib/csgo/cfg/settings/disable_knifedrop.cfg index f01ad3e..6b232c7 100644 --- a/lib/csgo/cfg/settings/disable_knifedrop.cfg +++ b/lib/csgo/cfg/settings/disable_knifedrop.cfg @@ -1,2 +1,4 @@ // Disables Dropping Knife -mp_drop_knife_enable 0 \ No newline at end of file +mp_drop_knife_enable 0 + +echo "settings/disable_knifedrop.cfg executed" diff --git a/lib/csgo/cfg/settings/disable_map_voting.cfg b/lib/csgo/cfg/settings/disable_map_voting.cfg index 64c0572..b172590 100644 --- a/lib/csgo/cfg/settings/disable_map_voting.cfg +++ b/lib/csgo/cfg/settings/disable_map_voting.cfg @@ -1,3 +1,6 @@ +// Enable SV Cheats +sv_cheats 1 + // Disable map voting sv_allow_votes 0 mp_endmatch_votenextmap 0 @@ -6,4 +9,7 @@ mp_match_end_restart 0 mp_endmatch_votenextleveltime 0 mp_endmatch_votenextmap_keepcurrent 0 +// Disable SV Cheats +sv_cheats 0 + echo "settings/disable_map_voting.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_movement_unlock.cfg b/lib/csgo/cfg/settings/disable_movement_unlock.cfg index 84bc7b7..fe4eb9e 100644 --- a/lib/csgo/cfg/settings/disable_movement_unlock.cfg +++ b/lib/csgo/cfg/settings/disable_movement_unlock.cfg @@ -1,3 +1,6 @@ +// Enable SV Cheats +sv_cheats 1 + // https://github.com/KZGlobalTeam/gokz/blob/master/addons/sourcemod/scripting/gokz-mode-kztimer.sp#L37 sv_accelerate 5.5 sv_accelerate_use_weapon_speed true @@ -24,4 +27,7 @@ sv_weapon_encumbrance_per_item 0 sv_weapon_encumbrance_scale 0 sv_clamp_unsafe_velocities 0 -echo "settings/enable_movement_unlock.cfg executed" \ No newline at end of file +// Disable SV Cheats +sv_cheats 0 + +echo "settings/disable_movement_unlock.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_one_round.cfg b/lib/csgo/cfg/settings/disable_one_round.cfg index 128e8f4..e22adbc 100644 --- a/lib/csgo/cfg/settings/disable_one_round.cfg +++ b/lib/csgo/cfg/settings/disable_one_round.cfg @@ -26,4 +26,4 @@ mp_teamcashawards 1 // Allow time for vote map mp_round_restart_delay 7 -echo "settings/one_round.cfg executed" \ No newline at end of file +echo "settings/disable_one_round.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/disable_scoutz.cfg b/lib/csgo/cfg/settings/disable_scoutz.cfg index 14cdd8c..a40b241 100644 --- a/lib/csgo/cfg/settings/disable_scoutz.cfg +++ b/lib/csgo/cfg/settings/disable_scoutz.cfg @@ -8,4 +8,6 @@ mp_ct_default_melee "weapon_knife" mp_ct_default_secondary "weapon_usp_silencer" mp_t_default_secondary "weapon_glock" mp_t_default_primary "" -mp_ct_default_primary "" \ No newline at end of file +mp_ct_default_primary "" + +echo "settings/disable_scoutz.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_alltalk.cfg b/lib/csgo/cfg/settings/enable_alltalk.cfg index 979cc10..c681273 100644 --- a/lib/csgo/cfg/settings/enable_alltalk.cfg +++ b/lib/csgo/cfg/settings/enable_alltalk.cfg @@ -1,3 +1,6 @@ +// Enable SV Cheats +sv_cheats 1 + // Enable all talk sv_alltalk 1 sv_deadtalk 1 @@ -12,4 +15,7 @@ tv_relayvoice 1 // Enable after round start exec_after_round_start "exec settings/enable_alltalk.cfg" +// Disable SV Cheats +sv_cheats 0 + echo "settings/enable_alltalk.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_bhop.cfg b/lib/csgo/cfg/settings/enable_autobhop.cfg similarity index 78% rename from lib/csgo/cfg/settings/enable_bhop.cfg rename to lib/csgo/cfg/settings/enable_autobhop.cfg index 47facc7..54456ce 100644 --- a/lib/csgo/cfg/settings/enable_bhop.cfg +++ b/lib/csgo/cfg/settings/enable_autobhop.cfg @@ -1,3 +1,6 @@ +// Enable SV Cheats +sv_cheats 1 + // Enable Movement Unlock exec settings/enable_dropknife.cfg exec settings/enable_movement_unlock.cfg @@ -9,4 +12,7 @@ sv_autobunnyhopping 1 r_drawviewmodel 0 sv_falldamage_scale 0 +// Disable SV Cheats +sv_cheats 0 + echo "settings/enable_bhop.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_bots.cfg b/lib/csgo/cfg/settings/enable_bots.cfg index ee682eb..85e811d 100644 --- a/lib/csgo/cfg/settings/enable_bots.cfg +++ b/lib/csgo/cfg/settings/enable_bots.cfg @@ -1,6 +1,15 @@ // Enables Bots -bot_chatter "off" -bot_join_after_player 1 -bot_quota 2 -bot_quota_mode "fill" -bot_difficulty 3 \ No newline at end of file +bot_allow_grenades 1 +bot_allow_shotguns 1 +bot_allow_pistols 1 +bot_allow_rifles 1 +bot_allow_snipers 1 +bot_chatter "off" +bot_difficulty 5 +custom_bot_difficulty 5 +bot_join_after_player 1 +bot_join_team "any" +bot_quota_mode "fill" +bot_quota 10 + +echo "settings/enable_bots.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_buying.cfg b/lib/csgo/cfg/settings/enable_buying.cfg index 8bf116e..751d9c5 100644 --- a/lib/csgo/cfg/settings/enable_buying.cfg +++ b/lib/csgo/cfg/settings/enable_buying.cfg @@ -11,4 +11,6 @@ mp_buy_allow_grenades 1 mp_max_armor 1 mp_maxmoney 1 mp_startmoney 1 -mp_promoted_item_enabled 1 \ No newline at end of file +mp_promoted_item_enabled 1 + +echo "settings/enable_buying.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_course.cfg b/lib/csgo/cfg/settings/enable_course.cfg index 86c9fc8..6d84757 100644 --- a/lib/csgo/cfg/settings/enable_course.cfg +++ b/lib/csgo/cfg/settings/enable_course.cfg @@ -1,3 +1,6 @@ +// Enable SV Cheats +sv_cheats 1 + // Round convars mp_solid_teammates 0 mp_ct_default_secondary weapon_usp_silencer @@ -17,4 +20,7 @@ mp_free_armor 2 mp_buy_anywhere 0 mp_give_player_c4 0 +// Disable SV Cheats +sv_cheats 0 + echo "settings/enable_course.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_knifedrop.cfg b/lib/csgo/cfg/settings/enable_knifedrop.cfg index 5dc03c9..05a3163 100644 --- a/lib/csgo/cfg/settings/enable_knifedrop.cfg +++ b/lib/csgo/cfg/settings/enable_knifedrop.cfg @@ -5,4 +5,4 @@ mp_weapons_allow_map_placed 1 exec_after_round_start "exec settings/enable_knifedrop.cfg" -echo "settings/enable_knifedrop.cfg executed" \ No newline at end of file +echo "settings/enable_knifedrop.cfg executed" diff --git a/lib/csgo/cfg/settings/enable_movement_unlock.cfg b/lib/csgo/cfg/settings/enable_movement_unlock.cfg index ece0269..abef41c 100644 --- a/lib/csgo/cfg/settings/enable_movement_unlock.cfg +++ b/lib/csgo/cfg/settings/enable_movement_unlock.cfg @@ -1,3 +1,6 @@ +// Enable SV Cheats +sv_cheats 1 + // https://github.com/KZGlobalTeam/gokz/blob/master/addons/sourcemod/scripting/gokz-mode-kztimer.sp#L37 sv_accelerate 6.5 sv_accelerate_use_weapon_speed 0 @@ -25,4 +28,7 @@ sv_weapon_encumbrance_per_item 0 sv_weapon_encumbrance_scale 0 sv_clamp_unsafe_velocities 0 -echo "settings/movement_unlock.cfg executed" \ No newline at end of file +// Disable SV Cheats +sv_cheats 0 + +echo "settings/enable_movement_unlock.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_one_round.cfg b/lib/csgo/cfg/settings/enable_one_round.cfg index 048c25f..f371f63 100644 --- a/lib/csgo/cfg/settings/enable_one_round.cfg +++ b/lib/csgo/cfg/settings/enable_one_round.cfg @@ -26,4 +26,4 @@ mp_teamcashawards 0 // Allow time for vote map mp_round_restart_delay 10 -echo "settings/one_round.cfg executed" \ No newline at end of file +echo "settings/enable_one_round.cfg executed" \ No newline at end of file diff --git a/lib/csgo/cfg/settings/enable_scoutz.cfg b/lib/csgo/cfg/settings/enable_scoutz.cfg index ebcd4cb..01e1f68 100644 --- a/lib/csgo/cfg/settings/enable_scoutz.cfg +++ b/lib/csgo/cfg/settings/enable_scoutz.cfg @@ -8,4 +8,6 @@ mp_ct_default_secondary "" mp_t_default_melee "weapon_knife" mp_ct_default_melee "weapon_knife" mp_t_default_primary "weapon_ssg08" -mp_ct_default_primary "weapon_ssg08" \ No newline at end of file +mp_ct_default_primary "weapon_ssg08" + +echo "settings/enable_scoutz.cfg executed" \ No newline at end of file From 7ef277e3872a426664866d51babfe48a0ffdf3ec Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sat, 8 Jun 2024 22:28:06 -0400 Subject: [PATCH 64/86] UPDATE: Plugin.cs Updated module description. --- Plugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugin.cs b/Plugin.cs index 1ed9137..84de37d 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -15,7 +15,7 @@ public partial class Plugin : BasePlugin public override string ModuleName => "GameModeManager"; public override string ModuleVersion => "1.0.4"; public override string ModuleAuthor => "Striker-Nick"; - public override string ModuleDescription => "A simple plugin to manage custom game modes and map rotations."; + public override string ModuleDescription => "A simple plugin to help administrators manage custom game modes, settings, and map rotations."; // Define plugin private BasePlugin? _plugin; From 5638007aa3d1d2293cdd510522081d4f50c85900 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 8 Jun 2024 22:30:58 -0400 Subject: [PATCH 65/86] UPDATE: README.md Minor clarification for settings folder directory. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 55920fc..972fb09 100644 --- a/README.md +++ b/README.md @@ -163,8 +163,8 @@ GameModeManager offers the following configuration options within the `GameModeM | Setting | Description | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | Enabled | Enables game settings. Settings are parsed on plugin load. | -| Folder | Default settings folder in `csgo` directory. Add custom configuration files with `enable_` and `disable_` prefixes. | -| Style | Changes setting menu type (i.e. "chat" or "center"). | +| Folder | Default settings folder in `csgo/cfg` directory. Add custom configuration files with `enable_` and `disable_` prefixes. | +| Style | Changes setting menu type (i.e. "chat" or "center"). | ### Map Group Settings | Setting | Description | From 2a23dc17e37a677084a8db69e062d2ab3ece665b Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:01:09 -0400 Subject: [PATCH 66/86] UPDATE: README.md Minor change for clarity --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 972fb09..45bcf0f 100644 --- a/README.md +++ b/README.md @@ -306,6 +306,6 @@ This plugin will display all in-game menus and messaging based on the player's p | -------------------------------------------------------------------| ------------------------------------------------------------------------------------------------------------------------ | | `Cannot Find` | Unable to locate the file specified from `GameModeManager.json` config. | | `Incomplete VDF data` | Your `gamemodes_server.txt` file is not formatted properly in [VDF Format](https://developer.valvesoftware.com/wiki/VDF).| -| `Your config file is too old` | Please delete it from `addons/counterstrikesharp/configs/plugins/GameModeManager` and let the plugin recreate it on load.| +| `Your config file is too old` | Please backup and remove it from `addons/counterstrikesharp/configs/plugins/GameModeManager` to recreate it. | | `The mapgroup property doesn't exist` | The "mapgroup" property cannot be found in your `gamemodes_server.txt` file. | | `Mapgroup found, but the 'maps' property is missing or incomplete` | The "maps" property cannot be found in your `gamemodes_server.txt` file for one of your map groups. | From a560158e3bc9d3f52a914a9e800897c49acbec25 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:06:04 -0400 Subject: [PATCH 67/86] UPDATE: README.md Missing space. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45bcf0f..3b957d3 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ This plugin is compatible with any RTV plugin using a maplist.txt file. ## Installation 1. Install Metamod:Source and Counter Strike Sharp. 2. Copy DLLs to `csgo/addons/counterstrikesharp/plugins/GameModeManager`. -3. Make sure your `gamemodes_server.txt` or custom map group file is in[VDF Format](https://developer.valvesoftware.com/wiki/VDF) and contains a list of map groups. +3. Make sure your `gamemodes_server.txt` or custom map group file is in [VDF Format](https://developer.valvesoftware.com/wiki/VDF) and contains a list of map groups. 4. If you are not using the JSON configuration file for specifying game modes, include the "displayname" property within your `gamemodes_server.txt` or custom map group file for each map group. Example: From ed31adeb97b4112077a6c0acf7a2b29e2380e3f8 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:08:09 -0400 Subject: [PATCH 68/86] UPDATE: README.md Added correct install directory. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b957d3..5e1f057 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ This plugin is compatible with any RTV plugin using a maplist.txt file. ## Installation 1. Install Metamod:Source and Counter Strike Sharp. -2. Copy DLLs to `csgo/addons/counterstrikesharp/plugins/GameModeManager`. +2. Copy `addons` and `cfg` folders to `/csgo/`. 3. Make sure your `gamemodes_server.txt` or custom map group file is in [VDF Format](https://developer.valvesoftware.com/wiki/VDF) and contains a list of map groups. 4. If you are not using the JSON configuration file for specifying game modes, include the "displayname" property within your `gamemodes_server.txt` or custom map group file for each map group. From 8a3fa005d8bce52162361042c7fa5e521ad48f8d Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:12:39 -0400 Subject: [PATCH 69/86] UPDATE: README.md Spelling mistake --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5e1f057..b993ecc 100644 --- a/README.md +++ b/README.md @@ -187,8 +187,8 @@ GameModeManager offers the following configuration options within the `GameModeM | Setting | Description | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | Enabled | Enables voting. Votes are registered when all plugins have been loaded. | -| Map | Enabled map vote. | -| GameMode | Enabled game mode votes (all modes and per mode votes) | +| Map | Enables map vote. | +| GameMode | Enables game mode votes (all modes and per mode votes) | | GameSetting | Enables game setting votes (per mode votes only) | | Style | Changes vote menu type (i.e. "chat" or "center"). | From 1303d3b8731786f328881b6bcd18934cc6d65fe5 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:21:30 -0400 Subject: [PATCH 70/86] UPDATE: README.md Additional clarifications. --- README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b993ecc..8229f0f 100644 --- a/README.md +++ b/README.md @@ -96,10 +96,6 @@ The below commands require the ***@css/cvar*** role. ![Screenshot 2024-06-08 213358](https://github.com/nickj609/GameModeManager/assets/32173425/0e188f9d-3c50-47bf-9f48-57ff0cb286e0) ## RTV Plugin Compatibility - -> [!IMPORTANT] -> After the first load, enable RTV Plugin Compatibility within the configuration file. - This plugin is compatible with any RTV plugin using a maplist.txt file. ![Screenshot 2024-03-21 161846](https://github.com/nickj609/GameModeManager/assets/32173425/1e291efb-fe7f-4f0d-bb2c-e21d042bd153) @@ -149,9 +145,9 @@ This plugin is compatible with any RTV plugin using a maplist.txt file. > [!IMPORTANT] > On the first load, a configuration file will be created in `csgo/addons/counterstrikesharp/configs/plugins/GameModeManager/GameModeManager.json`. -GameModeManager offers the following configuration options within the `GameModeManager.json` file: - ### RTV Settings +> After the first load, enable RTV Plugin Compatibility within the configuration file. It is disabled by default. + | Setting | Description | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | Enabled | Enables RTV Compatibility. The RTV plugin specified will be reloaded after updating the maplist.txt file. | @@ -184,6 +180,8 @@ GameModeManager offers the following configuration options within the `GameModeM | List | A customizable list of game modes for your server with friendly names. | ### Vote Settings +> After the first load, enable voting within the configuration file. It is disabled by default. + | Setting | Description | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | Enabled | Enables voting. Votes are registered when all plugins have been loaded. | @@ -193,9 +191,9 @@ GameModeManager offers the following configuration options within the `GameModeM | Style | Changes vote menu type (i.e. "chat" or "center"). | > [!NOTE] -> - All game mode configuration files must be in the `csgo/cfg` directory and include `css_mapgroup` to specify the current map group. -> - All game setting configuration files must be in the `csgo/` directory and include `css_mapgroup` to specify the current map group. -> - If `ListEnabled` is set to `false`, the game mode list will be created based on the discovered map groups. For example, `mg_surf` would display as `Surf` and the `surf.cfg` would be executed. +> - All game mode configuration files must be in the `/csgo/cfg` directory and include `css_mapgroup` to specify the current map group. +> - All game setting configuration files must be in the `/csgo/cfg/` directory. You can specify a custom settings folder within that directory. +> - If `ListEnabled` is set to `false`, the game mode list will be created based on the discovered map groups. For example, `mg_surf` would display as `surf` and the `surf.cfg` would be executed. You can also use 'friendly' names by adding a "displayname" property to each map group in your map group file. ### Default Values ``` From 438095a001a81de23e1ace5d57e7593c1ae3d3dd Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sat, 8 Jun 2024 23:49:15 -0400 Subject: [PATCH 71/86] UPDATE: Config.cs Added backup recommendation before recreating new config file. --- Config.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Config.cs b/Config.cs index c25cf76..d215f99 100644 --- a/Config.cs +++ b/Config.cs @@ -148,8 +148,8 @@ public void OnConfigParsed(Config _config) // Config version check if (_config.Version < 2) { - Logger.LogError("Your config file is too old, please delete it from addons/counterstrikesharp/configs/plugins/GameModeManager and let the plugin recreate it on load."); - throw new Exception("Your config file is too old, please delete it from addons/counterstrikesharp/configs/plugins/GameModeManager and let the plugin recreate it on load."); + Logger.LogError("Your config file is too old, please backup and remove it from addons/counterstrikesharp/configs/plugins/GameModeManager to recreate it."); + throw new Exception("Your config file is too old, please backup and remove it from addons/counterstrikesharp/configs/plugins/GameModeManager to recreate it"); } // Set config @@ -171,7 +171,7 @@ public class GameSettings { public bool Enabled { get; set; } = true; // Enable game settings - public string Folder { get; set; } = "settings"; // Default settings folder path + public string Folder { get; set; } = "settings"; // Default settings folder public string Style { get; set; } = "center"; // Changes admin menu type (i.e. "chat" or "center") } public class MapGroupSettings From 1697a560f7aa5887be80296416b3bd613214d56b Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 9 Jun 2024 11:12:20 -0400 Subject: [PATCH 72/86] ADDED: Full path to RTV exception Updated the RTV exception to included the full path of the file that it is attempting to locate. Thanks @mavproductions! --- Config.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config.cs b/Config.cs index d215f99..e3a1fda 100644 --- a/Config.cs +++ b/Config.cs @@ -33,8 +33,8 @@ public void OnConfigParsed(Config _config) } else { - Logger.LogError($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); - throw new Exception($"Cannot find RTV 'Plugin': {_config.RTV.Plugin}"); + Logger.LogError($"Cannot find RTV 'Plugin': {Path.Join(GameDirectory, _config.RTV.Plugin)}"); + throw new Exception($"Cannot find RTV 'Plugin': {Path.Join(GameDirectory, _config.RTV.Plugin)}"); } if (File.Exists(Path.Join(GameDirectory, _config.RTV.MapListFile))) { From 0dd628eabc103d9ab1fe81659b6c9c78c8720f61 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 9 Jun 2024 11:14:55 -0400 Subject: [PATCH 73/86] UPDATE: Bugfix for map votes Fixed issue where map lists were not updating. This was because the map votes were being deregistered prior to the map list updates and throwing an exception. The exception was because deregistration was not scoped to the current map group, but instead all maps from every map group. Thanks @mavproductions! --- Core/CommandManager.cs | 11 +++++++---- Core/VoteManager.cs | 6 +++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Core/CommandManager.cs b/Core/CommandManager.cs index f214b9a..ee997f9 100644 --- a/Core/CommandManager.cs +++ b/Core/CommandManager.cs @@ -18,9 +18,6 @@ public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) { if (player == null) { - // Deregister map votes - DeregisterMapVotes(); - // Get map group MapGroup? _mapGroup = MapGroups.FirstOrDefault(g => g.Name == $"{command.ArgByIndex(1)}"); @@ -42,7 +39,13 @@ public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) Logger.LogError($"{ex.Message}"); } - // Register map votes + // Deregister map votes from old map group + DeregisterMapVotes(); + + // Set new map group + CurrentMapGroup = _mapGroup; + + // Register map votes for new map group RegisterMapVotes(); } } diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs index 9e7ee9c..be2e442 100644 --- a/Core/VoteManager.cs +++ b/Core/VoteManager.cs @@ -174,11 +174,15 @@ private void DeregisterMapVotes() { if (_mapVote == true) { + // Get maps from current map group + List _maps = CurrentMapGroup.Maps; + // Deregister per map vote - foreach (Map _map in Maps) + foreach (Map _map in _maps) { Plugin.CustomVotesApi.Get()?.RemoveCustomVote(_map.Name); } + // Set map vote flag _mapVote = false; } From ab3ab8f50ae70aa3ad7e1974acabeb04d7800438 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:14:22 -0400 Subject: [PATCH 74/86] ADDED: Issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 8be315c26769e18f4fa5e2ab3158bf905c70a905 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:24:30 -0400 Subject: [PATCH 75/86] ADDED: Request for logs --- .github/ISSUE_TEMPLATE/bug_report.md | 30 +++++++++++++--------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7..1b44bc4 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,10 +1,9 @@ --- name: Bug report -about: Create a report to help us improve +about: Create a report to help us improve. title: '' labels: '' assignees: '' - --- **Describe the bug** @@ -12,10 +11,8 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +1. Change map group +2. Initiate a vote **Expected behavior** A clear and concise description of what you expected to happen. @@ -23,16 +20,17 @@ A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] +**Logging** +Please provide a copy of the log from `/csgo/counterstrikesharp/logs/` + +Example +``` +2024-06-07 21:31:26.872 +00:00 [INFO] plugin:GameModeManager Loading map groups... +2024-06-07 21:31:26.888 +00:00 [INFO] plugin:GameModeManager Creating game modes... +2024-06-07 21:31:26.889 +00:00 [INFO] plugin:GameModeManager Loading settings... +2024-06-07 21:31:26.895 +00:00 [EROR] plugin:GameModeManager Object reference not set to an instance of an object. +2024-06-07 21:31:26.895 +00:00 [INFO] plugin:GameModeManager Enabling game mode and map rotations... +``` **Additional context** Add any other context about the problem here. From d8ac8f45cffdb5635716051a352cf7a693fc581e Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:27:50 -0400 Subject: [PATCH 76/86] UPDATE: Formatting changes --- .github/ISSUE_TEMPLATE/bug_report.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1b44bc4..bcf5f01 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -6,21 +6,23 @@ labels: '' assignees: '' --- -**Describe the bug** +### Describe the bug + A clear and concise description of what the bug is. -**To Reproduce** +### To Reproduce + Steps to reproduce the behavior: 1. Change map group 2. Initiate a vote -**Expected behavior** +### Expected behavior A clear and concise description of what you expected to happen. -**Screenshots** +### Screenshots If applicable, add screenshots to help explain your problem. -**Logging** +### Logging Please provide a copy of the log from `/csgo/counterstrikesharp/logs/` Example @@ -32,5 +34,5 @@ Example 2024-06-07 21:31:26.895 +00:00 [INFO] plugin:GameModeManager Enabling game mode and map rotations... ``` -**Additional context** +### Additional context Add any other context about the problem here. From db6735242e2343158eb1fc629b07cfa5584ec587 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:34:02 -0400 Subject: [PATCH 77/86] UPDATE: Formatting changes --- .github/ISSUE_TEMPLATE/feature_request.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7..83b68a7 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,14 +7,17 @@ assignees: '' --- -**Is your feature request related to a problem? Please describe.** +### Is your feature request related to a problem? A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -**Describe the solution you'd like** +### Describe the feature and/or solution A clear and concise description of what you want to happen. -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. +1. Open the game mode list +2. See 'friendly names' to choose from instead of file names (i.e. comp). -**Additional context** +### Describe alternatives you've considered +A clear and concise description of any alternative solutions or features you may have considered. If none, replace this line with **N/A**. + +### Additional context Add any other context or screenshots about the feature request here. From 41d6d295dc4320406268a5a73e8903902323f08e Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:35:58 -0400 Subject: [PATCH 78/86] UPDATE: README.md Removed unnecessary screenshots. --- README.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/README.md b/README.md index 8229f0f..949ef0e 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,6 @@ The below commands require the ***@css/changemap*** role. - `!maps (css_maps)` - Displays an admin menu for changing the map. It only shows maps for the current game mode/map group. - ![Screenshot 2024-06-08 212858](https://github.com/nickj609/GameModeManager/assets/32173425/e3f4dfa8-a151-48b3-8c70-c866274a11cd) - ### Game Modes - `!mode (css_mode)` - Changes the game mode to the mode specified. @@ -48,8 +46,6 @@ The below commands require the ***@css/changemap*** role. - `!modes (css_modes)` - Displays an admin menu for changing the game mode. - ![Screenshot 2024-06-08 211937](https://github.com/nickj609/GameModeManager/assets/32173425/7f9c46f1-4ed3-47a9-b135-3a0d1e5cabed) - ## Game Settings - `!setting (css_setting)` - Enables or disables a custom game setting. @@ -57,10 +53,6 @@ The below commands require the ***@css/changemap*** role. - `!settings (css_settings)` - Displays an admin menu for enabling or disabling custom game settings. - ![Screenshot 2024-06-08 212010](https://github.com/nickj609/GameModeManager/assets/32173425/75fb865f-63ec-498c-84f8-b451d1edea45) - - ![Screenshot 2024-06-08 212046](https://github.com/nickj609/GameModeManager/assets/32173425/34206829-f570-4b00-a025-795d8431057c) - ## Player Commands The below commands require the ***@css/cvar*** role. From f993932f9bed6dc4bbc199fd3e4dc735cbb72603 Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:54:59 -0400 Subject: [PATCH 79/86] UPDATE: README.md Added a better logging sample --- README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 949ef0e..6d5674e 100644 --- a/README.md +++ b/README.md @@ -42,14 +42,14 @@ The below commands require the ***@css/changemap*** role. ### Game Modes - `!mode (css_mode)` - Changes the game mode to the mode specified. - > Only the mode name is required. For example, for **mg_surf** you would do **!mode surf**. + > For example, for **mg_surf** you would do **!mode surf**. - `!modes (css_modes)` - Displays an admin menu for changing the game mode. ## Game Settings - `!setting (css_setting)` - Enables or disables a custom game setting. - > Only the setting name is required. For example, **enable_movement_unlock.cfg** would be **!setting movement_unlock**. + > For example, for **enable_movement_unlock.cfg** you would do **!setting movement_unlock**. - `!settings (css_settings)` - Displays an admin menu for enabling or disabling custom game settings. @@ -279,16 +279,17 @@ This plugin will display all in-game menus and messaging based on the player's p ### Example ``` -2024-06-08 02:01:09.232 +00:00 [INFO] plugin:GameModeManager Loading map groups... -2024-06-08 02:01:09.245 +00:00 [INFO] plugin:GameModeManager Creating game modes... -2024-06-08 02:01:09.246 +00:00 [INFO] plugin:GameModeManager Loading settings... -2024-06-08 02:01:09.247 +00:00 [WARN] plugin:GameModeManager Skipping allow_drop_knife.cfg because its missing the correct prefix. -2024-06-08 02:01:09.250 +00:00 [INFO] plugin:GameModeManager Creating settings menu... -2024-06-08 02:01:09.251 +00:00 [INFO] plugin:GameModeManager Enabling game mode and map rotations... -2024-06-08 02:01:09.252 +00:00 [INFO] plugin:GameModeManager Registering custom votes... -2024-04-01 03:27:20.767 +00:00 [INFO] plugin:GameModeManager Current map group is mg_active. -2024-04-01 03:27:20.768 +00:00 [INFO] plugin:GameModeManager New map group is mg_aim. -2024-06-08 02:04:44.973 +00:00 [INFO] plugin:GameModeManager Deregistering custom votes... +2024-06-08 22:59:32.805 +00:00 [INFO] plugin:GameModeManager Loading map groups... +2024-06-08 22:59:32.821 +00:00 [INFO] plugin:GameModeManager Creating game modes... +2024-06-08 22:59:32.823 +00:00 [INFO] plugin:GameModeManager Loading settings... +2024-06-08 22:59:32.827 +00:00 [WARN] plugin:GameModeManager Skipping random_setting.cfg because its missing the correct prefix. +2024-06-08 22:59:32.835 +00:00 [INFO] plugin:GameModeManager Enabling game mode and map rotations... +2024-06-08 22:59:34.096 +00:00 [INFO] plugin:GameModeManager Registering custom votes... +2024-04-28 23:01:12.832 +00:00 [WARN] plugin:GameModeManager New map group could not be found. Setting default map group. +2024-06-08 23:05:24.421 +00:00 [INFO] plugin:GameModeManager Current map group is mg_active. +2024-06-08 23:05:24.421 +00:00 [INFO] plugin:GameModeManager New map group is mg_active. +2024-06-08 24:15:47.044 +00:00 [INFO] plugin:GameModeManager Game has ended. Picking random map from current map group... +2024-06-08 24:17:76.044 +00:00 [INFO] plugin:GameModeManager Deregistering custom votes... ``` ### Common Error Messages From c7c1d5165bf02fe6bf86cbc61445ca0d777295cc Mon Sep 17 00:00:00 2001 From: Nick M <32173425+nickj609@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:56:27 -0400 Subject: [PATCH 80/86] UPDATE README.md Wrong date --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d5674e..9ea2720 100644 --- a/README.md +++ b/README.md @@ -285,7 +285,7 @@ This plugin will display all in-game menus and messaging based on the player's p 2024-06-08 22:59:32.827 +00:00 [WARN] plugin:GameModeManager Skipping random_setting.cfg because its missing the correct prefix. 2024-06-08 22:59:32.835 +00:00 [INFO] plugin:GameModeManager Enabling game mode and map rotations... 2024-06-08 22:59:34.096 +00:00 [INFO] plugin:GameModeManager Registering custom votes... -2024-04-28 23:01:12.832 +00:00 [WARN] plugin:GameModeManager New map group could not be found. Setting default map group. +2024-06-08 23:01:12.832 +00:00 [WARN] plugin:GameModeManager New map group could not be found. Setting default map group. 2024-06-08 23:05:24.421 +00:00 [INFO] plugin:GameModeManager Current map group is mg_active. 2024-06-08 23:05:24.421 +00:00 [INFO] plugin:GameModeManager New map group is mg_active. 2024-06-08 24:15:47.044 +00:00 [INFO] plugin:GameModeManager Game has ended. Picking random map from current map group... From d01c242500c8adf70204722a4be96d05d6bbcb34 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 9 Jun 2024 14:22:17 -0400 Subject: [PATCH 81/86] ADDED: Logging --- Core/CommandManager.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Core/CommandManager.cs b/Core/CommandManager.cs index ee997f9..bf23933 100644 --- a/Core/CommandManager.cs +++ b/Core/CommandManager.cs @@ -40,13 +40,27 @@ public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) } // Deregister map votes from old map group - DeregisterMapVotes(); + try + { + DeregisterCustomVotes(); + } + catch (Exception ex) + { + Logger.LogError($"{ex.Message}"); + } // Set new map group CurrentMapGroup = _mapGroup; // Register map votes for new map group - RegisterMapVotes(); + try + { + RegisterCustomVotes(); + } + catch (Exception ex) + { + Logger.LogError($"{ex.Message}"); + } } } From 79d95111f3478c6a7e198ae8e36a672e34281e52 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 9 Jun 2024 14:22:28 -0400 Subject: [PATCH 82/86] UPDATE: Refactoring --- Core/SettingsManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/SettingsManager.cs b/Core/SettingsManager.cs index 719970d..53e40d0 100644 --- a/Core/SettingsManager.cs +++ b/Core/SettingsManager.cs @@ -127,4 +127,4 @@ private void ParseSettings() } } } -} +} \ No newline at end of file From 7f98a88ae0295e1f50a8c5573dc7125962d08c34 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 9 Jun 2024 14:22:52 -0400 Subject: [PATCH 83/86] UPDATE: Fix menu title Fixes menu title for per mode votes so that it shows the game mode. --- Core/VoteManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/VoteManager.cs b/Core/VoteManager.cs index be2e442..4a983ac 100644 --- a/Core/VoteManager.cs +++ b/Core/VoteManager.cs @@ -41,7 +41,7 @@ private void RegisterCustomVotes() Plugin.CustomVotesApi.Get()?.AddCustomVote( _option, // Command to trigger the vote new List(), // Aliases for the command (optional) - Localizer["modes.vote.menu-title", _entry.Value], // Description + Localizer["mode.vote.menu-title", _entry.Value], // Description "No", // Default 30, // Time to vote new Dictionary // vote options From 90fc56a2a00b73f523b2059030b3aa175a35c883 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 9 Jun 2024 14:23:56 -0400 Subject: [PATCH 84/86] REMOVE: Unnecessary logging --- Plugin.cs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/Plugin.cs b/Plugin.cs index 84de37d..bceac6e 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -61,7 +61,6 @@ public override void Load(bool hotReload) { Logger.LogInformation($"Loading settings..."); ParseSettings(); - Logger.LogInformation($"Creating settings menu..."); SetupSettingsMenu(); } } @@ -84,6 +83,7 @@ public override void OnAllPluginsLoaded(bool hotReload) if (Config.Votes.Enabled) { + // Ensure CS2-CustomVotes API is loaded try { if (CustomVotesApi.Get() is null) @@ -96,8 +96,16 @@ public override void OnAllPluginsLoaded(bool hotReload) } _isCustomVotesLoaded = true; - Logger.LogInformation("Registering custom votes..."); - RegisterCustomVotes(); + + // Register custom votes + try + { + RegisterCustomVotes(); + } + catch (Exception ex) + { + Logger.LogError($"{ex.Message}"); + } } } // Constuct unload behavior to deregister votes @@ -107,8 +115,18 @@ public override void Unload(bool hotReload) if (_isCustomVotesLoaded) { Logger.LogInformation("Deregistering custom votes..."); - DeregisterCustomVotes(); + + // Deregister custom votes + try + { + DeregisterCustomVotes(); + } + catch (Exception ex) + { + Logger.LogError($"{ex.Message}"); + } } + // Unload plugin base.Unload(hotReload); } } From daf6c151728838693677eedb7c6bbdcc1a4df916 Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 9 Jun 2024 14:56:07 -0400 Subject: [PATCH 85/86] UPDATE: Scoped degregistration Scoped deregistration to map votes only during map group change. --- Core/CommandManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/CommandManager.cs b/Core/CommandManager.cs index bf23933..02dbbd6 100644 --- a/Core/CommandManager.cs +++ b/Core/CommandManager.cs @@ -42,7 +42,7 @@ public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) // Deregister map votes from old map group try { - DeregisterCustomVotes(); + DeregisterMapVotes(); } catch (Exception ex) { @@ -55,7 +55,7 @@ public void OnMapGroupCommand(CCSPlayerController? player, CommandInfo command) // Register map votes for new map group try { - RegisterCustomVotes(); + RegisterMapVotes(); } catch (Exception ex) { From 733c18cccebdb16e955ccc2f7623d44641f4cfee Mon Sep 17 00:00:00 2001 From: "Nick M." Date: Sun, 9 Jun 2024 14:57:27 -0400 Subject: [PATCH 86/86] UPDATE: Fixed course conflict Course was a game mode and setting. This resulted in a conflict during deregistration. For any conflicts, rename the settings file and delete the old one. --- .../settings/{disable_course.cfg => disable_course_settings.cfg} | 0 .../settings/{enable_course.cfg => enable_course_settings.cfg} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename lib/csgo/cfg/settings/{disable_course.cfg => disable_course_settings.cfg} (100%) rename lib/csgo/cfg/settings/{enable_course.cfg => enable_course_settings.cfg} (100%) diff --git a/lib/csgo/cfg/settings/disable_course.cfg b/lib/csgo/cfg/settings/disable_course_settings.cfg similarity index 100% rename from lib/csgo/cfg/settings/disable_course.cfg rename to lib/csgo/cfg/settings/disable_course_settings.cfg diff --git a/lib/csgo/cfg/settings/enable_course.cfg b/lib/csgo/cfg/settings/enable_course_settings.cfg similarity index 100% rename from lib/csgo/cfg/settings/enable_course.cfg rename to lib/csgo/cfg/settings/enable_course_settings.cfg