Skip to content

ItemStorageAsset — Storage Barricade Definition

Overview

ItemStorageAsset extends ItemBarricadeAsset with an inventory grid system. It defines storage containers: crates, lockers, chests, wardrobes, fridges, and display cases. The class adds inventory grid dimensions, display case mode, auto-close behavior, player-open toggles, delete-on-destroy behavior, and pre-populated default contents.

Storage barricades inherit the full ItemBarricadeAsset property set (health, range, placement, explosion, build type, locking, etc.) and add inventory-specific fields. The build type for storage is typically EBuild.STORAGE or EBuild.STORAGE_WALL.

ItemSentryAsset inherits from ItemStorageAsset because sentries use their inventory grid to store ammunition and a weapon.

Source code location: Unturned/Bundles/ItemStorageAsset.cs (149 lines), inheriting from ItemBarricadeAsset.cs (605 lines), ItemPlaceableAsset.cs (454 lines), and ItemAsset.cs (base).

Inheritance Chain

ItemAsset → IArmorFalloff
  └─ ItemPlaceableAsset — salvage, destroy drops, crafting tags, armor falloff
       └─ ItemBarricadeAsset — EBuild system, placement, health, explosion
            └─ ItemStorageAsset — inventory grid, display, default contents
                 └─ ItemSentryAsset — sentry turret (uses storage for ammo)

Class Definition

csharp
public class ItemStorageAsset : ItemBarricadeAsset
{
    protected byte _storage_x;
    protected byte _storage_y;
    protected bool _isDisplay;

    public byte storage_x => _storage_x;
    public byte storage_y => _storage_y;
    public bool isDisplay => _isDisplay;

    public bool shouldCloseWhenOutsideRange { get; protected set; }
    public bool CanPlayersOpen { get; set; }
    public bool ShouldDeleteContainedItemsOnDestroy { get; set; }
    public LevelAsset.DefaultLoadoutItem[] DefaultContainedItems { get; set; }

    public void AddDefaultContainedItemsToStorage(InteractableStorage storage) { ... }
    public override byte[] getState(EItemOrigin origin) { ... }
}

Inventory Grid Dimensions

Field.dat KeyTypeDefaultRangeNotes
_storage_xStorage_Xbyte1 (clamped)1–255Grid width (columns)
_storage_yStorage_Ybyte1 (clamped)1–255Grid height (rows)

Parsing with Minimum

csharp
_storage_x = p.data.ParseUInt8("Storage_X");
if (storage_x < 1)
    _storage_x = 1;

_storage_y = p.data.ParseUInt8("Storage_Y");
if (storage_y < 1)
    _storage_y = 1;

The minimum enforced value is 1 in each dimension. A storage of 1 × 1 provides a single item slot. Values of 0 are clamped to 1 — storage is never fully disabled.

Description Display

csharp
if (storage_x > 0 && storage_y > 0)
{
    builder.Append(localization.format("ItemDescription_StorageDimensions",
        storage_x, storage_y), DescSort_Important);
}

Display format: Storage: 5 × 6

Common Storage Sizes

SizeSlotsTypical Item
1×11Small ammo box
3×39Wooden crate
5×420Metal locker
5×630Wardrobe
7×749Large industrial crate

Note: ItemBagAsset (clothing storage) uses Width/Height keys. ItemStorageAsset uses Storage_X/Storage_Y. These are different keys for different storage systems.


Display Case Mode

csharp
_isDisplay = p.data.ContainsKey("Display");
.dat KeyTypeDefaultEffect
DisplayflagStorage acts as a display case

State Difference

Display cases have a larger state array:

csharp
public override byte[] getState(EItemOrigin origin)
{
    if (isDisplay)
        return new byte[21];
    else
        return new byte[17];
}
ModeState sizeExtra bytes
Standard storage17 bytesOwner (8) + Group (8) + Interact (1)
Display case21 bytes+4 bytes for displayed item reference

The additional 4 bytes store the item being displayed. This allows display cases to show a specific item model to other players without exposing the full inventory.


Should Close When Outside Range

csharp
shouldCloseWhenOutsideRange = p.data.ParseBool("Should_Close_When_Outside_Range", defaultValue: false);
.dat KeyTypeDefaultBehavior
Should_Close_When_Outside_RangeboolfalseAuto-close storage UI when player moves away

When true, the storage interface automatically closes when the player moves beyond the interaction range. This is a UX convenience feature — it prevents the storage UI from staying open when the player walks away, which would block mouse input for non-storage interactions.


Can Players Open

csharp
CanPlayersOpen = p.data.ParseBool("Can_Players_Open", true);
.dat KeyTypeDefaultBehavior
Can_Players_OpenbooltrueWhether players can interact to open storage

When false, the storage cannot be opened by players. This is useful for:

  • Pre-placed sentry ammo storage (prevents players from stealing sentry guns)
  • Decorative storage that shouldn't be interactive
  • Storage that is opened through script/event rather than player interaction

Should Delete Contained Items On Destroy

csharp
ShouldDeleteContainedItemsOnDestroy = p.data.ParseBool("Delete_Contained_Items_On_Destroy");
.dat KeyTypeDefaultBehavior
Delete_Contained_Items_On_DestroyboolfalseItems are deleted instead of dropped when destroyed

When true, destroying the storage container permanently deletes all contained items rather than dropping them on the ground. This is useful for:

  • Sentry ammo boxes (ammo should not be lootable by destroying the sentry)
  • Temporary/event storage that shouldn't spill items
  • Safety: prevents item duplication exploits

