Skip to content

ECS Events

Package: com.hypixel.hytale.server.core.event.events.ecs + modules.entity.damage

ECS events are a separate event mechanism from the event bus. They are dispatched through the ECS store (store.invoke) rather than IEventBus, and handlers are registered as ECS systems rather than with eventRegistry.register().

Event BusECS Events
DispatcheventBus.dispatch(event)store.invoke(ref, event) or store.invoke(event)
ListeneventRegistry.register(Class, handler)storeRegistry.registerSystem(new MySystem())
Handlerlambda / Consumer<Event>class extending EntityEventSystem or WorldEventSystem
Entity accessevent.getPlayer() etc.handler parameters (ArchetypeChunk, Ref)
Filteringkeyed registrationgetQuery() archetype matching

For entity-scoped events dispatched to a specific entity via store.invoke(ref, event). The handler receives the entity’s archetype chunk and index, providing direct access to all of its components.

public class MyBreakBlockHandler extends EntityEventSystem<EntityStore, BreakBlockEvent> {
public MyBreakBlockHandler() {
super(BreakBlockEvent.class);
}
@Override
public void handle(int index, ArchetypeChunk<EntityStore> archetypeChunk,
Store<EntityStore> store, CommandBuffer<EntityStore> commandBuffer,
BreakBlockEvent event) {
// get entity reference
Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
// access components on the entity
Player player = archetypeChunk.getComponent(index, Player.getComponentType());
Vector3i blockPos = event.getTargetBlock();
if (shouldPrevent(player, blockPos)) {
event.setCancelled(true);
}
}
@Override
public Query<EntityStore> getQuery() {
return Player.getComponentType(); // only fire for entities with Player component
}
}

The handle parameters:

ParameterDescription
indexEntity’s index within the archetype chunk
archetypeChunkThe chunk containing the entity — use to read components
storeThe ECS store
commandBufferBuffered mutations (add/remove entities/components), applied after all handlers run
eventThe event object

For world-scoped events dispatched without an entity reference via store.invoke(event). No entity context or query filtering — the handler receives only the store.

public class MyPrefabPasteHandler extends WorldEventSystem<EntityStore, PrefabPasteEvent> {
public MyPrefabPasteHandler() {
super(PrefabPasteEvent.class);
}
@Override
public void handle(Store<EntityStore> store, CommandBuffer<EntityStore> commandBuffer,
PrefabPasteEvent event) {
int prefabId = event.getPrefabId();
if (isBlockedPrefab(prefabId)) {
event.setCancelled(true);
}
}
}

Register ECS event systems in your mod’s setup() method. PluginBase provides two store registries:

@Override
public void setup() {
// entity events (BreakBlockEvent, Damage, PlaceBlockEvent, etc.)
this.getEntityStoreRegistry().registerSystem(new MyBreakBlockHandler());
// chunk events (ChunkSaveEvent, ChunkUnloadEvent)
this.getChunkStoreRegistry().registerSystem(new MyChunkSaveHandler());
}

Systems registered through these registries are automatically unregistered when your mod shuts down.

EntityEventSystem implements QuerySystem, which means getQuery() controls which entities receive the event. The event is only delivered to entities whose archetype matches the query.

// only fire for entities with the Player component
@Override
public Query<EntityStore> getQuery() {
return Player.getComponentType();
}
// fire for entities with BOTH Player and Health components
@Override
public Query<EntityStore> getQuery() {
return Query.and(Player.getComponentType(), Health.getComponentType());
}
// fire for all entities (no filtering)
@Override
public Query<EntityStore> getQuery() {
return Query.any();
}

See Entity Queries for the full query API (Query.and, Query.or, Query.not).

WorldEventSystem does not have getQuery() — world events are always delivered to all registered handlers.

To fire an ECS event from your own code:

// entity-scoped: dispatches to all EntityEventSystems registered for this event type
// whose query matches the target entity's archetype
MyEvent event = new MyEvent(data);
store.invoke(targetRef, event);
// world-scoped: dispatches to all WorldEventSystems registered for this event type
store.invoke(event);

