📡 Sistema de Eventos y Acciones del Jugador
Guía para interceptar todas las acciones del jugador: atacar, minar, comer, moverse, interactuar con bloques y entidades. Sistema de EventBus y eventos ECS cancelables.
🎯 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.
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