Skip to content

Charge Explosive Asset — ItemChargeAsset

Understanding remote demolition and raiding mechanics in Unturned starts with the charge explosive asset system, where barricade-placed explosives carry independent damage values for seven target types, use claim-bypassing placement defaults, and pair with detonators for controlled detonation sequences. ItemChargeAsset extends ItemBarricadeAsset with explosive damage parameters for the remote-detonation raiding mechanic. Charges are barricades with independent damage values for seven target types, a dedicated detonation effect, and special placement defaults that bypass claims and clip volumes.

Source code location: Unturned/Items/ItemChargeAsset.cs

Inheritance Chain

ItemPlaceableAsset
  → ItemBarricadeAsset
    → ItemChargeAsset

Core Parameters

FieldTypeDescription
_range2floatBlast radius
playerDamagefloatDamage to players
zombieDamagefloatDamage to zombies
animalDamagefloatDamage to animals
barricadeDamagefloatDamage to barricades
structureDamagefloatDamage to structures
vehicleDamagefloatDamage to vehicles
resourceDamagefloatDamage to resources (trees, rocks)
objectDamagefloatDamage to world objects
_detonationEffectGuid / _explosion2Guid + ushortDetonation particle effect
explosionLaunchSpeedfloatPhysics impulse on detonation

Placement Defaults

Charges have special defaults in ItemBarricadeAsset:

PropertyDefaultEffect
Bypass_ClaimtrueIgnores building claims — can be placed on enemy structures
AllowPlacementInsideClipVolumestrueCan be placed inside safezone clip volumes (OOB areas)
shouldBypassPickupOwnershiptrueCan be stolen by other players after placement

These defaults make charges viable raiding tools. Placing charges on enemy structures ignores land claims. Placing inside clip volumes allows charges in areas normally restricted for building.

InteractableCharge Integration

InteractableCharge is the runtime component that manages a single-use explosive:

csharp
public void Detonate(Player instigatingPlayer)
{
    EffectAsset detonationEffectAsset = Assets.FindEffectAssetByGuidOrLegacyId(
        detonationEffectGuid, explosion2);

    ExplosionParameters parameters = new ExplosionParameters(
        transform.position, range2, EDeathCause.CHARGE);
    parameters.playerDamage = playerDamage;
    parameters.zombieDamage = zombieDamage;
    parameters.animalDamage = animalDamage;
    parameters.barricadeDamage = barricadeDamage;
    parameters.structureDamage = structureDamage;
    parameters.vehicleDamage = vehicleDamage;
    parameters.resourceDamage = resourceDamage;
    parameters.objectDamage = objectDamage;
    parameters.damageOrigin = EDamageOrigin.Charge_Explosion;
    parameters.launchSpeed = explosionLaunchSpeed;

    DamageTool.explode(parameters, out kills);

    BarricadeManager.damage(transform, 5.0f, 1.0f, false, ...);
}

The charge provides independent damage values for seven target types, allowing precise balance (e.g., high structure damage for raiding, low player damage for skill-based PvP).

Explosion Parameters Composition

The ExplosionParameters struct is populated from the charge asset's damage fields:

ParameterSourcePurpose
playerDamageItemChargeAsset.playerDamageDirect damage to players
zombieDamageItemChargeAsset.zombieDamageDamage to AI zombies
animalDamageItemChargeAsset.animalDamageDamage to wildlife
barricadeDamageItemChargeAsset.barricadeDamageDamage to placed barricades
structureDamageItemChargeAsset.structureDamageDamage to building grid structures
vehicleDamageItemChargeAsset.vehicleDamageDamage to vehicles
resourceDamageItemChargeAsset.resourceDamageDamage to trees/rocks
objectDamageItemChargeAsset.objectDamageDamage to world objects
rangeItemChargeAsset._range2Blast radius in world units
launchSpeedItemChargeAsset.explosionLaunchSpeedPhysics impulse to nearby rigidbodies
damageOriginEDamageOrigin.Charge_ExplosionKill attribution

Kill Credit

csharp
if (instigatingPlayer != null)
{
    parameters.killer = instigatingPlayer.channel.owner.playerID.steamID;
    parameters.ragdollEffect = instigatingPlayer.equipment.getUseableRagdollEffect();
}

The player who triggered the detonation gets kill credit. The ragdoll effect (fire, electric, etc.) is forwarded from the player's current equipment.

Charge Selection Protocol

The InteractableCharge component supports a two-state highlight system:

csharp
public bool isSelected { get; private set; }
public bool isTargeted { get; private set; }

public void select()
{
    if (isSelected) return;
    isSelected = true;
    updateHighlight();
}

public void target()
{
    if (isTargeted) return;
    isTargeted = true;
    updateHighlight();
}
  • isTargeted: The charge the player is looking at (crosshair highlight).
  • isSelected: The charge the player has selected for detonation (persistent highlight).

The visual feedback is rendered through partial void updateHighlight() — a platform-specific partial method.

