From 6f9feab159c4e931724d2a21d250b7d6b5eeee21 Mon Sep 17 00:00:00 2001 From: SrBedrock <51332006+SrBedrock@users.noreply.github.com> Date: Fri, 3 Apr 2026 19:40:58 -0300 Subject: [PATCH 1/5] Use Location for integration canLeash checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor integration permission checks to use Location instead of LivingEntity. Changed Integration.canLeash(Location, Player) and updated IntegrationManager, all integration implementations (WorldGuard, GriefDefender, GriefPrevention, Lands, Residence, Towny) and callers to pass a Location (e.g. entity.getLocation() or target.getLocation()). Also updated Tether event registration to supply integrationManager to PlayerInteractListener and made various cosmetic adjustments (added final modifiers and small local refactors). No functional behavior changes intended—this decouples integrations from entity objects and centralizes location-based permission checks. --- src/main/java/dev/naspo/tether/Tether.java | 2 +- .../tether/integrations/Integration.java | 14 ++-- .../WorldGuardIntegration.java | 24 +++---- .../GriefDefenderIntegration.java | 8 +-- .../GriefPreventionIntegration.java | 7 +- .../LandsIntegration.java | 9 +-- .../ResidenceIntegration.java | 10 +-- .../TownyIntegration.java | 11 +-- .../tether/services/IntegrationManager.java | 11 +-- .../tether/services/LeashMobService.java | 68 +++++++++---------- .../tether/services/LeashPlayerService.java | 20 +++--- 11 files changed, 95 insertions(+), 89 deletions(-) diff --git a/src/main/java/dev/naspo/tether/Tether.java b/src/main/java/dev/naspo/tether/Tether.java index a57cef1..386d3a8 100644 --- a/src/main/java/dev/naspo/tether/Tether.java +++ b/src/main/java/dev/naspo/tether/Tether.java @@ -46,7 +46,7 @@ private void instantiateClasses() { private void registerEvents() { this.getServer().getPluginManager().registerEvents(new PlayerInteractAtEntityListener(this, leashMobService, leashPlayerService), this); - this.getServer().getPluginManager().registerEvents(new PlayerInteractListener(leashMobService), this); + this.getServer().getPluginManager().registerEvents(new PlayerInteractListener(leashMobService, integrationManager), this); this.getServer().getPluginManager().registerEvents(new PlayerLeashEntityListener(leashMobService), this); this.getServer().getPluginManager().registerEvents(new EntityDeathListener(), this); this.getServer().getPluginManager().registerEvents(new EntityDismountListener(this, leashPlayerService), this); diff --git a/src/main/java/dev/naspo/tether/integrations/Integration.java b/src/main/java/dev/naspo/tether/integrations/Integration.java index 271175f..3850678 100644 --- a/src/main/java/dev/naspo/tether/integrations/Integration.java +++ b/src/main/java/dev/naspo/tether/integrations/Integration.java @@ -1,7 +1,7 @@ package dev.naspo.tether.integrations; import dev.naspo.tether.Tether; -import org.bukkit.entity.LivingEntity; +import org.bukkit.Location; import org.bukkit.entity.Player; public abstract class Integration { @@ -9,7 +9,7 @@ public abstract class Integration { protected final String pluginName; protected boolean enabled = false; - public Integration(Tether tetherPlugin, String pluginName) { + public Integration(final Tether tetherPlugin, final String pluginName) { this.tetherPlugin = tetherPlugin; this.pluginName = pluginName; } @@ -43,11 +43,11 @@ public boolean isEnabled() { } /** - * Checks if the clicked LivingEntity can be leashed based on this integration. + * Checks if a mob can be leashed at the given location based on this integration. * - * @param clicked The clicked LivingEntity. (Includes Player). - * @param player The player trying to leash. - * @return true if the player is permitted to leash the clicked LivingEntity. + * @param location The location the mob is trying to be leashed at. + * @param player The player trying to leash. + * @return true if the player is permitted to leash a mob at the given location. */ - public abstract boolean canLeash(LivingEntity clicked, Player player); + public abstract boolean canLeash(Location location, Player player); } diff --git a/src/main/java/dev/naspo/tether/integrations/standardintegrations/WorldGuardIntegration.java b/src/main/java/dev/naspo/tether/integrations/standardintegrations/WorldGuardIntegration.java index 13322b8..393ab91 100644 --- a/src/main/java/dev/naspo/tether/integrations/standardintegrations/WorldGuardIntegration.java +++ b/src/main/java/dev/naspo/tether/integrations/standardintegrations/WorldGuardIntegration.java @@ -23,7 +23,7 @@ public class WorldGuardIntegration extends Integration { private FlagRegistry flagRegistry; private StateFlag leashFlag; - public WorldGuardIntegration(Tether tetherPlugin) { + public WorldGuardIntegration(final Tether tetherPlugin) { super(tetherPlugin, "WorldGuard"); } @@ -35,23 +35,23 @@ protected boolean onEnable() { } @Override - public boolean canLeash(LivingEntity clicked, Player player) { + public boolean canLeash(final Location location, final Player player) { // WorldGuard uses their own custom Player, Location, and World objects, so I am converting them here. - LocalPlayer wgLocalPlayer = WorldGuardPlugin.inst().wrapPlayer(player); - com.sk89q.worldedit.util.Location wgClickedLocation = BukkitAdapter.adapt(clicked.getLocation()); - com.sk89q.worldedit.world.World wgClickedWorld = BukkitAdapter.adapt(clicked.getWorld()); + final LocalPlayer wgLocalPlayer = WorldGuardPlugin.inst().wrapPlayer(player); + final com.sk89q.worldedit.util.Location wgLocation = BukkitAdapter.adapt(location); + final com.sk89q.worldedit.world.World wgWorld = BukkitAdapter.adapt(location.getWorld()); // If they have WorldGuard region bypass permission, return true. - boolean canBypass = worldGuardAPI.getPlatform().getSessionManager().hasBypass(wgLocalPlayer, wgClickedWorld); + final boolean canBypass = worldGuardAPI.getPlatform().getSessionManager().hasBypass(wgLocalPlayer, wgWorld); if (canBypass) { return true; } // Region data can be accessed via the RegionContainer object. - RegionContainer regionContainer = worldGuardAPI.getPlatform().getRegionContainer(); + final RegionContainer regionContainer = worldGuardAPI.getPlatform().getRegionContainer(); - // Query the state of our custom leash StateFlag at the clicked entity's location for a player. - return regionContainer.createQuery().testState(wgClickedLocation, wgLocalPlayer, leashFlag); + // Query the state of our custom leash StateFlag at the location for a player. + return regionContainer.createQuery().testState(wgLocation, wgLocalPlayer, leashFlag); } /** @@ -63,13 +63,13 @@ private boolean registerLeashFlag() { final String LEASH_FLAG_STRING = "leash"; try { - StateFlag stateFlag = new StateFlag(LEASH_FLAG_STRING, true); + final StateFlag stateFlag = new StateFlag(LEASH_FLAG_STRING, true); flagRegistry.register(stateFlag); this.leashFlag = stateFlag; return true; - } catch (FlagConflictException e) { + } catch (final FlagConflictException e) { // If there is a flag conflict, log that as an error to the console. - Flag flag = flagRegistry.get(LEASH_FLAG_STRING); + final Flag flag = flagRegistry.get(LEASH_FLAG_STRING); if (flag != null) { tetherPlugin.getLogger().warning("Couldn't register the 'leash' WorldGuard flag! It looks like another " + "plugin registered it. WorldGuard integration with Tether will not work."); diff --git a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefDefenderIntegration.java b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefDefenderIntegration.java index c5a1455..537c358 100644 --- a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefDefenderIntegration.java +++ b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefDefenderIntegration.java @@ -5,13 +5,13 @@ import com.griefdefender.api.claim.Claim; import com.griefdefender.api.claim.TrustTypes; import dev.naspo.tether.Tether; -import org.bukkit.entity.LivingEntity; +import org.bukkit.Location; import org.bukkit.entity.Player; public class GriefDefenderIntegration extends ToggleableIntegration { private Core griefDefenderAPI; - public GriefDefenderIntegration(Tether tetherPlugin) { + public GriefDefenderIntegration(final Tether tetherPlugin) { super(tetherPlugin, "GriefDefender", "griefdefender"); } @@ -22,8 +22,8 @@ protected boolean onEnable() { } @Override - public boolean canLeash(LivingEntity clicked, Player player) { - Claim claim = griefDefenderAPI.getClaimAt(clicked.getLocation()); + public boolean canLeash(final Location location, final Player player) { + final Claim claim = griefDefenderAPI.getClaimAt(location); if (claim != null) { if (claim.isWilderness()) { diff --git a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefPreventionIntegration.java b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefPreventionIntegration.java index d4e75b4..36876df 100644 --- a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefPreventionIntegration.java +++ b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefPreventionIntegration.java @@ -5,13 +5,14 @@ import me.ryanhamshire.GriefPrevention.ClaimPermission; import me.ryanhamshire.GriefPrevention.DataStore; import me.ryanhamshire.GriefPrevention.GriefPrevention; +import org.bukkit.Location; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; public class GriefPreventionIntegration extends ToggleableIntegration { private DataStore dataStore; - public GriefPreventionIntegration(Tether tetherPlugin) { + public GriefPreventionIntegration(final Tether tetherPlugin) { super(tetherPlugin, "GriefPrevention", "griefprevention"); } @@ -22,8 +23,8 @@ protected boolean onEnable() { } @Override - public boolean canLeash(LivingEntity clicked, Player player) { - Claim claim = dataStore.getClaimAt(clicked.getLocation(), true, null); + public boolean canLeash(final Location location, final Player player) { + final Claim claim = dataStore.getClaimAt(location, true, null); // If there is a claim here, return true if the player has explicit permission or is ignoring claims. if (claim != null) { return claim.hasExplicitPermission(player.getUniqueId(), ClaimPermission.Access) || diff --git a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/LandsIntegration.java b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/LandsIntegration.java index acddd85..ab01d84 100644 --- a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/LandsIntegration.java +++ b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/LandsIntegration.java @@ -3,13 +3,14 @@ import dev.naspo.tether.Tether; import me.angeschossen.lands.api.land.Area; import me.angeschossen.lands.api.land.Land; +import org.bukkit.Location; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; public class LandsIntegration extends ToggleableIntegration { private me.angeschossen.lands.api.LandsIntegration landsAPI; - public LandsIntegration(Tether tetherPlugin) { + public LandsIntegration(final Tether tetherPlugin) { super(tetherPlugin, "Lands", "lands"); } @@ -20,10 +21,10 @@ protected boolean onEnable() { } @Override - public boolean canLeash(LivingEntity clicked, Player player) { - Area area = landsAPI.getArea(clicked.getLocation()); + public boolean canLeash(final Location location, final Player player) { + final Area area = landsAPI.getArea(location); if (area != null) { - Land land = area.getLand(); + final Land land = area.getLand(); return land.getTrustedPlayers().contains(player.getUniqueId()); } return true; diff --git a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/ResidenceIntegration.java b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/ResidenceIntegration.java index b292b8e..5b86d56 100644 --- a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/ResidenceIntegration.java +++ b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/ResidenceIntegration.java @@ -4,13 +4,14 @@ import com.bekvon.bukkit.residence.protection.ClaimedResidence; import com.bekvon.bukkit.residence.protection.ResidencePermissions; import dev.naspo.tether.Tether; +import org.bukkit.Location; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; public class ResidenceIntegration extends ToggleableIntegration { private Residence residenceAPI; - public ResidenceIntegration(Tether tetherPlugin) { + public ResidenceIntegration(final Tether tetherPlugin) { super(tetherPlugin, "Residence", "residence"); } @@ -21,13 +22,14 @@ protected boolean onEnable() { } @Override - public boolean canLeash(LivingEntity clicked, Player player) { - ClaimedResidence residence = residenceAPI.getResidenceManager().getByLoc(clicked.getLocation()); + public boolean canLeash(final Location location, final Player player) { + final ClaimedResidence residence = residenceAPI.getResidenceManager().getByLoc(location); if (residence != null) { - ResidencePermissions perms = residence.getPermissions(); + final ResidencePermissions perms = residence.getPermissions(); return perms.playerHas(player, "leash", true); } return true; } + } diff --git a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/TownyIntegration.java b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/TownyIntegration.java index 743a7b9..e6554fd 100644 --- a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/TownyIntegration.java +++ b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/TownyIntegration.java @@ -3,13 +3,14 @@ import com.palmergames.bukkit.towny.TownyAPI; import com.palmergames.bukkit.towny.object.Town; import dev.naspo.tether.Tether; +import org.bukkit.Location; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; public class TownyIntegration extends ToggleableIntegration { private TownyAPI townyAPI; - public TownyIntegration(Tether tetherPlugin) { + public TownyIntegration(final Tether tetherPlugin) { super(tetherPlugin, "Towny", "towny"); } @@ -20,11 +21,11 @@ protected boolean onEnable() { } @Override - public boolean canLeash(LivingEntity clicked, Player player) { - Town town; + public boolean canLeash(final Location location, final Player player) { + final Town town; try { - town = townyAPI.getTownBlock(clicked.getLocation()).getTown(); - } catch (Exception e) { + town = townyAPI.getTownBlock(location).getTown(); + } catch (final Exception e) { return true; } return town.getTrustedResidents().contains(player.getUniqueId()); diff --git a/src/main/java/dev/naspo/tether/services/IntegrationManager.java b/src/main/java/dev/naspo/tether/services/IntegrationManager.java index 1ba96e1..5e11773 100644 --- a/src/main/java/dev/naspo/tether/services/IntegrationManager.java +++ b/src/main/java/dev/naspo/tether/services/IntegrationManager.java @@ -4,6 +4,7 @@ import dev.naspo.tether.integrations.Integration; import dev.naspo.tether.integrations.standardintegrations.WorldGuardIntegration; import dev.naspo.tether.integrations.toggleableintegrations.*; +import org.bukkit.Location; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -17,7 +18,7 @@ public class IntegrationManager { private final List integrations; - public IntegrationManager(Tether plugin) { + public IntegrationManager(final Tether plugin) { this.plugin = plugin; // Creating an immutable list of integrations (via List.of()). @@ -34,15 +35,15 @@ public IntegrationManager(Tether plugin) { } public void enableIntegrations() { - for (Integration integration : integrations) { + for (final Integration integration : integrations) { integration.enable(); } } - public boolean canLeash(LivingEntity clicked, Player player) { - for (Integration integration : integrations) { + public boolean canLeash(final Location location, final Player player) { + for (final Integration integration : integrations) { if (integration.isEnabled()) { - if (!integration.canLeash(clicked, player)) { + if (!integration.canLeash(location, player)) { return false; } } diff --git a/src/main/java/dev/naspo/tether/services/LeashMobService.java b/src/main/java/dev/naspo/tether/services/LeashMobService.java index 8c1732e..aa6d6f9 100644 --- a/src/main/java/dev/naspo/tether/services/LeashMobService.java +++ b/src/main/java/dev/naspo/tether/services/LeashMobService.java @@ -22,7 +22,7 @@ public class LeashMobService { private final Tether plugin; private final IntegrationManager integrationManager; - public LeashMobService(Tether plugin, IntegrationManager integrationManager) { + public LeashMobService(final Tether plugin, final IntegrationManager integrationManager) { this.plugin = plugin; this.integrationManager = integrationManager; } @@ -37,7 +37,7 @@ public LeashMobService(Tether plugin, IntegrationManager integrationManager) { * @throws NoPermissionException if the player does not have permission. * @throws LeashException when the leash operation fails for a given reason (LeashErrorType). */ - public void playerLeashMob(Player player, LivingEntity entity) throws InvalidParameterException, + public void playerLeashMob(final Player player, final LivingEntity entity) throws InvalidParameterException, NoPermissionException, LeashException { if (entity instanceof Player) throw new InvalidParameterException(); @@ -45,13 +45,13 @@ public void playerLeashMob(Player player, LivingEntity entity) throws InvalidPar if (isEntityRestricted(entity)) throw new LeashException(LeashErrorType.MOB_RESTRICTED); // Integration checks. - if (!integrationManager.canLeash(entity, player)) { + if (!integrationManager.canLeash(entity.getLocation(), player)) { throw new LeashException(LeashErrorType.LAND_PROTECTED); } // If the entity is a Citizens NPC, check if it can be leashed. if (entity.hasMetadata("NPC")) { - net.citizensnpcs.api.npc.NPC npc = CitizensAPI.getNPCRegistry().getNPC(entity); + final net.citizensnpcs.api.npc.NPC npc = CitizensAPI.getNPCRegistry().getNPC(entity); // If the NPC cannot be leashed, return. if (npc.data().get(NPC.Metadata.LEASH_PROTECTED, true)) { throw new LeashException(LeashErrorType.NPC_UNLEASHABLE); @@ -60,7 +60,7 @@ public void playerLeashMob(Player player, LivingEntity entity) throws InvalidPar // Begin the leashing process. // Keep track of the player's leads, prevents duping. - int leads; + final int leads; leads = player.getInventory().getItemInMainHand().getAmount(); // Leashing the mob. @@ -70,7 +70,7 @@ public void playerLeashMob(Player player, LivingEntity entity) throws InvalidPar entity.setLeashHolder(player); // If a lead was not removed from the player's inventory, remove one. - ItemStack lead = new ItemStack(Material.LEAD, 1); + final ItemStack lead = new ItemStack(Material.LEAD, 1); if (player.getInventory().getItemInMainHand().getAmount() == (leads - 1)) { return; } @@ -84,7 +84,7 @@ public void playerLeashMob(Player player, LivingEntity entity) throws InvalidPar * @param player The player that right-clicked the fence or leash hitch. * @param location The location of the fence or leash hitch. */ - public void handleFenceLeashing(Player player, Location location) { + public void handleFenceLeashing(final Player player, final Location location) { // Transfer mobs from fence to player: // First wait for the PlayerLeashEntityEvent to finish then set the player as the leash holder for the rest of // the mobs still leashed to the fence. (The mobs still leashed to the fence at that point would be mobs not @@ -107,23 +107,23 @@ public void handleFenceLeashing(Player player, Location location) { * @param player The player who sneak-interacted with an entity. * @param entity The LivingEntity that was sneak-interacted with. (Not `Mob` because NPCs are supported). */ - public void handleSneakInteract(Player player, LivingEntity entity) { + public void handleSneakInteract(final Player player, final LivingEntity entity) { if (entity instanceof Player) return; if (entity.isLeashed() && entity.getLeashHolder().equals(player)) return; - for (Mob mob : getMobsLeashedByPlayer(player)) { + for (final Mob mob : getMobsLeashedByPlayer(player)) { mob.setLeashHolder(entity); } } // Checks the whitelist or blacklist to see whether the entity is restricted from being leashed or not. - public boolean isEntityRestricted(Entity entity) { + public boolean isEntityRestricted(final Entity entity) { // Use whitelist check. // If whitelist is set to be used over blacklist, check the whitelist only, else use blacklist. if (plugin.getConfig().getBoolean("use-whitelist-over-blacklist")) { // Whitelist check. // Getting whitelist values and converting all to uppercase. - List whitelist = plugin.getConfig().getStringList("whitelisted-mobs") + final List whitelist = plugin.getConfig().getStringList("whitelisted-mobs") .stream().map(String::toUpperCase).collect(Collectors.toList()); if (!whitelist.contains(entity.getType().name())) { @@ -132,7 +132,7 @@ public boolean isEntityRestricted(Entity entity) { } else { // Blacklist check. // Getting blacklist values and converting all to uppercase. - List blacklist = plugin.getConfig().getStringList("blacklisted-mobs") + final List blacklist = plugin.getConfig().getStringList("blacklisted-mobs") .stream().map(String::toUpperCase).collect(Collectors.toList()); if (blacklist.contains(entity.getType().name())) { @@ -142,11 +142,11 @@ public boolean isEntityRestricted(Entity entity) { return false; } - private List getMobsLeashedByPlayer(Player player) { - List leashedMobs = new ArrayList<>(); - for (Entity entity : player.getNearbyEntities(10, 10, 10)) { - if (entity instanceof Mob mob) { - if (mob.isLeashed() && mob.getLeashHolder() instanceof Player holder && holder.equals(player)) { + private List getMobsLeashedByPlayer(final Player player) { + final List leashedMobs = new ArrayList<>(); + for (final Entity entity : player.getNearbyEntities(10, 10, 10)) { + if (entity instanceof final Mob mob) { + if (mob.isLeashed() && mob.getLeashHolder() instanceof final Player holder && holder.equals(player)) { leashedMobs.add(mob); } } @@ -158,13 +158,13 @@ private List getMobsLeashedByPlayer(Player player) { * @param location The location of the fence or leash hitch. * @return The list of mobs leashed to that fence. */ - private List getMobsLeashedToFence(Location location) { - List leashedMobs = new ArrayList<>(); + private List getMobsLeashedToFence(final Location location) { + final List leashedMobs = new ArrayList<>(); // Find the leash hitch. LeashHitch leashHitch = null; - for (Entity entity : location.getWorld().getNearbyEntities(location, 1, 1, 1)) { - if (entity instanceof LeashHitch lh) { + for (final Entity entity : location.getWorld().getNearbyEntities(location, 1, 1, 1)) { + if (entity instanceof final LeashHitch lh) { leashHitch = lh; break; } @@ -172,9 +172,9 @@ private List getMobsLeashedToFence(Location location) { // If there is a leash hitch, find all entities leashed to it. if (leashHitch != null) { - for (Entity entity : leashHitch.getWorld().getNearbyEntities(leashHitch.getLocation(), 10, 10, 10)) { - if (entity instanceof Mob mob) { - if (mob.isLeashed() && mob.getLeashHolder() instanceof LeashHitch holder && holder.equals(leashHitch)) { + for (final Entity entity : leashHitch.getWorld().getNearbyEntities(leashHitch.getLocation(), 10, 10, 10)) { + if (entity instanceof final Mob mob) { + if (mob.isLeashed() && mob.getLeashHolder() instanceof final LeashHitch holder && holder.equals(leashHitch)) { leashedMobs.add(mob); } } @@ -183,20 +183,20 @@ private List getMobsLeashedToFence(Location location) { return leashedMobs; } - private void transferMobsFromFenceToPlayer(Player player, Location fenceLocation) { - List mobs = getMobsLeashedToFence(fenceLocation); - for (Mob mob : mobs) { + private void transferMobsFromFenceToPlayer(final Player player, final Location fenceLocation) { + final List mobs = getMobsLeashedToFence(fenceLocation); + for (final Mob mob : mobs) { mob.setLeashHolder(player); } } - private void transferMobsFromPlayerToFence(Player player, Location fenceLocation) { - List leashedMobs = getMobsLeashedByPlayer(player); + private void transferMobsFromPlayerToFence(final Player player, final Location fenceLocation) { + final List leashedMobs = getMobsLeashedByPlayer(player); // Finding the leash hitch on the fence. LeashHitch leashHitch = null; - for (Entity entity : fenceLocation.getWorld().getNearbyEntities(fenceLocation, 1, 1, 1)) { - if (entity instanceof LeashHitch lh) { + for (final Entity entity : fenceLocation.getWorld().getNearbyEntities(fenceLocation, 1, 1, 1)) { + if (entity instanceof final LeashHitch lh) { leashHitch = lh; break; } @@ -206,13 +206,13 @@ private void transferMobsFromPlayerToFence(Player player, Location fenceLocation if (leashHitch == null) { // The location that the hitch should be. Cloning as to not modify the fenceLocation value. // 0.5 is added to properly visually align the hitch. - Location hitchLocation = fenceLocation.clone().add(0.5, 0.5, 0.5); + final Location hitchLocation = fenceLocation.clone().add(0.5, 0.5, 0.5); leashHitch = (LeashHitch) fenceLocation.getWorld().spawnEntity(hitchLocation, EntityType.LEASH_KNOT); - for (Mob mob : leashedMobs) { + for (final Mob mob : leashedMobs) { mob.setLeashHolder(leashHitch); } } else { - for (Mob mob : leashedMobs) { + for (final Mob mob : leashedMobs) { mob.setLeashHolder(leashHitch); } } diff --git a/src/main/java/dev/naspo/tether/services/LeashPlayerService.java b/src/main/java/dev/naspo/tether/services/LeashPlayerService.java index 804e280..bcbf161 100644 --- a/src/main/java/dev/naspo/tether/services/LeashPlayerService.java +++ b/src/main/java/dev/naspo/tether/services/LeashPlayerService.java @@ -21,7 +21,7 @@ public class LeashPlayerService { private final Tether plugin; private final IntegrationManager integrationManager; - public LeashPlayerService(Tether plugin, IntegrationManager integrationManager) { + public LeashPlayerService(final Tether plugin, final IntegrationManager integrationManager) { this.plugin = plugin; this.integrationManager = integrationManager; } @@ -35,7 +35,7 @@ public LeashPlayerService(Tether plugin, IntegrationManager integrationManager) * @throws NoPermissionException if the player does not have permission. * @throws LeashException when the leash operation fails for a given reason (LeashErrorType). */ - public void playerLeashPlayer(Player player, Player target) throws NoPermissionException, LeashException { + public void playerLeashPlayer(final Player player, final Player target) throws NoPermissionException, LeashException { // Permission check. ("tether.use.players" is deprecated, here for backwards compatibility). if (!player.hasPermission("tether.leashplayers") && !player.hasPermission("tether.use.players")) throw new NoPermissionException(); @@ -57,7 +57,7 @@ public void playerLeashPlayer(Player player, Player target) throws NoPermissionE } // Claim checks. - if (!integrationManager.canLeash(target, player)) { + if (!integrationManager.canLeash(target.getLocation(), player)) { throw new LeashException(LeashErrorType.LAND_PROTECTED); } @@ -70,11 +70,11 @@ public void playerLeashPlayer(Player player, Player target) throws NoPermissionE // At this point we can actually leash the player. - World world = target.getWorld(); - Location loc = target.getLocation(); + final World world = target.getWorld(); + final Location loc = target.getLocation(); // Keeps track of leads in the leasher's hand. (Prevents duping). - int leads; + final int leads; // If they are holding a lead... if (player.getInventory().getItemInMainHand().getType().equals(Material.LEAD)) { @@ -84,7 +84,7 @@ public void playerLeashPlayer(Player player, Player target) throws NoPermissionE // due to the way the event works. Bukkit.getScheduler().runTaskLater(plugin, () -> { // Spawn a chicken (set invisible, invulnerable, etc) - LivingEntity mob = (LivingEntity) world.spawnEntity(loc, EntityType.CHICKEN); + final LivingEntity mob = (LivingEntity) world.spawnEntity(loc, EntityType.CHICKEN); mob.setMetadata("naspodev_tether_plugin", new FixedMetadataValue(plugin, "_")); mob.setInvisible(true); mob.setInvulnerable(true); @@ -105,7 +105,7 @@ public void playerLeashPlayer(Player player, Player target) throws NoPermissionE } // If a lead wasn't removed from the leasher's inventory, remove one. - ItemStack lead = new ItemStack(Material.LEAD, 1); + final ItemStack lead = new ItemStack(Material.LEAD, 1); if (player.getInventory().getItemInMainHand().getAmount() == (leads - 1)) { return; } @@ -115,14 +115,14 @@ public void playerLeashPlayer(Player player, Player target) throws NoPermissionE } // Checks if the mob being dismounted is the plugin's, then sets its health to 0. - public void onDismountEscapable(EntityDismountEvent event) { + public void onDismountEscapable(final EntityDismountEvent event) { if (event.getDismounted().hasMetadata("naspodev_tether_plugin")) { ((LivingEntity) event.getDismounted()).setHealth(0); } } // Checks if the mob being dismounted is the plugin's, then cancels the event. - public void onDismountNotEscapable(EntityDismountEvent event) { + public void onDismountNotEscapable(final EntityDismountEvent event) { if (event.getDismounted().hasMetadata("naspodev_tether_plugin")) { event.setCancelled(true); } From 96fc7596ac6a18285d6bea9762b49f964c69399e Mon Sep 17 00:00:00 2001 From: SrBedrock <51332006+SrBedrock@users.noreply.github.com> Date: Fri, 3 Apr 2026 19:41:24 -0300 Subject: [PATCH 2/5] Enforce claim checks for fence leashing Inject IntegrationManager and perform a canLeash(location, player) check before calling handleFenceLeashing so mobs can't be leashed in protected/claimed areas. Also add a null check for clickedBlock, import Location/Player types, and update the constructor and method params to accept/use the IntegrationManager and final modifiers. Added imports for leash-related exceptions (prepared for future error handling). --- .../listeners/PlayerInteractListener.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/dev/naspo/tether/listeners/PlayerInteractListener.java b/src/main/java/dev/naspo/tether/listeners/PlayerInteractListener.java index 7560256..ec9394a 100644 --- a/src/main/java/dev/naspo/tether/listeners/PlayerInteractListener.java +++ b/src/main/java/dev/naspo/tether/listeners/PlayerInteractListener.java @@ -1,6 +1,11 @@ package dev.naspo.tether.listeners; +import dev.naspo.tether.exceptions.leashexception.LeashErrorType; +import dev.naspo.tether.exceptions.leashexception.LeashException; +import dev.naspo.tether.services.IntegrationManager; import dev.naspo.tether.services.LeashMobService; +import org.bukkit.Location; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; @@ -9,19 +14,26 @@ public class PlayerInteractListener implements Listener { private final LeashMobService leashMobService; + private final IntegrationManager integrationManager; - public PlayerInteractListener(LeashMobService leashMobService) { + public PlayerInteractListener(final LeashMobService leashMobService, final IntegrationManager integrationManager) { this.leashMobService = leashMobService; + this.integrationManager = integrationManager; } @EventHandler - private void onPlayerInteract(PlayerInteractEvent event) { + private void onPlayerInteract(final PlayerInteractEvent event) { // Ensuring it's a right-click on a fence with the main hand. // Used for fence post functionality for mobs that are not leashable by default as fence post // functionality won't work for them. if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; if (event.getHand() != EquipmentSlot.HAND) return; + if (event.getClickedBlock() == null) return; if (!event.getClickedBlock().getType().name().toLowerCase().endsWith("fence")) return; - leashMobService.handleFenceLeashing(event.getPlayer(), event.getClickedBlock().getLocation()); + final Location location = event.getClickedBlock().getLocation(); + final Player player = event.getPlayer(); + // Claim checks. + if (!integrationManager.canLeash(location, player)) return; + leashMobService.handleFenceLeashing(player, location); } } From 597d9ff911c29b2a77c67497624a576dafa39065 Mon Sep 17 00:00:00 2001 From: SrBedrock <51332006+SrBedrock@users.noreply.github.com> Date: Fri, 3 Apr 2026 19:55:38 -0300 Subject: [PATCH 3/5] Remove unused dependencies from listeners and manager Simplify PlayerLeashEntityListener by removing its LeashMobService field and constructor, and register it without arguments in Tether. Mark the PlayerLeashEntityEvent parameter final and keep the event cancellation for LivingEntity. Also remove the unused Tether plugin field from IntegrationManager. These changes reduce coupling and remove unused state without changing runtime behavior. --- src/main/java/dev/naspo/tether/Tether.java | 2 +- .../naspo/tether/listeners/PlayerLeashEntityListener.java | 8 +------- .../dev/naspo/tether/services/IntegrationManager.java | 2 -- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/main/java/dev/naspo/tether/Tether.java b/src/main/java/dev/naspo/tether/Tether.java index 386d3a8..610894a 100644 --- a/src/main/java/dev/naspo/tether/Tether.java +++ b/src/main/java/dev/naspo/tether/Tether.java @@ -47,7 +47,7 @@ private void instantiateClasses() { private void registerEvents() { this.getServer().getPluginManager().registerEvents(new PlayerInteractAtEntityListener(this, leashMobService, leashPlayerService), this); this.getServer().getPluginManager().registerEvents(new PlayerInteractListener(leashMobService, integrationManager), this); - this.getServer().getPluginManager().registerEvents(new PlayerLeashEntityListener(leashMobService), this); + this.getServer().getPluginManager().registerEvents(new PlayerLeashEntityListener(), this); this.getServer().getPluginManager().registerEvents(new EntityDeathListener(), this); this.getServer().getPluginManager().registerEvents(new EntityDismountListener(this, leashPlayerService), this); this.getServer().getPluginManager().registerEvents(new EntityUnleashListener(), this); diff --git a/src/main/java/dev/naspo/tether/listeners/PlayerLeashEntityListener.java b/src/main/java/dev/naspo/tether/listeners/PlayerLeashEntityListener.java index 593d77d..9b7c389 100644 --- a/src/main/java/dev/naspo/tether/listeners/PlayerLeashEntityListener.java +++ b/src/main/java/dev/naspo/tether/listeners/PlayerLeashEntityListener.java @@ -1,22 +1,16 @@ package dev.naspo.tether.listeners; -import dev.naspo.tether.services.LeashMobService; import org.bukkit.entity.LivingEntity; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.PlayerLeashEntityEvent; public class PlayerLeashEntityListener implements Listener { - private final LeashMobService leashMobService; - - public PlayerLeashEntityListener(LeashMobService leashMobService) { - this.leashMobService = leashMobService; - } // Tether takes complete control of leashing LivingEntities, therefore this event should always be cancelled // if it's to do with a LivingEntity. @EventHandler - private void onPlayerLeashEntity(PlayerLeashEntityEvent event) { + private void onPlayerLeashEntity(final PlayerLeashEntityEvent event) { if (event.getEntity() instanceof LivingEntity) { event.setCancelled(true); } diff --git a/src/main/java/dev/naspo/tether/services/IntegrationManager.java b/src/main/java/dev/naspo/tether/services/IntegrationManager.java index 5e11773..6d27a52 100644 --- a/src/main/java/dev/naspo/tether/services/IntegrationManager.java +++ b/src/main/java/dev/naspo/tether/services/IntegrationManager.java @@ -14,12 +14,10 @@ // Manages integrations. public class IntegrationManager { - private Tether plugin; private final List integrations; public IntegrationManager(final Tether plugin) { - this.plugin = plugin; // Creating an immutable list of integrations (via List.of()). // Important: Ordering of integrations here is important. From 3be5df9acaeca06476cfb681ebe17a86bc1d09a9 Mon Sep 17 00:00:00 2001 From: SrBedrock <51332006+SrBedrock@users.noreply.github.com> Date: Sat, 4 Apr 2026 01:15:21 -0300 Subject: [PATCH 4/5] Refactor listener imports and move integrations init Replace wildcard listener import with explicit listener class imports for clarity and to avoid broad imports. Move integrationManager.enableIntegrations() from onLoad() into onEnable() so integrations are initialized during plugin enable (after classes are instantiated and config saved). --- src/main/java/dev/naspo/tether/Tether.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/dev/naspo/tether/Tether.java b/src/main/java/dev/naspo/tether/Tether.java index 610894a..d0162f5 100644 --- a/src/main/java/dev/naspo/tether/Tether.java +++ b/src/main/java/dev/naspo/tether/Tether.java @@ -2,7 +2,12 @@ import dev.naspo.tether.commands.Commands; import dev.naspo.tether.commands.TabCompleter; -import dev.naspo.tether.listeners.*; +import dev.naspo.tether.listeners.EntityDeathListener; +import dev.naspo.tether.listeners.EntityDismountListener; +import dev.naspo.tether.listeners.EntityUnleashListener; +import dev.naspo.tether.listeners.PlayerInteractAtEntityListener; +import dev.naspo.tether.listeners.PlayerInteractListener; +import dev.naspo.tether.listeners.PlayerLeashEntityListener; import dev.naspo.tether.services.IntegrationManager; import dev.naspo.tether.services.LeashMobService; import dev.naspo.tether.services.LeashPlayerService; @@ -18,11 +23,12 @@ public final class Tether extends JavaPlugin { @Override public void onLoad() { instantiateClasses(); - integrationManager.enableIntegrations(); } @Override public void onEnable() { + integrationManager.enableIntegrations(); + this.saveDefaultConfig(); this.getConfig().options().copyDefaults(true); this.saveConfig(); From 2b574fd262822877308c14e4efa506870d9e884f Mon Sep 17 00:00:00 2001 From: SrBedrock <51332006+SrBedrock@users.noreply.github.com> Date: Sat, 4 Apr 2026 01:28:59 -0300 Subject: [PATCH 5/5] Enable integrations in onLoad; lazy-init GP Move integrationManager.enableIntegrations() from onEnable() to onLoad() so integrations are initialized earlier during plugin load. Update GriefPreventionIntegration to lazy-initialize its DataStore via a new getDataStore() method and replace direct dataStore accesses to avoid null issues. Clean up IntegrationManager imports to explicitly reference toggleable integration classes and remove unused imports. --- src/main/java/dev/naspo/tether/Tether.java | 2 +- .../GriefPreventionIntegration.java | 12 +++++++++--- .../naspo/tether/services/IntegrationManager.java | 9 +++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/dev/naspo/tether/Tether.java b/src/main/java/dev/naspo/tether/Tether.java index d0162f5..9e2d2ac 100644 --- a/src/main/java/dev/naspo/tether/Tether.java +++ b/src/main/java/dev/naspo/tether/Tether.java @@ -23,11 +23,11 @@ public final class Tether extends JavaPlugin { @Override public void onLoad() { instantiateClasses(); + integrationManager.enableIntegrations(); } @Override public void onEnable() { - integrationManager.enableIntegrations(); this.saveDefaultConfig(); this.getConfig().options().copyDefaults(true); diff --git a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefPreventionIntegration.java b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefPreventionIntegration.java index 36876df..34e2c8b 100644 --- a/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefPreventionIntegration.java +++ b/src/main/java/dev/naspo/tether/integrations/toggleableintegrations/GriefPreventionIntegration.java @@ -18,19 +18,25 @@ public GriefPreventionIntegration(final Tether tetherPlugin) { @Override protected boolean onEnable() { - dataStore = GriefPrevention.instance.dataStore; return true; } @Override public boolean canLeash(final Location location, final Player player) { - final Claim claim = dataStore.getClaimAt(location, true, null); + final Claim claim = getDataStore().getClaimAt(location, true, null); // If there is a claim here, return true if the player has explicit permission or is ignoring claims. if (claim != null) { return claim.hasExplicitPermission(player.getUniqueId(), ClaimPermission.Access) || - dataStore.getPlayerData(player.getUniqueId()).ignoreClaims; + getDataStore().getPlayerData(player.getUniqueId()).ignoreClaims; } // Otherwise always return true if there is no claim. return true; } + + public DataStore getDataStore() { + if (dataStore == null) { + dataStore = GriefPrevention.instance.dataStore; + } + return dataStore; + } } diff --git a/src/main/java/dev/naspo/tether/services/IntegrationManager.java b/src/main/java/dev/naspo/tether/services/IntegrationManager.java index 6d27a52..d1d22e7 100644 --- a/src/main/java/dev/naspo/tether/services/IntegrationManager.java +++ b/src/main/java/dev/naspo/tether/services/IntegrationManager.java @@ -3,13 +3,14 @@ import dev.naspo.tether.Tether; import dev.naspo.tether.integrations.Integration; import dev.naspo.tether.integrations.standardintegrations.WorldGuardIntegration; -import dev.naspo.tether.integrations.toggleableintegrations.*; +import dev.naspo.tether.integrations.toggleableintegrations.GriefDefenderIntegration; +import dev.naspo.tether.integrations.toggleableintegrations.GriefPreventionIntegration; +import dev.naspo.tether.integrations.toggleableintegrations.LandsIntegration; +import dev.naspo.tether.integrations.toggleableintegrations.ResidenceIntegration; +import dev.naspo.tether.integrations.toggleableintegrations.TownyIntegration; import org.bukkit.Location; -import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; // Manages integrations.