Both Store, CommandBuffer, and ComponentAccessor expose invoke. When dispatching from inside a handler, use the commandBuffer to dispatch (it forks the buffer for re-entrant safety).

After dispatch returns, check the event object for modifications:

store.invoke(ref, damageEvent);
if (damageEvent.isCancelled()) {
return; // a handler cancelled the damage
}
float finalAmount = damageEvent.getAmount(); // handlers may have modified this

ECS events can be cancellable by extending CancellableEcsEvent:

public class MyEvent extends CancellableEcsEvent {
// ...
}

When a handler calls event.setCancelled(true), all subsequent handlers skip the event. The base EventSystem class checks shouldProcessEvent() before each handler — if the event implements ICancellableEcsEvent and isCancelled() returns true, the handler is not invoked.

For events with multiple inheritance constraints, implement ICancellableEcsEvent directly instead of extending CancellableEcsEvent.

Two ECS stores exist, each with their own component registry:

StoreEventsRegistration
EntityStoreBreakBlockEvent, PlaceBlockEvent, Damage, ChangeGameModeEvent, PrefabPasteEvent, and othersgetEntityStoreRegistry()
ChunkStoreChunkSaveEvent, ChunkUnloadEventgetChunkStoreRegistry()

Chunk store events operate on WorldChunk entities rather than game entities. See Chunk Saving for a full ChunkStore handler example.



The primary damage event.

Class: com.hypixel.hytale.server.core.modules.entity.damage.Damage

This event is cancellable.

PropertyValue
ExtendsCancellableEcsEvent, IMetaStore<Damage>
CancellableYes
MethodReturn TypeDescription
getSource()@Nonnull SourceReturns the source of the damage
setSource(@Nonnull Source source)voidSets the source of the damage
getDamageCauseIndex()intReturns the index referencing a DamageCause asset
setDamageCauseIndex(int damageCauseIndex)voidSets the damage cause index
getCause()@Nullable DamageCauseReturns the DamageCause asset (deprecated)
getAmount()floatReturns the current damage amount
setAmount(float amount)voidSets the damage amount
getInitialAmount()floatReturns the original damage amount before modifications
getDeathMessage(@Nonnull Ref<EntityStore> targetRef, @Nonnull ComponentAccessor<EntityStore> componentAccessor)@Nonnull MessageReturns the death message for this damage
getMetaStore()@Nonnull IMetaStoreImpl<Damage>Returns the meta store for accessing additional damage data

Base interface for all damage sources.

MethodReturn TypeDescription
getDeathMessage(@Nonnull Damage info, @Nonnull Ref<EntityStore> targetRef, @Nonnull ComponentAccessor<EntityStore> componentAccessor)@Nonnull MessageReturns the death message for this damage source

Damage originating from an entity.

MethodReturn TypeDescription
getRef()@Nonnull Ref<EntityStore>Returns the reference to the source entity

Damage.ProjectileSource (extends EntitySource)

Section titled “Damage.ProjectileSource (extends EntitySource)”

Damage originating from a projectile.

MethodReturn TypeDescription
getRef()@Nonnull Ref<EntityStore>Returns the reference to the shooter entity (inherited)
getProjectile()@Nonnull Ref<EntityStore>Returns the reference to the projectile entity

Damage originating from a command.

No additional public getters beyond the inherited getDeathMessage() method.

Damage originating from the environment.

MethodReturn TypeDescription
getType()@Nonnull StringReturns the environment damage type identifier

Particle effects for damage impact.

MethodReturn TypeDescription
getModelParticles()@Nullable ModelParticle[]Returns model particles for the impact
setModelParticles(@Nullable ModelParticle[] modelParticles)voidSets the model particles
getWorldParticles()@Nullable WorldParticle[]Returns world particles for the impact
setWorldParticles(@Nullable WorldParticle[] worldParticles)voidSets the world particles
getViewDistance()doubleReturns the view distance for particles
setViewDistance(double viewDistance)voidSets the view distance for particles

