Asset-Based Interactions
The most common way to create custom interactions is through JSON asset files. This allows you to define interaction chains, damage calculations, animations, and effects without writing Java code.
Asset Locations
Section titled “Asset Locations”DirectoryAssets/Server/Item/
DirectoryInteractions/
DirectoryWeapons/
- DamageEntityParent.json
DirectorySword/
DirectoryAttacks/
DirectoryPrimary/
- …
DirectorySignature/
- …
DirectoryRootInteractions/
DirectoryWeapons/
DirectorySword/
- Root_Weapon_Sword_Primary.json
- Root_Weapon_Sword_Signature_Vortexstrike.json
DirectoryItems/
DirectoryWeapon/
DirectorySword/
- …
Interaction System Architecture
Section titled “Interaction System Architecture”flowchart LR
subgraph ItemDef["Item Definition"]
Item["Interactions:<br/>Primary: Root_...<br/>Ability1: Root_..."]
end
subgraph RootInt["Root Interaction"]
Root["Interactions:<br/>[Weapon_Sword_Primary]"]
end
subgraph Chain["Interaction Chain"]
Charging["Type: Charging<br/>Next: Chain"]
Selector["Type: Selector<br/>HitEntity: ..."]
end
subgraph Vars["InteractionVars"]
Override["Swing_Damage<br/>Parent: Custom"]
end
Item --> Root
Root --> Charging
Charging --> Selector
Selector -.->|"Replace with<br/>custom damage"| Override
Interaction Types
Section titled “Interaction Types”Each interaction JSON file specifies a Type that determines its behavior:
| Type | Description | Key Fields |
|---|---|---|
Simple | Basic timed operation | RunTime, Effects |
Charging | Hold-to-charge mechanic | DisplayProgress, Next (time-based) |
Chaining | Combo system | ChainId, ChainingAllowance, Next (array) |
Selector | Hit detection sweep | Selector, HitEntity, HitBlock |
DamageEntity | Apply damage to entity | DamageCalculator, DamageEffects |
Serial | Run interactions in sequence | Interactions (array) |
Parallel | Run interactions simultaneously | Interactions (array) |
Replace | Var replacement for extensibility | Var, DefaultValue |
StatsCondition | Check/consume stats | Costs, ValueType, Next |
ApplyEffect | Apply entity effect | EffectId, Entity |
ClearEntityEffect | Remove entity effect | EntityEffectId, Entity |
ChangeStat | Modify entity stats | StatModifiers, ValueType |
RunOnBlockTypes | Search blocks and run interactions | Range, BlockSets, MaxCount, Interactions |
Creating a Custom Parent Interaction
Section titled “Creating a Custom Parent Interaction”To create a reusable Parent that other interactions can inherit from, create a JSON file with the desired base properties:
{ "Type": "DamageEntity", "DamageCalculator": { "Class": "Heavy" }, "DamageEffects": { "Knockback": { "Type": "Force", "Force": 8.0, "VelocityY": 3.0 }, "WorldParticles": [ { "SystemId": "Impact_Blade_01" } ] }, "Next": { "Type": "Serial", "Interactions": [ { "Type": "ApplyEffect", "EffectId": "Red_Flash", "Entity": "Target" } ] }}Then reference it as a Parent in your item’s InteractionVars:
{ "Parent": "Template_Weapon_Sword", "InteractionVars": { "Swing_Left_Damage": { "Interactions": [ { "Parent": "MyPlugin_DamageParent", "DamageCalculator": { "BaseDamage": { "Physical": 25 } } } ] } }}DamageEntity Interaction Schema
Section titled “DamageEntity Interaction Schema”{ "Parent": "DamageEntityParent", "DamageCalculator": { "Class": "Light", "BaseDamage": { "Physical": 18, "Fire": 5 }, "Type": "Absolute", "RandomPercentageModifier": 0.15 }, "Effects": { "CameraEffect": "Impact" }, "DamageEffects": { "Knockback": { "Type": "Force", "VelocityConfig": { "AirResistance": 0.99, "GroundResistance": 0.94, "Threshold": 3.0, "Style": "Linear" }, "Direction": { "X": 0, "Y": 1, "Z": -2 }, "Force": 6.0, "VelocityType": "Set" }, "WorldSoundEventId": "SFX_Sword_T2_Impact", "LocalSoundEventId": "SFX_Sword_T2_Impact", "WorldParticles": [ { "SystemId": "Impact_Sword_Basic" } ], "CameraEffect": "Impact_Light" }, "EntityStatsOnHit": [ { "EntityStatId": "SignatureEnergy", "Amount": 1 } ]}| Field | Type | Description |
|---|---|---|
Parent | string | Parent interaction to inherit from |
DamageCalculator.Class | string | Damage class: Light, Heavy, Signature |
DamageCalculator.BaseDamage | object | Damage by type: Physical, Fire, Ice, etc. |
DamageEffects.Knockback | object | Knockback force and direction |
DamageEffects.WorldParticles | array | Particles spawned on hit |
EntityStatsOnHit | array | Stats modified on successful hit |
Simple Interaction with Animation
Section titled “Simple Interaction with Animation”{ "Type": "Simple", "RunTime": 0.117, "Effects": { "ItemAnimationId": "SwingLeft", "WorldSoundEventId": "SFX_Light_Melee_T2_Swing", "LocalSoundEventId": "SFX_Sword_T2_Swing_RL_Local" }, "Next": { "Type": "Replace", "Var": "Swing_Left_Selector", "DefaultOk": true, "DefaultValue": { "Interactions": ["MyPlugin_Swing_Left_Selector"] } }}| Field | Type | Description |
|---|---|---|
RunTime | float | Duration in seconds |
Effects.ItemAnimationId | string | Animation ID from the item’s animation set |
Effects.WorldSoundEventId | string | Sound played for all players |
Effects.LocalSoundEventId | string | Sound played only for the player |
Effects.Trails | array | Trail effects during swing |
Effects.CameraEffect | string | Camera shake/effect ID |
Selector Interaction (Hit Detection)
Section titled “Selector Interaction (Hit Detection)”{ "Type": "Selector", "RunTime": 0.05, "Effects": { "ItemAnimationId": "SwingLeftCharged", "Trails": [ { "TrailId": "Sword_Trail", "StartDistance": 0.1, "EndDistance": 1.3 } ], "CameraEffect": "Sword_Swing_Diagonal_Right" }, "Selector": { "Id": "Horizontal", "Direction": "ToLeft", "TestLineOfSight": false, "StartDistance": 0.1, "EndDistance": 2.75, "Length": 90, "ExtendTop": 0.5, "ExtendBottom": 1.0, "YawStartOffset": -45 }, "HitBlock": { "Interactions": ["Block_Damage"] }, "HitEntity": { "Interactions": [ { "Type": "Replace", "Var": "Swing_Left_Damage", "DefaultOk": true, "DefaultValue": { "Interactions": ["MyPlugin_Swing_Left_Damage"] } } ] }}| Selector Field | Type | Description |
|---|---|---|
Id | string | Selector shape: Horizontal, Vertical, Thrust |
Direction | string | Sweep direction: ToLeft, ToRight |
StartDistance | float | Inner sweep radius |
EndDistance | float | Outer sweep radius |
Length | float | Arc angle in degrees (360 = full circle) |
ExtendTop/Bottom | float | Vertical extension of hitbox |
YawStartOffset | float | Starting angle offset |
TestLineOfSight | bool | Require line of sight to target |
Chaining Interaction (Combos)
Section titled “Chaining Interaction (Combos)”{ "Type": "Chaining", "ChainingAllowance": 2, "ChainId": "Sword_Swings", "Next": [ { "Type": "Replace", "Var": "Swing_Left", "DefaultOk": true, "DefaultValue": { "Interactions": ["MyPlugin_Swing_Left"] } }, { "Type": "Replace", "Var": "Swing_Right", "DefaultOk": true, "DefaultValue": { "Interactions": ["MyPlugin_Swing_Right"] } }, { "Type": "Replace", "Var": "Swing_Down", "DefaultOk": true, "DefaultValue": { "Interactions": ["MyPlugin_Swing_Down"] } } ]}| Field | Type | Description |
|---|---|---|
ChainId | string | Unique identifier for this combo chain |
ChainingAllowance | float | Time window to continue combo (seconds) |
Next | array | Sequence of interactions in the combo |
Var/Replace System
Section titled “Var/Replace System”The Replace type enables extensibility by defining variable points that items can override:
{ "Type": "Simple", "RunTime": 0.1, "Next": { "Type": "Replace", "Var": "Custom_Damage", "DefaultOk": true, "DefaultValue": { "Interactions": ["Default_Damage_Interaction"] } }}Items override these via InteractionVars:
{ "Parent": "Template_Weapon_Sword", "InteractionVars": { "Custom_Damage": { "Interactions": [ { "Parent": "DamageEntityParent", "DamageCalculator": { "BaseDamage": { "Physical": 30, "Fire": 10 } } } ] } }}Creating a Root Interaction
Section titled “Creating a Root Interaction”Root interactions are entry points that items reference:
{ "RequireNewClick": true, "ClickQueuingTimeout": 0.2, "Cooldown": { "Cooldown": 0.25 }, "Interactions": [ "MyPlugin_Custom_Primary" ]}| Field | Type | Description |
|---|---|---|
RequireNewClick | bool | Require new mouse click (not hold) |
ClickQueuingTimeout | float | Time to queue next click |
Cooldown.Cooldown | float | Cooldown duration in seconds |
Interactions | array | Interaction IDs to execute |
Signature Ability Example
Section titled “Signature Ability Example”Complete signature ability with stat cost:
{ "Type": "StatsCondition", "Costs": { "SignatureEnergy": 100 }, "ValueType": "Percent", "Next": { "Type": "Serial", "Interactions": [ { "Type": "Replace", "Var": "Signature_Effect", "DefaultOk": true, "DefaultValue": { "Interactions": ["MyPlugin_Signature_Spin"] } }, { "Type": "Simple", "RunTime": 0.15 }, { "Type": "Replace", "Var": "Signature_Finisher", "DefaultOk": true, "DefaultValue": { "Interactions": ["MyPlugin_Signature_Stab"] } }, { "Type": "ChangeStat", "StatModifiers": { "SignatureEnergy": -100 }, "ValueType": "Percent" } ] }}Parallel Interactions
Section titled “Parallel Interactions”Run multiple interactions simultaneously by forking into concurrent chains. Each entry in Interactions must be a RootInteraction string ID (not an inline object):
{ "Type": "Parallel", "Interactions": [ "Root_MyPlugin_Force_Effect", "Root_MyPlugin_Selector", "Root_MyPlugin_Particle_Effect" ]}RunOnBlockTypes Interaction
Section titled “RunOnBlockTypes Interaction”Search for blocks matching a BlockSet within a radius and run interactions on each found block:
{ "Type": "RunOnBlockTypes", "Range": 5.0, "BlockSets": ["Destructible_Stone", "Destructible_Wood"], "MaxCount": 20, "Interactions": [ { "Type": "Simple", "RunTime": 0.1, "Effects": { "WorldParticles": [{ "SystemId": "Block_Break" }] } } ]}| Field | Type | Description |
|---|---|---|
Range | float | Search radius in blocks (spherical) |
BlockSets | string[] | Array of BlockSet IDs to match |
MaxCount | int | Maximum blocks to affect (uses reservoir sampling) |
Interactions | array | Interaction chain to run on each found block |
Use Cases:
- AOE destruction abilities (break all nearby stone)
- Terrain modification spells (convert grass to dirt)
- Resource gathering sweeps (harvest all crops in range)
- Environmental effects (ignite all wood blocks)
{ "Type": "RunOnBlockTypes", "Range": 8.0, "BlockSets": ["Water_Sources"], "MaxCount": 50, "Interactions": [ { "Type": "Serial", "Interactions": [ { "Type": "Simple", "RunTime": 0.05, "Effects": { "WorldParticles": [{ "SystemId": "Frost_Spread" }], "WorldSoundEventId": "SFX_Ice_Form" } } ] } ]}Complete Custom Weapon Example
Section titled “Complete Custom Weapon Example”Here’s a complete example of a custom weapon with its own interaction chain:
1. Create the damage interaction (inherits from DamageEntityParent):
{ "Parent": "DamageEntityParent", "DamageCalculator": { "Class": "Heavy" }, "Effects": { "CameraEffect": "Impact" }, "DamageEffects": { "Knockback": { "Type": "Force", "Direction": { "X": 0, "Y": 2, "Z": -3 }, "Force": 10.0, "VelocityType": "Set" }, "WorldParticles": [ { "SystemId": "Impact_Blade_Heavy" } ], "CameraEffect": "Impact_Heavy" }, "EntityStatsOnHit": [ { "EntityStatId": "SignatureEnergy", "Amount": 2 } ]}2. Create the swing animation + selector:
{ "Type": "Simple", "RunTime": 0.2, "Effects": { "ItemAnimationId": "SwingDown", "WorldSoundEventId": "SFX_Heavy_Melee_Swing" }, "Next": { "Type": "Selector", "RunTime": 0.1, "Effects": { "Trails": [{ "TrailId": "Heavy_Blade_Trail" }], "CameraEffect": "Heavy_Swing" }, "Selector": { "Id": "Vertical", "Direction": "ToDown", "StartDistance": 0.2, "EndDistance": 3.0, "Length": 120 }, "HitEntity": { "Interactions": [ { "Type": "Replace", "Var": "Heavy_Damage", "DefaultOk": true, "DefaultValue": { "Interactions": ["MyPlugin_Heavy_Damage"] } } ] } }}3. Create the root interaction:
{ "RequireNewClick": true, "Cooldown": { "Cooldown": 0.5 }, "Interactions": ["MyPlugin_Swing"]}4. Create the weapon item:
{ "Parent": "Template_Weapon_Sword", "TranslationProperties": { "Name": "myplugin.items.greatsword_custom.name" }, "Model": "MyPlugin/Weapons/Greatsword_Custom.blockymodel", "Texture": "MyPlugin/Weapons/Greatsword_Custom_Texture.png", "Quality": "Epic", "ItemLevel": 40, "MaxDurability": 200, "DurabilityLossOnHit": 0.25, "Interactions": { "Primary": "Root_MyPlugin_Primary", "Secondary": "Root_Weapon_Sword_Secondary_Guard" }, "InteractionVars": { "Heavy_Damage": { "Interactions": [ { "Parent": "MyPlugin_Heavy_Damage", "DamageCalculator": { "BaseDamage": { "Physical": 35 } } } ] } }}Animation IDs
Section titled “Animation IDs”Available animation IDs depend on the item’s PlayerAnimationsId. For swords:
| Animation ID | Description |
|---|---|
SwingLeft | Horizontal left swing |
SwingRight | Horizontal right swing |
SwingDown | Vertical downward swing |
Thrust | Forward thrust |
SpinRightCharging | Spin charge-up |
SpinRightCharged | Spin attack |
Guard | Blocking stance |
GuardHit | Block impact reaction |
Best Practices
Section titled “Best Practices”- Use Parent inheritance - Create base damage interactions and override specific values
- Use Replace vars - Make interactions extensible so items can customize behavior
- Prefix custom files - Use your plugin name prefix for all custom interactions
- Chain interactions logically - Animation → Selector → Damage is the standard pattern
- Test with different targets - Verify hit detection with blocks and entities
- Balance cooldowns - Match cooldown to animation length
Related
Section titled “Related”- Interaction System Overview - System architecture
- Interaction Types - All 25 interaction types
- Control Flow Patterns - Serial, Parallel, Repeat
- Charging Mechanics - Hold-to-charge patterns
- Java Operations - Custom Operation types in Java
- Block Tracking - Track block placements