Overhaul to use public APIs

This commit is contained in:
MSWS
2024-12-23 00:18:12 -08:00
parent a190153cf3
commit dfd56e754b
15 changed files with 437 additions and 16 deletions

View File

@@ -62,6 +62,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Rainbow", "mod\Ja
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Draw", "mod\Jailbreak.Draw\Jailbreak.Draw.csproj", "{978DB4AA-A4C5-4B3A-9EB6-0371DDC854C1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gangs.WardenIconPerk", "mod\Gangs.WardenIconPerk\Gangs.WardenIconPerk.csproj", "{A8947625-840F-4A87-96F3-8E8D3C6F3331}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -172,6 +174,10 @@ Global
{978DB4AA-A4C5-4B3A-9EB6-0371DDC854C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{978DB4AA-A4C5-4B3A-9EB6-0371DDC854C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{978DB4AA-A4C5-4B3A-9EB6-0371DDC854C1}.Release|Any CPU.Build.0 = Release|Any CPU
{A8947625-840F-4A87-96F3-8E8D3C6F3331}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8947625-840F-4A87-96F3-8E8D3C6F3331}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8947625-840F-4A87-96F3-8E8D3C6F3331}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8947625-840F-4A87-96F3-8E8D3C6F3331}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9135CCC9-66C5-4A9C-AE3C-91475B5F0437} = {177DA48D-8306-4102-918D-992569878581}
@@ -201,5 +207,6 @@ Global
{D1CEDF10-A87E-4C81-85AE-D491739CA607} = {069A4F54-AE2A-4FDF-A5A8-F550B254C2A9}
{FC68F411-FE9D-4058-B66F-796E17746E67} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7}
{978DB4AA-A4C5-4B3A-9EB6-0371DDC854C1} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7}
{A8947625-840F-4A87-96F3-8E8D3C6F3331} = {069A4F54-AE2A-4FDF-A5A8-F550B254C2A9}
EndGlobalSection
EndGlobal

View File

@@ -11,6 +11,7 @@
<ProjectReference Include="..\Gangs.CellsPerk\Gangs.CellsPerk.csproj"/>
<ProjectReference Include="..\Gangs.LastRequestColorPerk\Gangs.LastRequestColorPerk.csproj"/>
<ProjectReference Include="..\Gangs.SpecialDayColorPerk\Gangs.SpecialDayColorPerk.csproj"/>
<ProjectReference Include="..\Gangs.WardenIconPerk\Gangs.WardenIconPerk.csproj" />
</ItemGroup>
<ItemGroup>

View File

@@ -3,6 +3,7 @@ using Gangs.BombIconPerk;
using Gangs.CellsPerk;
using Gangs.LastRequestColorPerk;
using Gangs.SpecialDayColorPerk;
using Gangs.WardenIconPerk;
using Jailbreak.Public;
using Jailbreak.Public.Behaviors;
using Jailbreak.Public.Extensions;
@@ -25,5 +26,6 @@ public class GangsInit : IPluginBehavior {
_ = new SDColorBootstrap(services);
_ = new CellsPerkBootstrap(services);
_ = new LRColorBootstrap(services);
_ = new WardenIconBootstrap(services);
}
}

View File

