OnBuildingSplit
OnBuildingSplit is called by ServerBuildingManager.Split each time the server carves a detached group of building blocks out of a building into a new building ID. It fires once per new building created during the split.
void OnBuildingSplit(BuildingManager.Building oldBuilding, uint newBuildingId)Parameters
| Parameter | Type | Description |
|---|---|---|
oldBuilding | BuildingManager.Building | The BuildingManager.Building that is being torn apart by the split. It still holds the blocks that remain to be processed, so its buildingBlocks list shrinks as the split loop advances. |
newBuildingId | uint | The freshly allocated building ID that the next set of connected blocks will be attached to. You can read it for logging or bookkeeping, but you cannot change it from this hook. |
Return value
The return value is ignored: the patcher continues the original method no matter what the hook returns, and Split still returns void. Returning anything has no effect on building IDs or block ownership.
How it works
The hook fires inside ServerBuildingManager.Split, which runs when a building loses blocks and the remaining pieces are no longer all connected. The server takes the first block of the old building, allocates a new building ID, fires OnBuildingSplit with the old BuildingManager.Building object and that new ID, then attaches every block reachable from the first one to the new ID. The loop repeats while the old building still has blocks, so a single break can produce several calls.
oldBuilding gives you the pre-split building object: you can read its ID, inspect buildingBlocks, and walk GetBuildingPrivilege(). newBuildingId is the identifier the next chunk will get, useful for correlating your own records with the engine's IDs. There is no return value you can use to cancel or alter the split; the hook is observational.
The hook only fires for structural recalculation, so it complements placement and upgrade hooks rather than replacing them. Keep handlers cheap because splits happen immediately after block destruction, often during raids when many blocks die in a short window.
Example plugin: Log building splits to chat for admins
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Building Split Notifier", "RustPluginGenerator", "1.0.0")]
[Description("Notifies online admins when the server splits a building into new building IDs")]
public class BuildingSplitNotifier : RustPlugin
{
private const string PermNotify = "buildingsplitnotifier.notify";
private PluginConfig config;
private readonly List<string> pendingMessages = new List<string>();
private Timer flushTimer;
private class PluginConfig
{
[JsonProperty("Minimum seconds between notifications")]
public float ThrottleSeconds = 3f;
[JsonProperty("Include block count in message")]
public bool ShowBlockCount = 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>
{
["Split"] = "Building {0} split into new building {1} ({2} blocks left).",
["SplitShort"] = "Building {0} split into new building {1}."
}, 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(PermNotify, this);
}
private void OnBuildingSplit(BuildingManager.Building oldBuilding, uint newBuildingId)
{
if (oldBuilding == null) return;
string message = config.ShowBlockCount
? Msg("Split", null, oldBuilding.ID, newBuildingId, oldBuilding.buildingBlocks?.Count ?? 0)
: Msg("SplitShort", null, oldBuilding.ID, newBuildingId);
pendingMessages.Add(message);
if (pendingMessages.Count > 20) pendingMessages.RemoveAt(0);
}
private void OnServerInitialized()
{
flushTimer?.Destroy();
flushTimer = timer.Every(Math.Max(1f, config.ThrottleSeconds), FlushMessages);
}
private void FlushMessages()
{
if (pendingMessages.Count == 0) return;
List<string> batch = new List<string>(pendingMessages);
pendingMessages.Clear();
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
if (player == null || !player.IsConnected) continue;
if (!player.IsAdmin && !permission.UserHasPermission(player.UserIDString, PermNotify)) continue;
foreach (string line in batch)
{
player.ChatMessage(line);
}
}
}
private void Unload()
{
flushTimer?.Destroy();
flushTimer = null;
pendingMessages.Clear();
}
}
}The plugin registers a permission and notifies online admins whenever the server splits a building. It stores the new building ID together with a timestamp in a small in-memory queue cleared by a repeating timer, so raids that split many buildings in a burst do not flood chat. Each notification tells the admin how many blocks the old building still holds at the moment of the call, which hints at how much of the structure is being reassigned. Messages go through the language file, and the permission prefix matches the lowercase class name so server owners can grant it with oxide.grant.
Common use cases
Raid diagnostics for staff
Tell admins when a base's connectivity breaks apart so they can watch for suspicious building patterns during reports.
Correlating building IDs in your own data
Record the new building ID alongside the old one when you persist structure data, so later saves can still match blocks to their original group.
Metrics on base integrity
Count splits per hour to see how often large compounds are being breached, then feed the numbers into a status command.
Pitfalls
It can fire several times per break
The split loop runs until the old building has no blocks left, so one collapsed section can trigger multiple calls with different new IDs. Aggregate or throttle instead of sending one message per call.
The new building may not exist yet
The building with
newBuildingIdis looked up after the hook returns, so callingBuildingManager.server.GetBuilding(newBuildingId)inside the hook can return null. Do not rely on the entity side being in place.No cancellation
The hook return value is ignored, so you cannot veto a split or merge it back. Use
OnBuildingMergefor the opposite path and keep this hook observational.
Build a plugin with OnBuildingSplit
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 OnBuildingSplit
Generate