package net.t7seven7t.craftfx.trigger;
import net.t7seven7t.craftfx.Registry;
import net.t7seven7t.craftfx.data.trigger.ChatData;
import net.t7seven7t.craftfx.data.trigger.HealthChangeData;
import net.t7seven7t.craftfx.data.trigger.HoldData;
import net.t7seven7t.craftfx.data.trigger.MoveData;
import net.t7seven7t.craftfx.data.trigger.SlotData;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemBreakEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
/**
*
*/
public class TriggerRegistry implements Registry<TriggerSpec> {
/**
* List of all trigger specs
*/
private final List<TriggerSpec> triggerSpecList = new ArrayList<>();
public TriggerRegistry() {
initDefaults();
}
/**
* Registers a TriggerSpec
*
* @param spec TriggerSpec to register
* @throws IllegalArgumentException if a TriggerSpec is already registered with the same alias
*/
@Override
public void register(TriggerSpec spec) {
for (String alias : spec.getAliases()) {
if (getSpec(alias).isPresent()) {
throw new IllegalArgumentException("A TriggerSpec is already registered " +
"with the alias " + alias);
}
}
triggerSpecList.add(spec);
}
@Override
public Optional<TriggerSpec> getSpec(String alias) {
alias = alias.toLowerCase();
for (TriggerSpec spec : triggerSpecList) {
if (spec.getAliases().contains(alias)) return Optional.of(spec);
}
return Optional.empty();
}
private void initDefaults() {
final Function<PlayerJoinEvent, TriggerContext> playerJoinFunction = e ->
new TriggerContext(e.getPlayer());
register(TriggerSpec.builder()
.aliases("chat")
.data(new ChatData())
.listener(AsyncPlayerChatEvent.class,
e -> new TriggerContext(e.getPlayer(), e.getMessage()))
.filter(c -> {
final ChatData data = c.getData(ChatData.class).get();
final Optional<String> opt = data.getPattern();
return opt.map(p -> c.getTarget().as(String.class).get().matches(p))
.orElse(true);
}).build());
register(TriggerSpec.builder()
.aliases("death")
.data(new SlotData("all"))
.listener(EntityDeathEvent.class, e -> e instanceof PlayerDeathEvent
? new TriggerContext((Player) e.getEntity()) : null)
.build());
register(TriggerSpec.builder()
.aliases("move")
.data(new MoveData(0, Double.MAX_VALUE))
.listener(PlayerMoveEvent.class, e -> new TriggerContext(e.getPlayer(), e.getTo()))
.filter(c -> {
final MoveData data = c.getData(MoveData.class).get();
final double dist = c.getInitiator().getLocation()
.distance(c.getTarget().getLocation().get());
return dist >= data.getMinMoveDist() && dist <= data.getMaxMoveDist();
}).build());
final Predicate<TriggerContext> holdFilter = c -> {
final HoldData data = c.getData(HoldData.class).get();
final Optional<ItemStack> opt = c.getTarget().as(ItemStack.class);
return opt.isPresent() && data.getMinimumStackSize() <= opt.get().getAmount()
&& data.getMaximumStackSize() >= opt.get().getAmount();
};
final Predicate<TriggerContext> equipFilter = c -> {
final SlotData data = c.getData(SlotData.class).get();
final int slot = c.getTargets().get(1).as(Integer.class).get();
if (data.isHandSlot() && slot != c.getInitiator().getInventory()
.getHeldItemSlot()) return false;
for (int i : data.getSlots()) {
if (i == slot) return true;
}
return false;
};
register(TriggerSpec.builder()
.aliases("hold item", "hold")
.data(new HoldData(0, 64))
.listener(PlayerItemHeldEvent.class, e -> new TriggerContext(e.getPlayer(),
e.getPlayer().getInventory().getItem(e.getNewSlot())))
.listener(InventoryClickEvent.class, e -> {
if (e.getWhoClicked() instanceof Player
&& e.getSlot() == e.getWhoClicked().getInventory().getHeldItemSlot()) {
return new TriggerContext((Player) e.getWhoClicked(), e.getCursor());
}
return null;
})
.listener(PlayerJoinEvent.class, playerJoinFunction)
.filter(holdFilter)
.build());
register(TriggerSpec.builder()
.aliases("unhold item", "unhold")
.data(new HoldData(0, 64))
.listener(PlayerItemHeldEvent.class, e -> new TriggerContext(e.getPlayer(),
e.getPlayer().getInventory().getItem(e.getPreviousSlot())),
// execute before hold trigger on monitor priority
EventPriority.HIGHEST)
.listener(InventoryClickEvent.class, e -> {
if (e.getWhoClicked() instanceof Player
&& e.getSlot() == e.getWhoClicked().getInventory().getHeldItemSlot()) {
return new TriggerContext((Player) e.getWhoClicked(), e.getCurrentItem());
}
return null;
})
.listener(PlayerJoinEvent.class, playerJoinFunction)
.filter(holdFilter)
.build());
register(TriggerSpec.builder()
.aliases("equip")
.listener(InventoryClickEvent.class, e -> {
if (e.getWhoClicked() instanceof Player) {
return new TriggerContext((Player) e.getWhoClicked(), e.getCursor(),
e.getSlot());
}
return null;
}).filter(equipFilter)
.build());
register(TriggerSpec.builder()
.aliases("unequip")
.listener(InventoryClickEvent.class, e -> {
if (e.getWhoClicked() instanceof Player) {
return new TriggerContext((Player) e.getWhoClicked(), e.getCurrentItem(),
e.getSlot());
}
return null;
}).filter(equipFilter)
.build());
register(TriggerSpec.builder()
.aliases("hit entity")
.data(new HealthChangeData(0, Double.MAX_VALUE))
.listener(EntityDamageByEntityEvent.class, e -> e.getDamager() instanceof Player ?
new TriggerContext((Player) e.getDamager(), e.getEntity(),
e.getFinalDamage()) : null)
.filter(c -> {
final HealthChangeData data = c.getData(HealthChangeData.class).get();
final double damage = c.getTargets().get(1).as(Double.class).get();
return damage >= data.getMinHealthChange() && damage <= data
.getMaxHealthChange();
}).build());
register(TriggerSpec.builder()
.aliases("break item")
.listener(PlayerItemBreakEvent.class,
e -> new TriggerContext(e.getPlayer(), e.getBrokenItem()))
.build());
register(TriggerSpec.builder()
.aliases("consume item", "consume")
.listener(PlayerItemConsumeEvent.class,
e -> new TriggerContext(e.getPlayer(), e.getItem()))
.build());
register(TriggerSpec.builder()
.aliases("change health", "modify health")
.data(new HealthChangeData(-20, 20))
.listener(EntityDamageEvent.class, e -> e.getEntityType() == EntityType.PLAYER ?
new TriggerContext((Player) e.getEntity(), e.getFinalDamage()) : null)
.filter(c -> {
final HealthChangeData data = c.getData(HealthChangeData.class).get();
final double damage = c.getTarget().as(Double.class).get();
return damage >= data.getMinHealthChange()
&& damage <= data.getMaxHealthChange();
}).build());
register(TriggerSpec.builder()
.aliases("teleport")
.data(new MoveData(0, Double.MAX_VALUE))
.listener(PlayerTeleportEvent.class,
e -> new TriggerContext(e.getPlayer(), e.getTo()))
.filter(c -> {
final MoveData data = c.getData(MoveData.class).get();
final double dist = c.getTarget().getLocation().get()
.distance(c.getInitiator().getLocation());
return dist >= data.getMinMoveDist() && dist <= data.getMaxMoveDist();
}).build());
register(TriggerSpec.builder()
.aliases("on kill", "kill")
.listener(EntityDamageByEntityEvent.class, e -> {
if (!(e.getEntity() instanceof LivingEntity)
|| !(e.getDamager() instanceof Player)) return null;
if (((LivingEntity) e.getEntity()).getHealth() - e.getFinalDamage() <= 0) {
return new TriggerContext((Player) e.getDamager(), e.getEntity());
}
return null;
}).build());
register(TriggerSpec.builder()
.aliases("left click air")
.listener(PlayerInteractEvent.class, e -> {
if (e.getAction() == Action.LEFT_CLICK_AIR) {
return new TriggerContext(e.getPlayer(), e.getPlayer());
}
return null;
})
.build());
register(TriggerSpec.builder()
.aliases("left click block")
.listener(PlayerInteractEvent.class, e -> {
if (e.getAction() == Action.LEFT_CLICK_BLOCK) {
return new TriggerContext(e.getPlayer(), e.getClickedBlock());
}
return null;
}).build());
register(TriggerSpec.builder()
.aliases("right click air")
.listener(PlayerInteractEvent.class, e -> {
if (e.getAction() == Action.RIGHT_CLICK_AIR) {
return new TriggerContext(e.getPlayer(), e.getPlayer());
}
return null;
}).build());
register(TriggerSpec.builder()
.aliases("right click block")
.listener(PlayerInteractEvent.class, e -> {
if (e.getAction() == Action.RIGHT_CLICK_BLOCK) {
return new TriggerContext(e.getPlayer(), e.getClickedBlock());
}
return null;
}).build());
register(TriggerSpec.builder()
.aliases("right click entity")
.listener(PlayerInteractEntityEvent.class, e ->
new TriggerContext(e.getPlayer(), e.getRightClicked()))
.build());
// .
}
}