OnCargoShipHarborApproach
OnCargoShipHarborApproach is called when a CargoShip begins its approach into a harbor, right before the horn plays and the approach state is set.
object OnCargoShipHarborApproach(CargoShip cargoShip, CargoNotifier cn)Parameters
| Parameter | Type | Description |
|---|---|---|
cargoShip | CargoShip | The CargoShip entity that is beginning its harbor approach. Use net.ID.Value as a stable identifier or transform.position for location. |
cn | CargoNotifier | The CargoNotifier that triggered the approach, normally the harbor's notifier. Useful for logging which harbor/notification source is involved; it can be null, so check before use. |
Return value
Returning a non-null value cancels the original approach: the method returns immediately, so the horn does not play and the ship is never flagged as isDoingHarborApproach. Returning null lets the normal approach proceed.
How it works
This hook fires from CargoShip.StartHarborApproach, which runs when the cargo ship's AI decides to enter a harbor and hands off to the notifier cn. It runs before PlayHorn() and before isDoingHarborApproach is set, so at call time the ship is not yet flagged as approaching. Use it to react to incoming events, adjust difficulty, or gate the approach entirely.
The cargoShip parameter gives you the entity: its position, owner, and flags. The cn (CargoNotifier) tells you which notifier is driving the approach; it may be null in edge cases, so null-check nested members.
Declaring a narrower parameter type is not useful here because there is exactly one injection site passing a CargoShip and a CargoNotifier. A BaseEntity declaration would still receive the call, but cargoShip as CargoShip gives you the specific API.
Because it fires once per approach, lightweight work (announcements, logging, spawning markers) is safe. Avoid expensive loops unless you are certain how many ships are active.
Example plugin: Announce cargo ship harbor approaches and block them via config
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Cargo Ship Approach Announcer", "RustPluginGenerator", "1.0.0")]
[Description("Announces cargo ship harbor approaches and can optionally block them.")]
public class CargoShipApproachAnnouncer : RustPlugin
{
private const string PermNotify = "cargoshipapproachannouncer.notify";
private PluginConfig config;
private float lastAnnouncement;
private const float AnnounceCooldown = 5f;
private class PluginConfig
{
[JsonProperty("Announce approaches to all players")]
public bool Announce = true;
[JsonProperty("Block approaches entirely")]
public bool BlockApproaches = false;
}
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>
{
["ApproachBlocked"] = "A cargo ship attempted a harbor approach but it was blocked.",
["ApproachInbound"] = "Cargo ship approaching the harbor near {0}."
}, 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 object OnCargoShipHarborApproach(CargoShip cargoShip, CargoNotifier cn)
{
if (cargoShip == null || cargoShip.IsDestroyed)
return null;
if (config.BlockApproaches)
{
Server.Broadcast(Msg("ApproachBlocked"));
return true;
}
if (!config.Announce)
return null;
if (UnityEngine.Time.realtimeSinceStartup - lastAnnouncement < AnnounceCooldown)
return null;
lastAnnouncement = UnityEngine.Time.realtimeSinceStartup;
var pos = cargoShip.transform.position;
string grid = MapHelper.PositionToString(pos);
Server.Broadcast(Msg("ApproachInbound", null, grid));
return null;
}
}
}The plugin listens on OnCargoShipHarborApproach. When a ship begins approaching, it reads the config to decide whether approaches are allowed. If BlockApproaches is true, it broadcasts a localized warning and returns a non-null value, which prevents the horn and approach state from being set. Otherwise it broadcasts the ship's map position so players know an event is starting. A short cooldown timestamp avoids duplicate announcements if multiple notifiers fire in quick succession. All player-facing text goes through the language file so admins can translate it.
Common use cases
Event countdowns
Start a timed countdown or spawn a UI banner when a cargo ship is inbound, using the ship position for a grid marker.
Scheduled difficulty
Only allow approaches during configured hours by returning non-null outside the window, keeping the ship offshore.
Logging and analytics
Record the ship ID, position and notifier to a data file so admins can audit how often harbor events occur.
Pitfalls
Cancelling skips the horn and state
Returning non-null stops the method before
PlayHorn()and beforeisDoingHarborApproachis set, so the ship will not register as approaching; it may retry or remain adrift depending on its AI.Notifier can be null
The
cnCargoNotifier may be missing in some call paths. Always null-check it before reading members or logging.Avoid heavy work here
This runs once per approach, but the method is on the ship AI thread path. Keep handlers short and defer long operations to timers.
Build a plugin with OnCargoShipHarborApproach
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 OnCargoShipHarborApproach
Generate