VehicleRedirectorAsset — Vehicle Redirectors
Migrating legacy vehicle IDs to consolidated vehicle assets while preserving paint colors requires understanding how VehicleRedirectorAsset intercepts spawn and load requests, resolves to target vehicle assets, and applies LoadPaintColor and SpawnPaintColor overrides. VehicleRedirectorAsset enables seamless transition from legacy vehicle IDs to consolidated assets. When a legacy vehicle ID is loaded or spawned, the redirector intercepts the request and creates a different (consolidated) vehicle instead, optionally preserving paint colors from the original vehicle.
Source code location: Unturned/Bundles/VehicleRedirectorAsset.cs
Inheritance Chain
Asset
→ VehicleRedirectorAssetPurpose
In earlier versions of Unturned, each color variant of a vehicle had its own item ID (e.g., Off_Roader_Orange = 4, Off_Roader_Blue = 5, etc.). When vehicles were consolidated into single assets with a paint color system, these legacy IDs needed to resolve to the new consolidated asset while preserving the original color.
A VehicleRedirectorAsset is assigned the legacy item ID. When the game attempts to load or spawn that ID:
- The redirector intercepts the request.
- The
TargetVehiclereference resolves to the consolidated vehicle asset. - If
LoadPaintColoris set, that color is applied when loading from saves. - If
SpawnPaintColoris set, that color is applied when spawning new vehicles.
Class Definition
csharp
public class VehicleRedirectorAsset : Asset
{
public override EAssetType assetCategory => EAssetType.VEHICLE;
public AssetReference<VehicleAsset> TargetVehicle { get; protected set; }
public Color32? LoadPaintColor { get; protected set; }
public Color32? SpawnPaintColor { get; protected set; }
}Core Fields
| Field | Type | .dat Key | Description |
|---|---|---|---|
TargetVehicle | AssetReference<VehicleAsset> | TargetVehicle | The consolidated vehicle to redirect to |
LoadPaintColor | Color32? | LoadPaintColor | Paint color applied when loading from save files |
SpawnPaintColor | Color32? | SpawnPaintColor | Paint color applied when spawning new vehicles |
Asset Category
csharp
public override EAssetType assetCategory => EAssetType.VEHICLE;The redirector advertises itself as EAssetType.VEHICLE so that legacy vehicle IDs resolve through the redirector in the asset registry. When the game looks up a vehicle by ID, it finds the redirector instead of the original vehicle — the redirector then resolves to the consolidated asset.
Load Paint Color
When a save file references the legacy vehicle ID, the redirector's LoadPaintColor preserves the original vehicle's appearance in the save. Without this, saved vehicles would appear with the consolidated vehicle's default random color, which might not match the original.
Spawn Paint Color
When a spawn table or world spawn references the legacy vehicle ID, SpawnPaintColor ensures newly spawned vehicles match the original color. This preserves color diversity in spawn tables — without it, all spawns of a given legacy ID would get the same random color distribution as the consolidated asset.
PopulateAsset
csharp
public override void PopulateAsset(in PopulateAssetParameters p)
{
base.PopulateAsset(in p);
TargetVehicle = p.data.readAssetReference<VehicleAsset>("TargetVehicle");
if (p.data.TryParseColor32RGB("LoadPaintColor", out Color32 loadPaintColor))
LoadPaintColor = loadPaintColor;
if (p.data.TryParseColor32RGB("SpawnPaintColor", out Color32 spawnPaintColor))
SpawnPaintColor = spawnPaintColor;
}The TargetVehicle reference is read via readAssetReference<VehicleAsset> which resolves the referenced asset by GUID or legacy ID. Both paint colors are optional — parsed via TryParseColor32RGB which only sets the value if the key exists and contains valid color data. If absent, the colors remain null and the consolidated vehicle's default paint system handles color assignment.
Redirection Flow
Vehicle Loading (from Save File)
- Save file contains a legacy vehicle ID (e.g.,
4for Off_Roader_Orange). - Asset registry resolves ID
4to theVehicleRedirectorAsset. - Redirector provides
TargetVehicle— the consolidated Off_Roader. - If
LoadPaintColoris set, that color replaces the saved color. - The consolidated vehicle is loaded with the correct paint.
Vehicle Spawning (Spawn Table / World)
- Spawn table entry references legacy vehicle ID
4. - Asset registry resolves to the redirector.
- Redirector provides the consolidated vehicle.
- If
SpawnPaintColoris set, it overrides the consolidated vehicle's default random paint. - The vehicle spawns with the preserved color.
Use Cases
Color Variant Consolidation
The primary use case: Off_Roader_Orange, Off_Roader_Blue, etc. become a single Off_Roader vehicle with paint color support. Each old ID gets a redirector pointing to the consolidated asset with the appropriate paint color.
Content Updates
When a vehicle model is updated but old saves reference the previous asset: a redirector can map the old asset to the new one while preserving appearance.
Seasonal / Event Variants
Seasonal vehicle variants (e.g., Halloween Off_Roader) can be redirected to the standard vehicle post-event, with or without preserved special colors.
Comparison to AssetConsolidation
VehicleRedirectorAsset is vehicle-specific. The more general AssetConsolidation system (in Assets.cs) handles similar mappings for generic assets through the consolidation table. The vehicle redirector exists specifically because vehicles need paint color preservation, which the generic system does not support.
| Feature | VehicleRedirectorAsset | AssetConsolidation |
|---|---|---|
| Scope | Vehicles only | All asset types |
| Paint color preservation | Yes (two modes) | No |
| Category registration | EAssetType.VEHICLE | Consolidation table |
| Runtime resolution | Through asset lookup | Through consolidation path |
Common Issues
- Missing TargetVehicle — If
TargetVehicleis null or references a missing asset, the redirector resolves to nothing. The spawn or load silently fails with no vehicle appearing. - Paint color not set — If neither
LoadPaintColornorSpawnPaintColoris set, the consolidated vehicle uses its own default paint system. The legacy vehicle's original color is lost. - Both paint colors set — Setting both
LoadPaintColorandSpawnPaintColoris valid but may be redundant if the intent is identical for load and spawn. Setting different colors for each is intentional for distinguishing between "what the vehicle looked like when saved" and "what new vehicles should look like." - Color format —
TryParseColor32RGBexpects RGB values (3 components, 0-255 range). A fourth component (alpha) is ignored. Colors specified in hex or named formats may fail to parse. - Circular redirects — A redirector whose
TargetVehicleis another redirector would create a chain. The game expects direct resolution; circular or long chains may not be validated at asset load time.
Worked Code Example: Redirector Validation
csharp
using SDG.Unturned;
using System.Collections.Generic;
public static class RedirectorValidator
{
/// <summary>
/// Validates all VehicleRedirectorAssets in the registry, detecting
/// circular chains, missing targets, and duplicate mappings that
/// could cause silent vehicle load failures.
/// </summary>
public static List<string> ValidateAllRedirectors()
{
List<string> issues = new List<string>();
Dictionary<System.Guid, VehicleRedirectorAsset> redirectors =
new Dictionary<System.Guid, VehicleRedirectorAsset>();
foreach (Asset asset in Assets.find(EAssetType.VEHICLE))
{
VehicleRedirectorAsset redirector = asset as VehicleRedirectorAsset;
if (redirector == null) continue;
if (redirector.TargetVehicle == null || redirector.TargetVehicle.isNull)
{
issues.Add($"Redirector {redirector.GUID}: TargetVehicle is null or missing");
continue;
}
// Check for circular chains
VehicleRedirectorAsset chainCheck = redirector;
for (int depth = 0; depth < 10; depth++)
{
VehicleAsset target = chainCheck.TargetVehicle.Find();
if (target is VehicleRedirectorAsset nextRedirector)
{
if (nextRedirector == redirector)
{
issues.Add($"Redirector {redirector.GUID}: Circular chain detected");
break;
}
chainCheck = nextRedirector;
}
else break;
}
}
return issues;
}
}
/// <summary>
/// Resolves a legacy vehicle ID through any redirector chain to find
/// the final consolidated VehicleAsset, applying paint color overrides
/// from each redirector in the chain.
/// </summary>
public static VehicleAsset ResolveLegacyVehicle(ushort legacyId, out Color32? paintColor)
{
paintColor = null;
VehicleRedirectorAsset redirector = Assets.find(EAssetType.VEHICLE, legacyId)
as VehicleRedirectorAsset;
while (redirector != null)
{
if (redirector.SpawnPaintColor.HasValue)
paintColor = redirector.SpawnPaintColor;
VehicleAsset target = redirector.TargetVehicle.Find();
redirector = target as VehicleRedirectorAsset;
if (redirector == null)
return target;
}
return null;
}Mermaid Diagram: Vehicle ID Resolution
Failure Modes and Common Mistakes
Redirector ID conflict — If a redirector occupies the same item ID as a real vehicle asset, the redirector wins (asset registry first-match behavior). The real vehicle becomes inaccessible. Always ensure redirector IDs are unique and do not overlap with active asset IDs.
Redirector chains breaking between updates — If the
TargetVehicleGUID changes (e.g., vehicle asset is regenerated with a new GUID), the redirector silently breaks. All legacy vehicle spawns referencing it produce no vehicle.
How This Differs from SDG Docs
- SDG docs describe redirectors as "deprecated migration code." In the SDK, redirectors are live runtime assets in the
VEHICLEcategory. They are not deprecated — they are the active mechanism for backward compatibility. - SDG docs claim redirectors only work on spawn. The documentation focuses on spawn tables. In the SDK, redirectors also handle save-file loads (
LoadPaintColor), making them critical for preserving existing player vehicles across updates.
Performance Considerations
One asset lookup per vehicle spawn or load. O(1) hash table access in the asset registry. With 200 redirector assets, a lookup is approximately 0.001ms. Paint color application is a single struct assignment. Redirector chain traversal is limited to loaded assets only, not per-frame iteration.
Deeper FAQ
Q: Can I create a redirector that maps to a custom vehicle mod?
Yes. Set the TargetVehicle to the GUID of the custom mod's VehicleAsset. The redirector bridges vanilla legacy IDs to custom replacement vehicles, useful for server-specific migration projects.
Q: What happens if both LoadPaintColor and SpawnPaintColor are null?
The consolidated vehicle uses its own default paint randomizer. For saved vehicles, the original paint color is lost — the vehicle may respawn with a random color. For spawned vehicles, they get the consolidated asset's default random color distribution.
Q: Can a redirector point to a vehicle in a different asset bundle?
Yes. AssetReference<VehicleAsset> resolves by GUID across all loaded bundles. The redirector does not need to reside in the same bundle as the target vehicle.
Cross-References
- Vehicle Asset — VehicleDefinition and Driveables — The consolidated vehicle assets that redirectors point to.
- Vehicle Physics Profile — Vehicle physics configuration that persists across redirector migrations.
- Asset Base Class and Registry — How the
EAssetType.VEHICLEcategory registration works. - Level Spawn Loading — Vehicle spawn system that triggers redirector resolution.
