### Create a Chat Menu Source: https://github.com/schwarper/cs2menumanager/blob/main/README.md Example of creating a basic chat menu with options. Options can have custom actions or be disabled. ```csharp ChatMenu menu = new("Title", this); menu.AddItem("Option 1", (p, o) => { p.PrintToChat("You selected option 1"); }); menu.AddItem("Option 2X", DisableOption.DisableShowNumber); menu.AddItem("Option 3X", DisableOption.DisableHideNumber); menu.Display(player); ``` -------------------------------- ### Create Panorama Vote Menu Source: https://github.com/schwarper/cs2menumanager/blob/main/README.md Example of creating an interactive vote menu using Panorama UI. The menu can be displayed to all players with a specified duration. ```csharp var menu = new PanoramaVote("#SFUI_vote_panorama_vote_default", "Hold on, Let me Cook", VoteResultCallback, VoteHandlerCallback, this) { VoteCaller = player // null is the server. }; menu.DisplayVoteToAll(20); ``` -------------------------------- ### Manage Player Menu Preferences with MenuTypeManager Source: https://context7.com/schwarper/cs2menumanager/llms.txt Shows how to use MenuTypeManager to get, set, and manage player-specific menu type preferences. It covers falling back to defaults, persisting to MySQL, and presenting menu type selection interfaces. ```csharp using CS2MenuManager.API.Class; using CS2MenuManager.API.Menu; // Get the player's preferred menu type (falls back to config default) Type menuType = MenuTypeManager.GetPlayerMenuType(player) ?? typeof(WasdMenu); // Force a player to use ChatMenu and persist it to MySQL if configured MenuTypeManager.SetPlayerMenuType(player, typeof(ChatMenu)); // Get the server-wide default (from config.toml DefaultMenuType) Type defaultType = MenuTypeManager.GetDefaultMenu(); // Present a "Select menu type" menu using the player's own preferred style MenuTypeManager.MenuTypeMenu(player, this, prevMenu: null); // Same thing but specify the wrapper type at runtime BaseMenu typeMenu = MenuTypeManager.MenuTypeMenuByType(typeof(PlayerMenu), player, this, prevMenu: null); typeMenu.Display(player, 0); ``` -------------------------------- ### Handle Vote Actions Callback Source: https://github.com/schwarper/cs2menumanager/blob/main/README.md Callback function to manage different stages and actions of a Yes/No vote. It handles starting votes, recording individual votes, and processing the end of a vote with various reasons. ```csharp public void VoteHandlerCallback(YesNoVoteAction action, int param1, CastVote param2) { switch (action) { case YesNoVoteAction.VoteAction_Start: Server.PrintToChatAll("Vote started!"); break; case YesNoVoteAction.VoteAction_Vote: var player = Utilities.GetPlayerFromSlot(param1); if (player == null) return; player.PrintToChat("You voted: " + (param2 == CastVote.VOTE_OPTION1 ? "Yes" : "No")); break; case YesNoVoteAction.VoteAction_End: switch ((YesNoVoteEndReason)param1) { case YesNoVoteEndReason.VoteEnd_Cancelled: Server.PrintToChatAll("Vote Ended! Cancelled"); break; case YesNoVoteEndReason.VoteEnd_AllVotes: Server.PrintToChatAll("Vote Ended! Thank you for participating."); break; case YesNoVoteEndReason.VoteEnd_TimeUp: Server.PrintToChatAll("Vote Ended! Time is up."); break; } break; } } ``` -------------------------------- ### Create and Display a WASD Menu Source: https://context7.com/schwarper/cs2menumanager/llms.txt Initializes a WasdMenu with custom colors and key bindings, adds menu items, and displays it to a player. Ensure WasdMenuStateManager is registered for cleanup. ```csharp using CS2MenuManager.API.Menu; WasdMenu menu = new("Player Options", this) { WasdMenu_FreezePlayer = true, // freeze player while menu is open WasdMenu_TitleColor = "green", WasdMenu_SelectedOptionColor = "orange", WasdMenu_OptionColor = "white", WasdMenu_DisabledOptionColor = "grey", WasdMenu_ArrowColor = "purple", // Override key bindings per menu instance WasdMenu_ScrollUpKey = "W", WasdMenu_ScrollDownKey = "S", WasdMenu_SelectKey = "E", WasdMenu_ExitKey = "Tab" }; menu.AddItem("Respawn", (p, o) => { /* respawn logic */ }); menu.AddItem("Change Team", (p, o) => { /* team change */ }); menu.AddItem("Spec Mode", (p, o) => { /* spectate */ }); menu.Display(player, 0); // Register WasdMenu state cleanup to handle disconnects and round ends WasdMenuStateManager.RegisterEvents(this); ``` -------------------------------- ### Create and Display a ChatMenu Source: https://context7.com/schwarper/cs2menumanager/llms.txt Demonstrates creating a basic ChatMenu with enabled, disabled-show-number, and disabled-hide-number items. Menus can be displayed to a single player or all players with an optional timeout. ```csharp using CS2MenuManager.API.Menu; using CS2MenuManager.API.Enum; // Basic ChatMenu with enabled, disabled-show-number, and disabled-hide-number items ChatMenu menu = new("Server Settings", this); menu.AddItem("Change Map", (player, option) => { player.PrintToChat("Map vote started!"); }); // Disabled item that still shows its number slot menu.AddItem("VIP Only Feature", DisableOption.DisableShowNumber); // Disabled item that hides its number entirely menu.AddItem("Hidden Disabled Item", DisableOption.DisableHideNumber); // Show to a single player for 30 seconds; pass 0 for no timeout menu.Display(player, 30); // Show to every human player simultaneously menu.DisplayToAll(30); ``` -------------------------------- ### Create and Manage Menus with MenuManager Source: https://context7.com/schwarper/cs2menumanager/llms.txt Demonstrates various ways to create and manage menus using the MenuManager. This includes creating menus by generic type, Type object, or string name, as well as retrieving active menus, closing them, and reloading configuration. ```csharp using CS2MenuManager.API.Class; using CS2MenuManager.API.Menu; // Create a menu by generic type (compile-time safe) WasdMenu wasd = MenuManager.CreateMenu("Pick Option", this); wasd.AddItem("Option A", (p, o) => { }); wasd.Display(player, 0); // Create a menu by Type object (runtime dispatch) Type preferredType = MenuTypeManager.GetPlayerMenuType(player) ?? typeof(WasdMenu); BaseMenu dynamic = MenuManager.MenuByType(preferredType, "Dynamic Menu", this); dynamic.AddItem("Hello", (p, o) => p.PrintToChat("Hello!")); dynamic.Display(player, 0); // Create a menu by string name (e.g. from config value) BaseMenu fromString = MenuManager.MenuByType("ChatMenu", "Chat-based Menu", this); // Get the player's currently active menu instance IMenuInstance? active = MenuManager.GetActiveMenu(player); if (active != null) player.PrintToChat($"You are on page {active.Page}"); // Programmatically close whatever menu is open for a player MenuManager.CloseActiveMenu(player); // Reload config.toml at runtime (e.g. after admin edits the file) MenuManager.ReloadConfig(); ``` -------------------------------- ### Build Chained Sub-Menus with Back-Navigation in C# Source: https://context7.com/schwarper/cs2menumanager/llms.txt Demonstrates how to create a hierarchy of menus where sub-menus can navigate back to their parent. Ensure PrevMenu is set correctly for back navigation. ```csharp using CS2MenuManager.API.Menu; private WasdMenu BuildWeaponMenu(CCSPlayerController player) { WasdMenu weaponMenu = new("Choose Weapon", this); weaponMenu.AddItem("Rifles", (p, o) => BuildRifleMenu(p).Display(p, 0)); weaponMenu.AddItem("Pistols", (p, o) => BuildPistolMenu(p).Display(p, 0)); return weaponMenu; } private WasdMenu BuildRifleMenu(CCSPlayerController player) { WasdMenu rifleMenu = new("Rifles", this); rifleMenu.PrevMenu = BuildWeaponMenu(player); // back = weapon root rifleMenu.AddItem("AK-47", (p, o) => { /* give */ }); rifleMenu.AddItem("M4A4", (p, o) => { /* give */ }); rifleMenu.AddItem("AWP", (p, o) => { /* give */ }); return rifleMenu; } // Entry point BuildWeaponMenu(player).Display(player, 0); ``` -------------------------------- ### Add Submenu to Menu Source: https://github.com/schwarper/cs2menumanager/blob/main/README.md Demonstrates how to link a submenu to an existing menu. Ensure the submenu is properly initialized. ```csharp menu.PrevMenu = AnySubMenu(); private static CenterHtmlMenu AnySubMenu() { CenterHtmlMenu menu = new("Title", this); //... return menu; } ``` -------------------------------- ### Create a Player-Preferred Proxy Menu Source: https://context7.com/schwarper/cs2menumanager/llms.txt Constructs a PlayerMenu, which acts as a proxy to render menus based on player preferences stored in a database. Requires the CS2MenuManager_MenuManager plugin and a MySQL connection. ```csharp using CS2MenuManager.API.Menu; using CS2MenuManager.API.Class; // Build the proxy menu — items are shared across all render types PlayerMenu menu = new(Localizer.ForPlayer(player, "MenuManager Title"), this); menu.AddItem(Localizer.ForPlayer(player, "Change Resolution"), (p, o) => { // ResolutionManager lives in the MenuManager companion plugin ResolutionManager.ResolutionMenuByType(typeof(PlayerMenu), p, this, menu) .Display(p, 0); }); menu.AddItem(Localizer.ForPlayer(player, "Change Menu Type"), (p, o) => { MenuTypeManager.MenuTypeMenuByType(typeof(PlayerMenu), p, this, menu) .Display(p, 0); }); menu.Display(player, 0); ``` -------------------------------- ### Create and Display a ConsoleMenu Source: https://context7.com/schwarper/cs2menumanager/llms.txt Shows how to create a ConsoleMenu with a specified auto-close time and disable the exit button. The menu is displayed to a player, using the MenuTime property for the timeout. ```csharp using CS2MenuManager.API.Menu; using CS2MenuManager.API.Enum; ConsoleMenu menu = new("Admin Panel", this) { MenuTime = 60 // auto-close after 60 s (alternative to passing time in Display) }; menu.AddItem("Kick Player", (player, option) => { // kick logic player.PrintToConsole("Kick initiated."); }); menu.AddItem("Ban Player", (player, option) => { // ban logic }); // Disable exit button menu.ExitButton = false; menu.Display(player, 0); // 0 = use MenuTime property ``` -------------------------------- ### Create and Display a CenterHtmlMenu Source: https://context7.com/schwarper/cs2menumanager/llms.txt Illustrates creating a CenterHtmlMenu with custom colors, inline page options, and max option length. Items can be added, and disabled items can be configured to show or hide their number. ```csharp using CS2MenuManager.API.Menu; using CS2MenuManager.API.Enum; CenterHtmlMenu menu = new("Choose Weapon", this) { CenterHtmlMenu_TitleColor = "cyan", CenterHtmlMenu_EnabledColor = "lime", CenterHtmlMenu_DisabledColor = "grey", CenterHtmlMenu_InlinePageOptions = true, CenterHtmlMenu_MaxOptionLength = 30 // truncate options longer than 30 chars }; menu.AddItem("AK-47", (p, o) => { /* give weapon */ }); menu.AddItem("M4A4", (p, o) => { /* give weapon */ }); menu.AddItem("AWP", (p, o) => { /* give weapon */ }); menu.AddItem("Desert Eagle", (p, o) => { /* give weapon */ }); menu.AddItem("Knife", DisableOption.DisableShowNumber); // out of stock menu.Display(player, 15); ``` -------------------------------- ### Global Configuration File for CS2MenuManager Source: https://context7.com/schwarper/cs2menumanager/llms.txt Configure default menu types, button bindings, sounds, database connections, and appearance settings for different menu types by placing this TOML file in the specified directory. ```toml DefaultMenuType = "WasdMenu" # ConsoleMenu | ChatMenu | WasdMenu | CenterHtmlMenu [ForceConfigSettings] ForceConfigSettings = true [Buttons] ScrollUp = "W" ScrollDown = "S" Select = "E" Prev = "Shift" Exit = "Tab" [Sound] Select = "" # e.g. "sounds/ui/buttonclick.vsnd_c" Exit = "" ScrollUp = "" ScrollDown = "" [MySQL] Host = "127.0.0.1" Name = "cs2_db" User = "cs2user" Pass = "secret" Port = 3306 [ChatMenu] TitleColor = "Yellow" EnabledColor = "Green" DisabledColor = "Grey" PrevPageColor = "Yellow" NextPageColor = "Yellow" ExitColor = "Red" [CenterHtmlMenu] TitleColor = "Yellow" EnabledColor = "Green" DisabledColor = "Grey" InlinePageOptions = true MaxTitleLength = 0 # 0 = unlimited MaxOptionLength = 0 [WasdMenu] TitleColor = "Green" SelectedOptionColor = "Orange" OptionColor = "White" DisabledOptionColor = "Grey" ArrowColor = "Purple" FreezePlayer = false [Lang.en] Prev = "Prev" Next = "Next" Exit = "Exit" WarnDisabledItem = "{Grey}You {Red}can't {Grey}enter this option." OptionListEmpty = "{Grey}No available options in this menu" ``` -------------------------------- ### Populate Team Menu with IMenu Interface Source: https://context7.com/schwarper/cs2menumanager/llms.txt A helper function demonstrating how to populate a menu using the IMenu interface. It sets the title, exit button, menu time, and adds items with associated actions. Ensure IMenu and CCSPlayerController are available. ```csharp using CS2MenuManager.API.Interface; using CS2MenuManager.API.Enum; // A helper that works with any IMenu implementation void PopulateTeamMenu(IMenu menu, CCSPlayerController player) { menu.Title = "Select Team"; menu.ExitButton = true; menu.MenuTime = 30; menu.AddItem("Terrorist", (p, o) => p.SwitchTeam(CsTeam.Terrorist)); menu.AddItem("Counter-Terrorist", (p, o) => p.SwitchTeam(CsTeam.CounterTerrorist)); menu.AddItem("Spectator", (p, o) => p.SwitchTeam(CsTeam.Spectator)); // Navigate to sub-menu on back WasdMenu confirmMenu = new("Confirm?", plugin); confirmMenu.AddItem("Yes", (p, o) => { /* confirm */ }); menu.PrevMenu = confirmMenu; menu.Display(player, menu.MenuTime); } ``` -------------------------------- ### Control Menu Behavior with ItemOption and PostSelectAction Source: https://context7.com/schwarper/cs2menumanager/llms.txt Illustrates how to control the behavior of a menu after an item is selected using PostSelectAction. Options include closing the menu, resetting to the first page, or doing nothing while updating item text. ```csharp using CS2MenuManager.API.Class; using CS2MenuManager.API.Enum; ChatMenu menu = new("Persistent Menu", this); // Default: close menu after selection menu.AddItem("One-shot action", (p, o) => { p.PrintToChat("Done! Menu closed."); // o.PostSelectAction == PostSelectAction.Close (default) }); // Reset: re-open the menu from page 1 after selection ItemOption refreshItem = menu.AddItem("Toggle God Mode", (p, o) => { // toggle logic... p.PrintToChat("Toggled! Menu stays open."); }); refreshItem.PostSelectAction = PostSelectAction.Reset; // Nothing: redisplay the current page without resetting ItemOption liveItem = menu.AddItem("Live Counter: 0", (p, o) => { o.Text = $"Clicked {++clickCount} times"; // PostSelectAction.Nothing keeps the menu visible and updates text }); liveItem.PostSelectAction = PostSelectAction.Nothing; menu.Display(player, 0); ``` -------------------------------- ### Create Player-Selected Menu Source: https://github.com/schwarper/cs2menumanager/blob/main/README.md Creates a menu where the player chooses which menu to open, requiring the CS2MenuManager_MenuManager plugin and a database connection. ```csharp PlayerMenu menu = new(Localizer.ForPlayer(player, "MenuManager Title"), this); menu.AddItem(Localizer.ForPlayer(player, "Change Resolution"), (p, o) => { ResolutionManager.ResolutionMenuByType(typeof(PlayerMenu), player, this, menu) .Display(player, 0); }); menu.AddItem(Localizer.ForPlayer(player, "Change Menu Type"), (p, o) => { MenuTypeManager.MenuTypeMenuByType(typeof(PlayerMenu), player, this, menu) .Display(player, 0); }); menu.Display(player, 0); ``` -------------------------------- ### Create and Display a Panorama UI Vote Source: https://context7.com/schwarper/cs2menumanager/llms.txt Initiates a native Panorama UI yes/no vote for all players. Requires callbacks for handling results and events. The vote duration is specified in seconds. ```csharp using CS2MenuManager.API.Menu; using CS2MenuManager.API.Class; using CS2MenuManager.API.Enum; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; // --- Vote creation --- PanoramaVote vote = new( title: "#SFUI_vote_panorama_vote_default", details: "Extend current map by 30 minutes?", resultCallback: OnVoteResult, handler: OnVoteAction, plugin: this) { VoteCaller = player // null = server-initiated }; vote.DisplayVoteToAll(20); // 20-second voting window // --- Result callback: return true = passed, false = failed --- public bool OnVoteResult(YesNoVoteInfo info) { // info.TotalVotes, info.YesVotes, info.NoVotes, info.TotalClients // info.ClientInfo: Dictionary if (info.YesVotes > info.NoVotes) { Server.PrintToChatAll($"[Vote] Passed! {info.YesVotes}/{info.TotalVotes} voted Yes."); return true; } Server.PrintToChatAll($"[Vote] Failed. {info.NoVotes}/{info.TotalVotes} voted No."); return false; } // --- Handler callback: per-event notifications --- public void OnVoteAction(YesNoVoteAction action, int param1, CastVote param2) { switch (action) { case YesNoVoteAction.VoteAction_Start: Server.PrintToChatAll("[Vote] Vote has started!"); break; case YesNoVoteAction.VoteAction_Vote: CCSPlayerController? voter = Utilities.GetPlayerFromSlot(param1); string choice = param2 == CastVote.VOTE_OPTION1 ? "Yes" : "No"; voter?.PrintToChat($"[Vote] You voted: {choice}"); break; case YesNoVoteAction.VoteAction_End: string reason = (YesNoVoteEndReason)param1 switch { YesNoVoteEndReason.VoteEnd_AllVotes => "all votes cast", YesNoVoteEndReason.VoteEnd_TimeUp => "time expired", YesNoVoteEndReason.VoteEnd_Cancelled => "cancelled", _ => "unknown" }; Server.PrintToChatAll($"[Vote] Ended: {reason}"); break; } } // Cancel an in-progress vote programmatically VoteManager.CancelActiveVote(); // Check if a vote is active if (VoteManager.IsVoteActive) player.PrintToChat("A vote is already running!"); ``` -------------------------------- ### Set Post-Select Action for Menu Option Source: https://github.com/schwarper/cs2menumanager/blob/main/README.md Configures the behavior after a menu option is selected. The default action is to close the menu. ```csharp menu.AddItem("Option After Reset", (p, o) => { o.PostSelectAction = PostSelectAction.Reset; }); ``` -------------------------------- ### WasdMenu Source: https://context7.com/schwarper/cs2menumanager/llms.txt Renders a center-screen HTML menu navigated with movement keys. Player position can optionally be frozen while the menu is open. Saves and restores per-player scroll position on re-open. ```APIDOC ## WasdMenu ### Description Creates and displays a WASD-style navigation menu for players. This menu allows for navigation using keys like W/S for scrolling, E for selection, and Shift/Tab for going back or exiting, without requiring chat commands. Player position can be optionally frozen while the menu is active, and scroll positions are saved and restored between sessions. ### Usage ```csharp using CS2MenuManager.API.Menu; WasdMenu menu = new WasdMenu("Player Options", this) { WasdMenu_FreezePlayer = true, // freeze player while menu is open WasdMenu_TitleColor = "green", WasdMenu_SelectedOptionColor = "orange", WasdMenu_OptionColor = "white", WasdMenu_DisabledOptionColor = "grey", WasdMenu_ArrowColor = "purple", // Override key bindings per menu instance WasdMenu_ScrollUpKey = "W", WasdMenu_ScrollDownKey = "S", WasdMenu_SelectKey = "E", WasdMenu_ExitKey = "Tab" }; menu.AddItem("Respawn", (p, o) => { /* respawn logic */ }); menu.AddItem("Change Team", (p, o) => { /* team change */ }); menu.AddItem("Spec Mode", (p, o) => { /* spectate */ }); menu.Display(player, 0); // Register WasdMenu state cleanup to handle disconnects and round ends WasdMenuStateManager.RegisterEvents(this); ``` ### Configuration Options - `WasdMenu_FreezePlayer`: Boolean to freeze player position while the menu is open. - `WasdMenu_TitleColor`: String for the title color. - `WasdMenu_SelectedOptionColor`: String for the selected option color. - `WasdMenu_OptionColor`: String for the default option color. - `WasdMenu_DisabledOptionColor`: String for disabled option color. - `WasdMenu_ArrowColor`: String for the arrow indicator color. - `WasdMenu_ScrollUpKey`: String for the key to scroll up. - `WasdMenu_ScrollDownKey`: String for the key to scroll down. - `WasdMenu_SelectKey`: String for the key to select an option. - `WasdMenu_ExitKey`: String for the key to exit the menu. ### Methods - `AddItem(string text, Action callback)`: Adds an item to the menu. - `Display(CCSPlayerController player, int initial_focus)`: Displays the menu to the specified player. ### State Management - `WasdMenuStateManager.RegisterEvents(this)`: Registers event handlers to manage WasdMenu state cleanup during disconnects and round ends. ``` -------------------------------- ### Display Menu at Specific Item Index in C# Source: https://context7.com/schwarper/cs2menumanager/llms.txt Utilize `DisplayAt` to open a menu scrolled to a specific item index, useful for resuming at the last-used position. `DisplayAtToAll` opens the menu for all players. ```csharp using CS2MenuManager.API.Menu; WasdMenu menu = new("Saved Position Menu", this); for (int i = 0; i < 20; i++) { int idx = i; menu.AddItem($"Item {idx + 1}", (p, o) => p.PrintToChat($"Selected {idx + 1}")); } // Open directly at item index 10 (0-based) menu.DisplayAt(player, 10, 0); // DisplayAtToAll opens for every human player at the same offset menu.DisplayAtToAll(5, 30); ``` -------------------------------- ### PlayerMenu Source: https://context7.com/schwarper/cs2menumanager/llms.txt A proxy menu that renders as the player's preferred menu type, defaulting to WasdMenu. Requires the CS2MenuManager_MenuManager plugin and MySQL. ```APIDOC ## PlayerMenu ### Description `PlayerMenu` acts as a proxy that dynamically renders as the player's preferred menu type, with `WasdMenu` as the default. It relies on the companion `CS2MenuManager_MenuManager` plugin and a MySQL connection to store and retrieve player preferences across sessions. ### Usage ```csharp using CS2MenuManager.API.Menu; using CS2MenuManager.API.Class; // Build the proxy menu — items are shared across all render types PlayerMenu menu = new PlayerMenu(Localizer.ForPlayer(player, "MenuManager Title"), this); menu.AddItem(Localizer.ForPlayer(player, "Change Resolution"), (p, o) => { // ResolutionManager lives in the MenuManager companion plugin ResolutionManager.ResolutionMenuByType(typeof(PlayerMenu), p, this, menu) .Display(p, 0); }); menu.AddItem(Localizer.ForPlayer(player, "Change Menu Type"), (p, o) => { MenuTypeManager.MenuTypeMenuByType(typeof(PlayerMenu), p, this, menu) .Display(p, 0); }); menu.Display(player, 0); ``` ### Constructor Parameters - `title` (string): The title of the menu, typically localized. - `plugin` (IPlugin): The plugin instance. ### Methods - `AddItem(string text, Action callback)`: Adds an item to the menu. The callback function is executed when the item is selected. - `Display(CCSPlayerController player, int initial_focus)`: Displays the menu to the specified player. ### Dependencies - Requires the `CS2MenuManager_MenuManager` companion plugin. - Requires a MySQL connection for persisting player menu preferences. ``` -------------------------------- ### ItemOption and PostSelectAction Source: https://context7.com/schwarper/cs2menumanager/llms.txt Controls the behavior of menu items after selection using ItemOption and PostSelectAction. ```APIDOC ## ItemOption and PostSelectAction Each item added to a menu returns an `ItemOption` object whose `PostSelectAction` controls what happens to the menu after the item is chosen. ### PostSelectAction Enum - **Close**: Closes the menu after selection (default). - **Reset**: Re-opens the menu from page 1 after selection. - **Nothing**: Redisplays the current page without resetting. ### ItemOption Properties - **Text** (string): The display text of the menu item. - **PostSelectAction** (PostSelectAction): The action to perform after the item is selected. ### Example Usage ```csharp ChatMenu menu = new("Persistent Menu", this); // Default: close menu after selection menu.AddItem("One-shot action", (p, o) => { p.PrintToChat("Done! Menu closed."); // o.PostSelectAction == PostSelectAction.Close (default) }); // Reset: re-open the menu from page 1 after selection ItemOption refreshItem = menu.AddItem("Toggle God Mode", (p, o) => { // toggle logic... p.PrintToChat("Toggled! Menu stays open."); }); refreshItem.PostSelectAction = PostSelectAction.Reset; // Nothing: redisplay the current page without resetting ItemOption liveItem = menu.AddItem("Live Counter: 0", (p, o) => { o.Text = $"Clicked {++clickCount} times"; // PostSelectAction.Nothing keeps the menu visible and updates text }); liveItem.PostSelectAction = PostSelectAction.Nothing; menu.Display(player, 0); ``` ``` -------------------------------- ### DisableOption Enumeration Reference Source: https://context7.com/schwarper/cs2menumanager/llms.txt Defines how non-selectable menu items are rendered. Use `DisableOption.None` for selectable items. ```csharp DisableOption.None // selectable (default) DisableOption.DisableShowNumber // grayed out, number still visible DisableOption.HideNumber // grayed out, number hidden ``` -------------------------------- ### IMenu Interface Source: https://context7.com/schwarper/cs2menumanager/llms.txt The IMenu interface defines the shared properties and methods for all menu types, enabling generic helper functions. ```APIDOC ## IMenu Interface All menu types implement `IMenu`, which defines the shared property and method surface. This allows generic helpers to work with any menu type. ### Properties - **Title** (string): The title of the menu. - **ExitButton** (bool): Whether to display an exit button. - **MenuTime** (int): The time limit for the menu. - **PrevMenu** (IMenu): The previous menu in the navigation stack. ### Methods #### AddItem Adds an item to the menu with a specified text and a callback action. ```csharp menu.AddItem("Menu Item Text", (p, o) => { /* action */ }); ``` #### Display Displays the menu to the specified player. ```csharp menu.Display(player, menu.MenuTime); ``` ### Example Usage ```csharp void PopulateTeamMenu(IMenu menu, CCSPlayerController player) { menu.Title = "Select Team"; menu.ExitButton = true; menu.MenuTime = 30; menu.AddItem("Terrorist", (p, o) => p.SwitchTeam(CsTeam.Terrorist)); menu.AddItem("Counter-Terrorist", (p, o) => p.SwitchTeam(CsTeam.CounterTerrorist)); menu.AddItem("Spectator", (p, o) => p.SwitchTeam(CsTeam.Spectator)); WasdMenu confirmMenu = new("Confirm?", plugin); confirmMenu.AddItem("Yes", (p, o) => { /* confirm */ }); menu.PrevMenu = confirmMenu; menu.Display(player, menu.MenuTime); } ``` ``` -------------------------------- ### MenuManager Class Source: https://context7.com/schwarper/cs2menumanager/llms.txt The MenuManager class provides static methods for creating, managing, and interacting with menu instances. ```APIDOC ## MenuManager `MenuManager` manages all active per-player menu instances, handles timers, and provides factory methods for creating menus by type at runtime. ### Methods #### CreateMenu Creates a menu by generic type. ```csharp WasdMenu wasd = MenuManager.CreateMenu("Pick Option", this); wasd.AddItem("Option A", (p, o) => { }); wasd.Display(player, 0); ``` #### MenuByType Creates a menu by Type object or string name. ```csharp // By Type object Type preferredType = MenuTypeManager.GetPlayerMenuType(player) ?? typeof(WasdMenu); BaseMenu dynamic = MenuManager.MenuByType(preferredType, "Dynamic Menu", this); dynamic.AddItem("Hello", (p, o) => p.PrintToChat("Hello!")); dynamic.Display(player, 0); // By string name BaseMenu fromString = MenuManager.MenuByType("ChatMenu", "Chat-based Menu", this); ``` #### GetActiveMenu Gets the player's currently active menu instance. ```csharp IMenuInstance? active = MenuManager.GetActiveMenu(player); if (active != null) player.PrintToChat($"You are on page {active.Page}"); ``` #### CloseActiveMenu Programmatically closes the active menu for a player. ```csharp MenuManager.CloseActiveMenu(player); ``` #### ReloadConfig Reloads the configuration file at runtime. ```csharp MenuManager.ReloadConfig(); ``` ``` -------------------------------- ### Set Menu Display Time Source: https://github.com/schwarper/cs2menumanager/blob/main/README.md Sets a timer for how long a menu will be displayed before automatically closing. This can be done during display or by setting a property. ```csharp menu.Display(menu, 10); // OR ConsoleMenu menu = new("Console Menu", this) { MenuTime = 20 }; ``` -------------------------------- ### MenuTypeManager Class Source: https://context7.com/schwarper/cs2menumanager/llms.txt The MenuTypeManager class handles per-player menu type preferences, with optional persistence to MySQL. ```APIDOC ## MenuTypeManager `MenuTypeManager` stores and retrieves each player's preferred menu type, optionally persisting it to MySQL so preferences survive server restarts. ### Methods #### GetPlayerMenuType Gets the player's preferred menu type, falling back to the config default. ```csharp Type menuType = MenuTypeManager.GetPlayerMenuType(player) ?? typeof(WasdMenu); ``` #### SetPlayerMenuType Forces a player to use a specific menu type and persists it if configured. ```csharp MenuTypeManager.SetPlayerMenuType(player, typeof(ChatMenu)); ``` #### GetDefaultMenu Gets the server-wide default menu type from the configuration. ```csharp Type defaultType = MenuTypeManager.GetDefaultMenu(); ``` #### MenuTypeMenu Presents a menu for selecting the menu type, using the player's preferred style. ```csharp MenuTypeManager.MenuTypeMenu(player, this, prevMenu: null); ``` #### MenuTypeMenuByType Presents a menu for selecting the menu type, specifying the wrapper type at runtime. ```csharp BaseMenu typeMenu = MenuTypeManager.MenuTypeMenuByType(typeof(PlayerMenu), player, this, prevMenu: null); typeMenu.Display(player, 0); ``` ``` -------------------------------- ### PostSelectAction Enumeration Reference Source: https://context7.com/schwarper/cs2menumanager/llms.txt Controls the menu's behavior after an item is selected. Defaults to closing the menu. ```csharp PostSelectAction.Close // close the menu (default) PostSelectAction.Reset // reset to page 1 and re-display PostSelectAction.Nothing // redisplay current page as-is ``` -------------------------------- ### Handle Vote Results Callback Source: https://github.com/schwarper/cs2menumanager/blob/main/README.md Callback function to process the results of a Yes/No vote. It determines if the vote passed or failed based on the vote counts and prints the outcome to all players. ```csharp public bool VoteResultCallback(YesNoVoteInfo info) { /* public int TotalVotes; public int YesVotes; public int NoVotes; public int TotalClients; public Dictionary ClientInfo = []; */ if (info.YesVotes > info.NoVotes) { Server.PrintToChatAll("Vote passed!"); return true; } Server.PrintToChatAll("Vote failed!"); return false; } ``` -------------------------------- ### PanoramaVote Source: https://context7.com/schwarper/cs2menumanager/llms.txt Triggers the game's native Panorama vote HUD for all human players. Requires result and handler callbacks. ```APIDOC ## PanoramaVote ### Description Initiates the built-in Panorama UI yes/no vote for all human players. This function requires a callback for handling the vote results and an optional callback for granular event control during the vote's lifecycle. ### Usage ```csharp using CS2MenuManager.API.Menu; using CS2MenuManager.API.Class; using CS2MenuManager.API.Enum; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; // --- Vote creation --- PanoramaVote vote = new PanoramaVote( title: "#SFUI_vote_panorama_vote_default", details: "Extend current map by 30 minutes?", resultCallback: OnVoteResult, handler: OnVoteAction, plugin: this) { VoteCaller = player // null = server-initiated }; vote.DisplayVoteToAll(20); // 20-second voting window // --- Result callback: return true = passed, false = failed --- public bool OnVoteResult(YesNoVoteInfo info) { // info.TotalVotes, info.YesVotes, info.NoVotes, info.TotalClients // info.ClientInfo: Dictionary if (info.YesVotes > info.NoVotes) { Server.PrintToChatAll($"[Vote] Passed! {info.YesVotes}/{info.TotalVotes} voted Yes."); return true; } Server.PrintToChatAll($"[Vote] Failed. {info.NoVotes}/{info.TotalVotes} voted No."); return false; } // --- Handler callback: per-event notifications --- public void OnVoteAction(YesNoVoteAction action, int param1, CastVote param2) { switch (action) { case YesNoVoteAction.VoteAction_Start: Server.PrintToChatAll("[Vote] Vote has started!"); break; case YesNoVoteAction.VoteAction_Vote: CCSPlayerController? voter = Utilities.GetPlayerFromSlot(param1); string choice = param2 == CastVote.VOTE_OPTION1 ? "Yes" : "No"; voter?.PrintToChat($"[Vote] You voted: {choice}"); break; case YesNoVoteAction.VoteAction_End: string reason = (YesNoVoteEndReason)param1 switch { YesNoVoteEndReason.VoteEnd_AllVotes => "all votes cast", YesNoVoteEndReason.VoteEnd_TimeUp => "time expired", YesNoVoteEndReason.VoteEnd_Cancelled => "cancelled", _ => "unknown" }; Server.PrintToChatAll($"[Vote] Ended: {reason}"); break; } } // Cancel an in-progress vote programmatically VoteManager.CancelActiveVote(); // Check if a vote is active if (VoteManager.IsVoteActive) player.PrintToChat("A vote is already running!"); ``` ### Constructor Parameters - `title` (string): The title of the vote. - `details` (string): The details or question for the vote. - `resultCallback` (Func): A callback function that receives vote information and returns true if the vote passed, false otherwise. - `handler` (Action): An optional callback function for handling specific vote events. - `plugin` (IPlugin): The plugin instance. ### Properties - `VoteCaller` (CCSPlayerController?): The player who initiated the vote. Set to null for server-initiated votes. ### Methods - `DisplayVoteToAll(int duration)`: Displays the vote to all players for the specified duration in seconds. ### Vote Management - `VoteManager.CancelActiveVote()`: Programmatically cancels the currently active vote. - `VoteManager.IsVoteActive` (bool): A property that indicates whether a vote is currently active. ### Callbacks - `OnVoteResult(YesNoVoteInfo info)`: Processes the final vote results. `info` contains `TotalVotes`, `YesVotes`, `NoVotes`, `TotalClients`, and `ClientInfo`. - `OnVoteAction(YesNoVoteAction action, int param1, CastVote param2)`: Handles various vote events like start, vote cast, and end. `action` specifies the event type, `param1` and `param2` provide event-specific data. ``` -------------------------------- ### Vote Constants in C# Source: https://context7.com/schwarper/cs2menumanager/llms.txt Defines constants for vote options, states, and end reasons used in the voting system. These are typically used within event handlers or when casting votes. ```csharp // CastVote CastVote.VOTE_OPTION1 // "Yes" CastVote.VOTE_OPTION2 // "No" CastVote.VOTE_UNCAST // player has not voted yet CastVote.VOTE_NOTINCLUDED // player excluded from vote // YesNoVoteAction (handler callback first parameter) YesNoVoteAction.VoteAction_Start // vote display began YesNoVoteAction.VoteAction_Vote // a player cast their vote YesNoVoteAction.VoteAction_End // voting period ended // YesNoVoteEndReason (param1 when action == VoteAction_End) YesNoVoteEndReason.VoteEnd_AllVotes // everyone voted YesNoVoteEndReason.VoteEnd_TimeUp // time limit reached YesNoVoteEndReason.VoteEnd_Cancelled // CancelActiveVote() called ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.