OnPlayerSpawn
OnPlayerSpawn is called from ServerMgr.SpawnNewPlayer right after the player entity is created for a connecting client. Returning a non-null value stops the original spawn routine and leaves the behavior entirely to your plugin.
object OnPlayerSpawn(BasePlayer player, Network.Connection connection)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer entity just created from the player prefab. It has no owner state settled yet and is still in the dead state until the original spawn code runs. |
connection | Network.Connection | The network connection associated with the incoming player. Use connection.userid for the Steam ID and connection.connection.connection to inspect socket-level info if needed. |
Return value
Returning null lets ServerMgr.SpawnNewPlayer continue and apply the default health, lifesteat and spawn handling. Returning any non-null object (even true) makes the original method skip the rest of its body and return the player entity immediately, so your plugin becomes responsible for finishing the spawn.
How it works
The hook fires inside ServerMgr.SpawnNewPlayer, immediately after the game creates the player.prefab entity at a spawn point and before the default health/lifestate values are applied. It is part of the join sequence: a connecting client has a connection, the server picks a spawn point, builds the player entity, then calls this hook.
player is the freshly constructed BasePlayer. At hook time it is not yet marked dead and spawn logic has not finished, so treat it as a bare entity: check player.IsConnected, player.userID, and player.IsNpc before doing anything. connection lets you correlate with connection hooks and read connection.userid.
Because the injection site only continues when the hook returns non-null, you can short-circuit the normal spawn path deliberately. Returning null keeps vanilla behavior. This hook is not the same as OnPlayerRespawn or OnPlayerSleepEnded, which fire later in the lifecycle.
Declaring BasePlayer is required since the argument is a BasePlayer; narrowing to a subtype is not useful here.
Example plugin: Grant starter kit on first spawn
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("First Spawn Kit", "RustPluginGenerator", "1.0.0")]
[Description("Gives a configurable starter kit to players the first time they spawn")]
public class FirstSpawnKit : RustPlugin
{
private const string DataFileName = "FirstSpawnKit/granted";
private PluginConfig config;
private HashSet<string> granted = new HashSet<string>();
private class PluginConfig
{
[JsonProperty("Starter items (shortname = amount)")]
public Dictionary<string, int> Items = new Dictionary<string, int>
{
["rock"] = 1,
["torch"] = 1,
["bandage"] = 3
};
[JsonProperty("Announce welcome message")]
public bool Announce = 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>
{
["Welcome"] = "Welcome to the server! Your starter kit has been placed in your inventory.",
["KitGiven"] = "Starter kit granted."
}, this);
}
private string Msg(string key, string userId = null, params object[] args) =>
string.Format(lang.GetMessage(key, this, userId), args);
private void Init()
{
granted = Interface.Oxide.DataFileSystem.ReadObject<HashSet<string>>(DataFileName) ?? new HashSet<string>();
}
private object OnPlayerSpawn(BasePlayer player, Network.Connection connection)
{
if (player == null || connection == null) return null;
if (player.IsNpc) return null;
string id = player.UserIDString;
if (string.IsNullOrEmpty(id) || granted.Contains(id)) return null;
granted.Add(id);
SaveData();
NextTick(() =>
{
if (player == null || !player.IsConnected) return;
foreach (KeyValuePair<string, int> entry in config.Items)
{
Item item = ItemManager.CreateByName(entry.Key, Mathf.Max(1, entry.Value));
if (item != null)
{
player.GiveItem(item);
}
}
if (config.Announce)
{
player.ChatMessage(Msg("Welcome", id));
}
});
return null;
}
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject(DataFileName, granted);
}
private void Unload()
{
SaveData();
}
}
}The plugin tracks which Steam IDs have already received their starter kit by storing a set of IDs in oxide/data. In OnPlayerSpawn it null-checks the player, skips NPCs and disconnected clients, then gives the configured items with inventory.GiveItem on a short NextTick delay so the player entity is fully ready. It sends a chat message through the language file, adds the ID to the set and saves the data file. Returning null is implicit, so the normal spawn path still runs. Unload writes the data file one last time.
Common use cases
Starter inventory for new players
Detect first-time Steam IDs and hand out a rock, torch and food so new joiners do not stand around empty-handed.
Spawn position and state overrides
Return a value to skip vanilla spawn handling and teleport, heal or equip the player yourself. Only do this when you fully replace the spawn routine.
Greeting and server info
Send a welcome message, rules reminder or short server info string to the player as they spawn, routed through the language file for localization.
Pitfalls
Not the same as respawn
Players who die and respawn do not go through
ServerMgr.SpawnNewPlayereach time; useOnPlayerRespawnorOnPlayerRespawnedfor that flow.Returning anything skips vanilla spawn
Even returning
trueshort-circuits the rest of the method. If you return a value, ensure health, position and inventory are set yourself, or the player may end up in a broken state.Null and NPC checks
Guard against
player == nulland skip entities whereplayer.IsNpcis true, since some NPC creation can route through similar spawn code in other setups.
Build a plugin with OnPlayerSpawn
Describe what should happen and get a compiled plugin that uses this hook.
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 OnPlayerSpawn
Generate