20 KiB
title, type, weight
| title | type | weight |
|---|---|---|
| Block Events | docs | 3 |
Events triggered by block interactions and changes. These events use the ECS (Entity Component System) pattern.
Breaking & Placing Events
BreakBlockEvent
{{< badge "Cancellable" >}} {{< badge "ECS" >}}
Fired when a block is being broken.
Package: com.hypixel.hytale.server.core.event.events.ecs
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| targetBlock | Vector3i |
Block position |
| blockType | BlockType |
Type of block |
| itemInHand | ItemStack |
Tool being used |
| {{< /tab >}} | ||
| {{< tab >}} |
getTargetBlock()- Returns block positiongetBlockType()- Returns block typegetItemInHand()- Returns tool being usedisCancelled()- Check if cancelledsetCancelled(boolean)- Cancel breaking {{< /tab >}} {{< tab >}}
getEventRegistry().register(BreakBlockEvent.class, event -> {
Vector3i position = event.getTargetBlock();
BlockType blockType = event.getBlockType();
ItemStack tool = event.getItemInHand();
// Protect certain blocks
if (blockType.getId().equals("special_ore")) {
event.setCancelled(true);
return;
}
// Log block break
getLogger().at(Level.INFO).log("Block broken at " + position + ": " + blockType.getId());
});
{{< /tab >}} {{< /tabs >}}
PlaceBlockEvent
{{< badge "Cancellable" >}} {{< badge "ECS" >}}
Fired when a block is placed.
Package: com.hypixel.hytale.server.core.event.events.ecs
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| targetBlock | Vector3i |
Position where block will be placed |
| rotation | RotationTuple |
Block rotation/orientation |
| itemInHand | ItemStack |
Block item being placed |
| {{< /tab >}} | ||
| {{< tab >}} |
getTargetBlock()- Returns target positionsetTargetBlock(Vector3i)- Change placement positiongetRotation()- Returns block rotationsetRotation(RotationTuple)- Change rotationgetItemInHand()- Returns block itemisCancelled()- Check if cancelledsetCancelled(boolean)- Cancel placement {{< /tab >}} {{< tab >}}
getEventRegistry().register(PlaceBlockEvent.class, event -> {
Vector3i position = event.getTargetBlock();
RotationTuple rotation = event.getRotation();
ItemStack item = event.getItemInHand();
// Check build permissions
if (isProtectedArea(position)) {
event.setCancelled(true);
return;
}
// Force certain rotation
event.setRotation(RotationTuple.of(Rotation.North, Rotation.None, Rotation.None));
});
{{< /tab >}} {{< /tabs >}}
DamageBlockEvent
{{< badge "Cancellable" >}} {{< badge "ECS" >}}
Fired when damage is applied to a block during breaking (before the block is fully broken).
Package: com.hypixel.hytale.server.core.event.events.ecs
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| targetBlock | Vector3i |
Block position |
| blockType | BlockType |
Type of block |
| itemInHand | ItemStack |
Tool being used (may be null) |
| currentDamage | float |
Damage already applied to block |
| damage | float |
Damage being applied this tick |
| {{< /tab >}} | ||
| {{< tab >}} |
getTargetBlock()- Returns block positionsetTargetBlock(Vector3i)- Change target blockgetBlockType()- Returns block typegetItemInHand()- Returns tool being usedgetCurrentDamage()- Returns accumulated damagegetDamage()- Returns damage this ticksetDamage(float)- Modify damage amountisCancelled()- Check if cancelledsetCancelled(boolean)- Cancel damage {{< /tab >}} {{< tab >}}
getEventRegistry().register(DamageBlockEvent.class, event -> {
Vector3i position = event.getTargetBlock();
BlockType blockType = event.getBlockType();
// Make certain blocks indestructible
if (blockType.getId().equals("bedrock")) {
event.setCancelled(true);
return;
}
// Reduce damage to hardened blocks
if (blockType.getId().startsWith("hardened_")) {
event.setDamage(event.getDamage() * 0.5f);
}
// Log mining progress
float progress = event.getCurrentDamage() / 100f;
getLogger().at(Level.INFO).log("Block " + blockType.getId() + " at " + progress + "% damage");
});
{{< /tab >}} {{< /tabs >}}
Interaction Events
UseBlockEvent
Base class for block use events. Has Pre and Post variants.
Package: com.hypixel.hytale.server.core.event.events.ecs
UseBlockEvent.Pre
{{< badge "Cancellable" >}}
Fired before a block use action occurs (right-click on block).
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| interactionType | InteractionType |
Type of interaction |
| context | InteractionContext |
Interaction context |
| targetBlock | Vector3i |
Block position |
| blockType | BlockType |
The block type |
| {{< /tab >}} | ||
| {{< tab >}} |
getInteractionType()- Returns interaction typegetContext()- Returns interaction contextgetTargetBlock()- Returns block positiongetBlockType()- Returns block typeisCancelled()- Check if cancelledsetCancelled(boolean)- Cancel use action {{< /tab >}} {{< tab >}}
getEventRegistry().register(UseBlockEvent.Pre.class, event -> {
Vector3i position = event.getTargetBlock();
BlockType blockType = event.getBlockType();
InteractionContext context = event.getContext();
// Prevent opening locked containers
if (isLocked(position)) {
event.setCancelled(true);
}
});
{{< /tab >}} {{< /tabs >}}
UseBlockEvent.Post
Fired after a block use action completes successfully.
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| interactionType | InteractionType |
Type of interaction |
| context | InteractionContext |
Interaction context |
| targetBlock | Vector3i |
Block position |
| blockType | BlockType |
The block type |
| {{< /tab >}} | ||
| {{< tab >}} |
getInteractionType()- Returns interaction typegetContext()- Returns interaction contextgetTargetBlock()- Returns block positiongetBlockType()- Returns block type {{< /tab >}} {{< tab >}}
getEventRegistry().register(UseBlockEvent.Post.class, event -> {
Vector3i position = event.getTargetBlock();
BlockType blockType = event.getBlockType();
// Track interactions for quests
if (isQuestBlock(blockType)) {
completeQuestObjective("interact_with_" + blockType.getId());
}
});
{{< /tab >}} {{< /tabs >}}
Item Events
DropItemEvent
{{< badge "Cancellable" >}} {{< badge "ECS" >}}
Fired when an item is dropped. Has two variants: Drop and PlayerRequest.
Package: com.hypixel.hytale.server.core.event.events.ecs
DropItemEvent.Drop
The actual drop event with item details.
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| itemStack | ItemStack |
Item being dropped |
| throwSpeed | float |
Speed of the throw |
| {{< /tab >}} | ||
| {{< tab >}} |
getItemStack()- Returns the item stacksetItemStack(ItemStack)- Change the dropped itemgetThrowSpeed()- Returns throw speedsetThrowSpeed(float)- Change throw speedisCancelled()- Check if cancelledsetCancelled(boolean)- Cancel drop {{< /tab >}} {{< tab >}}
getEventRegistry().register(DropItemEvent.Drop.class, event -> {
ItemStack item = event.getItemStack();
// Prevent dropping certain items
if (item.getId().equals("quest_item")) {
event.setCancelled(true);
return;
}
// Modify throw speed
event.setThrowSpeed(event.getThrowSpeed() * 1.5f);
});
{{< /tab >}} {{< /tabs >}}
DropItemEvent.PlayerRequest
Fired when a player requests to drop an item (before the actual drop).
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| inventorySectionId | int |
Inventory section ID |
| slotId | short |
Slot being dropped from |
| {{< /tab >}} | ||
| {{< tab >}} |
getInventorySectionId()- Returns inventory sectiongetSlotId()- Returns slot indexisCancelled()- Check if cancelledsetCancelled(boolean)- Cancel request {{< /tab >}} {{< tab >}}
getEventRegistry().register(DropItemEvent.PlayerRequest.class, event -> {
int sectionId = event.getInventorySectionId();
short slot = event.getSlotId();
// Prevent dropping from certain slots
if (sectionId == Inventory.HOTBAR && slot == 0) {
event.setCancelled(true); // Can't drop first hotbar item
}
});
{{< /tab >}} {{< /tabs >}}
InteractivelyPickupItemEvent
{{< badge "Cancellable" >}} {{< badge "ECS" >}}
Fired when a player picks up an item interactively (manual pickup, not auto-pickup).
Package: com.hypixel.hytale.server.core.event.events.ecs
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| itemStack | ItemStack |
The item being picked up |
| {{< /tab >}} | ||
| {{< tab >}} |
getItemStack()- Returns the item stacksetItemStack(ItemStack)- Change the item being picked upisCancelled()- Check if cancelledsetCancelled(boolean)- Cancel pickup {{< /tab >}} {{< tab >}}
getEventRegistry().register(InteractivelyPickupItemEvent.class, event -> {
ItemStack item = event.getItemStack();
// Prevent picking up quest items that don't belong to player
if (item.getId().startsWith("quest_") && !canPickupQuestItem(player, item)) {
event.setCancelled(true);
return;
}
// Transform items when picking up
if (item.getId().equals("raw_ore")) {
event.setItemStack(item.withCount(item.getCount() * 2));
}
});
{{< /tab >}} {{< /tabs >}}
Crafting Events
CraftRecipeEvent
{{< badge "Cancellable" >}} {{< badge "ECS" >}}
Fired when a crafting recipe is executed. Has Pre and Post variants.
Package: com.hypixel.hytale.server.core.event.events.ecs
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| craftedRecipe | CraftingRecipe |
The recipe being crafted |
| quantity | int |
Number of items being crafted |
| {{< /tab >}} | ||
| {{< tab >}} |
getCraftedRecipe()- Returns the crafting recipegetQuantity()- Returns craft quantityisCancelled()- Check if cancelled (Pre only)setCancelled(boolean)- Cancel crafting (Pre only) {{< /tab >}} {{< tab >}}
// Pre-craft check
getEventRegistry().register(CraftRecipeEvent.Pre.class, event -> {
CraftingRecipe recipe = event.getCraftedRecipe();
int quantity = event.getQuantity();
// Block certain recipes
if (isRestrictedRecipe(recipe)) {
event.setCancelled(true);
}
});
// Post-craft tracking
getEventRegistry().register(CraftRecipeEvent.Post.class, event -> {
CraftingRecipe recipe = event.getCraftedRecipe();
int quantity = event.getQuantity();
// Track crafting statistics
incrementCraftCount(recipe.getId(), quantity);
});
{{< /tab >}} {{< /tabs >}}
Other Events
SwitchActiveSlotEvent
{{< badge "Cancellable" >}} {{< badge "ECS" >}}
Fired when a player switches their active hotbar slot.
Package: com.hypixel.hytale.server.core.event.events.ecs
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| inventorySectionId | int |
The inventory section ID |
| previousSlot | int |
The slot before switching |
| newSlot | byte |
The target slot |
| serverRequest | boolean |
If server initiated the switch |
| {{< /tab >}} | ||
| {{< tab >}} |
getInventorySectionId()- Returns inventory sectiongetPreviousSlot()- Returns previous slot indexgetNewSlot()- Returns new slot indexsetNewSlot(byte)- Change the target slotisServerRequest()- Check if server initiatedisClientRequest()- Check if client initiatedisCancelled()- Check if cancelledsetCancelled(boolean)- Cancel slot switch {{< /tab >}} {{< tab >}}
getEventRegistry().register(SwitchActiveSlotEvent.class, event -> {
int fromSlot = event.getPreviousSlot();
int toSlot = event.getNewSlot();
// Prevent switching during cooldown
if (isOnCooldown(player)) {
event.setCancelled(true);
return;
}
// Track slot usage for analytics
if (event.isClientRequest()) {
trackSlotSwitch(player, fromSlot, toSlot);
}
});
{{< /tab >}} {{< /tabs >}}
DiscoverZoneEvent
{{< badge "ECS" >}}
Fired when a player discovers a new zone. Has a Display variant that is cancellable.
Package: com.hypixel.hytale.server.core.event.events.ecs
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| discoveryInfo | ZoneDiscoveryInfo |
Information about the discovered zone |
| {{< /tab >}} | ||
| {{< tab >}} |
getDiscoveryInfo()- Returns zone discovery infoisCancelled()- Check if cancelled (Display only)setCancelled(boolean)- Cancel display (Display only) {{< /tab >}} {{< tab >}}
// Cancel zone discovery notification display
getEventRegistry().register(DiscoverZoneEvent.Display.class, event -> {
WorldMapTracker.ZoneDiscoveryInfo info = event.getDiscoveryInfo();
// Hide certain zones from discovery UI
if (isHiddenZone(info)) {
event.setCancelled(true);
return;
}
// Log discovery for achievements
recordZoneDiscovery(player, info);
});
{{< /tab >}} {{< /tabs >}}
ChangeGameModeEvent
{{< badge "Cancellable" >}} {{< badge "ECS" >}}
Fired when an entity's game mode changes.
Package: com.hypixel.hytale.server.core.event.events.ecs
{{< tabs items="Fields,Methods,Example" >}} {{< tab >}}
| Field | Type | Description |
|---|---|---|
| gameMode | GameMode |
The new game mode |
| {{< /tab >}} | ||
| {{< tab >}} |
getGameMode()- Returns the new game modesetGameMode(GameMode)- Change the target game modeisCancelled()- Check if cancelledsetCancelled(boolean)- Cancel mode change {{< /tab >}} {{< tab >}}
getEventRegistry().register(ChangeGameModeEvent.class, event -> {
GameMode newMode = event.getGameMode();
// Prevent creative mode in certain worlds
if (newMode == GameMode.CREATIVE && isRestrictedWorld(player.getWorld())) {
event.setCancelled(true);
player.sendMessage(Message.raw("Creative mode not allowed here!"));
return;
}
// Force adventure mode override
if (shouldForceAdventure(player)) {
event.setGameMode(GameMode.ADVENTURE);
}
getLogger().at(Level.INFO).log(player.getDisplayName() + " changed to " + newMode);
});
{{< /tab >}} {{< /tabs >}}
Practical Examples
Block Logger Plugin
public class BlockLoggerPlugin extends JavaPlugin {
@Override
public void start() {
getEventRegistry().register(PlaceBlockEvent.class, event -> {
logAction("PLACE", event.getTargetBlock(), event.getItemInHand());
});
getEventRegistry().register(BreakBlockEvent.class, event -> {
logAction("BREAK", event.getTargetBlock(), event.getBlockType());
});
}
private void logAction(String action, Vector3i pos, Object data) {
getLogger().at(Level.INFO).log(String.format("%s: %d,%d,%d - %s",
action, pos.x(), pos.y(), pos.z(), data));
}
}
Region Protection System
public class RegionPlugin extends JavaPlugin {
private final Set<Region> regions = new HashSet<>();
@Override
public void start() {
// Protect against breaking
getEventRegistry().register(EventPriority.EARLY, BreakBlockEvent.class, event -> {
if (isInProtectedRegion(event.getTargetBlock())) {
event.setCancelled(true);
}
});
// Protect against placing
getEventRegistry().register(EventPriority.EARLY, PlaceBlockEvent.class, event -> {
if (isInProtectedRegion(event.getTargetBlock())) {
event.setCancelled(true);
}
});
// Protect against use
getEventRegistry().register(EventPriority.EARLY, UseBlockEvent.Pre.class, event -> {
if (isInProtectedRegion(event.getTargetBlock())) {
event.setCancelled(true);
}
});
}
private boolean isInProtectedRegion(Vector3i pos) {
return regions.stream().anyMatch(r -> r.contains(pos));
}
}
Custom Ore System
public class CustomOrePlugin extends JavaPlugin {
private final Random random = new Random();
@Override
public void start() {
getEventRegistry().register(BreakBlockEvent.class, event -> {
BlockType blockType = event.getBlockType();
if (isCustomOre(blockType)) {
// Apply fortune multiplier
ItemStack tool = event.getItemInHand();
int fortuneLevel = getFortuneLevel(tool);
int dropMultiplier = 1 + random.nextInt(fortuneLevel + 1);
// Schedule custom drops
Vector3i pos = event.getTargetBlock();
scheduleOreDrops(pos, blockType, dropMultiplier);
}
});
}
private boolean isCustomOre(BlockType blockType) {
return blockType.getId().startsWith("custom_ore_");
}
}
Anti-Grief System
public class AntiGriefPlugin extends JavaPlugin {
private final Map<Vector3i, BlockAction> recentActions = new HashMap<>();
@Override
public void start() {
// Track block breaks for rollback
getEventRegistry().register(BreakBlockEvent.class, event -> {
Vector3i pos = event.getTargetBlock();
BlockType blockType = event.getBlockType();
recentActions.put(pos, new BlockAction(
ActionType.BREAK,
blockType,
System.currentTimeMillis()
));
});
// Track block places for rollback
getEventRegistry().register(PlaceBlockEvent.class, event -> {
Vector3i pos = event.getTargetBlock();
recentActions.put(pos, new BlockAction(
ActionType.PLACE,
null,
System.currentTimeMillis()
));
});
}
public void rollback(World world, int seconds) {
long cutoff = System.currentTimeMillis() - (seconds * 1000L);
recentActions.entrySet().stream()
.filter(e -> e.getValue().timestamp() >= cutoff)
.forEach(e -> {
Vector3i pos = e.getKey();
BlockAction action = e.getValue();
if (action.type() == ActionType.PLACE) {
// Remove placed blocks
world.breakBlock(pos.x(), pos.y(), pos.z());
} else if (action.blockType() != null) {
// Restore broken blocks
world.setBlock(pos.x(), pos.y(), pos.z(), action.blockType());
}
});
recentActions.clear();
}
record BlockAction(ActionType type, BlockType blockType, long timestamp) {}
enum ActionType { BREAK, PLACE }
}
Best Practices
{{< callout type="info" >}} Block Event Guidelines:
- Use
EventPriority.EARLYfor protection systems - ECS events provide detailed control over block operations
- Always validate positions before modifying blocks
- Consider chunk load state when working with distant blocks
- Clean up tracking data when no longer needed {{< /callout >}}
{{< callout type="warning" >}} Performance Note: Block events can fire very frequently. Avoid expensive operations in handlers and cache results where possible. {{< /callout >}}