267 lines
7.0 KiB
Markdown
267 lines
7.0 KiB
Markdown
---
|
|
title: Faire Apparaître des Entités
|
|
type: docs
|
|
weight: 3
|
|
---
|
|
|
|
Créez et faites apparaître des entités dans le monde en enregistrant des classes d'entités et en utilisant l'API World.
|
|
|
|
## Enregistrer des Entités
|
|
|
|
Avant de faire apparaître des entités, enregistrez-les avec l'EntityRegistry dans la méthode `start()` de votre plugin :
|
|
|
|
```java
|
|
@Override
|
|
public void start() {
|
|
// Enregistrer l'entité avec clé, classe, constructeur et codec
|
|
getEntityRegistry().registerEntity(
|
|
"my_custom_entity",
|
|
CustomEntity.class,
|
|
world -> new CustomEntity(world),
|
|
CustomEntity.CODEC
|
|
);
|
|
}
|
|
```
|
|
|
|
### Paramètres d'Enregistrement
|
|
|
|
| Paramètre | Type | Description |
|
|
|-----------|------|-------------|
|
|
| key | `String` | Identifiant unique pour le type d'entité |
|
|
| clazz | `Class<T>` | La classe de l'entité |
|
|
| constructor | `Function<World, T>` | Fonction factory qui crée les instances |
|
|
| codec | `DirectDecodeCodec<T>` | Codec de sérialisation pour la persistance |
|
|
|
|
## Classes de Base d'Entité
|
|
|
|
Hytale fournit deux classes de base principales :
|
|
|
|
### Entity
|
|
|
|
Classe de base pour toutes les entités. Implémente `Component<EntityStore>`.
|
|
|
|
```java
|
|
public class SimpleEntity extends Entity {
|
|
public static final DirectDecodeCodec<SimpleEntity> CODEC =
|
|
Entity.CODEC.extend(SimpleEntity.class, SimpleEntity::new);
|
|
|
|
public SimpleEntity() {
|
|
super();
|
|
}
|
|
|
|
public SimpleEntity(World world) {
|
|
super(world);
|
|
}
|
|
}
|
|
```
|
|
|
|
### LivingEntity
|
|
|
|
Classe de base étendue pour les entités avec santé, inventaire et statistiques.
|
|
|
|
```java
|
|
public class CustomMob extends LivingEntity {
|
|
public static final DirectDecodeCodec<CustomMob> CODEC =
|
|
LivingEntity.CODEC.extend(CustomMob.class, CustomMob::new);
|
|
|
|
public CustomMob() {
|
|
super();
|
|
}
|
|
|
|
public CustomMob(World world) {
|
|
super(world);
|
|
}
|
|
|
|
@Override
|
|
protected Inventory createDefaultInventory() {
|
|
return new Inventory(36); // 36 emplacements
|
|
}
|
|
}
|
|
```
|
|
|
|
## Faire Apparaître des Entités
|
|
|
|
Utilisez l'API World pour faire apparaître des entités enregistrées :
|
|
|
|
```java
|
|
// Obtenir le monde
|
|
World world = player.getWorld();
|
|
|
|
// Créer l'instance de l'entité
|
|
CustomMob mob = new CustomMob(world);
|
|
|
|
// Définir la position et rotation de spawn
|
|
Vector3d position = new Vector3d(100, 64, 200);
|
|
Vector3f rotation = new Vector3f(0, 90, 0); // Face à l'est
|
|
|
|
// Faire apparaître l'entité (déprécié mais fonctionnel)
|
|
world.spawnEntity(mob, position, rotation);
|
|
```
|
|
|
|
### Méthode addEntity
|
|
|
|
Pour plus de contrôle sur les raisons de spawn, utilisez `addEntity` :
|
|
|
|
```java
|
|
// Options AddReason : SPAWN, LOAD, TRANSFER
|
|
world.addEntity(mob, position, rotation, AddReason.SPAWN);
|
|
```
|
|
|
|
{{< callout type="warning" >}}
|
|
**Avis de Dépréciation :** Les méthodes `spawnEntity` et `addEntity` sur World sont dépréciées. L'approche moderne utilise directement le système EntityStore basé sur les composants. Cependant, ces méthodes fonctionnent toujours et sont le moyen le plus simple de faire apparaître des entités.
|
|
{{< /callout >}}
|
|
|
|
## Cycle de Vie des Entités
|
|
|
|
### Chargement dans le Monde
|
|
|
|
Quand une entité est ajoutée à un monde :
|
|
|
|
```java
|
|
// Appelé automatiquement quand l'entité est ajoutée
|
|
entity.loadIntoWorld(world);
|
|
|
|
// L'entité reçoit un ID réseau
|
|
int networkId = entity.getNetworkId();
|
|
|
|
// Une référence est créée pour l'accès aux composants
|
|
Ref<EntityStore> ref = entity.getReference();
|
|
```
|
|
|
|
### Supprimer des Entités
|
|
|
|
```java
|
|
// Supprimer une entité du monde
|
|
boolean removed = entity.remove();
|
|
|
|
// Vérifier si l'entité a déjà été supprimée
|
|
if (entity.wasRemoved()) {
|
|
// L'entité n'est plus valide
|
|
}
|
|
```
|
|
|
|
## Événements d'Entité
|
|
|
|
### EntityRemoveEvent
|
|
|
|
Écouter la suppression d'entités :
|
|
|
|
```java
|
|
getEventRegistry().register(EntityRemoveEvent.class, event -> {
|
|
Entity entity = event.getEntity();
|
|
getLogger().at(Level.INFO).log("Entité supprimée: " + entity.getClass().getSimpleName());
|
|
});
|
|
```
|
|
|
|
### LivingEntityInventoryChangeEvent
|
|
|
|
Suivre les changements d'inventaire sur les entités vivantes :
|
|
|
|
```java
|
|
getEventRegistry().register(LivingEntityInventoryChangeEvent.class, event -> {
|
|
LivingEntity entity = event.getEntity();
|
|
// Gérer le changement d'inventaire
|
|
});
|
|
```
|
|
|
|
{{< callout type="info" >}}
|
|
**Pas d'Événement de Spawn :** Hytale n'a pas d'EntitySpawnEvent. Pour suivre les spawns, envisagez d'implémenter une logique personnalisée dans le constructeur de votre entité ou d'utiliser les callbacks d'ajout du système de composants.
|
|
{{< /callout >}}
|
|
|
|
## Exemple Complet
|
|
|
|
```java
|
|
public class MyPlugin extends JavaPlugin {
|
|
|
|
@Override
|
|
public void start() {
|
|
// Enregistrer l'entité personnalisée
|
|
getEntityRegistry().registerEntity(
|
|
"boss_monster",
|
|
BossMonster.class,
|
|
world -> new BossMonster(world),
|
|
BossMonster.CODEC
|
|
);
|
|
|
|
// Écouter les suppressions
|
|
getEventRegistry().register(EntityRemoveEvent.class, this::onEntityRemove);
|
|
}
|
|
|
|
private void onEntityRemove(EntityRemoveEvent event) {
|
|
if (event.getEntity() instanceof BossMonster) {
|
|
getLogger().at(Level.INFO).log("Le boss a été vaincu !");
|
|
}
|
|
}
|
|
|
|
public void spawnBoss(Player player) {
|
|
World world = player.getWorld();
|
|
|
|
// Créer le boss à la position du joueur
|
|
BossMonster boss = new BossMonster(world);
|
|
|
|
// Obtenir la position du joueur et ajouter un décalage
|
|
Vector3d spawnPos = player.getTransformComponent().getPosition();
|
|
spawnPos = new Vector3d(spawnPos.x + 5, spawnPos.y, spawnPos.z);
|
|
|
|
// Faire face au joueur
|
|
Vector3f rotation = new Vector3f(0, 180, 0);
|
|
|
|
// Spawner
|
|
world.spawnEntity(boss, spawnPos, rotation);
|
|
}
|
|
}
|
|
|
|
public class BossMonster extends LivingEntity {
|
|
public static final DirectDecodeCodec<BossMonster> CODEC =
|
|
LivingEntity.CODEC.extend(BossMonster.class, BossMonster::new);
|
|
|
|
public BossMonster() {
|
|
super();
|
|
}
|
|
|
|
public BossMonster(World world) {
|
|
super(world);
|
|
}
|
|
|
|
@Override
|
|
protected Inventory createDefaultInventory() {
|
|
return new Inventory(9); // Petit inventaire
|
|
}
|
|
|
|
@Override
|
|
public boolean isCollidable() {
|
|
return true;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Thread Safety
|
|
|
|
{{< callout type="error" >}}
|
|
**Important :** Le spawn d'entités doit être fait sur le thread de tick du monde. Si vous appelez depuis un contexte asynchrone, utilisez l'exécuteur du monde :
|
|
{{< /callout >}}
|
|
|
|
```java
|
|
// Spawn sécurisé depuis un contexte asynchrone
|
|
world.execute(() -> {
|
|
world.spawnEntity(entity, position, rotation);
|
|
});
|
|
```
|
|
|
|
## Validation du Spawn
|
|
|
|
Le monde valide les positions de spawn :
|
|
|
|
```java
|
|
// Exigences de position :
|
|
// - X et Z doivent être dans +/- 33554432
|
|
// - Y doit être >= -32
|
|
|
|
// Les positions invalides lèvent IllegalArgumentException
|
|
try {
|
|
world.spawnEntity(entity, invalidPosition, rotation);
|
|
} catch (IllegalArgumentException e) {
|
|
getLogger().warning("Position de spawn invalide: " + e.getMessage());
|
|
}
|
|
```
|