🎯 Puntos de Intercepción de Acciones

Acción del Jugador Evento a Escuchar ¿Cancelable?
⛏️ Minar bloque DamageBlockEvent, BreakBlockEvent ✅ Sí
🧱 Colocar bloque PlaceBlockEvent ✅ Sí
⚔️ Atacar entidad PlayerMouseButtonEvent + DamageEntityInteraction ✅ Sí
🍎 Usar/Consumir item UseBlockEvent.Pre, UseBlockEvent.Post ✅ Pre cancelable
📦 Soltar item DropItemEvent.PlayerRequest, DropItemEvent.Drop ✅ Sí
🖱️ Click (cualquiera) PlayerMouseButtonEvent ✅ Sí
🎮 Movimiento mouse PlayerMouseMotionEvent ✅ Sí
💬 Chat PlayerChatEvent ✅ Sí
🔗 Conectar/Desconectar PlayerConnectEvent, PlayerDisconnectEvent ⚠️ Parcial
📦 Cambio de inventario LivingEntityInventoryChangeEvent ❌ Solo notificación
🎒 Cambiar slot activo SwitchActiveSlotEvent ✅ Sí
🔨 Craftear CraftRecipeEvent, PlayerCraftEvent ✅ Sí

📝 Cómo Registrar Listeners de Eventos

Método 1: EventBus Global (Recomendado)

// En tu plugin, dentro del método setup()
@Override
protected void setup() {
    EventBus eventBus = HytaleServer.get().getEventBus();
    
    // Registrar listener para evento
    eventBus.register(PlayerMouseButtonEvent.class, this::handleMouseClick);
    eventBus.register(BreakBlockEvent.class, this::handleBreakBlock);
    eventBus.register(PlaceBlockEvent.class, this::handlePlaceBlock);
}

private void handleMouseClick(@Nonnull PlayerMouseButtonEvent event) {
    Player player = event.getPlayer();
    Item item = event.getItemInHand();
    Entity target = event.getTargetEntity();
    Vector3i block = event.getTargetBlock();
    
    // Cancelar la acción si es necesario
    if (shouldCancel(player, item)) {
        event.setCancelled(true);
    }
}

Método 2: EventRegistry del Plugin

// Usar el EventRegistry del plugin para auto-limpiar al desactivar
EventRegistry eventRegistry = this.getEventRegistry();
eventRegistry.register(LoadedAssetsEvent.class, MyAsset.class, this::onAssetLoaded);
💡
Diferencia clave
EventBus: Registro global, necesitas limpiar manualmente
EventRegistry: Auto-limpia cuando el plugin se desactiva

🧩 Eventos ECS (Bloques y Entidades)

Los eventos ECS extienden CancellableEcsEvent y se disparan desde sistemas de entidades/bloques:

BreakBlockEvent

public class BreakBlockEvent extends CancellableEcsEvent {
    ItemStack getItemInHand();     // Herramienta usada
    Vector3i getTargetBlock();     // Posición del bloque
    BlockType getBlockType();      // Tipo de bloque
    void setCancelled(boolean);    // Cancelar rotura
}

DamageBlockEvent (Minar)

public class DamageBlockEvent extends CancellableEcsEvent {
    ItemStack getItemInHand();      // Herramienta
    Vector3i getTargetBlock();      // Posición
    BlockType getBlockType();       // Tipo
    float getCurrentDamage();       // Daño acumulado
    float getDamage();              // Daño a aplicar
    void setDamage(float);          // Modificar daño!
}

PlaceBlockEvent

public class PlaceBlockEvent extends CancellableEcsEvent {
    ItemStack getItemInHand();
    Vector3i getTargetBlock();
    RotationTuple getRotation();   // Rotación del bloque
    void setTargetBlock(Vector3i); // Cambiar posición!
    void setRotation(RotationTuple);
}

UseBlockEvent (Pre/Post)

// Pre = ANTES de usar (cancelable)
public class UseBlockEvent.Pre implements ICancellableEcsEvent {
    InteractionType getInteractionType();
    InteractionContext getContext();
    Vector3i getTargetBlock();
    BlockType getBlockType();
}

// Post = DESPUÉS de usar (solo notificación)
public class UseBlockEvent.Post { ... }

🖱️ PlayerMouseButtonEvent (El Más Importante)

Este evento captura TODOS los clicks del jugador, antes de que se procesen las interacciones:

