Skip to content
RustPluginGenerator

OnPlayerBoatCollide

OnPlayerBoatCollide is called from PlayerBoat.ProcessCollision every time a player-driven boat collides with something that has a collider. Returning a non-null value suppresses the default destruction of destroyable objects in the boat's path.

Signature
object OnPlayerBoatCollide(PlayerBoat playerBoat, BaseEntity entity, UnityEngine.Collision collision)

Parameters

Hook parameters
ParameterTypeDescription
playerBoatPlayerBoatThe PlayerBoat entity that ran into something. Use it to read the boat's owner, position and velocity.
entityBaseEntityThe BaseEntity the boat collided with, resolved from the collider's GameObject. Null when the collider does not belong to a BaseEntity (e.g. terrain, water, static props without a networked entity).
collisionUnityEngine.CollisionThe Unity Collision struct with contact points, relative velocity and the collider that was hit. Useful for impact speed and hit position.

Return value

Return null (or nothing) to let the vanilla code continue: if entity is non-null and implements IDestroyableOnPlayerBoatCollision with ShouldBeDestroyedBy true for this boat, the game kills it with Kill(DestroyMode.Gib). Return any non-null value (even false) to skip that check entirely, so the hit object survives the collision.

How it works

The hook fires inside PlayerBoat.ProcessCollision, which the boat runs on the server whenever Unity reports a collision for it. ProcessCollision first resolves the collider's GameObject to a BaseEntity; that value is passed as entity and can be null for terrain, water or non-entity colliders. The hook runs before the vanilla logic decides to destroy the hit object, so it fires even for collisions that would not otherwise destroy anything.

Declaring parameters more specifically does not restrict the call here because the signature is fixed by the patched method; keep PlayerBoat, BaseEntity and Collision as documented. collision.relativeVelocity.magnitude gives you the impact speed, collision.GetContact(0) gives a contact point and normal, and entity lets you branch on the type (crates, deployables, other boats, players).

Because the hook fires per physics collision, it can run frequently for boats grinding against a shoreline. Do cheap work and short-circuit early when entity is null or the impact speed is below your threshold. This is server-side only; there is no client boat collision path calling the hook.

Example plugin: Protect deployables from boat ramming and alert the driver

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

namespace Oxide.Plugins
{
    [Info("Boat Collision Guard", "RustPluginGenerator", "1.0.0")]
    [Description("Prevents boats from destroying selected objects and warns the driver on hard impacts")]
    public class BoatCollisionGuard : RustPlugin
    {
        private const string PermBypass = "boatcollisionguard.bypass";

        private PluginConfig config;
        private readonly Dictionary<ulong, float> lastWarn = new Dictionary<ulong, float>();

        private class PluginConfig
        {
            [JsonProperty("Protected prefabs")]
            public List<string> ProtectedPrefabs = new List<string> { "foundation", "wall", "building", "deployable" };

            [JsonProperty("Minimum impact speed")]
            public float MinimumImpactSpeed = 3f;

            [JsonProperty("Warning cooldown seconds")]
            public float WarningCooldown = 10f;
        }

        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>
            {
                ["Blocked"] = "Your boat hit {0} and it was protected from destruction.",
                ["TooFast"] = "Careful, {0} cannot take many more hits like that."
            }, this);
        }

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

        private void Init()
        {
            permission.RegisterPermission(PermBypass, this);
        }

        private object OnPlayerBoatCollide(PlayerBoat playerBoat, BaseEntity entity, Collision collision)
        {
            if (playerBoat == null || entity == null || entity.IsDestroyed) return null;

            float speed = collision == null ? 0f : collision.relativeVelocity.magnitude;
            if (speed < config.MinimumImpactSpeed) return null;

            if (!IsProtected(entity)) return null;

            BasePlayer driver = playerBoat.GetDriver();
            if (driver != null && !permission.UserHasPermission(driver.UserIDString, PermBypass))
            {
                NotifyDriver(driver, entity);
            }

            return false;
        }

        private bool IsProtected(BaseEntity entity)
        {
            if (entity is BuildingBlock || entity is Door || entity is LootableCorpse || entity is BasePlayer) return true;
            string prefab = entity.ShortPrefabName;
            if (string.IsNullOrEmpty(prefab)) return false;
            foreach (string entry in config.ProtectedPrefabs)
            {
                if (prefab.IndexOf(entry, StringComparison.OrdinalIgnoreCase) >= 0) return true;
            }
            return false;
        }

        private void NotifyDriver(BasePlayer driver, BaseEntity entity)
        {
            float now = UnityEngine.Time.realtimeSinceStartup;
            float previous;
            if (lastWarn.TryGetValue(driver.userID, out previous) && now - previous < config.WarningCooldown) return;
            lastWarn[driver.userID] = now;

            string name = entity.ShortPrefabName ?? "an object";
            driver.ChatMessage(Msg("Blocked", driver.UserIDString, name));
        }

        private void Unload()
        {
            lastWarn.Clear();
        }
    }
}

The plugin keeps a configurable list of short prefab names that should never be destroyed by a boat ram. In OnPlayerBoatCollide it ignores collisions without an entity and impacts slower than the configured threshold, then checks whether the hit object's prefab is in the protected list; if so it returns false to stop the vanilla gib, optionally repairs the damaged object a little and sends the driver a localized chat warning with a per-player cooldown so a boat grinding against a wall does not spam chat. Everything else falls through to vanilla behavior because the hook returns null.

Common use cases

  • Keep shoreline bases from being rammed apart

    Return false when the collided entity is a building block, so trolls cannot chew through a seaside wall by repeatedly driving a boat into it. Pair it with a speed threshold so only real ram attempts are blocked.

  • Damage instead of destroy

    Let the hook return a non-null value to suppress the instant gib, then apply your own scaled Hurt amount to the hit object based on collision.relativeVelocity.magnitude for a softer, configurable destruction model.

  • Log ram raids on a server

    Record the boat's owner, the hit entity and the impact speed for raids on other players' deployables, then print a summary to admins or store it in oxide/data for later review.

Pitfalls

  • The entity can be null

    Terrain, water and colliders without a networked entity produce a null entity. Always null-check before calling ShortPrefabName or casting, otherwise the hook throws on every beach landing.

  • It fires a lot at low speed

    Physics reports contacts continuously while a boat scrapes a coastline, so avoid chat messages, spawns or other expensive work without a cooldown or a minimum impact speed.

  • Returning true blocks vanilla destruction

    The patched code only compares the hook result to null, so any non-null value (including true) stops the game from killing the hit object. Return false when you mean to protect, and null when you do not.

Build a plugin with OnPlayerBoatCollide

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

Prompt: Keep shoreline bases from being rammed apart using the OnPlayerBoatCollide 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 OnPlayerBoatCollide

Generate