Skip to content
RustPluginGenerator

OnPlayerBoatEditStarted

OnPlayerBoatEditStarted is called when a player starts editing their boat at a BoatBuildingStation, immediately before the game removes the original PlayerBoat entity and replaces it with a buildable boat construction.

Signature
void OnPlayerBoatEditStarted(PlayerBoat playerBoat, BoatBuildingStation boatBuildingStation)

Parameters

Hook parameters
ParameterTypeDescription
playerBoatPlayerBoatThe PlayerBoat entity that is being converted into an editable boat construction. Use it to read the owner, position, health or contents before the game destroys it.
boatBuildingStationBoatBuildingStationThe BoatBuildingStation that triggered the conversion and will take over the boat build. Read its position, owner or building privilege state here.

Return value

The return value is ignored. The game proceeds to kill the original PlayerBoat and complete the conversion regardless of what your hook method returns, so declare it void.

How it works

The hook fires inside BoatBuildingStation.ConvertPlayerBoatToConstruction, right before playerBoat.Kill() runs. That means it fires only when a player actually begins a boat edit session at a station, not when the boat is created, spawned or destroyed by other means. By the time you receive the call, the boat still exists in the world with its inventory, owner and health intact, so it is the last safe moment to inspect it.

playerBoat is the live vehicle entity: use OwnerID, transform.position, health or net.ID to identify it. boatBuildingStation is the station driving the conversion, useful for proximity checks or logging which station is in use. Declaring either parameter more generally has no practical benefit here; keep the exact types so the call is always delivered.

This is a notification hook. The conversion cannot be vetoed from here; if you need to block the edit, use CanEditPlayerBoat instead. Typical uses are logging boat edits, copying out ownership or metadata before the entity is killed, applying a cooldown, or notifying the owner and nearby players.

Example plugin: Log boat edit sessions and warn the owner

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

namespace Oxide.Plugins
{
    [Info("Boat Edit Announcer", "RustPluginGenerator", "1.0.0")]
    [Description("Counts boat edit sessions per owner and warns the player in chat")]
    public class BoatEditAnnouncer : RustPlugin
    {
        private const string DataFileName = "BoatEditAnnouncer";

        private PluginConfig config;
        private Dictionary<string, int> editCounts = new Dictionary<string, int>();

        private class PluginConfig
        {
            [JsonProperty("Warn owner in chat")]
            public bool WarnOnEdit = true;

            [JsonProperty("Log to server console")]
            public bool LogToConsole = true;
        }

        private class StoredData
        {
            [JsonProperty("Edit counts by owner id")]
            public Dictionary<string, int> Counts = new Dictionary<string, int>();
        }

        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>
            {
                ["EditStarted"] = "Your boat at {0} is now an edit station. Total edits: {1}.",
                ["ConsoleLine"] = "{0} ({1}) started a boat edit at {2}. Total edits: {3}."
            }, this);
        }

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

        private void Init()
        {
            LoadData();
        }

        private void LoadData()
        {
            var data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(DataFileName);
            editCounts = data?.Counts ?? new Dictionary<string, int>();
        }

        private void SaveData()
        {
            Interface.Oxide.DataFileSystem.WriteObject(DataFileName, new StoredData { Counts = editCounts });
        }

        private void OnPlayerBoatEditStarted(PlayerBoat playerBoat, BoatBuildingStation boatBuildingStation)
        {
            if (playerBoat == null || boatBuildingStation == null) return;

            string ownerId = playerBoat.OwnerID.ToString();
            int count;
            editCounts.TryGetValue(ownerId, out count);
            count++;
            editCounts[ownerId] = count;
            SaveData();

            Vector3 pos = playerBoat.transform.position;
            string position = $"({Mathf.RoundToInt(pos.x)}, {Mathf.RoundToInt(pos.z)})";

            BasePlayer owner = BasePlayer.FindByID(playerBoat.OwnerID);
            if (owner == null || !owner.IsConnected) return;

            if (config.WarnOnEdit)
            {
                owner.ChatMessage(Msg("EditStarted", owner.UserIDString, position, count));
            }

            if (config.LogToConsole)
            {
                Puts(string.Format(Msg("ConsoleLine"), owner.displayName, owner.UserIDString, position, count));
            }
        }

        private void Unload()
        {
            SaveData();
            editCounts?.Clear();
        }
    }
}

The plugin hooks OnPlayerBoatEditStarted and resolves the boat owner with BasePlayer.FindByID on the boat's OwnerID. It counts edits per owner in a dictionary that is written to oxide/data on every conversion and reloaded on startup, so admins can see how often a player rebuilds their boat. When the configured WarnOnEdit flag is enabled, the owner gets a chat message with their total edit count and the boat's world position, and the same information is printed as a console line so it lands in the server log. Unload saves the data and clears the dictionary.

Common use cases

  • Audit boat rebuilds

    Persist a per-owner counter of how often a PlayerBoat is converted at a station, then read the data file when investigating build abuse or dupe reports.

  • Give the owner a heads-up

    Send the owner a chat or console message that their boat is now an editable construction, including its position so they can find it again.

  • Snapshot metadata before the kill

    Read the boat's skin, health or net ID here and store it, since the PlayerBoat entity is removed immediately after the hook returns.

Pitfalls

  • The hook cannot cancel the edit

    It fires after the decision to convert has been made and the return value is discarded. Use CanEditPlayerBoat if you need to deny the action.

  • The boat is destroyed right after

    Any reference to playerBoat is invalid once the conversion finishes. Copy the values you need immediately and do not schedule timers that touch the entity.

  • OwnerID may not resolve to a player

    Boat ownership is stored as a raw ulong; the owner can be offline, banned or an entity ID. Always null-check the result of BasePlayer.FindByID before messaging.

Build a plugin with OnPlayerBoatEditStarted

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

Prompt: Audit boat rebuilds using the OnPlayerBoatEditStarted 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 OnPlayerBoatEditStarted

Generate