Skip to content

ItemBarricadeAsset — Placeable Barricade Definition

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 charge

EBuild 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 ValueState SizeContents
DOOR, GATE, SHUTTER, HATCH17 bytesOwner (8) + Group (8) + Interact (1)
BED8 bytesOwner only
FARM4 bytesSpawn time (uint)
TORCH, CAMPFIRE, OVEN, SPOT, SAFEZONE, OXYGENATOR, BARREL_RAIN, CAGE1 byteLit/activated state
OIL2 bytesOil amount
SIGN, SIGN_WALL, NOTE17 bytesOwner + Group + Text length
STEREO17 bytesSong GUID (16) + Volume (1)
MANNEQUIN73 bytesOwner + Cosmetics (28) + Items (21) + States (7)
STORAGE, STORAGE_WALL17 bytesOwner + Group + Interact
CHARGE17 bytesOwner + Group + Interact
VEHICLEMinimalNo placement state
Other0 bytesNo 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

FieldType.dat KeyDefaultDescription
_healthushortHealthMaximum hit points (max 65,535)
_rangefloatRangeInteraction/placement range in meters
_radiusfloatRadiusSphere overlap radius for placement validation
_offsetfloatOffsetSurface offset for placement from surface normal
armorTierEArmorTierArmor_TierLOW/HIGH by nameDamage resistance tier
canBeDamagedboolCan_Be_DamagedtrueWhether damage is applied at all
eligibleForPoolingboolEligible_For_Poolingtrue (false for BEACON)Object pool eligibility
isLockedboolLockedfalseSupports locking with key
isVulnerableboolVulnerablefalseCan be damaged (flag-based)
isRepairableboolUnrepairable (inverted)trueCan be repaired
proofExplosionboolProof_ExplosionfalseExplosion immunity
isUnpickupableboolUnpickupablefalseCannot be salvaged at all
isSalvageableboolUnsalvageable (inverted)trueCan be salvaged
isSaveableboolUnsaveable (inverted)truePersists between sessions
bypassClaimboolBypass_Claimfalse (true for CHARGE)Ignores building claim checks
shouldBypassPickupOwnershipboolBypass_Pickup_Ownershipfalse (true for CHARGE)Bypasses pickup ownership
AllowPlacementInsideClipVolumesboolAllow_Placement_Inside_Clip_Volumesfalse (true for CHARGE)Can be placed OOB
allowPlacementOnVehicleboolAllow_Placement_On_VehicleVaries by buildCan place on vehicle surface
salvageDurationMultiplierfloatSalvage_Duration_Multiplier1.0Time multiplier for salvage action
allowCollisionWhileAnimatingboolAllow_Collision_While_AnimatingfalseKeep colliders during animation
useWaterHeightTransparentSortboolUse_Water_Height_Transparent_SortfalseSpecial water rendering
CanParentVehicleBePickedUpboolCanParentVehicleBePickedUpfalseAllow 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;
}
ConditionArmor Tier
.dat sets Armor_TierUses specified value
Asset name contains "Metal"HIGH
OtherwiseLOW

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;
EraLogicEffect
Pre-2024Flag only (ContainsKey)Presence = bypass, absent = check
2024-09-18Bool + flag fallbacktrue/false values supported
DefaultCHARGE build typeCharges 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

  1. Surface detection: Raycast from player camera finds target surface within range distance
  2. Obstruction check: Physics.OverlapSphere at placement position using radius
  3. Support check: If other barricades/structures overlap, placement is blocked (unless Bypass_Claim)
  4. Offset application: offset applied from surface normal for final position
  5. Safezone check: canBeUsedInSafezone verifies building permissions
  6. 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 KeyTypePurpose
ExplosionGUID or legacy IDEffectAsset 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):

  1. Checks RequiresHeatSourceCraftingTagConversion (default true)
  2. Finds the Fire child transform on the barricade prefab
  3. Adds CraftingTagModifierComponent to the Fire transform (removes Heat Source tag when fire effect is inactive)
  4. Adds CraftingTagProviderComponent to 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
}
ConditionPrefab 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 KeyDefaultPurpose
_navNav (GameObject)Navigation mesh override
_useUse / PlacementAudioClip (AudioClip)Placement/use sound
placementPreviewRefPlacementPreviewPrefabClient-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");
}
ConditionAudio
Name contains "Seed"Seeds.asset
Name contains "Metal"SmallMetal.asset
Grid size ≤ 1 in either dimLightMetalEquipment.asset
Grid size ≤ 2 in either dimMediumMetalEquipment.asset
LargerHeavyMetalEquipment.asset

.dat File Reference — Barricade-Specific

.dat KeyTypeDefaultNotes
BuildstringRequiredEBuild enum value (e.g., Door, Storage, Farm)
HealthushortRequiredHit points (max 65,535)
RangefloatRequiredPlacement range (meters)
RadiusfloatRequiredPlacement overlap radius
OffsetfloatRequiredSurface offset
ExplosionGUID/IDDestruction effect
Can_Be_DamagedbooltrueDamage toggle
Eligible_For_Poolingbooltrue (false for BEACON)Object pool
LockedflagKey-lockable
VulnerableflagCan be damaged (flag)
Bypass_Claimbool/flagfalse (true for CHARGE)Bypass building claims
UnrepairableflagCannot repair
Proof_ExplosionflagExplosion immune
UnpickupableflagCannot salvage
UnsalvageableflagCannot salvage (separate from pickup)
Salvage_Duration_Multiplierfloat1.0Salvage time multiplier
UnsaveableflagDoes not persist
Allow_Collision_While_AnimatingboolfalseKeep colliders during animation
Allow_Placement_On_VehicleboolVaries by buildPlace on vehicles
Bypass_Pickup_Ownershipbooltrue for CHARGEBypass pickup ownership
Allow_Placement_Inside_Clip_Volumesbooltrue for CHARGEPlace OOB
Use_Water_Height_Transparent_SortflagWater rendering
CanParentVehicleBePickedUpboolfalseAllow vehicle hook
CanVehicleHookWhileAttachedboolfalseLegacy name for above
Armor_TierstringName-basedLow or High
Has_Clip_PrefabbooltrueServer 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 Low

Creates 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_Explosion

Creates 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

  1. Health wraps at 65,535: _health is ushort. Values above 65,535 wrap around. Vanilla never hits this, but mods with configurable health may.

  2. 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.

  3. Vehicle barricade GUID: Vehicle GUID is stored in _explosionGuid, not _vehicleGuid. Always use FindVehicleAsset() rather than accessing _vehicleGuid or _vehicleId directly.

  4. Bypass_Claim for charges: Charges default to bypassClaim = true. If you create a non-charge barricade that needs to bypass claims, explicitly set Bypass_Claim true.

  5. Eligible_For_Pooling: BEACON barricades default to false. If your modded barricade has custom MonoBehaviour components needing Awake/Start, disable pooling.

  6. CanParentVehicleBePickedUp naming: Support both CanParentVehicleBePickedUp and CanVehicleHookWhileAttached in .dat files for maximum compatibility.

Document history

VersionDateAuthorNotes
1.02026-07-2857 StudiosInitial publication. Full barricade asset documentation including EBuild system, state byte layouts, placement validation, vehicle integration, and auto heat tag.