Skip to content
RustPluginGenerator

OnTeamCreate

OnTeamCreate is called when a player uses the in-game "Create Team" action in the team UI, right before RelationshipManager.TryCreateTeam actually builds the PlayerTeam and assigns the player as leader.

Signature
object OnTeamCreate(BasePlayer player)

Parameters

Hook parameters
ParameterTypeDescription
playerBasePlayerThe BasePlayer who pressed the create-team button. At this point the player has no team yet (currentTeam is 0), so check this player for permission, cooldown, or cooldown data before allowing the team to exist.

Return value

Return null (or do nothing) to let the game create the team. Return any non-null object to stop the original code path, which prevents the team from being created and leaves the player without a team.

How it works

The hook fires from RelationshipManager.TryCreateTeam, which the client invokes through the team menu. The game only reaches this method when player.currentTeam == 0, so the argument is always a teamless player at the moment of the call. Returning a non-null object cancels the creation before any PlayerTeam is allocated; returning null lets RelationshipManager create the team, set teamLeader to the player's userID, add the player to it, and fire the analytics event. Because the return value is checked for any non-null object, the value you return does not need to be meaningful, but returning false or a string still blocks creation. Use this hook when you need to veto team creation outright, for example during a purge, a raid lockout on a PvE server, or a minimum-playtime rule. It is the correct place to enforce a pre-creation rule: if you need to inspect or modify the team after it exists, use OnTeamCreated instead, since at this point the team object does not exist yet. The parameter is never null in practice, but guard anyway for safety.

Example plugin: Block team creation during a raid lockout

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

namespace Oxide.Plugins
{
    [Info("Team Create Lockout", "RustPluginGenerator", "1.0.0")]
    [Description("Blocks team creation while a lockout is active for a player or globally.")]
    public class TeamCreateLockout : RustPlugin
    {
        private const string PermManage = "teamcreatelockout.manage";

        private PluginConfig config;
        private Timer unlockTimer;
        private float globalLockUntil;
        private readonly Dictionary<string, float> playerLocks = new Dictionary<string, float>();

        private class PluginConfig
        {
            [JsonProperty("Global lockout seconds on plugin load (0 = disabled)")]
            public float GlobalLockSeconds = 0f;

            [JsonProperty("Default per-player lockout seconds")]
            public float DefaultPlayerLockSeconds = 300f;
        }

        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>
            {
                ["GlobalLocked"] = "Team creation is currently disabled on this server.",
                ["PlayerLocked"] = "You cannot create a team for another {0} seconds.",
                ["GlobalSet"] = "Global team creation locked for {0} seconds.",
                ["PlayerSet"] = "Team creation locked for {0} for {1} seconds.",
                ["LockCleared"] = "All team creation locks cleared."
            }, 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(PermManage, this);
        }

        private void OnServerInitialized()
        {
            if (config.GlobalLockSeconds > 0f)
            {
                globalLockUntil = UnityEngine.Time.realtimeSinceStartup + config.GlobalLockSeconds;
                ScheduleUnlock();
            }
        }

        private object OnTeamCreate(BasePlayer player)
        {
            if (player == null) return null;

            float now = UnityEngine.Time.realtimeSinceStartup;

            if (now < globalLockUntil)
            {
                player.ChatMessage(Msg("GlobalLocked", player.UserIDString));
                return false;
            }

            float until;
            if (playerLocks.TryGetValue(player.UserIDString, out until))
            {
                if (until <= now)
                {
                    playerLocks.Remove(player.UserIDString);
                    return null;
                }

                player.ChatMessage(Msg("PlayerLocked", player.UserIDString, Math.Ceiling(until - now)));
                return false;
            }

            return null;
        }

