Skip to content
RustPluginGenerator

OnClanDisbanded

OnClanDisbanded is called after a clan has been deleted, at the end of LocalClan.Disband, so the clan no longer exists when your plugin runs.

Signature
void OnClanDisbanded(LocalClan localClan, ulong bySteamId)

Parameters

Hook parameters
ParameterTypeDescription
localClanLocalClanThe LocalClan instance that was just disbanded. It still holds clanId, clanTag, leader and member Steam IDs at the time of the call, but its backend state is already torn down, so treat it as a read-only snapshot.
bySteamIdulongSteam ID (ulong) of the player who triggered the disband. Compare it with localClan.leader to tell a leader-initiated disband apart from an admin or server-side removal.

Return value

The return value is discarded. Disband is a void coroutine and the call site simply continues to SetResult afterwards, so returning true, false or nothing has no effect on whether the clan is removed.

How it works

The hook fires from the tail of the LocalClan.Disband coroutine, after the backend has finished removing the clan. Every disband path reaches it: the leader pressing disband in the clan UI, an admin or server finishing the removal, or a scheduled cleanup that ends up calling Disband. Because the call is placed after the clan's own cleanup, this is a notification hook, not a veto point: you cannot cancel or delay the disband from here.

localClan gives you the identity of the clan that ended up gone (clanId, clanTag, leader) and its members. bySteamId is the Steam ID of whoever initiated the disband, useful for audit trails and for distinguishing self-disbands from administrative removals.

The hook always receives LocalClan and ulong; there is no narrower overload that makes sense, so declare the exact types. Any clan-related cache your plugin keeps (tag lookups, per-clan data files, CUI panels keyed by clan tag) should be invalidated here, otherwise stale entries survive until the next restart.

Example plugin: Log disbanded clans to a rotating data file

ClanDisbandLog.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("ClanDisbandLog", "RustPluginGenerator", "1.0.0")]
    [Description("Keeps a capped history of disbanded clans in a data file")]
    public class ClanDisbandLog : RustPlugin
    {
        private const string PermAdmin = "clandisbandlog.admin";

        [PluginReference] private Plugin Clans;

        private PluginConfig config;
        private StoredData data;

        private class PluginConfig
        {
            [JsonProperty("Maximum stored entries")]
            public int MaxEntries = 200;
        }

        private class DisbandRecord
        {
            [JsonProperty("clanId")] public ulong ClanId;
            [JsonProperty("clanTag")] public string ClanTag;
            [JsonProperty("leader")] public ulong Leader;
            [JsonProperty("disbandedBy")] public ulong DisbandedBy;
            [JsonProperty("memberCount")] public int MemberCount;
            [JsonProperty("timestamp")] public DateTime Timestamp;
        }

        private class StoredData
        {
            [JsonProperty("entries")] public List<DisbandRecord> Entries = new List<DisbandRecord>();
        }

        protected override void LoadDefaultConfig() => config = new PluginConfig();

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<PluginConfig>();
                if (config == null) throw new Exception();
            }
            catch
            {
                PrintWarning("Configuration file is invalid, using defaults");
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void SaveConfig() => Config.WriteObject(config);

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["Denied"] = "You do not have permission to use this command.",
                ["Empty"] = "No disbands have been recorded yet.",
                ["Cleared"] = "Disband log cleared.",
                ["Line"] = "{0}. [{1}] clan {2} - leader {3}, disbanded by {4}, {5} members, {6:yyyy-MM-dd HH:mm} UTC"
            }, this);
        }

        private string Msg(string key, string userId = null, params object[] args) => string.Format(lang.GetMessage(key, this, userId), args);

        private void Init()
        {
            permission.RegisterPermission(PermAdmin, this);
        }

        private void OnServerInitialized()
        {
            data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name) ?? new StoredData();
        }

        private void Unload()
        {
            if (data != null) Interface.Oxide.DataFileSystem.WriteObject(Name, data);
        }

        // LocalClan exposes no members/clanId/clanTag/leader fields; resolve through the Clans plugin API.
        private void OnClanDisbanded(object localClan, ulong bySteamId)
        {
            if (localClan == null || data == null || Clans == null) return;

            var clanIdObj = Clans.Call("GetClanId", localClan);
            ulong clanId = clanIdObj is ulong ? (ulong)clanIdObj : 0UL;
            if (clanId == 0UL) return;

            var tagObj = Clans.Call("GetClanTag", clanId);
            string clanTag = tagObj as string ?? "none";

            var leaderObj = Clans.Call("GetClanLeader", clanId);
            ulong leader = leaderObj is ulong ? (ulong)leaderObj : 0UL;

            int memberCount = 0;
            var membersObj = Clans.Call("GetClanMembers", clanId);
            var memberList = membersObj as List<string>;
            if (memberList != null) memberCount = memberList.Count;

            data.Entries.Add(new DisbandRecord
            {
                ClanId = clanId,
                ClanTag = clanTag,
                Leader = leader,
                DisbandedBy = bySteamId,
                MemberCount = memberCount,
                Timestamp = DateTime.UtcNow
            });

            if (config.MaxEntries > 0 && data.Entries.Count > config.MaxEntries)
                data.Entries.RemoveRange(0, data.Entries.Count - config.MaxEntries);

            Interface.Oxide.DataFileSystem.WriteObject(Name, data);
        }

        [ChatCommand("clanlog")]
        private void CmdClanLog(BasePlayer player, string command, string[] args)
        {
            if (player == null || !permission.UserHasPermission(player.UserIDString, PermAdmin))
            {
                SendReply(player, Msg("Denied", player.UserIDString));
                return;
            }

            if (args != null && args.Length > 0 && args[0].ToLower() == "clear")
            {
                data?.Entries.Clear();
                if (data != null) Interface.Oxide.DataFileSystem.WriteObject(Name, data);
                SendReply(player, Msg("Cleared", player.UserIDString));
                return;
            }

            if (data == null || data.Entries.Count == 0)
            {
                SendReply(player, Msg("Empty", player.UserIDString));
                return;
            }

            int shown = 0;
            for (int i = data.Entries.Count - 1; i >= 0 && shown < 8; i--, shown++)
            {
                var e = data.Entries[i];
                SendReply(player, Msg("Line", player.UserIDString, data.Entries.Count - i, e.ClanTag, e.ClanId, e.Leader, e.DisbandedBy, e.MemberCount, e.Timestamp));
            }
        }
    }
}

