The Interaction System in Hytale is a powerful, data-driven framework for defining player actions and their effects. Interactions are defined in JSON and handle everything from breaking blocks to using items and triggering abilities.
graph TD
A[Player Action] -->|Client Sends| B[Interaction Packet]
B -->|Network| C[Server Processes]
C --> D{Interaction Type?}
D -->|Block| E[BlockConditionInteraction]
D -->|Item Use| F[RootInteraction]
D -->|Entity| G[DamageEntityInteraction]
E --> H[Execute Interaction Chain]
F --> H
G --> H
H --> I[Apply Effects]
I --> J[Sync to Clients]
The InteractionType enum defines when an interaction can be triggered:
| Type | Trigger | Example Use Case |
|---|---|---|
| PRIMARY | Left-click / Main action | Mining blocks, melee attacks |
| SECONDARY | Right-click / Secondary action | Place blocks, use items |
| TERTIARY | Special action button | Ability activation |
| HOLD | Continuous hold | Charging bows, eating food |
| RELEASE | Button release | Fire charged projectile |
Interactions in Hytale use a chain pattern where multiple actions can be sequenced:
graph LR
A[Primary Interaction] --> B[Condition Check]
B -->|Pass| C[Apply Effect]
C --> D[Chained Interaction]
D --> E[Next Action]
B -->|Fail| F[Cancel Chain]
An interaction definition consists of:
Interaction: Base class for all interactionsRootInteraction: Top-level interaction definition (attached to items/entities)ChainedInteraction: Interaction triggered by another interactionConditionalInteraction: Interaction that checks conditions before executingFrom the 71 interaction-related classes found:
BreakBlockInteraction: Mining/destroying blocksPlaceBlockInteraction: Placing blocks in the worldChangeBlockInteraction: Modifying existing blocks (doors, switches)BlockConditionInteraction: Conditional logic based on block statesDamageEntityInteraction: Deal damage to entitiesProjectileInteraction: Fire projectilesAngledDamage: Damage based on attack angle/momentumPickBlockInteraction: Pick block in creative modeModifyInventoryInteraction: Add/remove items from inventoryRefillContainerInteraction: Refill item containersApplyEffectInteraction: Apply status effectsClearEntityEffectInteraction: Remove effectsApplyForceInteraction: Apply physics forces (knockback)ChangeStateInteraction: Modify entity/block statesChangeStatInteraction: Modify statistics (health, mana)ChangeActiveSlotInteraction: Switch hotbar slotsChargingInteraction: Hold-to-charge mechanicsChainingInteraction: Sequential interaction chainsParallelInteraction: Execute multiple interactions simultaneouslyRepeatInteraction: Loop interactionsCancelChainInteraction: Stop interaction chain executionFrom RootInteractionSettings and InteractionConfiguration:
{
"type": "SECONDARY",
"cooldown": {
"duration": 1.5,
"resetOnCancel": true
},
"conditions": [
{
"type": "MemoriesCondition",
"requiredLevel": 5
}
],
"effects": [
{
"type": "ApplyEffect",
"effect": "hytale:speed_boost",
"duration": 10.0
}
],
"chainData": {
"next": "hytale:follow_up_interaction"
}
}
From InteractionPriority:
When multiple interactions are valid, priority determines execution order:
Interactions can have multiple condition types:
CooldownConditionInteraction: Check if cooldown expiredMemoriesConditionInteraction: Require progression levelEffectConditionInteraction: Require active status effectBlockConditionInteraction: Check block state/typeMovementConditionInteraction: Check player movement stateFrom InteractionEffects:
Effects are what actually happen when an interaction executes:
// Apply a status effect to the player
{
"type": "ApplyEffect",
"target": "SELF",
"effect": "hytale:regeneration",
"duration": 30.0,
"amplifier": 1
}
// Change a block in the world
{
"type": "ChangeBlock",
"position": "TARGET",
"newBlock": "hytale:torch_on",
"playSound": true
}
// Consume an item from inventory
{
"type": "ModifyInventory",
"operation": "REMOVE",
"item": "hytale:apple",
"amount": 1,
"slot": "ACTIVE"
}
From InteractionTarget:
Interactions can target different entities:
From InteractionCooldown and IncrementCooldownInteraction:
stateDiagram-v2
[*] --> Ready
Ready --> Active: Interaction Triggered
Active --> Cooldown: Execute Action
Cooldown --> Ready: Duration Expires
Cooldown --> Ready: ResetCooldown Called
Cooldown --> Cooldown: IncrementCooldown
// Example: Set a custom cooldown
{
"type": "IncrementCooldown",
"cooldownId": "my_plugin:special_ability",
"duration": 5.0
}
// Reset a cooldown early
{
"type": "ResetCooldown",
"cooldownId": "my_plugin:special_ability"
}
From InteractionChainData and ChainingInteraction:
Execute interactions one after another:
{
"interaction": "first_action",
"chainData": {
"next": "second_action",
"delay": 0.5
}
}
From ChainFlagInteraction:
Branch based on success/failure:
{
"interaction": "try_action",
"chainData": {
"onSuccess": "success_action",
"onFailure": "failure_action"
}
}
From ParallelInteraction:
Run multiple interactions simultaneously:
{
"type": "ParallelInteraction",
"interactions": [
"play_sound",
"apply_effect",
"spawn_particles"
]
}
From CameraInteraction and InteractionCamera:
Interactions can control the camera:
{
"type": "CameraInteraction",
"settings": {
"shake": {
"intensity": 0.5,
"duration": 0.3
}
}
}
From BuilderToolInteraction:
Special interaction type for creative building tools:
These are handled by dedicated builder packets (400+ packet IDs).
@Override
public void setup() {
// Listen to any interaction event
getEventRegistry().register(PlayerInteractEvent.class, event -> {
Player player = event.getPlayer();
InteractionType type = event.getInteractionType();
if (type == InteractionType.SECONDARY) {
// Player right-clicked
ItemStack item = player.getActiveItem();
if (item.getId().equals("my_mod:special_item")) {
event.setCancelled(true); // Cancel default interaction
// Custom logic here
player.sendMessage("Special item activated!");
}
}
});
}
Interactions are primarily defined in JSON within item/entity definitions:
{
"id": "my_mod:magic_wand",
"interactions": {
"SECONDARY": {
"type": "RootInteraction",
"settings": {
"cooldown": { "duration": 2.0 },
"conditions": [
{
"type": "CooldownCondition",
"cooldownId": "my_mod:magic_wand"
}
],
"effects": [
{
"type": "ProjectileInteraction",
"projectile": "my_mod:magic_bolt",
"speed": 30.0
},
{
"type": "IncrementCooldown",
"cooldownId": "my_mod:magic_wand",
"duration": 2.0
}
]
}
}
}
}
From InteractionState and InteractionSyncData:
The server tracks interaction states:
Interaction states must be synced to clients for UI feedback:
From AOECircleSelector and AOECylinderSelector:
Interactions can affect multiple targets:
{
"type": "DamageEntity",
"aoeType": "CIRCLE",
"radius": 5.0,
"maxTargets": 10,
"filters": {
"excludeSelf": true,
"targetType": "ENEMY"
}
}
From FirstClickInteraction:
Distinguish between:
{
"type": "FirstClick",
"initialDelay": 0.0,
"repeatDelay": 0.5, // 0.5s between subsequent triggers
"interaction": "attack_action"
}
When a player performs an interaction, the client sends:
The server broadcasts interaction results:
// ❌ Bad: Heavy logic in interaction handler
event.getInteraction().execute(() -> {
// Complex pathfinding, database queries, etc.
});
// ✅ Good: Offload to async task
event.getInteraction().execute(() -> {
scheduler.runAsync(() -> {
// Heavy computation
});
});
Always validate interactions server-side:
public boolean validateInteraction(Player player, Interaction interaction) {
// Check permissions
if (!player.hasPermission(interaction.getRequiredPermission())) {
return false;
}
// Check cooldowns
if (player.isOnCooldown(interaction.getCooldownId())) {
return false;
}
// Check resources (mana, stamina, etc.)
if (!player.hasResources(interaction.getResourceCost())) {
return false;
}
return true;
}
Break complex interactions into reusable chains:
{
"base_attack": {
"effects": [
{ "type": "DamageEntity", "amount": 10 },
{ "type": "ApplyForce", "magnitude": 5.0 }
]
},
"critical_attack": {
"chainData": {
"bases": ["base_attack"],
"additionalEffects": [
{ "type": "PlaySound", "sound": "critical_hit" }
]
}
}
}
Interactions can modify movement:
{
"type": "ApplyForceInteraction",
"direction": "FORWARD",
"magnitude": 20.0,
"movementType": "INSTANT"
}
Interactions trigger EntityEventSystem updates:
EntityDamagedEventInteractions respect the permission system:
interaction.setRequiredPermission("my_plugin.ability.fireball");
ConditionInteraction requirements are metFirstClickInteraction: Require button releaseInteractionSyncData: Verify sync settingsCreate complex state-based systems:
stateDiagram-v2
[*] --> Idle
Idle --> Charging: Hold Button
Charging --> Charged: Full Charge
Charged --> Release: Release Button
Release --> Cooldown: Fire Projectile
Cooldown --> Idle: Cooldown Expires
Charging --> Idle: Release Early
Chain interactions based on timing:
// Detect rapid sequential interactions
if (timeSinceLastInteraction < 0.5) {
comboCounter++;
if (comboCounter == 3) {
executeComboFinisher();
}
}
Change interaction behavior based on context:
if (player.isSneaking()) {
// Execute alternate interaction
} else {
// Execute default interaction
}