@@ -17,6 +17,8 @@ public enum LRColor {
}
public static class LRColorExtensions {
private static readonly Random rng = new();
public static int GetCost(this LRColor color) {
if (color == LRColor.RAINBOW) return 10 * 8000;
return (int)Math.Round(color.GetColor().GetColorMultiplier() * 8000);
@@ -37,7 +39,7 @@ public static class LRColorExtensions {
}
public static Color? PickRandomColor(this LRColor color) {
var n = new Random().Next(Enum.GetValues<LRColor>().Length);
var n = rng.Next(Enum.GetValues<LRColor>().Length);
var available = Enum.GetValues<LRColor>()
.Where(c => color.HasFlag(c) && c.GetColor() != null)
.ToList();

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Reference Include="GangsAPI">
<HintPath>..\..\public\Jailbreak.Public\Mixin\GangsAPI.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="8.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Gangs.BaseImpl\Gangs.BaseImpl.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,69 @@
namespace Gangs.WardenIconPerk;
[Flags]
public enum WardenIcon {
DEFAULT = 1 << 0,
LOWER_DEFAULT = 1 << 1,
KATA_SMILE = 1 << 2,
DOWN_ARROW = 1 << 3,
STAR = 1 << 4,
KING = 1 << 5,
QUEEN = 1 << 6,
ROOK = 1 << 7,
BISHOP = 1 << 8,
KNIGHT = 1 << 9,
PAWN = 1 << 10,
RANDOM = 1 << 11
}
public static class WardenIconExtensions {
private static readonly Random rng = new();
public static string GetIcon(this WardenIcon icon) {
return icon switch {
WardenIcon.KING => "♔",
WardenIcon.QUEEN => "♕",
WardenIcon.ROOK => "♖",
WardenIcon.BISHOP => "♗",
WardenIcon.KNIGHT => "♘",
WardenIcon.PAWN => "♙",
WardenIcon.DEFAULT => "W",
WardenIcon.LOWER_DEFAULT => "w",
WardenIcon.KATA_SMILE => "ツ",
WardenIcon.DOWN_ARROW => "↓",
WardenIcon.STAR => "★",
WardenIcon.RANDOM => "?",
_ => "W"
};
}
public static int GetCost(this WardenIcon icon) {
return icon switch {
WardenIcon.DEFAULT => 0,
WardenIcon.LOWER_DEFAULT => 1500,
WardenIcon.KATA_SMILE => 4000,
WardenIcon.DOWN_ARROW => 3500,
WardenIcon.STAR => 6500,
WardenIcon.KING => 7000,
WardenIcon.QUEEN => 6500,
WardenIcon.ROOK => 5000,
WardenIcon.BISHOP => 2500,
WardenIcon.KNIGHT => 3000,
WardenIcon.PAWN => 4000,
WardenIcon.RANDOM => 10000,
_ => 5000
};
}
public static string PickRandom(this WardenIcon icon) {
var n = rng.Next(Enum.GetValues<WardenIcon>().Length);
var available = Enum.GetValues<WardenIcon>()
.Where(c => icon.HasFlag(c) && c != WardenIcon.RANDOM)
.ToList();
// Gang bought the random perk, but no colors, sillies!
return available.Count == 0 ?
WardenIcon.DEFAULT.GetIcon() :
available[n % available.Count].GetIcon();
}
}

View File

@@ -0,0 +1,12 @@
using GangsAPI.Services;
using Microsoft.Extensions.DependencyInjection;
namespace Gangs.WardenIconPerk;
public class WardenIconBootstrap {
public WardenIconBootstrap(IServiceProvider collection) {
new WardenIconCommand(collection).Start();
collection.GetRequiredService<IPerkManager>()
.Perks.Add(new WardenIconPerk(collection));
}
}

View File

@@ -0,0 +1,126 @@
using CounterStrikeSharp.API.Modules.Utils;
using GangsAPI;
using GangsAPI.Data;
using GangsAPI.Data.Command;
using GangsAPI.Exceptions;
using GangsAPI.Perks;
using GangsAPI.Permissions;
using GangsAPI.Services;
using GangsAPI.Services.Commands;
using GangsAPI.Services.Gang;
using GangsAPI.Services.Menu;
using GangsAPI.Services.Player;
using Jailbreak.Public.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
namespace Gangs.WardenIconPerk;
public class WardenIconCommand(IServiceProvider provider) : ICommand {
private readonly ICommandManager commands =
provider.GetRequiredService<ICommandManager>();
private readonly IEcoManager eco = provider.GetRequiredService<IEcoManager>();
private readonly IGangChatPerk? gangChat =
provider.GetService<IGangChatPerk>();
private readonly IGangManager gangs =
provider.GetRequiredService<IGangManager>();
private readonly IGangStatManager gangStats =
provider.GetRequiredService<IGangStatManager>();
private readonly IStringLocalizer localizer =
provider.GetRequiredService<IStringLocalizer>();
private readonly IMenuManager menus =
provider.GetRequiredService<IMenuManager>();
private readonly IPlayerManager players =
provider.GetRequiredService<IPlayerManager>();
private readonly IPlayerStatManager playerStats =
provider.GetRequiredService<IPlayerStatManager>();
private readonly IRankManager ranks =
provider.GetRequiredService<IRankManager>();
public string Name => "css_wardenicon";
public string[] Aliases => [Name, "css_warden_icon"];
public string[] Usage => ["<icon>"];
public void Start() { commands.RegisterCommand(this); }
public async Task<CommandResult> Execute(PlayerWrapper? executor,
CommandInfoWrapper info) {
if (executor == null) return CommandResult.PLAYER_ONLY;
var player = await players.GetPlayer(executor.Steam)
?? throw new PlayerNotFoundException(executor.Steam);
if (player.GangId == null) {
info.ReplySync(localizer.Get(MSG.NOT_IN_GANG));
return CommandResult.SUCCESS;
}
var gang = await gangs.GetGang(player.GangId.Value)
?? throw new GangNotFoundException(player.GangId.Value);
var (success, data) = await gangStats.GetForGang<WardenIcon>(
player.GangId.Value, WardenIconPerk.STAT_ID);
if (!success) data = WardenIcon.DEFAULT;
var (_, equipped) = await playerStats.GetForPlayer<WardenIcon>(
player.Steam, WardenIconPerk.STAT_ID);
if (info.Args.Length == 1) {
var menu = new WardenIconMenu(provider, data, equipped);
await menus.OpenMenu(executor, menu);
return CommandResult.SUCCESS;
}
WardenIcon icon;
var query = string.Join('_', info.Args.Skip(1)).ToUpper();
if (!int.TryParse(info[1], out var iconInt) || iconInt < 0) {
if (!Enum.TryParse(query, out icon)) {
info.ReplySync(localizer.Get(MSG.COMMAND_INVALID_PARAM, info[1],
"an icon"));
return CommandResult.SUCCESS;
}
} else
icon = (WardenIcon)iconInt;
if (!data.HasFlag(icon)) {
var (canPurchase, minRank) = await ranks.CheckRank(player,
Perm.PURCHASE_PERKS);
if (!canPurchase) {
info.ReplySync(localizer.Get(MSG.GENERIC_NOPERM_RANK, minRank.Name));
return CommandResult.SUCCESS;
}
var cost = icon.GetCost();
if (await eco.TryPurchase(executor, cost,
item: "Warden Icon: " + icon.ToString().ToTitleCase()) < 0)
return CommandResult.SUCCESS;
data |= icon;
await gangStats.SetForGang(gang, WardenIconPerk.STAT_ID, data);
if (gangChat != null)
await gangChat.SendGangChat(player, gang,
localizer.Get(MSG.PERK_PURCHASED,
$"Warden Icon ({icon.ToString().ToTitleCase()})"));
return CommandResult.SUCCESS;
}
await playerStats.SetForPlayer(executor, WardenIconPerk.STAT_ID, icon);
executor.PrintToChat(
$"{localizer.Get(MSG.PREFIX)}Set your warden icon to {icon.GetIcon()} ({icon.ToString().ToTitleCase()}){ChatColors.Grey}.");
return CommandResult.SUCCESS;
}
}

View File

@@ -0,0 +1,62 @@
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Utils;
using GangsAPI.Data;
using GangsAPI.Menu;
using GangsAPI.Services.Commands;
using Jailbreak.Public.Extensions;
using Microsoft.Extensions.DependencyInjection;
namespace Gangs.WardenIconPerk;
public class WardenIconMenu(IServiceProvider provider, WardenIcon data,
WardenIcon equipped)
: AbstractPagedMenu<WardenIcon>(provider, NativeSenders.Chat) {
private readonly ICommandManager commands =
provider.GetRequiredService<ICommandManager>();
// Method to sort smoke colors
private int CompareSmokeColors(WardenIcon a, WardenIcon b) {
if (a == equipped) return -1;
if (b == equipped) return 1;
// If icon is unlocked, it should be next
// If both are unlocked, sort by cost (highest first)
if (data.HasFlag(a)) {
if (data.HasFlag(b)) return a.GetCost().CompareTo(b.GetCost());
return -1;
}
// If both are locked, sort by cost (lowest first)
return data.HasFlag(b) ? 1 : a.GetCost().CompareTo(b.GetCost());
}
override protected Task<List<WardenIcon>> GetItems(PlayerWrapper player) {
var list = Enum.GetValues<WardenIcon>().ToList();
list.Sort(CompareSmokeColors);
list.Insert(0, 0);
return Task.FromResult(list);
}
override protected Task HandleItemSelection(PlayerWrapper player,
List<WardenIcon> items, int selectedIndex) {
commands.ProcessCommand(player, CommandCallingContext.Chat,
"css_wardenicon", items[selectedIndex].ToString());
Menus.CloseMenu(player);
return Task.CompletedTask;
}
override protected Task<string> FormatItem(PlayerWrapper player, int index,
WardenIcon item) {
var name = item.ToString().ToTitleCase();
if (item == 0)
return Task.FromResult(
$" {ChatColors.DarkBlue}Gang Perks: {ChatColors.LightBlue}Warden Icon\n{new WardenIconPerk(Provider).Description}");
if (item == equipped)
return Task.FromResult(
$"{index} {ChatColors.LightBlue}{item.GetIcon()} {ChatColors.White}{item.ToString().ToTitleCase()}");
if (data.HasFlag(item))
return Task.FromResult(
$"{index}. {ChatColors.DarkBlue}{item.GetIcon()} {ChatColors.Grey}{item.ToString().ToTitleCase()} {ChatColors.Green}({ChatColors.Grey}Unlocked{ChatColors.Green})");
return Task.FromResult(
$"{index}. {ChatColors.LightRed}{item.GetIcon()} {ChatColors.Grey}{name} {ChatColors.DarkRed}({ChatColors.LightRed}{item.GetCost()}{ChatColors.DarkRed})");
}
}

View File

@@ -0,0 +1,47 @@
using System.Diagnostics;
using CounterStrikeSharp.API.Modules.Menu;
using Gangs.BaseImpl;
using GangsAPI.Data.Gang;
using GangsAPI.Services.Gang;
using GangsAPI.Services.Player;
using Microsoft.Extensions.DependencyInjection;
using IMenu = GangsAPI.Services.Menu.IMenu;
namespace Gangs.WardenIconPerk;
public class WardenIconPerk(IServiceProvider provider)
: BasePerk<WardenIcon>(provider) {
public const string STAT_ID = "css_wardenicon";
private readonly IGangStatManager gangStats =
provider.GetRequiredService<IGangStatManager>();
private readonly IPlayerStatManager playerStats =
provider.GetRequiredService<IPlayerStatManager>();
public override string StatId => STAT_ID;
public override string Name => "Warden Icon";
public override string? Description
=> "Change the icon that appears above your head as warden";
public override WardenIcon Value { get; set; } = WardenIcon.DEFAULT;
public override Task<int?> GetCost(IGangPlayer player) {
return Task.FromResult<int?>(null);
}
public override Task OnPurchase(IGangPlayer player) {
return Task.CompletedTask;
}
public override async Task<IMenu?> GetMenu(IGangPlayer player) {
Debug.Assert(player.GangId != null, "player.GangId != null");
var (success, data) =
await gangStats.GetForGang<WardenIcon>(player.GangId.Value, STAT_ID);
if (!success) data = WardenIcon.DEFAULT;
var (_, equipped) =
await playerStats.GetForPlayer<WardenIcon>(player.Steam, STAT_ID);
return new WardenIconMenu(Provider, data, equipped);
}
}

View File

@@ -99,6 +99,8 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
private readonly ISet<CCSPlayerController> bluePrisoners =
new HashSet<CCSPlayerController>();
private readonly IWardenIcon? iconer = provider.GetService<IWardenIcon>();
private bool firstWarden;
private string? oldTag;
private char? oldTagColor;
@@ -107,8 +109,6 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
private PreWardenStats? preWardenStats;
private Timer? unblueTimer, openCellsTimer;
private IEnumerable<CPointWorldText>? wardenHat;
public void Start(BasePlugin basePlugin) {
parent = basePlugin;
if (API.Gangs != null) {
@@ -180,10 +180,7 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
});
}
var spawner = provider.GetService<ITextSpawner>();
wardenHat =
spawner?.CreateTextHat(new TextSetting { msg = "W", color = Color.Blue },
Warden);
iconer?.AssignWardenIcon(Warden);
foreach (var player in Utilities.GetPlayers())
player.ExecuteClientCommand($"play sounds/{CV_WARDEN_SOUND_NEW.Value}");
@@ -265,15 +262,8 @@ public class WardenBehavior(ILogger<WardenBehavior> logger,
Task.Run(async () => await updateWardenDeathStats(wrapper));
}
}
}
if (wardenHat != null) {
foreach (var ent in wardenHat) {
if (!ent.IsValid) continue;
ent.Remove();
}
wardenHat = null;
iconer?.RemoveWardenIcon(Warden);
}
var wardenPawn = Warden!.PlayerPawn.Value;