        [ConsoleCommand("teamlock.global")]
        private void CmdGlobalLock(ConsoleSystem.Arg arg)
        {
            if (arg.Player() != null && !permission.UserHasPermission(arg.Player().UserIDString, PermManage)) return;

            float seconds = arg.GetFloat(0, config.DefaultPlayerLockSeconds);
            globalLockUntil = UnityEngine.Time.realtimeSinceStartup + seconds;
            ScheduleUnlock();
            arg.ReplyWith(Msg("GlobalSet", null, seconds));
        }

        [ConsoleCommand("teamlock.player")]
        private void CmdPlayerLock(ConsoleSystem.Arg arg)
        {
            if (arg.Player() != null && !permission.UserHasPermission(arg.Player().UserIDString, PermManage)) return;

            string target = arg.GetString(0, "");
            if (string.IsNullOrEmpty(target))
            {
                arg.ReplyWith("Usage: teamlock.player <nameOrId> [seconds]");
                return;
            }

            BasePlayer found = BasePlayer.FindAwakeOrSleeping(target);
            if (found == null)
            {
                arg.ReplyWith("Player not found");
                return;
            }

            float seconds = arg.GetFloat(1, config.DefaultPlayerLockSeconds);
            playerLocks[found.UserIDString] = UnityEngine.Time.realtimeSinceStartup + seconds;
            arg.ReplyWith(Msg("PlayerSet", null, found.displayName, seconds));
        }

        [ConsoleCommand("teamlock.clear")]
        private void CmdClear(ConsoleSystem.Arg arg)
        {
            if (arg.Player() != null && !permission.UserHasPermission(arg.Player().UserIDString, PermManage)) return;

            playerLocks.Clear();
            globalLockUntil = 0f;
            if (unlockTimer != null)
            {
                unlockTimer.Destroy();
                unlockTimer = null;
            }
            arg.ReplyWith(Msg("LockCleared"));
        }

        private void ScheduleUnlock()
        {
            if (unlockTimer != null)
            {
                unlockTimer.Destroy();
            }

            float remaining = globalLockUntil - UnityEngine.Time.realtimeSinceStartup;
            if (remaining <= 0f) return;

            unlockTimer = timer.Once(remaining, () => { unlockTimer = null; });
        }

        private void Unload()
        {
            if (unlockTimer != null)
            {
                unlockTimer.Destroy();
                unlockTimer = null;
            }
            playerLocks.Clear();
        }
    }
}

The plugin gives admins a console command to lock team creation for a number of seconds. When OnTeamCreate fires, it looks up the player's lock in a dictionary keyed by UserIDString and, if the wall-clock time has not passed, sends a localized chat message and returns false to block the attempt. Because the return value only needs to be non-null, false is enough. Unlock and status commands are also provided. Entries are pruned when they expire on lookup, so the dictionary does not grow without bound, and the timer is cleaned up in Unload.

Common use cases

  • Purge or wipe lockout

    Refuse new team creation while a purge event is active so groups cannot reform and contest the purge. Clear the flag from a console command when the event ends.

  • Minimum playtime gate

    Block team creation for freshly connected players until they have met a playtime or wipe-day requirement, which slows down throwaway accounts forming groups.

  • PvE seasonal restriction

    On PvE servers that disable teams entirely or only allow them on a schedule, use the hook to reject every manual creation attempt outside the scheduled window.

Pitfalls

  • Returning a value by accident

    Any non-null return, including false or a string, blocks creation. Make sure every path in the hook either explicitly returns null or is intended to veto, otherwise team creation silently breaks for everyone.

  • This is not the moment to inspect the team

    The PlayerTeam object has not been created when this hook runs, so player.currentTeam is still 0 and no team members exist. Read or modify the team in OnTeamCreated instead.

  • Client UI may still change

    Blocking creation only stops the server-side team; the client team menu can briefly show a stale state. Send a chat message so the player understands why nothing happened.

Build a plugin with OnTeamCreate

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

Prompt: Purge or wipe lockout using the OnTeamCreate 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 OnTeamCreate

Generate