1
0

AdminFlagsHelper.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. using System.Linq;
  2. using System.Numerics;
  3. namespace Content.Shared.Administration
  4. {
  5. /// <summary>
  6. /// Contains various helper methods for working with admin flags.
  7. /// </summary>
  8. public static class AdminFlagsHelper
  9. {
  10. // As you can tell from the boatload of bitwise ops,
  11. // writing this class was genuinely fun.
  12. private static readonly Dictionary<string, AdminFlags> NameFlagsMap = new();
  13. private static readonly string[] FlagsNameMap = new string[32];
  14. /// <summary>
  15. /// Every admin flag in the game, at once!
  16. /// </summary>
  17. public static readonly AdminFlags Everything;
  18. /// <summary>
  19. /// A list of all individual admin flags.
  20. /// </summary>
  21. public static readonly IReadOnlyList<AdminFlags> AllFlags;
  22. static AdminFlagsHelper()
  23. {
  24. var t = typeof(AdminFlags);
  25. var flags = (AdminFlags[]) Enum.GetValues(t);
  26. var allFlags = new List<AdminFlags>();
  27. foreach (var value in flags)
  28. {
  29. var name = value.ToString().ToUpper();
  30. // If, in the future, somebody adds a combined admin flag or something for convenience,
  31. // ignore it.
  32. if (BitOperations.PopCount((uint) value) != 1)
  33. {
  34. continue;
  35. }
  36. allFlags.Add(value);
  37. Everything |= value;
  38. NameFlagsMap.Add(name, value);
  39. FlagsNameMap[BitOperations.Log2((uint) value)] = name;
  40. }
  41. AllFlags = allFlags.ToArray();
  42. }
  43. /// <summary>
  44. /// Converts an enumerable of admin flag names to a bitfield.
  45. /// </summary>
  46. /// <remarks>
  47. /// The flags must all be uppercase.
  48. /// </remarks>
  49. /// <exception cref="ArgumentException">
  50. /// Thrown if a string that is not a valid admin flag is contained in <paramref name="names"/>.
  51. /// </exception>
  52. public static AdminFlags NamesToFlags(IEnumerable<string> names)
  53. {
  54. var flags = AdminFlags.None;
  55. foreach (var name in names)
  56. {
  57. if (!NameFlagsMap.TryGetValue(name, out var value))
  58. {
  59. throw new ArgumentException($"Invalid admin flag name: {name}");
  60. }
  61. flags |= value;
  62. }
  63. return flags;
  64. }
  65. /// <summary>
  66. /// Gets the flag bit for an admin flag name.
  67. /// </summary>
  68. /// <remarks>
  69. /// The flag name must be all uppercase.
  70. /// </remarks>
  71. /// <exception cref="KeyNotFoundException">
  72. /// Thrown if <paramref name="name"/> is not a valid admin flag name.
  73. /// </exception>
  74. public static AdminFlags NameToFlag(string name)
  75. {
  76. return NameFlagsMap[name];
  77. }
  78. /// <summary>
  79. /// Converts a bitfield of admin flags to an array of all the flag names set.
  80. /// </summary>
  81. public static string[] FlagsToNames(AdminFlags flags)
  82. {
  83. var array = new string[BitOperations.PopCount((uint) flags)];
  84. var highest = BitOperations.LeadingZeroCount((uint) flags);
  85. var ai = 0;
  86. for (var i = 0; i < 32 - highest; i++)
  87. {
  88. var flagValue = (AdminFlags) (1u << i);
  89. if ((flags & flagValue) != 0)
  90. {
  91. array[ai++] = FlagsNameMap[i];
  92. }
  93. }
  94. return array;
  95. }
  96. public static string PosNegFlagsText(AdminFlags posFlags, AdminFlags negFlags)
  97. {
  98. var posFlagNames = FlagsToNames(posFlags).Select(f => (flag: f, fText: $"+{f}"));
  99. var negFlagNames = FlagsToNames(negFlags).Select(f => (flag: f, fText: $"-{f}"));
  100. var flagsText = string.Join(' ', posFlagNames.Concat(negFlagNames).OrderBy(f => f.flag).Select(p => p.fText));
  101. return flagsText;
  102. }
  103. }
  104. }