---
title: Événements Bloc
type: docs
weight: 3
---

Événements déclenchés par les interactions et modifications de blocs. Ces événements utilisent le pattern ECS (Entity Component System).

## Événements de Destruction & Placement

### BreakBlockEvent

{{< badge "Annulable" >}} {{< badge "ECS" >}}

Déclenché quand un bloc est en train d'être cassé.

**Package :** `com.hypixel.hytale.server.core.event.events.ecs`

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| targetBlock | `Vector3i` | Position du bloc |
| blockType | `BlockType` | Type de bloc |
| itemInHand | `ItemStack` | Outil utilisé |
{{< /tab >}}
{{< tab >}}
- `getTargetBlock()` - Retourne la position du bloc
- `getBlockType()` - Retourne le type de bloc
- `getItemInHand()` - Retourne l'outil utilisé
- `isCancelled()` - Vérifie si annulé
- `setCancelled(boolean)` - Annule le cassage
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(BreakBlockEvent.class, event -> {
    Vector3i position = event.getTargetBlock();
    BlockType blockType = event.getBlockType();
    ItemStack tool = event.getItemInHand();

    // Protéger certains blocs
    if (blockType.getId().equals("special_ore")) {
        event.setCancelled(true);
        return;
    }

    // Logger le cassage
    getLogger().at(Level.INFO).log("Bloc cassé à " + position + ": " + blockType.getId());
});
```
{{< /tab >}}
{{< /tabs >}}

---

### PlaceBlockEvent

{{< badge "Annulable" >}} {{< badge "ECS" >}}

Déclenché quand un bloc est placé.

**Package :** `com.hypixel.hytale.server.core.event.events.ecs`

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| targetBlock | `Vector3i` | Position où le bloc sera placé |
| rotation | `RotationTuple` | Rotation/orientation du bloc |
| itemInHand | `ItemStack` | Item bloc placé |
{{< /tab >}}
{{< tab >}}
- `getTargetBlock()` - Retourne la position cible
- `setTargetBlock(Vector3i)` - Change la position de placement
- `getRotation()` - Retourne la rotation du bloc
- `setRotation(RotationTuple)` - Change la rotation
- `getItemInHand()` - Retourne l'item bloc
- `isCancelled()` - Vérifie si annulé
- `setCancelled(boolean)` - Annule le placement
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(PlaceBlockEvent.class, event -> {
    Vector3i position = event.getTargetBlock();
    RotationTuple rotation = event.getRotation();
    ItemStack item = event.getItemInHand();

    // Vérifier les permissions de construction
    if (isProtectedArea(position)) {
        event.setCancelled(true);
        return;
    }

    // Forcer une certaine rotation
    event.setRotation(RotationTuple.of(Rotation.North, Rotation.None, Rotation.None));
});
```
{{< /tab >}}
{{< /tabs >}}

---

### DamageBlockEvent

{{< badge "Annulable" >}} {{< badge "ECS" >}}

Déclenché quand des dégâts sont appliqués à un bloc pendant le cassage (avant que le bloc ne soit complètement cassé).

