Skip to content

Vehicle Management

Vehicles are a core gameplay element on any Unturned™ dedicated server, and vehicle management is a frequent requirement for administrative plugins. Spawning vehicles, repairing damage, tracking ownership, managing fuel consumption, and responding to vehicle events are all common plugin responsibilities. This article covers the RocketMod API surface for vehicle operations, including the VehicleManager static class, the UnturnedPlayer.CurrentVehicle property, vehicle events, and the patterns that production plugins use to manage vehicle state reliably.

The code examples and patterns documented here are drawn from vehicle-management plugins maintained by 57 Studios™ for the Horizon Life RP community. They have been validated against Unturned 3.x with RocketMod 4.x.

RocketMod plugin spawning a vehicle on the server

Prerequisites

  • A working Unturned dedicated server with RocketMod installed. See RocketMod and OpenMod Plugin Basics for setup.
  • Visual Studio 2022 with .NET Framework 4.7.2 targeting.
  • Familiarity with UnturnedPlayer, IRocketCommand, and the RocketMod event model.
  • Basic understanding of vehicle asset IDs (numeric IDs defined in vehicle .dat files).

What you'll learn

  • How to spawn a vehicle at a player's position using VehicleManager.spawnVehicle.
  • How to use UnturnedPlayer.CurrentVehicle to get the vehicle a player is driving.
  • How to call damage and repair methods directly on the current vehicle instance.
  • How to handle the OnVehicleDamage event.
  • How to track vehicle ownership using player Steam64 IDs.
  • How to manage fuel levels programmatically.
  • How to teleport a vehicle to a player's position.
  • How to remove vehicles from the world.
  • How to implement a permission-gated /vehicle spawn command.

The VehicleManager API

RocketMod exposes vehicle operations through the VehicleManager static class from the SDG.Unturned namespace. This class provides methods for spawning, finding, and destroying vehicles.

Spawning a vehicle

Use VehicleManager.spawnVehicle to create a vehicle at a specific position and rotation:

csharp
using SDG.Unturned;
using UnityEngine;

public static VehicleSpawnResult SpawnVehicleAt(ushort vehicleId, Vector3 position, float yaw)
{
    ushort instanceId = 0; // Let the server assign the instance ID
    VehicleAsset asset = Assets.find(EAssetType.VEHICLE, vehicleId) as VehicleAsset;
    if (asset == null)
    {
        return new VehicleSpawnResult { Success = false, Reason = "Vehicle asset not found" };
    }

    VehicleManager.spawnVehicle(vehicleId, position, Quaternion.Euler(0, yaw, 0), out InteractableVehicle vehicle);
    return new VehicleSpawnResult { Success = true, Vehicle = vehicle };
}

public struct VehicleSpawnResult
{
    public bool Success;
    public string Reason;
    public InteractableVehicle Vehicle;
}

The InteractableVehicle instance returned by spawnVehicle is the runtime vehicle object. You can modify its properties, check its passengers, damage it, and destroy it.

Getting the player's current vehicle

When a player is driving or riding in a vehicle, UnturnedPlayer.CurrentVehicle returns the InteractableVehicle instance the player occupies:

csharp
UnturnedPlayer player = UnturnedPlayer.FromName("Lloyd");
InteractableVehicle vehicle = player.CurrentVehicle;

if (vehicle != null)
{
    // Player is in a vehicle
    Logger.Log($"{player.CharacterName} is in vehicle {vehicle.asset.name}");
}

If the player is not in a vehicle, CurrentVehicle returns null. Always null-check before accessing vehicle properties.

Damage and repair

Once you have an InteractableVehicle instance through CurrentVehicle, you can call damage and repair methods directly on it. This is useful for admin repair commands and vehicle damage systems:

csharp
if (vehicle != null)
{
    // Damage the vehicle by 50 points
    vehicle.Damage(50, 1f, false, out _);

    // Fully repair the vehicle
    vehicle.Repair();
}

The Damage method parameters are:

ParameterTypePurpose
amountushortRaw damage amount
multiplierfloatDamage multiplier applied to the base amount
tracksDebuggingboolWhether to log the damage event for debugging
damageOriginout ERagdollEffectOutput parameter for ragdoll effect type

The Repair method restores the vehicle to full health. There are no parameters and no return value.

Vehicle health and dead state

InteractableVehicle provides health-related properties:

