package toadmess.explosives;
import java.util.HashSet;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.block.BlockBurnEvent;
import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.block.BlockEvent;
import org.bukkit.event.block.BlockListener;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityListener;
import org.bukkit.event.entity.ExplosionPrimeEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import toadmess.explosives.config.MultiWorldConfStore;
import toadmess.explosives.events.HEEvent;
import toadmess.explosives.events.TippingPoint;
import toadmess.explosives.events.handlers.EventRouter;
public class BukkitListeners {
private final MultiWorldConfStore confStore;
private final Plugin plugin;
// Keep track of the event listeners that we have registered so we know
// what we have after the plugin has been enabled.
// We may need to register more listeners later on (e.g. MiningTNT workaround or commands etc.).
private final HashSet<Event.Type> registeredEvents = new HashSet<Event.Type>();
private final EntityListener entityListener;
private final BlockListener blockListener;
private final EventRouter router ;
public BukkitListeners(final Plugin plugin, final EventRouter router, final MultiWorldConfStore confStore) {
this.plugin = plugin;
this.confStore = confStore;
this.router = router;
this.entityListener = new EntityListenerImpl();
this.blockListener = new BlockListenerImpl(this.plugin);
}
public class EntityListenerImpl extends EntityListener {
@Override
public void onExplosionPrime(final ExplosionPrimeEvent event) {
if(event.isCancelled()) {
return;
}
router.handle(new HEEvent(TippingPoint.CAN_CHANGE_EXPLOSION_RADIUS, event, confStore));
router.handle(new HEEvent(TippingPoint.CAN_CHANGE_EXPLOSION_FIRE_FLAG, event, confStore));
}
@Override
public void onEntityDamage(final EntityDamageEvent event) {
if(!(event instanceof EntityDamageByEntityEvent)) {
return;
}
if(event.getCause() != EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) {
return;
}
if(event.isCancelled()) {
return;
}
final Entity damagee = event.getEntity();
if(damagee instanceof Player) {
router.handle(new HEEvent(TippingPoint.CAN_CHANGE_PLAYER_DAMAGE, event, confStore));
} else if(damagee instanceof LivingEntity){
router.handle(new HEEvent(TippingPoint.CAN_CHANGE_CREATURE_DAMAGE, event, confStore));
} else {
router.handle(new HEEvent(TippingPoint.CAN_CHANGE_ITEM_DAMAGE, event, confStore));
}
}
@Override
public void onEntityExplode(final EntityExplodeEvent event) {
final Location epicentre = event.getLocation();
if(null == epicentre) {
return;
}
if(event.getEntity() == null) {
// Can be null as a result of an explosion triggered without an entity (e.g. MCNative.playSoundExplosion())
// In such a case, it is not an interesting event to be passing on to any handlers.
return;
}
if(!event.isCancelled()) {
router.handle(new HEEvent(TippingPoint.CAN_PREVENT_TERRAIN_DAMAGE, event, confStore));
}
if(!event.isCancelled()) {
router.handle(new HEEvent(TippingPoint.CAN_CHANGE_EXPLOSION_YIELD, event, confStore));
}
if(!event.isCancelled()) {
router.handle(new HEEvent(TippingPoint.AN_EXPLOSION, event, confStore));
} else {
router.handle(new HEEvent(TippingPoint.AN_EXPLOSION_CANCELLED, event, confStore));
}
}
}
public class BlockListenerImpl extends BlockListener {
final Plugin pluginRef;
public BlockListenerImpl(final Plugin heMain) {
this.pluginRef = heMain;
}
private boolean commonTNTBlockChecks(final BlockEvent event) {
final Block damaged = event.getBlock();
if(damaged == null || damaged.getType() != Material.TNT) {
return false;
}
if(event instanceof Cancellable &&
((Cancellable) event).isCancelled()) {
return false;
}
return true;
}
@Override
public void onBlockDamage(final BlockDamageEvent event) {
if(!commonTNTBlockChecks(event)) {
return;
}
if(null == event.getPlayer()) {
return;
}
router.handle(new HEEvent(TippingPoint.TNT_PRIME_BY_PLAYER, event, confStore));
}
@Override
public void onBlockPhysics(final BlockPhysicsEvent event) {
if(!commonTNTBlockChecks(event)) {
return;
}
if(event.getBlock().getBlockPower() <= 0) {
return;
}
router.handle(new HEEvent(TippingPoint.TNT_PRIME_BY_REDSTONE, event, confStore));
}
@Override
public void onBlockBurn(final BlockBurnEvent event) {
if(!commonTNTBlockChecks(event)) {
return;
}
router.handle(new HEEvent(TippingPoint.TNT_PRIME_BY_FIRE, event, confStore));
}
}
/**
* Registers event listeners if they're needed by the config.
* This is safely re-runnable without registering a listener more than once (in
* cases where the config somehow changes, e.g. commands).
*/
public void registerNeededEvents(final PluginManager pm, final Plugin heMain) {
for(final Event.Type evType : this.router.getNeededBukkitEvents()) {
if(!this.registeredEvents.contains(evType)) { // Only register if we haven't done so before
switch(evType.getCategory()) {
case LIVING_ENTITY:
pm.registerEvent(evType, this.entityListener, Event.Priority.Normal, heMain);
break;
case BLOCK:
pm.registerEvent(evType, this.blockListener, Event.Priority.Normal, heMain);
break;
}
this.registeredEvents.add(evType);
}
}
}
}