From 72e3a3a98df22d1b27a29c3cf3a39355b2bc6aa8 Mon Sep 17 00:00:00 2001 From: Nico Sendan <76180677+YoshiroMaximus@users.noreply.github.com> Date: Sat, 20 Jun 2026 11:27:18 -0700 Subject: [PATCH 1/2] Fix: Resolve EntityMountEvent registration failure on modern Paper Newer Paper builds (e.g. 26.1.2) removed org.spigotmc.event.entity.EntityMountEvent, causing KnockbackRegionController registration to fail and region knockback protection to be disabled. Resolve EntityMountEvent at runtime (checking Bukkit, Paper, and Spigot packages) and register it reflectively while preserving the 1.19.3 compile target for compatibility. --- .DS_Store | Bin 0 -> 10244 bytes eternalcombat-plugin/.DS_Store | Bin 0 -> 8196 bytes .../com/eternalcode/combat/CombatPlugin.java | 3 + .../knockback/KnockbackMountController.java | 101 ++++++++++++++++++ .../knockback/KnockbackRegionController.java | 22 ---- 5 files changed, 104 insertions(+), 22 deletions(-) create mode 100644 .DS_Store create mode 100644 eternalcombat-plugin/.DS_Store create mode 100644 eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackMountController.java diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..1572514500288e273ff8e97bbc7f894e57c31ffb GIT binary patch literal 10244 zcmeHMYitx%6u#%Szzk*R6p9uYVCbq8X>}>@hh*C=D&g>+gPMFTro!Q-D zB`FaxfoO~merXg<{6+8;6B8tAqK4ozrZFPM82#Z7qwxp$(|GRO8PYCd&;$cvZgTIL zd+t5=?m7E?bN1dPgg|RSUrLBd2obO{DNn=ZZweb{^|C?(4I2csCq&Pd+@Y-HWG|Z= zDWV8O5r`rXMIeem6oKm_0+_Q|5vsV1+9(211fmFBiU4~*s92dy1ag#1|J8wwe*{2T ziE6*#GoAx{8#R!LK#p?ho8p@M^Z<7BkvoSx`9)6cbm5ElvxY+s}3}(BWs%Djq36>%?A#M!mQZc>pJ`PS%bE7ggXJji-1UFP92@- zk>wVX{6?Z88+vp;@JJA+R!x(pD^hP}*Y3=o9y90IDf3~YPp)>+u}#?Bo;Qls{(=#2rx5qPvy>RUb zLp>SS$$LqE{fsu8zBF$J+qh$hnY%lUyo)lHh;whnlht+V?ThbPw)&oyd)v2lj>$DM zX4cM5+XRfTwQx=3n zv*pqVx z2hmBF>ypYwK|UkwWgBnNT(4uuu)~j(R5l4h#vRb|Mn?&;7+P!<1phlmJu}&;o1T;B z(WqB;2tqGgtVP#x9eK{&*{QUm;J0krMH7*a-vcLr{FNXGVl2d8EO94)jJ>b@;6M41 zt_{Zn$uivn(m>XdR_X64yH1kiN~EVarXcjC`BIB0 z%EaF!*@nw7vRwn%e@}iUzmkgp2>Y2(2lJp2p}r1U5auc9La6sb2BB_1KMa5gdGMeJ zB?SIKcoZIk!|*sf1y94X@EjaN*dK?N;T1RmClUH@Aox$gyKoxbgEMdzK84TVb0oo+ zNP-`c0>78RdRrN+8QjOgx|qt_mSgv$mW|XBgLqi;#3mXh(HwEeAf{9ewM}FQH3ia- zM7PIXj^D`1^{V}iQg4)cqtyF9rrv+U%qTI3KU1T`{Exp!ulK}!)u1m++Y@vA&Dg8p zPOI$xf8&+^|GybS6ZsrP;HHTHRJNtsTG8F`SYPfryK7gmK7f@KHgA+m-vk@~Iv%Be z9giJ$uh@W<%?<9X{O3fV8|BhB$2q<^N`9Mv&HoGtujT&R-CK12kIw%${Q3Vc^}D;O literal 0 HcmV?d00001 diff --git a/eternalcombat-plugin/.DS_Store b/eternalcombat-plugin/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3d32d9669eea0f70cd7336a398f5077b14a16a77 GIT binary patch literal 8196 zcmeHMYitx%6u#%Szzk*REe|a)z|d7&r07!K56QM$RLY~!-O_e>)Y+Y}oiLrLJF~mR zN>U15xCMHPKL=C}bOk+fhG5W(FM&l3gr}5mmv!pHd4~fRcxyjr! z_uPB#opa{2!WP@v5JsdLWqPHm#hk_zbU+*UpEvQYAR6z+7n`AOWt7CcC$B( zjTBJ?q6kD0h$0Y0Ad0|$BLaA4^CC@h?u*{2jv^36;C~qbzCUPqahV9^h>*e7fmM(K zpyVk)Q1Bk}fWSrzWg?U#LI$Qdr^p^4G=(t50AY^(8Xt}_5y}xEg*gFXP9R(v!VCq1 z)zMB1h7(8#8P!n)q6pj=0ZyN3Bufg!BKEla{hjQfZFzn?{x#5w%4ySQV5ypMFxBst zQoimNycRvbpSRMkYiG;%dUl^>mU`K|r0e*)<(T=vz%oo6a-hp{47b$c797J1Y*V5` z#?s4bhle+;Thpkmi?2W0s10vyiZ^O&HZ~nSDogWYcW>_KJ!}s+?n&VUgc|`-COCC! zyhpZIOo}fO71^>!S3-{@d1lotWwxsHWcDA(9PGAou9LDJHhWpMhmLK>=AOJ+M2EU^ zu3Z>#yk1t5)9qZr)_t?tw)tSxv4UrIn5eUgW-Iofs@lutUEAK{dX{gwPEWUQ4*BJ| z$8~jQJU8zrgZVT1Q2P3~Ieg*vL2mBtGxHwGSRyXGmCsezYPT=HYxRbEn(uAf-7(5) z=FFWpUr{m`P{+3(w9I^G$uj)@9^K2Cj$t`{T}8{YvbLFa^Z~O58fAHO!NNsMU92uG zcTF^rSWN0JWUYq^mVab)Zp|E~)Ty`0>}~0Qfqw3C4Ze~Q^r&@egCyPngEQrg2A-D@7 zJ+Is!N`BHUB@JW~X(9WNb;IO1IZe)xv*ZJEiF`u7B|nkh$W`(uOou9%4b{M40W5=h zSOrb62G+t>xDW1!HrN5(phFgN;KC3bfnj(Aj=@Pd1y8_}@C-Z;FTjiN61)np!RzoQ zyangsL-+_jhA-e7xC~d|JNN~z!ZrAV0-Z^#=q$Q~*3$;MoUW!@Xgl3YJ7|igX(v5I z`{*Do2p?#fdxysRMo(aS%x;3*3%>@^3zKk9Q?|G5*x9ygDsk^}wP4#Vx7IGZV?})J z#;q;aF)1KiM(tQO1OymIn}7fTMkaz6d8sa5qG+AS5OZiEE6Z$UGdPPSj$5@Zrf6&$ za!54m8?ZSY`6HT*D>aQ#q^)SKYSI)|fusy}0Cn9;Y(m)Bv{_MDCDKzKRT28i5~W#| z83`6iw&FCLZ2ti4zb8MFU&%E9g#BEog~iZ_P~QyA2=f$lBGh{zgHSi25BkA^Jor$A z5(57iJPMD&33wcyf~VnGcn(e@?9af<@CuxTa|r!65d7!iUAO@6!9}w|LOf?J&;Peg{{4T7coRKl6oDuL zHxmJB|6z#t8V=<)iBOIRi5e{b X`iFqAKg)0Kw|8{@N9X^PKmY#%RjP%V literal 0 HcmV?d00001 diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/CombatPlugin.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/CombatPlugin.java index d491fba0..4385582c 100644 --- a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/CombatPlugin.java +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/CombatPlugin.java @@ -40,6 +40,7 @@ import com.eternalcode.combat.fight.effect.FightEffectService; import com.eternalcode.combat.fight.effect.FightEffectServiceImpl; import com.eternalcode.combat.fight.firework.FireworkController; +import com.eternalcode.combat.fight.knockback.KnockbackMountController; import com.eternalcode.combat.fight.knockback.KnockbackRegionController; import com.eternalcode.combat.fight.knockback.KnockbackService; import com.eternalcode.combat.fight.logout.LogoutController; @@ -211,6 +212,8 @@ public void onEnable() { new PlaceBlockBlocker(this.fightManager, noticeService, pluginConfig) ); + new KnockbackMountController(noticeService, this.regionProvider, this.fightManager).register(this); + eventManager.subscribe( PlayerDeathEvent.class, pluginConfig.drop.dropEventPriority, diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackMountController.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackMountController.java new file mode 100644 index 00000000..36c758ea --- /dev/null +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackMountController.java @@ -0,0 +1,101 @@ +package com.eternalcode.combat.fight.knockback; + +import com.eternalcode.combat.fight.FightManager; +import com.eternalcode.combat.notification.NoticeService; +import com.eternalcode.combat.region.RegionProvider; +import java.lang.reflect.Method; +import java.util.logging.Level; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityEvent; +import org.bukkit.plugin.Plugin; + +// EntityMountEvent moved between org.spigotmc, io.papermc.paper and org.bukkit across versions, +// so we resolve it at runtime to stay compatible without bumping the compile API. +public final class KnockbackMountController implements Listener { + + private static final String[] EVENT_CLASS_CANDIDATES = { + "org.bukkit.event.entity.EntityMountEvent", + "io.papermc.paper.event.entity.EntityMountEvent", + "org.spigotmc.event.entity.EntityMountEvent", + }; + + private final NoticeService noticeService; + private final RegionProvider regionProvider; + private final FightManager fightManager; + + public KnockbackMountController(NoticeService noticeService, RegionProvider regionProvider, FightManager fightManager) { + this.noticeService = noticeService; + this.regionProvider = regionProvider; + this.fightManager = fightManager; + } + + @SuppressWarnings("unchecked") + public void register(Plugin plugin) { + Class eventClass = null; + for (String candidate : EVENT_CLASS_CANDIDATES) { + try { + eventClass = (Class) Class.forName(candidate); + break; + } catch (ClassNotFoundException ignored) { + } + } + + if (eventClass == null) { + plugin.getLogger().warning("Could not find any EntityMountEvent class; mount protection in regions is disabled."); + return; + } + + Method getMount; + try { + getMount = eventClass.getMethod("getMount"); + } catch (NoSuchMethodException exception) { + plugin.getLogger().log(Level.WARNING, "EntityMountEvent has no getMount() method; mount protection in regions is disabled.", exception); + return; + } + + plugin.getServer().getPluginManager().registerEvent( + eventClass, + this, + EventPriority.HIGHEST, + (listener, event) -> this.handle(event, getMount), + plugin, + true + ); + } + + private void handle(Event event, Method getMount) { + if (!(event instanceof EntityEvent entityEvent) || !(event instanceof Cancellable cancellable)) { + return; + } + + if (!(entityEvent.getEntity() instanceof Player player)) { + return; + } + + if (!this.fightManager.isInCombat(player.getUniqueId())) { + return; + } + + Entity mount; + try { + mount = (Entity) getMount.invoke(event); + } catch (ReflectiveOperationException exception) { + return; + } + + if (mount == null || !this.regionProvider.isInRegion(mount.getLocation())) { + return; + } + + cancellable.setCancelled(true); + this.noticeService.create() + .player(player.getUniqueId()) + .notice(config -> config.messagesSettings.cantEnterOnRegion) + .send(); + } +} diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackRegionController.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackRegionController.java index 109e8cd7..589b0c41 100644 --- a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackRegionController.java +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackRegionController.java @@ -17,7 +17,6 @@ import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.vehicle.VehicleMoveEvent; -import org.spigotmc.event.entity.EntityMountEvent; public class KnockbackRegionController implements Listener { @@ -132,27 +131,6 @@ void onVehicleMove(VehicleMoveEvent event) { } } - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) - void onEntityMount(EntityMountEvent event) { - if (!(event.getEntity() instanceof Player player)) { - return; - } - - if (!this.fightManager.isInCombat(player.getUniqueId())) { - return; - } - - if (!this.regionProvider.isInRegion(event.getMount().getLocation())) { - return; - } - - event.setCancelled(true); - this.noticeService.create() - .player(player.getUniqueId()) - .notice(config -> config.messagesSettings.cantEnterOnRegion) - .send(); - } - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) void onTag(FightTagEvent event) { Player player = this.server.getPlayer(event.getPlayer()); From caa11572aa60abdad5add5a3c7d9a85d6bd90c3c Mon Sep 17 00:00:00 2001 From: Martin Sulikowski Date: Sun, 21 Jun 2026 15:26:42 +0200 Subject: [PATCH 2/2] Optimize dynamic mount event handling --- .DS_Store | Bin 10244 -> 0 bytes eternalcombat-plugin/.DS_Store | Bin 8196 -> 0 bytes .../knockback/KnockbackMountController.java | 50 ++++++++++++++---- 3 files changed, 39 insertions(+), 11 deletions(-) delete mode 100644 .DS_Store delete mode 100644 eternalcombat-plugin/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 1572514500288e273ff8e97bbc7f894e57c31ffb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMYitx%6u#%Szzk*R6p9uYVCbq8X>}>@hh*C=D&g>+gPMFTro!Q-D zB`FaxfoO~merXg<{6+8;6B8tAqK4ozrZFPM82#Z7qwxp$(|GRO8PYCd&;$cvZgTIL zd+t5=?m7E?bN1dPgg|RSUrLBd2obO{DNn=ZZweb{^|C?(4I2csCq&Pd+@Y-HWG|Z= zDWV8O5r`rXMIeem6oKm_0+_Q|5vsV1+9(211fmFBiU4~*s92dy1ag#1|J8wwe*{2T ziE6*#GoAx{8#R!LK#p?ho8p@M^Z<7BkvoSx`9)6cbm5ElvxY+s}3}(BWs%Djq36>%?A#M!mQZc>pJ`PS%bE7ggXJji-1UFP92@- zk>wVX{6?Z88+vp;@JJA+R!x(pD^hP}*Y3=o9y90IDf3~YPp)>+u}#?Bo;Qls{(=#2rx5qPvy>RUb zLp>SS$$LqE{fsu8zBF$J+qh$hnY%lUyo)lHh;whnlht+V?ThbPw)&oyd)v2lj>$DM zX4cM5+XRfTwQx=3n zv*pqVx z2hmBF>ypYwK|UkwWgBnNT(4uuu)~j(R5l4h#vRb|Mn?&;7+P!<1phlmJu}&;o1T;B z(WqB;2tqGgtVP#x9eK{&*{QUm;J0krMH7*a-vcLr{FNXGVl2d8EO94)jJ>b@;6M41 zt_{Zn$uivn(m>XdR_X64yH1kiN~EVarXcjC`BIB0 z%EaF!*@nw7vRwn%e@}iUzmkgp2>Y2(2lJp2p}r1U5auc9La6sb2BB_1KMa5gdGMeJ zB?SIKcoZIk!|*sf1y94X@EjaN*dK?N;T1RmClUH@Aox$gyKoxbgEMdzK84TVb0oo+ zNP-`c0>78RdRrN+8QjOgx|qt_mSgv$mW|XBgLqi;#3mXh(HwEeAf{9ewM}FQH3ia- zM7PIXj^D`1^{V}iQg4)cqtyF9rrv+U%qTI3KU1T`{Exp!ulK}!)u1m++Y@vA&Dg8p zPOI$xf8&+^|GybS6ZsrP;HHTHRJNtsTG8F`SYPfryK7gmK7f@KHgA+m-vk@~Iv%Be z9giJ$uh@W<%?<9X{O3fV8|BhB$2q<^N`9Mv&HoGtujT&R-CK12kIw%${Q3Vc^}D;O diff --git a/eternalcombat-plugin/.DS_Store b/eternalcombat-plugin/.DS_Store deleted file mode 100644 index 3d32d9669eea0f70cd7336a398f5077b14a16a77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMYitx%6u#%Szzk*REe|a)z|d7&r07!K56QM$RLY~!-O_e>)Y+Y}oiLrLJF~mR zN>U15xCMHPKL=C}bOk+fhG5W(FM&l3gr}5mmv!pHd4~fRcxyjr! z_uPB#opa{2!WP@v5JsdLWqPHm#hk_zbU+*UpEvQYAR6z+7n`AOWt7CcC$B( zjTBJ?q6kD0h$0Y0Ad0|$BLaA4^CC@h?u*{2jv^36;C~qbzCUPqahV9^h>*e7fmM(K zpyVk)Q1Bk}fWSrzWg?U#LI$Qdr^p^4G=(t50AY^(8Xt}_5y}xEg*gFXP9R(v!VCq1 z)zMB1h7(8#8P!n)q6pj=0ZyN3Bufg!BKEla{hjQfZFzn?{x#5w%4ySQV5ypMFxBst zQoimNycRvbpSRMkYiG;%dUl^>mU`K|r0e*)<(T=vz%oo6a-hp{47b$c797J1Y*V5` z#?s4bhle+;Thpkmi?2W0s10vyiZ^O&HZ~nSDogWYcW>_KJ!}s+?n&VUgc|`-COCC! zyhpZIOo}fO71^>!S3-{@d1lotWwxsHWcDA(9PGAou9LDJHhWpMhmLK>=AOJ+M2EU^ zu3Z>#yk1t5)9qZr)_t?tw)tSxv4UrIn5eUgW-Iofs@lutUEAK{dX{gwPEWUQ4*BJ| z$8~jQJU8zrgZVT1Q2P3~Ieg*vL2mBtGxHwGSRyXGmCsezYPT=HYxRbEn(uAf-7(5) z=FFWpUr{m`P{+3(w9I^G$uj)@9^K2Cj$t`{T}8{YvbLFa^Z~O58fAHO!NNsMU92uG zcTF^rSWN0JWUYq^mVab)Zp|E~)Ty`0>}~0Qfqw3C4Ze~Q^r&@egCyPngEQrg2A-D@7 zJ+Is!N`BHUB@JW~X(9WNb;IO1IZe)xv*ZJEiF`u7B|nkh$W`(uOou9%4b{M40W5=h zSOrb62G+t>xDW1!HrN5(phFgN;KC3bfnj(Aj=@Pd1y8_}@C-Z;FTjiN61)np!RzoQ zyangsL-+_jhA-e7xC~d|JNN~z!ZrAV0-Z^#=q$Q~*3$;MoUW!@Xgl3YJ7|igX(v5I z`{*Do2p?#fdxysRMo(aS%x;3*3%>@^3zKk9Q?|G5*x9ygDsk^}wP4#Vx7IGZV?})J z#;q;aF)1KiM(tQO1OymIn}7fTMkaz6d8sa5qG+AS5OZiEE6Z$UGdPPSj$5@Zrf6&$ za!54m8?ZSY`6HT*D>aQ#q^)SKYSI)|fusy}0Cn9;Y(m)Bv{_MDCDKzKRT28i5~W#| z83`6iw&FCLZ2ti4zb8MFU&%E9g#BEog~iZ_P~QyA2=f$lBGh{zgHSi25BkA^Jor$A z5(57iJPMD&33wcyf~VnGcn(e@?9af<@CuxTa|r!65d7!iUAO@6!9}w|LOf?J&;Peg{{4T7coRKl6oDuL zHxmJB|6z#t8V=<)iBOIRi5e{b X`iFqAKg)0Kw|8{@N9X^PKmY#%RjP%V diff --git a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackMountController.java b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackMountController.java index 36c758ea..e60f851f 100644 --- a/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackMountController.java +++ b/eternalcombat-plugin/src/main/java/com/eternalcode/combat/fight/knockback/KnockbackMountController.java @@ -3,7 +3,11 @@ import com.eternalcode.combat.fight.FightManager; import com.eternalcode.combat.notification.NoticeService; import com.eternalcode.combat.region.RegionProvider; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.Method; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -27,6 +31,7 @@ public final class KnockbackMountController implements Listener { private final NoticeService noticeService; private final RegionProvider regionProvider; private final FightManager fightManager; + private final AtomicBoolean mountFailureLogged = new AtomicBoolean(); public KnockbackMountController(NoticeService noticeService, RegionProvider regionProvider, FightManager fightManager) { this.noticeService = noticeService; @@ -34,14 +39,13 @@ public KnockbackMountController(NoticeService noticeService, RegionProvider regi this.fightManager = fightManager; } - @SuppressWarnings("unchecked") public void register(Plugin plugin) { Class eventClass = null; for (String candidate : EVENT_CLASS_CANDIDATES) { try { - eventClass = (Class) Class.forName(candidate); + eventClass = Class.forName(candidate).asSubclass(Event.class); break; - } catch (ClassNotFoundException ignored) { + } catch (ClassNotFoundException | ClassCastException ignored) { } } @@ -50,11 +54,11 @@ public void register(Plugin plugin) { return; } - Method getMount; + MethodHandle getMountHandle; try { - getMount = eventClass.getMethod("getMount"); - } catch (NoSuchMethodException exception) { - plugin.getLogger().log(Level.WARNING, "EntityMountEvent has no getMount() method; mount protection in regions is disabled.", exception); + getMountHandle = this.resolveGetMountHandle(eventClass); + } catch (NoSuchMethodException | IllegalAccessException exception) { + plugin.getLogger().log(Level.WARNING, "EntityMountEvent has incompatible getMount() method; mount protection in regions is disabled.", exception); return; } @@ -62,13 +66,28 @@ public void register(Plugin plugin) { eventClass, this, EventPriority.HIGHEST, - (listener, event) -> this.handle(event, getMount), + (listener, event) -> this.handle(event, getMountHandle, plugin), plugin, true ); } - private void handle(Event event, Method getMount) { + private MethodHandle resolveGetMountHandle(Class eventClass) throws NoSuchMethodException, IllegalAccessException { + if (!EntityEvent.class.isAssignableFrom(eventClass) || !Cancellable.class.isAssignableFrom(eventClass)) { + throw new NoSuchMethodException(eventClass.getName() + " is not a cancellable entity event"); + } + + Method getMount = eventClass.getMethod("getMount"); + if (!Entity.class.isAssignableFrom(getMount.getReturnType())) { + throw new NoSuchMethodException(eventClass.getName() + "#getMount() does not return Entity"); + } + + return MethodHandles.publicLookup() + .unreflect(getMount) + .asType(MethodType.methodType(Entity.class, Event.class)); + } + + private void handle(Event event, MethodHandle getMountHandle, Plugin plugin) { if (!(event instanceof EntityEvent entityEvent) || !(event instanceof Cancellable cancellable)) { return; } @@ -83,8 +102,9 @@ private void handle(Event event, Method getMount) { Entity mount; try { - mount = (Entity) getMount.invoke(event); - } catch (ReflectiveOperationException exception) { + mount = (Entity) getMountHandle.invokeExact(event); + } catch (Throwable exception) { + this.logMountFailure(plugin, exception); return; } @@ -98,4 +118,12 @@ private void handle(Event event, Method getMount) { .notice(config -> config.messagesSettings.cantEnterOnRegion) .send(); } + + private void logMountFailure(Plugin plugin, Throwable exception) { + if (!this.mountFailureLogged.compareAndSet(false, true)) { + return; + } + + plugin.getLogger().log(Level.WARNING, "Could not read EntityMountEvent mount; mount protection in regions is skipped.", exception); + } }