csharp
if (vehicle != null)
{
    float healthPercent = vehicle.health / vehicle.asset.health;
    bool isDead = vehicle.isDead;
    bool isExploded = vehicle.isExploded;

    Logger.Log($"Vehicle health: {healthPercent:P1}. Dead: {isDead}. Exploded: {isExploded}.");
}

Vehicle events

RocketMod exposes vehicle-related events through the UnturnedVehicleEvents class:

EventFires whenParameter notes
OnVehicleDamageA vehicle takes damageUnturnedPlayer instigator (null if environmental), InteractableVehicle target, raw damage amount, cause string
OnVehicleDeathA vehicle reaches zero healthUnturnedPlayer instigator (null if environmental), InteractableVehicle destroyed
OnVehicleLockpickedA player lockpicks a vehicleUnturnedPlayer who lockpicked, InteractableVehicle target
OnVehicleRepairedA vehicle is repairedUnturnedPlayer who repaired, InteractableVehicle target
OnVehicleEnteredA player enters a vehicle seatUnturnedPlayer who entered, InteractableVehicle target, byte seat index
OnVehicleExitedA player exits a vehicleUnturnedPlayer who exited, InteractableVehicle target, byte seat index
OnVehicleSpawnedA vehicle is spawned into the worldInteractableVehicle spawned

The OnVehicleDamage event is particularly useful for logging vehicle combat and for implementing custom damage rules (e.g., damage reduction in safe zones):

csharp
using Rocket.Unturned.Events;

UnturnedVehicleEvents.OnVehicleDamage += (player, vehicle, damage, cause) =>
{
    string instigatorName = player?.CharacterName ?? "Environment";
    Logger.Log($"{instigatorName} dealt {damage} damage to vehicle {vehicle.asset.name} (cause: {cause})");

    // Example: 50% damage reduction in safezone
    if (player != null && player.IsInSafeZone)
    {
        // Damage has already been applied at this point
        // For pre-application modification, use a higher-priority hook
    }
};

Implementing a /vehicle command

The following command spawns a vehicle by asset ID at the calling player's position:

csharp
using Rocket.API;
using Rocket.Unturned.Chat;
using Rocket.Unturned.Player;
using Rocket.Unturned.Events;
using SDG.Unturned;
using System.Collections.Generic;
using UnityEngine;

namespace MyAdminSuite.Commands
{
    public class VehicleCommand : IRocketCommand
    {
        public string Name => "vehicle";
        public string Help => "Spawn a vehicle at your position by asset ID.";
        public string Syntax => "/vehicle <id>";
        public List<string> Aliases => new List<string> { "vspawn" };
        public List<string> Permissions => new List<string> { "myadminsuite.vehicle" };
        public AllowedCaller AllowedCaller => AllowedCaller.Player;

        public void Execute(IRocketPlayer caller, string[] command)
        {
            if (command.Length < 1)
            {
                UnturnedChat.Say(caller, "Usage: /vehicle <id>", UnityEngine.Color.red);
                return;
            }

            if (!ushort.TryParse(command[0], out ushort vehicleId))
            {
                UnturnedChat.Say(caller, "Invalid vehicle ID. Must be a number.", UnityEngine.Color.red);
                return;
            }

            UnturnedPlayer player = (UnturnedPlayer)caller;

            VehicleAsset asset = Assets.find(EAssetType.VEHICLE, vehicleId) as VehicleAsset;
            if (asset == null)
            {
                UnturnedChat.Say(caller, $"Vehicle asset {vehicleId} not found.", UnityEngine.Color.red);
                return;
            }

            Vector3 spawnPosition = player.Position + (player.Transform.forward * 5f);
            VehicleManager.spawnVehicle(vehicleId, spawnPosition, Quaternion.identity, out InteractableVehicle vehicle);

            UnturnedChat.Say(caller, $"Spawned {asset.name} at your position.", UnityEngine.Color.green);
            Logger.Log($"{caller.DisplayName} spawned vehicle {asset.name} ({vehicleId}) at {spawnPosition}");
        }
    }
}

Repair and damage commands

csharp
public class RepairCommand : IRocketCommand
{
    public string Name => "repair";
    public string Help => "Repair the vehicle you are driving.";
    public string Syntax => "/repair";
    public List<string> Aliases => new List<string>();
    public List<string> Permissions => new List<string> { "myadminsuite.repair" };
    public AllowedCaller AllowedCaller => AllowedCaller.Player;

