Skip to content
RustPluginGenerator

OnTeamUpdate

OnTeamUpdate is called from BasePlayer.UpdateTeam whenever the server is about to change a player's currentTeam value, including joining, switching and leaving a team.

Signature
object OnTeamUpdate(ulong currentTeam, ulong newTeam, BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
currentTeamulongThe team ID the player is currently a member of. 0 means the player has no team.
newTeamulongThe team ID the player is being moved to. 0 means the player is being removed from any team.
playerBasePlayerThe BasePlayer whose team assignment is being changed.

Return value

Returning null lets the change proceed exactly as vanilla: the team ID is written and the client receives a network update. Returning any non-null value skips the rest of BasePlayer.UpdateTeam, so currentTeam keeps its old value and the player stays on currentTeam while the game believes the change never happened.

How it works

The hook fires inside BasePlayer.UpdateTeam(ulong newTeam), immediately before the assignment currentTeam = newTeam and the network update that follows it. That method is the single place the server writes a player's team ID, so it covers normal operations such as accepting an invite, being kicked, leaving a team, disbanding removing members, and the internal resets that happen on connect or disconnect. currentTeam is what the player is on now, newTeam is the target, and both use 0 to mean "no team". player is the affected BasePlayer; check player.net?.connection if you want to know whether the player is currently connected. Narrowing the parameter type does not help here because player is always a real BasePlayer. The hook is a guard-style callback: it is not dispatched for sleeping players in a different way, and there is no separate event for the team object itself (look at OnTeamCreated, OnTeamDisbanded and OnTeamUpdated for that).

Example plugin: Block joining or leaving teams during a PvP event

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

namespace Oxide.Plugins
{
    [Info("TeamLockdown", "RustPluginGenerator", "1.0.0")]
    [Description("Blocks team joins and leaves while a lockdown is enabled")]
    public class TeamLockdown : RustPlugin
    {
        private const string PermManage = "teamlockdown.manage";
        private const string PermExempt = "teamlockdown.exempt";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Lockdown enabled")]
            public bool LockdownEnabled = false;

            [JsonProperty("Block joins")]
            public bool BlockJoins = true;

            [JsonProperty("Block leaves")]
            public bool BlockLeaves = true;
        }

        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>
            {
                ["LockdownOn"] = "Team lockdown is now enabled.",
                ["LockdownOff"] = "Team lockdown is now disabled.",
                ["NoPermission"] = "You do not have permission to use this command.",
                ["JoinsBlocked"] = "Joining a team is disabled right now.",
                ["LeavesBlocked"] = "Leaving your team is disabled right now."
            }, this);
        }

        private string Msg(string key, string userId = null) => lang.GetMessage(key, this, userId);

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

        [ChatCommand("teamlockdown")]
        private void CmdLockdown(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;
            if (!permission.UserHasPermission(player.UserIDString, PermManage))
            {
                player.ChatMessage(Msg("NoPermission", player.UserIDString));
                return;
            }

            config.LockdownEnabled = !config.LockdownEnabled;
            SaveConfig();
            player.ChatMessage(Msg(config.LockdownEnabled ? "LockdownOn" : "LockdownOff", player.UserIDString));
        }

        private object OnTeamUpdate(ulong currentTeam, ulong newTeam, BasePlayer player)
        {
            if (!config.LockdownEnabled || player == null || currentTeam == newTeam) return null;
            if (permission.UserHasPermission(player.UserIDString, PermExempt)) return null;

            bool joining = currentTeam == 0 && newTeam != 0;
            bool leaving = currentTeam != 0 && newTeam == 0;

            if (joining && config.BlockJoins)
            {
                NotifyBlocked(player, "JoinsBlocked");
                return false;
            }

            if (leaving && config.BlockLeaves)
            {
                NotifyBlocked(player, "LeavesBlocked");
                return false;
            }

            return null;
        }

        private void NotifyBlocked(BasePlayer player, string key)
        {
            if (player.net?.connection == null) return;
            player.ChatMessage(Msg(key, player.UserIDString));
        }
    }
}

The plugin reads a config toggle plus a permission that exempts admins and staff. OnTeamUpdate compares currentTeam and newTeam: a change from 0 to a team ID is a join, a change from a team ID to 0 is a leave, and anything else is a switch or internal reassignment. While lockdown is enabled, any change that is not exempt and not initiated for a player in currentTeam == newTeam is refused by returning a non-null object, so the assignment never happens. A chat command lets holders of the permission flip the lock at runtime, and the state is saved through the config so a server restart keeps the last setting.

Common use cases

  • Event lockdown

    Freeze team membership while a tournament or raid event runs so players cannot regroup mid-fight. The hook is the only reliable place to stop the change, because the team manager itself has already authorised the action by then.

  • Minimum team size enforcement

    Prevent a player from leaving a team that would drop below a configured size, or from joining a team that is already full according to your own rules.

  • Audit team churn

    Record every transition from currentTeam to newTeam with a timestamp to investigate abuse, alt accounts or suspicious team hopping after the fact.

Pitfalls

  • Return value blocks the whole method

    The hook wraps more than the ID assignment: SendNetworkUpdate and the team lookup after it are skipped too. Returning a value is a hard block, not a veto on a sub-step, so only do it when you really want the player to stay where they are.

  • Zero means both 'none' and 'reset'

    Connect, disconnect and wipe-related resets can produce currentTeam == newTeam == 0 or a drop to 0 for reasons that are not a player-initiated leave. Guard against blocking transitions that would leave the server in an inconsistent state, for example by never blocking when currentTeam is already 0.

  • Client and server can drift

    If you block a change the player requested through the UI, their client may still show the new roster until the next team update arrives. Send a short chat or console line explaining the refusal so the player understands the state.

Build a plugin with OnTeamUpdate

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

Prompt: Event lockdown using the OnTeamUpdate 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 OnTeamUpdate

Generate