When false (default), items drop at the destruction point with the standard ±2m scatter pattern.


Default Contained Items

csharp
if (p.data.TryGetList("Default_Contained_Items", out IDatList itemsNode))
{
    DefaultContainedItems = itemsNode.ParseArrayOfStructs<LevelAsset.DefaultLoadoutItem>();
}
.dat KeyTypePurpose
Default_Contained_ItemsArray of DefaultLoadoutItemItems spawned in storage on first placement

Pre-Population Logic

csharp
public void AddDefaultContainedItemsToStorage(InteractableStorage storage)
{
    if (storage == null || DefaultContainedItems.IsNullOrEmpty())
        return;

    foreach (LevelAsset.DefaultLoadoutItem item in DefaultContainedItems)
    {
        ItemAsset itemAsset = item.ResolveAsset(OnGetDefaultContainedItemsErrorContext);
        if (itemAsset == null)
            continue;

        for (int amount = 0; amount < item.amount; ++amount)
        {
            storage.items.tryAddItem(new Item(itemAsset, item.origin), false);
        }
    }

    storage.items.onStateUpdated?.Invoke();
}

When a storage barricade is placed for the first time (not loaded from save), AddDefaultContainedItemsToStorage populates the storage with items defined in Default_Contained_Items. Each item specifies:

  • Asset reference (GUID)
  • Amount (quantity)
  • Origin (crafted, nature, admin, etc.)

The onStateUpdated callback is invoked after all items are added to notify listeners.


BuildDescription — Inventory Tooltip

csharp
public override void BuildDescription(ItemDescriptionBuilder builder, Item itemInstance)
{
    base.BuildDescription(builder, itemInstance);

    if (storage_x > 0 && storage_y > 0)
    {
        builder.Append(localization.format("ItemDescription_StorageDimensions",
            storage_x, storage_y), DescSort_Important);
    }
}

The storage dimensions are appended to the barricade description (health, armor tier, etc.) with DescSort_Important priority.


BuildCargoData — Wiki Export

csharp
CargoDeclaration data = builder.GetOrAddDeclaration("Storage");
data.Append("GUID", GUID);
data.Append("Storage_X", storage_x);
data.Append("Storage_Y", storage_y);
data.Append("Display", isDisplay);
data.Append("Should_Close_When_Outside_Range", shouldCloseWhenOutsideRange);
ColumnSource
GUIDPK, FK to Barricade table
Storage_X_storage_x
Storage_Y_storage_y
Display_isDisplay
Should_Close_When_Outside_RangeshouldCloseWhenOutsideRange

.dat File Reference — Storage-Specific

.dat KeyTypeDefaultNotes
Storage_Xbyte1 (clamped)Grid columns
Storage_Ybyte1 (clamped)Grid rows
DisplayflagEnable display case mode
Should_Close_When_Outside_RangeboolfalseAuto-close on move
Can_Players_OpenbooltrueAllow player interaction
Delete_Contained_Items_On_DestroyboolfalseDelete items on destroy
Default_Contained_ItemsarrayPre-populate items on first placement

All ItemBarricadeAsset and ItemPlaceableAsset keys are also available.


Modding Example — Wooden Crate .dat

ini
GUID a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
Type Barricade
Build Storage
Health 200
Range 4
Radius 0.5
Offset 0.1
Storage_X 5
Storage_Y 4
Armor_Tier Low

Creates a 5×4 (20-slot) wooden crate with 200 HP.


Modding Example — Display Case .dat

ini
GUID f1e2d3c4b5a69788796a5b4c3d2e1f0a
Type Barricade
Build Storage
Health 100
Range 4
Radius 0.3
Offset 0.1
Storage_X 3
Storage_Y 2
Display
Armor_Tier Low

Creates a 3×2 display case (21-byte state) that shows a displayed item model.


Modding Example — Pre-Populated Locker .dat

ini
GUID d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9
Type Barricade
Build Storage
Health 400
Range 4
Radius 0.5
Offset 0.1
Storage_X 5
Storage_Y 6
Armor_Tier High
Default_Contained_Items
[
    { "GUID": "abc...", "Amount": 2, "Origin": "Craft" },
    { "GUID": "def...", "Amount": 1, "Origin": "Nature" }
]

Creates a high-armor locker that spawns with 2 crafted items and 1 natural item on first placement.


Common Issues

  1. Storage_X vs Width: ItemStorageAsset uses Storage_X/Storage_Y. ItemBagAsset (clothing storage) uses Width/Height. These are completely separate systems with different key names.

  2. Zero dimensions clamped: Setting Storage_X 0 is automatically clamped to 1. There is no way to create a storage barricade with zero inventory slots.

  3. Display case state size: Display cases have a 21-byte state vs 17-byte standard. This is automatically handled by getState based on the Display flag.

  4. Default contained items origin: The DefaultLoadoutItem.origin field determines the item's origin. This affects stack merging and some game mechanics that check item origin.

  5. Delete-on-destroy safety: When Delete_Contained_Items_On_Destroy is false, all items physically drop at the destruction point. With large inventories, this can cause performance issues from many dropped item entities.

Document history

VersionDateAuthorNotes
1.02026-07-2857 StudiosInitial publication. Full storage asset documentation including grid dimensions, display case, default contents, and modding examples.