Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CSSUniversalMenuAPI.sln
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
global.json = global.json
package.sh = package.sh
README.md = README.md
EndProjectSection
EndProject
Expand All @@ -41,6 +42,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub Actions", "GitHub Ac
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalMenu.Compat.CSSharp", "src\UniversalMenu.Compat.CSSharp\UniversalMenu.Compat.CSSharp.csproj", "{EF2866D7-C411-42ED-B5E0-DCE79CCFCA09}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalMenu.Driver.MenuManagerApi", "src\UniversalMenu.Driver.MenuManagerApi\UniversalMenu.Driver.MenuManagerApi.csproj", "{FB832721-DCE2-4F62-A441-6C3E21A05317}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -75,6 +78,10 @@ Global
{EF2866D7-C411-42ED-B5E0-DCE79CCFCA09}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF2866D7-C411-42ED-B5E0-DCE79CCFCA09}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF2866D7-C411-42ED-B5E0-DCE79CCFCA09}.Release|Any CPU.Build.0 = Release|Any CPU
{FB832721-DCE2-4F62-A441-6C3E21A05317}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FB832721-DCE2-4F62-A441-6C3E21A05317}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FB832721-DCE2-4F62-A441-6C3E21A05317}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FB832721-DCE2-4F62-A441-6C3E21A05317}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,19 @@ classDiagram
UniversalMenu.Compat.ScreenMenuAPI <-- PluginUsingSomeScreenMenu
CSSUniversalMenuAPI <-- PluginUsingUniversalAPI
```

<!--
Potentially interested parties in working on this project:

exkludera Custom Menu
rasco Menu library
Intersting WASDMenuAPI
xWidovV Admin menu
Constummer Simple Guns Menu
daffyy Simple Admin
verneri Player votes
schwarper CS2MenuManager
ln(x) CS2 RTV/Extend/MapChooser
T3Marius ScreenMenusAPI
Mesharsky VIP manager
-->
101 changes: 52 additions & 49 deletions package.sh
Original file line number Diff line number Diff line change
@@ -1,52 +1,55 @@
#!/bin/bash
set -euf -o pipefail

# build CSSUniversalMenuAPI.zip
dst="./artifacts/CSSUniversalMenuAPI"
dst_shared="$dst/addons/counterstrikesharp/shared"
dst_plugins="$dst/addons/counterstrikesharp/plugins"

# package CSSUniversalMenuAPI
mkdir -p "$dst_shared/CSSUniversalMenuAPI"
src="./src/CSSUniversalMenuAPI/bin/Release/net8.0/publish"
cp -r "$src/." "$dst_shared/CSSUniversalMenuAPI/"

# package UniversalMenu.Compat.MenuManagerApi
mkdir -p "$dst_plugins/UniversalMenu.Compat.MenuManagerApi"
src="./src/UniversalMenu.Compat.MenuManagerApi/bin/Release/net8.0/publish"
cp -r "$src/." "$dst_plugins/UniversalMenu.Compat.MenuManagerApi/"

# package UniversalMenu.Compat.CSSharp
mkdir -p "$dst_plugins/UniversalMenu.Compat.CSSharp"
src="./src/UniversalMenu.Compat.CSSharp/bin/Release/net8.0/publish"
cp -r "$src/." "$dst_plugins/UniversalMenu.Compat.CSSharp/"
# shared part: allows modified methods to load the 0Harmony.dll dependency
mkdir -p "$dst_shared/0Harmony"
mv "$dst_plugins/UniversalMenu.Compat.CSSharp/0Harmony.dll" "$dst_shared/0Harmony/"

# package UniversalMenu.Compat.ScreenMenuAPI # this isn't implemented yet
#mkdir -p "$dst_plugins/UniversalMenu.Compat.ScreenMenuAPI"
#src="./src/UniversalMenu.Compat.ScreenMenuAPI/bin/Release/net8.0/publish"
#cp -r "$src/." "$dst_shared/UniversalMenu.Compat.ScreenMenuAPI/"

# zip CSSUniversalMenuAPI.zip
pushd "$dst"
7z a ../CSSUniversalMenuAPI.zip ./
popd
rm -rf "$dst"

# build UniversalMenu.Driver.ScreenMenuAPI.zip
dst="./artifacts/UniversalMenu.Driver.ScreenMenuAPI"
dst_shared="$dst/addons/counterstrikesharp/shared"
dst_plugins="$dst/addons/counterstrikesharp/plugins"

# package UniversalMenu.Driver.ScreenMenuAPI
mkdir -p "$dst_plugins/UniversalMenu.Driver.ScreenMenuAPI"
src="./src/UniversalMenu.Driver.ScreenMenuAPI/bin/Release/net8.0/publish"
cp -r "$src/." "$dst_plugins/UniversalMenu.Driver.ScreenMenuAPI/"

# zip UniversalMenu.Driver.ScreenMenuAPI.zip
pushd "$dst"
7z a ../UniversalMenu.Driver.ScreenMenuAPI.zip ./
popd
rm -rf "$dst"
zip_name=""
dst=""
dst_css=""

setup_zip() {
zip_name="$1"
dst="./artifacts/$zip_name"
dst_css="$dst/addons/counterstrikesharp"
}

copy_dir() {
mkdir -p "$dst_css/$2/"
cp -r "$1/." "$dst_css/$2/"
}

move_file() {
mkdir -p "$dst_css/$2/"
mv "$dst_css/$1" "$dst_css/$2/"
}

commit_zip() {
pushd "$dst"
7z a "../$zip_name.zip" ./
popd
rm -rf "$dst"
}

setup_zip CSSUniversalMenuAPI
copy_dir src/CSSUniversalMenuAPI/bin/Release/net8.0/publish shared/CSSUniversalMenuAPI
commit_zip

setup_zip UniversalMenu.Compat.CSSharp
copy_dir src/UniversalMenu.Compat.CSSharp/bin/Release/net8.0/publish plugins/UniversalMenu.Compat.CSSharp
# we move this into a shared location so that injected code can find the dll
move_file plugins/UniversalMenu.Compat.CSSharp/0Harmony.dll shared/0Harmony
commit_zip

setup_zip UniversalMenu.Compat.MenuManagerApi
copy_dir src/UniversalMenu.Compat.MenuManagerApi/bin/Release/net8.0/publish plugins/UniversalMenu.Compat.MenuManagerApi
commit_zip

#setup_zip UniversalMenu.Compat.ScreenMenuAPI
#copy_dir src/UniversalMenu.Compat.ScreenMenuAPI/bin/Release/net8.0/publish plugins/UniversalMenu.Compat.ScreenMenuAPI
#commit_zip

setup_zip UniversalMenu.Driver.ScreenMenuAPI
copy_dir src/UniversalMenu.Driver.ScreenMenuAPI/bin/Release/net8.0/publish shared/UniversalMenu.Driver.ScreenMenuAPI
commit_zip

setup_zip UniversalMenu.Driver.MenuManagerApi
copy_dir src/UniversalMenu.Driver.MenuManagerApi/bin/Release/net8.0/publish shared/UniversalMenu.Driver.MenuManagerApi
commit_zip
154 changes: 154 additions & 0 deletions src/UniversalMenu.Driver.MenuManagerApi/MenuManagerApiDriver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using System;
using System.Threading;
using System.Collections.Generic;

using CounterStrikeSharp.API.Core;

using CSSUniversalMenuAPI;
using CSSUniversalMenuAPI.Extensions;

using IMenuManagerApi = MenuManager.IMenuApi;
using IMenuManagerMenu = CounterStrikeSharp.API.Modules.Menu.IMenu;
using IMenu = CSSUniversalMenuAPI.IMenu;

namespace UniversalMenu.Driver.MenuManagerApi;

internal class PlayerMenuState
{
public Menu? ActiveMenu { get; set; }
}

public sealed class MenuManagerApiDriver : IMenuAPI
{
internal MenuManagerApiDriverPlugin Plugin { get; }
internal IMenuManagerApi? MenuManagerApi { get; set; }

public MenuManagerApiDriver(MenuManagerApiDriverPlugin plugin)
{
Plugin = plugin;
}

private Dictionary<ulong, PlayerMenuState> MenuStates = new();
internal PlayerMenuState GetMenuState(CCSPlayerController player)
{
if (!MenuStates.TryGetValue(player.SteamID, out var menuState))
MenuStates.Add(player.SteamID, menuState = new());
return menuState;
}
internal void PlayerDisconnected(ulong steamId)
{
MenuStates.Remove(steamId);
}

IMenu IMenuAPI.CreateMenu(CCSPlayerController player, CancellationToken ct)
{
return new Menu()
{
MenuAPI = this,
Player = player,
Parent = null,
};
}

IMenu IMenuAPI.CreateMenu(IMenu parent, CancellationToken ct)
{
if (parent is not Menu parentMenu)
throw new ArgumentException("Menu given belongs to another menu implementation", nameof(parent));

return new Menu()
{
MenuAPI = this,
Player = parent.Player,
Parent = parentMenu,
};
}

bool IMenuAPI.IsExtensionSupported(Type extension)
{
if (extension == typeof(INavigateBackMenuExtension))
return true;
return false;
}

bool IMenuAPI.IsMenuOpen(CCSPlayerController player)
{
return MenuManagerApi?.HasOpenedMenu(player) ?? false;
}
}

internal class Menu : IMenu, INavigateBackMenuExtension
{
public required MenuManagerApiDriver MenuAPI { get; set; }

// IMenu
public required Menu? Parent { get; init; }
IMenu? IMenu.Parent => Parent;
public required CCSPlayerController Player { get; init; }
public bool PlayerCanClose { get; set; } = true;
public bool IsActive { get; private set; }
public string Title { get; set; } = string.Empty;

// ScreenMenuAPI
internal IMenuManagerMenu? TheMenu { get; set; }
private List<MenuItem> MenuItems { get; } = new();
public Action<IMenu>? NavigateBack { get; set; }

void IMenu.Close()
{
if (!IsActive)
return;
IsActive = false;

var state = MenuAPI.GetMenuState(Player);
if (this == state.ActiveMenu)
{
MenuAPI.MenuManagerApi.CloseMenu(Player);

Check warning on line 105 in src/UniversalMenu.Driver.MenuManagerApi/MenuManagerApiDriver.cs

View workflow job for this annotation

GitHub Actions / Continuous integration

Dereference of a possibly null reference.
state.ActiveMenu = null;
}
}

IMenuItem IMenu.CreateItem()
{
var ret = new MenuItem() { Menu = this };
MenuItems.Add(ret);
return ret;
}

void IMenu.Display()
{
if (MenuAPI.MenuManagerApi is null)
throw new Exception("MenuManagerApi not found");

IsActive = true;
if (TheMenu is not null)
{
TheMenu.Open(Player);
return;
}

Action<CCSPlayerController>? navBack = null;
if (NavigateBack is not null)
navBack = (player) => NavigateBack(this);

TheMenu = MenuAPI.MenuManagerApi.GetMenu(Title, back_action: navBack!);

foreach (var item in MenuItems)
TheMenu.AddMenuOption(item.Title, (player, option) => item.RaiseSelected(), !item.Enabled);

TheMenu.Open(Player);
}
}

internal class MenuItem : IMenuItem
{
public required IMenu Menu { get; init; }
public string Title { get; set; } = string.Empty;
public bool Enabled { get; set; } = true;
public object? Context { get; set; }

public event ItemSelectedAction? Selected;
internal void RaiseSelected()
{
Selected?.Invoke(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Threading;

using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Core.Capabilities;

using IMenuManagerApi = MenuManager.IMenuApi;

namespace UniversalMenu.Driver.MenuManagerApi;

[MinimumApiVersion(314)]
public class MenuManagerApiDriverPlugin : BasePlugin
{
public override string ModuleName => "UniversalMenu.DefaultDriver.MenuManagerApi";
public override string ModuleDescription => "Implement CSSUniversalMenuAPI via MenuManagerApi";
public override string ModuleVersion => Verlite.Version.Full;

internal CancellationTokenSource Cts { get; set; } = null!;
private MenuManagerApiDriver? DriverInstance { get; set; }
private static readonly PluginCapability<IMenuManagerApi> MenuCapability = new("menu:nfcore");

public override void Load(bool hotReload)
{
Cts = new CancellationTokenSource();
DriverInstance = new MenuManagerApiDriver(this);
CSSUniversalMenuAPI.UniversalMenu.RegisterDriver("MenuManagerApi", DriverInstance);
}

public override void Unload(bool hotReload)
{
Cts.Cancel();
CSSUniversalMenuAPI.UniversalMenu.UnregisterDriver("MenuManagerApi");
}

public override void OnAllPluginsLoaded(bool hotReload)
{
DriverInstance!.MenuManagerApi = MenuCapability.Get();
}

[GameEventHandler(HookMode.Pre)]
public HookResult OnPlayerDisconnect(EventPlayerDisconnect e, GameEventInfo info)
{
if (e.Userid is null)
return HookResult.Continue;

DriverInstance?.PlayerDisconnected(e.Userid.SteamID);
return HookResult.Continue;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<RootNamespace>UniversalMenu.Driver.MenuManagerApi</RootNamespace>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\CSSUniversalMenuAPI\CSSUniversalMenuAPI.csproj">
<Private>False</Private>
<CopyLocalSatelliteAssemblies>False</CopyLocalSatelliteAssemblies>
</ProjectReference>

<Reference Include="MenuManagerApi">
<Private>false</Private>
<HintPath>..\..\thirdparty\MenuManagerApi\MenuManagerApi.dll</HintPath>
</Reference>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ public override void Unload(bool hotReload)
CSSUniversalMenuAPI.UniversalMenu.UnregisterDriver("ScreenMenuAPI");
}

[GameEventHandler(HookMode.Pre)]
public HookResult OnPlayerDisconnected(EventPlayerDisconnect e, GameEventInfo info)
{
if (e.Userid is null)
return HookResult.Continue;

DriverInstance?.PlayerDisconnected(e.Userid.SteamID);
return HookResult.Continue;
}

[ConsoleCommand("css_0"), ConsoleCommand("css_1"), ConsoleCommand("css_2"), ConsoleCommand("css_3"), ConsoleCommand("css_4")]
[ConsoleCommand("css_5"), ConsoleCommand("css_6"), ConsoleCommand("css_7"), ConsoleCommand("css_8"), ConsoleCommand("css_9")]
[ConsoleCommand("css_screenmenu_bound_buttons")]
Expand Down