**Package :** `com.hypixel.hytale.server.core.event.events.ecs`

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| targetBlock | `Vector3i` | Position du bloc |
| blockType | `BlockType` | Type de bloc |
| itemInHand | `ItemStack` | Outil utilisé (peut être null) |
| currentDamage | `float` | Dégâts déjà appliqués au bloc |
| damage | `float` | Dégâts appliqués ce tick |
{{< /tab >}}
{{< tab >}}
- `getTargetBlock()` - Retourne la position du bloc
- `setTargetBlock(Vector3i)` - Change le bloc cible
- `getBlockType()` - Retourne le type de bloc
- `getItemInHand()` - Retourne l'outil utilisé
- `getCurrentDamage()` - Retourne les dégâts accumulés
- `getDamage()` - Retourne les dégâts ce tick
- `setDamage(float)` - Modifie le montant de dégâts
- `isCancelled()` - Vérifie si annulé
- `setCancelled(boolean)` - Annule les dégâts
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(DamageBlockEvent.class, event -> {
    Vector3i position = event.getTargetBlock();
    BlockType blockType = event.getBlockType();

    // Rendre certains blocs indestructibles
    if (blockType.getId().equals("bedrock")) {
        event.setCancelled(true);
        return;
    }

    // Réduire les dégâts sur les blocs renforcés
    if (blockType.getId().startsWith("hardened_")) {
        event.setDamage(event.getDamage() * 0.5f);
    }

    // Logger la progression du minage
    float progress = event.getCurrentDamage() / 100f;
    getLogger().at(Level.INFO).log("Bloc " + blockType.getId() + " à " + progress + "% de dégâts");
});
```
{{< /tab >}}
{{< /tabs >}}

---

## Événements d'Interaction

### UseBlockEvent

Classe de base pour les événements d'utilisation de bloc. A des variantes Pre et Post.

**Package :** `com.hypixel.hytale.server.core.event.events.ecs`

#### UseBlockEvent.Pre

{{< badge "Annulable" >}}

Déclenché avant qu'une action d'utilisation de bloc ne se produise (clic droit sur bloc).

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| interactionType | `InteractionType` | Type d'interaction |
| context | `InteractionContext` | Contexte d'interaction |
| targetBlock | `Vector3i` | Position du bloc |
| blockType | `BlockType` | Le type de bloc |
{{< /tab >}}
{{< tab >}}
- `getInteractionType()` - Retourne le type d'interaction
- `getContext()` - Retourne le contexte d'interaction
- `getTargetBlock()` - Retourne la position du bloc
- `getBlockType()` - Retourne le type de bloc
- `isCancelled()` - Vérifie si annulé
- `setCancelled(boolean)` - Annule l'action d'utilisation
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(UseBlockEvent.Pre.class, event -> {
    Vector3i position = event.getTargetBlock();
    BlockType blockType = event.getBlockType();
    InteractionContext context = event.getContext();

    // Empêcher l'ouverture de conteneurs verrouillés
    if (isLocked(position)) {
        event.setCancelled(true);
    }
});
```
{{< /tab >}}
{{< /tabs >}}

---

#### UseBlockEvent.Post

Déclenché après qu'une action d'utilisation de bloc s'est terminée avec succès.

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| interactionType | `InteractionType` | Type d'interaction |
| context | `InteractionContext` | Contexte d'interaction |
| targetBlock | `Vector3i` | Position du bloc |
| blockType | `BlockType` | Le type de bloc |
{{< /tab >}}
{{< tab >}}
- `getInteractionType()` - Retourne le type d'interaction
- `getContext()` - Retourne le contexte d'interaction
- `getTargetBlock()` - Retourne la position du bloc
- `getBlockType()` - Retourne le type de bloc
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(UseBlockEvent.Post.class, event -> {
    Vector3i position = event.getTargetBlock();
    BlockType blockType = event.getBlockType();

    // Suivre les interactions pour les quêtes
    if (isQuestBlock(blockType)) {
        completeQuestObjective("interact_with_" + blockType.getId());
    }
});
```
{{< /tab >}}
{{< /tabs >}}

---

## Événements d'Items

### DropItemEvent

{{< badge "Annulable" >}} {{< badge "ECS" >}}

Déclenché quand un item est lâché. A deux variantes : `Drop` et `PlayerRequest`.

**Package :** `com.hypixel.hytale.server.core.event.events.ecs`

#### DropItemEvent.Drop

L'événement de drop réel avec les détails de l'item.

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| itemStack | `ItemStack` | Item lâché |
| throwSpeed | `float` | Vitesse du lancer |
{{< /tab >}}
{{< tab >}}
- `getItemStack()` - Retourne le stack d'items
- `setItemStack(ItemStack)` - Change l'item lâché
- `getThrowSpeed()` - Retourne la vitesse de lancer
- `setThrowSpeed(float)` - Change la vitesse de lancer
- `isCancelled()` - Vérifie si annulé
- `setCancelled(boolean)` - Annule le drop
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(DropItemEvent.Drop.class, event -> {
    ItemStack item = event.getItemStack();

    // Empêcher de lâcher certains items
    if (item.getId().equals("quest_item")) {
        event.setCancelled(true);
        return;
    }

    // Modifier la vitesse de lancer
    event.setThrowSpeed(event.getThrowSpeed() * 1.5f);
});
```
{{< /tab >}}
{{< /tabs >}}

