aboutsummaryrefslogtreecommitdiffstats
path: root/bukkit/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'bukkit/src/main/java/com')
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java10
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler.java6
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler20.java15
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler8.java5
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DealDamageTaskType.java8
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingTaskType.java6
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/MythicMobsDealDamageTaskType.java7
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Projectile2ItemCache.java80
8 files changed, 129 insertions, 8 deletions
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
index 00920e77..586ba55d 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
@@ -147,6 +147,7 @@ import com.leonardobishop.quests.bukkit.tasktype.type.dependent.uSkyBlockLevelTa
import com.leonardobishop.quests.bukkit.util.CompatUtils;
import com.leonardobishop.quests.bukkit.util.FormatUtils;
import com.leonardobishop.quests.bukkit.util.LogHistory;
+import com.leonardobishop.quests.bukkit.util.Projectile2ItemCache;
import com.leonardobishop.quests.common.config.ConfigProblem;
import com.leonardobishop.quests.common.config.ConfigProblemDescriptions;
import com.leonardobishop.quests.common.config.QuestsConfig;
@@ -226,6 +227,7 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests {
private QuestsBossBar bossBarHandle;
private QuestsActionBar actionBarHandle;
private VersionSpecificHandler versionSpecificHandler;
+ private Projectile2ItemCache projectile2ItemCache;
private LogHistory logHistory;
private WrappedTask questAutoSaveTask;
@@ -370,6 +372,10 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests {
};
}
+ // Instantiate Projectile to ItemStack cache
+ this.projectile2ItemCache = new Projectile2ItemCache();
+ this.projectile2ItemCache.registerEvents(this);
+
// Set item getter to be used by Quests config
this.questsConfig.setItemGetter(this.itemGetter);
@@ -972,6 +978,10 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests {
return versionSpecificHandler;
}
+ public Projectile2ItemCache getProjectile2ItemCache() {
+ return projectile2ItemCache;
+ }
+
public QuestItemRegistry getQuestItemRegistry() {
return questItemRegistry;
}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler.java
index 08db3e50..dacca889 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler.java
@@ -245,10 +245,14 @@ public interface VersionSpecificHandler {
/**
* {@link DamageSource}s were introduced in {@code 1.20.4}.
*/
- @SuppressWarnings("UnstableApiUsage")
@Nullable Player getDamager(@Nullable EntityDamageEvent lastDamageCause);
/**
+ * {@link DamageSource}s were introduced in {@code 1.20.4}.
+ */
+ @Nullable Entity getDirectSource(@Nullable EntityDamageEvent lastDamageCause);
+
+ /**
* {@link Tag#CANDLE_CAKES} was introduced in {@code 1.17}.
*/
boolean isCake(Material type);
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler20.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler20.java
index 5e7065dd..687da6fa 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler20.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler20.java
@@ -54,7 +54,6 @@ public class VersionSpecificHandler20 extends VersionSpecificHandler17 implement
}
}
- @SuppressWarnings("UnstableApiUsage")
@Override
public @Nullable Player getDamager(@Nullable EntityDamageEvent event) {
if (!DAMAGE_SOURCE_API) {
@@ -74,4 +73,18 @@ public class VersionSpecificHandler20 extends VersionSpecificHandler17 implement
return null;
}
+
+ @Override
+ public @Nullable Entity getDirectSource(@Nullable EntityDamageEvent event) {
+ if (!DAMAGE_SOURCE_API) {
+ return super.getDamager(event);
+ }
+
+ if (event == null) {
+ return null;
+ }
+
+ DamageSource source = event.getDamageSource();
+ return source.getDirectEntity();
+ }
}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler8.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler8.java
index 7e3e2ee4..55ab69ba 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler8.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/versionspecific/VersionSpecificHandler8.java
@@ -227,6 +227,11 @@ public class VersionSpecificHandler8 implements VersionSpecificHandler {
}
@Override
+ public @Nullable Entity getDirectSource(@Nullable EntityDamageEvent lastDamageCause) {
+ return null;
+ }
+
+ @Override
public boolean isCake(Material type) {
return type == Material.CAKE;
}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DealDamageTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DealDamageTaskType.java
index 469f6c50..be15175d 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DealDamageTaskType.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/DealDamageTaskType.java
@@ -45,9 +45,7 @@ public final class DealDamageTaskType extends BukkitTaskType {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityDamage(EntityDamageEvent event) {
- Entity entity = event.getEntity();
Player player = plugin.getVersionSpecificHandler().getDamager(event);
-
if (player == null || player.hasMetadata("NPC")) {
return;
}
@@ -57,10 +55,15 @@ public final class DealDamageTaskType extends BukkitTaskType {
return;
}
+ Entity entity = event.getEntity();
if (!(entity instanceof Damageable damageable)) {
return;
}
+ Entity directSource = plugin.getVersionSpecificHandler().getDirectSource(event);
+ ItemStack bowItem = directSource != null ? plugin.getProjectile2ItemCache().getItem(directSource) : null;
+ ItemStack item = bowItem != null ? bowItem : plugin.getVersionSpecificHandler().getItemInMainHand(player);
+
// Clamp entity damage as getDamage() returns Float.MAX_VALUE for killing a parrot with a cookie
// https://github.com/LMBishop/Quests/issues/753
double finalDamage = event.getFinalDamage();
@@ -87,7 +90,6 @@ public final class DealDamageTaskType extends BukkitTaskType {
}
if (task.hasConfigKey("item")) {
- ItemStack item = plugin.getVersionSpecificHandler().getItemInMainHand(player);
if (item == null) {
super.debug("Specific item is required, player has no item in hand; continuing...", quest.getId(), task.getId(), player.getUniqueId());
continue;
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingTaskType.java
index e38cc01f..6b843d89 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingTaskType.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/MobkillingTaskType.java
@@ -106,6 +106,11 @@ public final class MobkillingTaskType extends BukkitTaskType {
return;
}
+ EntityDamageEvent lastDamageCause = entity.getLastDamageCause();
+ Entity directSource = plugin.getVersionSpecificHandler().getDirectSource(lastDamageCause);
+ ItemStack bowItem = directSource != null ? plugin.getProjectile2ItemCache().getItem(directSource) : null;
+ ItemStack item = bowItem != null ? bowItem : plugin.getVersionSpecificHandler().getItemInMainHand(player);
+
//noinspection deprecation
String customName = entity.getCustomName();
@@ -144,7 +149,6 @@ public final class MobkillingTaskType extends BukkitTaskType {
}
if (task.hasConfigKey("item")) {
- ItemStack item = plugin.getVersionSpecificHandler().getItemInMainHand(player);
if (item == null) {
super.debug("Specific item is required, player has no item in hand; continuing...", quest.getId(), task.getId(), player.getUniqueId());
continue;
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/MythicMobsDealDamageTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/MythicMobsDealDamageTaskType.java
index cdd4578d..f322f856 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/MythicMobsDealDamageTaskType.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/dependent/MythicMobsDealDamageTaskType.java
@@ -100,7 +100,6 @@ public final class MythicMobsDealDamageTaskType extends BukkitTaskType {
}
private void handle(final EntityDamageEvent event, final String mobName, final double level) {
- Entity entity = event.getEntity();
Player player = plugin.getVersionSpecificHandler().getDamager(event);
if (player == null || player.hasMetadata("NPC")) {
@@ -112,10 +111,15 @@ public final class MythicMobsDealDamageTaskType extends BukkitTaskType {
return;
}
+ Entity entity = event.getEntity();
if (!(entity instanceof Damageable damageable)) {
return;
}
+ Entity directSource = plugin.getVersionSpecificHandler().getDirectSource(event);
+ ItemStack bowItem = directSource != null ? plugin.getProjectile2ItemCache().getItem(directSource) : null;
+ ItemStack item = bowItem != null ? bowItem : plugin.getVersionSpecificHandler().getItemInMainHand(player);
+
// Clamp entity damage as getDamage() returns Float.MAX_VALUE for killing a parrot with a cookie
// https://github.com/LMBishop/Quests/issues/753
double finalDamage = event.getFinalDamage();
@@ -147,7 +151,6 @@ public final class MythicMobsDealDamageTaskType extends BukkitTaskType {
}
if (task.hasConfigKey("item")) {
- ItemStack item = plugin.getVersionSpecificHandler().getItemInMainHand(player);
if (item == null) {
super.debug("Specific item is required, player has no item in hand; continuing...", quest.getId(), task.getId(), player.getUniqueId());
continue;
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Projectile2ItemCache.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Projectile2ItemCache.java
new file mode 100644
index 00000000..1b6b91e0
--- /dev/null
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/Projectile2ItemCache.java
@@ -0,0 +1,80 @@
+package com.leonardobishop.quests.bukkit.util;
+
+import com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent;
+import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Projectile;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityShootBowEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.PluginManager;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * Provides a cache that links projectiles to the item used to fire them.
+ *
+ * <p>This cache exists because damage-related events do not expose
+ * information about the item from which a projectile was fired.
+ * By capturing this association at the time the projectile is created,
+ * the item can later be retrieved when handling damage events.</p>
+ */
+@NullMarked
+public final class Projectile2ItemCache implements Listener {
+
+ private final Map<Entity, @Nullable ItemStack> backingMap;
+
+ public Projectile2ItemCache() {
+ this.backingMap = WeakHashMap.newWeakHashMap(1024);
+ }
+
+ public void registerEvents(final BukkitQuestsPlugin plugin) {
+ final PluginManager pluginManager = plugin.getServer().getPluginManager();
+
+ pluginManager.registerEvents(this, plugin);
+
+ try {
+ Class.forName("com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent");
+ pluginManager.registerEvents(new PlayerLaunchProjectileListener(), plugin);
+ } catch (final ClassNotFoundException e) {
+ // not supported on Spigot
+ }
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onEntityShootBow(final EntityShootBowEvent event) {
+ final LivingEntity shooter = event.getEntity();
+ final Entity projectile = event.getProjectile();
+ final ItemStack bow = event.getBow();
+
+ // Currently there are no advantages of caching projectiles for non-player arrows.
+ // It would be needed to cache these if we needed a task to take damage from mobs.
+ if (shooter instanceof Player) {
+ this.backingMap.put(projectile, bow);
+ }
+ }
+
+ public final class PlayerLaunchProjectileListener implements Listener {
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onPlayerLaunchProjectile(final PlayerLaunchProjectileEvent event) {
+ final Projectile projectile = event.getProjectile();
+ final ItemStack item = event.getItemStack();
+
+ // TODO: doesn't really work for tridents
+ // https://github.com/LMBishop/Quests/pull/833
+ Projectile2ItemCache.this.backingMap.put(projectile, item);
+ }
+ }
+
+ public @Nullable ItemStack getItem(final Entity projectile) {
+ return this.backingMap.get(projectile);
+ }
+}