Files
Documentation/content/advanced/effects/entity-effects.fr.md
2026-01-20 20:33:59 +01:00

10 KiB

title, type, weight
title type weight
Effets d'Entité docs 3

Les effets d'entité sont des effets de statut qui peuvent inclure des composants visuels, des modificateurs de stats et des comportements basés sur la durée.

Configuration EntityEffect

public class EntityEffect {
    protected String id;
    protected String name;                      // Clé de localisation

    protected ApplicationEffects applicationEffects;  // Effets visuels/audio

    protected String modelChange;               // Changer le modèle de l'entité
    protected float duration;                   // Durée par défaut (secondes)

    protected boolean infinite;                 // N'expire jamais ?
    protected boolean debuff;                   // Est un effet négatif ?
    protected String statusEffectIcon;          // Icône UI

    // Dégâts et stats
    protected Int2FloatMap entityStats;         // Modificateurs de stats
    protected ValueType valueType;              // Absolute ou Percent

    // Comportement
    protected OverlapBehavior overlapBehavior;  // EXTEND, OVERWRITE, IGNORE
    protected RemovalBehavior removalBehavior;  // COMPLETE, DURATION, INFINITE

    protected boolean invulnerable;             // Accorder l'invulnérabilité
}

Accéder aux Assets d'Effets

// Obtenir un effet par ID
EntityEffect effect = EntityEffect.getAssetMap().getAsset("fire_resistance");

// Obtenir l'index de l'effet pour les opérations
int effectIndex = EntityEffect.getAssetMap().getIndex(effect.getId());

EffectControllerComponent

Le EffectControllerComponent gère les effets actifs sur une entité :

import com.hypixel.hytale.server.core.entity.effect.EffectControllerComponent;

// Obtenir le contrôleur d'effets de l'entité
EffectControllerComponent controller = store.getComponent(
    entityRef,
    EffectControllerComponent.getComponentType()
);

Ajouter des Effets

Ajout Basique

EntityEffect effect = EntityEffect.getAssetMap().getAsset("speed_boost");

// Ajouter avec les paramètres par défaut
controller.addEffect(
    entityRef,
    effect,
    componentAccessor
);

Avec Durée Personnalisée

// Ajouter avec durée personnalisée et comportement de superposition
controller.addEffect(
    entityRef,
    effect,
    100.0f,                      // Durée en secondes
    OverlapBehavior.EXTEND,      // Comment gérer la superposition
    componentAccessor
);

Effets Infinis

// Ajouter un effet qui n'expire jamais
controller.addInfiniteEffect(
    entityRef,
    EntityEffect.getAssetMap().getIndex(effect.getId()),
    effect,
    componentAccessor
);

Supprimer des Effets

// Supprimer un effet spécifique
controller.removeEffect(
    entityRef,
    EntityEffect.getAssetMap().getIndex(effect.getId()),
    componentAccessor
);

Comportements de Superposition

public enum OverlapBehavior {
    EXTEND,     // Ajouter la durée à l'effet existant
    OVERWRITE,  // Remplacer l'effet existant
    IGNORE      // Ne pas appliquer si déjà actif
}

Exemples d'Utilisation

// Étendre la durée si déjà appliqué
controller.addEffect(
    entityRef,
    effect,
    30.0f,
    OverlapBehavior.EXTEND,
    componentAccessor
);

// Remplacer avec une durée fraîche
controller.addEffect(
    entityRef,
    effect,
    30.0f,
    OverlapBehavior.OVERWRITE,
    componentAccessor
);

// Appliquer seulement si pas déjà actif
controller.addEffect(
    entityRef,
    effect,
    30.0f,
    OverlapBehavior.IGNORE,
    componentAccessor
);

Comportements de Suppression

public enum RemovalBehavior {
    COMPLETE,   // Supprimer quand terminé
    DURATION,   // Supprimer après la durée
    INFINITE    // Ne jamais supprimer automatiquement
}

Types de Valeurs pour les Stats

public enum ValueType {
    Absolute,   // Ajouter/soustraire une valeur fixe
    Percent     // Multiplier par un pourcentage
}

Exemples Pratiques

Buff par Commande

public class BuffCommand extends AbstractCommand {
    private final RequiredArg<PlayerRef> playerArg;
    private final RequiredArg<String> effectArg;
    private final RequiredArg<Integer> durationArg;

    // Serait défini lors de l'initialisation du plugin
    private Store<EntityStore> store;
    private ComponentAccessor<EntityStore> componentAccessor;

    public BuffCommand() {
        super("buff", "effects.command.buff.description");
        this.playerArg = withRequiredArg("player", "Joueur cible", ArgTypes.PLAYER_REF);
        this.effectArg = withRequiredArg("effect", "ID de l'effet", ArgTypes.STRING);
        this.durationArg = withRequiredArg("duration", "Durée en secondes", ArgTypes.INTEGER);
    }