---

#### DropItemEvent.PlayerRequest

Déclenché quand un joueur demande à lâcher un item (avant le drop réel).

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| inventorySectionId | `int` | ID de la section d'inventaire |
| slotId | `short` | Slot depuis lequel on drop |
{{< /tab >}}
{{< tab >}}
- `getInventorySectionId()` - Retourne la section d'inventaire
- `getSlotId()` - Retourne l'index du slot
- `isCancelled()` - Vérifie si annulé
- `setCancelled(boolean)` - Annule la requête
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(DropItemEvent.PlayerRequest.class, event -> {
    int sectionId = event.getInventorySectionId();
    short slot = event.getSlotId();

    // Empêcher de drop depuis certains slots
    if (sectionId == Inventory.HOTBAR && slot == 0) {
        event.setCancelled(true);  // Ne peut pas drop le premier slot hotbar
    }
});
```
{{< /tab >}}
{{< /tabs >}}

---

### InteractivelyPickupItemEvent

{{< badge "Annulable" >}} {{< badge "ECS" >}}

Déclenché quand un joueur ramasse un item de manière interactive (ramassage manuel, pas auto-pickup).

**Package :** `com.hypixel.hytale.server.core.event.events.ecs`

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| itemStack | `ItemStack` | L'item ramassé |
{{< /tab >}}
{{< tab >}}
- `getItemStack()` - Retourne le stack d'items
- `setItemStack(ItemStack)` - Change l'item ramassé
- `isCancelled()` - Vérifie si annulé
- `setCancelled(boolean)` - Annule le ramassage
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(InteractivelyPickupItemEvent.class, event -> {
    ItemStack item = event.getItemStack();

    // Empêcher de ramasser des items de quête qui n'appartiennent pas au joueur
    if (item.getId().startsWith("quest_") && !canPickupQuestItem(player, item)) {
        event.setCancelled(true);
        return;
    }

    // Transformer les items au ramassage
    if (item.getId().equals("raw_ore")) {
        event.setItemStack(item.withCount(item.getCount() * 2));
    }
});
```
{{< /tab >}}
{{< /tabs >}}

---

## Événements de Craft

### CraftRecipeEvent

{{< badge "Annulable" >}} {{< badge "ECS" >}}

Déclenché quand une recette de craft est exécutée. A des variantes Pre et Post.

**Package :** `com.hypixel.hytale.server.core.event.events.ecs`

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| craftedRecipe | `CraftingRecipe` | La recette craftée |
| quantity | `int` | Nombre d'items craftés |
{{< /tab >}}
{{< tab >}}
- `getCraftedRecipe()` - Retourne la recette de craft
- `getQuantity()` - Retourne la quantité craftée
- `isCancelled()` - Vérifie si annulé (Pre uniquement)
- `setCancelled(boolean)` - Annule le craft (Pre uniquement)
{{< /tab >}}
{{< tab >}}
```java
// Vérification pré-craft
getEventRegistry().register(CraftRecipeEvent.Pre.class, event -> {
    CraftingRecipe recipe = event.getCraftedRecipe();
    int quantity = event.getQuantity();

    // Bloquer certaines recettes
    if (isRestrictedRecipe(recipe)) {
        event.setCancelled(true);
    }
});

// Suivi post-craft
getEventRegistry().register(CraftRecipeEvent.Post.class, event -> {
    CraftingRecipe recipe = event.getCraftedRecipe();
    int quantity = event.getQuantity();

    // Suivre les statistiques de craft
    incrementCraftCount(recipe.getId(), quantity);
});
```
{{< /tab >}}
{{< /tabs >}}