Sound effect for damage impact.

MethodReturn TypeDescription
getSoundEventIndex()intReturns the sound event index
setSoundEventIndex(int soundEventIndex)voidSets the sound event index

Camera effect for damage impact.

MethodReturn TypeDescription
cameraEffectIndex()intReturns the camera effect index (record component)
getEffectIndex()intReturns the camera effect index

Additional data accessible via damage.getIfPresentMetaObject(key):

  • Damage.HIT_LOCATION - Vector4d
  • Damage.HIT_ANGLE - Float
  • Damage.IMPACT_PARTICLES - Damage.Particles
  • Damage.IMPACT_SOUND_EFFECT - Damage.SoundEffect
  • Damage.PLAYER_IMPACT_SOUND_EFFECT - Damage.SoundEffect
  • Damage.CAMERA_EFFECT - Damage.CameraEffect
  • Damage.DEATH_ICON - String
  • Damage.BLOCKED - Boolean (default: false)
  • Damage.STAMINA_DRAIN_MULTIPLIER - Float
  • Damage.CAN_BE_PREDICTED - Boolean (default: false)
  • Damage.KNOCKBACK_COMPONENT - KnockbackComponent
Damage.Source source = damage.getSource();
if (source instanceof Damage.EntitySource entitySource) {
Ref<EntityStore> attackerRef = entitySource.getRef();
}
if (source instanceof Damage.ProjectileSource projectileSource) {
Ref<EntityStore> projectile = projectileSource.getProjectile();
}
if (source instanceof Damage.CommandSource cmdSource) {
// command-initiated damage
}
if (source instanceof Damage.EnvironmentSource envSource) {
String type = envSource.getType();
}

Block events fire during player interaction chains. The flow depends on game mode:

  • Adventure modeDamageBlockEvent fires on each hit. When the block’s health reaches zero, BreakBlockEvent fires.
  • Creative modeBreakBlockEvent fires immediately (no damage phase).
  • PlacingPlaceBlockEvent fires after validation (Y range, collision, WorldConfig flags).
  • UsingUseBlockEvent.Pre fires before the block’s interaction chain, UseBlockEvent.Post fires after.

setTargetBlock() on BreakBlockEvent, PlaceBlockEvent, and DamageBlockEvent lets listeners redirect the operation to a different position — the server reads the value back after dispatch.


Fired when a block is broken.

Class: com.hypixel.hytale.server.core.event.events.ecs.BreakBlockEvent

This event is cancellable.

MethodReturn TypeDescription
getItemInHand()@Nullable ItemStackItem held when breaking, or null if empty
getTargetBlock()@Nonnull Vector3iPosition of the block being broken
setTargetBlock(@Nonnull Vector3i)voidRedirect the break to a different position
getBlockType()@Nonnull BlockTypeType of block being broken

Fired when a block is placed.

Class: com.hypixel.hytale.server.core.event.events.ecs.PlaceBlockEvent

This event is cancellable.

MethodReturn TypeDescription
getItemInHand()@Nullable ItemStackItem held when placing, or null if empty
getTargetBlock()@Nonnull Vector3iPosition where the block will be placed
setTargetBlock(@Nonnull Vector3i)voidRedirect the placement to a different position
getRotation()@Nonnull RotationTupleRotation of the placed block
setRotation(@Nonnull RotationTuple)voidOverride the placed block’s rotation

Fired when a block takes damage (during mining in adventure mode). Fires every hit — use setDamage() to modify the damage dealt, which the server reads back after dispatch.

Class: com.hypixel.hytale.server.core.event.events.ecs.DamageBlockEvent

This event is cancellable.

MethodReturn TypeDescription
getItemInHand()@Nullable ItemStackItem held when damaging, or null if empty
getTargetBlock()@Nonnull Vector3iPosition of the block being damaged
setTargetBlock(@Nonnull Vector3i)voidRedirect the damage to a different position
getBlockType()@Nonnull BlockTypeType of block being damaged
getCurrentDamage()floatAccumulated damage on the block before this hit
getDamage()floatDamage this hit will deal
setDamage(float)voidModify the damage this hit will deal

