Init
This commit is contained in:
50
content/core-concepts/events/event-reference/_index.en.md
Normal file
50
content/core-concepts/events/event-reference/_index.en.md
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: Event Reference
|
||||
type: docs
|
||||
weight: 5
|
||||
---
|
||||
|
||||
This section provides a comprehensive reference of all available events in Hytale.
|
||||
|
||||
{{< cards >}}
|
||||
{{< card link="player-events" title="Player Events" subtitle="Join, quit, chat, and player actions" >}}
|
||||
{{< card link="entity-events" title="Entity Events" subtitle="Spawn, damage, death, and movement" >}}
|
||||
{{< card link="block-events" title="Block Events" subtitle="Break, place, and interact with blocks" >}}
|
||||
{{< card link="permission-events" title="Permission Events" subtitle="Permission checking and management" >}}
|
||||
{{< /cards >}}
|
||||
|
||||
## Event Categories
|
||||
|
||||
### Player Events
|
||||
Events related to player actions and state changes:
|
||||
- `PlayerConnectEvent` - Player joins the server
|
||||
- `PlayerDisconnectEvent` - Player leaves the server
|
||||
- `PlayerChatEvent` - Player sends a chat message
|
||||
- `PlayerMoveEvent` - Player moves
|
||||
- `PlayerInteractEvent` - Player interacts with the world
|
||||
- `PlayerDamageEvent` - Player takes damage
|
||||
- `PlayerDeathEvent` - Player dies
|
||||
|
||||
### Entity Events
|
||||
Events related to all entities:
|
||||
- `EntitySpawnEvent` - Entity is spawned
|
||||
- `EntityDamageEvent` - Entity takes damage
|
||||
- `EntityDeathEvent` - Entity dies
|
||||
- `EntityMoveEvent` - Entity moves
|
||||
|
||||
### Block Events
|
||||
Events related to world blocks:
|
||||
- `BlockBreakEvent` - Block is broken
|
||||
- `BlockPlaceEvent` - Block is placed
|
||||
- `BlockInteractEvent` - Block is interacted with
|
||||
|
||||
### World Events
|
||||
Events related to world state:
|
||||
- `WorldLoadEvent` - World is loaded
|
||||
- `WorldUnloadEvent` - World is unloaded
|
||||
- `ChunkLoadEvent` - Chunk is loaded
|
||||
- `ChunkUnloadEvent` - Chunk is unloaded
|
||||
|
||||
### Permission Events
|
||||
Events related to permissions:
|
||||
- `PermissionCheckEvent` - Permission is checked
|
||||
50
content/core-concepts/events/event-reference/_index.fr.md
Normal file
50
content/core-concepts/events/event-reference/_index.fr.md
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: Référence des Événements
|
||||
type: docs
|
||||
weight: 5
|
||||
---
|
||||
|
||||
Cette section fournit une référence complète de tous les événements disponibles dans Hytale.
|
||||
|
||||
{{< cards >}}
|
||||
{{< card link="player-events" title="Événements Joueur" subtitle="Connexion, déconnexion, chat et actions joueur" >}}
|
||||
{{< card link="entity-events" title="Événements Entité" subtitle="Spawn, dégâts, mort et mouvement" >}}
|
||||
{{< card link="block-events" title="Événements Bloc" subtitle="Casser, placer et interagir avec les blocs" >}}
|
||||
{{< card link="permission-events" title="Événements Permission" subtitle="Vérification et gestion des permissions" >}}
|
||||
{{< /cards >}}
|
||||
|
||||
## Catégories d'Événements
|
||||
|
||||
### Événements Joueur
|
||||
Événements liés aux actions et changements d'état des joueurs :
|
||||
- `PlayerConnectEvent` - Un joueur rejoint le serveur
|
||||
- `PlayerDisconnectEvent` - Un joueur quitte le serveur
|
||||
- `PlayerChatEvent` - Un joueur envoie un message chat
|
||||
- `PlayerMoveEvent` - Un joueur se déplace
|
||||
- `PlayerInteractEvent` - Un joueur interagit avec le monde
|
||||
- `PlayerDamageEvent` - Un joueur subit des dégâts
|
||||
- `PlayerDeathEvent` - Un joueur meurt
|
||||
|
||||
### Événements Entité
|
||||
Événements liés à toutes les entités :
|
||||
- `EntitySpawnEvent` - Une entité apparaît
|
||||
- `EntityDamageEvent` - Une entité subit des dégâts
|
||||
- `EntityDeathEvent` - Une entité meurt
|
||||
- `EntityMoveEvent` - Une entité se déplace
|
||||
|
||||
### Événements Bloc
|
||||
Événements liés aux blocs du monde :
|
||||
- `BlockBreakEvent` - Un bloc est cassé
|
||||
- `BlockPlaceEvent` - Un bloc est placé
|
||||
- `BlockInteractEvent` - Un bloc subit une interaction
|
||||
|
||||
### Événements Monde
|
||||
Événements liés à l'état du monde :
|
||||
- `WorldLoadEvent` - Un monde est chargé
|
||||
- `WorldUnloadEvent` - Un monde est déchargé
|
||||
- `ChunkLoadEvent` - Un chunk est chargé
|
||||
- `ChunkUnloadEvent` - Un chunk est déchargé
|
||||
|
||||
### Événements Permission
|
||||
Événements liés aux permissions :
|
||||
- `PermissionCheckEvent` - Une permission est vérifiée
|
||||
721
content/core-concepts/events/event-reference/block-events.en.md
Normal file
721
content/core-concepts/events/event-reference/block-events.en.md
Normal file
@@ -0,0 +1,721 @@
|
||||
---
|
||||
title: Block Events
|
||||
type: docs
|
||||
weight: 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 position
|
||||
- `getBlockType()` - Returns block type
|
||||
- `getItemInHand()` - Returns tool being used
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel breaking
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
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 position
|
||||
- `setTargetBlock(Vector3i)` - Change placement position
|
||||
- `getRotation()` - Returns block rotation
|
||||
- `setRotation(RotationTuple)` - Change rotation
|
||||
- `getItemInHand()` - Returns block item
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel placement
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
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 position
|
||||
- `setTargetBlock(Vector3i)` - Change target block
|
||||
- `getBlockType()` - Returns block type
|
||||
- `getItemInHand()` - Returns tool being used
|
||||
- `getCurrentDamage()` - Returns accumulated damage
|
||||
- `getDamage()` - Returns damage this tick
|
||||
- `setDamage(float)` - Modify damage amount
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel damage
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
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 type
|
||||
- `getContext()` - Returns interaction context
|
||||
- `getTargetBlock()` - Returns block position
|
||||
- `getBlockType()` - Returns block type
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel use action
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
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 type
|
||||
- `getContext()` - Returns interaction context
|
||||
- `getTargetBlock()` - Returns block position
|
||||
- `getBlockType()` - Returns block type
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
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 stack
|
||||
- `setItemStack(ItemStack)` - Change the dropped item
|
||||
- `getThrowSpeed()` - Returns throw speed
|
||||
- `setThrowSpeed(float)` - Change throw speed
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel drop
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
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 section
|
||||
- `getSlotId()` - Returns slot index
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel request
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
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 stack
|
||||
- `setItemStack(ItemStack)` - Change the item being picked up
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel pickup
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
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 recipe
|
||||
- `getQuantity()` - Returns craft quantity
|
||||
- `isCancelled()` - Check if cancelled (Pre only)
|
||||
- `setCancelled(boolean)` - Cancel crafting (Pre only)
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// 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 section
|
||||
- `getPreviousSlot()` - Returns previous slot index
|
||||
- `getNewSlot()` - Returns new slot index
|
||||
- `setNewSlot(byte)` - Change the target slot
|
||||
- `isServerRequest()` - Check if server initiated
|
||||
- `isClientRequest()` - Check if client initiated
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel slot switch
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
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 info
|
||||
- `isCancelled()` - Check if cancelled (Display only)
|
||||
- `setCancelled(boolean)` - Cancel display (Display only)
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// 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 mode
|
||||
- `setGameMode(GameMode)` - Change the target game mode
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel mode change
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
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
|
||||
|
||||
```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));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Region Protection System
|
||||
|
||||
```java
|
||||
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
|
||||
|
||||
```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)) {
|
||||
// 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
|
||||
|
||||
```java
|
||||
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.EARLY` for 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 >}}
|
||||
721
content/core-concepts/events/event-reference/block-events.fr.md
Normal file
721
content/core-concepts/events/event-reference/block-events.fr.md
Normal file
@@ -0,0 +1,721 @@
|
||||
---
|
||||
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 >}}
|
||||
193
content/core-concepts/events/event-reference/entity-events.en.md
Normal file
193
content/core-concepts/events/event-reference/entity-events.en.md
Normal file
@@ -0,0 +1,193 @@
|
||||
---
|
||||
title: Entity Events
|
||||
type: docs
|
||||
weight: 2
|
||||
---
|
||||
|
||||
Events triggered by entity actions and state changes. These events apply to entities in the game world.
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Note:** Hytale's entity event system is minimal compared to other game APIs. Most entity-related logic is handled through the ECS (Entity Component System) rather than traditional events. For block interactions, item drops, and crafting, see [Block Events](../block-events).
|
||||
{{< /callout >}}
|
||||
|
||||
## Entity Lifecycle Events
|
||||
|
||||
### EntityRemoveEvent
|
||||
|
||||
Fired when an entity is removed from the world.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.entity`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| entity | `Entity` | The entity being removed |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getEntity()` - Returns the Entity object being removed
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(EntityRemoveEvent.class, event -> {
|
||||
Entity entity = event.getEntity();
|
||||
|
||||
// Clean up any custom data associated with this entity
|
||||
if (trackedEntities.contains(entity.getUuid())) {
|
||||
trackedEntities.remove(entity.getUuid());
|
||||
getLogger().at(Level.INFO).log("Tracked entity removed: " + entity.getType().getId());
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Living Entity Events
|
||||
|
||||
### LivingEntityInventoryChangeEvent
|
||||
|
||||
Fired when a living entity's inventory changes.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.entity`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| entity | `LivingEntity` | The entity whose inventory changed |
|
||||
| itemContainer | `ItemContainer` | The item container that changed |
|
||||
| transaction | `Transaction` | The transaction that occurred |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getEntity()` - Returns the LivingEntity
|
||||
- `getItemContainer()` - Returns the ItemContainer that changed
|
||||
- `getTransaction()` - Returns the Transaction details
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(LivingEntityInventoryChangeEvent.class, event -> {
|
||||
LivingEntity entity = event.getEntity();
|
||||
ItemContainer container = event.getItemContainer();
|
||||
Transaction transaction = event.getTransaction();
|
||||
|
||||
// Log inventory changes for debugging
|
||||
getLogger().at(Level.INFO).log("Inventory changed for: " + entity.getType().getId());
|
||||
getLogger().at(Level.INFO).log("Container: " + container);
|
||||
getLogger().at(Level.INFO).log("Transaction: " + transaction);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### LivingEntityUseBlockEvent
|
||||
|
||||
{{< badge "Deprecated" >}}
|
||||
|
||||
Fired when a living entity uses a block. This event is deprecated and marked for removal.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.entity`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| ref | `Ref<EntityStore>` | Reference to the entity store |
|
||||
| blockType | `String` | The type of block being used |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getRef()` - Returns the entity store reference
|
||||
- `getBlockType()` - Returns the block type string
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Note: This event is deprecated. Use UseBlockEvent instead.
|
||||
getEventRegistry().register(LivingEntityUseBlockEvent.class, event -> {
|
||||
String blockType = event.getBlockType();
|
||||
Ref<EntityStore> ref = event.getRef();
|
||||
|
||||
getLogger().at(Level.INFO).log("Entity used block: " + blockType);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Deprecated:** This event is marked for removal. Use `UseBlockEvent.Pre` and `UseBlockEvent.Post` from the ECS event system instead. See [Block Events](../block-events#useblockevent) for the modern alternative.
|
||||
{{< /callout >}}
|
||||
|
||||
---
|
||||
|
||||
## Working with Entities
|
||||
|
||||
### Entity Component System (ECS)
|
||||
|
||||
Hytale uses an Entity Component System architecture. Instead of traditional entity events, much of the entity behavior is handled through components and the ECS event system.
|
||||
|
||||
For entity-related operations, consider using:
|
||||
|
||||
- **ECS Events** for block interactions, item management, and game mode changes
|
||||
- **Entity Components** for entity state and behavior
|
||||
- **EntityStore** for entity data persistence
|
||||
|
||||
### Example: Tracking Entities
|
||||
|
||||
```java
|
||||
public class EntityTrackerPlugin extends JavaPlugin {
|
||||
|
||||
private final Set<UUID> trackedEntities = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Track entity removal
|
||||
getEventRegistry().register(EntityRemoveEvent.class, event -> {
|
||||
Entity entity = event.getEntity();
|
||||
|
||||
if (trackedEntities.remove(entity.getUuid())) {
|
||||
getLogger().at(Level.INFO).log("Tracked entity removed: " + entity.getUuid());
|
||||
onEntityRemoved(entity);
|
||||
}
|
||||
});
|
||||
|
||||
// Track inventory changes
|
||||
getEventRegistry().register(LivingEntityInventoryChangeEvent.class, event -> {
|
||||
LivingEntity entity = event.getEntity();
|
||||
|
||||
if (trackedEntities.contains(entity.getUuid())) {
|
||||
onInventoryChanged(entity, event.getTransaction());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void trackEntity(Entity entity) {
|
||||
trackedEntities.add(entity.getUuid());
|
||||
getLogger().at(Level.INFO).log("Now tracking entity: " + entity.getUuid());
|
||||
}
|
||||
|
||||
private void onEntityRemoved(Entity entity) {
|
||||
// Custom cleanup logic
|
||||
}
|
||||
|
||||
private void onInventoryChanged(LivingEntity entity, Transaction transaction) {
|
||||
// React to inventory changes
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Entity Event Guidelines:**
|
||||
- Entity events in Hytale are minimal - prefer ECS patterns for complex behavior
|
||||
- Use `EntityRemoveEvent` for cleanup when entities are removed
|
||||
- `LivingEntityUseBlockEvent` is deprecated - migrate to `UseBlockEvent`
|
||||
- For player-specific entity events, see [Player Events](../player-events)
|
||||
- For block and item interactions, see [Block Events](../block-events)
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="tip" >}}
|
||||
**Migration Note:** If you're coming from Minecraft/Bukkit development, note that Hytale doesn't have traditional `EntityDamageEvent`, `EntityDeathEvent`, or `EntitySpawnEvent`. Entity lifecycle and combat are handled differently through the ECS architecture.
|
||||
{{< /callout >}}
|
||||
193
content/core-concepts/events/event-reference/entity-events.fr.md
Normal file
193
content/core-concepts/events/event-reference/entity-events.fr.md
Normal file
@@ -0,0 +1,193 @@
|
||||
---
|
||||
title: Événements Entité
|
||||
type: docs
|
||||
weight: 2
|
||||
---
|
||||
|
||||
Événements déclenchés par les actions et changements d'état des entités dans le monde du jeu.
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Note :** Le système d'événements d'entité de Hytale est minimal comparé à d'autres APIs de jeu. La plupart de la logique liée aux entités est gérée via l'ECS (Entity Component System) plutôt que par des événements traditionnels. Pour les interactions de blocs, drops d'items et craft, voir [Événements Bloc](../block-events).
|
||||
{{< /callout >}}
|
||||
|
||||
## Événements du Cycle de Vie
|
||||
|
||||
### EntityRemoveEvent
|
||||
|
||||
Déclenché quand une entité est supprimée du monde.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.entity`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| entity | `Entity` | L'entité supprimée |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getEntity()` - Retourne l'objet Entity supprimé
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(EntityRemoveEvent.class, event -> {
|
||||
Entity entity = event.getEntity();
|
||||
|
||||
// Nettoyer les données personnalisées associées à cette entité
|
||||
if (trackedEntities.contains(entity.getUuid())) {
|
||||
trackedEntities.remove(entity.getUuid());
|
||||
getLogger().at(Level.INFO).log("Entité suivie supprimée : " + entity.getType().getId());
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Événements d'Entités Vivantes
|
||||
|
||||
### LivingEntityInventoryChangeEvent
|
||||
|
||||
Déclenché quand l'inventaire d'une entité vivante change.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.entity`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| entity | `LivingEntity` | L'entité dont l'inventaire a changé |
|
||||
| itemContainer | `ItemContainer` | Le conteneur d'items modifié |
|
||||
| transaction | `Transaction` | La transaction effectuée |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getEntity()` - Retourne le LivingEntity
|
||||
- `getItemContainer()` - Retourne l'ItemContainer modifié
|
||||
- `getTransaction()` - Retourne les détails de la Transaction
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(LivingEntityInventoryChangeEvent.class, event -> {
|
||||
LivingEntity entity = event.getEntity();
|
||||
ItemContainer container = event.getItemContainer();
|
||||
Transaction transaction = event.getTransaction();
|
||||
|
||||
// Logger les changements d'inventaire pour debug
|
||||
getLogger().at(Level.INFO).log("Inventaire changé pour : " + entity.getType().getId());
|
||||
getLogger().at(Level.INFO).log("Conteneur : " + container);
|
||||
getLogger().at(Level.INFO).log("Transaction : " + transaction);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### LivingEntityUseBlockEvent
|
||||
|
||||
{{< badge "Déprécié" >}}
|
||||
|
||||
Déclenché quand une entité vivante utilise un bloc. Cet événement est déprécié et marqué pour suppression.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.entity`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| ref | `Ref<EntityStore>` | Référence au store d'entité |
|
||||
| blockType | `String` | Le type de bloc utilisé |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getRef()` - Retourne la référence du store d'entité
|
||||
- `getBlockType()` - Retourne la chaîne du type de bloc
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Note : Cet événement est déprécié. Utilisez UseBlockEvent à la place.
|
||||
getEventRegistry().register(LivingEntityUseBlockEvent.class, event -> {
|
||||
String blockType = event.getBlockType();
|
||||
Ref<EntityStore> ref = event.getRef();
|
||||
|
||||
getLogger().at(Level.INFO).log("Entité a utilisé le bloc : " + blockType);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Déprécié :** Cet événement est marqué pour suppression. Utilisez `UseBlockEvent.Pre` et `UseBlockEvent.Post` du système d'événements ECS à la place. Voir [Événements Bloc](../block-events#useblockevent) pour l'alternative moderne.
|
||||
{{< /callout >}}
|
||||
|
||||
---
|
||||
|
||||
## Travailler avec les Entités
|
||||
|
||||
### Entity Component System (ECS)
|
||||
|
||||
Hytale utilise une architecture Entity Component System. Au lieu d'événements d'entité traditionnels, la plupart du comportement des entités est géré via des composants et le système d'événements ECS.
|
||||
|
||||
Pour les opérations liées aux entités, considérez utiliser :
|
||||
|
||||
- **Événements ECS** pour les interactions de blocs, gestion d'items et changements de mode de jeu
|
||||
- **Composants d'Entité** pour l'état et le comportement des entités
|
||||
- **EntityStore** pour la persistance des données d'entité
|
||||
|
||||
### Exemple : Suivi d'Entités
|
||||
|
||||
```java
|
||||
public class EntityTrackerPlugin extends JavaPlugin {
|
||||
|
||||
private final Set<UUID> trackedEntities = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Suivre la suppression d'entités
|
||||
getEventRegistry().register(EntityRemoveEvent.class, event -> {
|
||||
Entity entity = event.getEntity();
|
||||
|
||||
if (trackedEntities.remove(entity.getUuid())) {
|
||||
getLogger().at(Level.INFO).log("Entité suivie supprimée : " + entity.getUuid());
|
||||
onEntityRemoved(entity);
|
||||
}
|
||||
});
|
||||
|
||||
// Suivre les changements d'inventaire
|
||||
getEventRegistry().register(LivingEntityInventoryChangeEvent.class, event -> {
|
||||
LivingEntity entity = event.getEntity();
|
||||
|
||||
if (trackedEntities.contains(entity.getUuid())) {
|
||||
onInventoryChanged(entity, event.getTransaction());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void trackEntity(Entity entity) {
|
||||
trackedEntities.add(entity.getUuid());
|
||||
getLogger().at(Level.INFO).log("Suivi de l'entité : " + entity.getUuid());
|
||||
}
|
||||
|
||||
private void onEntityRemoved(Entity entity) {
|
||||
// Logique de nettoyage personnalisée
|
||||
}
|
||||
|
||||
private void onInventoryChanged(LivingEntity entity, Transaction transaction) {
|
||||
// Réagir aux changements d'inventaire
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Bonnes Pratiques
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Directives pour les Événements d'Entité :**
|
||||
- Les événements d'entité dans Hytale sont minimaux - préférez les patterns ECS pour les comportements complexes
|
||||
- Utilisez `EntityRemoveEvent` pour le nettoyage quand les entités sont supprimées
|
||||
- `LivingEntityUseBlockEvent` est déprécié - migrez vers `UseBlockEvent`
|
||||
- Pour les événements d'entité spécifiques aux joueurs, voir [Événements Joueur](../player-events)
|
||||
- Pour les interactions de blocs et d'items, voir [Événements Bloc](../block-events)
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="tip" >}}
|
||||
**Note de Migration :** Si vous venez du développement Minecraft/Bukkit, notez que Hytale n'a pas de `EntityDamageEvent`, `EntityDeathEvent`, ou `EntitySpawnEvent` traditionnels. Le cycle de vie des entités et le combat sont gérés différemment via l'architecture ECS.
|
||||
{{< /callout >}}
|
||||
@@ -0,0 +1,425 @@
|
||||
---
|
||||
title: Permission Events
|
||||
type: docs
|
||||
weight: 4
|
||||
---
|
||||
|
||||
Events triggered when permissions or group memberships change. These events allow plugins to react to permission system modifications.
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Note:** These events fire when permissions change, not when they are checked. They are useful for synchronization, logging, and reacting to permission modifications.
|
||||
{{< /callout >}}
|
||||
|
||||
## Player Permission Events
|
||||
|
||||
### PlayerPermissionChangeEvent
|
||||
|
||||
Abstract base class for all player permission change events.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.permissions`
|
||||
|
||||
{{< tabs items="Fields,Methods" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerUuid | `UUID` | UUID of the affected player |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayerUuid()` - Returns the UUID of the player whose permissions changed
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerPermissionChangeEvent.PermissionsAdded
|
||||
|
||||
Fired when permissions are directly added to a player.
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerUuid | `UUID` | UUID of the affected player |
|
||||
| addedPermissions | `Set<String>` | Set of permission nodes added |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayerUuid()` - Returns the player's UUID
|
||||
- `getAddedPermissions()` - Returns unmodifiable set of added permissions
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsAdded.class, event -> {
|
||||
UUID playerUuid = event.getPlayerUuid();
|
||||
Set<String> addedPerms = event.getAddedPermissions();
|
||||
|
||||
getLogger().at(Level.INFO).log("Player " + playerUuid + " gained permissions: " + addedPerms);
|
||||
|
||||
// Notify online player
|
||||
Player player = Universe.get().getPlayer(playerUuid);
|
||||
if (player != null) {
|
||||
player.sendMessage(Message.raw("You gained new permissions!"));
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerPermissionChangeEvent.PermissionsRemoved
|
||||
|
||||
Fired when permissions are directly removed from a player.
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerUuid | `UUID` | UUID of the affected player |
|
||||
| removedPermissions | `Set<String>` | Set of permission nodes removed |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayerUuid()` - Returns the player's UUID
|
||||
- `getRemovedPermissions()` - Returns unmodifiable set of removed permissions
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsRemoved.class, event -> {
|
||||
UUID playerUuid = event.getPlayerUuid();
|
||||
Set<String> removedPerms = event.getRemovedPermissions();
|
||||
|
||||
getLogger().at(Level.INFO).log("Player " + playerUuid + " lost permissions: " + removedPerms);
|
||||
|
||||
// Check if player lost admin permission
|
||||
if (removedPerms.contains("admin.*")) {
|
||||
notifyAdmins("Player " + playerUuid + " is no longer an admin");
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerPermissionChangeEvent.GroupAdded
|
||||
|
||||
Fired when a player is added to a permission group (via PlayerPermissionChangeEvent).
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerUuid | `UUID` | UUID of the affected player |
|
||||
| groupName | `String` | Name of the group added |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayerUuid()` - Returns the player's UUID
|
||||
- `getGroupName()` - Returns the group name
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerPermissionChangeEvent.GroupAdded.class, event -> {
|
||||
UUID playerUuid = event.getPlayerUuid();
|
||||
String group = event.getGroupName();
|
||||
|
||||
getLogger().at(Level.INFO).log("Player " + playerUuid + " added to group: " + group);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerPermissionChangeEvent.GroupRemoved
|
||||
|
||||
Fired when a player is removed from a permission group (via PlayerPermissionChangeEvent).
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerUuid | `UUID` | UUID of the affected player |
|
||||
| groupName | `String` | Name of the group removed |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayerUuid()` - Returns the player's UUID
|
||||
- `getGroupName()` - Returns the group name
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerPermissionChangeEvent.GroupRemoved.class, event -> {
|
||||
UUID playerUuid = event.getPlayerUuid();
|
||||
String group = event.getGroupName();
|
||||
|
||||
getLogger().at(Level.INFO).log("Player " + playerUuid + " removed from group: " + group);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Group Permission Events
|
||||
|
||||
### GroupPermissionChangeEvent
|
||||
|
||||
Abstract base class for group permission change events.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.permissions`
|
||||
|
||||
{{< tabs items="Fields,Methods" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| groupName | `String` | Name of the affected group |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getGroupName()` - Returns the name of the group whose permissions changed
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### GroupPermissionChangeEvent.Added
|
||||
|
||||
Fired when permissions are added to a group.
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| groupName | `String` | Name of the affected group |
|
||||
| addedPermissions | `Set<String>` | Set of permission nodes added |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getGroupName()` - Returns the group name
|
||||
- `getAddedPermissions()` - Returns unmodifiable set of added permissions
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(GroupPermissionChangeEvent.Added.class, event -> {
|
||||
String group = event.getGroupName();
|
||||
Set<String> addedPerms = event.getAddedPermissions();
|
||||
|
||||
getLogger().at(Level.INFO).log("Group " + group + " gained permissions: " + addedPerms);
|
||||
|
||||
// Notify all online players in this group
|
||||
notifyGroupMembers(group, "Your group gained new permissions!");
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### GroupPermissionChangeEvent.Removed
|
||||
|
||||
Fired when permissions are removed from a group.
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| groupName | `String` | Name of the affected group |
|
||||
| removedPermissions | `Set<String>` | Set of permission nodes removed |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getGroupName()` - Returns the group name
|
||||
- `getRemovedPermissions()` - Returns unmodifiable set of removed permissions
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(GroupPermissionChangeEvent.Removed.class, event -> {
|
||||
String group = event.getGroupName();
|
||||
Set<String> removedPerms = event.getRemovedPermissions();
|
||||
|
||||
getLogger().at(Level.INFO).log("Group " + group + " lost permissions: " + removedPerms);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Player Group Events
|
||||
|
||||
### PlayerGroupEvent
|
||||
|
||||
Fired when a player's group membership changes. Extends `PlayerPermissionChangeEvent`.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.permissions`
|
||||
|
||||
{{< tabs items="Fields,Methods" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerUuid | `UUID` | UUID of the affected player |
|
||||
| groupName | `String` | Name of the group |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayerUuid()` - Returns the player's UUID
|
||||
- `getGroupName()` - Returns the group name
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerGroupEvent.Added
|
||||
|
||||
Fired when a player is added to a group.
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerUuid | `UUID` | UUID of the affected player |
|
||||
| groupName | `String` | Name of the group joined |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayerUuid()` - Returns the player's UUID
|
||||
- `getGroupName()` - Returns the group name
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerGroupEvent.Added.class, event -> {
|
||||
UUID playerUuid = event.getPlayerUuid();
|
||||
String group = event.getGroupName();
|
||||
|
||||
getLogger().at(Level.INFO).log("Player " + playerUuid + " joined group: " + group);
|
||||
|
||||
// Welcome message for VIP group
|
||||
if (group.equals("vip")) {
|
||||
Player player = Universe.get().getPlayer(playerUuid);
|
||||
if (player != null) {
|
||||
player.sendMessage(Message.raw("Welcome to the VIP group!"));
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerGroupEvent.Removed
|
||||
|
||||
Fired when a player is removed from a group.
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerUuid | `UUID` | UUID of the affected player |
|
||||
| groupName | `String` | Name of the group left |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayerUuid()` - Returns the player's UUID
|
||||
- `getGroupName()` - Returns the group name
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerGroupEvent.Removed.class, event -> {
|
||||
UUID playerUuid = event.getPlayerUuid();
|
||||
String group = event.getGroupName();
|
||||
|
||||
getLogger().at(Level.INFO).log("Player " + playerUuid + " left group: " + group);
|
||||
|
||||
// Log staff changes
|
||||
if (group.equals("staff") || group.equals("admin")) {
|
||||
logStaffChange(playerUuid, group, "removed");
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Practical Examples
|
||||
|
||||
### Permission Audit Logger
|
||||
|
||||
```java
|
||||
public class PermissionAuditPlugin extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Log all player permission changes
|
||||
getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsAdded.class, event -> {
|
||||
logAudit("PERM_ADD", event.getPlayerUuid(), event.getAddedPermissions());
|
||||
});
|
||||
|
||||
getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsRemoved.class, event -> {
|
||||
logAudit("PERM_REMOVE", event.getPlayerUuid(), event.getRemovedPermissions());
|
||||
});
|
||||
|
||||
// Log all group membership changes
|
||||
getEventRegistry().register(PlayerGroupEvent.Added.class, event -> {
|
||||
logAudit("GROUP_JOIN", event.getPlayerUuid(), Set.of(event.getGroupName()));
|
||||
});
|
||||
|
||||
getEventRegistry().register(PlayerGroupEvent.Removed.class, event -> {
|
||||
logAudit("GROUP_LEAVE", event.getPlayerUuid(), Set.of(event.getGroupName()));
|
||||
});
|
||||
|
||||
// Log group permission changes
|
||||
getEventRegistry().register(GroupPermissionChangeEvent.Added.class, event -> {
|
||||
logGroupAudit("GROUP_PERM_ADD", event.getGroupName(), event.getAddedPermissions());
|
||||
});
|
||||
|
||||
getEventRegistry().register(GroupPermissionChangeEvent.Removed.class, event -> {
|
||||
logGroupAudit("GROUP_PERM_REMOVE", event.getGroupName(), event.getRemovedPermissions());
|
||||
});
|
||||
}
|
||||
|
||||
private void logAudit(String action, UUID player, Set<String> items) {
|
||||
getLogger().at(Level.INFO).log(String.format("[AUDIT] %s: player=%s items=%s", action, player, items));
|
||||
}
|
||||
|
||||
private void logGroupAudit(String action, String group, Set<String> items) {
|
||||
getLogger().at(Level.INFO).log(String.format("[AUDIT] %s: group=%s items=%s", action, group, items));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Permission Synchronization
|
||||
|
||||
```java
|
||||
public class PermissionSyncPlugin extends JavaPlugin {
|
||||
|
||||
private final Map<UUID, Set<String>> cachedPermissions = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Keep cache synchronized with permission changes
|
||||
getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsAdded.class, event -> {
|
||||
cachedPermissions.computeIfAbsent(event.getPlayerUuid(), k -> new HashSet<>())
|
||||
.addAll(event.getAddedPermissions());
|
||||
});
|
||||
|
||||
getEventRegistry().register(PlayerPermissionChangeEvent.PermissionsRemoved.class, event -> {
|
||||
Set<String> perms = cachedPermissions.get(event.getPlayerUuid());
|
||||
if (perms != null) {
|
||||
perms.removeAll(event.getRemovedPermissions());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Set<String> getCachedPermissions(UUID player) {
|
||||
return cachedPermissions.getOrDefault(player, Collections.emptySet());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Permission Event Guidelines:**
|
||||
- These events fire after permissions have changed, not before
|
||||
- Use for logging, synchronization, and notifications
|
||||
- The returned permission sets are unmodifiable - do not try to modify them
|
||||
- Player may be offline when permission changes occur - check for null
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Important:** These events do not allow you to intercept or modify permission checks. They only notify you when permissions have been modified through the permission system.
|
||||
{{< /callout >}}
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
title: Événements Permission
|
||||
type: docs
|
||||
weight: 4
|
||||
---
|
||||
|
||||
Événements liés à la vérification et gestion des permissions.
|
||||
|
||||
## PermissionCheckEvent
|
||||
|
||||
Déclenché quand une permission est vérifiée pour un joueur.
|
||||
|
||||
```java
|
||||
getEventRegistry().register(PermissionCheckEvent.class, event -> {
|
||||
String permission = event.getPermission();
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Overrider le résultat de permission
|
||||
if (permission.startsWith("vip.") && isVIP(player)) {
|
||||
event.setResult(true);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
| Méthode | Retourne | Description |
|
||||
|---------|----------|-------------|
|
||||
| `getPlayer()` | `Player` | Joueur vérifié |
|
||||
| `getPermission()` | `String` | Noeud de permission |
|
||||
| `getResult()` | `boolean` | Résultat actuel |
|
||||
| `setResult(boolean)` | `void` | Overrider le résultat |
|
||||
|
||||
## Cas d'Utilisation
|
||||
|
||||
### Logique de Permission Personnalisée
|
||||
|
||||
```java
|
||||
getEventRegistry().register(PermissionCheckEvent.class, event -> {
|
||||
String permission = event.getPermission();
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Accorder toutes les permissions aux admins
|
||||
if (isServerAdmin(player)) {
|
||||
event.setResult(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Vérifier une source de permissions personnalisée
|
||||
if (customPermissions.hasPermission(player.getUuid(), permission)) {
|
||||
event.setResult(true);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Logging des Permissions
|
||||
|
||||
```java
|
||||
getEventRegistry().register(PermissionCheckEvent.class, event -> {
|
||||
getLogger().fine(String.format(
|
||||
"Vérification permission : %s pour %s = %s",
|
||||
event.getPermission(),
|
||||
event.getPlayer().getName(),
|
||||
event.getResult()
|
||||
));
|
||||
});
|
||||
```
|
||||
|
||||
### Permissions Temporaires
|
||||
|
||||
```java
|
||||
public class TempPermPlugin extends JavaPlugin {
|
||||
|
||||
private final Map<UUID, Set<String>> tempPerms = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
getEventRegistry().register(PermissionCheckEvent.class, event -> {
|
||||
UUID uuid = event.getPlayer().getUuid();
|
||||
Set<String> perms = tempPerms.get(uuid);
|
||||
|
||||
if (perms != null && perms.contains(event.getPermission())) {
|
||||
event.setResult(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void grantTemp(UUID player, String permission) {
|
||||
tempPerms.computeIfAbsent(player, k -> new HashSet<>())
|
||||
.add(permission);
|
||||
}
|
||||
|
||||
public void revokeTemp(UUID player, String permission) {
|
||||
Set<String> perms = tempPerms.get(player);
|
||||
if (perms != null) {
|
||||
perms.remove(permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
675
content/core-concepts/events/event-reference/player-events.en.md
Normal file
675
content/core-concepts/events/event-reference/player-events.en.md
Normal file
@@ -0,0 +1,675 @@
|
||||
---
|
||||
title: Player Events
|
||||
type: docs
|
||||
weight: 1
|
||||
---
|
||||
|
||||
Events triggered by player actions and state changes.
|
||||
|
||||
## Connection Events
|
||||
|
||||
### PlayerSetupConnectEvent
|
||||
|
||||
{{< badge "Cancellable" >}}
|
||||
|
||||
Fired during player connection setup. Can be cancelled to prevent connection or redirect to another server.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| uuid | `UUID` | Player's unique identifier |
|
||||
| username | `String` | Player's username |
|
||||
| auth | `PlayerAuthentication` | Authentication information |
|
||||
| referralData | `byte[]` | Data from referral (if redirected) |
|
||||
| referralSource | `HostAddress` | Server that referred player |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getUuid()` - Returns player UUID
|
||||
- `getUsername()` - Returns player username
|
||||
- `getAuth()` - Returns authentication data
|
||||
- `getReferralData()` - Returns referral data (may be null)
|
||||
- `isReferralConnection()` - Check if redirected from another server
|
||||
- `getReferralSource()` - Returns source server address
|
||||
- `referToServer(host, port)` - Redirect player to another server
|
||||
- `referToServer(host, port, data)` - Redirect with data
|
||||
- `getReason()` - Get disconnect reason message
|
||||
- `setReason(String)` - Set disconnect reason message
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel connection
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerSetupConnectEvent.class, event -> {
|
||||
String username = event.getUsername();
|
||||
UUID uuid = event.getUuid();
|
||||
|
||||
// Ban check
|
||||
if (isBanned(uuid)) {
|
||||
event.setCancelled(true);
|
||||
event.setReason("You are banned from this server!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Redirect to different server based on condition
|
||||
if (shouldRedirect(uuid)) {
|
||||
event.referToServer("lobby.example.com", 25565);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerConnectEvent
|
||||
|
||||
Fired when a player connects to the server. Use this to set the spawn world.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| holder | `Holder<EntityStore>` | Entity store holder |
|
||||
| playerRef | `PlayerRef` | Reference to the connecting player |
|
||||
| world | `World` | The world player will spawn in |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getHolder()` - Returns the entity store holder
|
||||
- `getPlayerRef()` - Returns the player reference
|
||||
- `getPlayer()` - Returns the Player object (deprecated)
|
||||
- `getWorld()` - Returns current spawn world (may be null)
|
||||
- `setWorld(World)` - Set the world player will spawn in
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerConnectEvent.class, event -> {
|
||||
PlayerRef playerRef = event.getPlayerRef();
|
||||
getLogger().at(Level.INFO).log("Player connecting: " + playerRef.getUsername());
|
||||
|
||||
// Set spawn world
|
||||
World lobbyWorld = Universe.get().getWorld("lobby");
|
||||
if (lobbyWorld != null) {
|
||||
event.setWorld(lobbyWorld);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
The `getPlayer()` method is deprecated. Prefer using `getPlayerRef()` or `getHolder()` to access player data.
|
||||
{{< /callout >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerSetupDisconnectEvent
|
||||
|
||||
Fired when a player disconnects during the setup phase (before fully connecting).
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| uuid | `UUID` | Player's unique identifier |
|
||||
| username | `String` | Player's username |
|
||||
| auth | `PlayerAuthentication` | Authentication information |
|
||||
| disconnectReason | `DisconnectReason` | Why the player disconnected |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getUuid()` - Returns player UUID
|
||||
- `getUsername()` - Returns player username
|
||||
- `getAuth()` - Returns authentication data
|
||||
- `getDisconnectReason()` - Returns disconnect reason
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerSetupDisconnectEvent.class, event -> {
|
||||
String username = event.getUsername();
|
||||
PacketHandler.DisconnectReason reason = event.getDisconnectReason();
|
||||
|
||||
getLogger().at(Level.INFO).log("Player " + username + " disconnected during setup: " + reason);
|
||||
|
||||
// Cleanup any pre-connection data
|
||||
cleanupPendingData(event.getUuid());
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerReadyEvent
|
||||
|
||||
Fired when a player is fully ready and loaded into the game. This is the safe point to interact with the player.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerRef | `Ref<EntityStore>` | Entity store reference |
|
||||
| player | `Player` | The player object |
|
||||
| readyId | `int` | Ready event identifier |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayer()` - Returns the Player object
|
||||
- `getPlayerRef()` - Returns the entity store reference
|
||||
- `getReadyId()` - Returns the ready event ID
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerReadyEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Player is fully loaded, safe to send complex data
|
||||
player.sendMessage(Message.raw("Welcome to the server!"));
|
||||
loadPlayerData(player);
|
||||
sendWelcomeScreen(player);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerDisconnectEvent
|
||||
|
||||
Fired when a player disconnects from the server.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerRef | `PlayerRef` | Reference to the disconnecting player |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayerRef()` - Returns the player reference
|
||||
- `getDisconnectReason()` - Returns why the player disconnected
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerDisconnectEvent.class, event -> {
|
||||
PlayerRef playerRef = event.getPlayerRef();
|
||||
|
||||
savePlayerData(playerRef.getUuid());
|
||||
getLogger().at(Level.INFO).log(playerRef.getUsername() + " has left the server");
|
||||
|
||||
// Check disconnect reason
|
||||
PacketHandler.DisconnectReason reason = event.getDisconnectReason();
|
||||
getLogger().at(Level.INFO).log("Reason: " + reason);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## World Events
|
||||
|
||||
### AddPlayerToWorldEvent
|
||||
|
||||
Fired when a player is added to a world.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| holder | `Holder<EntityStore>` | Entity store holder |
|
||||
| world | `World` | The world being entered |
|
||||
| broadcastJoinMessage | `boolean` | Whether to broadcast join message |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getHolder()` - Returns the entity store holder
|
||||
- `getWorld()` - Returns the world
|
||||
- `shouldBroadcastJoinMessage()` - Check if join message will be sent
|
||||
- `setBroadcastJoinMessage(boolean)` - Control join message broadcast
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(AddPlayerToWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
|
||||
// Disable default join message for silent joins
|
||||
if (isSilentJoin(event.getHolder())) {
|
||||
event.setBroadcastJoinMessage(false);
|
||||
}
|
||||
|
||||
applyWorldEffects(event.getHolder(), world);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### DrainPlayerFromWorldEvent
|
||||
|
||||
Fired when a player is removed from a world (before teleporting to another or disconnecting).
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| holder | `Holder<EntityStore>` | Entity store holder |
|
||||
| world | `World` | The world being left |
|
||||
| transform | `Transform` | Player's position/rotation |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getHolder()` - Returns the entity store holder
|
||||
- `getWorld()` - Returns the world being left
|
||||
- `setWorld(World)` - Change destination world
|
||||
- `getTransform()` - Returns player's transform
|
||||
- `setTransform(Transform)` - Set spawn transform in new world
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(DrainPlayerFromWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
|
||||
removeWorldEffects(event.getHolder());
|
||||
saveWorldProgress(event.getHolder(), world);
|
||||
|
||||
// Optionally redirect to different world
|
||||
World newWorld = Universe.get().getWorld("hub");
|
||||
if (newWorld != null) {
|
||||
event.setWorld(newWorld);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Chat Events
|
||||
|
||||
### PlayerChatEvent
|
||||
|
||||
{{< badge "Cancellable" >}} {{< badge "Async" >}}
|
||||
|
||||
Fired when a player sends a chat message. This event is asynchronous.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| sender | `PlayerRef` | The player sending the message |
|
||||
| targets | `List<PlayerRef>` | Players who will receive the message |
|
||||
| content | `String` | The message content |
|
||||
| formatter | `Formatter` | Message formatting handler |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getSender()` - Returns the sending player reference
|
||||
- `setSender(PlayerRef)` - Change the sender
|
||||
- `getContent()` - Returns the message content
|
||||
- `setContent(String)` - Modify the message
|
||||
- `getTargets()` - Returns message recipients
|
||||
- `setTargets(List<PlayerRef>)` - Change recipients
|
||||
- `getFormatter()` - Returns the message formatter
|
||||
- `setFormatter(Formatter)` - Set custom formatter
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel the message
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// PlayerChatEvent has String key and is async - use registerAsyncGlobal()
|
||||
getEventRegistry().registerAsyncGlobal(PlayerChatEvent.class, future -> {
|
||||
return future.thenApply(event -> {
|
||||
PlayerRef sender = event.getSender();
|
||||
String message = event.getContent();
|
||||
|
||||
// Filter bad words
|
||||
if (containsBadWord(message)) {
|
||||
event.setCancelled(true);
|
||||
// Use PlayerRef.sendMessage() directly
|
||||
sender.sendMessage(Message.raw("Please don't use that word!"));
|
||||
return event;
|
||||
}
|
||||
|
||||
// Add prefix based on rank
|
||||
String prefix = getPlayerPrefix(sender);
|
||||
event.setContent(prefix + message);
|
||||
|
||||
// Custom formatter
|
||||
event.setFormatter((playerRef, msg) ->
|
||||
Message.translation("custom.chat.format")
|
||||
.param("name", playerRef.getUsername())
|
||||
.param("message", msg)
|
||||
);
|
||||
|
||||
return event;
|
||||
});
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Async Event:** This event runs asynchronously. Use `sender.getReference()` to check if the player is still online (returns null or invalid reference if disconnected).
|
||||
{{< /callout >}}
|
||||
|
||||
---
|
||||
|
||||
## Crafting Events
|
||||
|
||||
### PlayerCraftEvent
|
||||
|
||||
{{< badge "Deprecated" >}}
|
||||
|
||||
Fired when a player crafts an item.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Deprecated:** This event is marked for removal. Use `CraftRecipeEvent` from the ECS events instead.
|
||||
{{< /callout >}}
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| ref | `Ref<EntityStore>` | Entity store reference |
|
||||
| player | `Player` | The crafting player |
|
||||
| craftedRecipe | `CraftingRecipe` | The recipe being crafted |
|
||||
| quantity | `int` | Number of items crafted |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayer()` - Returns the Player object
|
||||
- `getPlayerRef()` - Returns entity store reference
|
||||
- `getCraftedRecipe()` - Returns the crafting recipe
|
||||
- `getQuantity()` - Returns number crafted
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Deprecated - prefer CraftRecipeEvent
|
||||
getEventRegistry().register(PlayerCraftEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
CraftingRecipe recipe = event.getCraftedRecipe();
|
||||
int quantity = event.getQuantity();
|
||||
|
||||
getLogger().at(Level.INFO).log(player.getDisplayName() + " crafted " + quantity + " items");
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Input Events
|
||||
|
||||
### PlayerMouseButtonEvent
|
||||
|
||||
{{< badge "Cancellable" >}}
|
||||
|
||||
Fired when a player presses a mouse button.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerRef | `PlayerRef` | Reference to the player |
|
||||
| clientUseTime | `long` | Client-side timestamp |
|
||||
| itemInHand | `Item` | The item being held |
|
||||
| targetBlock | `Vector3i` | Block being targeted |
|
||||
| targetEntity | `Entity` | Entity being targeted |
|
||||
| screenPoint | `Vector2f` | Screen coordinates |
|
||||
| mouseButton | `MouseButtonEvent` | Which button was pressed |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayer()` - Returns the Player object
|
||||
- `getPlayerRef()` - Returns entity store reference
|
||||
- `getPlayerRefComponent()` - Returns PlayerRef component
|
||||
- `getClientUseTime()` - Returns client timestamp
|
||||
- `getItemInHand()` - Returns held item
|
||||
- `getTargetBlock()` - Returns targeted block position
|
||||
- `getTargetEntity()` - Returns targeted entity
|
||||
- `getScreenPoint()` - Returns screen coordinates
|
||||
- `getMouseButton()` - Returns mouse button info
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel the input
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerMouseButtonEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Prevent input during cutscene
|
||||
if (isInCutscene(player)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Custom item interaction
|
||||
Item item = event.getItemInHand();
|
||||
if (item != null && item.getId().equals("magic_wand")) {
|
||||
handleMagicWandUse(player, event.getTargetBlock());
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerMouseMotionEvent
|
||||
|
||||
{{< badge "Cancellable" >}}
|
||||
|
||||
Fired when a player moves their mouse (camera rotation, aiming).
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerRef | `Ref<EntityStore>` | Entity store reference |
|
||||
| player | `Player` | The player |
|
||||
| clientUseTime | `long` | Client-side timestamp |
|
||||
| itemInHand | `Item` | The item being held |
|
||||
| targetBlock | `Vector3i` | Block being targeted |
|
||||
| targetEntity | `Entity` | Entity being targeted |
|
||||
| screenPoint | `Vector2f` | Screen coordinates |
|
||||
| mouseMotion | `MouseMotionEvent` | Mouse motion data |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayer()` - Returns the Player object
|
||||
- `getPlayerRef()` - Returns entity store reference
|
||||
- `getClientUseTime()` - Returns client timestamp
|
||||
- `getItemInHand()` - Returns held item
|
||||
- `getTargetBlock()` - Returns targeted block position
|
||||
- `getTargetEntity()` - Returns targeted entity
|
||||
- `getScreenPoint()` - Returns screen coordinates
|
||||
- `getMouseMotion()` - Returns mouse motion data
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel the motion event
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerMouseMotionEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Track what the player is looking at
|
||||
Entity target = event.getTargetEntity();
|
||||
if (target != null) {
|
||||
updatePlayerTarget(player, target);
|
||||
}
|
||||
|
||||
// Track camera movement for analytics
|
||||
trackCameraMovement(player, event.getMouseMotion());
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Interaction Events
|
||||
|
||||
### PlayerInteractEvent
|
||||
|
||||
{{< badge "Deprecated" >}} {{< badge "Cancellable" >}}
|
||||
|
||||
Fired when a player interacts with the world.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Deprecated:** This event is deprecated. Use more specific events like `UseBlockEvent`, `PlayerMouseButtonEvent`, or ECS interaction events instead.
|
||||
{{< /callout >}}
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| actionType | `InteractionType` | Type of interaction |
|
||||
| clientUseTime | `long` | Client timestamp |
|
||||
| itemInHand | `ItemStack` | Item being used |
|
||||
| targetBlock | `Vector3i` | Block being targeted |
|
||||
| targetEntity | `Entity` | Entity being targeted |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayer()` - Returns the Player object
|
||||
- `getActionType()` - Returns interaction type
|
||||
- `getClientUseTime()` - Returns client timestamp
|
||||
- `getItemInHand()` - Returns item in hand
|
||||
- `getTargetBlock()` - Returns targeted block
|
||||
- `getTargetEntity()` - Returns targeted entity
|
||||
- `getTargetRef()` - Returns target entity reference
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel interaction
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Deprecated - prefer UseBlockEvent or PlayerMouseButtonEvent
|
||||
getEventRegistry().register(PlayerInteractEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
InteractionType action = event.getActionType();
|
||||
|
||||
// Handle interaction
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Practical Examples
|
||||
|
||||
### Complete Welcome System
|
||||
|
||||
```java
|
||||
public class WelcomePlugin extends JavaPlugin {
|
||||
|
||||
private final Set<UUID> firstJoinPlayers = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Track setup phase
|
||||
getEventRegistry().register(PlayerSetupConnectEvent.class, event -> {
|
||||
if (isFirstJoin(event.getUuid())) {
|
||||
firstJoinPlayers.add(event.getUuid());
|
||||
}
|
||||
});
|
||||
|
||||
// Welcome when fully ready
|
||||
getEventRegistry().register(PlayerReadyEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (firstJoinPlayers.remove(player.getUuid())) {
|
||||
// First time player
|
||||
player.sendMessage(Message.raw("Welcome to the server for the first time!"));
|
||||
giveStarterKit(player);
|
||||
} else {
|
||||
// Returning player
|
||||
player.sendMessage(Message.raw("Welcome back, " + player.getDisplayName() + "!"));
|
||||
}
|
||||
});
|
||||
|
||||
// Save on disconnect
|
||||
getEventRegistry().register(PlayerDisconnectEvent.class, event -> {
|
||||
savePlayerData(event.getPlayerRef().getUuid());
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Server Referral System
|
||||
|
||||
```java
|
||||
public class ReferralPlugin extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
getEventRegistry().register(PlayerSetupConnectEvent.class, event -> {
|
||||
// Check if player came from referral
|
||||
if (event.isReferralConnection()) {
|
||||
byte[] data = event.getReferralData();
|
||||
HostAddress source = event.getReferralSource();
|
||||
getLogger().at(Level.INFO).log("Player referred from " + source.host);
|
||||
}
|
||||
|
||||
// Redirect based on load balancing
|
||||
String targetServer = getOptimalServer();
|
||||
if (!isThisServer(targetServer)) {
|
||||
event.referToServer(targetServer, 25565, createReferralData());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Chat Filter System
|
||||
|
||||
```java
|
||||
public class ChatFilterPlugin extends JavaPlugin {
|
||||
|
||||
private final Set<String> bannedWords = new HashSet<>();
|
||||
private final Map<UUID, Integer> warnings = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
loadBannedWords();
|
||||
|
||||
getEventRegistry().register(PlayerChatEvent.class, event -> {
|
||||
PlayerRef sender = event.getSender();
|
||||
String message = event.getContent().toLowerCase();
|
||||
|
||||
for (String banned : bannedWords) {
|
||||
if (message.contains(banned)) {
|
||||
event.setCancelled(true);
|
||||
|
||||
Player player = sender.getPlayer();
|
||||
if (player != null) {
|
||||
int count = warnings.merge(sender.getUuid(), 1, Integer::sum);
|
||||
player.sendMessage(Message.raw("Warning " + count + "/3: Watch your language!"));
|
||||
|
||||
if (count >= 3) {
|
||||
player.kick("Too many chat violations");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
675
content/core-concepts/events/event-reference/player-events.fr.md
Normal file
675
content/core-concepts/events/event-reference/player-events.fr.md
Normal file
@@ -0,0 +1,675 @@
|
||||
---
|
||||
title: Player Events
|
||||
type: docs
|
||||
weight: 1
|
||||
---
|
||||
|
||||
Events triggered by player actions and state changes.
|
||||
|
||||
## Connection Events
|
||||
|
||||
### PlayerSetupConnectEvent
|
||||
|
||||
{{< badge "Cancellable" >}}
|
||||
|
||||
Fired during player connection setup. Can be cancelled to prevent connection or redirect to another server.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| uuid | `UUID` | Player's unique identifier |
|
||||
| username | `String` | Player's username |
|
||||
| auth | `PlayerAuthentication` | Authentication information |
|
||||
| referralData | `byte[]` | Data from referral (if redirected) |
|
||||
| referralSource | `HostAddress` | Server that referred player |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getUuid()` - Returns player UUID
|
||||
- `getUsername()` - Returns player username
|
||||
- `getAuth()` - Returns authentication data
|
||||
- `getReferralData()` - Returns referral data (may be null)
|
||||
- `isReferralConnection()` - Check if redirected from another server
|
||||
- `getReferralSource()` - Returns source server address
|
||||
- `referToServer(host, port)` - Redirect player to another server
|
||||
- `referToServer(host, port, data)` - Redirect with data
|
||||
- `getReason()` - Get disconnect reason message
|
||||
- `setReason(String)` - Set disconnect reason message
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel connection
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerSetupConnectEvent.class, event -> {
|
||||
String username = event.getUsername();
|
||||
UUID uuid = event.getUuid();
|
||||
|
||||
// Ban check
|
||||
if (isBanned(uuid)) {
|
||||
event.setCancelled(true);
|
||||
event.setReason("You are banned from this server!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Redirect to different server based on condition
|
||||
if (shouldRedirect(uuid)) {
|
||||
event.referToServer("lobby.example.com", 25565);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerConnectEvent
|
||||
|
||||
Fired when a player connects to the server. Use this to set the spawn world.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| holder | `Holder<EntityStore>` | Entity store holder |
|
||||
| playerRef | `PlayerRef` | Reference to the connecting player |
|
||||
| world | `World` | The world player will spawn in |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getHolder()` - Returns the entity store holder
|
||||
- `getPlayerRef()` - Returns the player reference
|
||||
- `getPlayer()` - Returns the Player object (deprecated)
|
||||
- `getWorld()` - Returns current spawn world (may be null)
|
||||
- `setWorld(World)` - Set the world player will spawn in
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerConnectEvent.class, event -> {
|
||||
PlayerRef playerRef = event.getPlayerRef();
|
||||
getLogger().at(Level.INFO).log("Player connecting: " + playerRef.getUsername());
|
||||
|
||||
// Set spawn world
|
||||
World lobbyWorld = Universe.get().getWorld("lobby");
|
||||
if (lobbyWorld != null) {
|
||||
event.setWorld(lobbyWorld);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
The `getPlayer()` method is deprecated. Prefer using `getPlayerRef()` or `getHolder()` to access player data.
|
||||
{{< /callout >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerSetupDisconnectEvent
|
||||
|
||||
Fired when a player disconnects during the setup phase (before fully connecting).
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| uuid | `UUID` | Player's unique identifier |
|
||||
| username | `String` | Player's username |
|
||||
| auth | `PlayerAuthentication` | Authentication information |
|
||||
| disconnectReason | `DisconnectReason` | Why the player disconnected |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getUuid()` - Returns player UUID
|
||||
- `getUsername()` - Returns player username
|
||||
- `getAuth()` - Returns authentication data
|
||||
- `getDisconnectReason()` - Returns disconnect reason
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerSetupDisconnectEvent.class, event -> {
|
||||
String username = event.getUsername();
|
||||
PacketHandler.DisconnectReason reason = event.getDisconnectReason();
|
||||
|
||||
getLogger().at(Level.INFO).log("Player " + username + " disconnected during setup: " + reason);
|
||||
|
||||
// Cleanup any pre-connection data
|
||||
cleanupPendingData(event.getUuid());
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerReadyEvent
|
||||
|
||||
Fired when a player is fully ready and loaded into the game. This is the safe point to interact with the player.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerRef | `Ref<EntityStore>` | Entity store reference |
|
||||
| player | `Player` | The player object |
|
||||
| readyId | `int` | Ready event identifier |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayer()` - Returns the Player object
|
||||
- `getPlayerRef()` - Returns the entity store reference
|
||||
- `getReadyId()` - Returns the ready event ID
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerReadyEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Player is fully loaded, safe to send complex data
|
||||
player.sendMessage(Message.raw("Welcome to the server!"));
|
||||
loadPlayerData(player);
|
||||
sendWelcomeScreen(player);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerDisconnectEvent
|
||||
|
||||
Fired when a player disconnects from the server.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerRef | `PlayerRef` | Reference to the disconnecting player |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayerRef()` - Returns the player reference
|
||||
- `getDisconnectReason()` - Returns why the player disconnected
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerDisconnectEvent.class, event -> {
|
||||
PlayerRef playerRef = event.getPlayerRef();
|
||||
|
||||
savePlayerData(playerRef.getUuid());
|
||||
getLogger().at(Level.INFO).log(playerRef.getUsername() + " has left the server");
|
||||
|
||||
// Check disconnect reason
|
||||
PacketHandler.DisconnectReason reason = event.getDisconnectReason();
|
||||
getLogger().at(Level.INFO).log("Reason: " + reason);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## World Events
|
||||
|
||||
### AddPlayerToWorldEvent
|
||||
|
||||
Fired when a player is added to a world.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| holder | `Holder<EntityStore>` | Entity store holder |
|
||||
| world | `World` | The world being entered |
|
||||
| broadcastJoinMessage | `boolean` | Whether to broadcast join message |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getHolder()` - Returns the entity store holder
|
||||
- `getWorld()` - Returns the world
|
||||
- `shouldBroadcastJoinMessage()` - Check if join message will be sent
|
||||
- `setBroadcastJoinMessage(boolean)` - Control join message broadcast
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(AddPlayerToWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
|
||||
// Disable default join message for silent joins
|
||||
if (isSilentJoin(event.getHolder())) {
|
||||
event.setBroadcastJoinMessage(false);
|
||||
}
|
||||
|
||||
applyWorldEffects(event.getHolder(), world);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### DrainPlayerFromWorldEvent
|
||||
|
||||
Fired when a player is removed from a world (before teleporting to another or disconnecting).
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| holder | `Holder<EntityStore>` | Entity store holder |
|
||||
| world | `World` | The world being left |
|
||||
| transform | `Transform` | Player's position/rotation |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getHolder()` - Returns the entity store holder
|
||||
- `getWorld()` - Returns the world being left
|
||||
- `setWorld(World)` - Change destination world
|
||||
- `getTransform()` - Returns player's transform
|
||||
- `setTransform(Transform)` - Set spawn transform in new world
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(DrainPlayerFromWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
|
||||
removeWorldEffects(event.getHolder());
|
||||
saveWorldProgress(event.getHolder(), world);
|
||||
|
||||
// Optionally redirect to different world
|
||||
World newWorld = Universe.get().getWorld("hub");
|
||||
if (newWorld != null) {
|
||||
event.setWorld(newWorld);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Chat Events
|
||||
|
||||
### PlayerChatEvent
|
||||
|
||||
{{< badge "Cancellable" >}} {{< badge "Async" >}}
|
||||
|
||||
Fired when a player sends a chat message. This event is asynchronous.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| sender | `PlayerRef` | The player sending the message |
|
||||
| targets | `List<PlayerRef>` | Players who will receive the message |
|
||||
| content | `String` | The message content |
|
||||
| formatter | `Formatter` | Message formatting handler |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getSender()` - Returns the sending player reference
|
||||
- `setSender(PlayerRef)` - Change the sender
|
||||
- `getContent()` - Returns the message content
|
||||
- `setContent(String)` - Modify the message
|
||||
- `getTargets()` - Returns message recipients
|
||||
- `setTargets(List<PlayerRef>)` - Change recipients
|
||||
- `getFormatter()` - Returns the message formatter
|
||||
- `setFormatter(Formatter)` - Set custom formatter
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel the message
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// PlayerChatEvent has String key and is async - use registerAsyncGlobal()
|
||||
getEventRegistry().registerAsyncGlobal(PlayerChatEvent.class, future -> {
|
||||
return future.thenApply(event -> {
|
||||
PlayerRef sender = event.getSender();
|
||||
String message = event.getContent();
|
||||
|
||||
// Filter bad words
|
||||
if (containsBadWord(message)) {
|
||||
event.setCancelled(true);
|
||||
// Use PlayerRef.sendMessage() directly
|
||||
sender.sendMessage(Message.raw("Please don't use that word!"));
|
||||
return event;
|
||||
}
|
||||
|
||||
// Add prefix based on rank
|
||||
String prefix = getPlayerPrefix(sender);
|
||||
event.setContent(prefix + message);
|
||||
|
||||
// Custom formatter
|
||||
event.setFormatter((playerRef, msg) ->
|
||||
Message.translation("custom.chat.format")
|
||||
.param("name", playerRef.getUsername())
|
||||
.param("message", msg)
|
||||
);
|
||||
|
||||
return event;
|
||||
});
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Async Event:** This event runs asynchronously. Use `sender.getReference()` to check if the player is still online (returns null or invalid reference if disconnected).
|
||||
{{< /callout >}}
|
||||
|
||||
---
|
||||
|
||||
## Crafting Events
|
||||
|
||||
### PlayerCraftEvent
|
||||
|
||||
{{< badge "Deprecated" >}}
|
||||
|
||||
Fired when a player crafts an item.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Deprecated:** This event is marked for removal. Use `CraftRecipeEvent` from the ECS events instead.
|
||||
{{< /callout >}}
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| ref | `Ref<EntityStore>` | Entity store reference |
|
||||
| player | `Player` | The crafting player |
|
||||
| craftedRecipe | `CraftingRecipe` | The recipe being crafted |
|
||||
| quantity | `int` | Number of items crafted |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayer()` - Returns the Player object
|
||||
- `getPlayerRef()` - Returns entity store reference
|
||||
- `getCraftedRecipe()` - Returns the crafting recipe
|
||||
- `getQuantity()` - Returns number crafted
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Deprecated - prefer CraftRecipeEvent
|
||||
getEventRegistry().register(PlayerCraftEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
CraftingRecipe recipe = event.getCraftedRecipe();
|
||||
int quantity = event.getQuantity();
|
||||
|
||||
getLogger().at(Level.INFO).log(player.getDisplayName() + " crafted " + quantity + " items");
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Input Events
|
||||
|
||||
### PlayerMouseButtonEvent
|
||||
|
||||
{{< badge "Cancellable" >}}
|
||||
|
||||
Fired when a player presses a mouse button.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerRef | `PlayerRef` | Reference to the player |
|
||||
| clientUseTime | `long` | Client-side timestamp |
|
||||
| itemInHand | `Item` | The item being held |
|
||||
| targetBlock | `Vector3i` | Block being targeted |
|
||||
| targetEntity | `Entity` | Entity being targeted |
|
||||
| screenPoint | `Vector2f` | Screen coordinates |
|
||||
| mouseButton | `MouseButtonEvent` | Which button was pressed |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayer()` - Returns the Player object
|
||||
- `getPlayerRef()` - Returns entity store reference
|
||||
- `getPlayerRefComponent()` - Returns PlayerRef component
|
||||
- `getClientUseTime()` - Returns client timestamp
|
||||
- `getItemInHand()` - Returns held item
|
||||
- `getTargetBlock()` - Returns targeted block position
|
||||
- `getTargetEntity()` - Returns targeted entity
|
||||
- `getScreenPoint()` - Returns screen coordinates
|
||||
- `getMouseButton()` - Returns mouse button info
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel the input
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerMouseButtonEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Prevent input during cutscene
|
||||
if (isInCutscene(player)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Custom item interaction
|
||||
Item item = event.getItemInHand();
|
||||
if (item != null && item.getId().equals("magic_wand")) {
|
||||
handleMagicWandUse(player, event.getTargetBlock());
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PlayerMouseMotionEvent
|
||||
|
||||
{{< badge "Cancellable" >}}
|
||||
|
||||
Fired when a player moves their mouse (camera rotation, aiming).
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| playerRef | `Ref<EntityStore>` | Entity store reference |
|
||||
| player | `Player` | The player |
|
||||
| clientUseTime | `long` | Client-side timestamp |
|
||||
| itemInHand | `Item` | The item being held |
|
||||
| targetBlock | `Vector3i` | Block being targeted |
|
||||
| targetEntity | `Entity` | Entity being targeted |
|
||||
| screenPoint | `Vector2f` | Screen coordinates |
|
||||
| mouseMotion | `MouseMotionEvent` | Mouse motion data |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayer()` - Returns the Player object
|
||||
- `getPlayerRef()` - Returns entity store reference
|
||||
- `getClientUseTime()` - Returns client timestamp
|
||||
- `getItemInHand()` - Returns held item
|
||||
- `getTargetBlock()` - Returns targeted block position
|
||||
- `getTargetEntity()` - Returns targeted entity
|
||||
- `getScreenPoint()` - Returns screen coordinates
|
||||
- `getMouseMotion()` - Returns mouse motion data
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel the motion event
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PlayerMouseMotionEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Track what the player is looking at
|
||||
Entity target = event.getTargetEntity();
|
||||
if (target != null) {
|
||||
updatePlayerTarget(player, target);
|
||||
}
|
||||
|
||||
// Track camera movement for analytics
|
||||
trackCameraMovement(player, event.getMouseMotion());
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Interaction Events
|
||||
|
||||
### PlayerInteractEvent
|
||||
|
||||
{{< badge "Deprecated" >}} {{< badge "Cancellable" >}}
|
||||
|
||||
Fired when a player interacts with the world.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.player`
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Deprecated:** This event is deprecated. Use more specific events like `UseBlockEvent`, `PlayerMouseButtonEvent`, or ECS interaction events instead.
|
||||
{{< /callout >}}
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| actionType | `InteractionType` | Type of interaction |
|
||||
| clientUseTime | `long` | Client timestamp |
|
||||
| itemInHand | `ItemStack` | Item being used |
|
||||
| targetBlock | `Vector3i` | Block being targeted |
|
||||
| targetEntity | `Entity` | Entity being targeted |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlayer()` - Returns the Player object
|
||||
- `getActionType()` - Returns interaction type
|
||||
- `getClientUseTime()` - Returns client timestamp
|
||||
- `getItemInHand()` - Returns item in hand
|
||||
- `getTargetBlock()` - Returns targeted block
|
||||
- `getTargetEntity()` - Returns targeted entity
|
||||
- `getTargetRef()` - Returns target entity reference
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel interaction
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
// Deprecated - prefer UseBlockEvent or PlayerMouseButtonEvent
|
||||
getEventRegistry().register(PlayerInteractEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
InteractionType action = event.getActionType();
|
||||
|
||||
// Handle interaction
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Practical Examples
|
||||
|
||||
### Complete Welcome System
|
||||
|
||||
```java
|
||||
public class WelcomePlugin extends JavaPlugin {
|
||||
|
||||
private final Set<UUID> firstJoinPlayers = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Track setup phase
|
||||
getEventRegistry().register(PlayerSetupConnectEvent.class, event -> {
|
||||
if (isFirstJoin(event.getUuid())) {
|
||||
firstJoinPlayers.add(event.getUuid());
|
||||
}
|
||||
});
|
||||
|
||||
// Welcome when fully ready
|
||||
getEventRegistry().register(PlayerReadyEvent.class, event -> {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (firstJoinPlayers.remove(player.getUuid())) {
|
||||
// First time player
|
||||
player.sendMessage(Message.raw("Welcome to the server for the first time!"));
|
||||
giveStarterKit(player);
|
||||
} else {
|
||||
// Returning player
|
||||
player.sendMessage(Message.raw("Welcome back, " + player.getDisplayName() + "!"));
|
||||
}
|
||||
});
|
||||
|
||||
// Save on disconnect
|
||||
getEventRegistry().register(PlayerDisconnectEvent.class, event -> {
|
||||
savePlayerData(event.getPlayerRef().getUuid());
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Server Referral System
|
||||
|
||||
```java
|
||||
public class ReferralPlugin extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
getEventRegistry().register(PlayerSetupConnectEvent.class, event -> {
|
||||
// Check if player came from referral
|
||||
if (event.isReferralConnection()) {
|
||||
byte[] data = event.getReferralData();
|
||||
HostAddress source = event.getReferralSource();
|
||||
getLogger().at(Level.INFO).log("Player referred from " + source.host);
|
||||
}
|
||||
|
||||
// Redirect based on load balancing
|
||||
String targetServer = getOptimalServer();
|
||||
if (!isThisServer(targetServer)) {
|
||||
event.referToServer(targetServer, 25565, createReferralData());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Chat Filter System
|
||||
|
||||
```java
|
||||
public class ChatFilterPlugin extends JavaPlugin {
|
||||
|
||||
private final Set<String> bannedWords = new HashSet<>();
|
||||
private final Map<UUID, Integer> warnings = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
loadBannedWords();
|
||||
|
||||
getEventRegistry().register(PlayerChatEvent.class, event -> {
|
||||
PlayerRef sender = event.getSender();
|
||||
String message = event.getContent().toLowerCase();
|
||||
|
||||
for (String banned : bannedWords) {
|
||||
if (message.contains(banned)) {
|
||||
event.setCancelled(true);
|
||||
|
||||
Player player = sender.getPlayer();
|
||||
if (player != null) {
|
||||
int count = warnings.merge(sender.getUuid(), 1, Integer::sum);
|
||||
player.sendMessage(Message.raw("Warning " + count + "/3: Watch your language!"));
|
||||
|
||||
if (count >= 3) {
|
||||
player.kick("Too many chat violations");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
468
content/core-concepts/events/event-reference/server-events.en.md
Normal file
468
content/core-concepts/events/event-reference/server-events.en.md
Normal file
@@ -0,0 +1,468 @@
|
||||
---
|
||||
title: Server Events
|
||||
type: docs
|
||||
weight: 6
|
||||
---
|
||||
|
||||
Events related to server lifecycle, plugins, and system operations.
|
||||
|
||||
## Server Lifecycle Events
|
||||
|
||||
### BootEvent
|
||||
|
||||
Fired when the server finishes booting up. This is a marker event with no fields.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events`
|
||||
|
||||
{{< tabs items="Fields,Example" >}}
|
||||
{{< tab >}}
|
||||
This event has no fields. It is a simple notification that boot has completed.
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(BootEvent.class, event -> {
|
||||
getLogger().at(Level.INFO).log("Server boot complete!");
|
||||
|
||||
// Initialize post-boot features
|
||||
initializeMetrics();
|
||||
startBackgroundTasks();
|
||||
openConnectionsToExternalServices();
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### ShutdownEvent
|
||||
|
||||
Fired when the server is shutting down. This is a marker event with priority constants.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events`
|
||||
|
||||
{{< tabs items="Constants,Example" >}}
|
||||
{{< tab >}}
|
||||
| Constant | Value | Description |
|
||||
|----------|-------|-------------|
|
||||
| `DISCONNECT_PLAYERS` | -48 | Priority for disconnecting players |
|
||||
| `UNBIND_LISTENERS` | -40 | Priority for unbinding network listeners |
|
||||
| `SHUTDOWN_WORLDS` | -32 | Priority for shutting down worlds |
|
||||
|
||||
Use these constants with `EventPriority` to order shutdown handlers.
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ShutdownEvent.class, event -> {
|
||||
getLogger().at(Level.INFO).log("Server shutting down!");
|
||||
|
||||
// Perform cleanup
|
||||
saveAllPlayerData();
|
||||
closeExternalConnections();
|
||||
flushMetrics();
|
||||
});
|
||||
|
||||
// Use priority constants for ordering
|
||||
getEventRegistry().register(
|
||||
ShutdownEvent.DISCONNECT_PLAYERS,
|
||||
ShutdownEvent.class,
|
||||
event -> {
|
||||
// Notify players before disconnect
|
||||
Universe.get().getPlayers().forEach(player ->
|
||||
player.sendMessage(Message.raw("Server shutting down!"))
|
||||
);
|
||||
}
|
||||
);
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Important:** Keep shutdown handlers fast and synchronous. The server may force-terminate if handlers take too long.
|
||||
{{< /callout >}}
|
||||
|
||||
---
|
||||
|
||||
## Plugin Events
|
||||
|
||||
### PluginSetupEvent
|
||||
|
||||
Fired when a plugin is being set up (before start).
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.plugin`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| plugin | `JavaPlugin` | The plugin being set up |
|
||||
| pluginInfo | `PluginInfo` | Plugin metadata |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlugin()` - Returns the plugin instance
|
||||
- `getPluginInfo()` - Returns plugin metadata
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PluginSetupEvent.class, event -> {
|
||||
PluginInfo info = event.getPluginInfo();
|
||||
|
||||
getLogger().at(Level.INFO).log("Plugin setting up: " + info.getName() +
|
||||
" v" + info.getVersion());
|
||||
|
||||
// Check for plugin dependencies
|
||||
if (isDependencyPlugin(info.getName())) {
|
||||
registerDependencyHooks(event.getPlugin());
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PluginEnableEvent
|
||||
|
||||
Fired when a plugin is enabled.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.plugin`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| plugin | `JavaPlugin` | The enabled plugin |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlugin()` - Returns the plugin instance
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PluginEnableEvent.class, event -> {
|
||||
JavaPlugin plugin = event.getPlugin();
|
||||
|
||||
getLogger().at(Level.INFO).log("Plugin enabled: " + plugin.getName());
|
||||
|
||||
// Hook into other plugins
|
||||
if (plugin.getName().equals("Economy")) {
|
||||
hookEconomyPlugin(plugin);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PluginDisableEvent
|
||||
|
||||
Fired when a plugin is disabled.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.plugin`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| plugin | `JavaPlugin` | The disabled plugin |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlugin()` - Returns the plugin instance
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PluginDisableEvent.class, event -> {
|
||||
JavaPlugin plugin = event.getPlugin();
|
||||
|
||||
getLogger().at(Level.INFO).log("Plugin disabled: " + plugin.getName());
|
||||
|
||||
// Unhook from other plugins
|
||||
if (plugin.getName().equals("Economy")) {
|
||||
unhookEconomyPlugin();
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Tick Events
|
||||
|
||||
### ServerTickEvent
|
||||
|
||||
Fired every server tick (typically 20 times per second).
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.server`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| tickNumber | `long` | Current tick number |
|
||||
| deltaTime | `float` | Time since last tick (seconds) |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getTickNumber()` - Returns current tick count
|
||||
- `getDeltaTime()` - Returns delta time in seconds
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ServerTickEvent.class, event -> {
|
||||
long tick = event.getTickNumber();
|
||||
|
||||
// Run every second (20 ticks)
|
||||
if (tick % 20 == 0) {
|
||||
updateScoreboards();
|
||||
}
|
||||
|
||||
// Run every minute (1200 ticks)
|
||||
if (tick % 1200 == 0) {
|
||||
saveAutoSave();
|
||||
cleanupExpiredData();
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Performance Critical:** This event fires 20 times per second. Keep handlers extremely lightweight. Use tick counting for periodic tasks instead of running on every tick.
|
||||
{{< /callout >}}
|
||||
|
||||
---
|
||||
|
||||
## Command Events
|
||||
|
||||
### CommandExecuteEvent
|
||||
|
||||
{{< badge "Cancellable" >}}
|
||||
|
||||
Fired when a command is executed.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.command`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| sender | `CommandSender` | Who executed the command |
|
||||
| command | `String` | Command name |
|
||||
| args | `String[]` | Command arguments |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getSender()` - Returns the command sender
|
||||
- `getCommand()` - Returns command name
|
||||
- `getArgs()` - Returns arguments array
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel command
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(CommandExecuteEvent.class, event -> {
|
||||
CommandSender sender = event.getSender();
|
||||
String command = event.getCommand();
|
||||
|
||||
// Log all commands
|
||||
getLogger().at(Level.INFO).log(sender.getName() + " executed: /" + command +
|
||||
" " + String.join(" ", event.getArgs()));
|
||||
|
||||
// Block certain commands for non-ops
|
||||
if (command.equals("stop") && !sender.isOp()) {
|
||||
event.setCancelled(true);
|
||||
sender.sendMessage("You don't have permission!");
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Practical Examples
|
||||
|
||||
### Server Metrics Plugin
|
||||
|
||||
```java
|
||||
public class MetricsPlugin extends JavaPlugin {
|
||||
|
||||
private long startTime;
|
||||
private long tickCount = 0;
|
||||
private long lastTickTime;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Track server boot
|
||||
getEventRegistry().register(BootEvent.class, event -> {
|
||||
startTime = System.currentTimeMillis();
|
||||
lastTickTime = startTime;
|
||||
getLogger().at(Level.INFO).log("Server boot complete, tracking metrics...");
|
||||
});
|
||||
|
||||
// Calculate TPS
|
||||
getEventRegistry().register(ServerTickEvent.class, event -> {
|
||||
tickCount++;
|
||||
|
||||
// Calculate TPS every second
|
||||
if (tickCount % 20 == 0) {
|
||||
long now = System.currentTimeMillis();
|
||||
long elapsed = now - lastTickTime;
|
||||
double tps = 20000.0 / elapsed;
|
||||
lastTickTime = now;
|
||||
|
||||
if (tps < 18.0) {
|
||||
getLogger().warning("Low TPS: " + String.format("%.2f", tps));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Save metrics on shutdown
|
||||
getEventRegistry().register(ShutdownEvent.class, event -> {
|
||||
long uptime = System.currentTimeMillis() - startTime;
|
||||
saveMetrics(uptime, tickCount);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Plugin Dependency Manager
|
||||
|
||||
```java
|
||||
public class DependencyPlugin extends JavaPlugin {
|
||||
|
||||
private final Map<String, JavaPlugin> loadedDependencies = new HashMap<>();
|
||||
private final Set<String> requiredPlugins = Set.of("Economy", "Permissions");
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Track plugin loading
|
||||
getEventRegistry().register(PluginEnableEvent.class, event -> {
|
||||
JavaPlugin plugin = event.getPlugin();
|
||||
|
||||
if (requiredPlugins.contains(plugin.getName())) {
|
||||
loadedDependencies.put(plugin.getName(), plugin);
|
||||
getLogger().at(Level.INFO).log("Dependency loaded: " + plugin.getName());
|
||||
|
||||
// Check if all dependencies are loaded
|
||||
if (loadedDependencies.keySet().containsAll(requiredPlugins)) {
|
||||
initializeDependentFeatures();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle dependency unload
|
||||
getEventRegistry().register(PluginDisableEvent.class, event -> {
|
||||
JavaPlugin plugin = event.getPlugin();
|
||||
|
||||
if (loadedDependencies.remove(plugin.getName()) != null) {
|
||||
getLogger().warning("Dependency unloaded: " + plugin.getName());
|
||||
disableDependentFeatures();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Command Logging & Rate Limiting
|
||||
|
||||
```java
|
||||
public class CommandSecurityPlugin extends JavaPlugin {
|
||||
|
||||
private final Map<UUID, List<Long>> commandHistory = new HashMap<>();
|
||||
private static final int MAX_COMMANDS_PER_SECOND = 5;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
getEventRegistry().register(CommandExecuteEvent.class, event -> {
|
||||
CommandSender sender = event.getSender();
|
||||
|
||||
// Only rate limit players
|
||||
if (!(sender instanceof Player)) return;
|
||||
|
||||
Player player = (Player) sender;
|
||||
UUID uuid = player.getUuid();
|
||||
|
||||
// Get command history
|
||||
List<Long> history = commandHistory.computeIfAbsent(
|
||||
uuid, k -> new ArrayList<>()
|
||||
);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
// Remove old entries (older than 1 second)
|
||||
history.removeIf(time -> now - time > 1000);
|
||||
|
||||
// Check rate limit
|
||||
if (history.size() >= MAX_COMMANDS_PER_SECOND) {
|
||||
event.setCancelled(true);
|
||||
player.sendMessage("Too many commands! Please slow down.");
|
||||
getLogger().warning("Rate limited: " + player.getDisplayName());
|
||||
return;
|
||||
}
|
||||
|
||||
// Record this command
|
||||
history.add(now);
|
||||
|
||||
// Log to file
|
||||
logCommand(player, event.getCommand(), event.getArgs());
|
||||
});
|
||||
|
||||
// Cleanup on disconnect
|
||||
getEventRegistry().register(PlayerDisconnectEvent.class, event -> {
|
||||
commandHistory.remove(event.getPlayer().getUuid());
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Scheduled Tasks Manager
|
||||
|
||||
```java
|
||||
public class SchedulerPlugin extends JavaPlugin {
|
||||
|
||||
private final List<ScheduledTask> tasks = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Schedule various tasks
|
||||
scheduleTask("autosave", 6000, this::autoSave); // Every 5 minutes
|
||||
scheduleTask("cleanup", 72000, this::cleanup); // Every hour
|
||||
scheduleTask("broadcast", 12000, this::broadcast); // Every 10 minutes
|
||||
|
||||
// Execute tasks based on tick
|
||||
getEventRegistry().register(ServerTickEvent.class, event -> {
|
||||
long tick = event.getTickNumber();
|
||||
|
||||
for (ScheduledTask task : tasks) {
|
||||
if (tick % task.interval() == 0) {
|
||||
try {
|
||||
task.runnable().run();
|
||||
} catch (Exception e) {
|
||||
getLogger().error("Task failed: " + task.name(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void scheduleTask(String name, int intervalTicks, Runnable runnable) {
|
||||
tasks.add(new ScheduledTask(name, intervalTicks, runnable));
|
||||
}
|
||||
|
||||
record ScheduledTask(String name, int interval, Runnable runnable) {}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Server Event Guidelines:**
|
||||
- Keep `ShutdownEvent` handlers fast and reliable
|
||||
- Use tick counting in `ServerTickEvent` for periodic tasks
|
||||
- Clean up resources in `PluginDisableEvent`
|
||||
- Initialize cross-plugin features in `PluginEnableEvent`
|
||||
- Log important command executions for auditing
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="error" >}}
|
||||
**Critical:** Never perform blocking operations (I/O, network, database) directly in `ServerTickEvent`. Use async tasks instead.
|
||||
{{< /callout >}}
|
||||
468
content/core-concepts/events/event-reference/server-events.fr.md
Normal file
468
content/core-concepts/events/event-reference/server-events.fr.md
Normal file
@@ -0,0 +1,468 @@
|
||||
---
|
||||
title: Événements Serveur
|
||||
type: docs
|
||||
weight: 6
|
||||
---
|
||||
|
||||
Événements liés au cycle de vie du serveur, aux plugins et aux opérations système.
|
||||
|
||||
## Événements du Cycle de Vie du Serveur
|
||||
|
||||
### BootEvent
|
||||
|
||||
Déclenché quand le serveur finit de démarrer. C'est un événement marqueur sans champs.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events`
|
||||
|
||||
{{< tabs items="Champs,Exemple" >}}
|
||||
{{< tab >}}
|
||||
Cet événement n'a pas de champs. C'est une simple notification que le démarrage est terminé.
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(BootEvent.class, event -> {
|
||||
getLogger().at(Level.INFO).log("Démarrage du serveur terminé !");
|
||||
|
||||
// Initialiser les fonctionnalités post-démarrage
|
||||
initializeMetrics();
|
||||
startBackgroundTasks();
|
||||
openConnectionsToExternalServices();
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### ShutdownEvent
|
||||
|
||||
Déclenché quand le serveur s'arrête. C'est un événement marqueur avec des constantes de priorité.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events`
|
||||
|
||||
{{< tabs items="Constantes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Constante | Valeur | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `DISCONNECT_PLAYERS` | -48 | Priorité pour déconnecter les joueurs |
|
||||
| `UNBIND_LISTENERS` | -40 | Priorité pour délier les listeners réseau |
|
||||
| `SHUTDOWN_WORLDS` | -32 | Priorité pour arrêter les mondes |
|
||||
|
||||
Utilisez ces constantes avec `EventPriority` pour ordonner les handlers d'arrêt.
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ShutdownEvent.class, event -> {
|
||||
getLogger().at(Level.INFO).log("Arrêt du serveur !");
|
||||
|
||||
// Effectuer le nettoyage
|
||||
saveAllPlayerData();
|
||||
closeExternalConnections();
|
||||
flushMetrics();
|
||||
});
|
||||
|
||||
// Utiliser les constantes de priorité pour l'ordre
|
||||
getEventRegistry().register(
|
||||
ShutdownEvent.DISCONNECT_PLAYERS,
|
||||
ShutdownEvent.class,
|
||||
event -> {
|
||||
// Notifier les joueurs avant la déconnexion
|
||||
Universe.get().getPlayers().forEach(player ->
|
||||
player.sendMessage(Message.raw("Le serveur s'arrête !"))
|
||||
);
|
||||
}
|
||||
);
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Important :** Gardez les handlers d'arrêt rapides et synchrones. Le serveur peut forcer l'arrêt si les handlers prennent trop de temps.
|
||||
{{< /callout >}}
|
||||
|
||||
---
|
||||
|
||||
## Événements de Plugin
|
||||
|
||||
### PluginSetupEvent
|
||||
|
||||
Déclenché quand un plugin est en cours de configuration (avant le démarrage).
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.plugin`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| plugin | `JavaPlugin` | Le plugin en configuration |
|
||||
| pluginInfo | `PluginInfo` | Métadonnées du plugin |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlugin()` - Retourne l'instance du plugin
|
||||
- `getPluginInfo()` - Retourne les métadonnées du plugin
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PluginSetupEvent.class, event -> {
|
||||
PluginInfo info = event.getPluginInfo();
|
||||
|
||||
getLogger().at(Level.INFO).log("Configuration du plugin : " + info.getName() +
|
||||
" v" + info.getVersion());
|
||||
|
||||
// Vérifier les dépendances du plugin
|
||||
if (isDependencyPlugin(info.getName())) {
|
||||
registerDependencyHooks(event.getPlugin());
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PluginEnableEvent
|
||||
|
||||
Déclenché quand un plugin est activé.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.plugin`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| plugin | `JavaPlugin` | Le plugin activé |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlugin()` - Retourne l'instance du plugin
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PluginEnableEvent.class, event -> {
|
||||
JavaPlugin plugin = event.getPlugin();
|
||||
|
||||
getLogger().at(Level.INFO).log("Plugin activé : " + plugin.getName());
|
||||
|
||||
// Se connecter à d'autres plugins
|
||||
if (plugin.getName().equals("Economy")) {
|
||||
hookEconomyPlugin(plugin);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### PluginDisableEvent
|
||||
|
||||
Déclenché quand un plugin est désactivé.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.plugin`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| plugin | `JavaPlugin` | Le plugin désactivé |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getPlugin()` - Retourne l'instance du plugin
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(PluginDisableEvent.class, event -> {
|
||||
JavaPlugin plugin = event.getPlugin();
|
||||
|
||||
getLogger().at(Level.INFO).log("Plugin désactivé : " + plugin.getName());
|
||||
|
||||
// Se déconnecter des autres plugins
|
||||
if (plugin.getName().equals("Economy")) {
|
||||
unhookEconomyPlugin();
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Événements de Tick
|
||||
|
||||
### ServerTickEvent
|
||||
|
||||
Déclenché à chaque tick serveur (typiquement 20 fois par seconde).
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.server`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| tickNumber | `long` | Numéro du tick actuel |
|
||||
| deltaTime | `float` | Temps depuis le dernier tick (secondes) |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getTickNumber()` - Retourne le compte de ticks actuel
|
||||
- `getDeltaTime()` - Retourne le delta time en secondes
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ServerTickEvent.class, event -> {
|
||||
long tick = event.getTickNumber();
|
||||
|
||||
// Exécuter toutes les secondes (20 ticks)
|
||||
if (tick % 20 == 0) {
|
||||
updateScoreboards();
|
||||
}
|
||||
|
||||
// Exécuter toutes les minutes (1200 ticks)
|
||||
if (tick % 1200 == 0) {
|
||||
saveAutoSave();
|
||||
cleanupExpiredData();
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Performance Critique :** Cet événement se déclenche 20 fois par seconde. Gardez les handlers extrêmement légers. Utilisez le comptage de ticks pour les tâches périodiques au lieu de s'exécuter à chaque tick.
|
||||
{{< /callout >}}
|
||||
|
||||
---
|
||||
|
||||
## Événements de Commande
|
||||
|
||||
### CommandExecuteEvent
|
||||
|
||||
{{< badge "Annulable" >}}
|
||||
|
||||
Déclenché quand une commande est exécutée.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.command`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| sender | `CommandSender` | Qui a exécuté la commande |
|
||||
| command | `String` | Nom de la commande |
|
||||
| args | `String[]` | Arguments de la commande |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getSender()` - Retourne l'expéditeur de la commande
|
||||
- `getCommand()` - Retourne le nom de la commande
|
||||
- `getArgs()` - Retourne le tableau d'arguments
|
||||
- `isCancelled()` - Vérifie si annulé
|
||||
- `setCancelled(boolean)` - Annule la commande
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(CommandExecuteEvent.class, event -> {
|
||||
CommandSender sender = event.getSender();
|
||||
String command = event.getCommand();
|
||||
|
||||
// Logger toutes les commandes
|
||||
getLogger().at(Level.INFO).log(sender.getName() + " a exécuté : /" + command +
|
||||
" " + String.join(" ", event.getArgs()));
|
||||
|
||||
// Bloquer certaines commandes pour les non-ops
|
||||
if (command.equals("stop") && !sender.isOp()) {
|
||||
event.setCancelled(true);
|
||||
sender.sendMessage("Vous n'avez pas la permission !");
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Exemples Pratiques
|
||||
|
||||
### Plugin de Métriques Serveur
|
||||
|
||||
```java
|
||||
public class MetricsPlugin extends JavaPlugin {
|
||||
|
||||
private long startTime;
|
||||
private long tickCount = 0;
|
||||
private long lastTickTime;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Suivre le démarrage du serveur
|
||||
getEventRegistry().register(BootEvent.class, event -> {
|
||||
startTime = System.currentTimeMillis();
|
||||
lastTickTime = startTime;
|
||||
getLogger().at(Level.INFO).log("Démarrage terminé, suivi des métriques...");
|
||||
});
|
||||
|
||||
// Calculer les TPS
|
||||
getEventRegistry().register(ServerTickEvent.class, event -> {
|
||||
tickCount++;
|
||||
|
||||
// Calculer les TPS toutes les secondes
|
||||
if (tickCount % 20 == 0) {
|
||||
long now = System.currentTimeMillis();
|
||||
long elapsed = now - lastTickTime;
|
||||
double tps = 20000.0 / elapsed;
|
||||
lastTickTime = now;
|
||||
|
||||
if (tps < 18.0) {
|
||||
getLogger().warning("TPS faibles : " + String.format("%.2f", tps));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Sauvegarder les métriques à l'arrêt
|
||||
getEventRegistry().register(ShutdownEvent.class, event -> {
|
||||
long uptime = System.currentTimeMillis() - startTime;
|
||||
saveMetrics(uptime, tickCount);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Gestionnaire de Dépendances de Plugins
|
||||
|
||||
```java
|
||||
public class DependencyPlugin extends JavaPlugin {
|
||||
|
||||
private final Map<String, JavaPlugin> loadedDependencies = new HashMap<>();
|
||||
private final Set<String> requiredPlugins = Set.of("Economy", "Permissions");
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Suivre le chargement des plugins
|
||||
getEventRegistry().register(PluginEnableEvent.class, event -> {
|
||||
JavaPlugin plugin = event.getPlugin();
|
||||
|
||||
if (requiredPlugins.contains(plugin.getName())) {
|
||||
loadedDependencies.put(plugin.getName(), plugin);
|
||||
getLogger().at(Level.INFO).log("Dépendance chargée : " + plugin.getName());
|
||||
|
||||
// Vérifier si toutes les dépendances sont chargées
|
||||
if (loadedDependencies.keySet().containsAll(requiredPlugins)) {
|
||||
initializeDependentFeatures();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Gérer le déchargement de dépendance
|
||||
getEventRegistry().register(PluginDisableEvent.class, event -> {
|
||||
JavaPlugin plugin = event.getPlugin();
|
||||
|
||||
if (loadedDependencies.remove(plugin.getName()) != null) {
|
||||
getLogger().warning("Dépendance déchargée : " + plugin.getName());
|
||||
disableDependentFeatures();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Journalisation & Limitation de Débit des Commandes
|
||||
|
||||
```java
|
||||
public class CommandSecurityPlugin extends JavaPlugin {
|
||||
|
||||
private final Map<UUID, List<Long>> commandHistory = new HashMap<>();
|
||||
private static final int MAX_COMMANDS_PER_SECOND = 5;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
getEventRegistry().register(CommandExecuteEvent.class, event -> {
|
||||
CommandSender sender = event.getSender();
|
||||
|
||||
// Ne limiter que les joueurs
|
||||
if (!(sender instanceof Player)) return;
|
||||
|
||||
Player player = (Player) sender;
|
||||
UUID uuid = player.getUuid();
|
||||
|
||||
// Obtenir l'historique des commandes
|
||||
List<Long> history = commandHistory.computeIfAbsent(
|
||||
uuid, k -> new ArrayList<>()
|
||||
);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
// Supprimer les anciennes entrées (plus d'1 seconde)
|
||||
history.removeIf(time -> now - time > 1000);
|
||||
|
||||
// Vérifier la limite de débit
|
||||
if (history.size() >= MAX_COMMANDS_PER_SECOND) {
|
||||
event.setCancelled(true);
|
||||
player.sendMessage("Trop de commandes ! Veuillez ralentir.");
|
||||
getLogger().warning("Limité : " + player.getDisplayName());
|
||||
return;
|
||||
}
|
||||
|
||||
// Enregistrer cette commande
|
||||
history.add(now);
|
||||
|
||||
// Logger dans un fichier
|
||||
logCommand(player, event.getCommand(), event.getArgs());
|
||||
});
|
||||
|
||||
// Nettoyer à la déconnexion
|
||||
getEventRegistry().register(PlayerDisconnectEvent.class, event -> {
|
||||
commandHistory.remove(event.getPlayer().getUuid());
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Gestionnaire de Tâches Planifiées
|
||||
|
||||
```java
|
||||
public class SchedulerPlugin extends JavaPlugin {
|
||||
|
||||
private final List<ScheduledTask> tasks = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Planifier diverses tâches
|
||||
scheduleTask("autosave", 6000, this::autoSave); // Toutes les 5 minutes
|
||||
scheduleTask("cleanup", 72000, this::cleanup); // Toutes les heures
|
||||
scheduleTask("broadcast", 12000, this::broadcast); // Toutes les 10 minutes
|
||||
|
||||
// Exécuter les tâches selon le tick
|
||||
getEventRegistry().register(ServerTickEvent.class, event -> {
|
||||
long tick = event.getTickNumber();
|
||||
|
||||
for (ScheduledTask task : tasks) {
|
||||
if (tick % task.interval() == 0) {
|
||||
try {
|
||||
task.runnable().run();
|
||||
} catch (Exception e) {
|
||||
getLogger().error("Tâche échouée : " + task.name(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void scheduleTask(String name, int intervalTicks, Runnable runnable) {
|
||||
tasks.add(new ScheduledTask(name, intervalTicks, runnable));
|
||||
}
|
||||
|
||||
record ScheduledTask(String name, int interval, Runnable runnable) {}
|
||||
}
|
||||
```
|
||||
|
||||
## Bonnes Pratiques
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Directives pour les Événements Serveur :**
|
||||
- Gardez les handlers de `ShutdownEvent` rapides et fiables
|
||||
- Utilisez le comptage de ticks dans `ServerTickEvent` pour les tâches périodiques
|
||||
- Nettoyez les ressources dans `PluginDisableEvent`
|
||||
- Initialisez les fonctionnalités inter-plugins dans `PluginEnableEvent`
|
||||
- Loggez les exécutions de commandes importantes pour l'audit
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="error" >}}
|
||||
**Critique :** Ne jamais effectuer d'opérations bloquantes (I/O, réseau, base de données) directement dans `ServerTickEvent`. Utilisez des tâches asynchrones à la place.
|
||||
{{< /callout >}}
|
||||
496
content/core-concepts/events/event-reference/world-events.en.md
Normal file
496
content/core-concepts/events/event-reference/world-events.en.md
Normal file
@@ -0,0 +1,496 @@
|
||||
---
|
||||
title: World Events
|
||||
type: docs
|
||||
weight: 5
|
||||
---
|
||||
|
||||
Events related to world management, chunks, and environmental changes.
|
||||
|
||||
## World Lifecycle Events
|
||||
|
||||
### AddWorldEvent
|
||||
|
||||
{{< badge "Cancellable" >}}
|
||||
|
||||
Fired when a world is being added to the server.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | The world being added |
|
||||
| universe | `Universe` | The parent universe |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Returns the world
|
||||
- `getUniverse()` - Returns the parent universe
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel world addition
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(AddWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
Universe universe = event.getUniverse();
|
||||
|
||||
getLogger().at(Level.INFO).log("World added: " + world.getName() + " to " + universe.getName());
|
||||
|
||||
// Prevent certain world types from loading
|
||||
if (world.getName().contains("test") && !isDevMode()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### RemoveWorldEvent
|
||||
|
||||
{{< badge "Cancellable" >}}
|
||||
|
||||
Fired when a world is being removed from the server.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | The world being removed |
|
||||
| reason | `RemovalReason` | Why the world is being removed |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Returns the world
|
||||
- `getReason()` - Returns removal reason
|
||||
- `isCancelled()` - Check if cancelled
|
||||
- `setCancelled(boolean)` - Cancel world removal
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(RemoveWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
|
||||
// Prevent removal of main world
|
||||
if (world.getName().equals("main")) {
|
||||
event.setCancelled(true);
|
||||
getLogger().warning("Cannot remove main world!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Save data before world is removed
|
||||
saveWorldData(world);
|
||||
notifyPlayersInWorld(world, "World is being unloaded!");
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### StartWorldEvent
|
||||
|
||||
Fired when a world starts (finishes initialization).
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | The world that started |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Returns the world
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(StartWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
|
||||
getLogger().at(Level.INFO).log("World started: " + world.getName());
|
||||
|
||||
// Initialize world-specific features
|
||||
initializeWorldBorders(world);
|
||||
spawnWorldBoss(world);
|
||||
startWeatherCycle(world);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### AllWorldsLoadedEvent
|
||||
|
||||
Fired when all worlds have finished loading on server startup.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| worlds | `List<World>` | All loaded worlds |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorlds()` - Returns list of all loaded worlds
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(AllWorldsLoadedEvent.class, event -> {
|
||||
List<World> worlds = event.getWorlds();
|
||||
|
||||
getLogger().at(Level.INFO).log("All " + worlds.size() + " worlds loaded!");
|
||||
|
||||
// Initialize cross-world features
|
||||
initializePortalNetwork(worlds);
|
||||
syncWorldTimes(worlds);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Chunk Events
|
||||
|
||||
### ChunkPreLoadProcessEvent
|
||||
|
||||
Fired before a chunk begins loading.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | The world |
|
||||
| chunkX | `int` | Chunk X coordinate |
|
||||
| chunkZ | `int` | Chunk Z coordinate |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Returns the world
|
||||
- `getChunkX()` - Returns chunk X coordinate
|
||||
- `getChunkZ()` - Returns chunk Z coordinate
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ChunkPreLoadProcessEvent.class, event -> {
|
||||
int x = event.getChunkX();
|
||||
int z = event.getChunkZ();
|
||||
|
||||
// Pre-load adjacent chunk data for seamless loading
|
||||
prepareAdjacentChunkData(event.getWorld(), x, z);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### ChunkLoadEvent
|
||||
|
||||
Fired when a chunk finishes loading.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | The world |
|
||||
| chunk | `Chunk` | The loaded chunk |
|
||||
| isNewChunk | `boolean` | Whether this is a newly generated chunk |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Returns the world
|
||||
- `getChunk()` - Returns the chunk
|
||||
- `isNewChunk()` - Returns true if newly generated
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ChunkLoadEvent.class, event -> {
|
||||
Chunk chunk = event.getChunk();
|
||||
World world = event.getWorld();
|
||||
|
||||
if (event.isNewChunk()) {
|
||||
// Add custom structures to new chunks
|
||||
generateCustomStructures(chunk);
|
||||
populateCustomOres(chunk);
|
||||
}
|
||||
|
||||
// Restore entities from storage
|
||||
loadChunkEntities(world, chunk);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### ChunkUnloadEvent
|
||||
|
||||
Fired when a chunk is about to be unloaded.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | The world |
|
||||
| chunk | `Chunk` | The chunk being unloaded |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Returns the world
|
||||
- `getChunk()` - Returns the chunk
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ChunkUnloadEvent.class, event -> {
|
||||
Chunk chunk = event.getChunk();
|
||||
World world = event.getWorld();
|
||||
|
||||
// Save custom chunk data
|
||||
saveChunkEntities(world, chunk);
|
||||
saveChunkMetadata(chunk);
|
||||
|
||||
// Clean up chunk-specific resources
|
||||
cleanupChunkParticles(chunk);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### ChunkSaveEvent
|
||||
|
||||
Fired when a chunk is being saved.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | The world |
|
||||
| chunk | `Chunk` | The chunk being saved |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Returns the world
|
||||
- `getChunk()` - Returns the chunk
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ChunkSaveEvent.class, event -> {
|
||||
Chunk chunk = event.getChunk();
|
||||
|
||||
// Save additional custom data alongside chunk
|
||||
saveCustomChunkData(chunk);
|
||||
|
||||
getLogger().debug("Chunk saved: " + chunk.getX() + ", " + chunk.getZ());
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Environmental Events
|
||||
|
||||
### MoonPhaseChangeEvent
|
||||
|
||||
Fired when the moon phase changes.
|
||||
|
||||
**Package:** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Fields,Methods,Example" >}}
|
||||
{{< tab >}}
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | The world |
|
||||
| previousPhase | `MoonPhase` | Previous moon phase |
|
||||
| newPhase | `MoonPhase` | New moon phase |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Returns the world
|
||||
- `getPreviousPhase()` - Returns previous phase
|
||||
- `getNewPhase()` - Returns new phase
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(MoonPhaseChangeEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
MoonPhase phase = event.getNewPhase();
|
||||
|
||||
getLogger().at(Level.INFO).log("Moon phase changed to: " + phase);
|
||||
|
||||
// Full moon special events
|
||||
if (phase == MoonPhase.FULL) {
|
||||
increaseHostileMobSpawns(world);
|
||||
enableWerewolfTransformations(world);
|
||||
}
|
||||
|
||||
// New moon darkness events
|
||||
if (phase == MoonPhase.NEW) {
|
||||
spawnDarkCreatures(world);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Practical Examples
|
||||
|
||||
### World Manager Plugin
|
||||
|
||||
```java
|
||||
public class WorldManagerPlugin extends JavaPlugin {
|
||||
|
||||
private final Map<String, WorldConfig> worldConfigs = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Track world additions
|
||||
getEventRegistry().register(AddWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
WorldConfig config = loadWorldConfig(world.getName());
|
||||
worldConfigs.put(world.getName(), config);
|
||||
|
||||
// Apply world-specific settings
|
||||
applyWorldConfig(world, config);
|
||||
});
|
||||
|
||||
// Handle world removal
|
||||
getEventRegistry().register(RemoveWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
WorldConfig config = worldConfigs.remove(world.getName());
|
||||
|
||||
if (config != null) {
|
||||
saveWorldConfig(world.getName(), config);
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize when all worlds ready
|
||||
getEventRegistry().register(AllWorldsLoadedEvent.class, event -> {
|
||||
getLogger().at(Level.INFO).log("Initializing world manager with " +
|
||||
event.getWorlds().size() + " worlds");
|
||||
initializeCrossWorldFeatures();
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Chunk Protection System
|
||||
|
||||
```java
|
||||
public class ChunkProtectionPlugin extends JavaPlugin {
|
||||
|
||||
private final Set<ChunkCoord> protectedChunks = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Load protected chunks when chunk loads
|
||||
getEventRegistry().register(ChunkLoadEvent.class, event -> {
|
||||
Chunk chunk = event.getChunk();
|
||||
ChunkCoord coord = new ChunkCoord(
|
||||
event.getWorld().getName(),
|
||||
chunk.getX(),
|
||||
chunk.getZ()
|
||||
);
|
||||
|
||||
if (isChunkProtected(coord)) {
|
||||
protectedChunks.add(coord);
|
||||
// Apply chunk-level protection
|
||||
markChunkAsProtected(chunk);
|
||||
}
|
||||
});
|
||||
|
||||
// Save protection status on unload
|
||||
getEventRegistry().register(ChunkUnloadEvent.class, event -> {
|
||||
Chunk chunk = event.getChunk();
|
||||
ChunkCoord coord = new ChunkCoord(
|
||||
event.getWorld().getName(),
|
||||
chunk.getX(),
|
||||
chunk.getZ()
|
||||
);
|
||||
|
||||
if (protectedChunks.contains(coord)) {
|
||||
saveProtectionStatus(coord);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void protectChunk(World world, int chunkX, int chunkZ) {
|
||||
ChunkCoord coord = new ChunkCoord(world.getName(), chunkX, chunkZ);
|
||||
protectedChunks.add(coord);
|
||||
saveProtectionStatus(coord);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Dynamic World Events
|
||||
|
||||
```java
|
||||
public class DynamicWorldPlugin extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Moon phase effects
|
||||
getEventRegistry().register(MoonPhaseChangeEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
MoonPhase phase = event.getNewPhase();
|
||||
|
||||
switch (phase) {
|
||||
case FULL:
|
||||
broadcastToWorld(world, "The full moon rises...");
|
||||
applyMoonEffect(world, "mob_spawn_increase", 2.0);
|
||||
break;
|
||||
case NEW:
|
||||
broadcastToWorld(world, "Darkness falls...");
|
||||
applyMoonEffect(world, "visibility_decrease", 0.5);
|
||||
break;
|
||||
default:
|
||||
clearMoonEffects(world);
|
||||
}
|
||||
});
|
||||
|
||||
// Custom chunk generation
|
||||
getEventRegistry().register(ChunkLoadEvent.class, event -> {
|
||||
if (event.isNewChunk()) {
|
||||
Chunk chunk = event.getChunk();
|
||||
|
||||
// Add mystery locations
|
||||
if (random.nextFloat() < 0.01) { // 1% chance
|
||||
generateMysteryStructure(chunk);
|
||||
}
|
||||
|
||||
// Add resource nodes
|
||||
populateResourceNodes(chunk, event.getWorld());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**World Event Guidelines:**
|
||||
- Use `AllWorldsLoadedEvent` for cross-world initialization
|
||||
- Save important data in `ChunkUnloadEvent` and `RemoveWorldEvent`
|
||||
- Use `isNewChunk()` to avoid regenerating content in existing chunks
|
||||
- Be careful with cancelling `AddWorldEvent` and `RemoveWorldEvent`
|
||||
- Consider memory usage when storing per-chunk data
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Performance Note:** Chunk events can fire frequently during player movement. Keep handlers lightweight and avoid blocking operations.
|
||||
{{< /callout >}}
|
||||
496
content/core-concepts/events/event-reference/world-events.fr.md
Normal file
496
content/core-concepts/events/event-reference/world-events.fr.md
Normal file
@@ -0,0 +1,496 @@
|
||||
---
|
||||
title: Événements Monde
|
||||
type: docs
|
||||
weight: 5
|
||||
---
|
||||
|
||||
Événements liés à la gestion des mondes, chunks et changements environnementaux.
|
||||
|
||||
## Événements du Cycle de Vie des Mondes
|
||||
|
||||
### AddWorldEvent
|
||||
|
||||
{{< badge "Annulable" >}}
|
||||
|
||||
Déclenché quand un monde est en train d'être ajouté au serveur.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | Le monde ajouté |
|
||||
| universe | `Universe` | L'univers parent |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Retourne le monde
|
||||
- `getUniverse()` - Retourne l'univers parent
|
||||
- `isCancelled()` - Vérifie si annulé
|
||||
- `setCancelled(boolean)` - Annule l'ajout du monde
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(AddWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
Universe universe = event.getUniverse();
|
||||
|
||||
getLogger().at(Level.INFO).log("Monde ajouté : " + world.getName() + " à " + universe.getName());
|
||||
|
||||
// Empêcher certains types de mondes de se charger
|
||||
if (world.getName().contains("test") && !isDevMode()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### RemoveWorldEvent
|
||||
|
||||
{{< badge "Annulable" >}}
|
||||
|
||||
Déclenché quand un monde est en train d'être retiré du serveur.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | Le monde retiré |
|
||||
| reason | `RemovalReason` | Raison du retrait |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Retourne le monde
|
||||
- `getReason()` - Retourne la raison du retrait
|
||||
- `isCancelled()` - Vérifie si annulé
|
||||
- `setCancelled(boolean)` - Annule le retrait du monde
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(RemoveWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
|
||||
// Empêcher le retrait du monde principal
|
||||
if (world.getName().equals("main")) {
|
||||
event.setCancelled(true);
|
||||
getLogger().warning("Impossible de retirer le monde principal !");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sauvegarder les données avant que le monde soit retiré
|
||||
saveWorldData(world);
|
||||
notifyPlayersInWorld(world, "Le monde est en cours de déchargement !");
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### StartWorldEvent
|
||||
|
||||
Déclenché quand un monde démarre (termine son initialisation).
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | Le monde qui a démarré |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Retourne le monde
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(StartWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
|
||||
getLogger().at(Level.INFO).log("Monde démarré : " + world.getName());
|
||||
|
||||
// Initialiser les fonctionnalités spécifiques au monde
|
||||
initializeWorldBorders(world);
|
||||
spawnWorldBoss(world);
|
||||
startWeatherCycle(world);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### AllWorldsLoadedEvent
|
||||
|
||||
Déclenché quand tous les mondes ont fini de charger au démarrage du serveur.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| worlds | `List<World>` | Tous les mondes chargés |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorlds()` - Retourne la liste de tous les mondes chargés
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(AllWorldsLoadedEvent.class, event -> {
|
||||
List<World> worlds = event.getWorlds();
|
||||
|
||||
getLogger().at(Level.INFO).log("Tous les " + worlds.size() + " mondes chargés !");
|
||||
|
||||
// Initialiser les fonctionnalités inter-mondes
|
||||
initializePortalNetwork(worlds);
|
||||
syncWorldTimes(worlds);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Événements de Chunk
|
||||
|
||||
### ChunkPreLoadProcessEvent
|
||||
|
||||
Déclenché avant qu'un chunk commence à charger.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | Le monde |
|
||||
| chunkX | `int` | Coordonnée X du chunk |
|
||||
| chunkZ | `int` | Coordonnée Z du chunk |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Retourne le monde
|
||||
- `getChunkX()` - Retourne la coordonnée X du chunk
|
||||
- `getChunkZ()` - Retourne la coordonnée Z du chunk
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ChunkPreLoadProcessEvent.class, event -> {
|
||||
int x = event.getChunkX();
|
||||
int z = event.getChunkZ();
|
||||
|
||||
// Pré-charger les données des chunks adjacents pour un chargement fluide
|
||||
prepareAdjacentChunkData(event.getWorld(), x, z);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### ChunkLoadEvent
|
||||
|
||||
Déclenché quand un chunk finit de charger.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | Le monde |
|
||||
| chunk | `Chunk` | Le chunk chargé |
|
||||
| isNewChunk | `boolean` | Si c'est un chunk nouvellement généré |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Retourne le monde
|
||||
- `getChunk()` - Retourne le chunk
|
||||
- `isNewChunk()` - Retourne vrai si nouvellement généré
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ChunkLoadEvent.class, event -> {
|
||||
Chunk chunk = event.getChunk();
|
||||
World world = event.getWorld();
|
||||
|
||||
if (event.isNewChunk()) {
|
||||
// Ajouter des structures personnalisées aux nouveaux chunks
|
||||
generateCustomStructures(chunk);
|
||||
populateCustomOres(chunk);
|
||||
}
|
||||
|
||||
// Restaurer les entités depuis le stockage
|
||||
loadChunkEntities(world, chunk);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### ChunkUnloadEvent
|
||||
|
||||
Déclenché quand un chunk est sur le point d'être déchargé.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | Le monde |
|
||||
| chunk | `Chunk` | Le chunk déchargé |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Retourne le monde
|
||||
- `getChunk()` - Retourne le chunk
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ChunkUnloadEvent.class, event -> {
|
||||
Chunk chunk = event.getChunk();
|
||||
World world = event.getWorld();
|
||||
|
||||
// Sauvegarder les données personnalisées du chunk
|
||||
saveChunkEntities(world, chunk);
|
||||
saveChunkMetadata(chunk);
|
||||
|
||||
// Nettoyer les ressources spécifiques au chunk
|
||||
cleanupChunkParticles(chunk);
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
### ChunkSaveEvent
|
||||
|
||||
Déclenché quand un chunk est en cours de sauvegarde.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | Le monde |
|
||||
| chunk | `Chunk` | Le chunk sauvegardé |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Retourne le monde
|
||||
- `getChunk()` - Retourne le chunk
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(ChunkSaveEvent.class, event -> {
|
||||
Chunk chunk = event.getChunk();
|
||||
|
||||
// Sauvegarder des données personnalisées supplémentaires avec le chunk
|
||||
saveCustomChunkData(chunk);
|
||||
|
||||
getLogger().debug("Chunk sauvegardé : " + chunk.getX() + ", " + chunk.getZ());
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Événements Environnementaux
|
||||
|
||||
### MoonPhaseChangeEvent
|
||||
|
||||
Déclenché quand la phase lunaire change.
|
||||
|
||||
**Package :** `com.hypixel.hytale.server.core.event.events.world`
|
||||
|
||||
{{< tabs items="Champs,Méthodes,Exemple" >}}
|
||||
{{< tab >}}
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| world | `World` | Le monde |
|
||||
| previousPhase | `MoonPhase` | Phase lunaire précédente |
|
||||
| newPhase | `MoonPhase` | Nouvelle phase lunaire |
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
- `getWorld()` - Retourne le monde
|
||||
- `getPreviousPhase()` - Retourne la phase précédente
|
||||
- `getNewPhase()` - Retourne la nouvelle phase
|
||||
{{< /tab >}}
|
||||
{{< tab >}}
|
||||
```java
|
||||
getEventRegistry().register(MoonPhaseChangeEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
MoonPhase phase = event.getNewPhase();
|
||||
|
||||
getLogger().at(Level.INFO).log("Phase lunaire changée en : " + phase);
|
||||
|
||||
// Événements spéciaux pleine lune
|
||||
if (phase == MoonPhase.FULL) {
|
||||
increaseHostileMobSpawns(world);
|
||||
enableWerewolfTransformations(world);
|
||||
}
|
||||
|
||||
// Événements de ténèbres nouvelle lune
|
||||
if (phase == MoonPhase.NEW) {
|
||||
spawnDarkCreatures(world);
|
||||
}
|
||||
});
|
||||
```
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
---
|
||||
|
||||
## Exemples Pratiques
|
||||
|
||||
### Plugin Gestionnaire de Mondes
|
||||
|
||||
```java
|
||||
public class WorldManagerPlugin extends JavaPlugin {
|
||||
|
||||
private final Map<String, WorldConfig> worldConfigs = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Suivre les ajouts de mondes
|
||||
getEventRegistry().register(AddWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
WorldConfig config = loadWorldConfig(world.getName());
|
||||
worldConfigs.put(world.getName(), config);
|
||||
|
||||
// Appliquer les paramètres spécifiques au monde
|
||||
applyWorldConfig(world, config);
|
||||
});
|
||||
|
||||
// Gérer le retrait de monde
|
||||
getEventRegistry().register(RemoveWorldEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
WorldConfig config = worldConfigs.remove(world.getName());
|
||||
|
||||
if (config != null) {
|
||||
saveWorldConfig(world.getName(), config);
|
||||
}
|
||||
});
|
||||
|
||||
// Initialiser quand tous les mondes sont prêts
|
||||
getEventRegistry().register(AllWorldsLoadedEvent.class, event -> {
|
||||
getLogger().at(Level.INFO).log("Initialisation du gestionnaire de mondes avec " +
|
||||
event.getWorlds().size() + " mondes");
|
||||
initializeCrossWorldFeatures();
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Système de Protection de Chunks
|
||||
|
||||
```java
|
||||
public class ChunkProtectionPlugin extends JavaPlugin {
|
||||
|
||||
private final Set<ChunkCoord> protectedChunks = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Charger les chunks protégés quand le chunk charge
|
||||
getEventRegistry().register(ChunkLoadEvent.class, event -> {
|
||||
Chunk chunk = event.getChunk();
|
||||
ChunkCoord coord = new ChunkCoord(
|
||||
event.getWorld().getName(),
|
||||
chunk.getX(),
|
||||
chunk.getZ()
|
||||
);
|
||||
|
||||
if (isChunkProtected(coord)) {
|
||||
protectedChunks.add(coord);
|
||||
// Appliquer la protection au niveau du chunk
|
||||
markChunkAsProtected(chunk);
|
||||
}
|
||||
});
|
||||
|
||||
// Sauvegarder le statut de protection au déchargement
|
||||
getEventRegistry().register(ChunkUnloadEvent.class, event -> {
|
||||
Chunk chunk = event.getChunk();
|
||||
ChunkCoord coord = new ChunkCoord(
|
||||
event.getWorld().getName(),
|
||||
chunk.getX(),
|
||||
chunk.getZ()
|
||||
);
|
||||
|
||||
if (protectedChunks.contains(coord)) {
|
||||
saveProtectionStatus(coord);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void protectChunk(World world, int chunkX, int chunkZ) {
|
||||
ChunkCoord coord = new ChunkCoord(world.getName(), chunkX, chunkZ);
|
||||
protectedChunks.add(coord);
|
||||
saveProtectionStatus(coord);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Événements de Monde Dynamiques
|
||||
|
||||
```java
|
||||
public class DynamicWorldPlugin extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Effets de phase lunaire
|
||||
getEventRegistry().register(MoonPhaseChangeEvent.class, event -> {
|
||||
World world = event.getWorld();
|
||||
MoonPhase phase = event.getNewPhase();
|
||||
|
||||
switch (phase) {
|
||||
case FULL:
|
||||
broadcastToWorld(world, "La pleine lune se lève...");
|
||||
applyMoonEffect(world, "mob_spawn_increase", 2.0);
|
||||
break;
|
||||
case NEW:
|
||||
broadcastToWorld(world, "Les ténèbres tombent...");
|
||||
applyMoonEffect(world, "visibility_decrease", 0.5);
|
||||
break;
|
||||
default:
|
||||
clearMoonEffects(world);
|
||||
}
|
||||
});
|
||||
|
||||
// Génération de chunk personnalisée
|
||||
getEventRegistry().register(ChunkLoadEvent.class, event -> {
|
||||
if (event.isNewChunk()) {
|
||||
Chunk chunk = event.getChunk();
|
||||
|
||||
// Ajouter des emplacements mystères
|
||||
if (random.nextFloat() < 0.01) { // 1% de chance
|
||||
generateMysteryStructure(chunk);
|
||||
}
|
||||
|
||||
// Ajouter des nœuds de ressources
|
||||
populateResourceNodes(chunk, event.getWorld());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Bonnes Pratiques
|
||||
|
||||
{{< callout type="info" >}}
|
||||
**Directives pour les Événements de Monde :**
|
||||
- Utiliser `AllWorldsLoadedEvent` pour l'initialisation inter-mondes
|
||||
- Sauvegarder les données importantes dans `ChunkUnloadEvent` et `RemoveWorldEvent`
|
||||
- Utiliser `isNewChunk()` pour éviter de régénérer du contenu dans les chunks existants
|
||||
- Être prudent en annulant `AddWorldEvent` et `RemoveWorldEvent`
|
||||
- Considérer l'utilisation mémoire lors du stockage de données par chunk
|
||||
{{< /callout >}}
|
||||
|
||||
{{< callout type="warning" >}}
|
||||
**Note de Performance :** Les événements de chunk peuvent se déclencher fréquemment pendant le mouvement des joueurs. Gardez les handlers légers et évitez les opérations bloquantes.
|
||||
{{< /callout >}}
|
||||
Reference in New Issue
Block a user