The plugin keeps a capped history of disbands in oxide/data/ClanDisbandLog.json. When the Clans plugin is loaded, OnClanDisbanded resolves the clan ID, tag, leader and member count through the Clans API, records the steam ID that triggered the disband, trims the list to the configured Maximum stored entries and saves the file. OnServerInitialized loads the file, and Unload writes it again so nothing is lost on reload. A chat command clanlog lets admins read the most recent entries (up to 8) and clanlog clear empties the log; both require the clandisbandlog.admin permission. The clan tag defaults to none and unknown leader/member counts fall back to 0 when the Clans API returns nothing.

Common use cases

  • Clean up per-clan cached data

    If your plugin stores data keyed by clanId, delete the entry in this hook so a newly created clan that reuses the ID does not inherit old settings.

  • Audit trail for staff

    Record who disbanded which clan and when. Comparing bySteamId with localClan.leader separates leader decisions from administrative removals.

  • Remove clan UI

    If a custom clan panel is shown to members, destroy it for every online member stored in the disbanded clan so nobody is left with a stale overlay.

Pitfalls

  • The clan is already gone

    Do not try to look up the clan by tag or ID from here and expect a live object. Work with the passed LocalClan snapshot and drop any references by clanId instead.

  • Members may be empty

    Some removal paths finish clearing membership before Disband completes, so treat localClan.members as possibly null or empty and guard before iterating.

  • Not a cancellation hook

    There is no return value handling here. To prevent a disband you need a different hook; OnClanDisbanded only reports what already happened.

Build a plugin with OnClanDisbanded

Describe what should happen and get a compiled plugin that uses this hook.

Prompt: Clean up per-clan cached data using the OnClanDisbanded hook, with a config file and a permission
Generate this plugin

Edit the prompt on the next screen. 2 free plugins a month, no card.

Last updated Oct 26, 2026. Found a mistake? Email support@rustplugingenerator.com.

Build a plugin with OnClanDisbanded

Generate