---

## Autres Événements

### SwitchActiveSlotEvent

{{< badge "Annulable" >}} {{< badge "ECS" >}}

Déclenché quand un joueur change son slot actif de hotbar.

**Package :** `com.hypixel.hytale.server.core.event.events.ecs`

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| inventorySectionId | `int` | ID de la section d'inventaire |
| previousSlot | `int` | Le slot avant le changement |
| newSlot | `byte` | Le slot cible |
| serverRequest | `boolean` | Si le serveur a initié le changement |
{{< /tab >}}
{{< tab >}}
- `getInventorySectionId()` - Retourne la section d'inventaire
- `getPreviousSlot()` - Retourne l'index du slot précédent
- `getNewSlot()` - Retourne l'index du nouveau slot
- `setNewSlot(byte)` - Change le slot cible
- `isServerRequest()` - Vérifie si initié par le serveur
- `isClientRequest()` - Vérifie si initié par le client
- `isCancelled()` - Vérifie si annulé
- `setCancelled(boolean)` - Annule le changement de slot
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(SwitchActiveSlotEvent.class, event -> {
    int fromSlot = event.getPreviousSlot();
    int toSlot = event.getNewSlot();

    // Empêcher le changement pendant un cooldown
    if (isOnCooldown(player)) {
        event.setCancelled(true);
        return;
    }

    // Suivre l'usage des slots pour analytics
    if (event.isClientRequest()) {
        trackSlotSwitch(player, fromSlot, toSlot);
    }
});
```
{{< /tab >}}
{{< /tabs >}}

---

### DiscoverZoneEvent

{{< badge "ECS" >}}

Déclenché quand un joueur découvre une nouvelle zone. A une variante `Display` qui est annulable.

**Package :** `com.hypixel.hytale.server.core.event.events.ecs`

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| discoveryInfo | `ZoneDiscoveryInfo` | Informations sur la zone découverte |
{{< /tab >}}
{{< tab >}}
- `getDiscoveryInfo()` - Retourne les infos de découverte de zone
- `isCancelled()` - Vérifie si annulé (Display uniquement)
- `setCancelled(boolean)` - Annule l'affichage (Display uniquement)
{{< /tab >}}
{{< tab >}}
```java
// Annuler l'affichage de notification de découverte de zone
getEventRegistry().register(DiscoverZoneEvent.Display.class, event -> {
    WorldMapTracker.ZoneDiscoveryInfo info = event.getDiscoveryInfo();

    // Cacher certaines zones de l'UI de découverte
    if (isHiddenZone(info)) {
        event.setCancelled(true);
        return;
    }

    // Logger la découverte pour les succès
    recordZoneDiscovery(player, info);
});
```
{{< /tab >}}
{{< /tabs >}}

---

### ChangeGameModeEvent

{{< badge "Annulable" >}} {{< badge "ECS" >}}

Déclenché quand le mode de jeu d'une entité change.

**Package :** `com.hypixel.hytale.server.core.event.events.ecs`

{{< tabs items="Champs,Méthodes,Exemple" >}}
{{< tab >}}
| Champ | Type | Description |
|-------|------|-------------|
| gameMode | `GameMode` | Le nouveau mode de jeu |
{{< /tab >}}
{{< tab >}}
- `getGameMode()` - Retourne le nouveau mode de jeu
- `setGameMode(GameMode)` - Change le mode de jeu cible
- `isCancelled()` - Vérifie si annulé
- `setCancelled(boolean)` - Annule le changement de mode
{{< /tab >}}
{{< tab >}}
```java
getEventRegistry().register(ChangeGameModeEvent.class, event -> {
    GameMode newMode = event.getGameMode();

    // Empêcher le mode créatif dans certains mondes
    if (newMode == GameMode.CREATIVE && isRestrictedWorld(player.getWorld())) {
        event.setCancelled(true);
        player.sendMessage(Message.raw("Mode créatif non autorisé ici !"));
        return;
    }

    // Forcer le mode aventure
    if (shouldForceAdventure(player)) {
        event.setGameMode(GameMode.ADVENTURE);
    }

    getLogger().at(Level.INFO).log(player.getDisplayName() + " changé en " + newMode);
});
```
{{< /tab >}}
{{< /tabs >}}

---

## Exemples Pratiques

### Plugin Logger de Blocs

```java
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));
    }
}
```

### Système de Protection de Région

```java
public class RegionPlugin extends JavaPlugin {