Fired when a block is used/interacted with. Has Pre and Post phases.

Class: com.hypixel.hytale.server.core.event.events.ecs.UseBlockEvent

MethodReturn TypeDescription
getInteractionType()@Nonnull InteractionTypeType of interaction
getContext()@Nonnull InteractionContextInteraction context (contains entity ref via getEntity())
getTargetBlock()@Nonnull Vector3iPosition of the block being used
getBlockType()@Nonnull BlockTypeType of block being used

Fired before the block interaction occurs. This event is cancellable.

Inherits all methods from UseBlockEvent.

Fired after the block interaction occurs. Not cancellable.

Inherits all methods from UseBlockEvent.

// useBlockEvent provides entity access through context
Ref<EntityStore> entityRef = event.getContext().getEntity();

Fired when items are dropped. Has subclasses for different drop types.

Class: com.hypixel.hytale.server.core.event.events.ecs.DropItemEvent

This event is cancellable.

Fired when a player requests to drop an item from their inventory. This event is cancellable.

MethodReturn TypeDescription
getInventorySectionId()intReturns the inventory section identifier
getSlotId()shortReturns the slot ID of the item to drop

Fired when an item is actually being dropped into the world. This event is cancellable.

MethodReturn TypeDescription
getItemStack()@Nonnull ItemStackReturns the item stack being dropped
setItemStack(@Nonnull ItemStack itemStack)voidSets the item stack to drop
getThrowSpeed()floatReturns the throw speed of the dropped item
setThrowSpeed(float throwSpeed)voidSets the throw speed of the dropped item

Fired when an item is picked up interactively.

Class: com.hypixel.hytale.server.core.event.events.ecs.InteractivelyPickupItemEvent

This event is cancellable.

MethodReturn TypeDescription
getItemStack()@Nonnull ItemStackReturns the item stack being picked up
setItemStack(@Nonnull ItemStack itemStack)voidSets the item stack being picked up

Fired when hotbar slot changes.

Class: com.hypixel.hytale.server.core.event.events.ecs.SwitchActiveSlotEvent

This event is cancellable.

MethodReturn TypeDescription
getInventorySectionId()intReturns the inventory section identifier
getPreviousSlot()intReturns the previously active slot index
getNewSlot()byteReturns the new slot index to switch to
setNewSlot(byte newSlot)voidSets the new slot index to switch to
isServerRequest()booleanReturns true if the slot change was initiated by the server
isClientRequest()booleanReturns true if the slot change was initiated by the client

Fired when crafting. Has Pre and Post phases, both cancellable. See Crafting & Recipes for usage examples and scope details.

Class: com.hypixel.hytale.server.core.event.events.ecs.CraftRecipeEvent

This event is cancellable.

MethodReturn TypeDescription
getCraftedRecipe()@Nonnull CraftingRecipeReturns the recipe being crafted
getQuantity()intReturns the quantity being crafted

Fired before crafting occurs. Cancel to prevent crafting. This event is cancellable.

Inherits all methods from CraftRecipeEvent.

Fired after crafting occurs. Cancel to prevent giving the crafted item. This event is cancellable.

Inherits all methods from CraftRecipeEvent.


Fired when a zone is discovered. Base class is not cancellable.

Class: com.hypixel.hytale.server.core.event.events.ecs.DiscoverZoneEvent

MethodReturn TypeDescription
getDiscoveryInfo()@Nonnull WorldMapTracker.ZoneDiscoveryInfoReturns information about the discovered zone

Fired when zone discovery UI would be shown. This event is cancellable.

Inherits all methods from DiscoverZoneEvent.


Fired when game mode changes.

Class: com.hypixel.hytale.server.core.event.events.ecs.ChangeGameModeEvent

This event is cancellable.

MethodReturn TypeDescription
getGameMode()@Nonnull GameModeReturns the game mode being changed to
setGameMode(@Nonnull GameMode gameMode)voidSets the game mode to change to