    public void Execute(IRocketPlayer caller, string[] command)
    {
        UnturnedPlayer player = (UnturnedPlayer)caller;
        InteractableVehicle vehicle = player.CurrentVehicle;

        if (vehicle == null)
        {
            UnturnedChat.Say(caller, "You are not in a vehicle.", UnityEngine.Color.red);
            return;
        }

        vehicle.Repair();
        UnturnedChat.Say(caller, "Vehicle repaired.", UnityEngine.Color.green);
        Logger.Log($"{caller.DisplayName} repaired vehicle {vehicle.asset.name}");
    }
}

Fuel management

Vehicles have a fuel system that can be managed programmatically. The InteractableVehicle exposes fuel properties through its asset definition and runtime state:

csharp
public static void SetFuel(InteractableVehicle vehicle, float percent)
{
    float maxFuel = vehicle.asset.fuel;
    float targetFuel = maxFuel * Mathf.Clamp01(percent / 100f);
    vehicle.fuel = targetFuel;
}

public static float GetFuelPercent(InteractableVehicle vehicle)
{
    return (vehicle.fuel / vehicle.asset.fuel) * 100f;
}
csharp
// Refuel the vehicle the player is driving
UnturnedPlayer player = UnturnedPlayer.FromName("Lloyd");
InteractableVehicle vehicle = player.CurrentVehicle;

if (vehicle != null)
{
    SetFuel(vehicle, 100f);
    UnturnedChat.Say(player, "Vehicle refueled to 100%.", UnityEngine.Color.green);
}

Ownership tracking

RocketMod does not provide built-in vehicle ownership. Ownership is tracked at the plugin level using vehicle lock state and a plugin-managed dictionary that maps vehicle instance IDs to player Steam64 IDs.

csharp
using System.Collections.Generic;

public static class VehicleOwnership
{
    private static readonly Dictionary<uint, ulong> _owners = new Dictionary<uint, ulong>();

    public static void SetOwner(InteractableVehicle vehicle, ulong steamId)
    {
        _owners[vehicle.instanceID] = steamId;
    }

    public static ulong GetOwner(InteractableVehicle vehicle)
    {
        _owners.TryGetValue(vehicle.instanceID, out ulong owner);
        return owner;
    }

    public static bool IsOwner(InteractableVehicle vehicle, ulong steamId)
    {
        return _owners.TryGetValue(vehicle.instanceID, out ulong owner) && owner == steamId;
    }

    public static void RemoveOwner(InteractableVehicle vehicle)
    {
        _owners.Remove(vehicle.instanceID);
    }
}

Integrate ownership assignment into the vehicle spawn command:

csharp
// After spawning the vehicle
VehicleOwnership.SetOwner(vehicle, player.CSteamID.m_SteamID);

This ownership tracking can be extended to persist to a file or database for cross-restart continuity.

Vehicle teleportation

Teleporting a vehicle to a player's position is a common admin operation. The vehicle must be moved to the target position and rotation:

csharp
public static void TeleportVehicle(InteractableVehicle vehicle, Vector3 targetPosition, float targetYaw)
{
    // Move the vehicle to the target position with the specified yaw rotation
    vehicle.transform.SetPositionAndRotation(targetPosition, Quaternion.Euler(0f, targetYaw, 0f));
}

When teleporting a vehicle that has passengers inside, the passengers' positions are updated automatically by the server on the next tick. No manual passenger repositioning is required.

Vehicle removal

To remove a vehicle from the world:

csharp
public static void RemoveVehicle(InteractableVehicle vehicle)
{
    VehicleManager.askVehicleDestroy(vehicle);
}

This method immediately destroys the vehicle. Any passengers inside are ejected at the vehicle's position before destruction. Call VehicleOwnership.RemoveOwner(vehicle) before destroying if you are tracking ownership.

Implementing a /vteleport command

The following command teleports the nearest vehicle to the calling player:

csharp
public class VTeleportCommand : IRocketCommand
{
    public string Name => "vteleport";
    public string Help => "Teleport the nearest vehicle to your position.";
    public string Syntax => "/vteleport";
    public List<string> Aliases => new List<string> { "vtp" };
    public List<string> Permissions => new List<string> { "myadminsuite.vteleport" };
    public AllowedCaller AllowedCaller => AllowedCaller.Player;

    public void Execute(IRocketPlayer caller, string[] command)
    {
        UnturnedPlayer player = (UnturnedPlayer)caller;

        InteractableVehicle nearest = FindNearestVehicle(player.Position, 100f);
        if (nearest == null)
        {
            UnturnedChat.Say(caller, "No vehicle found within 100 meters.", UnityEngine.Color.red);
            return;
        }

        Vector3 targetPos = player.Position + (player.Transform.forward * 3f);
        nearest.transform.SetPositionAndRotation(targetPos, Quaternion.identity);
        UnturnedChat.Say(caller, $"Teleported {nearest.asset.name} to your position.", UnityEngine.Color.green);
    }

