DisguiseEffectListener
Keeps the disguise's invisibility potion effect in place whenever something tries to remove or clear it from a disguised player. Two complementary handlers because no single event covers everything:
- EntityPotionEffectEvent fires on every effect removal, regardless of cause — milk bucket (
Cause.MILK),/effect clear(Cause.COMMAND), third-party plugins, etc. The 1-tick deferred re-apply lands while the player is still alive, so the effect sticks. - PlayerRespawnEvent covers the death→respawn cycle. The potion event ALSO fires on death (with
Cause.DEATH), but the deferred re-apply from that path tries toaddPotionEffectwhile the player is in the dead state, where it doesn't stick across the respawn. The respawn handler re-applies after the player is fully alive again, which is whenaddPotionEffectactually persists.
Self-removal during /fmm undisguise is naturally skipped: undisguise removes the player from the active-disguise map BEFORE remove strips the potion. By the time the potion event handler runs, DisguiseManager.getDisguise(player) returns null and we no-op — no infinite loop.