OnEngineStop
OnEngineStop is called when a player requests that a boat engine be turned off, before the game actually disables it. Returning a non-null value cancels the shutdown.
object OnEngineStop(SmallEngine smallEngine, BasePlayer player)Parameters
| Parameter | Type | Description |
|---|---|---|
smallEngine | SmallEngine | The SmallEngine component being turned off. Use it to reach the parent boat via GetParentEntity(), read the owner, or compare against tracked engines. |
player | BasePlayer | The BasePlayer whose RPC requested the shutdown (the player interacting with the engine control). Can be null in edge cases, so null-check it before use. |
Return value
At the SmallEngine.TurnOff site the original method returns void and any non-null return skips the shutdown call, leaving the engine running. At VehicleEngineController.StopEngine a non-null return likewise aborts the stop sequence. Return null (or nothing) to let the engine turn off normally.
How it works
This hook fires from two places. The main one is SmallEngine.TurnOff(RPCMessage), the server-side RPC handler invoked when a player switches a boat engine off from the controls; here smallEngine is the engine and player is the caller. The second is VehicleEngineController.StopEngine, which uses the other overload OnEngineStop(BaseMountable owner) and fires on non-player-driven shutdown paths such as vehicles whose engine is stopped by code.
Because the two calls carry different argument shapes, declaring object OnEngineStop(SmallEngine engine, BasePlayer player) only receives the player-driven case. To also intercept the controller path you must declare the BaseMountable overload as well. Oxide matches parameters by type, so narrowing BasePlayer to a subclass (for example ScientistNPC) would skip ordinary player calls.
Practical use: gate engine shutdown by permission, building privilege, or combat state. Since the return value cancels the original method, the engine stays running, which can be surprising to the player, so send chat feedback from the hook.
Other signatures
Oxide also calls OnEngineStop from other places in the game with these parameter types. Declare the overload you need, or several:
object OnEngineStop(BaseMountable owner)
Example plugin: Prevent engine shutdown while the crew is in combat
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Engine Stop Guard", "RustPluginGenerator", "1.0.0")]
[Description("Blocks boat engine shutdown for a short time after a player or their boat takes damage")]
public class EngineStopGuard : RustPlugin
{
private const string PermBypass = "enginestopguard.bypass";
private PluginConfig config;
private readonly Dictionary<ulong, DateTime> combatUntil = new Dictionary<ulong, DateTime>();
private class PluginConfig
{
[JsonProperty("Combat block seconds")]
public float CombatBlockSeconds = 8f;
[JsonProperty("Block for boat owner and team")]
public bool UseTeam = 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>
{
["Blocked"] = "Engine locked in combat. Try again in {0} seconds."
}, 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(PermBypass, this);
}
private object OnEngineStop(SmallEngine engine, BasePlayer player)
{
if (engine == null || player == null || !player.IsConnected) return null;
if (permission.UserHasPermission(player.UserIDString, PermBypass)) return null;
DateTime until;
if (!combatUntil.TryGetValue(player.userID.Get(), out until) || until <= DateTime.UtcNow) return null;
double remaining = Math.Ceiling((until - DateTime.UtcNow).TotalSeconds);
player.ChatMessage(Msg("Blocked", player.UserIDString, remaining));
return true;
}
private object OnEngineStop(BaseMountable owner)
{
if (owner == null) return null;
return null;
}
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
{
if (entity == null || info == null || config.CombatBlockSeconds <= 0f) return;
var player = entity as BasePlayer;
if (player != null && !player.IsNpc)
{
MarkCombat(player.userID.Get());
if (config.UseTeam && player.currentTeam != 0)
{
var team = RelationshipManager.ServerInstance.FindTeam(player.currentTeam);
if (team != null)
foreach (var member in team.members)
MarkCombat(member);
}
return;
}
if (entity is BaseBoat)
{
ulong ownerId = entity.OwnerID;
if (ownerId != 0) MarkCombat(ownerId);
}
}
private void MarkCombat(ulong userId)
{
if (userId == 0) return;
combatUntil[userId] = DateTime.UtcNow.AddSeconds(config.CombatBlockSeconds);
}
private void Unload()
{
combatUntil.Clear();
}
}
}The plugin registers the enginestopguard.bypass permission and stores the combat hold duration in config. When OnEngineStop fires, it checks that the engine and player are valid, that the caller may bypass, and whether the player or a team member recently took damage (tracked in OnEntityTakeDamage). If combat is active, it returns true to stop the shutdown, sends the player a localized message, and tells them how long until the hold expires. The BaseMountable overload is declared so the controller path is also handled, and combat timestamps are cleared on unload. Timestamps use DateTime.UtcNow.
Common use cases
Combat lock for boat crews
Block engine shutdown for a few seconds after the boat or crew takes damage so players cannot instantly flee or kill the engine mid-fight.
Permission-gated engine control
Only allow turning an engine off for players holding a specific permission, useful on servers with shared public boats.
Audit logging of shutdowns
Record who switched off which boat engine and when by writing the call to a data file, without blocking the shutdown itself.
Pitfalls
Two overloads, one hook name
Declaring only the
(SmallEngine, BasePlayer)overload misses theVehicleEngineController.StopEnginepath. AddOnEngineStop(BaseMountable owner)if you need to block every shutdown.Null player argument
The RPC player can be null. Always test
player == null(and!player.IsConnected) before reading UserIDString or sending messages.Blocking shutdown silently
Returning non-null leaves the engine running with no built-in feedback. Send a chat reply from the hook so players understand why controls did nothing.
Build a plugin with OnEngineStop
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 OnEngineStop
Generate