OnTerrainCreate
OnTerrainCreate is called at the very start of TerrainGenerator.CreateTerrain, before the TerrainData, heightmap and alphamap are built and the terrain GameObject is produced.
void OnTerrainCreate(TerrainGenerator terrainGenerator)Parameters
| Parameter | Type | Description |
|---|---|---|
terrainGenerator | TerrainGenerator | The TerrainGenerator instance that is building the terrain. It is the object whose CreateTerrain method is running, so it carries the generator's settings (configuration, seed and related state) and can be inspected or stored for later use. |
Return value
The return value is ignored. Terrain generation continues unchanged whether you return null or any other value, so the method must be void and cannot cancel or alter the terrain creation.
How it works
This hook fires once per call to TerrainGenerator.CreateTerrain, which the server runs while it is constructing the terrain object (the GameObject that will carry the Terrain component and the TerrainData for the map). The call happens at the top of the method, before base map resolution, heightmap resolution, alphamap resolution and the terrainData.size based on World.Size are assigned to the new TerrainData. Because it runs first, it is a point where your plugin can read the incoming heightmapResolution and alphamapResolution values through the generator's state, capture a reference to the generator, or set up any plugin-side data that later world hooks (OnTerrainInitialized, OnWorldPrefabSpawned, OnServerInitialized) will consume. Declaring the parameter type as TerrainGenerator matches exactly the type the patch passes, so dispatch always succeeds. Declaring anything else (for example BaseEntity) means your method is never selected, since a TerrainGenerator is not that type. This hook is not a gameplay event: it does not fire per player, per entity or when terrain objects change later. It is a one-time world build notification, so heavy work here delays map load; prefer to record state and do expensive work in OnServerInitialized. Note that the hook runs whether the server is generating a fresh map or loading procedurally generated terrain data.
Example plugin: Record terrain generator seed and world size on build and report a summary on startup
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Terrain Create Reporter", "RustPluginGenerator", "1.0.0")]
[Description("Records terrain generation start and reports a summary after the server is initialised")]
public class TerrainCreateReporter : RustPlugin
{
private const string PermNotify = "terraincreatereporter.notify";
private PluginConfig config;
private bool terrainCreateSeen;
private string recordedAt = "unknown";
private uint recordedSeed;
private int recordedWorldSize;
private class PluginConfig
{
[JsonProperty("Announce terrain summary on startup")]
public bool AnnounceOnStartup { get; set; } = 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>
{
["Summary"] = "Terrain build recorded at {0} UTC. World seed {1}, size {2}.",
["NotSeen"] = "No terrain creation event was observed this boot."
}, 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 OnTerrainCreate(TerrainGenerator terrainGenerator)
{
if (terrainGenerator == null) return;
terrainCreateSeen = true;
recordedAt = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss");
recordedSeed = (uint)ConVar.Server.seed;
recordedWorldSize = Mathf.RoundToInt(World.Size);
}
private void OnServerInitialized()
{
if (!config.AnnounceOnStartup) return;
string message = terrainCreateSeen
? Msg("Summary", null, recordedAt, recordedSeed, recordedWorldSize)
: Msg("NotSeen", null);
foreach (var player in BasePlayer.activePlayerList)
{
if (player == null || !player.IsConnected) continue;
if (!permission.UserHasPermission(player.UserIDString, PermNotify)) continue;
player.ChatMessage(message);
}
}
}
}The plugin records a UTC timestamp, the server seed and the rounded world size when OnTerrainCreate fires, storing them in plugin fields. Nothing heavy runs inside the hook. Once OnServerInitialized fires, it checks whether the terrain-create event was seen, builds a chat summary from the stored data and sends it to connected players who have the terraincreatereporter.notify permission. The AnnounceOnStartup config field controls whether the summary is sent at all. Player-facing text uses the language file so admins can localise it. The hook method declares the exact TerrainGenerator type, and it null-checks the generator before reading from it.
Common use cases
Record map generation details
Store the generator reference or a snapshot of its settings so later hooks and admin commands can report how the current world was built.
Delay heavy world work
Use the event as a marker that terrain construction has begun, then schedule real work for
OnServerInitializedso map load is not slowed.Reinitialise plugin state on wipe
A new
CreateTerraincall indicates a fresh world, so plugins that cache world-derived data can flag their caches as stale.
Pitfalls
Declaring the wrong parameter type
Only
TerrainGeneratormatches the argument Oxide passes. A broader type likeobjectmay still be called, but specific unrelated types cause your method to be skipped entirely.Expecting per-frame or per-entity calls
This fires once during terrain creation, not on terrain changes, entity spawns or player events. Use
OnTerrainInitializedorOnEntitySpawnedfor those.Doing heavy work directly
The hook runs before vertex data and textures are generated, so long synchronous work here adds to map load time and can appear as a server hang on restart.
Build a plugin with OnTerrainCreate
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 OnTerrainCreate
Generate