Code/AdminSystem.cs
using Sandbox;
using System.Collections.Generic;

namespace ExtendedNetworking;

public class AdminSystem : GameObjectSystem<AdminSystem>, Component.INetworkListener
{
    [ConVar("auto_load_admins", ConVarFlags.Admin | ConVarFlags.Saved | ConVarFlags.Hidden)]
    public static bool AutoLoad { get; set; } = false;

    private static readonly HashSet<SteamId> _admins = [];


    public AdminSystem(Scene scene) : base(scene)
    {
        if(AutoLoad)
            LoadAdmins();
    }


    [RpcX.Broadcast(RpcSender.Admin)]
    public static void AddAdmin(SteamId steamId) => _admins.Add(steamId);
    public static void AddAdmin(Connection connection)
    {
        if(connection.IsHost)
            return;

        AddAdmin(connection.SteamId);
    }

    [RpcX.Broadcast(RpcSender.Admin)]
    public static void RemoveAdmin(SteamId steamId) => _admins.Remove(steamId);
    public static void RemoveAdmin(Connection connection)
    {
        if(connection.IsHost)
            return;

        RemoveAdmin(connection.SteamId);
    }

    [RpcX.Broadcast(RpcSender.Admin)]
    public static void ClearAdmins() => _admins.Clear();

    public static bool IsAdmin(SteamId steamId) => _admins.Contains(steamId);

    public static bool IsAdmin(Connection connection)
    {
        if(connection.IsHost)
            return true;

        return _admins.Contains(connection.SteamId);
    }


    [RpcX.Broadcast(RpcSender.Host)]
    private static void UpdateAdmins(SteamId[] steamIds)
    {
        _admins.Clear();
        _admins.UnionWith(steamIds);
    }


    [RpcX.Host(RpcSender.Admin)]
    public static void SaveAdmins()
    {
        var adminEntries = Storage.GetAll("admins");
        for(int i = 1; i < adminEntries.Length; ++i)
            adminEntries[i].Delete();

        var entry = adminEntries.Length > 0 ? adminEntries[0] : Storage.CreateEntry("admins");
        entry.Files.WriteJson("admins.json", _admins);
    }

    [RpcX.Host(RpcSender.Admin)]
    public static void LoadAdmins()
    {
        _admins.Clear();

        var adminEntries = Storage.GetAll("admins");
        if(adminEntries.Length == 0)
            return;

        var entry = adminEntries[0];
        _admins.UnionWith(entry.Files.ReadJson<SteamId[]>("admins.json", []));
    }


    [ConCmd("add_admin", ConVarFlags.Server)]
    private static void AddAdminCmd(Connection caller, ulong steamId)
    {
        if(!IsAdmin(caller))
        {
            caller.SendLog(LogLevel.Warn, "You are not allowed to run this command.");
            return;
        }

        AddAdmin(steamId);
        caller.SendLog(LogLevel.Info, $"Admin {steamId} added.");
    }

    [ConCmd("remove_admin", ConVarFlags.Server)]
    private static void RemoveAdminCmd(Connection caller, ulong steamId)
    {
        if(!IsAdmin(caller))
        {
            caller.SendLog(LogLevel.Warn, "You are not allowed to run this command.");
            return;
        }

        RemoveAdmin(steamId);
        caller.SendLog(LogLevel.Info, $"Admin {steamId} removed.");
    }

    [ConCmd("clear_admins", ConVarFlags.Server)]
    private static void ClearAdminsCmd(Connection caller)
    {
        if(!IsAdmin(caller))
        {
            caller.SendLog(LogLevel.Warn, "You are not allowed to run this command.");
            return;
        }

        ClearAdmins();
        caller.SendLog(LogLevel.Info, "Admins cleared.");
    }

    [ConCmd("is_admin")]
    private static void IsAdminCmd(Connection caller, ulong steamId)
    {
        if(!IsAdmin(caller))
        {
            caller.SendLog(LogLevel.Warn, "You are not allowed to run this command.");
            return;
        }

        Log.Info($"{steamId} is {(IsAdmin(steamId) ? string.Empty : "not ")}admin.");
    }

    [ConCmd("list_admins")]
    private static void ListAdminsCmd(Connection caller)
    {
        if(!IsAdmin(caller))
        {
            caller.SendLog(LogLevel.Warn, "You are not allowed to run this command.");
            return;
        }

        foreach(var admin in _admins)
            caller.SendLog(LogLevel.Info, admin.ToString());
    }

    [ConCmd("save_admins", ConVarFlags.Server)]
    private static void SaveAdminsCmd(Connection caller)
    {
        if(!IsAdmin(caller))
        {
            caller.SendLog(LogLevel.Warn, "You are not allowed to run this command.");
            return;
        }

        SaveAdmins();
        caller.SendLog(LogLevel.Info, "Admins saved.");
    }


    [ConCmd("load_admins", ConVarFlags.Server)]
    private static void LoadAdminsCmd(Connection caller)
    {
        if(!IsAdmin(caller))
        {
            caller.SendLog(LogLevel.Warn, "You are not allowed to run this command.");
            return;
        }

        LoadAdmins();
        caller.SendLog(LogLevel.Info, "Admins loaded.");
    }


    [ConCmd("auto_load_admins", ConVarFlags.Server)]
    private static void AutoLoadAdminsCmd(Connection caller, bool? value = null)
    {
        if(!IsAdmin(caller))
        {
            caller.SendLog(LogLevel.Warn, "You are not allowed to run this command.");
            return;
        }

        if(value.HasValue)
            AutoLoad = value.Value;
        caller.SendLog(LogLevel.Info, $"Auto load admins: {AutoLoad}.");
    }

    void Component.INetworkListener.OnActive(Connection connection)
    {
        if(!Networking.IsHost || connection == Connection.Local)
            return;

        using(RpcX.FilterInclude(connection))
        {
            UpdateAdmins([.. _admins]);
        }
    }
}