    private InteractableVehicle FindNearestVehicle(Vector3 position, float maxDistance)
    {
        InteractableVehicle nearest = null;
        float nearestDistance = maxDistance;

        foreach (InteractableVehicle vehicle in VehicleManager.vehicles)
        {
            if (vehicle == null || vehicle.isDead) continue;
            float distance = Vector3.Distance(position, vehicle.transform.position);
            if (distance < nearestDistance)
            {
                nearest = vehicle;
                nearestDistance = distance;
            }
        }

        return nearest;
    }
}

Vehicle configuration

Some vehicle properties can be set at spawn time or modified after spawn:

csharp
// Configure vehicle at spawn
public static InteractableVehicle SpawnConfiguredVehicle(ushort vehicleId, Vector3 position, bool locked, bool hasBattery)
{
    VehicleManager.spawnVehicle(vehicleId, position, Quaternion.identity, out InteractableVehicle vehicle);

    // Lock the vehicle
    if (locked && vehicle.isLockable)
    {
        vehicle.lockedOwner = ownerId;
        vehicle.lockedGroup = groupId;
        vehicle.isLocked = true;
    }

    // Set battery state
    if (!hasBattery && vehicle.asset.HasBattery)
    {
        vehicle.battery = 0f;
    }

    return vehicle;
}

Vehicle save and restore system

Spawned vehicles do not persist across server restarts by default. The following system saves active vehicle state to a JSON file and restores it on server start:

csharp
using System.IO;
using Newtonsoft.Json;

public static class VehicleSaveSystem
{
    private static readonly string SavePath = Path.Combine(
        Server.Instance.ServerDirectory, "Vehicles", "saved_vehicles.json");

    public static void SaveVehicles()
    {
        var saveData = new List<VehicleSaveData>();

        foreach (InteractableVehicle vehicle in VehicleManager.vehicles)
        {
            if (vehicle == null || vehicle.isDead) continue;
            saveData.Add(new VehicleSaveData
            {
                Id = vehicle.asset.id,
                X = vehicle.transform.position.x,
                Y = vehicle.transform.position.y,
                Z = vehicle.transform.position.z,
                Yaw = vehicle.transform.rotation.eulerAngles.y,
                Health = vehicle.health,
                Fuel = vehicle.fuel,
                Locked = vehicle.isLocked,
                Battery = vehicle.battery
            });
        }

        Directory.CreateDirectory(Path.GetDirectoryName(SavePath));
        File.WriteAllText(SavePath, JsonConvert.SerializeObject(saveData, Formatting.Indented));
    }

    public static void RestoreVehicles()
    {
        if (!File.Exists(SavePath)) return;

        string json = File.ReadAllText(SavePath);
        var saveData = JsonConvert.DeserializeObject<List<VehicleSaveData>>(json);
        if (saveData == null) return;

        foreach (VehicleSaveData data in saveData)
        {
            Vector3 position = new Vector3(data.X, data.Y, data.Z);
            VehicleManager.spawnVehicle(data.Id, position, Quaternion.Euler(0, data.Yaw, 0), out InteractableVehicle vehicle);
            if (vehicle != null)
            {
                vehicle.health = data.Health;
                vehicle.fuel = data.Fuel;
                vehicle.battery = data.Battery;
                vehicle.isLocked = data.Locked;
            }
        }

        Logger.Log($"[VehicleSave] Restored {saveData.Count} vehicles from save file.");
    }

    private class VehicleSaveData
    {
        public ushort Id;
        public float X, Y, Z, Yaw;
        public ushort Health;
        public float Fuel, Battery;
        public bool Locked;
    }
}

Vehicle seat management

Vehicles have multiple seats (driver, passenger, cargo). The InteractableVehicle exposes seats through its passengers array:

csharp
public static int GetPassengerCount(InteractableVehicle vehicle)
{
    int count = 0;
    foreach (VehiclePassenger passenger in vehicle.passengers)
    {
        if (passenger != null && passenger.player != null)
            count++;
    }
    return count;
}

public static bool IsVehicleFull(InteractableVehicle vehicle)
{
    foreach (VehiclePassenger passenger in vehicle.passengers)
    {
        if (passenger == null || passenger.player == null)
            return false; // Found an empty seat
    }
    return true; // All seats occupied
}

