From e2b1fc8d133a9c9250274e4f82f71dca703246b3 Mon Sep 17 00:00:00 2001 From: WhiteFang Date: Fri, 5 Aug 2022 20:34:15 +0200 Subject: [PATCH] Refactored the Command System so it makes use of the V-Rising AdminLevel enum --- ExperimentalMod/ExperimentalMod.csproj | 1 + PvPPunishment/Systems/PvPPunishmentSystem.cs | 7 ++- Shared/CommandSystem/CommandAttribute.cs | 24 ++++++-- Shared/CommandSystem/CommandExtensions.cs | 2 +- Shared/CommandSystem/CommandSystem.cs | 37 ++++++++---- Shared/ExtensionMethods.cs | 10 ++++ .../HighestGearScoreSystem.cs | 5 +- Shared/Utils.cs | 11 ++++ Shared/VModCharacter.cs | 57 ++++++++++++++----- Shared/VModStorage.cs | 4 +- 10 files changed, 118 insertions(+), 40 deletions(-) diff --git a/ExperimentalMod/ExperimentalMod.csproj b/ExperimentalMod/ExperimentalMod.csproj index 6226e62..613a083 100644 --- a/ExperimentalMod/ExperimentalMod.csproj +++ b/ExperimentalMod/ExperimentalMod.csproj @@ -22,6 +22,7 @@ + diff --git a/PvPPunishment/Systems/PvPPunishmentSystem.cs b/PvPPunishment/Systems/PvPPunishmentSystem.cs index 3a7bde5..8331299 100644 --- a/PvPPunishment/Systems/PvPPunishmentSystem.cs +++ b/PvPPunishment/Systems/PvPPunishmentSystem.cs @@ -6,6 +6,7 @@ using Unity.Entities; using VMods.Shared; using Wetstone.API; +using AdminLevel = VMods.Shared.CommandAttribute.AdminLevel; namespace VMods.PvPPunishment { @@ -221,7 +222,7 @@ private static void PruneOffenses() } } - [Command("ispunished", "ispunished []", "Tell you if the the given player (or yourself when no playername is given) currently has the PvP Punishment buff", true)] + [Command("ispunished", "ispunished []", "Tell you if the the given player (or yourself when no playername is given) currently has the PvP Punishment buff", AdminLevel.Admin)] private static void OnIsPunishedPlayerCommand(Command command) { var entityManager = VWorld.Server.EntityManager; @@ -241,7 +242,7 @@ private static void OnIsPunishedPlayerCommand(Command command) command.Use(); } - [Command("punish", "punish []", "Adds (or refreshes) the PvP Punishment buff for the given player (or yourself when no playername is given)", true)] + [Command("punish", "punish []", "Adds (or refreshes) the PvP Punishment buff for the given player (or yourself when no playername is given)", AdminLevel.Admin)] private static void OnPunishPlayerCommand(Command command) { var entityManager = VWorld.Server.EntityManager; @@ -255,7 +256,7 @@ private static void OnPunishPlayerCommand(Command command) command.Use(); } - [Command("unpunish", "unpunish []", "Removes the PvP Punishment buff for the given player (or yourself when no playername is given)", true)] + [Command("unpunish", "unpunish []", "Removes the PvP Punishment buff for the given player (or yourself when no playername is given)", AdminLevel.Admin)] private static void OnUnPunishPlayerCommand(Command command) { var entityManager = VWorld.Server.EntityManager; diff --git a/Shared/CommandSystem/CommandAttribute.cs b/Shared/CommandSystem/CommandAttribute.cs index 8689557..a8bf991 100644 --- a/Shared/CommandSystem/CommandAttribute.cs +++ b/Shared/CommandSystem/CommandAttribute.cs @@ -1,4 +1,5 @@ -using System; +using ProjectM; +using System; using System.Collections.Generic; using System.Linq; @@ -12,18 +13,31 @@ public class CommandAttribute : Attribute public IReadOnlyList Names { get; } public string Usage { get; } public string Description { get; } - public bool ReqAdmin { get; } + public AdminLevel ReqAdminLevel { get; } #endregion - #region Livecycle + #region Lifecycle - public CommandAttribute(string name, string usage = "", string description = "", bool reqAdmin = false) + public CommandAttribute(string name, string usage = "", string description = "", AdminLevel reqAdminLevel = AdminLevel.None) { Names = name.Split(',').Select(x => x.Trim()).ToList(); Usage = usage; Description = description; - ReqAdmin = reqAdmin; + ReqAdminLevel = reqAdminLevel; + } + + #endregion + + #region Nested + + /// Exact copy of + public enum AdminLevel + { + None = 0, + Moderator = 1, + Admin = 2, + SuperAdmin = 3 } #endregion diff --git a/Shared/CommandSystem/CommandExtensions.cs b/Shared/CommandSystem/CommandExtensions.cs index f514502..506cbf4 100644 --- a/Shared/CommandSystem/CommandExtensions.cs +++ b/Shared/CommandSystem/CommandExtensions.cs @@ -15,7 +15,7 @@ public static (string searchUsername, VModCharacter? vmodCharacter) FindVModChar if(argIdx >= 0 && command.Args.Length >= (argIdx + 1)) { - searchUsername = command.Args[0]; + searchUsername = command.Args[argIdx]; fromCharacter = VModCharacter.GetVModCharacter(searchUsername, entityManager); } else diff --git a/Shared/CommandSystem/CommandSystem.cs b/Shared/CommandSystem/CommandSystem.cs index 53f9adb..231cc69 100644 --- a/Shared/CommandSystem/CommandSystem.cs +++ b/Shared/CommandSystem/CommandSystem.cs @@ -1,10 +1,10 @@ -using ProjectM.Network; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Wetstone.API; using Wetstone.Hooks; +using static VMods.Shared.CommandAttribute; namespace VMods.Shared { @@ -21,7 +21,7 @@ public static class CommandSystem private static readonly Dictionary _lastUsedCommandTimes = new(); private static List<(MethodInfo method, CommandAttribute attribute)> _commandReflectionMethods; - private static readonly List<(Action method, CommandAttribute attribute)> _commandMethods = new(); + private static readonly List<(string id, Action method, CommandAttribute attribute)> _commandMethods = new(); #endregion @@ -47,9 +47,14 @@ public static void Deinitialize() _commandMethods.Clear(); } - public static void RegisterCommand(Action commandMethod, CommandAttribute commandAttribute) + public static void RegisterCommand(string uniqueId, Action commandMethod, CommandAttribute commandAttribute) { - _commandMethods.Add((commandMethod, commandAttribute)); + _commandMethods.Add((uniqueId, commandMethod, commandAttribute)); + } + + public static void UnregisterCommand(string uniqueId) + { + _commandMethods.RemoveAll(x => x.id == uniqueId); } public static void UnregisterCommand(Action commandMethod, CommandAttribute commandAttribute) @@ -126,9 +131,9 @@ private static void OnChatMessage(VChatEvent chatEvent) // Fire the command (so an event handler can actually handle/execute it) Command command = new(new VModCharacter(chatEvent.SenderUserEntity, chatEvent.SenderCharacterEntity), name, args); - foreach((var method, var attribute) in _commandMethods) + foreach((_, var method, var attribute) in _commandMethods) { - if(!attribute.Names.Contains(command.Name) || (attribute.ReqAdmin && !user.IsAdmin)) + if(!attribute.Names.Contains(command.Name) || !command.VModCharacter.AdminLevel.HasReqLevel(attribute.ReqAdminLevel)) { continue; } @@ -151,7 +156,7 @@ private static void OnChatMessage(VChatEvent chatEvent) { foreach((var method, var attribute) in _commandReflectionMethods) { - if(!attribute.Names.Contains(command.Name) || (attribute.ReqAdmin && !user.IsAdmin)) + if(!attribute.Names.Contains(command.Name) || !command.VModCharacter.AdminLevel.HasReqLevel(attribute.ReqAdminLevel)) { continue; } @@ -208,14 +213,22 @@ private static void OnHelpCommand(Command command) // Nested Method(s) void SendCommandInfo(CommandAttribute attribute) { - if(attribute.ReqAdmin && !vmodCharacter.IsAdmin) + if(!vmodCharacter.AdminLevel.HasReqLevel(attribute.ReqAdminLevel)) { return; } string message = $"{string.Join(", ", attribute.Names.Select(x => $"{commandPrefix}{x}"))}"; - if(attribute.ReqAdmin) + switch(attribute.ReqAdminLevel) { - message += " - [ADMIN]"; + case AdminLevel.Moderator: + message += " - [MOD]"; + break; + case AdminLevel.Admin: + message += " - [ADMIN]"; + break; + case AdminLevel.SuperAdmin: + message += " - [SUPER-ADMIN]"; + break; } message += $" - {attribute.Description}"; vmodCharacter.SendSystemMessage(message); @@ -239,7 +252,7 @@ void SendCommandInfo(CommandAttribute attribute) } // Check the found info - if(attribute == null || attribute.ReqAdmin && !vmodCharacter.IsAdmin) + if(attribute == null || !vmodCharacter.AdminLevel.HasReqLevel(attribute.ReqAdminLevel)) { return; } diff --git a/Shared/ExtensionMethods.cs b/Shared/ExtensionMethods.cs index a7f9f39..67f1c7a 100644 --- a/Shared/ExtensionMethods.cs +++ b/Shared/ExtensionMethods.cs @@ -24,5 +24,15 @@ public static string ToAgoString(this TimeSpan timeSpan) } return $"{timeSpan.Milliseconds}ms"; } + + public static bool HasReqLevel(this ProjectM.AdminLevel adminLevel, ProjectM.AdminLevel reqAdminLevel) => (int)adminLevel >= (int)reqAdminLevel; + + public static bool HasReqLevel(this ProjectM.AdminLevel adminLevel, CommandAttribute.AdminLevel reqAdminLevel) => (int)adminLevel >= (int)reqAdminLevel; + + public static bool HasReqLevel(this CommandAttribute.AdminLevel adminLevel, ProjectM.AdminLevel reqAdminLevel) => (int)adminLevel >= (int)reqAdminLevel; + + public static ProjectM.AdminLevel ToAdminLevel(this CommandAttribute.AdminLevel adminLevel) => (ProjectM.AdminLevel)(int)adminLevel; + + public static CommandAttribute.AdminLevel ToAdminLevel(this ProjectM.AdminLevel adminLevel) => (CommandAttribute.AdminLevel)(int)adminLevel; } } diff --git a/Shared/HighestGearScoreSystem/HighestGearScoreSystem.cs b/Shared/HighestGearScoreSystem/HighestGearScoreSystem.cs index a404849..28c7ba8 100644 --- a/Shared/HighestGearScoreSystem/HighestGearScoreSystem.cs +++ b/Shared/HighestGearScoreSystem/HighestGearScoreSystem.cs @@ -5,6 +5,7 @@ using System.Linq; using Unity.Entities; using Wetstone.API; +using AdminLevel = VMods.Shared.CommandAttribute.AdminLevel; namespace VMods.Shared { @@ -140,7 +141,7 @@ private static void OnVampireDowned(Entity killer, Entity victim) _gearScoreData.Remove(victumUser.PlatformId); } - [Command("highestgs,hgs,higs,highgs,highestgearscore", "highestgs []", "Tells you what the highest gear score is for the given player (or yourself when noplayername is given)", true)] + [Command("highestgs,hgs,higs,highgs,highestgearscore", "highestgs []", "Tells you what the highest gear score is for the given player (or yourself when noplayername is given)", AdminLevel.Admin)] private static void OnHighestGearScoreCommand(Command command) { var entityManager = VWorld.Server.EntityManager; @@ -161,7 +162,7 @@ private static void OnHighestGearScoreCommand(Command command) } } - [Command("clearhgs,resethgs,clearhighestgearscore,resethighestgearscore", "clearhgs []", "Removes the current Highest Gear Score record for the given player (or yourself when noplayername is given)", true)] + [Command("clearhgs,resethgs,clearhighestgearscore,resethighestgearscore", "clearhgs []", "Removes the current Highest Gear Score record for the given player (or yourself when noplayername is given)", AdminLevel.Admin)] private static void OnResetHighestGearScoreCommand(Command command) { var entityManager = VWorld.Server.EntityManager; diff --git a/Shared/Utils.cs b/Shared/Utils.cs index 75114d5..b1143b4 100644 --- a/Shared/Utils.cs +++ b/Shared/Utils.cs @@ -275,6 +275,17 @@ public static string GetCharacterName(ulong platformId, EntityManager? entityMan return null; } + public static AdminLevel GetAdminLevel(Entity userEntity, EntityManager? entityManager = null) + { + entityManager ??= CurrentWorld.EntityManager; + if(entityManager.Value.HasComponent(userEntity)) + { + var adminUser = entityManager.Value.GetComponentData(userEntity); + return adminUser.Level; + } + return AdminLevel.None; + } + public static void LogAllComponentTypes(Entity entity, EntityManager? entityManager = null) { if(entity == Entity.Null) diff --git a/Shared/VModCharacter.cs b/Shared/VModCharacter.cs index 2e4f36d..72c0a83 100644 --- a/Shared/VModCharacter.cs +++ b/Shared/VModCharacter.cs @@ -20,15 +20,26 @@ public readonly struct VModCharacter public bool IsAdmin => User.IsAdmin; + public AdminLevel AdminLevel { get; } + + public string CharacterName => User.CharacterName.ToString(); + #endregion #region Lifecycle - public VModCharacter(User user, PlayerCharacter character) => (User, Character, FromCharacter) = (user, character, FromCharacter = new FromCharacter() + public VModCharacter(User user, PlayerCharacter character, EntityManager? entityManager = null) { - User = character.UserEntity._Entity, - Character = user.LocalCharacter._Entity, - }); + entityManager ??= Utils.CurrentWorld.EntityManager; + User = user; + Character = character; + FromCharacter = new FromCharacter() + { + User = character.UserEntity._Entity, + Character = user.LocalCharacter._Entity, + }; + AdminLevel = Utils.GetAdminLevel(FromCharacter.User, entityManager); + } public VModCharacter(FromCharacter fromCharacter, EntityManager? entityManager = null) { @@ -36,6 +47,7 @@ public VModCharacter(FromCharacter fromCharacter, EntityManager? entityManager = User = entityManager.Value.GetComponentData(fromCharacter.User); Character = entityManager.Value.GetComponentData(fromCharacter.Character); FromCharacter = fromCharacter; + AdminLevel = Utils.GetAdminLevel(FromCharacter.User, entityManager); } public VModCharacter(Entity userEntity, Entity charEntity, EntityManager? entityManager = null) @@ -48,23 +60,23 @@ public VModCharacter(Entity userEntity, Entity charEntity, EntityManager? entity User = Character.UserEntity._Entity, Character = User.LocalCharacter._Entity, }; + AdminLevel = Utils.GetAdminLevel(FromCharacter.User, entityManager); } - public VModCharacter(Entity charEntity, EntityManager? entityManager = null) + #endregion + + #region Public Methods + + public static bool operator ==(VModCharacter left, VModCharacter right) { - entityManager ??= Utils.CurrentWorld.EntityManager; - Character = entityManager.Value.GetComponentData(charEntity); - User = entityManager.Value.GetComponentData(Character.UserEntity._Entity); - FromCharacter = new FromCharacter() + if(ReferenceEquals(left, right)) { - User = Character.UserEntity._Entity, - Character = User.LocalCharacter._Entity, - }; + return true; + } + return left.User == right.User; } - #endregion - - #region Public Methods + public static bool operator !=(VModCharacter left, VModCharacter right) => !(left == right); public static VModCharacter? GetVModCharacter(string charactername, EntityManager? entityManager = null) { @@ -82,6 +94,21 @@ public VModCharacter(Entity charEntity, EntityManager? entityManager = null) return null; } + public override bool Equals(object obj) + { + if(base.Equals(obj)) + { + return true; + } + if(obj is VModCharacter vmodCharacter) + { + return this == vmodCharacter; + } + return false; + } + + public override int GetHashCode() => (User, Character).GetHashCode(); + public void ApplyBuff(PrefabGUID buffGUID) { Utils.ApplyBuff(FromCharacter, buffGUID); diff --git a/Shared/VModStorage.cs b/Shared/VModStorage.cs index cd8ecd5..282608d 100644 --- a/Shared/VModStorage.cs +++ b/Shared/VModStorage.cs @@ -1,7 +1,7 @@ using System; using System.IO; using System.Text.Json; -using Wetstone.API; +using static VMods.Shared.CommandAttribute; namespace VMods.Shared { @@ -73,7 +73,7 @@ public static T Load(string filename, Func getDefaultValue) #region Private Methods - [Command("saveall", "saveall", "Saves all data of all VMod plugins", true)] + [Command("saveall", "saveall", "Saves all data of all VMod plugins", AdminLevel.Admin)] private static void OnSaveAllCommand(Command command) { SaveAll();