using System; using System.Collections.Generic; using System.Linq; using System.Numerics; namespace Content.Shared.Administration { /// /// Contains various helper methods for working with admin flags. /// public static class AdminFlagsHelper { // As you can tell from the boatload of bitwise ops, // writing this class was genuinely fun. private static readonly Dictionary NameFlagsMap = new Dictionary(); private static readonly string[] FlagsNameMap = new string[32]; /// /// Every admin flag in the game, at once! /// public static readonly AdminFlags Everything; /// /// A list of all individual admin flags. /// public static readonly IReadOnlyList AllFlags; static AdminFlagsHelper() { var t = typeof(AdminFlags); var flags = (AdminFlags[]) Enum.GetValues(t); var allFlags = new List(); foreach (var value in flags) { var name = value.ToString().ToUpper(); // If, in the future, somebody adds a combined admin flag or something for convenience, // ignore it. if (BitOperations.PopCount((uint) value) != 1) { continue; } allFlags.Add(value); Everything |= value; NameFlagsMap.Add(name, value); FlagsNameMap[BitOperations.Log2((uint) value)] = name; } AllFlags = allFlags.ToArray(); } /// /// Converts an enumerable of admin flag names to a bitfield. /// /// /// The flags must all be uppercase. /// /// /// Thrown if a string that is not a valid admin flag is contained in . /// public static AdminFlags NamesToFlags(IEnumerable names) { var flags = AdminFlags.None; foreach (var name in names) { if (!NameFlagsMap.TryGetValue(name, out var value)) { throw new ArgumentException($"Invalid admin flag name: {name}"); } flags |= value; } return flags; } /// /// Gets the flag bit for an admin flag name. /// /// /// The flag name must be all uppercase. /// /// /// Thrown if is not a valid admin flag name. /// public static AdminFlags NameToFlag(string name) { return NameFlagsMap[name]; } /// /// Converts a bitfield of admin flags to an array of all the flag names set. /// public static string[] FlagsToNames(AdminFlags flags) { var array = new string[BitOperations.PopCount((uint) flags)]; var highest = BitOperations.LeadingZeroCount((uint) flags); var ai = 0; for (var i = 0; i < 32 - highest; i++) { var flagValue = (AdminFlags) (1u << i); if ((flags & flagValue) != 0) { array[ai++] = FlagsNameMap[i]; } } return array; } public static string PosNegFlagsText(AdminFlags posFlags, AdminFlags negFlags) { var posFlagNames = FlagsToNames(posFlags).Select(f => (flag: f, fText: $"+{f}")); var negFlagNames = FlagsToNames(negFlags).Select(f => (flag: f, fText: $"-{f}")); var flagsText = string.Join(' ', posFlagNames.Concat(negFlagNames).OrderBy(f => f.flag).Select(p => p.fText)); return flagsText; } } }