Skip to content
RustPluginGenerator

OnTeamCreated

OnTeamCreated is called right after a new team is created via RelationshipManager.TryCreateTeam, once the leader has been set and added to the team's member list. It fires before any invite or join message flow, so it is the earliest point to react to a brand new team.

Signature
void OnTeamCreated(BasePlayer player, RelationshipManager.PlayerTeam playerTeam)

Parameters

Hook parameters
ParameterTypeDescription
playerBasePlayerThe BasePlayer who triggered team creation. This is the player who ran the create-team action (for example /create) and becomes the team leader. It is a connected player, not a sleeper.
playerTeamRelationshipManager.PlayerTeamThe RelationshipManager.PlayerTeam instance that was just created. It already has teamID set, teamLeader equal to player.userID, and the leader added to members, so you can read or change it immediately.

Return value

The return value is ignored. The original method returns void and continues regardless of what your hook returns, so you cannot prevent or replace team creation from OnTeamCreated. To block or alter creation, use the OnTeamCreate hook instead.

How it works

The hook fires inside RelationshipManager.TryCreateTeam, after a fresh PlayerTeam is allocated from the server instance, the leader is assigned, and the player is added to the team. At that moment the team has exactly one member (the leader) and teamID is already valid. Every game path that creates a team runs through this method, so accepting an invite to a non-existent team or a console/plugin call that builds a team will reach it too, not only the chat command a player types.

Use player for identity and permission checks, and playerTeam for the team data: teamID, teamLeader, and members. You can tag or record the team immediately, seed metadata keyed by teamID, or apply a starting state (for example store the creation time).

Declaring player as BasePlayer matches the game's actual argument; narrowing it to a subclass would make Oxide skip calls where the argument is not that type. Because this is a void game method and the return value is ignored, the hook cannot cancel creation. The team already exists when your code runs, so treat it as a notification, not a guard.

Example plugin: Record new teams and give the leader a welcome notice

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

namespace Oxide.Plugins
{
    [Info("Team Created Logger", "RustPluginGenerator", "1.0.0")]
    [Description("Records newly created teams and optionally notifies the team leader.")]
    public class TeamCreatedLogger : RustPlugin
    {
        private const string DataFileName = "TeamCreatedLogger";

        private PluginConfig config;
        private Dictionary<string, TeamRecord> records = new Dictionary<string, TeamRecord>();

        private class PluginConfig
        {
            [JsonProperty("Notify leader in chat")]
            public bool NotifyLeader { get; set; } = true;

            [JsonProperty("Maximum stored records")]
            public int MaxRecords { get; set; } = 5000;
        }

        private class TeamRecord
        {
            [JsonProperty("teamId")]
            public ulong TeamId { get; set; }

            [JsonProperty("leaderName")]
            public string LeaderName { get; set; }

            [JsonProperty("leaderSteamId")]
            public string LeaderSteamId { get; set; }

            [JsonProperty("createdUnix")]
            public int CreatedUnix { get; set; }
        }

        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>
            {
                ["TeamCreated"] = "Your team has been created. Team ID: {0}"
            }, this);
        }

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

        private void OnServerInitialized()
        {
            records = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, TeamRecord>>(DataFileName)
                      ?? new Dictionary<string, TeamRecord>();
        }

        private void OnTeamCreated(BasePlayer player, RelationshipManager.PlayerTeam playerTeam)
        {
            if (player == null || playerTeam == null) return;

            string key = playerTeam.teamID.ToString();
            if (records.ContainsKey(key)) return;

            if (records.Count >= config.MaxRecords) return;

            records[key] = new TeamRecord
            {
                TeamId = playerTeam.teamID,
                LeaderName = player.displayName,
                LeaderSteamId = player.UserIDString,
                CreatedUnix = Facepunch.Math.Epoch.Current
            };

            if (config.NotifyLeader && player.IsConnected)
            {
                player.ChatMessage(Msg("TeamCreated", player.UserIDString, playerTeam.teamID));
            }
        }

        private void OnServerSave()
        {
            Interface.Oxide.DataFileSystem.WriteObject(DataFileName, records);
        }

        private void Unload()
        {
            Interface.Oxide.DataFileSystem.WriteObject(DataFileName, records);
        }
    }
}

The plugin stores a simple record for each team when it is created: the team ID, leader name, leader Steam ID, a unix timestamp, and a starting member count. Writes go to oxide/data/TeamCreatedLogger through the data file system. Optionally, the leader receives a chat line confirming the team exists and showing the team ID, which is useful on servers that hand out team-based rewards. The config toggles the chat notice and sets the maximum number of stored records so the data file does not grow without bound. Records are saved on unload and also on the server's periodic save hook.

Common use cases

  • Register team-based reward eligibility

    Create a record keyed by teamID so later hooks like OnTeamMemberInvite or OnTeamAcceptInvite can check whether the team is new and grant a starter bonus.

  • Audit team creation

    Log every new team with the leader's Steam ID and time so admins can investigate suspicious team churn or abusive team-splitting on PvP servers.

  • Apply starting team settings

    Initialize per-team metadata such as a friendly-fire flag or a display name, then let players modify it through your own chat commands.

Pitfalls

  • Cannot cancel creation here

    The return value is ignored and the team already exists. If you need to reject team creation, handle the OnTeamCreate hook instead of OnTeamCreated.

  • Team has only the leader

    Do not assume members beyond the leader are present. Read playerTeam.members fresh rather than caching the count and expecting it to stay accurate as players join.

  • Not every creation is a chat command

    Other paths and plugins can call team creation directly. Guard against duplicate records by checking that teamID is not already stored before writing.

Build a plugin with OnTeamCreated

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

Prompt: Register team-based reward eligibility using the OnTeamCreated 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 OnTeamCreated

Generate