    private final Set<Region> regions = new HashSet<>();

    @Override
    public void start() {
        // Protéger contre le cassage
        getEventRegistry().register(EventPriority.EARLY, BreakBlockEvent.class, event -> {
            if (isInProtectedRegion(event.getTargetBlock())) {
                event.setCancelled(true);
            }
        });

        // Protéger contre le placement
        getEventRegistry().register(EventPriority.EARLY, PlaceBlockEvent.class, event -> {
            if (isInProtectedRegion(event.getTargetBlock())) {
                event.setCancelled(true);
            }
        });

        // Protéger contre l'utilisation
        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));
    }
}
```

### Système de Minerais Custom

```java
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)) {
                // Appliquer le multiplicateur fortune
                ItemStack tool = event.getItemInHand();
                int fortuneLevel = getFortuneLevel(tool);
                int dropMultiplier = 1 + random.nextInt(fortuneLevel + 1);

                // Programmer les drops custom
                Vector3i pos = event.getTargetBlock();
                scheduleOreDrops(pos, blockType, dropMultiplier);
            }
        });
    }

    private boolean isCustomOre(BlockType blockType) {
        return blockType.getId().startsWith("custom_ore_");
    }
}
```

### Système Anti-Grief

```java
public class AntiGriefPlugin extends JavaPlugin {

    private final Map<Vector3i, BlockAction> recentActions = new HashMap<>();

    @Override
    public void start() {
        // Suivre les cassages de blocs pour rollback
        getEventRegistry().register(BreakBlockEvent.class, event -> {
            Vector3i pos = event.getTargetBlock();
            BlockType blockType = event.getBlockType();

            recentActions.put(pos, new BlockAction(
                ActionType.BREAK,
                blockType,
                System.currentTimeMillis()
            ));
        });

        // Suivre les placements de blocs pour 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) {
                    // Supprimer les blocs placés
                    world.breakBlock(pos.x(), pos.y(), pos.z());
                } else if (action.blockType() != null) {
                    // Restaurer les blocs cassés
                    world.setBlock(pos.x(), pos.y(), pos.z(), action.blockType());
                }
            });

        recentActions.clear();
    }

    record BlockAction(ActionType type, BlockType blockType, long timestamp) {}
    enum ActionType { BREAK, PLACE }
}
```

## Bonnes Pratiques

{{< callout type="info" >}}
**Directives pour les Événements de Bloc :**
- Utiliser `EventPriority.EARLY` pour les systèmes de protection
- Les événements ECS fournissent un contrôle détaillé sur les opérations de bloc
- Toujours valider les positions avant de modifier les blocs
- Considérer l'état de chargement des chunks pour les blocs distants
- Nettoyer les données de suivi quand elles ne sont plus nécessaires
{{< /callout >}}

{{< callout type="warning" >}}
**Note de Performance :** Les événements de bloc peuvent se déclencher très fréquemment. Évitez les opérations coûteuses dans les handlers et mettez en cache les résultats si possible.
{{< /callout >}}