    @Override
    protected CompletableFuture<Void> execute(CommandContext ctx) {
        PlayerRef target = playerArg.get(ctx);
        String effectId = effectArg.get(ctx);
        int duration = durationArg.get(ctx);

        Ref<EntityStore> entityRef = target.getReference();
        if (entityRef == null || !entityRef.isValid()) {
            ctx.sender().sendMessage(Message.raw("Joueur non trouvé"));
            return null;
        }

        EntityEffect effect = EntityEffect.getAssetMap().getAsset(effectId);
        if (effect == null) {
            ctx.sender().sendMessage(Message.raw("Effet inconnu : " + effectId));
            return null;
        }

        EffectControllerComponent controller = store.getComponent(
            entityRef,
            EffectControllerComponent.getComponentType()
        );

        if (controller != null) {
            controller.addEffect(
                entityRef,
                effect,
                (float) duration,
                OverlapBehavior.EXTEND,
                componentAccessor
            );
        }

        ctx.sender().sendMessage(Message.raw("Appliqué " + effectId + " à " + target.getUsername()));
        return null;
    }
}

{{< callout type="warning" >}} Notes API :

  • Utilisez withRequiredArg() pour définir les arguments, pas addArgument()
  • Utilisez arg.get(ctx) pour récupérer les valeurs, pas ctx.getArg()
  • Utilisez ctx.sender() pas ctx.getSender()
  • Utilisez target.getUsername() pas target.getName()
  • Utilisez target.getReference() pour obtenir la référence d'entité (PlayerRef n'a pas getPlayer()) {{< /callout >}}

Effet de Dégâts dans le Temps

public void applyPoison(Player player, float duration, Store<EntityStore> store,
                        ComponentAccessor<EntityStore> componentAccessor) {
    EntityEffect poison = EntityEffect.getAssetMap().getAsset("poison");

    Ref<EntityStore> entityRef = player.getReference();
    EffectControllerComponent controller = store.getComponent(
        entityRef,
        EffectControllerComponent.getComponentType()
    );

    if (controller != null && poison != null) {
        controller.addEffect(
            entityRef,
            poison,
            duration,
            OverlapBehavior.EXTEND,
            componentAccessor
        );
    }

    player.sendMessage(Message.raw("Vous avez été empoisonné !"));
}

Invulnérabilité Temporaire

public void grantInvulnerability(Player player, float seconds, Store<EntityStore> store,
                                  ComponentAccessor<EntityStore> componentAccessor) {
    EntityEffect invuln = EntityEffect.getAssetMap().getAsset("invulnerability");

    Ref<EntityStore> entityRef = player.getReference();
    EffectControllerComponent controller = store.getComponent(
        entityRef,
        EffectControllerComponent.getComponentType()
    );

    if (controller != null && invuln != null) {
        controller.addEffect(
            entityRef,
            invuln,
            seconds,
            OverlapBehavior.OVERWRITE,  // Durée fraîche
            componentAccessor
        );
    }
}

Effacer Tous les Effets

public void clearAllEffects(Player player, Store<EntityStore> store,
                            ComponentAccessor<EntityStore> componentAccessor) {
    Ref<EntityStore> entityRef = player.getReference();
    EffectControllerComponent controller = store.getComponent(
        entityRef,
        EffectControllerComponent.getComponentType()
    );

    if (controller != null) {
        // Utiliser la méthode clearEffects intégrée
        controller.clearEffects(
            entityRef,
            componentAccessor
        );
    }

    player.sendMessage(Message.raw("Tous les effets effacés !"));
}

Combiner avec d'Autres Effets

Les effets d'entité fonctionnent bien avec les particules et les lumières dynamiques :

public void applyMagicBuff(Player player, Store<EntityStore> store,
                           ComponentAccessor<EntityStore> componentAccessor) {
    Ref<EntityStore> entityRef = player.getReference();

    // Appliquer l'effet de statut
    EntityEffect buff = EntityEffect.getAssetMap().getAsset("magic_power");
    EffectControllerComponent controller = store.getComponent(
        entityRef,
        EffectControllerComponent.getComponentType()
    );
    if (controller != null && buff != null) {
        controller.addEffect(entityRef, buff, componentAccessor);
    }

    // Ajouter une lueur visuelle
    ColorLight glow = new ColorLight((byte) 10, (byte) 200, (byte) 50, (byte) 255);
    DynamicLight light = new DynamicLight(glow);
    componentAccessor.putComponent(
        entityRef,
        DynamicLight.getComponentType(),
        light
    );

    // Obtenir la position via TransformComponent pour les particules
    TransformComponent transform = store.getComponent(entityRef, TransformComponent.getComponentType());
    if (transform != null) {
        ParticleUtil.spawnParticleEffect(
            "magic_aura",
            transform.getPosition(),
            componentAccessor
        );
    }
}

{{< callout type="info" >}} Note : Utilisez player.getReference() pour obtenir la référence d'entité. La position doit être obtenue via TransformComponent, pas directement depuis Player. {{< /callout >}}

Bonnes Pratiques

{{< callout type="info" >}} Directives pour les Effets :

  • Utilisez EXTEND pour les buffs cumulables afin de récompenser l'application répétée
  • Utilisez OVERWRITE pour les effets qui doivent réinitialiser leur durée
  • Utilisez IGNORE pour empêcher l'empilement d'effets quand indésirable
  • Vérifiez toujours si l'effet existe avant de l'appliquer
  • Considérez les performances avec de nombreux effets simultanés {{< /callout >}}