@@ -135,6 +135,9 @@ class PlayerEventHandler implements Listener {
135135 private final Set <UUID > refundedEnderPearlEntities = ConcurrentHashMap .newKeySet ();
136136 // Track players who were just rolled back from denied pearl - prevents endermite spawn at rollback location
137137 private final Set <UUID > recentPearlRollbackPlayers = ConcurrentHashMap .newKeySet ();
138+ // Purpur etc: both events can fire; track which handler refunded to avoid double refund
139+ private final Set <UUID > refundedByTeleportEvent = ConcurrentHashMap .newKeySet ();
140+ private final Set <UUID > refundedByProjectileHitEvent = ConcurrentHashMap .newKeySet ();
138141
139142 // regex pattern for the "how do i claim land?" scanner
140143 private Pattern howToClaimPattern = null ;
@@ -1084,7 +1087,10 @@ public void onPlayerTeleport(PlayerTeleportEvent event) {
10841087 if (noAccessReason != null ) {
10851088 GriefPrevention .sendMessage (player , TextMode .Err , noAccessReason .get ());
10861089 event .setCancelled (true );
1087- if (cause == TeleportCause .ENDER_PEARL && instance .config_claims_refundDeniedEnderPearls ) {
1090+ if (cause == TeleportCause .ENDER_PEARL && instance .config_claims_refundDeniedEnderPearls
1091+ && !refundedByProjectileHitEvent .contains (player .getUniqueId ())) {
1092+ refundedByTeleportEvent .add (player .getUniqueId ());
1093+ SchedulerUtil .runLaterGlobal (instance , () -> refundedByTeleportEvent .remove (player .getUniqueId ()), 15L );
10881094 player .getInventory ().addItem (new ItemStack (Material .ENDER_PEARL ));
10891095 }
10901096 return ; // Don't update lastClaim when teleport is cancelled
@@ -1141,9 +1147,13 @@ public void onProjectileHitEnderPearlCancel(ProjectileHitEvent event) {
11411147 ClaimPermission .Access , null );
11421148 if (noAccessReason != null ) {
11431149 event .setCancelled (true );
1150+ // Skip refund if PlayerTeleportEvent already refunded (Purpur etc have both events fire)
1151+ if (refundedByTeleportEvent .contains (shooter .getUniqueId ())) return ;
11441152 // Only message/refund once - ProjectileHitEvent can fire multiple times when pearl hits entity
11451153 UUID pearlID = event .getEntity ().getUniqueId ();
11461154 if (refundedEnderPearlEntities .add (pearlID )) {
1155+ refundedByProjectileHitEvent .add (shooter .getUniqueId ());
1156+ SchedulerUtil .runLaterGlobal (instance , () -> refundedByProjectileHitEvent .remove (shooter .getUniqueId ()), 15L );
11471157 recentPearlRollbackPlayers .add (shooter .getUniqueId ());
11481158 SchedulerUtil .runLaterGlobal (instance , () -> recentPearlRollbackPlayers .remove (shooter .getUniqueId ()), 20L );
11491159 GriefPrevention .sendMessage (shooter , TextMode .Err , noAccessReason .get ());
0 commit comments