package toadmess.explosives.events; import java.util.List; import java.util.Random; import org.bukkit.Location; import org.bukkit.entity.Chicken; import org.bukkit.entity.Creeper; import org.bukkit.entity.Entity; import org.bukkit.entity.Fireball; import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; import org.bukkit.event.Event; import org.bukkit.event.block.BlockDamageEvent; import org.bukkit.event.block.BlockEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityEvent; import toadmess.explosives.Gatekeeper; import toadmess.explosives.config.MultiWorldConfStore; import toadmess.explosives.config.entity.EntityConf; import toadmess.explosives.events.handlers.TNTTracker; public class HEEvent { public final TippingPoint type; public final Event event; public final MultiWorldConfStore confStore; private EntityConf applicableConfig = null; private Location eventLocation = null; /** * TODO: Clean up this tracker. Find a better way to deal with tracking of entities. */ private static TNTTracker tntTracker = null; public HEEvent(final TippingPoint interestingEvent, final Event bukkitEvent, final MultiWorldConfStore confStore) { this.type = interestingEvent; this.event = bukkitEvent; this.confStore = confStore; } public boolean hasApplicableConfig() { return null != getApplicableConfig(); } /** * @param confStore The configuration store to interrogate for the relevant EntityConf. * * @return An active config for the event's location and event's causal entity. * Or null if there is no applicable config. */ public EntityConf getApplicableConfig() { if(this.applicableConfig == null) { final EntityConf activeConf = this.confStore.getActiveConf(getConfigEntityClass(), getEventLocation()); this.applicableConfig = getApplicableSubConfig(activeConf); } return this.applicableConfig; } /** * TODO: Clean up these trackers and get some better structure in place for them. */ public static void setTNTTracker(final TNTTracker tracker) { HEEvent.tntTracker = tracker; } private EntityConf getApplicableSubConfig(final EntityConf fromThisParentConfig) { // Get any relevant sub config for this event type switch(this.type) { case TNT_PRIME_BY_PLAYER: if(fromThisParentConfig.hasTNTPrimeByHandConfig()) { EntityConf permissionChainHead = fromThisParentConfig.getTNTPrimeByHandConfig(); if(permissionChainHead.hasPermissionsBasedConfigs()) { for(final EntityConf permissionConfig : permissionChainHead.getPermissionsBasedConfigs()) { final Player suspect = ((BlockDamageEvent) event).getPlayer(); final String reqPermission = permissionConfig.getPermissionNodeName(); if(reqPermission != null && !Gatekeeper.hasPermission(suspect, reqPermission)) { continue; } final String reqGroup = permissionConfig.getPermissionGroupName(); if(reqGroup != null && !Gatekeeper.inGroup(suspect, reqGroup)) { continue; } // This player has the needed permissions for this permissions based sub config. // Add this sub config to the chain of permissions. permissionChainHead = new EntityConf(permissionConfig, permissionChainHead, new Random()); } } return permissionChainHead; } break; case TNT_PRIME_BY_FIRE: if(fromThisParentConfig.hasTNTPrimeByFireConfig()) { return fromThisParentConfig.getTNTPrimeByFireConfig(); } break; case TNT_PRIME_BY_REDSTONE: if(fromThisParentConfig.hasTNTPrimeByRedstoneConfig()) { return fromThisParentConfig.getTNTPrimeByRedstoneConfig(); } break; case TNT_PRIME_BY_EXPLOSION: if(fromThisParentConfig.hasTNTPrimeByExplosionConfig()) { return fromThisParentConfig.getTNTPrimeByExplosionConfig(); } break; default: final Entity relevantEntity = getRelevantEntity(); if(relevantEntity instanceof TNTPrimed && tntTracker != null) { final HEEvent triggeringEvent = tntTracker.getTriggerFor((TNTPrimed) relevantEntity); if(triggeringEvent != null) { return triggeringEvent.getApplicableConfig(); } } else if(relevantEntity instanceof Creeper && ((Creeper) relevantEntity).isPowered() && fromThisParentConfig.hasCreeperChargedConfig()) { return fromThisParentConfig.getCreeperChargedConfig(); } } return fromThisParentConfig; } public Location getEventLocation() { if(this.eventLocation == null) { switch(this.type) { case CAN_CHANGE_EXPLOSION_RADIUS: case CAN_CHANGE_EXPLOSION_FIRE_FLAG: case CAN_CHANGE_EXPLOSION_YIELD: case CAN_PREVENT_TERRAIN_DAMAGE: case AN_EXPLOSION: case AN_EXPLOSION_CANCELLED: this.eventLocation = ((EntityEvent)event).getEntity().getLocation(); break; case CAN_CHANGE_PLAYER_DAMAGE: case CAN_CHANGE_CREATURE_DAMAGE: case CAN_CHANGE_ITEM_DAMAGE: this.eventLocation = ((EntityDamageByEntityEvent) event).getDamager().getLocation(); break; case TNT_PRIME_BY_FIRE: case TNT_PRIME_BY_PLAYER: case TNT_PRIME_BY_REDSTONE: this.eventLocation = ((BlockEvent) event).getBlock().getLocation(); break; default: System.err.println("HEEvent.getEventLocation(): Not sure what the location is of unknown event type " + this.type); } if(this.eventLocation != null) { // Clone the event just in case Location instances are reused and this HEEvent is held onto for a long time. this.eventLocation = this.eventLocation.clone(); } } return this.eventLocation; } /** * @return The class of the bukkit entity - the name of which corresponds to * the section in the config.yml file that we want to use for this event. */ public Class<? extends Entity> getConfigEntityClass() { final Entity relevantEntity = getRelevantEntity(); if(relevantEntity != null) { if(relevantEntity instanceof TNTPrimed) { return TNTPrimed.class; } else if(relevantEntity instanceof Creeper) { return Creeper.class; } else if(relevantEntity instanceof Fireball) { return Fireball.class; } else { System.err.println("HEEvent.getApplicableConfig(): not sure how to get the config for entity " + relevantEntity); return Chicken.class; } } else { switch(this.type) { case TNT_PRIME_BY_FIRE: case TNT_PRIME_BY_PLAYER: case TNT_PRIME_BY_REDSTONE: case AN_EXPLOSION: case AN_EXPLOSION_CANCELLED: return TNTPrimed.class; default: System.err.println("HEEvent.getApplicableConfig(): not sure how to get the config for event type " + type + ". this="+this); return Chicken.class; } } } /** * @return Where it makes sense, this will return the event's interesting * entity instance (the one that is the entity we will be looking up configs against). * If there is no bukkit event or entity for the event then null is returned. */ protected Entity getRelevantEntity() { switch(this.type) { case CAN_CHANGE_EXPLOSION_RADIUS: case CAN_CHANGE_EXPLOSION_FIRE_FLAG: case CAN_CHANGE_EXPLOSION_YIELD: case CAN_PREVENT_TERRAIN_DAMAGE: return ((EntityEvent)event).getEntity(); case CAN_CHANGE_PLAYER_DAMAGE: case CAN_CHANGE_CREATURE_DAMAGE: case CAN_CHANGE_ITEM_DAMAGE: return ((EntityDamageByEntityEvent) event).getDamager(); default: return null; } } @Override public String toString() { return "HEEvent("+type+", "+event+")"; } }