Charge-Detonator Communication

The detonation sequence:

  1. UseableDetonator sends a DetonateCharge RPC to the server.
  2. Server validates each paired charge (exists, in range, not already detonated).
  3. Server calls InteractableCharge.detonate() on each valid charge.
  4. Each charge spawns its detonation effect and applies damage.
  5. The charge's barricade drop is destroyed via BarricadeManager.damage.

Detonator-Charge Validation

CheckRequirement
RangeCharge must be within interaction range (default 5m)
Line of sightRaycast from player's eyes to charge center must be clear
OwnershipIf claims active, player must own or bypass the claim
StateCharge must not have already been detonated

Charges failing validation are silently excluded. If all charges fail, the detonator plays a failure click sound.

Safezone Rules

canBeUsedInSafezone via ItemBarricadeAsset checks safezone.CurrentlyAllowsBuilding. If building is allowed, charges can be placed. The 2025 update (public issue #5175) modified detonator safezone behavior: previously detonators only affected sentries; now they also check safezones.

Cargo Data Export

Writes to the Charge Cargo table with range, damage values, and explosion effect reference.

Worked Code Example: Custom Charge Detonation

Charge Damage Calculator

csharp
using SDG.Unturned;
using UnityEngine;

public static class ChargeDamageCalculator
{
    /// <summary>
    /// Calculates the total effective damage a charge deals to all entity types
    /// within its blast radius, useful for comparing charge assets or simulating
    /// raid damage before placing charges.
    /// </summary>
    public static float GetTotalDamagePotential(ItemChargeAsset charge, int entityCountPerType)
    {
        float total = 0f;
        total += charge.playerDamage * entityCountPerType;
        total += charge.zombieDamage * entityCountPerType;
        total += charge.animalDamage * entityCountPerType;
        total += charge.barricadeDamage * entityCountPerType;
        total += charge.structureDamage * entityCountPerType;
        total += charge.vehicleDamage * entityCountPerType;
        total += charge.resourceDamage * entityCountPerType;
        total += charge.objectDamage * entityCountPerType;
        return total;
    }

    /// <summary>
    /// Estimates the number of charges required to destroy a structure
    /// with a given total health, accounting for linear falloff.
    /// </summary>
    public static int ChargesRequiredForStructure(
        ItemChargeAsset charge, float structureHealth, float distanceToStructure)
    {
        float falloff = 1f - (distanceToStructure / charge.range2);
        if (falloff <= 0f) return int.MaxValue;

        float effectiveDamage = charge.structureDamage * falloff;
        return Mathf.CeilToInt(structureHealth / effectiveDamage);
    }
}

Charge Placement Validator

csharp
using SDG.Unturned;

public class ChargePlacementValidator
{
    /// <summary>
    /// Validates that a charge can be legally placed at a position,
    /// checking claim bypass, clip volume status, and power requirements
    /// if the charge asset specifies them.
    /// </summary>
    public static bool CanPlaceChargeAtPosition(
        ItemChargeAsset charge, 
        Vector3 position, 
        Player placer,
        out string rejectionReason
    )
    {
        rejectionReason = null;

        // Charges bypass claims by default
        if (!charge.Bypass_Claim)
        {
            if (!BarricadeManager.IsOwnerAtPosition(placer, position))
            {
                rejectionReason = "Land claim prevents placement";
                return false;
            }
        }

        // Charges allow placement inside clip volumes by default
        if (!charge.AllowPlacementInsideClipVolumes)
        {
            if (SafezoneManager.IsInsideClipVolume(position))
            {
                rejectionReason = "Inside restricted clip volume";
                return false;
            }
        }

        return true;
    }
}

Mermaid Diagram: Charge Detonation Flow

Comparison: Charge vs. Other Explosive Systems

FeatureCharge (ItemChargeAsset)Grenade (ItemThrowableAsset)Sticky GrenadeRocket Launcher
PlacementBarricade (surface attach)Thrown projectileThrown + sticks to surfaceFired from launcher
TriggerRemote detonatorFuse timerFuse timerImpact or timed
Per-type damage7 independent floats4 multipliers (weapon base)Same as grenadeAmmo-based multipliers
Claim bypassYes (default)NoNoNo
Clip volume placementYes (default)N/A (thrown)N/A (thrown)N/A (projectile)
Multi-charge simultaneousYes (paired detonator)No (individual fuses)NoNo (one rocket per shot)
Can be stolenYes (shouldBypassPickupOwnership)NoNoNo
Self-destruction5 damage on detonateObject destroyedObject destroyedDepleted on use
Visual selectionisTargeted/isSelected highlightsTracer/trailTracer/trailTracer
Cargo table"Charge" table"Throwable" via ItemWeaponAssetSame as grenade"Gun" table

Failure Modes and Common Mistakes

  1. Charge placed but detonator ignores it — Charges must be within interaction range (5m) and have clear line of sight to the player's eyes. Charges behind walls, floors, or ceilings fail the LOS raycast silently. The detonator clicks without detonation, and the player assumes the charge was destroyed rather than blocked.

  2. Premature charge theftshouldBypassPickupOwnership = true means other players can steal a placed charge. A common raiding mistake: place all charges, step back to detonate, and find that a defending player sprinted through and picked up half the charges during the step-back window.

  3. Charge stacking damage calculation — Players often assume 2 charges = 2x damage. While each charge independently applies its full damage in its blast radius, the overlapping area receives cumulative damage from all charges. A 500-HP structure hit by 5 charges in the same spot receives 5 independent damage calculations, not a unified "explosion cluster" damage formula.

  4. Surface type affecting charge placement — Charges are barricades and follow standard barricade placement rules. If a surface is marked as non-buildable or has isBlocked set, charges cannot be placed even though they bypass claims. The claim bypass covers ownership, not buildability.

  5. Object damage against non-damageable objectsobjectDamage is applied to world objects (ObjectAsset instances). Some objects have isInvulnerable = true, making them immune to charge damage. Spraying object damage at an invulnerable map prop is a waste of charges. Check the object's invulnerability flag before placing charges.

How This Field Behaves Differently from the SDG Docs

  • SDG docs claim charges use weapon damage multipliers. Some documentation suggests charges derive damage from weapon multipliers like ItemWeaponAsset.playerDamageMultiplier. In the SDK, ItemChargeAsset defines its own independent float fields for each of the seven target types — no multiplier inheritance from ItemWeaponAsset is used.

  • SDG docs describe charges as "single-use items." The wiki characterizes charges as consumables. In the SDK, charges are barricades — they are placed, not consumed from inventory by a "use" action. The charge item is removed from inventory when the barricade is placed (standard barricade placement), not when detonated.

  • SDG docs mention "charge tier" or "charge quality." Some community discussion references charge quality or tiered charges. In the SDK, charges have no quality system, no tier enum, and no scaled damage based on rarity or condition. The damage values are flat floats in the asset definition.

  • SDG docs state detonation is "instantaneous." The documentation suggests all charges detonate on the same frame. While UseableDetonator sends a single RPC with all charge references, the server processes them sequentially in a loop. Very large charge counts (100+) may cause visual staggering as DamageTool.explode is called once per charge.

Performance Considerations

Detonation Overhead

Each DamageTool.explode() call performs a Physics.OverlapSphere query. A simultaneous detonation of 20 charges = 20 overlap queries. Each query scans all Rigidbody and damageable colliders in the scene. In densely populated maps with thousands of barricades and objects, a single overlap query can take 0.5ms. Twenty charges = 10ms of explosion calculation — enough to cause a visible frame hitch.

Optimization Strategies

  1. Cluster cooldown: Limit simultaneous charge detonations to 8 per RPC, queuing the rest for the next frame.
  2. Spatial indexing: Pre-filter entities in the charge's region before running full blast radius overlap queries.
  3. Effect pooling: The detonation effect is instantiated per charge. Use object pooling for the detonation prefab to avoid GC pressure from 20+ instantiations in one frame.

Memory

Each charge stores its damage values as floats (7 × 4 bytes = 28 bytes) plus the explosion effect GUID (16 bytes) and a few booleans. The asset memory footprint per charge type is approximately 64 bytes — negligible.

Deeper FAQ

Q: Can I detonate only specific charges from a group?

Yes. Use the right-click toggle on individual charges to unpair them from the detonator. The isSelected highlight state toggles on each right-click. Unpaired charges remain placed and can be re-paired by right-clicking again. The detonator only triggers charges currently in the paired list.

Q: What happens if the detonator player dies mid-detonation?

The RPC is sent instantly. If the player dies after the server receives the DetonateCharge RPC but before the explosion visuals reach the client, the detonation still occurs — the kill credit still goes to the now-dead player. If the player dies before the RPC reaches the server (network cutoff), the charges remain in their paired state and can be detonated by the same player after respawning and re-equipping the detonator (pairings persist through death for a short window).

Q: Do charges affect the terrain or water?

No. Charge explosions do not deform terrain, create craters, or displace water. The explosion parameters only damage entities (players, zombies, animals, barricades, structures, vehicles, resources, objects). Terrain and water are world-level elements unaffected by explosive damage.

Q: Can I increase the blast radius beyond the asset's _range2?

Not through vanilla configuration. A Harmony patch on InteractableCharge.Detonate() or on the ExplosionParameters constructor is required to modify the blast radius. Plugins commonly scale radius based on charge count (sqrt clustering) — 4 charges at the same point double the effective radius.

Q: What prevents a charge from being detonated in a safezone?

The detonator's canBeUsedInSafezone check (inherited from ItemAsset) blocks the DetonateCharge RPC from being sent. This prevents detonation in weapon-restricted safezones. However, if a charge was placed in a safezone before the safezone was created (e.g., the zone was added after charge placement), the charge itself is still valid — only the detonation is blocked.

Cross-References

Document history