View File

@@ -0,0 +1,68 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using Gangs.WardenIconPerk;
using GangsAPI;
using GangsAPI.Data;
using GangsAPI.Services.Gang;
using GangsAPI.Services.Player;
using Jailbreak.Public;
using Jailbreak.Public.Mod.Draw;
using Jailbreak.Public.Mod.Warden;
using Microsoft.Extensions.DependencyInjection;
namespace Jailbreak.Warden.Global;
public class WardenIconBehavior(ITextSpawner spawner)
: IPluginBehavior, IWardenIcon {
private readonly IEnumerable<CPointWorldText>?[] wardenIcons =
new IEnumerable<CPointWorldText>?[65];
public void AssignWardenIcon(CCSPlayerController warden) {
var wrapper = new PlayerWrapper(warden);
Task.Run(async () => {
var icon = await getIcon(wrapper);
await Server.NextFrameAsync(() => {
var hat = spawner.CreateTextHat(icon, warden);
wardenIcons[warden.Slot] = hat;
});
});
}
public void RemoveWardenIcon(CCSPlayerController warden) {
var hat = wardenIcons[warden.Slot];
if (hat == null) return;
foreach (var text in hat) {
if (!text.IsValid) continue;
text.Remove();
}
wardenIcons[warden.Slot] = null;
}
private async Task<string> getIcon(PlayerWrapper player) {
var playerStats = API.Gangs?.Services.GetService<IPlayerStatManager>();
var gangStats = API.Gangs?.Services.GetService<IGangStatManager>();
var players = API.Gangs?.Services.GetService<IPlayerManager>();
if (playerStats == null) return WardenIcon.DEFAULT.GetIcon();
var (success, icon) =
await playerStats.GetForPlayer<WardenIcon>(player,
WardenIconPerk.STAT_ID);
if (!success) icon = WardenIcon.DEFAULT;
if (icon == WardenIcon.RANDOM && gangStats != null && players != null) {
var gangPlayer = await players.GetPlayer(player.Steam);
if (gangPlayer?.GangId == null) return WardenIcon.DEFAULT.GetIcon();
var (_, available) =
await gangStats.GetForGang<WardenIcon>(gangPlayer.GangId.Value,
WardenIconPerk.STAT_ID);
return available.PickRandom();
}
return icon.GetIcon();
}
}

