package tc.oc.pgm.filters.matcher;
import javax.inject.Inject;
import javax.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EntityAction;
import org.bukkit.event.Event;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockBurnEvent;
import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.PlayerBucketFillEvent;
import tc.oc.commons.bukkit.event.BlockPunchEvent;
import tc.oc.commons.bukkit.event.BlockTrampleEvent;
import tc.oc.commons.bukkit.event.GeneralizingEvent;
import tc.oc.pgm.filters.query.IEventQuery;
import tc.oc.pgm.tracker.EventResolver;
import tc.oc.pgm.tracker.damage.DamageInfo;
import tc.oc.pgm.tracker.damage.ItemInfo;
import tc.oc.pgm.tracker.damage.MeleeInfo;
import tc.oc.pgm.tracker.damage.PhysicalInfo;
import tc.oc.pgm.tracker.damage.PotionInfo;
import tc.oc.pgm.tracker.damage.ProjectileInfo;
public class CauseFilter extends TypedFilter.Impl<IEventQuery> {
// TODO: add other causes like growth, flow, mob, machine, etc.
public enum Cause {
// Actor types
WORLD, LIVING, MOB, PLAYER,
// Block actions
PUNCH, TRAMPLE, MINE,
// Damage types
MELEE, PROJECTILE, POTION, EXPLOSION, COMBUSTION, FALL, GRAVITY, VOID,
SQUASH, SUFFOCATION, DROWNING, STARVATION, LIGHTNING, CACTUS, THORNS;
}
public interface Factory {
CauseFilter create(Cause cause);
}
private final @Inspect Cause cause;
private final Provider<EventResolver> eventResolverProvider;
@Inject CauseFilter(@Assisted Cause cause, Provider<EventResolver> eventResolverProvider) {
this.cause = cause;
this.eventResolverProvider = eventResolverProvider;
}
public boolean matches(IEventQuery query) {
Event event = query.getEvent();
if(event instanceof GeneralizingEvent) {
event = ((GeneralizingEvent) event).getCause();
}
EntityDamageEvent.DamageCause damageCause = null;
DamageInfo damageInfo = null;
boolean punchDamage = false;
if(event instanceof EntityDamageEvent) {
EntityDamageEvent damageEvent = (EntityDamageEvent) event;
damageCause = damageEvent.getCause();
damageInfo = eventResolverProvider.get().resolveDamage(damageEvent);
if(damageInfo instanceof MeleeInfo) {
PhysicalInfo weapon = ((MeleeInfo) damageInfo).getWeapon();
if(weapon instanceof ItemInfo && ((ItemInfo) weapon).getItem().getType() == Material.AIR) {
punchDamage = true;
}
}
}
Entity actor = null;
if(event instanceof EntityAction) {
actor = ((EntityAction) event).getActor();
}
switch(this.cause) {
// Actor types
case WORLD:
return !(actor instanceof LivingEntity);
case LIVING:
return actor instanceof LivingEntity;
case MOB:
return actor instanceof LivingEntity && !(actor instanceof Player);
case PLAYER:
return actor instanceof Player;
// Block actions
case PUNCH:
return event instanceof BlockPunchEvent || punchDamage;
case TRAMPLE:
return event instanceof BlockTrampleEvent;
case MINE:
return event instanceof BlockDamageEvent ||
event instanceof BlockBreakEvent ||
event instanceof PlayerBucketFillEvent;
// Damage types
case MELEE:
return damageCause == EntityDamageEvent.DamageCause.ENTITY_ATTACK ||
damageInfo instanceof MeleeInfo;
case PROJECTILE:
return damageCause == EntityDamageEvent.DamageCause.PROJECTILE ||
damageInfo instanceof ProjectileInfo;
case POTION:
return damageCause == EntityDamageEvent.DamageCause.MAGIC ||
damageCause == EntityDamageEvent.DamageCause.POISON ||
damageCause == EntityDamageEvent.DamageCause.WITHER ||
damageInfo instanceof PotionInfo;
case EXPLOSION:
return event instanceof EntityExplodeEvent ||
damageCause == EntityDamageEvent.DamageCause.BLOCK_EXPLOSION ||
damageCause == EntityDamageEvent.DamageCause.ENTITY_EXPLOSION;
case COMBUSTION:
return event instanceof BlockBurnEvent ||
damageCause == EntityDamageEvent.DamageCause.FIRE ||
damageCause == EntityDamageEvent.DamageCause.FIRE_TICK ||
damageCause == EntityDamageEvent.DamageCause.LAVA;
case FALL: // Strictly damage from hitting the ground
return damageCause == EntityDamageEvent.DamageCause.FALL;
case GRAVITY: // Any damage caused by a fall
return damageCause == EntityDamageEvent.DamageCause.FALL ||
damageCause == EntityDamageEvent.DamageCause.VOID;
case VOID:
return damageCause == EntityDamageEvent.DamageCause.VOID;
case SQUASH:
return damageCause == EntityDamageEvent.DamageCause.FALLING_BLOCK;
case SUFFOCATION:
return damageCause == EntityDamageEvent.DamageCause.SUFFOCATION;
case DROWNING:
return damageCause == EntityDamageEvent.DamageCause.DROWNING;
case STARVATION:
return damageCause == EntityDamageEvent.DamageCause.STARVATION;
case LIGHTNING:
return damageCause == EntityDamageEvent.DamageCause.LIGHTNING;
case CACTUS:
return damageCause == EntityDamageEvent.DamageCause.CONTACT;
case THORNS:
return damageCause == EntityDamageEvent.DamageCause.THORNS;
default:
return false;
}
}
}