1
0

CVarControlManager.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. using System.Linq;
  2. using System.Reflection;
  3. using Content.Shared.CCVar.CVarAccess;
  4. using Robust.Shared.Configuration;
  5. using Robust.Shared.Console;
  6. using Robust.Shared.Player;
  7. using Robust.Shared.Reflection;
  8. namespace Content.Server.Administration.Managers;
  9. /// <summary>
  10. /// Manages the control of CVars via the <see cref="Content.Shared.CCVar.CVarAccess.CVarControl"/> attribute.
  11. /// </summary>
  12. public sealed class CVarControlManager : IPostInjectInit
  13. {
  14. [Dependency] private readonly IReflectionManager _reflectionManager = default!;
  15. [Dependency] private readonly IAdminManager _adminManager = default!;
  16. [Dependency] private readonly ILocalizationManager _localizationManager = default!;
  17. [Dependency] private readonly ILogManager _logger = default!;
  18. private readonly List<ChangableCVar> _changableCvars = new();
  19. private ISawmill _sawmill = default!;
  20. void IPostInjectInit.PostInject()
  21. {
  22. _sawmill = _logger.GetSawmill("cvarcontrol");
  23. }
  24. public void Initialize()
  25. {
  26. RegisterCVars();
  27. }
  28. private void RegisterCVars()
  29. {
  30. if (_changableCvars.Count != 0)
  31. {
  32. _sawmill.Warning("CVars already registered, overwriting.");
  33. _changableCvars.Clear();
  34. }
  35. var validCvarsDefs = _reflectionManager.FindTypesWithAttribute<CVarDefsAttribute>();
  36. foreach (var type in validCvarsDefs)
  37. {
  38. foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy))
  39. {
  40. var allowed = field.GetCustomAttribute<CVarControl>();
  41. if (allowed == null)
  42. {
  43. continue;
  44. }
  45. var cvarDef = (CVarDef)field.GetValue(null)!;
  46. _changableCvars.Add(new ChangableCVar(cvarDef.Name, allowed, _localizationManager));
  47. }
  48. }
  49. _sawmill.Info($"Registered {_changableCvars.Count} CVars.");
  50. }
  51. /// <summary>
  52. /// Gets all CVars that the player can change.
  53. /// </summary>
  54. public List<ChangableCVar> GetAllRunnableCvars(IConsoleShell shell)
  55. {
  56. // Not a player, running as server. We COULD return all cvars,
  57. // but a check later down the line will prevent it from anyways. Use the "cvar" command instead.
  58. if (shell.Player == null)
  59. return [];
  60. return GetAllRunnableCvars(shell.Player);
  61. }
  62. public List<ChangableCVar> GetAllRunnableCvars(ICommonSession session)
  63. {
  64. var adminData = _adminManager.GetAdminData(session);
  65. if (adminData == null)
  66. return []; // Not an admin
  67. return _changableCvars
  68. .Where(cvar => adminData.HasFlag(cvar.Control.AdminFlags))
  69. .ToList();
  70. }
  71. public ChangableCVar? GetCVar(string name)
  72. {
  73. return _changableCvars.FirstOrDefault(cvar => cvar.Name == name);
  74. }
  75. }
  76. public sealed class ChangableCVar
  77. {
  78. private const string LocPrefix = "changecvar";
  79. public string Name { get; }
  80. // Holding a reference to the attribute might be skrunkly? Not sure how much mem it eats up.
  81. public CVarControl Control { get; }
  82. public string? ShortHelp;
  83. public string? LongHelp;
  84. public ChangableCVar(string name, CVarControl control, ILocalizationManager loc)
  85. {
  86. Name = name;
  87. Control = control;
  88. if (loc.TryGetString($"{LocPrefix}-simple-{name.Replace('.', '_')}", out var simple))
  89. {
  90. ShortHelp = simple;
  91. }
  92. if (loc.TryGetString($"{LocPrefix}-full-{name.Replace('.', '_')}", out var longHelp))
  93. {
  94. LongHelp = longHelp;
  95. }
  96. // If one is set and the other is not, we throw
  97. if (ShortHelp == null && LongHelp != null || ShortHelp != null && LongHelp == null)
  98. {
  99. throw new InvalidOperationException("Short and long help must both be set or both be null.");
  100. }
  101. }
  102. }