330 lines
10 KiB
Markdown
330 lines
10 KiB
Markdown
---
|
|
title: Blocs
|
|
type: docs
|
|
weight: 3
|
|
---
|
|
|
|
La manipulation des blocs est une partie centrale de la modification du monde dans les plugins Hytale. La classe `World` fournit l'accès aux blocs via l'interface `IChunkAccessorSync`, tandis que `WorldChunk` implémente l'interface complète `BlockAccessor` pour le placement avec rotation.
|
|
|
|
{{< callout type="warning" >}}
|
|
**Important :** `World` n'implémente PAS `BlockAccessor` directement. Pour `placeBlock()` avec rotation, vous devez d'abord obtenir le chunk avec `world.getChunk()`.
|
|
{{< /callout >}}
|
|
|
|
## Obtenir des Blocs
|
|
|
|
```java
|
|
import com.hypixel.hytale.server.core.universe.Universe;
|
|
import com.hypixel.hytale.server.core.universe.world.World;
|
|
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
|
|
import com.hypixel.hytale.math.vector.Vector3i;
|
|
|
|
World world = Universe.get().getWorld("default");
|
|
|
|
// Obtenir l'ID du bloc (index int) à une position
|
|
int blockId = world.getBlock(x, y, z);
|
|
int blockId = world.getBlock(new Vector3i(x, y, z));
|
|
|
|
// Obtenir le BlockType à une position
|
|
BlockType blockType = world.getBlockType(x, y, z);
|
|
BlockType blockType = world.getBlockType(new Vector3i(x, y, z));
|
|
|
|
// Vérifier si le bloc est vide
|
|
if (blockType == BlockType.EMPTY) {
|
|
// Air ou espace vide
|
|
}
|
|
```
|
|
|
|
## Définir des Blocs
|
|
|
|
La méthode `setBlock` prend une **clé de type bloc String**, pas un objet BlockType ou un int ID :
|
|
|
|
```java
|
|
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
|
|
|
|
World world = player.getWorld();
|
|
|
|
// Définir un bloc par clé de type (ID string)
|
|
world.setBlock(x, y, z, "stone");
|
|
world.setBlock(x, y, z, "oak_planks", 0); // avec settings
|
|
|
|
// Utiliser BlockType - obtenir d'abord la chaîne ID
|
|
BlockType stone = BlockType.getAssetMap().getAsset("stone");
|
|
if (stone != null) {
|
|
world.setBlock(x, y, z, stone.getId()); // Utiliser getId() pour obtenir la clé string
|
|
}
|
|
|
|
// Index d'ID de bloc (pour usage interne)
|
|
int stoneIndex = BlockType.getAssetMap().getIndex("stone");
|
|
// Note : setBlock prend String, pas int - utilisez la clé directement
|
|
```
|
|
|
|
## Placement de Blocs avec Rotation
|
|
|
|
{{< callout type="info" >}}
|
|
**placeBlock() est sur WorldChunk, pas World !** Vous devez d'abord obtenir le chunk pour placer des blocs avec rotation.
|
|
{{< /callout >}}
|
|
|
|
```java
|
|
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
|
|
import com.hypixel.hytale.server.core.asset.type.blocktype.config.Rotation;
|
|
import com.hypixel.hytale.server.core.asset.type.blocktype.config.RotationTuple;
|
|
import com.hypixel.hytale.math.util.ChunkUtil;
|
|
|
|
// Obtenir le chunk contenant cette position de bloc
|
|
WorldChunk chunk = world.getChunk(ChunkUtil.indexChunkFromBlock(x, z));
|
|
|
|
if (chunk != null) {
|
|
// Placer un bloc avec rotation
|
|
// Valeurs de Rotation : None, Ninety, OneEighty, TwoSeventy
|
|
chunk.placeBlock(x, y, z, "oak_log",
|
|
Rotation.Ninety, // yaw (90 degrés)
|
|
Rotation.None, // pitch
|
|
Rotation.None // roll
|
|
);
|
|
|
|
// Placer avec tuple de rotation et options
|
|
chunk.placeBlock(x, y, z, "oak_log",
|
|
RotationTuple.of(Rotation.Ninety, Rotation.None, Rotation.None),
|
|
0, // settings
|
|
true // validatePlacement
|
|
);
|
|
}
|
|
```
|
|
|
|
### Valeurs de Rotation
|
|
|
|
L'enum `Rotation` a ces valeurs (PAS les directions cardinales) :
|
|
|
|
| Rotation | Degrés |
|
|
|----------|--------|
|
|
| `Rotation.None` | 0° |
|
|
| `Rotation.Ninety` | 90° |
|
|
| `Rotation.OneEighty` | 180° |
|
|
| `Rotation.TwoSeventy` | 270° |
|
|
|
|
## Casser des Blocs
|
|
|
|
```java
|
|
// Casser un bloc à une position (nécessite le paramètre settings)
|
|
world.breakBlock(x, y, z, 0); // 0 = settings par défaut
|
|
```
|
|
|
|
## Assets BlockType
|
|
|
|
Les assets BlockType définissent les propriétés des blocs :
|
|
|
|
```java
|
|
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
|
|
import com.hypixel.hytale.protocol.BlockMaterial;
|
|
|
|
// Obtenir le type de bloc par ID
|
|
BlockType blockType = BlockType.getAssetMap().getAsset("stone");
|
|
|
|
if (blockType != null) {
|
|
// Obtenir la chaîne ID du bloc
|
|
String blockId = blockType.getId();
|
|
|
|
// Obtenir le matériau
|
|
BlockMaterial material = blockType.getMaterial();
|
|
}
|
|
|
|
// Obtenir l'index d'ID du bloc (pour usage interne)
|
|
int blockIndex = BlockType.getAssetMap().getIndex("stone");
|
|
|
|
// Obtenir le bloc depuis l'index
|
|
BlockType fromIndex = BlockType.getAssetMap().getAsset(blockIndex);
|
|
```
|
|
|
|
## Événements de Blocs
|
|
|
|
### BreakBlockEvent
|
|
|
|
Déclenché quand un bloc est cassé :
|
|
|
|
```java
|
|
import com.hypixel.hytale.server.core.event.events.ecs.BreakBlockEvent;
|
|
import com.hypixel.hytale.math.vector.Vector3i;
|
|
import java.util.logging.Level;
|
|
|
|
getEventRegistry().register(BreakBlockEvent.class, event -> {
|
|
// Obtenir les infos de destruction
|
|
Vector3i position = event.getTargetBlock();
|
|
BlockType blockType = event.getBlockType();
|
|
|
|
getLogger().at(Level.INFO).log("Bloc cassé à " + position);
|
|
|
|
// Annuler si protégé
|
|
event.setCancelled(true);
|
|
});
|
|
```
|
|
|
|
### PlaceBlockEvent
|
|
|
|
Déclenché quand un bloc est placé :
|
|
|
|
```java
|
|
import com.hypixel.hytale.server.core.event.events.ecs.PlaceBlockEvent;
|
|
import com.hypixel.hytale.server.core.asset.type.blocktype.config.RotationTuple;
|
|
|
|
getEventRegistry().register(PlaceBlockEvent.class, event -> {
|
|
// Obtenir les infos de placement
|
|
Vector3i position = event.getTargetBlock();
|
|
RotationTuple rotation = event.getRotation();
|
|
|
|
getLogger().at(Level.INFO).log("Bloc placé à " + position);
|
|
|
|
// Annuler si non autorisé
|
|
event.setCancelled(true);
|
|
});
|
|
```
|
|
|
|
### DamageBlockEvent
|
|
|
|
Déclenché quand un bloc est endommagé (avant d'être cassé) :
|
|
|
|
```java
|
|
import com.hypixel.hytale.server.core.event.events.ecs.DamageBlockEvent;
|
|
|
|
getEventRegistry().register(DamageBlockEvent.class, event -> {
|
|
Vector3i position = event.getTargetBlock();
|
|
BlockType blockType = event.getBlockType();
|
|
|
|
// Annuler pour empêcher les dégâts
|
|
event.setCancelled(true);
|
|
});
|
|
```
|
|
|
|
## État d'Interaction de Bloc
|
|
|
|
Les blocs peuvent avoir des états d'interaction (comme portes ouvertes/fermées) :
|
|
|
|
```java
|
|
BlockType currentBlock = world.getBlockType(x, y, z);
|
|
|
|
if (currentBlock != null) {
|
|
// Définir le bloc à un état différent
|
|
world.setBlockInteractionState(
|
|
new Vector3i(x, y, z),
|
|
currentBlock,
|
|
"open" // nom de l'état
|
|
);
|
|
}
|
|
```
|
|
|
|
## Travailler avec les Blocs
|
|
|
|
### Vérifier une Zone pour un Type de Bloc
|
|
|
|
```java
|
|
public boolean containsBlockType(World world, Vector3i min, Vector3i max, String blockTypeKey) {
|
|
// Note : Vector3i utilise getX(), getY(), getZ() - PAS x(), y(), z()
|
|
for (int x = min.getX(); x <= max.getX(); x++) {
|
|
for (int y = min.getY(); y <= max.getY(); y++) {
|
|
for (int z = min.getZ(); z <= max.getZ(); z++) {
|
|
BlockType block = world.getBlockType(x, y, z);
|
|
if (block != null && block.getId().equals(blockTypeKey)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
```
|
|
|
|
### Remplir une Zone
|
|
|
|
```java
|
|
public void fillArea(World world, Vector3i min, Vector3i max, String blockTypeKey) {
|
|
for (int x = min.getX(); x <= max.getX(); x++) {
|
|
for (int y = min.getY(); y <= max.getY(); y++) {
|
|
for (int z = min.getZ(); z <= max.getZ(); z++) {
|
|
world.setBlock(x, y, z, blockTypeKey);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Remplacer des Blocs
|
|
|
|
```java
|
|
public void replaceBlocks(World world, Vector3i min, Vector3i max,
|
|
String fromBlock, String toBlock) {
|
|
for (int x = min.getX(); x <= max.getX(); x++) {
|
|
for (int y = min.getY(); y <= max.getY(); y++) {
|
|
for (int z = min.getZ(); z <= max.getZ(); z++) {
|
|
BlockType current = world.getBlockType(x, y, z);
|
|
if (current != null && current.getId().equals(fromBlock)) {
|
|
world.setBlock(x, y, z, toBlock);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Positions de Blocs
|
|
|
|
```java
|
|
import com.hypixel.hytale.math.vector.Vector3i;
|
|
|
|
// Vector3i pour les positions de blocs entières
|
|
Vector3i blockPos = new Vector3i(100, 64, 200);
|
|
|
|
// Obtenir les coordonnées individuelles - utiliser getX(), getY(), getZ()
|
|
int x = blockPos.getX();
|
|
int y = blockPos.getY();
|
|
int z = blockPos.getZ();
|
|
|
|
// Positions adjacentes
|
|
Vector3i above = new Vector3i(x, y + 1, z);
|
|
Vector3i below = new Vector3i(x, y - 1, z);
|
|
Vector3i north = new Vector3i(x, y, z - 1);
|
|
Vector3i south = new Vector3i(x, y, z + 1);
|
|
Vector3i east = new Vector3i(x + 1, y, z);
|
|
Vector3i west = new Vector3i(x - 1, y, z);
|
|
```
|
|
|
|
## Bonnes Pratiques
|
|
|
|
{{< callout type="info" >}}
|
|
**Conseils pour la Manipulation de Blocs :**
|
|
- Les opérations sur les blocs doivent s'exécuter sur le thread de tick du monde
|
|
- Utilisez `getBlockType()` pour vérifier les types, `getBlock()` pour les IDs bruts
|
|
- Vérifiez `BlockType.EMPTY` pour les blocs air/vides
|
|
- Les événements étendent `CancellableEcsEvent` - utilisez `setCancelled(true)` pour empêcher
|
|
- Considérez les limites de chunks lors du traitement de grandes zones
|
|
- Pour `placeBlock()` avec rotation, obtenez d'abord le chunk
|
|
{{< /callout >}}
|
|
|
|
```java
|
|
// Modification sécurisée de bloc depuis un contexte asynchrone
|
|
world.execute(() -> {
|
|
world.setBlock(x, y, z, "stone");
|
|
});
|
|
```
|
|
|
|
## Référence API
|
|
|
|
### Méthodes World (IChunkAccessorSync)
|
|
|
|
| Méthode | Retour | Description |
|
|
|--------|--------|-------------|
|
|
| `getBlock(int, int, int)` | `int` | Obtenir l'ID du bloc à la position |
|
|
| `getBlock(Vector3i)` | `int` | Obtenir l'ID du bloc à la position |
|
|
| `getBlockType(int, int, int)` | `BlockType?` | Obtenir le BlockType à la position |
|
|
| `getBlockType(Vector3i)` | `BlockType?` | Obtenir le BlockType à la position |
|
|
| `setBlock(x, y, z, String)` | `void` | Définir bloc par clé de type |
|
|
| `setBlock(x, y, z, String, int)` | `void` | Définir bloc avec settings |
|
|
| `breakBlock(x, y, z, int)` | `boolean` | Casser bloc avec settings |
|
|
| `setBlockInteractionState(...)` | `void` | Définir état du bloc |
|
|
|
|
### Méthodes WorldChunk (BlockAccessor)
|
|
|
|
| Méthode | Retour | Description |
|
|
|--------|--------|-------------|
|
|
| `placeBlock(x, y, z, String, Rotation, Rotation, Rotation)` | `boolean` | Placer avec rotation |
|
|
| `placeBlock(x, y, z, String, RotationTuple, int, boolean)` | `boolean` | Placer avec options |
|
|
| `testPlaceBlock(...)` | `boolean` | Tester si placement valide |
|