public class PlayerMouseButtonEvent extends PlayerEvent implements ICancellable {
    PlayerRef getPlayerRefComponent();
    long getClientUseTime();
    Item getItemInHand();           // Item que tiene en mano
    Vector3i getTargetBlock();       // Bloque apuntado (puede ser null)
    Entity getTargetEntity();        // Entidad apuntada (puede ser null)
    Vector2f getScreenPoint();       // Posición en pantalla
    MouseButtonEvent getMouseButton(); // Left/Right/Middle + State
}
Punto de Intercepción Universal
Escuchar este evento te permite interceptar CUALQUIER click antes de que Hytale lo procese. Ideal para sistemas anti-cheat, logging, o modificar comportamiento global.

⚔️ Sistema de Daño a Entidades

El daño se maneja a través de DamageSystems con múltiples etapas:

Sistema Función
DamageEntityInteraction Interacción que inicia el ataque
DamageCalculatorSystems Calcula daño con modificadores
ArmorDamageReduction Aplica reducción por armadura
HackKnockbackValues Calcula knockback
executeDamage() Aplica el daño final

Acceder al Daño

// Desde DamageEntityInteraction
for (Damage damageEvent : hits) {
    damageEvent.putMetaObject(Damage.KNOCKBACK_COMPONENT, knockback);
    float damageValue = damageEvent.getAmount();
    damageEvent.setAmount(damageValue * modifier);  // Modificar daño
    commandBuffer.invoke(targetRef, damageEvent);
}

🔗 Sistema de Interactions (Acciones de Items)

InteractionModule registra 50+ tipos de interacciones que definen el comportamiento de items:

Interacciones del Servidor (Modificables)

Interaction Acción
DamageEntity Atacar entidad
ModifyInventory Modificar inventario
ChangeStat Cambiar estadísticas
EquipItem Equipar item
LaunchProjectile Lanzar proyectil
SpawnPrefab Spawnear entidad
ApplyEffect Aplicar efecto
OpenContainer Abrir contenedor

Interacciones del Cliente

Interaction Acción
PlaceBlock Colocar bloque
BreakBlock Romper bloque
DestroyBlock Destruir bloque
UseBlock Usar bloque
UseEntity Usar entidad
Charging Cargar ataque
Wielding Empuñar arma

📋 Ejemplo: Plugin que Intercepta Todas las Acciones

public class ActionInterceptorPlugin extends JavaPlugin {
    
    public ActionInterceptorPlugin(JavaPluginInit init) {
        super(init);
    }
    
    @Override
    protected void setup() {
        EventBus bus = HytaleServer.get().getEventBus();
        
        // Clicks del ratón (CUALQUIER acción)
        bus.register(PlayerMouseButtonEvent.class, this::onMouseClick);
        
        // Bloques
        bus.register(BreakBlockEvent.class, this::onBreakBlock);
        bus.register(PlaceBlockEvent.class, this::onPlaceBlock);
        bus.register(DamageBlockEvent.class, this::onDamageBlock);
        
        // Items
        bus.register(DropItemEvent.class, this::onDropItem);
        bus.register(SwitchActiveSlotEvent.class, this::onSwitchSlot);
        
        // Crafteo
        bus.register(CraftRecipeEvent.class, this::onCraft);
        
        // Conexión
        bus.register(PlayerConnectEvent.class, this::onConnect);
        bus.register(PlayerDisconnectEvent.class, this::onDisconnect);
    }
    
    private void onMouseClick(PlayerMouseButtonEvent e) {
        // Acceso a TODO: jugador, item, target block/entity
        log("Click: " + e.getMouseButton() + " con " + e.getItemInHand());
        
        // Cancelar si es necesario
        if (shouldBlock(e.getPlayer())) {
            e.setCancelled(true);
        }
    }
    
    private void onDamageBlock(DamageBlockEvent e) {
        // Modificar velocidad de minado
        e.setDamage(e.getDamage() * 2.0f); // 2x más rápido
    }
}

📁 Archivos Clave

  • 📄 InteractionModule.java 384 líneas - Registro de interacciones
  • 📄 PlayerMouseButtonEvent.java 89 líneas - Evento de clicks
  • 📄 BreakBlockEvent.java 48 líneas - Evento de rotura
  • 📄 DamageBlockEvent.java 64 líneas - Evento de minar
  • 📄 PlaceBlockEvent.java 54 líneas - Evento de colocar
  • 📄 DamageSystems.java 1451 líneas - Sistema de daño
  • 📄 DamageEntityInteraction.java Interacción de ataque