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
→ ItemChargeAssetCore Parameters
| Field | Type | Description |
|---|---|---|
_range2 | float | Blast radius |
playerDamage | float | Damage to players |
zombieDamage | float | Damage to zombies |
animalDamage | float | Damage to animals |
barricadeDamage | float | Damage to barricades |
structureDamage | float | Damage to structures |
vehicleDamage | float | Damage to vehicles |
resourceDamage | float | Damage to resources (trees, rocks) |
objectDamage | float | Damage to world objects |
_detonationEffectGuid / _explosion2 | Guid + ushort | Detonation particle effect |
explosionLaunchSpeed | float | Physics impulse on detonation |
Placement Defaults
Charges have special defaults in ItemBarricadeAsset:
| Property | Default | Effect |
|---|---|---|
Bypass_Claim | true | Ignores building claims — can be placed on enemy structures |
AllowPlacementInsideClipVolumes | true | Can be placed inside safezone clip volumes (OOB areas) |
shouldBypassPickupOwnership | true | Can 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:
| Parameter | Source | Purpose |
|---|---|---|
playerDamage | ItemChargeAsset.playerDamage | Direct damage to players |
zombieDamage | ItemChargeAsset.zombieDamage | Damage to AI zombies |
animalDamage | ItemChargeAsset.animalDamage | Damage to wildlife |
barricadeDamage | ItemChargeAsset.barricadeDamage | Damage to placed barricades |
structureDamage | ItemChargeAsset.structureDamage | Damage to building grid structures |
vehicleDamage | ItemChargeAsset.vehicleDamage | Damage to vehicles |
resourceDamage | ItemChargeAsset.resourceDamage | Damage to trees/rocks |
objectDamage | ItemChargeAsset.objectDamage | Damage to world objects |
range | ItemChargeAsset._range2 | Blast radius in world units |
launchSpeed | ItemChargeAsset.explosionLaunchSpeed | Physics impulse to nearby rigidbodies |
damageOrigin | EDamageOrigin.Charge_Explosion | Kill 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:
UseableDetonatorsends aDetonateChargeRPC to the server.- Server validates each paired charge (exists, in range, not already detonated).
- Server calls
InteractableCharge.detonate()on each valid charge. - Each charge spawns its detonation effect and applies damage.
- The charge's barricade drop is destroyed via
BarricadeManager.damage.
Detonator-Charge Validation
| Check | Requirement |
|---|---|
| Range | Charge must be within interaction range (default 5m) |
| Line of sight | Raycast from player's eyes to charge center must be clear |
| Ownership | If claims active, player must own or bypass the claim |
| State | Charge 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
| Feature | Charge (ItemChargeAsset) | Grenade (ItemThrowableAsset) | Sticky Grenade | Rocket Launcher |
|---|---|---|---|---|
| Placement | Barricade (surface attach) | Thrown projectile | Thrown + sticks to surface | Fired from launcher |
| Trigger | Remote detonator | Fuse timer | Fuse timer | Impact or timed |
| Per-type damage | 7 independent floats | 4 multipliers (weapon base) | Same as grenade | Ammo-based multipliers |
| Claim bypass | Yes (default) | No | No | No |
| Clip volume placement | Yes (default) | N/A (thrown) | N/A (thrown) | N/A (projectile) |
| Multi-charge simultaneous | Yes (paired detonator) | No (individual fuses) | No | No (one rocket per shot) |
| Can be stolen | Yes (shouldBypassPickupOwnership) | No | No | No |
| Self-destruction | 5 damage on detonate | Object destroyed | Object destroyed | Depleted on use |
| Visual selection | isTargeted/isSelected highlights | Tracer/trail | Tracer/trail | Tracer |
| Cargo table | "Charge" table | "Throwable" via ItemWeaponAsset | Same as grenade | "Gun" table |
Failure Modes and Common Mistakes
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.
Premature charge theft —
shouldBypassPickupOwnership = truemeans 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.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.
Surface type affecting charge placement — Charges are barricades and follow standard barricade placement rules. If a surface is marked as non-buildable or has
isBlockedset, charges cannot be placed even though they bypass claims. The claim bypass covers ownership, not buildability.Object damage against non-damageable objects —
objectDamageis applied to world objects (ObjectAsset instances). Some objects haveisInvulnerable = 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,ItemChargeAssetdefines its own independent float fields for each of the seven target types — no multiplier inheritance fromItemWeaponAssetis 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
UseableDetonatorsends a single RPC with all charge references, the server processes them sequentially in a loop. Very large charge counts (100+) may cause visual staggering asDamageTool.explodeis 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
- Cluster cooldown: Limit simultaneous charge detonations to 8 per RPC, queuing the rest for the next frame.
- Spatial indexing: Pre-filter entities in the charge's region before running full blast radius overlap queries.
- 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
- Detonator Asset — ItemDetonatorAsset — The detonator used to pair and trigger charges remotely.
- Grenade Asset — ItemThrowableAsset — Contrast between thrown explosives and placed charges.
- Barricade Asset — Barricade placement, pickup, and ownership rules that charges inherit.
- Interactable Trap — Trigger Damage System — Traps also use explosive damage with per-entity-type values but are automatic, not remote-controlled.
