Skip to content
RustPluginGenerator

CanTrainCarCouple

CanTrainCarCouple is called when a train car coupling attempts to link two cars, before the coupling is actually performed. Returning a bool overrides whether the connection is allowed.

Signature
object CanTrainCarCouple(TrainCar owner, TrainCar owner2)

Parameters

Hook parameters
ParameterTypeDescription
ownerTrainCarThe TrainCar that is trying to attach itself, i.e. the coupling vehicle that initiated the attempt.
owner2TrainCarThe TrainCar on the other side of the connection, taken from the target coupling being approached.

Return value

Return a bool to decide the coupling: false blocks the connection, true forces it to be accepted by this stage. Returning null (or any non-bool value) lets the vanilla TryCouple continue and couple normally.

How it works

Fires inside TrainCoupling.TryCouple, after the game has already checked that the car is not currently coupled and before it recurses into the other car's coupling. The two TrainCar arguments are the cars being joined: owner is the car whose coupling is doing the work, owner2 is the car on the far side. Return a bool to force the outcome; return null to let the default coupling logic run. Because Oxide checks declared parameter types, declaring TrainCar (as the signature does) always matches; narrowing is not useful here since both arguments are always train cars. The hook is only reached when a coupling interaction is actually attempted, so it fires on both the forward and reflected calls as the coupling propagates across a consist. There is no player argument, so to make decisions per player you must look at the cars themselves (owners, positions, contents) or track state elsewhere. This is the only injection site for this hook.

Example plugin: Block coupling of locked train cars

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

namespace Oxide.Plugins
{
    [Info("Train Couple Guard", "RustPluginGenerator", "1.0.0")]
    [Description("Blocks train car coupling between protected owners")]
    public class TrainCoupleGuard : RustPlugin
    {
        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Protected owner Steam IDs")]
            public List<string> ProtectedOwnerIds = new List<string>();
        }

        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);

        private bool IsProtected(TrainCar car)
        {
            if (car == null) return false;
            if (car.OwnerID == 0UL) return false;
            return config.ProtectedOwnerIds.Contains(car.OwnerID.ToString());
        }

        private object CanTrainCarCouple(TrainCar owner, TrainCar owner2)
        {
            if (owner == null || owner2 == null) return null;

            if (IsProtected(owner) || IsProtected(owner2))
            {
                return false;
            }

            return null;
        }
    }
}

The plugin tracks which cars are protected by inspecting their owner IDs: any car owned by a player listed in the config is considered locked. When CanTrainCarCouple fires, it checks both owner and owner2 against that list and returns false if either is protected, preventing the join. Because the coupling call recurses across the consist, the block is applied at every step. Config field LockedOwnerIds holds the Steam IDs to protect, and CanLootEntity-style admin commands are avoided to keep the file short. The hook itself returns null when neither car is protected so vanilla behavior is preserved.

Common use cases

  • Protect owned consists

    Prevent griefers from attaching their cars to a player-owned train by refusing the coupling when either car belongs to a protected owner.

  • Enforce coupling rules

    Allow or deny coupling based on car type, position, or current consist size to keep server rail networks manageable.

  • Event control

    Temporarily disable coupling during special train events by storing a flag and returning false while it is set.

Pitfalls

  • No player context

    The hook gives you two TrainCar objects only. If you need to attribute the action to a player, inspect the cars' OwnerID or track interactions with another hook.

  • Recursive coupling

    TryCouple recurses into the other car's coupling, so CanTrainCarCouple can fire multiple times for one apparent action. Keep the check cheap and idempotent.

  • Return type matters

    Only a bool return is honored. Returning a non-bool value is ignored and the default coupling proceeds, which is easy to do by mistake when returning objects.

Build a plugin with CanTrainCarCouple

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

Prompt: Protect owned consists using the CanTrainCarCouple 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 CanTrainCarCouple

Generate