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.

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
.datfiles).
What you'll learn
- How to spawn a vehicle at a player's position using
VehicleManager.spawnVehicle. - How to use
UnturnedPlayer.CurrentVehicleto get the vehicle a player is driving. - How to call damage and repair methods directly on the current vehicle instance.
- How to handle the
OnVehicleDamageevent. - 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
/vehiclespawn 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:
| Parameter | Type | Purpose |
|---|---|---|
amount | ushort | Raw damage amount |
multiplier | float | Damage multiplier applied to the base amount |
tracksDebugging | bool | Whether to log the damage event for debugging |
damageOrigin | out ERagdollEffect | Output 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:
| Event | Fires when | Parameter notes |
|---|---|---|
OnVehicleDamage | A vehicle takes damage | UnturnedPlayer instigator (null if environmental), InteractableVehicle target, raw damage amount, cause string |
OnVehicleDeath | A vehicle reaches zero health | UnturnedPlayer instigator (null if environmental), InteractableVehicle destroyed |
OnVehicleLockpicked | A player lockpicks a vehicle | UnturnedPlayer who lockpicked, InteractableVehicle target |
OnVehicleRepaired | A vehicle is repaired | UnturnedPlayer who repaired, InteractableVehicle target |
OnVehicleEntered | A player enters a vehicle seat | UnturnedPlayer who entered, InteractableVehicle target, byte seat index |
OnVehicleExited | A player exits a vehicle | UnturnedPlayer who exited, InteractableVehicle target, byte seat index |
OnVehicleSpawned | A vehicle is spawned into the world | InteractableVehicle 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
| Symptom | Cause | Resolution |
|---|---|---|
NullReferenceException on player.CurrentVehicle | Player not in a vehicle | Always null-check CurrentVehicle before accessing any property |
VehicleManager.spawnVehicle does nothing | Invalid vehicle asset ID | Verify 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 system | Access 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 definition | Use vehicle.health = vehicle.asset.health instead, or call repair through the vehicle's internal API |
OnVehicleDamage event not found | No such event exists in UnturnedVehicleEvents | The correct event is OnVehicleDamaged under a different namespace; check the SDG.Unturned.VehicleManager events |
| Vehicle spawns but has no health | Vehicle is spawned as dead | Set vehicle.health = vehicle.asset.health immediately after spawning |
| Vehicle disappears on restart | Spawned vehicles do not persist | Use VehicleManager.saveVehicle or a plugin-managed vehicle save/restore system |
| Vehicle teleports but passengers are left behind | Passengers not repositioned | The 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
- RocketMod and OpenMod Plugin Basics — plugin lifecycle, event subscription, permission system.
- Player Inventory — the previous article; inventory management.
- Chat Messaging — the next article; sending messages to players.
- Triggering Effects — playing effects for vehicle events.
- Teleportation — player and vehicle teleportation commands.
- Server Commands Reference — built-in vehicle commands.
- Asset Reference — vehicle asset file structure and field reference.
Document history
| Version | Date | Author | Notes |
|---|---|---|---|
| 1.0 | 2025-07-27 | 57 Studios | Initial publication. VehicleManager API, vehicle events, damage/repair, fuel management, ownership tracking, teleportation, and diagnostics. |
