package com.supaham.commons.bukkit.entities; import com.google.common.base.Preconditions; import com.supaham.commons.bukkit.TickerTask; import com.supaham.commons.bukkit.modules.CommonModule; import com.supaham.commons.bukkit.modules.ModuleContainer; import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityChangeBlockEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.plugin.Plugin; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import javax.annotation.Nonnull; public class EntityRemover extends CommonModule { private Map<Entity, Long> expiringEntities = new HashMap<>(); private TickerTask removerTask; private Listener listener = new EntityListener(); /** * Constructs a new module. This module should never automatically register to the given * {@link ModuleContainer} as that is extremely unproductive and may cause compatibility issues. * * @param container module container to own this module. */ public EntityRemover(@Nonnull ModuleContainer container) { super(container); this.removerTask = new RemoverTask(container.getPlugin(), 0, 1); registerTask(this.removerTask); registerListener(this.listener); } /** * Schedules an {@link Entity} for removal after the given delay in ticks. * * @param entity entity to remove * @param delay delay (in ticks) until the entity should be removed */ public void schedule(@Nonnull Entity entity, int delay) { Preconditions.checkNotNull(entity, "entity cannot be null."); Preconditions.checkArgument(delay > 0, "delay must be larger than 0."); this.expiringEntities.put(entity, System.currentTimeMillis() + ((long) delay * 50)); } public boolean remove(@Nonnull Entity entity) { return this.expiringEntities.remove(entity) != null; } public void clear() { clear(false); } public void clear(boolean removeEntities) { Iterator<Entity> it = EntityRemover.this.expiringEntities.keySet().iterator(); while (it.hasNext()) { Entity next = it.next(); if (removeEntities) { next.remove(); } it.remove(); } } private final class RemoverTask extends TickerTask { public RemoverTask(@Nonnull Plugin plugin, long delay, long interval) { super(plugin, delay, interval); } @Override public void run() { Iterator<Entry<Entity, Long>> it = EntityRemover.this.expiringEntities.entrySet().iterator(); while (it.hasNext()) { Entry<Entity, Long> entry = it.next(); if (System.currentTimeMillis() >= entry.getValue()) { entry.getKey().remove(); it.remove(); } } } } private final class EntityListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityDeath(EntityDeathEvent event) { EntityRemover.this.expiringEntities.remove(event.getEntity()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityDeath(EntityChangeBlockEvent event) { EntityRemover.this.expiringEntities.remove(event.getEntity()); } // TODO Do we need to check for more events? } }