diff --git a/src/CSSUniversalMenuAPI/IMenuAPI.cs b/src/CSSUniversalMenuAPI/IMenuAPI.cs index e230954..2a0e193 100644 --- a/src/CSSUniversalMenuAPI/IMenuAPI.cs +++ b/src/CSSUniversalMenuAPI/IMenuAPI.cs @@ -2,7 +2,6 @@ using System.Threading; using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Core.Capabilities; namespace CSSUniversalMenuAPI; @@ -38,9 +37,4 @@ public interface IMenuAPI /// The player of which to query. /// Whether the player has an active menu on their screen. bool IsMenuOpen(CCSPlayerController player); - - /// - /// Standard helper to get get or provide this implementation - /// - static readonly PluginCapability PluginCapability = new("universalmenuapi"); } diff --git a/src/CSSUniversalMenuAPI/UniversalMenu.cs b/src/CSSUniversalMenuAPI/UniversalMenu.cs new file mode 100644 index 0000000..830539d --- /dev/null +++ b/src/CSSUniversalMenuAPI/UniversalMenu.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text.Json; +using System.Threading; + +using CounterStrikeSharp.API.Core; + +namespace CSSUniversalMenuAPI; + +/// +/// Because menus may want access to other drivers, and PluginCapability<> is not expressive enough, +/// this helper class is included with the interface to aid in constructing and +/// +public static class UniversalMenu +{ + private static string? DefaultDriverDesired { get; } + private static string? DefaultDriverName { get; set; } + public static IMenuAPI? DefaultDriver { get; private set; } + + private static Dictionary RegisteredDrivers { get; } = new(); + public static IReadOnlyDictionary Drivers => RegisteredDrivers; + public static event EventHandler? DriversChanged; + + static UniversalMenu() + { + var configDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Environment.CurrentDirectory; + var configPath = Path.Join(configDir, "config.json"); + + if (!File.Exists(configPath)) + { + Console.WriteLine("UniversalMenu: No default driver configured, will use first registered driver"); + return; + } + + var contents = File.ReadAllText(configPath); + var doc = JsonDocument.Parse(contents); + DefaultDriverDesired = doc.RootElement.GetProperty("driver").GetString(); + + Console.WriteLine($"UniversalMenu: Desired default driver: {DefaultDriverDesired}"); + } + + public static void RegisterDriver(string name, IMenuAPI driver) + { + if (!RegisteredDrivers.TryAdd(name, driver)) + throw new InvalidOperationException($"RegisterDriver(): Conflicting named drivers configured: {name}"); + + if (DefaultDriverDesired is null || name == DefaultDriverDesired) + { + if (DefaultDriver is not null) + throw new InvalidOperationException($"RegisterDriver(): Conflicting default drivers configured: {name} and {DefaultDriverName}"); + DefaultDriver = driver; + DefaultDriverName = name; + } + DriversChanged?.Invoke(null, EventArgs.Empty); + } + + public static void UnregisterDriver(string name) + { + if (RegisteredDrivers.Remove(name, out var driver) && driver == DefaultDriver) + { + DefaultDriver = null; + DefaultDriverName = null; + } + DriversChanged?.Invoke(null, EventArgs.Empty); + } + + public static IMenu CreateMenu(CCSPlayerController player, CancellationToken ct = default) + { + if (DefaultDriver is null) + throw new InvalidOperationException("No default driver has been registered. Do you have a driver installed and/or configured?"); + return DefaultDriver.CreateMenu(player, ct); + } + + public static IMenu CreateMenu(IMenu parent, CancellationToken ct = default) + { + if (DefaultDriver is null) + throw new InvalidOperationException("No default driver has been registered. Do you have a driver installed and/or configured?"); + return DefaultDriver.CreateMenu(parent, ct); + } +} diff --git a/src/UniversalMenu.Compat.CSSharp/CSSharpCompatPlugin.cs b/src/UniversalMenu.Compat.CSSharp/CSSharpCompatPlugin.cs index 7995713..5cfa963 100644 --- a/src/UniversalMenu.Compat.CSSharp/CSSharpCompatPlugin.cs +++ b/src/UniversalMenu.Compat.CSSharp/CSSharpCompatPlugin.cs @@ -80,7 +80,7 @@ public static bool BaseMenu_Open(BasePlugin? plugin, CCSPlayerController player, activeMenu.Close(); } - var api = IMenuAPI.PluginCapability.Get(); + var api = CSSUniversalMenuAPI.UniversalMenu.DefaultDriver; if (api is null) // fall back to builtin menu return true; diff --git a/src/UniversalMenu.Compat.MenuManagerApi/MenuManagerCompat.cs b/src/UniversalMenu.Compat.MenuManagerApi/MenuManagerCompat.cs index aa4a84a..8761de5 100644 --- a/src/UniversalMenu.Compat.MenuManagerApi/MenuManagerCompat.cs +++ b/src/UniversalMenu.Compat.MenuManagerApi/MenuManagerCompat.cs @@ -30,9 +30,7 @@ public override void Load(bool hotReload) if (Instance is not null) return Instance; - var universalAPI = IMenuAPI.PluginCapability.Get() - ?? throw new Exception("Unable to find CSSUniversalAPI supporting menu or adapter"); - Instance = new MenuManagerTranslator(this, universalAPI); + Instance = new MenuManagerTranslator(this); return Instance; }); diff --git a/src/UniversalMenu.Compat.MenuManagerApi/MenuManagerTranslator.cs b/src/UniversalMenu.Compat.MenuManagerApi/MenuManagerTranslator.cs index 28f7a78..681ed16 100644 --- a/src/UniversalMenu.Compat.MenuManagerApi/MenuManagerTranslator.cs +++ b/src/UniversalMenu.Compat.MenuManagerApi/MenuManagerTranslator.cs @@ -9,7 +9,6 @@ using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Menu; -using CSSUniversalMenuAPI; using CSSUniversalMenuAPI.Extensions; using ICssMenu = CounterStrikeSharp.API.Modules.Menu.IMenu; @@ -22,11 +21,9 @@ namespace UniversalMenu.Compat.MenuManagerApi; public sealed class MenuManagerTranslator : IMenuManagerAPI { public MenuManagerCompat Plugin { get; } - public IMenuAPI UniversalAPI { get; } - public MenuManagerTranslator(MenuManagerCompat plugin, IMenuAPI universalAPI) + public MenuManagerTranslator(MenuManagerCompat plugin) { Plugin = plugin; - UniversalAPI = universalAPI; } internal class PlayerState @@ -69,7 +66,7 @@ MenuManagerMenuType IMenuManagerAPI.GetMenuType(CCSPlayerController player) bool IMenuManagerAPI.HasOpenedMenu(CCSPlayerController player) { - return UniversalAPI.IsMenuOpen(player); + return CSSUniversalMenuAPI.UniversalMenu.DefaultDriver?.IsMenuOpen(player) ?? false; } ICssMenu IMenuManagerAPI.NewMenu(string title, Action back_action) @@ -87,7 +84,6 @@ internal sealed class MenuInstanceTranslator : ICssMenu { public string Title { get; set; } public MenuManagerTranslator Translator { get; } - public IMenuAPI UniversalAPI => Translator.UniversalAPI; public bool ExitButton { get; set; } public List MenuOptions { get; } = new(); @@ -130,7 +126,7 @@ public void Open(CCSPlayerController player) return; } - menu = PlayerMenus[player.SteamID] = UniversalAPI.CreateMenu(player); + menu = PlayerMenus[player.SteamID] = CSSUniversalMenuAPI.UniversalMenu.CreateMenu(player); menu.Title = Title; menu.PlayerCanClose = true;// ExitButton; diff --git a/src/UniversalMenu.Driver.ScreenMenuAPI/ScreenMenuAPIDriverPlugin.cs b/src/UniversalMenu.Driver.ScreenMenuAPI/ScreenMenuAPIDriverPlugin.cs index 3f51b4c..81378b5 100644 --- a/src/UniversalMenu.Driver.ScreenMenuAPI/ScreenMenuAPIDriverPlugin.cs +++ b/src/UniversalMenu.Driver.ScreenMenuAPI/ScreenMenuAPIDriverPlugin.cs @@ -13,7 +13,7 @@ namespace UniversalMenu.ScreenMenuAPIAdapter; [MinimumApiVersion(314)] public class ScreenMenuAPIDriverPlugin : BasePlugin { - public override string ModuleName => "UniversalMenu.Driver.ScreenMenuAPI"; + public override string ModuleName => "UniversalMenu.DefaultDriver.ScreenMenuAPI"; public override string ModuleDescription => "Implement CSSUniversalMenuAPI via ScreenMenuAPI"; public override string ModuleVersion => Verlite.Version.Full; @@ -24,16 +24,14 @@ public override void Load(bool hotReload) { Cts = new CancellationTokenSource(); - Capabilities.RegisterPluginCapability(IMenuAPI.PluginCapability, () => - { - DriverInstance ??= new ScreenMenuApiDriver(this); - return DriverInstance; - }); + DriverInstance = new ScreenMenuApiDriver(this); + CSSUniversalMenuAPI.UniversalMenu.RegisterDriver("ScreenMenuAPI", DriverInstance); } public override void Unload(bool hotReload) { Cts.Cancel(); + CSSUniversalMenuAPI.UniversalMenu.UnregisterDriver("ScreenMenuAPI"); } [ConsoleCommand("css_0"), ConsoleCommand("css_1"), ConsoleCommand("css_2"), ConsoleCommand("css_3"), ConsoleCommand("css_4")]