View File

@@ -10,6 +10,7 @@
<ProjectReference Include="..\..\public\Jailbreak.Formatting\Jailbreak.Formatting.csproj"/>
<ProjectReference Include="..\..\public\Jailbreak.Public\Jailbreak.Public.csproj"/>
<ProjectReference Include="..\Gangs.CellsPerk\Gangs.CellsPerk.csproj"/>
<ProjectReference Include="..\Gangs.WardenIconPerk\Gangs.WardenIconPerk.csproj" />
<ProjectReference Include="..\Jailbreak.Zones\Jailbreak.Zones.csproj"/>
</ItemGroup>

View File

@@ -1,4 +1,5 @@
using Jailbreak.Public.Extensions;
using GangsAPI.Extensions;
using Jailbreak.Public.Extensions;
using Jailbreak.Public.Mod.Warden;
using Jailbreak.Warden.Commands;
using Jailbreak.Warden.Global;
@@ -20,6 +21,7 @@ public static class WardenServiceExtension {
.AddPluginBehavior<ISpecialTreatmentService, SpecialTreatmentBehavior>();
serviceCollection
.AddPluginBehavior<IWardenOpenCommand, WardenOpenCommandsBehavior>();
serviceCollection.AddPluginBehavior<IWardenIcon, WardenIconBehavior>();
serviceCollection.AddPluginBehavior<CountCommandsBehavior>();

View File

@@ -0,0 +1,8 @@
using CounterStrikeSharp.API.Core;
namespace Jailbreak.Public.Mod.Warden;
public interface IWardenIcon {
void AssignWardenIcon(CCSPlayerController warden);
void RemoveWardenIcon(CCSPlayerController warden);
}