ExcellentEnchants-spigot/Core/src/main/java/su/nightexpress/excellentenchants/enchantment/listener/EnchantHandlerListener.java

304 lines
13 KiB
Java

package su.nightexpress.excellentenchants.enchantment.listener;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.event.entity.*;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.FixedMetadataValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nexmedia.engine.api.manager.AbstractListener;
import su.nexmedia.engine.utils.EntityUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.api.enchantment.meta.Arrowed;
import su.nightexpress.excellentenchants.api.enchantment.type.*;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.enchantment.EnchantManager;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
public class EnchantHandlerListener extends AbstractListener<ExcellentEnchants> {
private static final String META_PROJECTILE_WEAPON = "sourceWeapon";
public EnchantHandlerListener(@NotNull EnchantManager enchantManager) {
super(enchantManager.plugin());
}
private void setSourceWeapon(@NotNull Projectile projectile, @NotNull ItemStack item) {
projectile.setMetadata(META_PROJECTILE_WEAPON, new FixedMetadataValue(plugin, item));
}
@Nullable
private ItemStack getSourceWeapon(@NotNull Projectile projectile) {
return projectile.hasMetadata(META_PROJECTILE_WEAPON) ? (ItemStack) projectile.getMetadata(META_PROJECTILE_WEAPON).get(0).value() : null;
}
private void removeSourceWeapon(@NotNull Projectile projectile) {
projectile.removeMetadata(META_PROJECTILE_WEAPON, plugin);
}
// ---------------------------------------------------------------
// Combat Attacking Enchants
// ---------------------------------------------------------------
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onEnchantCombatMelee(EntityDamageEvent e) {
if (e.getCause() == DamageCause.THORNS) return;
if (!(e.getEntity() instanceof LivingEntity victim)) return;
if (e instanceof EntityDamageByEntityEvent ede) {
LivingEntity damager = null;
if (ede.getDamager() instanceof LivingEntity living) {
damager = living;
}
else if (ede.getDamager() instanceof Projectile pj && pj.getShooter() instanceof LivingEntity living) {
damager = living;
}
if (damager == null || damager.equals(victim)) return;
if (ede.getDamager() instanceof Projectile projectile) {
this.handleCombatBowEnchants(ede, projectile, victim);
}
else {
this.handleCombatWeaponEnchants(ede, damager, victim);
}
this.handleCombatArmorEnchants(ede, damager, victim);
}
else {
this.handleArmorEnchants(e, victim);
}
}
private void handleCombatWeaponEnchants(@NotNull EntityDamageByEntityEvent e,
@NotNull LivingEntity damager, @NotNull LivingEntity victim) {
EntityEquipment equipment = damager.getEquipment();
if (equipment == null) return;
ItemStack weapon = equipment.getItemInMainHand();
if (weapon.getType().isAir() || weapon.getType() == Material.ENCHANTED_BOOK) return;
EnchantUtils.getExcellents(weapon, CombatEnchant.class).forEach((combatEnchant, level) -> {
if (combatEnchant.isOutOfCharges(weapon)) return;
if (combatEnchant.onAttack(e, damager, victim, weapon, level)) {
combatEnchant.consumeChargesNoUpdate(weapon, level);
}
});
EnchantUtils.updateChargesDisplay(weapon);
}
private void handleCombatArmorEnchants(@NotNull EntityDamageByEntityEvent e,
@NotNull LivingEntity damager, @NotNull LivingEntity victim) {
EntityEquipment equipDamager = damager.getEquipment();
if (equipDamager == null) return;
ItemStack weaponDamager = equipDamager.getItemInMainHand();
for (ItemStack armor : EntityUtil.getEquippedArmor(victim).values()) {
if (armor == null || armor.getType().isAir()) continue;
EnchantUtils.getExcellents(armor, CombatEnchant.class).forEach((combatEnchant, level) -> {
if (combatEnchant.isOutOfCharges(armor)) return;
if (combatEnchant.onProtect(e, damager, victim, weaponDamager, level)) {
combatEnchant.consumeChargesNoUpdate(armor, level);
}
});
EnchantUtils.updateChargesDisplay(armor);
}
}
private void handleArmorEnchants(@NotNull EntityDamageEvent e, @NotNull LivingEntity entity) {
EnchantUtils.getEquipped(entity, DamageEnchant.class).forEach((item, enchants) -> {
enchants.forEach((enchant, level) -> {
if (enchant.isOutOfCharges(item)) return;
if (enchant.onDamage(e, entity, item, level)) {
enchant.consumeChargesNoUpdate(item, level);
}
});
EnchantUtils.updateChargesDisplay(item);
});
}
private void handleCombatBowEnchants(@NotNull EntityDamageByEntityEvent e, @NotNull Projectile projectile,
@NotNull LivingEntity victim) {
if (!(projectile.getShooter() instanceof LivingEntity shooter)) return;
ItemStack bow = this.getSourceWeapon(projectile);
if (bow == null || bow.getType().isAir() || bow.getType() == Material.ENCHANTED_BOOK) return;
EnchantUtils.getExcellents(bow, BowEnchant.class).forEach((bowEnchant, level) -> {
bowEnchant.onDamage(e, projectile, shooter, victim, bow, level);
});
}
// ---------------------------------------------------------------
// Bow Shooting Enchants
// ---------------------------------------------------------------
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onEnchantBowShoot(EntityShootBowEvent e) {
LivingEntity shooter = e.getEntity();
if (shooter.getEquipment() == null) return;
ItemStack bow = e.getBow();
if (bow == null || bow.getType().isAir() || bow.getType() == Material.ENCHANTED_BOOK) return;
EnchantUtils.getExcellents(bow, BowEnchant.class).forEach((bowEnchant, level) -> {
if (bowEnchant.isOutOfCharges(bow)) return;
if (bowEnchant.onShoot(e, shooter, bow, level)) {
if (bowEnchant instanceof Arrowed arrowed && e.getProjectile() instanceof Projectile projectile) {
arrowed.addData(projectile);
arrowed.addTrail(projectile);
}
bowEnchant.consumeChargesNoUpdate(bow, level);
}
});
EnchantUtils.updateChargesDisplay(bow);
if (e.getProjectile() instanceof Projectile projectile) {
this.setSourceWeapon(projectile, bow);
}
}
// ---------------------------------------------------------------
// Bow Hit Land Enchants
// ---------------------------------------------------------------
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onEnchantBowHit(ProjectileHitEvent e) {
Projectile projectile = e.getEntity();
ItemStack bow = this.getSourceWeapon(projectile);
if (bow == null || bow.getType().isAir() || bow.getType() == Material.ENCHANTED_BOOK) return;
EnchantUtils.getExcellents(bow, BowEnchant.class).forEach((bowEnchant, level) -> {
bowEnchant.onHit(e, projectile, bow, level);
});
// Prevent to apply enchants multiple times on hits.
this.plugin.getScheduler().runTask(this.plugin, c -> this.removeSourceWeapon(projectile));
}
// ---------------------------------------------------------------
// Interaction Related Enchants
// ---------------------------------------------------------------
@EventHandler(priority = EventPriority.HIGHEST)
public void onEnchantInteract(PlayerInteractEvent e) {
if (e.useInteractedBlock() == Result.DENY) return;
if (e.useItemInHand() == Result.DENY) return;
ItemStack item = e.getItem();
if (item == null || item.getType().isAir() || item.getType() == Material.ENCHANTED_BOOK) return;
Player player = e.getPlayer();
EnchantUtils.getExcellents(item, InteractEnchant.class).forEach((interEnchant, level) -> {
if (interEnchant.isOutOfCharges(item)) return;
if (interEnchant.onInteract(e, player, item, level)) {
interEnchant.consumeChargesNoUpdate(item, level);
}
});
EnchantUtils.updateChargesDisplay(item);
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onEnchantFishing(PlayerFishEvent event) {
Player player = event.getPlayer();
ItemStack item = EnchantUtils.getFishingRod(player);
if (item == null) return;
EnchantUtils.getExcellents(item, FishingEnchant.class).forEach((enchant, level) -> {
if (event.isCancelled()) return; // Check if event was cancelled by some enchantment.
if (enchant.isOutOfCharges(item)) return;
if (enchant.onFishing(event, item, level)) {
enchant.consumeChargesNoUpdate(item, level);
}
});
EnchantUtils.updateChargesDisplay(item);
}
// ---------------------------------------------------------------
// Death Related Enchants
// ---------------------------------------------------------------
@EventHandler(priority = EventPriority.HIGHEST)
public void onEnchantDeath(EntityDeathEvent event) {
LivingEntity entity = event.getEntity();
EnchantUtils.getEquipped(entity, DeathEnchant.class).forEach((item, enchants) -> {
enchants.forEach(((deathEnchant, level) -> {
if (deathEnchant.isOutOfCharges(item)) return;
if (deathEnchant.onDeath(event, entity, item, level)) {
deathEnchant.consumeChargesNoUpdate(item, level);
}
}));
if (Config.ENCHANTMENTS_CHARGES_ENABLED.get()) {
EnchantUtils.updateChargesDisplay(item);
}
});
Player killer = entity.getKiller();
if (killer == null) return;
ItemStack weapon = killer.getInventory().getItemInMainHand();
if (weapon.getType().isAir() || weapon.getType() == Material.ENCHANTED_BOOK) return;
EnchantUtils.getExcellents(weapon, DeathEnchant.class).forEach((deathEnchant, level) -> {
if (deathEnchant.isOutOfCharges(weapon)) return;
if (deathEnchant.onKill(event, entity, killer, level)) {
deathEnchant.consumeChargesNoUpdate(weapon, level);
}
});
EnchantUtils.updateChargesDisplay(weapon);
}
// Handle BlockBreak enchantments.
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onEnchantBlockBreak(BlockBreakEvent e) {
Player player = e.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE) return;
ItemStack tool = player.getInventory().getItemInMainHand();
if (tool.getType().isAir() || tool.getType() == Material.ENCHANTED_BOOK) return;
EnchantUtils.getExcellents(tool, BlockBreakEnchant.class).forEach((blockEnchant, level) -> {
if (blockEnchant.isOutOfCharges(tool)) return;
if (blockEnchant.onBreak(e, player, tool, level)) {
blockEnchant.consumeChargesNoUpdate(tool, level);
}
});
EnchantUtils.updateChargesDisplay(tool);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onEnchantBlockDropItem(BlockDropItemEvent event) {
Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE) return;
ItemStack tool = player.getInventory().getItemInMainHand();
if (tool.getType().isAir() || tool.getType() == Material.ENCHANTED_BOOK) return;
//EnchantDropContainer dropContainer = new EnchantDropContainer(e);
EnchantUtils.getExcellents(tool, BlockDropEnchant.class).forEach((enchant, level) -> {
if (enchant.isOutOfCharges(tool)) return;
if (enchant.onDrop(event, player, tool, level)) {
enchant.consumeChargesNoUpdate(tool, level);
}
});
EnchantUtils.updateChargesDisplay(tool);
//BlockState state = e.getBlockState();
//World world = state.getWorld();
//Location location = state.getLocation();
//dropContainer.getDrop().forEach(item -> world.dropItem(location, item));
}
}