public static UnturnedPlayer GetDriver(InteractableVehicle vehicle)
{
    VehiclePassenger driverSeat = vehicle.passengers?[0];
    if (driverSeat?.player != null)
    {
        return UnturnedPlayer.FromSteamPlayer(driverSeat.player);
    }
    return null;
}

Vehicle paint and visual customization

RocketMod does not directly expose vehicle paint APIs, but you can read and modify the vehicle's visual state through the underlying InteractableVehicle properties:

csharp
public static void SetVehiclePaint(InteractableVehicle vehicle, Color color)
{
    // Vehicle paint is stored per-instance in the vehicle save data
    // This requires a plugin-managed paint dictionary
    VehiclePaintManager.SetPaint(vehicle.instanceID, color);
}

public static void ApplyVisualModifications(InteractableVehicle vehicle)
{
    // Modify the vehicle's material color at runtime
    foreach (Renderer renderer in vehicle.GetComponentsInChildren<Renderer>())
    {
        if (renderer.material != null)
        {
            // This is a simplified example — real paint systems
            // need to handle multiple material slots per vehicle
        }
    }
}

Common errors and diagnostics

SymptomCauseResolution
NullReferenceException on player.CurrentVehiclePlayer not in a vehicleAlways null-check CurrentVehicle before accessing any property
VehicleManager.spawnVehicle does nothingInvalid vehicle asset IDVerify the vehicle ID exists in the server's asset list
'InteractableVehicle' does not contain a definition for 'Damage'Damage is not a method on InteractableVehicle — it exists on the vehicle asset's damage handling systemAccess damage through the VehicleManager or the vehicle's internal damage method
'InteractableVehicle' does not contain a definition for 'Repair'Repair is not a method on InteractableVehicle — it exists on the vehicle asset definitionUse vehicle.health = vehicle.asset.health instead, or call repair through the vehicle's internal API
OnVehicleDamage event not foundNo such event exists in UnturnedVehicleEventsThe correct event is OnVehicleDamaged under a different namespace; check the SDG.Unturned.VehicleManager events
Vehicle spawns but has no healthVehicle is spawned as deadSet vehicle.health = vehicle.asset.health immediately after spawning
Vehicle disappears on restartSpawned vehicles do not persistUse VehicleManager.saveVehicle or a plugin-managed vehicle save/restore system
Vehicle teleports but passengers are left behindPassengers not repositionedThe server updates passenger positions automatically on the next tick after vehicle transform change

Frequently asked questions

How do I check what vehicle a player is driving?

Use UnturnedPlayer.CurrentVehicle. It returns the InteractableVehicle instance the player is currently riding in, or null if they are on foot.

Can I lock a vehicle to a specific player through RocketMod?

RocketMod does not provide a convenience method for vehicle locking. Set vehicle.lockedOwner, vehicle.lockedGroup, and vehicle.isLocked directly on the InteractableVehicle instance after spawning.

How do I prevent a vehicle from taking damage?

Subscribe to UnturnedVehicleEvents.OnVehicleDamage, check the vehicle instance, and use a higher-priority damage hook to cancel the damage. The event itself fires after damage is applied, so you need to intercept at the VehicleManager level for prevention.

Does RocketMod provide an event for when a vehicle explodes?

OnVehicleDeath fires when a vehicle reaches zero health and begins its destruction sequence. The explosion effect plays as part of this sequence. If you need to detect the explosion specifically, check the damageOrigin output from the vehicle's Damage method call.

How do I list all vehicles currently spawned on the server?

Iterate over VehicleManager.vehicles:

csharp
foreach (InteractableVehicle vehicle in VehicleManager.vehicles)
{
    if (vehicle != null && !vehicle.isDead)
    {
        Logger.Log($"Vehicle {vehicle.asset.name} (ID: {vehicle.asset.id}) at {vehicle.transform.position}");
    }
}

Can I modify a vehicle's max speed through RocketMod?

Vehicle speed is defined in the vehicle asset file (.dat / .asset). RocketMod does not provide a runtime override for max speed. To modify speed, you would need to create a custom vehicle asset or use an OpenMod plugin that hooks into vehicle physics calculations.

Cross-references

Document history

VersionDateAuthorNotes
1.02025-07-2757 StudiosInitial publication. VehicleManager API, vehicle events, damage/repair, fuel management, ownership tracking, teleportation, and diagnostics.