ItemBarricadeAsset — Placeable Barricade Definition
Advanced25-30 minutesWindowsVisual Studio
Overview
ItemBarricadeAsset is the primary placeable item class for smaller world objects in Unturned. It inherits from ItemPlaceableAsset (salvage, destroy drops, crafting tags, armor falloff), which inherits from ItemAsset and implements IArmorFalloff. Barricades encompass an enormous range of placed objects: walls, doors, storage crates, furniture, lights, signs, stereos, beds, mannequins, vehicles, farms, sentries, generators, traps, and explosive charges.
The class is the largest non-weapon asset at 605 lines. Its defining feature is the EBuild discriminant (30+ values) that controls state byte layout, placement behavior, and runtime interaction. Specialized subclasses like ItemStorageAsset, ItemFarmAsset, ItemSentryAsset, ItemGeneratorAsset, ItemTrapAsset, and ItemChargeAsset further extend specific build types.
Source code location: Unturned/Bundles/ItemBarricadeAsset.cs (605 lines), inheriting from ItemPlaceableAsset.cs (454 lines), and ItemAsset.cs (base).
Inheritance Chain
ItemAsset → IArmorFalloff
└─ ItemPlaceableAsset — salvage, destroy drops, crafting tags, armor falloff
└─ ItemBarricadeAsset — EBuild system, health, placement, explosion
├─ ItemStorageAsset — inventory grid
│ └─ ItemSentryAsset — sentry turret
├─ ItemFarmAsset — crop growth
├─ ItemGeneratorAsset — fuel-powered generator
├─ ItemTrapAsset — proximity/powered trap
└─ ItemChargeAsset — explosive chargeEBuild Type System
The build field (type EBuild) is the primary discriminator of barricade function. There are 30+ EBuild values, each with a specific state byte layout and interaction model.
State Byte Layouts by Build Type
| EBuild Value | State Size | Contents |
|---|---|---|
DOOR, GATE, SHUTTER, HATCH | 17 bytes | Owner (8) + Group (8) + Interact (1) |
BED | 8 bytes | Owner only |
FARM | 4 bytes | Spawn time (uint) |
TORCH, CAMPFIRE, OVEN, SPOT, SAFEZONE, OXYGENATOR, BARREL_RAIN, CAGE | 1 byte | Lit/activated state |
OIL | 2 bytes | Oil amount |
SIGN, SIGN_WALL, NOTE | 17 bytes | Owner + Group + Text length |
STEREO | 17 bytes | Song GUID (16) + Volume (1) |
MANNEQUIN | 73 bytes | Owner + Cosmetics (28) + Items (21) + States (7) |
STORAGE, STORAGE_WALL | 17 bytes | Owner + Group + Interact |
CHARGE | 17 bytes | Owner + Group + Interact |
VEHICLE | Minimal | No placement state |
| Other | 0 bytes | No state |
getState Implementation
csharp
public override byte[] getState(EItemOrigin origin)
{
if (build == EBuild.DOOR || build == EBuild.GATE || build == EBuild.SHUTTER || build == EBuild.HATCH)
return new byte[17];
else if (build == EBuild.BED)
return new byte[8];
else if (build == EBuild.FARM)
{
byte[] newState = new byte[4];
System.BitConverter.TryWriteBytes(newState, Provider.time);
return newState;
}
else if (build == EBuild.TORCH || build == EBuild.CAMPFIRE || build == EBuild.OVEN
|| build == EBuild.SPOT || build == EBuild.SAFEZONE || build == EBuild.OXYGENATOR
|| build == EBuild.BARREL_RAIN || build == EBuild.CAGE)
return new byte[1];
else if (build == EBuild.OIL)
return new byte[2];
else if (build == EBuild.SIGN || build == EBuild.SIGN_WALL || build == EBuild.NOTE)
return new byte[17];
else if (build == EBuild.STEREO)
return new byte[17];
else if (build == EBuild.MANNEQUIN)
return new byte[73];
else
return new byte[0];
}FARM state note: As of 2024-02-05, FARM state defaults to the current Provider.time (Unix timestamp) rather than zeroes. This allows plants spawned by default to grow properly without needing a manual planting interaction (public issue #4320).
State Byte Breakdown — 17-Byte Types
Bytes 0-7: Owner SteamID (ulong, 8 bytes)
Bytes 8-15: Group SteamID (ulong, 8 bytes)
Byte 16: Interact state (0=closed/off, 1=open/on)Used by: DOOR, GATE, SHUTTER, HATCH, SIGN, SIGN_WALL, NOTE, STEREO, STORAGE, STORAGE_WALL.
State Byte Breakdown — MANNEQUIN (73 bytes)
Bytes 0-15: Owner (16 bytes for extended SteamID)
Bytes 16-43: Cosmetic item IDs (28 bytes = 14 ushort values)
Bytes 44-64: Equipment item IDs + quality (21 bytes)
Bytes 65-71: Zero-length state placeholders (7 bytes)Core Properties
| Field | Type | .dat Key | Default | Description |
|---|---|---|---|---|
_health | ushort | Health | — | Maximum hit points (max 65,535) |
_range | float | Range | — | Interaction/placement range in meters |
_radius | float | Radius | — | Sphere overlap radius for placement validation |
_offset | float | Offset | — | Surface offset for placement from surface normal |
armorTier | EArmorTier | Armor_Tier | LOW/HIGH by name | Damage resistance tier |
canBeDamaged | bool | Can_Be_Damaged | true | Whether damage is applied at all |
eligibleForPooling | bool | Eligible_For_Pooling | true (false for BEACON) | Object pool eligibility |
isLocked | bool | Locked | false | Supports locking with key |
isVulnerable | bool | Vulnerable | false | Can be damaged (flag-based) |
isRepairable | bool | Unrepairable (inverted) | true | Can be repaired |
proofExplosion | bool | Proof_Explosion | false | Explosion immunity |
isUnpickupable | bool | Unpickupable | false | Cannot be salvaged at all |
isSalvageable | bool | Unsalvageable (inverted) | true | Can be salvaged |
isSaveable | bool | Unsaveable (inverted) | true | Persists between sessions |
bypassClaim | bool | Bypass_Claim | false (true for CHARGE) | Ignores building claim checks |
shouldBypassPickupOwnership | bool | Bypass_Pickup_Ownership | false (true for CHARGE) | Bypasses pickup ownership |
AllowPlacementInsideClipVolumes | bool | Allow_Placement_Inside_Clip_Volumes | false (true for CHARGE) | Can be placed OOB |
allowPlacementOnVehicle | bool | Allow_Placement_On_Vehicle | Varies by build | Can place on vehicle surface |
salvageDurationMultiplier | float | Salvage_Duration_Multiplier | 1.0 | Time multiplier for salvage action |
allowCollisionWhileAnimating | bool | Allow_Collision_While_Animating | false | Keep colliders during animation |
useWaterHeightTransparentSort | bool | Use_Water_Height_Transparent_Sort | false | Special water rendering |
CanParentVehicleBePickedUp | bool | CanParentVehicleBePickedUp | false | Allow vehicle hook pickup |
Armor Tier Resolution
csharp
if (p.data.ContainsKey("Armor_Tier"))
{
armorTier = (EArmorTier) System.Enum.Parse(typeof(EArmorTier),
p.data.GetString("Armor_Tier"), true);
}
else
{
if (name.Contains("Metal"))
armorTier = EArmorTier.HIGH;
else
armorTier = EArmorTier.LOW;
}| Condition | Armor Tier |
|---|---|
.dat sets Armor_Tier | Uses specified value |
Asset name contains "Metal" | HIGH |
| Otherwise | LOW |
Bypass_Claim Evolution
The bypassClaim field has evolved through three parsing strategies:
csharp
if (p.data.TryParseBool("Bypass_Claim", out bool bypassClaimValue))
_bypassClaim = bypassClaimValue;
else if (p.data.ContainsKey("Bypass_Claim"))
_bypassClaim = true;
else
_bypassClaim = build == EBuild.CHARGE;| Era | Logic | Effect |
|---|---|---|
| Pre-2024 | Flag only (ContainsKey) | Presence = bypass, absent = check |
| 2024-09-18 | Bool + flag fallback | true/false values supported |
| Default | CHARGE build type | Charges always bypass unless explicitly set to false |
Placement Validation
Radius/Offset Wiggle Room
csharp
if (radius > 0.05f && Mathf.Abs(radius - offset) < 0.05f)
{
_radius -= 0.05f;
}When the sphere overlap radius is within 0.05 meters of the surface offset, the radius is reduced by 0.05. This gives barricades "wiggle room" — without it, a tight-fitting barricade would block its own placement because the overlap sphere would detect the barricade itself.
Placement Process
- Surface detection: Raycast from player camera finds target surface within
rangedistance - Obstruction check:
Physics.OverlapSphereat placement position usingradius - Support check: If other barricades/structures overlap, placement is blocked (unless
Bypass_Claim) - Offset application:
offsetapplied from surface normal for final position - Safezone check:
canBeUsedInSafezoneverifies building permissions - Claim check: Building claim system verifies player permissions
allowPlacementOnVehicle Default
csharp
bool defaultAllowPlacementOnVehicle =
build != EBuild.BED && build != EBuild.SENTRY && build != EBuild.SENTRY_FREEFORM;Beds and sentries cannot be placed on most vehicles by default.
Explosion Effect
csharp
_explosion = p.data.ParseGuidOrLegacyId("Explosion", out _explosionGuid);| .dat Key | Type | Purpose |
|---|---|---|
Explosion | GUID or legacy ID | EffectAsset played when barricade is destroyed |
csharp
public EffectAsset FindExplosionEffectAsset()
{
return Assets.FindEffectAssetByGuidOrLegacyId(_explosionGuid, _explosion);
}The FindExplosionEffectAsset helper resolves the effect from either GUID or legacy ID. This is the destruction visual/audio effect.
Vehicle Barricades
When build == EBuild.VEHICLE, the barricade acts as a vehicle spawner:
csharp
if (build == EBuild.VEHICLE)
{
// Sigh.
_vehicleId = _explosion;
_vehicleGuid = _explosionGuid;
}The vehicle GUID is stored in the _explosion fields — a historical field reuse noted with "Sigh." in the source. The vehicle asset is resolved via FindVehicleAsset():
csharp
internal Asset FindVehicleAsset()
{
return Assets.FindBaseVehicleAssetByGuidOrLegacyId(_vehicleGuid, _vehicleId);
}The returned asset may be a VehicleRedirectorAsset (for paint color overrides) rather than a direct VehicleAsset. The vehicle spawner handles the redirect.
Auto Heat Source Crafting Tag
Barricades with Fire child transforms get automatic heat source crafting tag provisioning for ovens, torches, and campfires (build is OVEN, TORCH, or CAMPFIRE):
- Checks
RequiresHeatSourceCraftingTagConversion(defaulttrue) - Finds the
Firechild transform on the barricade prefab - Adds
CraftingTagModifierComponentto the Fire transform (removes Heat Source tag when fire effect is inactive) - Adds
CraftingTagProviderComponentto the barricade root (provides the tag)
The modifier GUID is hardcoded: "20f30322bbcc4b01a4f116d22b24c21a" (the vanilla Heat Source crafting tag).
This automatic system means oven/torch/campfire mods do not need to manually configure crafting tags — the system detects the Fire transform and sets up the tag pipeline automatically.
Prefab Loading — Clip vs Barricade
The barricade prefab loading has a server optimization path:
csharp
hasClipPrefab = p.data.ParseBool("Has_Clip_Prefab", defaultValue: true);
if (Dedicator.IsDedicatedServer && hasClipPrefab)
{
_barricade = p.bundle.load<GameObject>("Clip");
if (barricade == null)
{
shouldLoadBarricadePrefab = true;
Assets.ReportError(this, "missing \"Clip\" GameObject, loading \"Barricade\" GameObject instead");
}
else
shouldLoadBarricadePrefab = false;
}
else
shouldLoadBarricadePrefab = true;
if (shouldLoadBarricadePrefab)
{
_barricade = p.bundle.load<GameObject>("Barricade");
// ... validation and optimization
}| Condition | Prefab loaded |
|---|---|
| Client | "Barricade" (full visual prefab) |
| Dedicated server, has Clip | "Clip" (optimized, no visual details) |
| Dedicated server, no Clip | "Barricade" then optimized via ServerPrefabUtil |
The Clip prefab is a lighter version for server authority (collision only, no rendering). If unavailable, the full prefab is loaded and client components are stripped.
CanParentVehicleBePickedUp Compatibility
The .dat key for this field had a mid-development rename:
csharp
if (p.data.ContainsKey("CanVehicleHookWhileAttached"))
CanParentVehicleBePickedUp = p.data.ParseBool("CanVehicleHookWhileAttached");
else
CanParentVehicleBePickedUp = p.data.ParseBool("CanParentVehicleBePickedUp");The 3.24.7.0 update mistakenly documented the new name while the .dat property was still called CanVehicleHookWhileAttached. The code supports both names for backward compatibility. CanVehicleHookWhileAttached is checked first; if absent, CanParentVehicleBePickedUp is used.
Leftover Properties
Additional properties with less common usage:
| Field | .dat Key | Default | Purpose |
|---|---|---|---|
_nav | Nav (GameObject) | — | Navigation mesh override |
_use | Use / PlacementAudioClip (AudioClip) | — | Placement/use sound |
placementPreviewRef | PlacementPreviewPrefab | — | Client-side placement preview model |
BuildDescription — Inventory Tooltip
csharp
public override void BuildDescription(ItemDescriptionBuilder builder, Item itemInstance)
{
base.BuildDescription(builder, itemInstance);
if (build == EBuild.VEHICLE) return; // Vehicle barricades skip barricade description
if (_health > 0)
builder.Append(...health..., DescSort_BuildableCommon);
// Armor tier
switch (armorTier) { ... }
// Pickup/salvage restrictions
if (_isUnpickupable) { ... }
else if (!_isSalvageable) { ... }
// Repairable
if (!isRepairable) { ... }
// Proof
if (proofExplosion) { ... }
// Lockable
if (isLocked) { ... }
// Invulnerable
if (!_isVulnerable) { ... }
}Vehicle barricades return early — they don't show barricade stats (health, armor tier, etc.) because the vehicle itself handles those.
Inventory Audio
csharp
protected override AudioReference GetDefaultInventoryAudio()
{
if (name.Contains("Seed", StringComparison.InvariantCultureIgnoreCase))
return new AudioReference("core.masterbundle", "Sounds/Inventory/Seeds.asset");
if (name.Contains("Metal", StringComparison.InvariantCultureIgnoreCase))
return new AudioReference("core.masterbundle", "Sounds/Inventory/SmallMetal.asset");
if (size_x <= 1 || size_y <= 1)
return new AudioReference("core.masterbundle", "Sounds/Inventory/LightMetalEquipment.asset");
else if (size_x <= 2 || size_y <= 2)
return new AudioReference("core.masterbundle", "Sounds/Inventory/MediumMetalEquipment.asset");
else
return new AudioReference("core.masterbundle", "Sounds/Inventory/HeavyMetalEquipment.asset");
}| Condition | Audio |
|---|---|
| Name contains "Seed" | Seeds.asset |
| Name contains "Metal" | SmallMetal.asset |
| Grid size ≤ 1 in either dim | LightMetalEquipment.asset |
| Grid size ≤ 2 in either dim | MediumMetalEquipment.asset |
| Larger | HeavyMetalEquipment.asset |
.dat File Reference — Barricade-Specific
| .dat Key | Type | Default | Notes |
|---|---|---|---|
Build | string | Required | EBuild enum value (e.g., Door, Storage, Farm) |
Health | ushort | Required | Hit points (max 65,535) |
Range | float | Required | Placement range (meters) |
Radius | float | Required | Placement overlap radius |
Offset | float | Required | Surface offset |
Explosion | GUID/ID | — | Destruction effect |
Can_Be_Damaged | bool | true | Damage toggle |
Eligible_For_Pooling | bool | true (false for BEACON) | Object pool |
Locked | flag | — | Key-lockable |
Vulnerable | flag | — | Can be damaged (flag) |
Bypass_Claim | bool/flag | false (true for CHARGE) | Bypass building claims |
Unrepairable | flag | — | Cannot repair |
Proof_Explosion | flag | — | Explosion immune |
Unpickupable | flag | — | Cannot salvage |
Unsalvageable | flag | — | Cannot salvage (separate from pickup) |
Salvage_Duration_Multiplier | float | 1.0 | Salvage time multiplier |
Unsaveable | flag | — | Does not persist |
Allow_Collision_While_Animating | bool | false | Keep colliders during animation |
Allow_Placement_On_Vehicle | bool | Varies by build | Place on vehicles |
Bypass_Pickup_Ownership | bool | true for CHARGE | Bypass pickup ownership |
Allow_Placement_Inside_Clip_Volumes | bool | true for CHARGE | Place OOB |
Use_Water_Height_Transparent_Sort | flag | — | Water rendering |
CanParentVehicleBePickedUp | bool | false | Allow vehicle hook |
CanVehicleHookWhileAttached | bool | false | Legacy name for above |
Armor_Tier | string | Name-based | Low or High |
Has_Clip_Prefab | bool | true | Server Clip prefab exists |
Modding Example — Basic Wooden Crate .dat
ini
GUID a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
Type Barricade
Build Storage
Health 200
Range 4
Radius 0.5
Offset 0.1
Armor_Tier LowCreates a storage barricade (expand with ItemStorageAsset .dat keys) with 200 HP, 4m placement range.
Modding Example — Reinforced Door .dat
ini
GUID f1e2d3c4b5a69788796a5b4c3d2e1f0a
Type Barricade
Build Door
Health 900
Range 4
Radius 0.3
Offset 0.05
Armor_Tier High
Locked
Proof_ExplosionCreates a reinforced door with 900 HP, high armor, key-lockable, and explosion proof.
Modding Example — Vehicle Spawner .dat
ini
GUID d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9
Type Barricade
Build Vehicle
Health 1
Range 4
Radius 0.5
Offset 0.0
Explosion <vehicle_guid_or_id>The Explosion field holds the vehicle GUID/ID (historical field reuse). Use FindVehicleAsset() at runtime to resolve the vehicle.
Common Issues
Health wraps at 65,535:
_healthisushort. Values above 65,535 wrap around. Vanilla never hits this, but mods with configurable health may.Radius/offset tight fit: If
radius ≈ offset(within 0.05), the system auto-reduces radius by 0.05 for placement wiggle room. Don't set them exactly equal expecting precision.Vehicle barricade GUID: Vehicle GUID is stored in
_explosionGuid, not_vehicleGuid. Always useFindVehicleAsset()rather than accessing_vehicleGuidor_vehicleIddirectly.Bypass_Claim for charges: Charges default to
bypassClaim = true. If you create a non-charge barricade that needs to bypass claims, explicitly setBypass_Claim true.Eligible_For_Pooling: BEACON barricades default to
false. If your modded barricade has customMonoBehaviourcomponents needingAwake/Start, disable pooling.CanParentVehicleBePickedUp naming: Support both
CanParentVehicleBePickedUpandCanVehicleHookWhileAttachedin.datfiles for maximum compatibility.
Document history
| Version | Date | Author | Notes |
|---|---|---|---|
| 1.0 | 2026-07-28 | 57 Studios | Initial publication. Full barricade asset documentation including EBuild system, state byte layouts, placement validation, vehicle integration, and auto heat tag. |
