Skip to content
RustPluginGenerator

OnPlayerDismountFailed

OnPlayerDismountFailed is called when a mounted player tries to dismount but the server rejects it because there is no valid dismount position around the mountable.

Signature
void OnPlayerDismountFailed(BasePlayer player, BaseMountable mountable)

Parameters

Hook parameters
ParameterTypeDescription
playerBasePlayerThe BasePlayer who sent the dismount request through BaseMountable.RPC_WantsDismount. May be null in edge cases, so null-check it.
mountableBaseMountableThe BaseMountable the player is currently sitting on (vehicle, horse, chair, turret seat, etc.). This is the entity whose HasValidDismountPosition check failed.

Return value

The hook is called from a void method and its return value is ignored. Returning null, true, or anything else does not force the dismount and does not change the game's decision.

How it works

The hook fires inside BaseMountable.RPC_WantsDismount, which the server receives when a seated client asks to get off. Before allowing a dismount the game calls HasValidDismountPosition(player), which looks for a free, non-blocked spot near the mountable to place the player. When that check fails, the game calls OnPlayerDismountFailed and does nothing else — the player stays mounted.

Typical triggers: the player is wedged against a wall, inside a base, under terrain, boxed in by a vehicle or another entity, or the mountable is in a location where no dismount point exists.

Both parameters are useful: player lets you notify the player or apply custom logic, and mountable identifies the seat or vehicle so you can inspect its position or type. You can declare a more specific type for the mountable (e.g. BaseVehicle, BaseBoat, Horse) to only receive calls for that entity kind; Oxide skips the hook when the argument is not an instance of the declared type.

This hook is informational only — the dismount has already failed by the time it fires. Keep heavy work out of it and avoid spamming.

Example plugin: Tell players why they cannot dismount

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

namespace Oxide.Plugins
{
    [Info("Dismount Failure Notice", "RustPluginGenerator", "1.0.0")]
    [Description("Notifies players when the server rejects their dismount because no safe spot exists.")]
    public class DismountFailureNotice : RustPlugin
    {
        private const string PermUse = "dismountfailurenotice.use";

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

        private class PluginConfig
        {
            [JsonProperty("Notice cooldown (seconds)")]
            public float Cooldown { get; set; } = 5f;

            [JsonProperty("Include mountable prefab name")]
            public bool ShowPrefab { get; set; } = 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>
            {
                ["DismountFailed"] = "You cannot dismount here - find open ground around the {0}.",
                ["DismountFailedGeneric"] = "You cannot dismount here - find open ground around your seat.",
                ["NoPermission"] = "You do not have permission to use this command."
            }, 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(PermUse, this);
        }

        private void OnPlayerDismountFailed(BasePlayer player, BaseMountable mountable)
        {
            if (player == null || mountable == null) return;
            if (!permission.UserHasPermission(player.UserIDString, PermUse)) return;

            ulong id = player.userID.Get();
            float now = Time.realtimeSinceStartup;
            float last;
            if (lastNotice.TryGetValue(id, out last) && now - last < config.Cooldown) return;
            lastNotice[id] = now;

            if (config.ShowPrefab && !string.IsNullOrEmpty(mountable.ShortPrefabName))
                player.ChatMessage(Msg("DismountFailed", player.UserIDString, mountable.ShortPrefabName.Replace(".prefab", "")));
            else
                player.ChatMessage(Msg("DismountFailedGeneric", player.UserIDString));
        }

        private void OnPlayerDisconnected(BasePlayer player)
        {
            if (player != null) lastNotice.Remove(player.userID.Get());
        }

        [ChatCommand("dismountnotice")]
        private void CmdToggle(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;
            if (!player.IsAdmin && !permission.UserHasPermission(player.UserIDString, PermUse))
            {
                player.ChatMessage(Msg("NoPermission", player.UserIDString));
                return;
            }

            if (permission.UserHasPermission(player.UserIDString, PermUse))
                permission.RevokeUserPermission(player.UserIDString, PermUse);
            else
                permission.GrantUserPermission(player.UserIDString, PermUse, this);

            player.ChatMessage("Dismount notices toggled.");
        }

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

The plugin listens for OnPlayerDismountFailed and sends the seated player a localized chat message explaining that no safe dismount spot was found. It also logs a cooldown per player so a client spamming the dismount key does not flood chat; the stored Time.realtimeSinceStartup value is compared against a configurable cooldown in seconds. The mountable prefab name is included when the config enables verbose messages. Permissions are registered so admins can toggle notifications with /dismountnotice, and all player-facing strings come from the language file.

Common use cases

  • Explain failed dismounts

    Send a short chat message telling the player to move away from walls or obstacles, which reduces confusion when they are stuck in a seat.

  • Log stuck seats

    Record the player, mountable prefab and position when dismounts fail repeatedly, so admins can find badly placed turret seats or vehicle spawns.

  • Vehicle-specific handling

    Declare a narrower mountable type such as BaseBoat or Horse to only react to failures on that entity class and leave other seats untouched.

Pitfalls

  • Do not treat it as a cancel hook

    The dismount already failed when this fires. There is no return value that forces the player off the mountable.

  • Players can spam the dismount key

    Holding the dismount button can resend the RPC repeatedly, so throttle chat output per player instead of printing on every call.

  • Null checks still matter

    Although player and mountable are usually set, check both before touching transform, displayName or UserIDString to avoid runtime errors.

Build a plugin with OnPlayerDismountFailed

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

Prompt: Explain failed dismounts using the OnPlayerDismountFailed 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 OnPlayerDismountFailed

Generate