Hytale asset pack development reference for JSON-based content definition. Use when creating or modifying block definitions, item definitions, NPC roles (including official Template/Variant system, 183 builders, pre-built components), NPC balancing/CAE configs, interaction chains, root interactions, block sets, world generation assets (biomes, density nodes, props, materials, assignments), Custom UI markup (.ui files, Common.ui styling), or any Server/ directory JSON asset files. Also use when setting IncludesAssetPack in manifest.json, structuring the Server/ directory, working with Hytale data assets, or configuring NPC AI behavior trees via JSON.
Use this skill when creating or editing JSON asset files. For complete schemas, read ${SKILL_DIR}/references/asset-schemas.md. For naming rules, read ${SKILL_DIR}/references/naming-conventions.md. For comprehensive NPC AI behavior tree design (sensors, motion controllers, attack sequences, mob archetypes, official Template/Variant system, 183 official builders, pre-built components, debugging), read ${SKILL_DIR}/references/npc-ai-behavior.md. For world generation assets (density nodes, biomes, props, materials, assignments), read ${SKILL_DIR}/references/worldgen-assets.md. For Custom UI markup (cross-skill reference to hytale-plugin-api), see hytale-plugin-api/references/custom-ui-system.md.
This skill covers Layer 1 (Asset Pack JSON) of the 8-layer architecture — including NPC behavior trees, Custom UI markup (.ui files), world generation assets, item/block definitions, and all Server/ directory content. Always check Layer 0 (Engine Configuration) first — GameplayConfig, PlayerConfig, CombatConfig may handle your need without any JSON or Java. See engineering-philosophy/references/layer-architecture.md.
ALWAYS check this table before writing Java code for NPC/item/combat features. See engineering-philosophy/references/decision-gates.md Gate 1 for the full framework.
| I want to... | Use Asset JSON | Use Java | Why |
|---|---|---|---|
| Make mobs attack crystals | NPC Role: Block sensor with Reserve: true | No | Sensors auto-retarget, reserve prevents stacking |
| Make mobs ignore a player faction | Role: DisableDamageGroups | No | Engine-enforced, instant, no timing window |
| Tune attack damage/cooldown | CAE: DamageCalculator, CooldownRange | No | Data-driven, easy to rebalance without recompile |
| Define attack animations + sound | Interaction chains (Parallel branches) | No | Engine handles animation timing, hit detection, sound |
| Make mobs follow/seek targets | Role: Sensor + Seek body motion | No | Native pathfinding, no jitter |
| Create status effects (tints, overlays) | Server/Entity/Effects/ JSON | No | Engine handles duration, overlap, visual |
| Define mob motion (walk, fly, swim) | Role: MotionControllerList | No | Most reliable motion — dev guideline #3 |
| Apply player armor DR/immunity | No | Gather-stage DamageEventSystem handler | Player equipment effects need Java events |
| Cancel item drops conditionally | No | DropItemEvent.setCancelled() handler | Runtime logic, no JSON equivalent |
| Auto-consume items on pickup | No | InteractivelyPickupItemEvent handler | Runtime logic |
| Define weapon damage/speed | ItemWeapon JSON — statModifiers, DamageConfig | No | Data-driven, no recompile to rebalance |
| Define drop tables | Server/Drops/ JSON | No | Loot probability without Java |
| Define crafting recipes | CraftRecipe JSON | No | Recipe data as content, not code |
| Weather/environment configs | Weather JSON | No | Sky, fog, precipitation as data |
| Procedural block mechanics | No | world.setBlock() in scheduler | BFS/algorithmic logic |
| Custom UI pages/HUDs | .ui markup + UICommandBuilder | UICommandBuilder Java for data binding | Markup defines layout, Java pushes data |
| World generation (biomes, terrain) | Worldgen JSON (Density, Biomes, Props) | No | Engine processes density nodes, biome rules |
| NPC Template/Variant roles | Role JSON with Abstract/Variant type | No | Official component reuse system |
WRONG (CorruptionMod v0.8.2-v0.8.9 — fought the engine at every step):
// Every 500ms per mob in a scheduler loop:
overrideAttitude(player, FRIENDLY, duration); // temporary, resets
clearDamageData(); // SensorDamage bypasses it
clearMarkedEntity(0); // removes target lock temporarily
resetAllInstructions(); // resets entire behavior tree
setLeashPoint(crystalPos); // fights native pathfinding
RIGHT (engine-native, zero Java code):
{
"DisableDamageGroups": ["Onyxium"],
"Instructions": [{
"Sensor": { "Type": "Block", "Range": 50, "Blocks": "Crystals", "Reserve": true },
"BodyMotion": { "Type": "Seek", "StopDistance": 2.5 }
}]
}
The JSON approach is instant (applied on spawn), permanent (no resets), correct (engine's own targeting), and zero Java (less to maintain).
Asset packs live in the Server/ directory at JAR root. Set "IncludesAssetPack": true in manifest.json.
Server/
├── Item/
│ ├── Block/Sets/ # Block set definitions (wildcard groups)
│ ├── Items/<Category>/<Sub>/ # Item/block JSON definitions
│ ├── Interactions/NPCs/<Faction>/<Mob>/ # Attack interaction chains
│ └── RootInteractions/NPCs/<Faction>/<Mob>/ # Root interaction entry points
├── NPC/
│ ├── Roles/<Faction>/ # NPC role definitions (AI behavior trees)
│ └── Balancing/<Faction>/ # CombatActionEvaluator configs
├── Biomes/ # World generation biome definitions
├── WorldStructure/ # World structure, density, framework
├── Density/ # Density node definitions (SimplexNoise, etc.)
└── Assignments/ # Material assignment rules
Common/
└── UI/
└── Custom/ # Custom .ui markup files + Common.ui library
Block sets define groups for NPC targeting sensors. Use wildcard patterns:
{ "IncludeBlockTypes": ["Rock_Crystal_White_*"] }
This matches all blocks starting with Rock_Crystal_White_ — used by NPC Block sensors to detect target blocks.
Roles define NPC behavior through a priority-based instruction hierarchy. The NPC evaluates instructions top-to-bottom, executing the first matching sensor.
Top-level fields:
DefaultSubState: initial state (usually "Start")Type: "Generic" for most NPCsAppearance: visual model IDDisableDamageGroups: factions NPC won't damage (e.g., ["Void"])HotbarItems: equipped itemsMotionControllerList: movement capabilities (Walk/Fly/Swim)MaxHealth: use { "Compute": "MaxHealth" } with Parameters blockInstructions: nested priority selector{
"Instructions": [
{
"Instructions": [
{
"Sensor": { "Type": "Block", "Range": 30, "Blocks": "BlockSetName", "Reserve": true },
"Instructions": [
{
"Sensor": { "Type": "Block", "Range": 3.5, "Blocks": "BlockSetName" },
"Actions": [{ "Type": "Attack", "Attack": "Root_Attack_Name", "AttackPauseRange": [1.5, 2.5] }],
"HeadMotion": { "Type": "Aim", "RelativeTurnSpeed": 1 }
},
{
"Sensor": { "Type": "Block", "Range": 30, "Blocks": "BlockSetName" },
"BodyMotion": { "Type": "Seek", "StopDistance": 3.0, "SlowDownDistance": 4, "RelativeSpeed": 1 }
}
]
},
{
"Sensor": { "Type": "Player", "Range": 20, "LockOnTarget": true },
"Instructions": [
{ "Sensor": { "Type": "Player", "Range": 2.5 }, "Actions": [{ "Type": "Attack", "Attack": "Root_Attack_Name" }] },
{ "Sensor": { "Type": "Player", "Range": 20 }, "BodyMotion": { "Type": "Seek", "StopDistance": 1.5 } }
]
},
{
"Sensor": { "Type": "Any" },
"BodyMotion": { "Type": "Wander", "MaxHeadingChange": 45, "RelativeSpeed": 0.3 }
}
]
}
]
}
Priority: Block sensor (crystal targeting) > Player sensor (combat) > Wander (idle).
Reserve: true: prevents multiple NPCs from targeting the same block.
Block: detects specific block sets. Range, Blocks (set name), Reserve (exclusive)Player: detects players. Range, LockOnTarget (persist targeting)Any: always matches (fallback/idle behavior)Seek: pathfind toward target. StopDistance, SlowDownDistance, RelativeSpeedWander: random movement. MaxHeadingChange, RelativeSpeedAim (head): look at target. RelativeTurnSpeed{ "Type": "Walk", "MaxWalkSpeed": 6, "RunThreshold": 0.7, "Gravity": 10, "MaxFallSpeed": 20, "Acceleration": 10 }
CAE controls NPC combat decision-making: when to attack, how much damage, cooldowns.
{
"Type": "CombatActionEvaluator",
"TargetMemoryDuration": 10,
"CombatActionEvaluator": {
"RunConditions": [
{ "Type": "TimeSinceLastUsed", "Curve": { "ResponseCurve": "Linear", "XRange": [0, 5] } },
{ "Type": "Randomiser", "MinValue": 0.75, "MaxValue": 1 }
],
"MinRunUtility": 0.5,
"MinActionUtility": 0.01,
"AvailableActions": { ... },
"ActionSets": { ... }
}
}
{
"BasicAttacks": {
"Attacks": ["Root_Crystal_Spawn_Attack"],
"InteractionVars": {
"Melee_Damage": {
"Interactions": [{
"Parent": "NPC_Attack_Melee_Damage",
"DamageCalculator": { "Type": "Absolute", "BaseDamage": { "Physical": 48 }, "RandomPercentageModifier": 0.1 },
"DamageEffects": { "Knockback": { "Force": 0.5 }, "WorldSoundEventId": "SFX_Sword_T2_Impact" }
}]
}
},
"MaxRange": 3.5,
"CooldownRange": [0.5, 1.0],
"Timeout": 0.001
}
}
Interactions define attack animation chains with hit detection and damage.
Root Interaction (entry point):
{ "Interactions": [{ "Type": "Chaining", "ChainId": "Slashes", "ChainingAllowance": 15, "Next": ["Swing_Left", "Swing_Right"] }], "Tags": { "Attack": ["Melee"] } }
Simple (animation trigger):
{ "Type": "Simple", "Effects": { "ItemPlayerAnimationsId": "...", "ItemAnimationId": "SwingLeft" }, "RunTime": 0.1, "Next": { ... } }
Parallel (concurrent branches):
{ "Type": "Parallel", "Interactions": [ { "Interactions": [/* hit detection */] }, { "Interactions": [/* sound */] }, { "Interactions": [/* block break */] } ] }
Selector (hit detection cone):
{ "Type": "Selector", "RunTime": 0.25, "Selector": { "Id": "Horizontal", "Direction": "ToLeft", "StartDistance": 0.5, "EndDistance": 2, "Length": 60, "YawStartOffset": -30 }, "HitEntity": { "Interactions": [{ "Type": "Replace", "DefaultOk": true, "Var": "Melee_Damage" }] } }
Replace (damage injection from CAE):
{ "Type": "Replace", "DefaultOk": true, "DefaultValue": { "Interactions": ["NPC_Attack_Melee_Damage"] }, "Var": "Melee_Damage" }
Add Block_Break as a Parallel branch to enable NPC block destruction without any plugin code:
{ "Interactions": [{ "Type": "Simple", "RunTime": 0, "Next": "Block_Break" }] }
This is the v5.5.9 pattern — the engine handles block breaking natively through the interaction system.
WorldSoundEventId in interaction DamageEffects sections MUST reference valid sound events. Invalid IDs cause SEVERE asset validation failure and the entire mod will not load (server shuts down).
Known INVALID IDs (do not exist in current Hytale build):
SFX_Zombie_Attack_ImpactSFX_Light_Melee_T2_ImpactSFX_Unarmed_ImpactSafe approach: When unsure if a sound ID exists, omit WorldSoundEventId and WorldParticles from DamageEffects. Keep only Knockback:
"DamageEffects": {
"Knockback": { "Force": 0.5, "VelocityY": 3 }
}
Multi-file pattern for boss NPCs with special attacks:
Server/Drops/NPCs/<Faction>/Drop_Boss_Custom.json){
"Entries": [
{ "ItemId": "Ore_Special", "Count": 18 },
{ "Type": "Choice", "Entries": [
{ "Weight": 25, "ItemId": "Weapon_Daggers_Special", "Count": 1 },
{ "Weight": 25, "ItemId": "Weapon_Sword_Special", "Count": 1 },
{ "Weight": 25, "ItemId": "Weapon_Mace_Special", "Count": 1 },
{ "Weight": 25, "ItemId": "Weapon_Axe_Special", "Count": 1 }
]}
]
}
Server/Item/Interactions/NPCs/<Faction>/<Boss>/Boss_Special_Attack.json)Override vanilla damage with custom values:
{
"DamageCalculator": { "Type": "Absolute", "BaseDamage": { "Physical": 30 } },
"DamageEffects": {
"Knockback": { "Force": 3, "VelocityY": 5 },
"StaminaDrainMultiplier": 2.0,
"CameraEffect": { "Name": "HitBoss", "Intensity": 1 }
}
}
If the boss should destroy blocks with melee attacks, add HitBlock with DestroyBlock to the interaction's Parallel branch:
{ "HitBlock": { "Interactions": [{ "Type": "Simple", "RunTime": 0, "Next": "DestroyBlock" }] } }
Reference the custom drop table in the NPC Role JSON:
{ "DropList": "Drop_Boss_Custom" }
Items at Server/Item/Items/<Category>/<SubCategory>/<ItemId>.json:
{
"TranslationProperties": { "NameKey": "...", "DescriptionKey": "..." },
"Icon": { "Type": "Item", "ItemId": "..." },
"Categories": [...],
"BlockType": { "Material": "Solid", "DrawType": "Cube", "Opacity": "Opaque", ... },
"Gathering": { "DropList": [...], "GatherType": "..." },
"Recipe": { "Input": [{ "ItemId": "...", "Quantity": 4 }], "BenchRequirement": { "Id": "...", "Type": "...", "Categories": [...] } }
}