diff --git a/resources/lang/en-US.yml b/resources/lang/en-US.yml index ebd4f648721..19f2769723c 100644 --- a/resources/lang/en-US.yml +++ b/resources/lang/en-US.yml @@ -1869,5 +1869,16 @@ msg_warn_are_you_sure_you_want_to_transfer_nation_ownership: "Are you sure msg_warn_town_already_capital: "The town of %s is already the nation capital." msg_min_adjacent_blocks: 'You are required to have at least %s adjacent town blocks. There is only %s.' + # Shown when a player with /plot evict permissions uses /plot claim on an owned but not for sale plot, please preserve comma space at the start when translating. msg_plot_claim_consider_evict_instead: ', perhaps you are looking for /plot evict instead?' + +msg_you_are_unknown: "You are not known to Towny." +msg_townyobject_unknown: "%s is not known to Towny." +msg_err_resident_unknown: "%s is not a resident that is recognized." +msg_err_town_unknown: "%s is not a town that is recognized." +msg_err_nation_unknown: "%s is not a nation that is recognized." +msg_err_townyobject_x_has_no_town: "%s does not belong to any town." +msg_err_townyobject_x_has_no_nation: "%s does not belong to any nation." + +msg_err_townblock_has_no_claimedat_data: "This townblock has no data on when it was claimed." diff --git a/src/com/palmergames/bukkit/towny/TownyAsciiMap.java b/src/com/palmergames/bukkit/towny/TownyAsciiMap.java index c5c87becd0b..2c9d1c5d02a 100644 --- a/src/com/palmergames/bukkit/towny/TownyAsciiMap.java +++ b/src/com/palmergames/bukkit/towny/TownyAsciiMap.java @@ -113,9 +113,10 @@ public static void generateAndSend(Towny plugin, Player player, int lineHeight) for (int tbx = pos.getZ() - halfLineHeight; tbx <= pos.getZ() + (lineHeight - halfLineHeight - 1); tbx++) { try { townyMap[y][x] = Component.empty().color(NamedTextColor.WHITE); - TownBlock townblock = world.getTownBlock(tby, tbx); - if (!townblock.hasTown()) + WorldCoord wc = new WorldCoord(world.getBukkitWorld(), new Coord(tby, tbx)); + if (wc.isWilderness()) throw new TownyException(); + TownBlock townblock = wc.getTownBlockOrNull(); Town town = townblock.getTownOrNull(); if (x == halfLineHeight && y == halfLineWidth) // This is the player's location, colour it special. diff --git a/src/com/palmergames/bukkit/towny/TownyUniverse.java b/src/com/palmergames/bukkit/towny/TownyUniverse.java index 564ef801ec5..f65dd2680cf 100644 --- a/src/com/palmergames/bukkit/towny/TownyUniverse.java +++ b/src/com/palmergames/bukkit/towny/TownyUniverse.java @@ -443,6 +443,46 @@ public void unregisterResident(@NotNull Resident resident) throws NotRegisteredE } } + /** + * Used internally by Towny to correct resident UUIDs which were improperly + * recorded. (Probably something to do with offline servers.) + * + * @param resident Resident that exists in the correct name maps. + * @param uuid UUID that the Resident should have. + */ + public void changeResidentUUID(@NotNull Resident resident, @NotNull UUID uuid) { + Preconditions.checkNotNull(resident, "Resident cannot be null!"); + Preconditions.checkNotNull(uuid, "UUID cannot be null!"); + + Preconditions.checkState(residentNameMap.containsKey(resident.getName()), "ResidentNameMap must contain resident!"); + Preconditions.checkState(residentUUIDMap.containsKey(uuid), "ResidentUUIDMap must contain resident!"); + + try { + unregisterResident(resident); // Unregister + resident.setUUID(uuid); // Set proper UUID. + registerResident(resident); // Re-register. + } catch (NotRegisteredException | AlreadyRegisteredException ignored) {} // Ignored because we know we will be successful. + } + + public void changeResidentName(@NotNull Resident resident, @NotNull String name) { + Preconditions.checkNotNull(resident, "Resident cannot be null!"); + Preconditions.checkNotNull(name, "Name cannot be null!"); + + Preconditions.checkState(residentNameMap.containsKey(resident.getName()), "ResidentNameMap must contain resident!"); + try { + // Forcefully remove the resident from the Universe. + residentNameMap.remove(resident.getName().toLowerCase(Locale.ROOT)); + residentsTrie.removeKey(resident.getName()); + if (resident.getUUID() != null) + residentUUIDMap.remove(resident.getUUID()); + + resident.setName(name); // Set proper name. + registerResident(resident); // Re-register. + } catch (AlreadyRegisteredException e) { + e.printStackTrace(); + } + } + @Unmodifiable public Collection getResidents() { return Collections.unmodifiableCollection(residentNameMap.values()); diff --git a/src/com/palmergames/bukkit/towny/command/BaseCommand.java b/src/com/palmergames/bukkit/towny/command/BaseCommand.java index 3e2c177fdb3..c82f20af630 100644 --- a/src/com/palmergames/bukkit/towny/command/BaseCommand.java +++ b/src/com/palmergames/bukkit/towny/command/BaseCommand.java @@ -3,7 +3,7 @@ import com.palmergames.bukkit.towny.TownyAPI; import com.palmergames.bukkit.towny.TownyUniverse; import com.palmergames.bukkit.towny.exceptions.NoPermissionException; -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +//import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.object.Nation; import com.palmergames.bukkit.towny.object.Resident; @@ -273,22 +273,22 @@ protected static Optional parseToggleChoice(String str) { @NotNull protected static Town getTownFromPlayerOrThrow(Player player) throws TownyException { - return getTownFromResidentOrThrow(getResidentOrThrow(player.getUniqueId())); + return getTownFromResidentOrThrow(getResidentOrThrow(player)); } @NotNull protected static Town getTownFromResidentOrThrow(@NotNull Resident resident) throws TownyException { if (!resident.hasTown()) - throw new TownyException(Translatable.of("msg_err_dont_belong_town")); + throw new TownyException(Translatable.of("msg_err_townyobject_x_has_no_town", resident)); return resident.getTownOrNull(); } @NotNull - protected static Resident getResidentOrThrow(UUID playerUUID) throws NotRegisteredException { + protected static Resident getResidentOrThrow(UUID playerUUID) throws TownyException { Resident res = TownyUniverse.getInstance().getResident(playerUUID); if (res == null) { - throw new NotRegisteredException(Translatable.of("msg_err_not_registered")); + throw new TownyException(Translatable.of("msg_err_not_registered")); } return res; @@ -296,65 +296,65 @@ protected static Resident getResidentOrThrow(UUID playerUUID) throws NotRegister @NotNull @Contract("null -> fail") - protected static Resident getResidentOrThrow(@Nullable Player player) throws NotRegisteredException { + protected static Resident getResidentOrThrow(@Nullable Player player) throws TownyException { Resident resident = player == null ? null : TownyAPI.getInstance().getResident(player); if (resident == null) - throw new NotRegisteredException(Translatable.of("msg_err_not_registered")); + throw new TownyException(Translatable.of("msg_err_resident_unknown", player.getName())); return resident; } @NotNull - protected static Resident getResidentOrThrow(String residentName) throws NotRegisteredException { + protected static Resident getResidentOrThrow(String residentName) throws TownyException { Resident res = TownyUniverse.getInstance().getResident(residentName); if (res == null) { - throw new NotRegisteredException(Translatable.of("msg_err_not_registered_1", residentName)); + throw new TownyException(Translatable.of("msg_err_resident_unknown", residentName)); } return res; } @NotNull - protected static Town getTownOrThrow(String townName) throws NotRegisteredException { + protected static Town getTownOrThrow(String townName) throws TownyException { Town town = TownyUniverse.getInstance().getTown(townName); if (town == null) { - throw new NotRegisteredException(Translatable.of("msg_err_not_registered_1", townName)); + throw new TownyException(Translatable.of("msg_err_town_unknown", townName)); } return town; } @NotNull - protected static Nation getNationOrThrow(String nationName) throws NotRegisteredException { + protected static Nation getNationOrThrow(String nationName) throws TownyException { Nation nation = TownyUniverse.getInstance().getNation(nationName); if (nation == null) - throw new NotRegisteredException(Translatable.of("msg_err_not_registered_1", nationName)); + throw new TownyException(Translatable.of("msg_err_nation_unknown", nationName)); return nation; } @NotNull protected static Nation getNationFromPlayerOrThrow(Player player) throws TownyException { - return getNationFromResidentOrThrow(getResidentOrThrow(player.getUniqueId())); + return getNationFromResidentOrThrow(getResidentOrThrow(player)); } @NotNull protected static Nation getNationFromResidentOrThrow(Resident resident) throws TownyException { if (!resident.hasNation()) - throw new TownyException(Translatable.of("msg_err_dont_belong_nation")); + throw new TownyException(Translatable.of("msg_err_townyobject_x_has_no_nation", resident)); return resident.getNationOrNull(); } @NotNull - protected static Nation getNationFromTownOrThrow(Town town) throws NotRegisteredException { + protected static Nation getNationFromTownOrThrow(Town town) throws TownyException { Nation nation = town.getNationOrNull(); if (nation == null) - throw new NotRegisteredException(Translatable.of("msg_err_town_doesnt_belong_to_any_nation")); + throw new TownyException(Translatable.of("msg_err_townyobject_x_has_no_nation", town)); return nation; } diff --git a/src/com/palmergames/bukkit/towny/command/NationCommand.java b/src/com/palmergames/bukkit/towny/command/NationCommand.java index d9cfedada45..00320b61055 100644 --- a/src/com/palmergames/bukkit/towny/command/NationCommand.java +++ b/src/com/palmergames/bukkit/towny/command/NationCommand.java @@ -40,7 +40,6 @@ import com.palmergames.bukkit.towny.event.nation.NationKingChangeEvent; import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; import com.palmergames.bukkit.towny.exceptions.InvalidNameException; -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.invites.Invite; import com.palmergames.bukkit.towny.invites.InviteHandler; @@ -649,8 +648,8 @@ private void parseNationJoin(Player player, String[] args) { nationName = args[0]; - resident = getResidentOrThrow(player.getUniqueId()); - town = resident.getTown(); + resident = getResidentOrThrow(player); + town = getTownFromResidentOrThrow(resident); nation = getNationOrThrow(nationName); // Check if town is currently in a nation. @@ -752,7 +751,7 @@ public void nationRank(Player player, String[] split) throws TownyException { return; } - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); Resident target = getResidentOrThrow(split[1]); Nation nation = getNationFromResidentOrThrow(resident); @@ -895,20 +894,21 @@ public void listNations(CommandSender sender, String[] split) throws TownyExcept } private void newNation(Player player, String[] split) throws TownyException { - Resident resident = getResidentOrThrow(player.getUniqueId()); - if (TownySettings.getNumResidentsCreateNation() > 0 && resident.getTown().getNumResidents() < TownySettings.getNumResidentsCreateNation()) + Resident resident = getResidentOrThrow(player); + Town town = getTownFromResidentOrThrow(resident); + if (TownySettings.getNumResidentsCreateNation() > 0 && town.getNumResidents() < TownySettings.getNumResidentsCreateNation()) throw new TownyException(Translatable.of("msg_err_not_enough_residents_new_nation")); if (split.length == 1) throw new TownyException(Translatable.of("msg_specify_nation_name")); - if (!resident.isMayor() && !resident.getTown().hasResidentWithRank(resident, "assistant")) + if (!resident.isMayor() && !town.hasResidentWithRank(resident, "assistant")) throw new TownyException(Translatable.of("msg_peasant_right")); boolean noCharge = TownySettings.getNewNationPrice() == 0.0 || !TownyEconomyHandler.isActive(); String nationName = String.join("_", StringMgmt.remFirstArg(split)); - newNation(player, nationName, resident.getTown(), noCharge); + newNation(player, nationName, town, noCharge); } public static void newNation(Player player, String name, Town capitalTown, boolean noCharge) { @@ -955,7 +955,7 @@ public static void newNation(CommandSender sender, String name, Town capitalTown Confirmation.runOnAccept(() -> { try { newNation(finalName, capitalTown); - } catch (AlreadyRegisteredException | NotRegisteredException e) { + } catch (TownyException e) { TownyMessaging.sendErrorMsg(sender, e.getMessage(sender)); return; } @@ -977,7 +977,7 @@ public static void newNation(CommandSender sender, String name, Town capitalTown } } - public static Nation newNation(String name, Town town) throws AlreadyRegisteredException, NotRegisteredException { + public static Nation newNation(String name, Town town) throws TownyException { TownyUniverse townyUniverse = TownyUniverse.getInstance(); UUID nationUUID = UUID.randomUUID(); @@ -987,7 +987,7 @@ public static Nation newNation(String name, Town town) throws AlreadyRegisteredE // Should never happen if (nation == null) { TownyMessaging.sendErrorMsg(String.format("Error fetching new nation with name %s; it was not properly registered!", name)); - throw new NotRegisteredException(Translatable.of("msg_err_not_registered_1", name)); + throw new TownyException(Translatable.of("msg_err_not_registered_1", name)); } nation.setRegistered(System.currentTimeMillis()); nation.setMapColorHexCode(MapUtil.generateRandomNationColourAsHexCode()); @@ -1020,7 +1020,7 @@ public static void mergeNation(CommandSender sender, String[] split, @NotNull Na throw new TownyException(Translatable.of("msg_specify_nation_name")); String name = split[0]; - if (!admin && sender instanceof Player player && !getResidentOrThrow(player.getUniqueId()).isKing()) + if (!admin && sender instanceof Player player && !getResidentOrThrow(player).isKing()) throw new TownyException(Translatable.of("msg_err_merging_for_kings_only")); Nation nation = TownyUniverse.getInstance().getNation(name); @@ -1057,7 +1057,7 @@ public static void mergeNation(CommandSender sender, String[] split, @NotNull Na } public void nationLeave(Player player) throws TownyException { - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); Town town = getTownFromResidentOrThrow(resident); Nation nation = getNationFromResidentOrThrow(resident); @@ -1093,7 +1093,7 @@ public void nationDelete(Player player, String[] split) { // Player is using "/n delete" if (split.length == 0) { try { - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); Town town = getTownFromResidentOrThrow(resident); Nation nation = getNationFromResidentOrThrow(resident); // Check that the capital wont have too many residents after deletion. @@ -1165,13 +1165,12 @@ public void nationAdd(Player player, String[] names) throws TownyException { continue; } - Town town = null; - try { - town = getTownOrThrow(townname); - } catch (NotRegisteredException e) { + Town town = TownyAPI.getInstance().getTown(townname); + if (town == null) { // The Town doesn't actually exist or was mis-spelled. removeinvites.add(townname); continue; + } if (nation.hasTown(town) || town.hasNation()) { @@ -1424,7 +1423,7 @@ private void nationAlly(Player player, String[] split) throws TownyException { HelpMenu.ALLIES_STRING.send(player); return; } - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); Nation nation = getNationFromResidentOrThrow(resident); switch (split[0].toLowerCase()) { @@ -1785,7 +1784,7 @@ public void nationEnemy(Player player, String[] split) throws TownyException { return; } - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); Nation nation = getNationFromResidentOrThrow(resident); ArrayList list = new ArrayList<>(); @@ -1906,7 +1905,7 @@ public static void nationSet(CommandSender sender, String[] split, boolean admin Resident resident; try { if (!admin && sender instanceof Player player) { - resident = getResidentOrThrow(player.getUniqueId()); + resident = getResidentOrThrow(player); nation = getNationFromResidentOrThrow(resident); } else // treat resident as king for testing purposes. resident = nation.getKing(); @@ -2023,7 +2022,7 @@ private static void nationSetBoard(CommandSender sender, Nation nation, String[] } } - private static void nationSetSurname(CommandSender sender, Nation nation, Resident resident, String[] split, boolean admin) throws NotRegisteredException { + private static void nationSetSurname(CommandSender sender, Nation nation, Resident resident, String[] split, boolean admin) throws TownyException { // Give the resident a title if (split.length < 2) TownyMessaging.sendErrorMsg(sender, "Eg: /nation set surname bilbo the dwarf "); @@ -2062,7 +2061,7 @@ private static void nationSetSurname(CommandSender sender, Nation nation, Reside } - private static void nationSetTitle(CommandSender sender, Nation nation, Resident resident, String[] split, boolean admin) throws NotRegisteredException { + private static void nationSetTitle(CommandSender sender, Nation nation, Resident resident, String[] split, boolean admin) throws TownyException { // Give the resident a title if (split.length < 2) TownyMessaging.sendErrorMsg(sender, "Eg: /nation set title bilbo Jester "); @@ -2296,7 +2295,7 @@ private static void nationSetKing(CommandSender sender, Nation nation, String[] if (!newKing.isMayor()) throw new TownyException(Translatable.of("msg_err_new_king_notmayor")); - changeNationOwnership(sender, nation, getResidentOrThrow(split[1]).getTown(), admin); + changeNationOwnership(sender, nation, newKing.getTownOrNull(), admin); } catch (TownyException e) { TownyMessaging.sendErrorMsg(sender, e.getMessage(sender)); } @@ -2357,7 +2356,7 @@ public static void nationToggle(CommandSender sender, String[] split, boolean ad Resident resident; if (!admin) { - resident = getResidentOrThrow(((Player) sender).getUniqueId()); + resident = getResidentOrThrow((Player) sender); nation = getNationFromResidentOrThrow(resident); } else // Treat any resident tests as though the king were doing it. resident = nation.getKing(); @@ -2524,7 +2523,7 @@ private static void nationTransaction(Player player, String[] args, boolean with } try { - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); Nation nation = getNationFromResidentOrThrow(resident); if (args.length < 2 || args.length > 3) diff --git a/src/com/palmergames/bukkit/towny/command/PlotCommand.java b/src/com/palmergames/bukkit/towny/command/PlotCommand.java index 585f1309cf9..19de3197ee7 100644 --- a/src/com/palmergames/bukkit/towny/command/PlotCommand.java +++ b/src/com/palmergames/bukkit/towny/command/PlotCommand.java @@ -296,18 +296,21 @@ public boolean parsePlotCommand(Player player, String[] split) { List selection = AreaSelectionUtil.selectWorldCoordArea(resident, new WorldCoord(world, Coord.parseCoord(player)), StringMgmt.remFirstArg(split), true); // Fast-fail if this is a single plot and it is already claimed. - if (selection.size() == 1 && selection.get(0).hasTownBlock() && selection.get(0).getTownBlock().hasResident() && !selection.get(0).getTownBlock().isForSale()) { - final Translatable message = Translatable.of("msg_already_claimed", selection.get(0).getTownBlock().getResidentOrNull()); - - // Add extra message if the player has permission to evict - if (player.hasPermission(PermissionNodes.TOWNY_COMMAND_PLOT_EVICT.getNode())) { - try { - plotTestOwner(resident, selection.get(0).getTownBlock()); - message.append(Translatable.of("msg_plot_claim_consider_evict_instead")); - } catch (TownyException ignored) {} + if (selection.size() == 1 && selection.get(0).hasTownBlock()) { + TownBlock tb = selection.get(0).getTownBlockOrNull(); + if (tb.hasResident() && !tb.isForSale()) { + final Translatable message = Translatable.of("msg_already_claimed", tb.getResidentOrNull()); + + // Add extra message if the player has permission to evict + if (player.hasPermission(PermissionNodes.TOWNY_COMMAND_PLOT_EVICT.getNode())) { + try { + plotTestOwner(resident, tb); + message.append(Translatable.of("msg_plot_claim_consider_evict_instead")); + } catch (TownyException ignored) {} + } + + throw new TownyException(message); } - - throw new TownyException(message); } // Filter to just plots that are for sale. @@ -405,7 +408,7 @@ public boolean parsePlotCommand(Player player, String[] split) { if (selection.size() > 0) { for (WorldCoord coord : selection) { - TownBlock block = coord.getTownBlock(); + TownBlock block = coord.getTownBlockOrNull(); // We've already filtered out unclaimed land. if (!block.hasPlotObjectGroup()) { // Start the unclaim task @@ -443,7 +446,7 @@ public boolean parsePlotCommand(Player player, String[] split) { if (resident.hasPermissionNode(PermissionNodes.TOWNY_ADMIN.getNode())) { for (WorldCoord worldCoord : selection) { - if (worldCoord.getTownBlock().hasPlotObjectGroup()) { + if (worldCoord.getTownBlockOrNull().hasPlotObjectGroup()) { TownyMessaging.sendErrorMsg(player, Translatable.of("msg_err_plot_belongs_to_group_plot_nfs", worldCoord)); return false; } @@ -460,7 +463,7 @@ public boolean parsePlotCommand(Player player, String[] split) { (resident.hasPermissionNode(PermissionNodes.TOWNY_COMMAND_PLOT_ASMAYOR.getNode()) && town.hasResident(resident)) || (resident.hasPermissionNode(PermissionNodes.TOWNY_COMMAND_PLOT_ASMAYORINUNOWNED.getNode()) && town.hasResident(resident) && !townBlock.hasResident()) ) { - selection = AreaSelectionUtil.filterOwnedBlocks(resident.getTown(), selection); // Treat it as a mayor able to set their town's plots not for sale. + selection = AreaSelectionUtil.filterOwnedBlocks(resident.getTownOrNull(), selection); // Treat it as a mayor able to set their town's plots not for sale. } else { selection = AreaSelectionUtil.filterOwnedBlocks(resident, selection); // Treat it as a resident making their own plots not for sale. } @@ -472,7 +475,7 @@ public boolean parsePlotCommand(Player player, String[] split) { for (WorldCoord worldCoord : selection) { // Skip over any plots that are part of a PlotGroup. - if (worldCoord.getTownBlock().hasPlotObjectGroup()) { + if (worldCoord.getTownBlockOrNull().hasPlotObjectGroup()) { // We've already filtered out wilderness coords. TownyMessaging.sendErrorMsg(player, Translatable.of("msg_err_plot_belongs_to_group_plot_nfs", worldCoord)); continue; } @@ -509,7 +512,7 @@ public boolean parsePlotCommand(Player player, String[] split) { (resident.hasPermissionNode(PermissionNodes.TOWNY_COMMAND_PLOT_ASMAYOR.getNode()) && town.hasResident(resident)) || (resident.hasPermissionNode(PermissionNodes.TOWNY_COMMAND_PLOT_ASMAYORINUNOWNED.getNode()) && town.hasResident(resident) && !townBlock.hasResident()) ) { - selection = AreaSelectionUtil.filterOwnedBlocks(resident.getTown(), selection); // Treat it as a mayor able to put their town's plots for sale. + selection = AreaSelectionUtil.filterOwnedBlocks(resident.getTownOrNull(), selection); // Treat it as a mayor able to put their town's plots for sale. selection = AreaSelectionUtil.filterOutResidentBlocks(resident, selection); // Filter out any resident-owned plots. } else { selection = AreaSelectionUtil.filterOwnedBlocks(resident, selection); // Treat it as a resident putting their own plots up for sale. @@ -531,7 +534,7 @@ public boolean parsePlotCommand(Player player, String[] split) { // Set each WorldCoord in selection for sale. for (WorldCoord worldCoord : selection) { - TownBlock tb = worldCoord.getTownBlock(); + TownBlock tb = worldCoord.getTownBlockOrNull(); // We've already filtered out any wilderness blocks. // Skip over any plots that are part of a PlotGroup. if (tb.hasPlotObjectGroup()) { @@ -548,7 +551,7 @@ public boolean parsePlotCommand(Player player, String[] split) { */ // Skip over any plots that are part of a PlotGroup. - if (pos.getTownBlock().hasPlotObjectGroup()) { + if (townBlock.hasPlotObjectGroup()) { TownyMessaging.sendErrorMsg(player, Translatable.of("msg_err_plot_belongs_to_group_plot_fs2", pos)); return false; } @@ -581,7 +584,7 @@ public boolean parsePlotCommand(Player player, String[] split) { return false; } - plotToggle(player, new WorldCoord(world, Coord.parseCoord(player)).getTownBlock(), StringMgmt.remFirstArg(split)); + plotToggle(player, townBlock, StringMgmt.remFirstArg(split)); } else if (split[0].equalsIgnoreCase("set")) { @@ -649,6 +652,8 @@ public boolean parsePlotCommand(Player player, String[] split) { plotTestOwner(resident, townBlock); Town town = townBlock.getTownOrNull(); + if (!town.hasResident(resident)) + throw new TownyException(Translatable.of("msg_not_own_area")); TownyWorld townyWorld = townBlock.getWorld(); Coord key = Coord.parseCoord(plugin.getCache(player).getLastLocation()); @@ -1389,7 +1394,7 @@ public static void plotTestOwner(Resident resident, TownBlock townBlock) throws private boolean handlePlotGroupCommand(String[] split, Player player) throws TownyException { - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); TownBlock townBlock = TownyAPI.getInstance().getTownBlock(player); if (townBlock == null) throw new TownyException(Translatable.of("msg_not_claimed_1")); @@ -2087,7 +2092,7 @@ public void parsePlotPermCommand(Player player, String[] args) throws TownyExcep } try { - plotTestOwner(getResidentOrThrow(player.getUniqueId()), townBlock); + plotTestOwner(getResidentOrThrow(player), townBlock); } catch (TownyException e) { TownyMessaging.sendErrorMsg(player, e.getMessage(player)); return; @@ -2121,7 +2126,7 @@ public void parsePlotPermCommand(Player player, String[] args) throws TownyExcep } try { - plotTestOwner(getResidentOrThrow(player.getUniqueId()), townBlock); + plotTestOwner(getResidentOrThrow(player), townBlock); } catch (TownyException e) { TownyMessaging.sendErrorMsg(player, e.getMessage(player)); return; diff --git a/src/com/palmergames/bukkit/towny/command/ResidentCommand.java b/src/com/palmergames/bukkit/towny/command/ResidentCommand.java index 3d8b01ffa9a..0f478b91c6e 100644 --- a/src/com/palmergames/bukkit/towny/command/ResidentCommand.java +++ b/src/com/palmergames/bukkit/towny/command/ResidentCommand.java @@ -250,7 +250,7 @@ public void parseResidentCommand(final Player player, String[] split) { try { if (split.length == 0) { - Resident res = getResidentOrThrow(player.getUniqueId()); + Resident res = getResidentOrThrow(player); Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> TownyMessaging.sendStatusScreen(player, TownyFormatter.getStatus(res, player))); } else if (split[0].equalsIgnoreCase("?") || split[0].equalsIgnoreCase("help")) { @@ -274,7 +274,7 @@ public void parseResidentCommand(final Player player, String[] split) { if (split.length > 1) res = getResidentOrThrow(split[1]); else - res = getResidentOrThrow(player.getUniqueId()); + res = getResidentOrThrow(player); TownyMessaging.sendMessage(player, TownyFormatter.getTaxStatus(res, Translator.locale(player))); @@ -292,7 +292,7 @@ public void parseResidentCommand(final Player player, String[] split) { return; } - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); if (!resident.isJailed()) { TownyMessaging.sendErrorMsg(player, Translatable.of("msg_err_you_aren't currently jailed")); @@ -354,7 +354,7 @@ public void parseResidentCommand(final Player player, String[] split) { } else if (split[0].equalsIgnoreCase("spawn")) { checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_RESIDENT_SPAWN.getNode()); - SpawnUtil.sendToTownySpawn(player, split, getResidentOrThrow(player.getUniqueId()), Translatable.of("msg_err_cant_afford_tp").forLocale(player), false, false, SpawnType.RESIDENT); + SpawnUtil.sendToTownySpawn(player, split, getResidentOrThrow(player), Translatable.of("msg_err_cant_afford_tp").forLocale(player), false, false, SpawnType.RESIDENT); } else if (TownyCommandAddonAPI.hasCommand(CommandType.RESIDENT, split[0])) { TownyCommandAddonAPI.getAddonCommand(CommandType.RESIDENT, split[0]).execute(player, "resident", split); diff --git a/src/com/palmergames/bukkit/towny/command/TownCommand.java b/src/com/palmergames/bukkit/towny/command/TownCommand.java index 4708dd9b80d..9983ce4cb01 100644 --- a/src/com/palmergames/bukkit/towny/command/TownCommand.java +++ b/src/com/palmergames/bukkit/towny/command/TownCommand.java @@ -51,7 +51,6 @@ import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; import com.palmergames.bukkit.towny.exceptions.InvalidNameException; import com.palmergames.bukkit.towny.exceptions.NoPermissionException; -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.exceptions.CancelledEventException; import com.palmergames.bukkit.towny.invites.Invite; @@ -287,7 +286,7 @@ public TownCommand(Towny instance) { public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { if (sender instanceof Player player) { - + Resident res = TownyUniverse.getInstance().getResident(player.getUniqueId()); switch (args[0].toLowerCase()) { case "online": case "reslist": @@ -329,9 +328,9 @@ public List onTabComplete(CommandSender sender, Command command, String case "add": return NameUtil.filterByStart(TownyPerms.getTownRanks(), args[3]); case "remove": { - Resident res = TownyUniverse.getInstance().getResident(args[2]); - if (res != null) - return res.getTownRanks().isEmpty() ? Collections.emptyList() : NameUtil.filterByStart(res.getTownRanks(), args[3]); + Resident rankHaver = TownyUniverse.getInstance().getResident(args[2]); + if (rankHaver != null) + return rankHaver.getTownRanks().isEmpty() ? Collections.emptyList() : NameUtil.filterByStart(rankHaver.getTownRanks(), args[3]); break; } default: @@ -348,7 +347,6 @@ public List onTabComplete(CommandSender sender, Command command, String } case "unjail": if (args.length == 2) { - Resident res = TownyUniverse.getInstance().getResident(player.getUniqueId()); if (res != null && res.hasTown()) { Town town = res.getTownOrNull(); List jailedResidents = new ArrayList<>(); @@ -372,12 +370,8 @@ public List onTabComplete(CommandSender sender, Command command, String case "add": return getTownyStartingWith(args[2], "r"); case "remove": { - Resident resident = TownyUniverse.getInstance().getResident(player.getUniqueId()); - if (resident != null) { - try { - return NameUtil.filterByStart(NameUtil.getNames(resident.getTown().getOutlaws()), args[2]); - } catch (TownyException ignore) { - } + if (res != null && res.hasTown()) { + return NameUtil.filterByStart(NameUtil.getNames(res.getTownOrNull().getOutlaws()), args[2]); } } default: @@ -410,11 +404,8 @@ public List onTabComplete(CommandSender sender, Command command, String return getTownResidentNamesOfPlayerStartingWith(player, args[1]); break; case "set": - try { - Resident res = TownyUniverse.getInstance().getResident(player.getUniqueId()); - if (res != null) - return townSetTabComplete(sender, res.getTown(), args); - } catch (TownyException ignore) {} + if (res != null && res.hasTown()) + return townSetTabComplete(sender, res.getTownOrNull(), args); return Collections.emptyList(); case "invite": switch (args.length) { @@ -424,13 +415,9 @@ public List onTabComplete(CommandSender sender, Command command, String return returnValue; } else { if (args[1].startsWith("-")) { - Resident res = TownyUniverse.getInstance().getResident(player.getUniqueId()); - - if (res == null) - return null; - - try { - return NameUtil.filterByStart(res.getTown().getSentInvites() + if (res == null || !res.hasTown()) + return Collections.emptyList(); + return NameUtil.filterByStart(res.getTownOrNull().getSentInvites() // Get all sent invites .stream() .map(Invite::getReceiver) @@ -440,7 +427,6 @@ public List onTabComplete(CommandSender sender, Command command, String .stream() .map(e -> "-"+e) .collect(Collectors.toList()); - } catch (TownyException ignore) {} } else { return getVisibleResidentsForPlayerWithoutTownsStartingWith(args[1], sender); } @@ -449,19 +435,14 @@ public List onTabComplete(CommandSender sender, Command command, String switch (args[1].toLowerCase()) { case "accept": case "deny": { - Resident res = TownyUniverse.getInstance().getResident(player.getUniqueId()); - if (res == null) - return null; - - try { - return NameUtil.filterByStart(res.getTown().getReceivedInvites() + if (res == null || !res.hasTown()) + return Collections.emptyList(); + return NameUtil.filterByStart(res.getTownOrNull().getReceivedInvites() // Get the names of all received invites .stream() .map(Invite::getSender) .map(InviteSender::getName) .collect(Collectors.toList()),args[2]); - } catch (TownyException ignore) { - } } default: return Collections.emptyList(); @@ -660,7 +641,7 @@ private void parseTownCommand(final Player player, String[] split) throws TownyE } else { String townName = String.join("_", StringMgmt.remFirstArg(split)); boolean noCharge = TownySettings.getNewTownPrice() == 0.0 || !TownyEconomyHandler.isActive(); - newTown(player, townName, getResidentOrThrow(player.getUniqueId()), noCharge); + newTown(player, townName, getResidentOrThrow(player), noCharge); } break; case "reclaim": @@ -669,7 +650,7 @@ private void parseTownCommand(final Player player, String[] split) throws TownyE if(!TownySettings.getTownRuinsReclaimEnabled()) throw new TownyException(Translatable.of("msg_err_command_disable")); - TownRuinUtil.processRuinedTownReclaimRequest(player, plugin); + TownRuinUtil.processRuinedTownReclaimRequest(player); break; case "join": checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_TOWN_JOIN.getNode()); @@ -787,7 +768,7 @@ private void parseTownCommand(final Player player, String[] split) throws TownyE case "outlaw", "ban": checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_TOWN_OUTLAW.getNode()); catchRuinedTown(player); - parseTownOutlawCommand(player, StringMgmt.remFirstArg(split), false, getResidentOrThrow(player.getUniqueId()).getTown()); + parseTownOutlawCommand(player, StringMgmt.remFirstArg(split), false, getTownFromPlayerOrThrow(player)); break; case "bankhistory": checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_TOWN_BANKHISTORY.getNode()); @@ -915,14 +896,15 @@ private void parseTownPurgeCommand(Player player, String[] arg) throws TownyExce } private void parseInviteCommand(Player player, String[] newSplit) throws TownyException { - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); + Town town = getTownFromResidentOrThrow(resident); String received = Translatable.of("town_received_invites").forLocale(player) - .replace("%a", Integer.toString(resident.getTown().getReceivedInvites().size())) - .replace("%m", Integer.toString(InviteHandler.getReceivedInvitesMaxAmount(resident.getTown()))); + .replace("%a", Integer.toString(town.getReceivedInvites().size())) + .replace("%m", Integer.toString(InviteHandler.getReceivedInvitesMaxAmount(town))); String sent = Translatable.of("town_sent_invites").forLocale(player) - .replace("%a", Integer.toString(resident.getTown().getSentInvites().size())) - .replace("%m", Integer.toString(InviteHandler.getSentInvitesMaxAmount(resident.getTown()))); + .replace("%a", Integer.toString(town.getSentInvites().size())) + .replace("%m", Integer.toString(InviteHandler.getSentInvitesMaxAmount(town))); if (newSplit.length == 0) { // (/town invite) checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_TOWN_INVITE_SEE_HOME.getNode()); @@ -940,7 +922,7 @@ private void parseInviteCommand(Player player, String[] newSplit) throws TownyEx if (newSplit[0].equalsIgnoreCase("sent")) { // /invite(remfirstarg) sent args[1] checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_TOWN_INVITE_LIST_SENT.getNode()); - List sentinvites = resident.getTown().getSentInvites(); + List sentinvites = town.getSentInvites(); int page = 1; if (newSplit.length >= 2) { try { @@ -955,7 +937,7 @@ private void parseInviteCommand(Player player, String[] newSplit) throws TownyEx if (newSplit[0].equalsIgnoreCase("received")) { // /town invite received checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_TOWN_INVITE_LIST_RECEIVED.getNode()); - List receivedinvites = resident.getTown().getReceivedInvites(); + List receivedinvites = town.getReceivedInvites(); int page = 1; if (newSplit.length >= 2) { try { @@ -974,7 +956,6 @@ private void parseInviteCommand(Player player, String[] newSplit) throws TownyEx // invite (gone) // args[0] = accept = length = 1 // args[1] = [Nation] = length = 2 - Town town = resident.getTown(); Nation nation; List invites = town.getReceivedInvites(); @@ -1014,7 +995,6 @@ private void parseInviteCommand(Player player, String[] newSplit) throws TownyEx if (newSplit[0].equalsIgnoreCase("deny")) { // /town invite deny checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_TOWN_INVITE_DENY.getNode()); - Town town = resident.getTown(); Nation nation; List invites = town.getReceivedInvites(); @@ -1063,7 +1043,6 @@ private void parseInviteCommand(Player player, String[] newSplit) throws TownyEx } public static void parseTownOutlawCommand(CommandSender sender, String[] split, boolean admin, Town town) throws TownyException { - TownyUniverse townyUniverse = TownyUniverse.getInstance(); if (split.length == 0) { // Help output. @@ -1077,7 +1056,6 @@ public static void parseTownOutlawCommand(CommandSender sender, String[] split, } else { - Resident resident; Resident target = null; Town targetTown = null; @@ -1087,17 +1065,7 @@ public static void parseTownOutlawCommand(CommandSender sender, String[] split, if (split.length < 2) throw new TownyException(Translatable.of("msg_usage", "/town outlaw add/remove [name]")); - if (!admin) - resident = getResidentOrThrow(sender.getName()); - else - resident = town.getMayor(); // if this is an Admin-initiated command, dupe the action as if it were done by the mayor. - - target = townyUniverse.getResident(split[1]); - - if (target == null) { - TownyMessaging.sendErrorMsg(sender, Translatable.of("msg_err_invalid_name", split[1])); - return; - } + target = getResidentOrThrow(split[1]); if (split[0].equalsIgnoreCase("add")) { try { @@ -1106,7 +1074,7 @@ public static void parseTownOutlawCommand(CommandSender sender, String[] split, targetTown = TownyAPI.getInstance().getResidentTownOrNull(target); // Don't allow a resident to outlaw their own mayor. - if (resident.getTown().getMayor().equals(target)) + if (town.getMayor().equals(target)) return; // Call cancellable event. @@ -1385,7 +1353,7 @@ public static void townToggle(CommandSender sender, String[] split, boolean admi } if (!admin) { Resident resident = getResidentOrThrow(sender.getName()); - town = resident.getTown(); + town = getTownFromResidentOrThrow(resident); checkPermOrThrow(sender, PermissionNodes.TOWNY_COMMAND_TOWN_TOGGLE.getNode(split[0].toLowerCase())); } @@ -1908,7 +1876,7 @@ public void townRank(Player player, String[] split) throws TownyException { target = getResidentOrThrow(split[1]); town = getTownFromPlayerOrThrow(player); - if (town != target.getTown()) + if (!town.hasResident(target)) throw new TownyException(Translatable.of("msg_resident_not_your_town")); /* @@ -1984,8 +1952,8 @@ public static void townSet(CommandSender sender, String[] split, boolean admin, player = p; if (!admin && player != null) { - resident = getResidentOrThrow(player.getUniqueId()); - town = resident.getTown(); + resident = getResidentOrThrow(player); + town = getTownFromResidentOrThrow(resident); } else // Have the resident being tested be the mayor. resident = town.getMayor(); @@ -2249,7 +2217,7 @@ public static void townSetSurname(@NotNull CommandSender sender, @NotNull Reside TownyMessaging.sendMsg(sender, message); } - public static void townSetMayor(CommandSender sender, String[] split, boolean admin, Town town, Resident resident) throws TownyException, NotRegisteredException { + public static void townSetMayor(CommandSender sender, String[] split, boolean admin, Town town, Resident resident) throws TownyException { if (split.length < 2) throw new TownyException("Eg: /town set mayor Dumbo"); @@ -2941,7 +2909,7 @@ public static void townRename(CommandSender sender, Town town, String newName) { public void townLeave(Player player) throws TownyException { - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); Town town = getTownFromResidentOrThrow(resident); if (resident.isMayor()) @@ -3044,8 +3012,8 @@ public static void townKick(Player player, String[] names) { Resident resident; Town town; try { - resident = getResidentOrThrow(player.getUniqueId()); - town = resident.getTown(); + resident = getResidentOrThrow(player); + town = getTownFromResidentOrThrow(resident); } catch (TownyException x) { TownyMessaging.sendErrorMsg(player, x.getMessage(player)); return; @@ -3361,7 +3329,7 @@ public static void townAdd(CommandSender sender, Town specifiedTown, String[] na } else { resident = getResidentOrThrow(name); if (specifiedTown == null) - town = resident.getTown(); + town = getTownFromResidentOrThrow(resident); else town = specifiedTown; } @@ -3632,7 +3600,7 @@ public static void parseTownClaimCommand(Player player, String[] split) throws T return; } - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); Town town = getTownFromResidentOrThrow(resident); // Allow a bankrupt town to claim a single plot. @@ -3802,7 +3770,7 @@ public static void parseTownUnclaimCommand(Player player, String[] split) throws return; } - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); Town town = getTownFromResidentOrThrow(resident); TownyWorld world = TownyAPI.getInstance().getTownyWorld(player.getWorld()); @@ -3841,7 +3809,7 @@ public static void parseTownUnclaimCommand(Player player, String[] split) throws if (selection.isEmpty()) throw new TownyException(Translatable.of("msg_err_empty_area_selection")); - if (selection.get(0).getTownBlock().isHomeBlock()) + if (selection.get(0).getTownBlockOrNull().isHomeBlock()) throw new TownyException(Translatable.of("msg_err_cannot_unclaim_homeblock")); if (AreaSelectionUtil.filterHomeBlock(town, selection)) { @@ -3882,7 +3850,7 @@ public static void parseTownMergeCommand(CommandSender sender, String[] args, @N if (args.length <= 0) // /t merge throw new TownyException(Translatable.of("msg_specify_name")); - if (!admin && sender instanceof Player player && !getResidentOrThrow(player.getUniqueId()).isMayor()) + if (!admin && sender instanceof Player player && !getResidentOrThrow(player).isMayor()) throw new TownyException(Translatable.of("msg_town_merge_err_mayor_only")); Town succumbingTown = getTownOrThrow(args[0]); diff --git a/src/com/palmergames/bukkit/towny/command/TownyAdminCommand.java b/src/com/palmergames/bukkit/towny/command/TownyAdminCommand.java index 7792f93e748..f98f8f6a0f2 100644 --- a/src/com/palmergames/bukkit/towny/command/TownyAdminCommand.java +++ b/src/com/palmergames/bukkit/towny/command/TownyAdminCommand.java @@ -25,7 +25,6 @@ import com.palmergames.bukkit.towny.event.nation.NationRankRemoveEvent; import com.palmergames.bukkit.towny.exceptions.InvalidMetadataTypeException; import com.palmergames.bukkit.towny.exceptions.NoPermissionException; -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.exceptions.initialization.TownyInitException; import com.palmergames.bukkit.towny.object.Coord; @@ -908,14 +907,18 @@ private void parseAdminPlotClaim(Player player, String[] split) throws TownyExce new PlotClaim(plugin, player, resOpt.get(), selection, true, true, false).start(); } - private void parseAdminPlotClaimedAt(Player player) throws NoPermissionException, NotRegisteredException { + private void parseAdminPlotClaimedAt(Player player) throws TownyException { checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_TOWNYADMIN_PLOT_CLAIMEDAT.getNode()); WorldCoord wc = WorldCoord.parseWorldCoord(player); - if (!wc.hasTownBlock() || wc.getTownBlock().getClaimedAt() == 0) - throw new NotRegisteredException(); + if (!wc.hasTownBlock()) + throw new TownyException(Translatable.of("msg_not_claimed_1")); + + long claimedAt = wc.getTownBlockOrNull().getClaimedAt(); + if (claimedAt == 0) + throw new TownyException(Translatable.of("msg_err_townblock_has_no_claimedat_data")); - TownyMessaging.sendMsg(player, Translatable.of("msg_plot_perm_claimed_at").append(" " + TownyFormatter.fullDateFormat.format(wc.getTownBlock().getClaimedAt()))); + TownyMessaging.sendMsg(player, Translatable.of("msg_plot_perm_claimed_at").append(" " + TownyFormatter.fullDateFormat.format(claimedAt))); } private void parseAdminPlotTrust(Player player, String[] split) throws NoPermissionException, TownyException { @@ -1266,7 +1269,7 @@ public void parseAdminTownCommand(CommandSender sender, String[] split) throws T if (!town.hasNation()) throw new TownyException(Translatable.of("That town does not belong to a nation.")); - Nation nation = town.getNation(); + Nation nation = town.getNationOrNull(); town.removeNation(); plugin.resetCache(); @@ -1442,7 +1445,7 @@ private void parseAdminTownRankCommand(CommandSender sender, Town town, String[] if (!target.hasTown()) { throw new TownyException(Translatable.of("msg_err_resident_doesnt_belong_to_any_town")); } - if (target.getTown() != town) { + if (!town.hasResident(target)) { throw new TownyException(Translatable.of("msg_err_townadmintownrank_wrong_town")); } @@ -2328,16 +2331,13 @@ private static void handleTownMetaRemove(CommandSender sender, Town town, final public static void handlePlotMetaCommand(Player player, String[] split) throws TownyException { - String world = player.getWorld().getName(); - TownBlock townBlock = null; - try { - townBlock = new WorldCoord(world, Coord.parseCoord(player)).getTownBlock(); - } catch (Exception e) { - throw new TownyException(e.getMessage()); - } - checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_TOWNYADMIN_PLOT_META.getNode()); + WorldCoord wc = WorldCoord.parseWorldCoord(player); + if (wc.isWilderness()) + throw new TownyException(Translatable.of("msg_not_claimed_1")); + TownBlock townBlock = wc.getTownBlockOrNull(); + if (split.length == 1) { displayPlotMeta(player, townBlock); return; diff --git a/src/com/palmergames/bukkit/towny/command/TownyCommand.java b/src/com/palmergames/bukkit/towny/command/TownyCommand.java index 1bf4a5a6d9b..8611bf86135 100644 --- a/src/com/palmergames/bukkit/towny/command/TownyCommand.java +++ b/src/com/palmergames/bukkit/towny/command/TownyCommand.java @@ -190,7 +190,7 @@ else if (split.length > 1 && split[1].equalsIgnoreCase("hud")) if (world == null || !world.isUsingTowny()) throw new TownyException(Translatable.of("msg_err_usingtowny_disabled")); - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); ResidentUtil.openSelectionGUI(resident, SelectionGUI.SelectionType.SWITCHES); break; } @@ -199,7 +199,7 @@ else if (split.length > 1 && split[1].equalsIgnoreCase("hud")) if (world == null || !world.isUsingTowny()) throw new TownyException(Translatable.of("msg_err_usingtowny_disabled")); - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); ResidentUtil.openSelectionGUI(resident, SelectionGUI.SelectionType.ITEMUSE); break; } @@ -208,7 +208,7 @@ else if (split.length > 1 && split[1].equalsIgnoreCase("hud")) if (world == null || !world.isUsingTowny()) throw new TownyException(Translatable.of("msg_err_usingtowny_disabled")); - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); ResidentUtil.openSelectionGUI(resident, SelectionGUI.SelectionType.ALLOWEDBLOCKS); break; } @@ -217,7 +217,7 @@ else if (split.length > 1 && split[1].equalsIgnoreCase("hud")) if (world == null || !world.isUsingTowny()) throw new TownyException(Translatable.of("msg_err_usingtowny_disabled")); - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); ResidentUtil.openGUIInventory(resident, world.getUnclaimedZoneIgnoreMaterials(), Translatable.of("gui_title_towny_wildsblocks").forLocale(player)); break; } @@ -226,7 +226,7 @@ else if (split.length > 1 && split[1].equalsIgnoreCase("hud")) if (world == null || !world.isUsingTowny()) throw new TownyException(Translatable.of("msg_err_usingtowny_disabled")); - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); ResidentUtil.openGUIInventory(resident, world.getPlotManagementMayorDelete(), Translatable.of("gui_title_towny_plotclear").forLocale(player)); break; } @@ -273,7 +273,7 @@ else if (split.length > 1 && split[1].equalsIgnoreCase("hud")) catchConsole(sender); checkPermOrThrow(sender, PermissionNodes.TOWNY_CHAT_SPY.getNode()); - Resident resident = getResidentOrThrow(player.getUniqueId()); + Resident resident = getResidentOrThrow(player); resident.toggleMode(split, true); break; } diff --git a/src/com/palmergames/bukkit/towny/db/TownyDataSource.java b/src/com/palmergames/bukkit/towny/db/TownyDataSource.java index 8dc088753dd..58d9cbf9646 100644 --- a/src/com/palmergames/bukkit/towny/db/TownyDataSource.java +++ b/src/com/palmergames/bukkit/towny/db/TownyDataSource.java @@ -573,7 +573,7 @@ public void newTown(String name) throws AlreadyRegisteredException, NotRegistere abstract public void mergeTown(Town mergeInto, Town mergeFrom); - abstract public void renamePlayer(Resident resident, String newName) throws AlreadyRegisteredException, NotRegisteredException; + abstract public void renamePlayer(Resident resident, String newName); abstract public void renameGroup(PlotGroup group, String newName) throws AlreadyRegisteredException; } diff --git a/src/com/palmergames/bukkit/towny/db/TownyDatabaseHandler.java b/src/com/palmergames/bukkit/towny/db/TownyDatabaseHandler.java index 174997a7e06..0b7d5326b2e 100644 --- a/src/com/palmergames/bukkit/towny/db/TownyDatabaseHandler.java +++ b/src/com/palmergames/bukkit/towny/db/TownyDatabaseHandler.java @@ -579,14 +579,8 @@ public void removeTown(Town town, boolean delayFullRemoval) { if (TownyEconomyHandler.isActive()) town.getAccount().removeAccount(); - if (townyWorld != null) { - try { - townyWorld.removeTown(town); - } catch (NotRegisteredException e) { - // Must already be removed - } - saveWorld(townyWorld); - } + if (townyWorld != null && townyWorld.hasTown(town)) + townyWorld.removeTown(town); try { universe.unregisterTown(town); @@ -927,7 +921,7 @@ public void renameGroup(PlotGroup group, String newName) throws AlreadyRegistere } @Override - public void renamePlayer(Resident resident, String newName) throws AlreadyRegisteredException, NotRegisteredException { + public void renamePlayer(Resident resident, String newName) { lock.lock(); @@ -945,12 +939,8 @@ public void renamePlayer(Resident resident, String newName) throws AlreadyRegist if (TownyEconomyHandler.isActive() && resident.getAccountOrNull() != null) resident.getAccount().setName(newName); - // Remove the resident from the universe name storage. - universe.unregisterResident(resident); - //rename the resident - resident.setName(newName); - // Re-register the resident with the new name. - universe.registerResident(resident); + universe.changeResidentName(resident, newName); + // Set the economy account balance in ico5 (because it doesn't use UUIDs.) if (TownyEconomyHandler.isActive() && TownyEconomyHandler.getVersion().startsWith("iConomy 5")) { resident.getAccount().setName(resident.getName()); @@ -967,7 +957,7 @@ public void renamePlayer(Resident resident, String newName) throws AlreadyRegist // Save the town if the player was the mayor. if (resident.isMayor()) - saveTown(resident.getTown()); + saveTown(resident.getTownOrNull()); // Make an oldResident with the previous name for use in searching friends/outlawlists/deleting the old resident file. Resident oldResident = new Resident(oldName); @@ -977,7 +967,10 @@ public void renamePlayer(Resident resident, String newName) throws AlreadyRegist for (Resident toCheck : toSaveResident){ if (toCheck.hasFriend(oldResident)) { toCheck.removeFriend(oldResident); - toCheck.addFriend(resident); + if (!toCheck.hasFriend(resident)) + try { + toCheck.addFriend(resident); + } catch (AlreadyRegisteredException ignored) {} } } for (Resident toCheck : toSaveResident) @@ -988,7 +981,10 @@ public void renamePlayer(Resident resident, String newName) throws AlreadyRegist for (Town toCheckTown : toSaveTown) { if (toCheckTown.hasOutlaw(oldResident)) { toCheckTown.removeOutlaw(oldResident); - toCheckTown.addOutlaw(resident); + if (!toCheckTown.hasOutlaw(resident)) + try { + toCheckTown.addOutlaw(resident); + } catch (AlreadyRegisteredException ignored) {} } } for (Town toCheckTown : toSaveTown) diff --git a/src/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java b/src/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java index 38159e64500..92eddd7bae7 100644 --- a/src/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java +++ b/src/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java @@ -449,10 +449,8 @@ public boolean loadResident(Resident resident) { } catch (NotRegisteredException ignored) {} // Check if the older resident is a part of a town if (olderRes.hasTown()) { - try { - // Resident#removeTown saves the resident, so we can't use it. - olderRes.getTown().removeResident(olderRes); - } catch (NotRegisteredException nre) {} + // Resident#removeTown saves the resident, so we can't use it. + olderRes.getTownOrNull().removeResident(olderRes); } deleteResident(olderRes); } else { @@ -807,12 +805,15 @@ public boolean loadTown(Town town) { try { int x = Integer.parseInt(tokens[1]); int z = Integer.parseInt(tokens[2]); - TownBlock homeBlock = universe.getTownBlock(new WorldCoord(world.getName(), x, z)); - town.forceSetHomeBlock(homeBlock); + WorldCoord wc = new WorldCoord(world.getName(), x, z); + if (!universe.hasTownBlock(wc)) { + TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_homeblock_load_invalid_townblock", town.getName())); + } else { + TownBlock homeBlock = wc.getTownBlockOrNull();; + town.forceSetHomeBlock(homeBlock); + } } catch (NumberFormatException e) { TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_homeblock_load_invalid_location", town.getName())); - } catch (NotRegisteredException e) { - TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_homeblock_load_invalid_townblock", town.getName())); } catch (TownyException e) { TownyMessaging.sendErrorMsg(Translation.of("flatfile_err_town_homeblock_not_exist", town.getName())); } @@ -872,7 +873,9 @@ public boolean loadTown(Town town) { tokens = spawn.split(","); if (tokens.length >= 4) try { - World world = plugin.getServerWorld(tokens[0]); + World world = Bukkit.getWorld(tokens[0]); + if (world == null) + continue; double x = Double.parseDouble(tokens[1]); double y = Double.parseDouble(tokens[2]); double z = Double.parseDouble(tokens[3]); @@ -882,16 +885,16 @@ public boolean loadTown(Town town) { loc.setPitch(Float.parseFloat(tokens[4])); loc.setYaw(Float.parseFloat(tokens[5])); } - - TownBlock tb = universe.getTownBlock(WorldCoord.parseWorldCoord(loc)); - if (tb == null) + WorldCoord wc = WorldCoord.parseWorldCoord(loc); + if (!universe.hasTownBlock(wc)) continue; + TownBlock tb = wc.getTownBlockOrNull(); Jail jail = new Jail(UUID.randomUUID(), town, tb, new ArrayList<>(Collections.singleton(loc))); universe.registerJail(jail); town.addJail(jail); tb.setJail(jail); jail.save(); - } catch (NumberFormatException | NullPointerException | NotRegisteredException ignored) { + } catch (NumberFormatException | NullPointerException ignored) { } } } @@ -1789,15 +1792,21 @@ public boolean loadJail(Jail jail) { line = keys.get("townblock"); if (line != null) { - tokens = line.split(","); - TownBlock tb = null; try { - tb = universe.getTownBlock(new WorldCoord(tokens[0], Integer.parseInt(tokens[1].trim()), Integer.parseInt(tokens[2].trim()))); + tokens = line.split(","); + WorldCoord wc = new WorldCoord(tokens[0], Integer.parseInt(tokens[1].trim()), Integer.parseInt(tokens[2].trim())); + if (!universe.hasTownBlock(wc)) { + TownyMessaging.sendErrorMsg("Jail " + jail.getUUID() + " tried to load invalid townblock " + line + " deleting jail."); + removeJail(jail); + deleteJail(jail); + return true; + } + TownBlock tb = wc.getTownBlockOrNull(); jail.setTownBlock(tb); - jail.setTown(tb.getTown()); + jail.setTown(tb.getTownOrNull()); tb.setJail(jail); - tb.getTown().addJail(jail); - } catch (NumberFormatException | NotRegisteredException e) { + tb.getTownOrNull().addJail(jail); + } catch (NumberFormatException e) { TownyMessaging.sendErrorMsg("Jail " + jail.getUUID() + " tried to load invalid townblock " + line + " deleting jail."); removeJail(jail); deleteJail(jail); @@ -1878,10 +1887,7 @@ public boolean saveResident(Resident resident) { list.add("surname=" + resident.getSurname()); if (resident.hasTown()) { - try { - list.add("town=" + resident.getTown().getName()); - } catch (NotRegisteredException ignored) { - } + list.add("town=" + resident.getTownOrNull().getName()); list.add("town-ranks=" + StringMgmt.join(resident.getTownRanks(), ",")); list.add("nation-ranks=" + StringMgmt.join(resident.getNationRanks(), ",")); } @@ -2287,18 +2293,20 @@ public boolean saveTownBlock(TownBlock townBlock) { List list = new ArrayList<>(); + // town + if (townBlock.hasTown()) // This should always be true. + list.add("town=" + townBlock.getTownOrNull().getName()); + else { + TownyMessaging.sendErrorMsg("TownBlock with no Town attempted to save: " + townBlock.toString() + ". This townblock will not be saved to the database."); + return true; // None of the methods that call this care about the return value. + } + // name list.add("name=" + townBlock.getName()); // price list.add("price=" + townBlock.getPlotPrice()); - // town - try { - list.add("town=" + townBlock.getTown().getName()); - } catch (NotRegisteredException ignored) { - } - // resident if (townBlock.hasResident()) list.add("resident=" + townBlock.getResidentOrNull().getName()); @@ -2418,11 +2426,8 @@ public void deleteTownBlock(TownBlock townBlock) { // This will move a deleted townblock to either: // towny\townblocks\worldname\deleted\townname folder, or the // towny\townblocks\worldname\deleted\ folder if there is not valid townname. - String name = null; - try { - name = townBlock.getTown().getName(); - } catch (NotRegisteredException ignored) { - } + Town town = townBlock.getTownOrNull(); + String name = town != null ? town.getName() : null; if (name != null) FileMgmt.moveTownBlockFile(file, "deleted", name); else diff --git a/src/com/palmergames/bukkit/towny/db/TownySQLSource.java b/src/com/palmergames/bukkit/towny/db/TownySQLSource.java index 247e800f5a3..0d420667d9d 100644 --- a/src/com/palmergames/bukkit/towny/db/TownySQLSource.java +++ b/src/com/palmergames/bukkit/towny/db/TownySQLSource.java @@ -752,10 +752,8 @@ private boolean loadResident(Resident resident, ResultSet rs) { } catch (NotRegisteredException ignored) {} // Check if the older resident is a part of a town if (olderRes.hasTown()) { - try { - // Resident#removeTown saves the resident, so we can't use it. - olderRes.getTown().removeResident(olderRes); - } catch (NotRegisteredException nre) {} + // Resident#removeTown saves the resident, so we can't use it. + olderRes.getTownOrNull().removeResident(olderRes); } deleteResident(olderRes); } else { @@ -1020,15 +1018,16 @@ private boolean loadTown(ResultSet rs) { try { int x = Integer.parseInt(tokens[1]); int z = Integer.parseInt(tokens[2]); - TownBlock homeBlock = universe - .getTownBlock(new WorldCoord(world.getName(), x, z)); - town.forceSetHomeBlock(homeBlock); + WorldCoord wc = new WorldCoord(world.getName(), x, z); + if (!universe.hasTownBlock(wc)) { + TownyMessaging.sendErrorMsg("[Warning] " + town.getName() + " homeBlock tried to load invalid TownBlock."); + } else { + TownBlock homeBlock = wc.getTownBlockOrNull(); + town.forceSetHomeBlock(homeBlock); + } } catch (NumberFormatException e) { TownyMessaging.sendErrorMsg( "[Warning] " + town.getName() + " homeBlock tried to load invalid location."); - } catch (NotRegisteredException e) { - TownyMessaging.sendErrorMsg( - "[Warning] " + town.getName() + " homeBlock tried to load invalid TownBlock."); } catch (TownyException e) { TownyMessaging.sendErrorMsg("[Warning] " + town.getName() + " does not have a home block."); } @@ -1089,7 +1088,9 @@ private boolean loadTown(ResultSet rs) { tokens = spawn.split(search); if (tokens.length >= 4) try { - World world = plugin.getServerWorld(tokens[0]); + World world = Bukkit.getWorld(tokens[0]); + if (world == null) + continue; double x = Double.parseDouble(tokens[1]); double y = Double.parseDouble(tokens[2]); double z = Double.parseDouble(tokens[3]); @@ -1099,16 +1100,16 @@ private boolean loadTown(ResultSet rs) { loc.setPitch(Float.parseFloat(tokens[4])); loc.setYaw(Float.parseFloat(tokens[5])); } - - TownBlock tb = universe.getTownBlock(WorldCoord.parseWorldCoord(loc)); - if (tb == null) + WorldCoord wc = WorldCoord.parseWorldCoord(loc); + if (!universe.hasTownBlock(wc)) continue; + TownBlock tb = wc.getTownBlockOrNull(); Jail jail = new Jail(UUID.randomUUID(), town, tb, new ArrayList<>(Collections.singleton(loc))); universe.registerJail(jail); town.addJail(jail); tb.setJail(jail); jail.save(); - } catch (NumberFormatException | NullPointerException | NotRegisteredException ignored) { + } catch (NumberFormatException | NullPointerException ignored) { } } } @@ -1768,18 +1769,22 @@ public boolean loadTownBlocks() { try (Statement s = cntx.createStatement(); ResultSet rs = s.executeQuery("SELECT * FROM " + tb_prefix + "TOWNBLOCKS")) { + List warnedWorlds = new ArrayList<>(); + while (rs.next()) { String worldName = rs.getString("world"); int x = rs.getInt("x"); int z = rs.getInt("z"); - - try { - townBlock = universe.getTownBlock(new WorldCoord(worldName, x, z)); - } catch (NotRegisteredException ex) { - TownyMessaging.sendErrorMsg("Loading Error: Exception while fetching townblock: " + worldName + " " - + x + " " + z + " from memory!"); - return false; + WorldCoord wc = new WorldCoord(worldName, x, z); + if (!universe.hasTownBlock(wc)) { + if (warnedWorlds.contains(worldName)) + continue; + warnedWorlds.add(worldName); + TownyMessaging.sendErrorMsg("Loading Error: Exception while fetching townblock: " + worldName + " " + x + " " + z + " from memory!"); + TownyMessaging.sendErrorMsg("Towny is going to continue trying to loading townblocks, but you wont see anymore failures for this world."); + continue; } + townBlock = wc.getTownBlockOrNull(); line = rs.getString("name"); if (line != null) @@ -2052,15 +2057,21 @@ private boolean loadJail(ResultSet rs) { line = rs.getString("townBlock"); if (line != null) { - tokens = line.split("#"); - TownBlock tb = null; try { - tb = universe.getTownBlock(new WorldCoord(tokens[0], Integer.parseInt(tokens[1].trim()), Integer.parseInt(tokens[2].trim()))); + tokens = line.split("#"); + WorldCoord wc = new WorldCoord(tokens[0], Integer.parseInt(tokens[1].trim()), Integer.parseInt(tokens[2].trim())); + if (!universe.hasTownBlock(wc)) { + TownyMessaging.sendErrorMsg("Jail " + jail.getUUID() + " tried to load invalid townblock " + line + " deleting jail."); + removeJail(jail); + deleteJail(jail); + return true; + } + TownBlock tb = wc.getTownBlockOrNull(); jail.setTownBlock(tb); - jail.setTown(tb.getTown()); + jail.setTown(tb.getTownOrNull()); tb.setJail(jail); - tb.getTown().addJail(jail); - } catch (NumberFormatException | NotRegisteredException e) { + tb.getTownOrNull().addJail(jail); + } catch (NumberFormatException e) { TownyMessaging.sendErrorMsg("Jail " + jail.getUUID() + " tried to load invalid townblock " + line + " deleting jail."); removeJail(jail); deleteJail(jail); @@ -2133,7 +2144,7 @@ public synchronized boolean saveResident(Resident resident) { res_hm.put("jailBail", resident.getJailBailCost()); res_hm.put("title", resident.getTitle()); res_hm.put("surname", resident.getSurname()); - res_hm.put("town", resident.hasTown() ? resident.getTown().getName() : ""); + res_hm.put("town", resident.hasTown() ? resident.getTownOrNull().getName() : ""); res_hm.put("town-ranks", resident.hasTown() ? StringMgmt.join(resident.getTownRanks(), "#") : ""); res_hm.put("nation-ranks", resident.hasTown() ? StringMgmt.join(resident.getNationRanks(), "#") : ""); res_hm.put("friends", StringMgmt.join(resident.getFriends(), "#")); @@ -2468,7 +2479,7 @@ public synchronized boolean saveTownBlock(TownBlock townBlock) { tb_hm.put("z", townBlock.getZ()); tb_hm.put("name", townBlock.getName()); tb_hm.put("price", townBlock.getPlotPrice()); - tb_hm.put("town", townBlock.getTown().getName()); + tb_hm.put("town", townBlock.hasTown() ? townBlock.getTownOrNull().getName() : ""); tb_hm.put("resident", (townBlock.hasResident()) ? townBlock.getResidentOrNull().getName() : ""); tb_hm.put("typeName", townBlock.getTypeName()); tb_hm.put("outpost", townBlock.isOutpost()); diff --git a/src/com/palmergames/bukkit/towny/huds/HUDManager.java b/src/com/palmergames/bukkit/towny/huds/HUDManager.java index 2d393413254..8e7edd65e36 100644 --- a/src/com/palmergames/bukkit/towny/huds/HUDManager.java +++ b/src/com/palmergames/bukkit/towny/huds/HUDManager.java @@ -3,7 +3,6 @@ import com.palmergames.bukkit.towny.Towny; import com.palmergames.bukkit.towny.event.PlayerChangePlotEvent; import com.palmergames.bukkit.towny.event.TownBlockSettingsChangedEvent; -import com.palmergames.bukkit.towny.object.Coord; import com.palmergames.bukkit.towny.object.WorldCoord; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -90,20 +89,13 @@ public void onPlayerMovePlotsEvent(PlayerChangePlotEvent event) { public void onTownBlockSettingsChanged (TownBlockSettingsChangedEvent e) { if (e.getTownyWorld() != null) - for (Player p : permUsers) - PermHUD.updatePerms(p); + permUsers.forEach(p -> PermHUD.updatePerms(p)); else if (e.getTown() != null) - for (Player p : permUsers) - try { - if (new WorldCoord(p.getWorld().getName(), Coord.parseCoord(p)).getTownBlock().getTown() == e.getTown()) - PermHUD.updatePerms(p); - } catch (Exception ex) {} + permUsers.stream().filter(p -> WorldCoord.parseWorldCoord(p).hasTown(e.getTown())) + .forEach(p -> PermHUD.updatePerms(p)); else if (e.getTownBlock() != null) - for (Player p : permUsers) - try { - if (new WorldCoord(p.getWorld().getName(), Coord.parseCoord(p)).getTownBlock() == e.getTownBlock()) - PermHUD.updatePerms(p); - } catch (Exception ex) {} + permUsers.stream().filter(p -> e.getTownBlock().getWorldCoord().equals(WorldCoord.parseWorldCoord(p))) + .forEach(p -> PermHUD.updatePerms(p)); } public static String check(String string) { diff --git a/src/com/palmergames/bukkit/towny/huds/MapHUD.java b/src/com/palmergames/bukkit/towny/huds/MapHUD.java index 0a824f0c215..0a6aac05232 100644 --- a/src/com/palmergames/bukkit/towny/huds/MapHUD.java +++ b/src/com/palmergames/bukkit/towny/huds/MapHUD.java @@ -7,6 +7,7 @@ import com.palmergames.bukkit.towny.TownyUniverse; import com.palmergames.bukkit.towny.event.asciimap.WildernessMapEvent; import com.palmergames.bukkit.towny.exceptions.TownyException; +import com.palmergames.bukkit.towny.object.Coord; import com.palmergames.bukkit.towny.object.Nation; import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.Town; @@ -94,9 +95,10 @@ public static void updateMap(Player player, WorldCoord wc) { for (int tbx = wc.getZ() - halfLineHeight; tbx <= wc.getZ() + (lineHeight - halfLineHeight - 1); tbx++) { map[y][x] = Colors.White; try { - TownBlock townblock = world.getTownBlock(tby, tbx); - if (!townblock.hasTown()) + WorldCoord currentWC = new WorldCoord(world.getBukkitWorld(), new Coord(tby, tbx)); + if (currentWC.isWilderness()) throw new TownyException(); + TownBlock townblock = currentWC.getTownBlockOrNull(); Town town = townblock.getTownOrNull(); if (x == halfLineHeight && y == halfLineWidth) // This is the player's location, colour it special. @@ -110,7 +112,7 @@ else if (resident.hasTown()) map[y][x] = Colors.LightGreen; } else if (resident.hasNation()) { Nation resNation = resident.getNationOrNull(); - if (resNation.hasTown(townblock.getTown())) + if (resNation.hasTown(town)) // own nation map[y][x] = Colors.Green; else if (town.hasNation()) { diff --git a/src/com/palmergames/bukkit/towny/listeners/TownyBlockListener.java b/src/com/palmergames/bukkit/towny/listeners/TownyBlockListener.java index 746aec6812a..a8180964b23 100644 --- a/src/com/palmergames/bukkit/towny/listeners/TownyBlockListener.java +++ b/src/com/palmergames/bukkit/towny/listeners/TownyBlockListener.java @@ -5,7 +5,6 @@ import com.palmergames.bukkit.towny.TownySettings; import com.palmergames.bukkit.towny.TownyUniverse; import com.palmergames.bukkit.towny.event.executors.TownyActionEventExecutor; -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.object.TownBlock; import com.palmergames.bukkit.towny.object.TownyWorld; import com.palmergames.bukkit.towny.object.WorldCoord; @@ -241,23 +240,23 @@ private boolean canBlockMove(Block block, Block blockTo, boolean allowWild) { WorldCoord from = WorldCoord.parseWorldCoord(block); WorldCoord to = WorldCoord.parseWorldCoord(blockTo); - if (from.equals(to) || (allowWild && to.isWilderness()) || (to.isWilderness() && from.isWilderness())) + // Same WorldCoord, Both are Wilderness, or We allow moving from Town to Wild. + if (from.equals(to) || (to.isWilderness() && from.isWilderness()) || (allowWild && to.isWilderness())) return true; - try { - TownBlock currentTownBlock = from.getTownBlock(); - TownBlock destinationTownBlock = to.getTownBlock(); + if (from.isWilderness()) + return false; - //Both townblocks are owned by the same resident. - if (currentTownBlock.hasResident() && destinationTownBlock.hasResident() && currentTownBlock.getResidentOrNull() == destinationTownBlock.getResidentOrNull()) - return true; + // At this point we know that "to" is not wilderness, because "from" is not. + TownBlock currentTownBlock = from.getTownBlockOrNull(); + TownBlock destinationTownBlock = to.getTownBlockOrNull(); - //Both townblocks are owned by the same town. - return currentTownBlock.getTown() == destinationTownBlock.getTown() && !currentTownBlock.hasResident() && !destinationTownBlock.hasResident(); - } catch (NotRegisteredException e) { - //The 'from' townblock is wilderness. - return false; - } + //Both townblocks are owned by the same resident. + if (currentTownBlock.hasResident() && destinationTownBlock.hasResident() && currentTownBlock.getResidentOrNull() == destinationTownBlock.getResidentOrNull()) + return true; + + //Both townblocks are owned by the same town. + return currentTownBlock.getTownOrNull() == destinationTownBlock.getTownOrNull() && !currentTownBlock.hasResident() && !destinationTownBlock.hasResident(); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) diff --git a/src/com/palmergames/bukkit/towny/object/Nation.java b/src/com/palmergames/bukkit/towny/object/Nation.java index 9e0dd52e6c6..4054198446a 100644 --- a/src/com/palmergames/bukkit/towny/object/Nation.java +++ b/src/com/palmergames/bukkit/towny/object/Nation.java @@ -427,7 +427,7 @@ public void setKing(Resident king) throws TownyException { throw new TownyException(Translatable.of("msg_err_king_not_in_nation")); if (!king.isMayor()) throw new TownyException(Translatable.of("msg_err_new_king_notmayor")); - setCapital(king.getTown()); + setCapital(king.getTownOrNull()); this.save(); } diff --git a/src/com/palmergames/bukkit/towny/object/Resident.java b/src/com/palmergames/bukkit/towny/object/Resident.java index 69a8ddccdfd..35a4462f7d3 100644 --- a/src/com/palmergames/bukkit/towny/object/Resident.java +++ b/src/com/palmergames/bukkit/towny/object/Resident.java @@ -230,6 +230,12 @@ public boolean hasNation() { return hasTown() && town.hasNation(); } + /** + * Not used internally by Towny. It is preferred to use {@link #getTownOrNull()} instead. + * + * @return Town belonging to the Resident or throw {@link NotRegisteredException} + * @throws NotRegisteredException exception thrown when the resident has no Town. + */ public Town getTown() throws NotRegisteredException { if (hasTown()) @@ -287,19 +293,8 @@ public void removeTown() { return; Town town = this.town; - - BukkitTools.fireEvent(new TownPreRemoveResidentEvent(this, town)); - - try { - - town.removeResident(this); - - } catch (NotRegisteredException e1) { - e1.printStackTrace(); - } catch (EmptyTownException ignore) { - } - BukkitTools.fireEvent(new TownRemoveResidentEvent(this, town)); + BukkitTools.fireEvent(new TownPreRemoveResidentEvent(this, town)); // Remove any non-embassy plots owned by the player in the town that was just left. for (TownBlock townBlock : town.getTownBlocks()) { @@ -315,14 +310,22 @@ public void removeTown() { townBlock.save(); } } - + + try { + + town.removeResident(this); + + } catch (EmptyTownException ignore) {} + + BukkitTools.fireEvent(new TownRemoveResidentEvent(this, town)); + try { setTown(null); } catch (AlreadyRegisteredException ignored) { // It cannot reach the point in the code at which the exception can be thrown. } - + this.save(); // Reset everyones cache permissions as this player losing their could affect multiple areas @@ -880,7 +883,9 @@ public void setJoinedTownAt(long joinedTownAt) { } public Nation getNation() throws TownyException { - return getTown().getNation(); + if (!hasNation()) + throw new TownyException(Translatable.of("msg_err_that_resident_doesnt_belong_to_that_nation")); + return getNationOrNull(); } @Nullable diff --git a/src/com/palmergames/bukkit/towny/object/Town.java b/src/com/palmergames/bukkit/towny/object/Town.java index 3b258f1cf23..41d1788896b 100644 --- a/src/com/palmergames/bukkit/towny/object/Town.java +++ b/src/com/palmergames/bukkit/towny/object/Town.java @@ -215,6 +215,12 @@ public void setFounder(String founderName) { this.founderName = founderName; } + /** + * Not used internally by Towny. It is preferred to use {@link #getNationOrNull()} instead. + * + * @return Nation belonging to the Town or throw {@link NotRegisteredException} + * @throws NotRegisteredException exception thrown when the Town has no Nation. + */ public Nation getNation() throws NotRegisteredException { if (hasNation()) @@ -355,15 +361,10 @@ void addResident(Resident resident) { public void addResidentCheck(Resident resident) throws AlreadyRegisteredException { - if (hasResident(resident)) + if (hasResident(resident)) // In this town already. throw new AlreadyRegisteredException(Translation.of("msg_err_already_in_town", resident.getName(), getFormattedName())); - else if (resident.hasTown()) - try { - if (!resident.getTown().equals(this)) - throw new AlreadyRegisteredException(Translation.of("msg_err_already_in_town", resident.getName(), resident.getTown().getFormattedName())); - } catch (NotRegisteredException e) { - e.printStackTrace(); - } + else if (resident.hasTown()) // In a different town already. + throw new AlreadyRegisteredException(Translation.of("msg_err_already_in_town", resident.getName(), resident.getTownOrNull().getFormattedName())); } public boolean isMayor(Resident resident) { @@ -737,12 +738,8 @@ public void setWorld(TownyWorld world) { if (this.world == world) return; - if (hasWorld()) { - try { - world.removeTown(this); - } catch (NotRegisteredException ignored) { - } - } + if (hasWorld()) + this.world.removeTown(this); this.world = world; @@ -771,19 +768,16 @@ public boolean hasMayor() { return mayor != null; } - public void removeResident(Resident resident) throws EmptyTownException, NotRegisteredException { + public void removeResident(Resident resident) throws EmptyTownException { - if (!hasResident(resident)) { - throw new NotRegisteredException(); - } else { + if (!hasResident(resident)) + return; - remove(resident); - resident.setJoinedTownAt(0); + remove(resident); + resident.setJoinedTownAt(0); - if (getNumResidents() == 0) { - throw new EmptyTownException(this); - } - } + if (getNumResidents() == 0) + throw new EmptyTownException(this); } private void remove(Resident resident) { @@ -1146,13 +1140,8 @@ public void addOutlawCheck(Resident resident) throws AlreadyRegisteredException if (hasOutlaw(resident)) throw new AlreadyRegisteredException(Translation.of("msg_err_resident_already_an_outlaw")); - else if (resident.hasTown()) - try { - if (resident.getTown().equals(this)) - throw new AlreadyRegisteredException(Translation.of("msg_err_not_outlaw_in_your_town")); - } catch (NotRegisteredException e) { - e.printStackTrace(); - } + else if (hasResident(resident)) + throw new AlreadyRegisteredException(Translation.of("msg_err_not_outlaw_in_your_town")); } public void removeOutlaw(Resident resident) { diff --git a/src/com/palmergames/bukkit/towny/object/TownBlock.java b/src/com/palmergames/bukkit/towny/object/TownBlock.java index 020fd1ca88a..be89b8fb923 100644 --- a/src/com/palmergames/bukkit/towny/object/TownBlock.java +++ b/src/com/palmergames/bukkit/towny/object/TownBlock.java @@ -83,6 +83,12 @@ public void setTown(Town town, boolean updateClaimedAt) { } catch (AlreadyRegisteredException | NullPointerException ignored) {} } + /** + * Not used internally by Towny. It is preferred to use {@link #getTownOrNull()} instead. + * + * @return Town belonging to the TownBlock or throw {@link NotRegisteredException} + * @throws NotRegisteredException exception thrown when the TownBlock has no Town. + */ public Town getTown() throws NotRegisteredException { if (!hasTown()) @@ -187,6 +193,12 @@ public boolean setResident(@Nullable Resident resident, boolean callEvent) { return true; } + /** + * Not used internally by Towny. It is preferred to use {@link #getResidentOrNull()} instead. + * + * @return Resident belonging to the TownBlock or throw {@link NotRegisteredException} + * @throws NotRegisteredException exception thrown when the TownBlock has no Resident. + */ public Resident getResident() throws NotRegisteredException { if (!hasResident()) @@ -392,7 +404,7 @@ public void setType(TownBlockType type, Resident resident) throws TownyException setType(type); if (this.isJail() && resident.getPlayer() != null) - JailUtil.createJailPlot(this, getTown(), resident.getPlayer().getLocation()); + JailUtil.createJailPlot(this, town, resident.getPlayer().getLocation()); this.save(); } diff --git a/src/com/palmergames/bukkit/towny/object/TownBlockOwner.java b/src/com/palmergames/bukkit/towny/object/TownBlockOwner.java index 534f51f72c3..4245f5b5271 100644 --- a/src/com/palmergames/bukkit/towny/object/TownBlockOwner.java +++ b/src/com/palmergames/bukkit/towny/object/TownBlockOwner.java @@ -1,8 +1,6 @@ package com.palmergames.bukkit.towny.object; import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; - import java.util.Collection; /** @@ -41,7 +39,6 @@ public interface TownBlockOwner extends Permissible, Nameable { * Removes townblock from the list of existing townblocks. * * @param townBlock The townblock to remove. - * @throws NotRegisteredException Thrown when the townblock given is not in the list. */ - void removeTownBlock(TownBlock townBlock) throws NotRegisteredException; + void removeTownBlock(TownBlock townBlock); } diff --git a/src/com/palmergames/bukkit/towny/object/TownyWorld.java b/src/com/palmergames/bukkit/towny/object/TownyWorld.java index a76b9fb4abb..a718a63443e 100644 --- a/src/com/palmergames/bukkit/towny/object/TownyWorld.java +++ b/src/com/palmergames/bukkit/towny/object/TownyWorld.java @@ -127,22 +127,6 @@ public void addTown(Town town) { towns.put(town.getName(), town); } - public TownBlock getTownBlock(Coord coord) throws NotRegisteredException { - if (!hasTownBlock(coord)) - throw new NotRegisteredException(); - return TownyUniverse.getInstance().getTownBlock(new WorldCoord(this.getName(), this.getUUID(), coord)); - } - - public boolean hasTownBlock(Coord key) { - - return TownyUniverse.getInstance().hasTownBlock(new WorldCoord(this.getName(), this.getUUID(), key)); - } - - public TownBlock getTownBlock(int x, int z) throws NotRegisteredException { - - return getTownBlock(new Coord(x, z)); - } - public List getTownBlocks(Town town) { List out = new ArrayList<>(); @@ -164,19 +148,10 @@ public Collection getTownBlocks() { return townBlocks; } - public void removeTown(Town town) throws NotRegisteredException { + public void removeTown(Town town) { - if (!hasTown(town)) - throw new NotRegisteredException(); - else { + if (hasTown(town)) towns.remove(town.getName()); - /* - * try { - * town.setWorld(null); - * } catch (AlreadyRegisteredException e) { - * } - */ - } } @Override @@ -1001,4 +976,42 @@ public boolean isFriendlyFireEnabled( ) { public void save() { TownyUniverse.getInstance().getDataSource().saveWorld(this); } + + /** + * Unused by Towny. + * + * @deprecated since 0.98.6.9 use {@link TownyUniverse.getInstance().getTownBlockOrNull(WorldCoord)} instead. + * @param coord Coord from this TownyWorld to get a TownBlock from. + * @return TownBlock or NotRegisteredException. + * @throws NotRegisteredException + */ + @Deprecated + public TownBlock getTownBlock(Coord coord) throws NotRegisteredException { + return TownyUniverse.getInstance().getTownBlock(new WorldCoord(this.getName(), this.getUUID(), coord)); + } + + /** + * Unused by Towny. + * + * @deprecated since 0.98.6.9 use {@link TownyUniverse.getInstance().getTownBlockOrNull(WorldCoord)} instead. + * @param coord Coord from this TownyWorld to get a TownBlock from. + * @return TownBlock or NotRegisteredException. + * @throws NotRegisteredException + */ + @Deprecated + public TownBlock getTownBlock(int x, int z) throws NotRegisteredException { + return getTownBlock(new Coord(x, z)); + } + + /** + * Unused by Towny. + * + * @deprecated since 0.98.6.9 use {@link TownyUniverse.getInstance().hasTownBlock(WorldCoord)} instead. + * @param coord Coord from this TownyWorld to get a TownBlock from. + * @return true if the TownBlock exists. + */ + @Deprecated + public boolean hasTownBlock(Coord key) { + return TownyUniverse.getInstance().hasTownBlock(new WorldCoord(this.getName(), this.getUUID(), key)); + } } diff --git a/src/com/palmergames/bukkit/towny/object/WorldCoord.java b/src/com/palmergames/bukkit/towny/object/WorldCoord.java index 71f240a4eaa..e0f8df7b83b 100644 --- a/src/com/palmergames/bukkit/towny/object/WorldCoord.java +++ b/src/com/palmergames/bukkit/towny/object/WorldCoord.java @@ -171,12 +171,12 @@ public TownyWorld getTownyWorldOrNull() { /** * Shortcut for TownyUniverse.getInstance().getTownBlock(WorldCoord). * + * @deprecated as of 0.98.6.9 use {@link #getTownBlockOrNull()} instead. * @return the relevant TownBlock instance. * @throws NotRegisteredException If there is no TownBlock at this WorldCoord. */ + @Deprecated public TownBlock getTownBlock() throws NotRegisteredException { - if (!hasTownBlock()) - throw new NotRegisteredException(); return TownyUniverse.getInstance().getTownBlock(this); } diff --git a/src/com/palmergames/bukkit/towny/tasks/OnPlayerLogin.java b/src/com/palmergames/bukkit/towny/tasks/OnPlayerLogin.java index ea3ca18305e..cd4cd3c2ceb 100644 --- a/src/com/palmergames/bukkit/towny/tasks/OnPlayerLogin.java +++ b/src/com/palmergames/bukkit/towny/tasks/OnPlayerLogin.java @@ -33,7 +33,7 @@ public class OnPlayerLogin implements Runnable { Towny plugin; - com.palmergames.bukkit.towny.TownyUniverse universe; + TownyUniverse universe; volatile Player player; /** @@ -45,100 +45,14 @@ public class OnPlayerLogin implements Runnable { public OnPlayerLogin(Towny plugin, Player player) { this.plugin = plugin; - this.universe = com.palmergames.bukkit.towny.TownyUniverse.getInstance(); + this.universe = TownyUniverse.getInstance(); this.player = player; } @Override public void run() { - Resident resident = null; - - if (!universe.hasResident(player.getUniqueId())) { - /* - * No record of this resident's UUID. - */ - resident = universe.getResident(player.getName()); - - // If the universe has a resident and the resident has no UUID, log them in with their current name. - if (resident != null && !resident.hasUUID()) { - loginExistingResident(resident); - - // We have a resident but the resident's UUID was not recorded properly (or the server has somehow altered the player's UUID since recording it.) - } else if (resident != null && !resident.getUUID().equals(player.getUniqueId())) { - try { - universe.unregisterResident(resident); // Unregister. - resident.setUUID(player.getUniqueId()); // Set proper UUID. - universe.registerResident(resident); // Re-register. - - } catch (NotRegisteredException | AlreadyRegisteredException ignored) {} - loginExistingResident(resident); - - // Else we're dealing with a new resident, because there's no resident by that UUID or resident by that Name without a UUID. - } else { - - /* - * Make a brand new Resident. - */ - try { - universe.getDataSource().newResident(player.getName(), player.getUniqueId()); - TownySettings.incrementUUIDCount(); - - resident = universe.getResident(player.getUniqueId()); - - if (TownySettings.isShowingLocaleMessage()) - TownyMessaging.sendMsg(resident, Translatable.of("msg_your_locale", player.getLocale())); - - resident.setRegistered(System.currentTimeMillis()); - - final Resident finalResident = resident; - universe.getDataSource().getHibernatedResidentRegistered(player.getUniqueId()).thenAccept(registered -> { - if (registered.isPresent()) { - finalResident.setRegistered(registered.get()); - finalResident.save(); - } - }); - - resident.setLastOnline(System.currentTimeMillis()); - if (!TownySettings.getDefaultTownName().equals("")) { - Town town = TownyUniverse.getInstance().getTown(TownySettings.getDefaultTownName()); - if (town != null) { - try { - resident.setTown(town); - town.save(); - } catch (AlreadyRegisteredException ignore) {} - } - } - - resident.save(); - BukkitTools.fireEvent(new NewResidentEvent(resident)); - - } catch (AlreadyRegisteredException | NotRegisteredException ignored) {} - - } - - } else { - /* - * We do have record of this UUID being used before, log in the resident after checking for a name change. - */ - resident = universe.getResident(player.getUniqueId()); - - // Name change test. - if (!resident.getName().equals(player.getName())) { - try { - universe.getDataSource().renamePlayer(resident, player.getName()); - } catch (AlreadyRegisteredException e) { - e.printStackTrace(); - } catch (NotRegisteredException e) { - e.printStackTrace(); - } - } - /* - * This resident is known so fetch the data and update it. - */ - resident = universe.getResident(player.getUniqueId()); - loginExistingResident(resident); - } + Resident resident = tryGetOrCreateResident(); if (resident != null) { TownyPerms.assignPermissions(resident, player); @@ -180,6 +94,92 @@ public void run() { } } } + + private Resident tryGetOrCreateResident() { + Resident resident = null; + if (!universe.hasResident(player.getUniqueId())) { + /* + * No record of this resident's UUID. + */ + resident = universe.getResident(player.getName()); + + // If the universe has a resident by this name but the resident has no UUID, log + // them in with their current name. + if (resident != null && !resident.hasUUID()) { + loginExistingResident(resident); + + // We have a resident but the resident's UUID was not recorded properly (or the + // server has somehow altered the player's UUID since recording it. ie: Offline mode) + } else if (resident != null && !resident.getUUID().equals(player.getUniqueId())) { + universe.changeResidentUUID(resident, player.getUniqueId()); + loginExistingResident(resident); + + // Else resident is null and we're dealing with a new resident, because there's + // no resident by that UUID or resident by that Name without a UUID. + } else { + resident = createANewResident(resident); + + } + return resident; + } + + /* + * We do have record of this UUID being used before, log in the resident after checking for a name change. + */ + resident = universe.getResident(player.getUniqueId()); + + // Name change test. + if (!resident.getName().equals(player.getName())) { + universe.getDataSource().renamePlayer(resident, player.getName()); + // Re-fetch the resident with the corrected name. + resident = universe.getResident(player.getUniqueId()); + } + + loginExistingResident(resident); + return resident; + } + + private Resident createANewResident(Resident resident) { + try { + universe.getDataSource().newResident(player.getName(), player.getUniqueId()); + } catch (AlreadyRegisteredException | NotRegisteredException e) { + // This would only happen if the player's name contains symbols like \, /, ', `, + // which could be harmful to the database. + return null; + } + + TownySettings.incrementUUIDCount(); + + resident = universe.getResident(player.getUniqueId()); + + if (TownySettings.isShowingLocaleMessage()) + TownyMessaging.sendMsg(resident, Translatable.of("msg_your_locale", player.getLocale())); + + resident.setRegistered(System.currentTimeMillis()); + + final Resident finalResident = resident; + universe.getDataSource().getHibernatedResidentRegistered(player.getUniqueId()).thenAccept(registered -> { + if (registered.isPresent()) { + finalResident.setRegistered(registered.get()); + finalResident.save(); + } + }); + + resident.setLastOnline(System.currentTimeMillis()); + if (!TownySettings.getDefaultTownName().equals("")) { + Town town = universe.getTown(TownySettings.getDefaultTownName()); + if (town != null) { + try { + resident.setTown(town); + town.save(); + } catch (AlreadyRegisteredException ignore) {} + } + } + + resident.save(); + BukkitTools.fireEvent(new NewResidentEvent(resident)); + return resident; + } /** * Update last online, add UUID if needed, then save the resident. @@ -197,7 +197,7 @@ private void loginExistingResident(Resident resident) { if (!resident.hasUUID()) { resident.setUUID(player.getUniqueId()); try { - TownyUniverse.getInstance().registerResidentUUID(resident); + universe.registerResidentUUID(resident); } catch (AlreadyRegisteredException e) { e.printStackTrace(); } diff --git a/src/com/palmergames/bukkit/towny/tasks/PlotClaim.java b/src/com/palmergames/bukkit/towny/tasks/PlotClaim.java index e8224749e54..8bd4b73a7fc 100644 --- a/src/com/palmergames/bukkit/towny/tasks/PlotClaim.java +++ b/src/com/palmergames/bukkit/towny/tasks/PlotClaim.java @@ -6,7 +6,6 @@ import com.palmergames.bukkit.towny.TownyMessaging; import com.palmergames.bukkit.towny.TownySettings; import com.palmergames.bukkit.towny.exceptions.AlreadyRegisteredException; -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.object.PlotGroup; import com.palmergames.bukkit.towny.object.Resident; @@ -74,8 +73,12 @@ public void run() { for (WorldCoord worldCoord : selection) { try { - if (worldCoord.getTownBlock().hasPlotObjectGroup()) { - final PlotGroup group = worldCoord.getTownBlock().getPlotObjectGroup(); + if (worldCoord.isWilderness()) + throw new TownyException(Translatable.of("msg_not_claimed_1")); + + TownBlock tb = worldCoord.getTownBlockOrNull(); + if (tb.hasPlotObjectGroup()) { + final PlotGroup group = tb.getPlotObjectGroup(); /* * Handle paying for the plot here so it is not paid for per-townblock in the group. @@ -97,12 +100,10 @@ public void run() { /* * The plots are town-owned. */ - double bankcap = worldCoord.getTownBlock().getPlotObjectGroup().getTown().getBankCap(); - if (bankcap > 0) { - if (worldCoord.getTownBlock().getPlotObjectGroup().getPrice() + worldCoord.getTownBlock().getPlotObjectGroup().getTown().getAccount().getHoldingBalance() > bankcap) + double bankcap = group.getTown().getBankCap(); + if (bankcap > 0 && group.getPrice() + group.getTown().getAccount().getHoldingBalance() > bankcap) throw new TownyException(Translatable.of("msg_err_deposit_capped", bankcap)); - } - + if (!resident.getAccount().payTo(group.getPrice(), group.getTown(), "Plot Group - Buy From Town")) { /* * Should not be possible, as the resident has already been tested to see if they have enough to pay. @@ -122,7 +123,7 @@ public void run() { group.setResident(resident); group.setPrice(-1); - TownyMessaging.sendPrefixedTownMessage(worldCoord.getTownBlock().getTown(), Translatable.of("msg_player_successfully_bought_group_x", player.getName(), group.getName())); + TownyMessaging.sendPrefixedTownMessage(group.getTown(), Translatable.of("msg_player_successfully_bought_group_x", player.getName(), group.getName())); group.save(); break; @@ -198,176 +199,166 @@ private boolean residentGroupClaim(List worldCoords) throws TownyExc for (int i = 0; i < worldCoords.size(); ++i) { WorldCoord worldCoord = worldCoords.get(i); - - - try { - TownBlock townBlock = worldCoord.getTownBlock(); - Town town = townBlock.getTown(); - PlotGroup group = townBlock.getPlotObjectGroup(); - - if ((resident.hasTown() && (resident.getTown() != town) && (!townBlock.getType().equals(TownBlockType.EMBASSY))) || ((!resident.hasTown()) && (!townBlock.getType().equals(TownBlockType.EMBASSY)))) - throw new TownyException(Translatable.of("msg_err_not_part_town")); - - if (townBlock.getPlotObjectGroup().hasResident()) { - /* - * Plotgroup is resident-owned. - */ - Resident owner = townBlock.getPlotObjectGroup().getResident(); - - if (group.getPrice() != -1) { - // Plot is for sale - - int maxPlots = TownySettings.getMaxResidentPlots(resident); - int extraPlots = TownySettings.getMaxResidentExtraPlots(resident); - - //Infinite plots - if (maxPlots != -1) { - maxPlots = maxPlots + extraPlots; - } - - if (maxPlots >= 0 && resident.getTownBlocks().size() + group.getTownBlocks().size() > maxPlots) - throw new TownyException(Translatable.of("msg_max_plot_own", maxPlots)); - - TownyMessaging.sendPrefixedTownMessage(town, Translatable.of("msg_buy_resident_plot", resident.getName(), owner.getName(), townBlock.getPlotObjectGroup().getPrice())); - - townBlock.setResident(resident); - - // Set the plot permissions to mirror the new owners. - // TODO: Plot types for groups. - //group.setType(townBlock.getType()); - - owner.save(); - group.save(); - townBlock.save(); - - if (i >= worldCoords.size() - 2) { - TownyMessaging.sendPrefixedTownMessage(town, Translatable.of("msg_player_successfully_bought_group_x", resident.getName(), group.getName())); - } - - // Update any caches for this WorldCoord - plugin.updateCache(worldCoord); - } else { - //Should never reach here. - throw new AlreadyRegisteredException(Translatable.of("msg_already_claimed", owner.getName()).forLocale(player)); - } - - } else { - /* - * Plot group is town-owned. - */ - - if (townBlock.getPlotObjectGroup().getPrice() == -1) { - throw new TownyException(Translatable.of("msg_err_plot_nfs")); - } - - townBlock.setResident(resident); - - // Set the plot permissions to mirror the new owners. - townBlock.setType(townBlock.getType()); - townBlock.save(); - - } - } catch (NotRegisteredException e) { + if (worldCoord.isWilderness()) throw new TownyException(Translatable.of("msg_err_not_part_town")); - } - } - - return true; - } + TownBlock townBlock = worldCoord.getTownBlockOrNull(); + Town town = townBlock.getTownOrNull(); + PlotGroup group = townBlock.getPlotObjectGroup(); - private boolean residentClaim(WorldCoord worldCoord) throws TownyException { - - try { - TownBlock townBlock = worldCoord.getTownBlock(); - Town town = townBlock.getTown(); - if ((resident.hasTown() && (resident.getTown() != town) && (!townBlock.getType().equals(TownBlockType.EMBASSY))) || ((!resident.hasTown()) && (!townBlock.getType().equals(TownBlockType.EMBASSY)))) + if (!townBlock.getType().equals(TownBlockType.EMBASSY) && !town.hasResident(resident)) throw new TownyException(Translatable.of("msg_err_not_part_town")); - final Resident owner = townBlock.getResidentOrNull(); - if (owner != null) { + if (townBlock.getPlotObjectGroup().hasResident()) { + /* + * Plotgroup is resident-owned. + */ + Resident owner = townBlock.getPlotObjectGroup().getResident(); - if (townBlock.getPlotPrice() != -1) { + if (group.getPrice() != -1) { // Plot is for sale - if (TownyEconomyHandler.isActive() && townBlock.getPlotPrice() > 0 && !resident.getAccount().payTo(townBlock.getPlotPrice(), owner, "Plot - Buy From Seller")) - throw new TownyException(Translatable.of("msg_no_money_purchase_plot")); - int maxPlots = TownySettings.getMaxResidentPlots(resident); int extraPlots = TownySettings.getMaxResidentExtraPlots(resident); - + //Infinite plots if (maxPlots != -1) { maxPlots = maxPlots + extraPlots; } - - if (maxPlots >= 0 && resident.getTownBlocks().size() + 1 > maxPlots) + + if (maxPlots >= 0 && resident.getTownBlocks().size() + group.getTownBlocks().size() > maxPlots) throw new TownyException(Translatable.of("msg_max_plot_own", maxPlots)); - TownyMessaging.sendPrefixedTownMessage(town, Translatable.of("msg_buy_resident_plot", resident.getName(), owner.getName(), townBlock.getPlotPrice())); - townBlock.setPlotPrice(-1); + TownyMessaging.sendPrefixedTownMessage(town, Translatable.of("msg_buy_resident_plot", resident.getName(), owner.getName(), townBlock.getPlotObjectGroup().getPrice())); + townBlock.setResident(resident); // Set the plot permissions to mirror the new owners. - townBlock.setType(townBlock.getType()); - + // TODO: Plot types for groups. + //group.setType(townBlock.getType()); + owner.save(); + group.save(); townBlock.save(); + if (i >= worldCoords.size() - 2) { + TownyMessaging.sendPrefixedTownMessage(town, Translatable.of("msg_player_successfully_bought_group_x", resident.getName(), group.getName())); + } + // Update any caches for this WorldCoord plugin.updateCache(worldCoord); - return true; } else { //Should never reach here. throw new AlreadyRegisteredException(Translatable.of("msg_already_claimed", owner.getName()).forLocale(player)); } } else { - //Plot has no owner so it's the town selling it + /* + * Plot group is town-owned. + */ - if (townBlock.getPlotPrice() == -1) + if (townBlock.getPlotObjectGroup().getPrice() == -1) { throw new TownyException(Translatable.of("msg_err_plot_nfs")); - - double bankcap = town.getBankCap(); - if (TownyEconomyHandler.isActive() && bankcap > 0) { - if (townBlock.getPlotPrice() + town.getAccount().getHoldingBalance() > bankcap) - throw new TownyException(Translatable.of("msg_err_deposit_capped", bankcap)); } - if (TownyEconomyHandler.isActive() && townBlock.getPlotPrice() > 0 && !resident.getAccount().payTo(townBlock.getPlotPrice(), town, "Plot - Buy From Town")) + townBlock.setResident(resident); + + // Set the plot permissions to mirror the new owners. + townBlock.setType(townBlock.getType()); + townBlock.save(); + + } + + } + + return true; + } + + private boolean residentClaim(WorldCoord worldCoord) throws TownyException { + if (worldCoord.isWilderness()) + throw new TownyException(Translatable.of("msg_err_not_part_town")); + + TownBlock townBlock = worldCoord.getTownBlockOrNull(); + Town town = townBlock.getTownOrNull(); + if (!townBlock.getType().equals(TownBlockType.EMBASSY) && !town.hasResident(resident)) + throw new TownyException(Translatable.of("msg_err_not_part_town")); + + final Resident owner = townBlock.getResidentOrNull(); + if (owner != null) { + + if (townBlock.getPlotPrice() != -1) { + // Plot is for sale + if (TownyEconomyHandler.isActive() && townBlock.getPlotPrice() > 0 && !resident.getAccount().payTo(townBlock.getPlotPrice(), owner, "Plot - Buy From Seller")) throw new TownyException(Translatable.of("msg_no_money_purchase_plot")); + int maxPlots = TownySettings.getMaxResidentPlots(resident); + int extraPlots = TownySettings.getMaxResidentExtraPlots(resident); + + //Infinite plots + if (maxPlots != -1) { + maxPlots = maxPlots + extraPlots; + } + + if (maxPlots >= 0 && resident.getTownBlocks().size() + 1 > maxPlots) + throw new TownyException(Translatable.of("msg_max_plot_own", maxPlots)); + + TownyMessaging.sendPrefixedTownMessage(town, Translatable.of("msg_buy_resident_plot", resident.getName(), owner.getName(), townBlock.getPlotPrice())); townBlock.setPlotPrice(-1); townBlock.setResident(resident); // Set the plot permissions to mirror the new owners. townBlock.setType(townBlock.getType()); + + owner.save(); townBlock.save(); + // Update any caches for this WorldCoord + plugin.updateCache(worldCoord); return true; + } else { + //Should never reach here. + throw new AlreadyRegisteredException(Translatable.of("msg_already_claimed", owner.getName()).forLocale(player)); } - } catch (NotRegisteredException e) { - throw new TownyException(Translatable.of("msg_err_not_part_town")); - } - } - private boolean residentUnclaim(WorldCoord worldCoord) throws TownyException { + } else { + //Plot has no owner so it's the town selling it - try { - TownBlock townBlock = worldCoord.getTownBlock(); + if (townBlock.getPlotPrice() == -1) + throw new TownyException(Translatable.of("msg_err_plot_nfs")); + + double bankcap = town.getBankCap(); + if (TownyEconomyHandler.isActive() && bankcap > 0) { + if (townBlock.getPlotPrice() + town.getAccount().getHoldingBalance() > bankcap) + throw new TownyException(Translatable.of("msg_err_deposit_capped", bankcap)); + } - townBlock.setResident(null); - townBlock.setPlotPrice(townBlock.getTown().getPlotTypePrice(townBlock.getType())); + if (TownyEconomyHandler.isActive() && !resident.getAccount().payTo(townBlock.getPlotPrice(), town, "Plot - Buy From Town")) + throw new TownyException(Translatable.of("msg_no_money_purchase_plot")); - // Set the plot permissions to mirror the towns. + townBlock.setPlotPrice(-1); + townBlock.setResident(resident); + + // Set the plot permissions to mirror the new owners. townBlock.setType(townBlock.getType()); townBlock.save(); - plugin.updateCache(worldCoord); + return true; + } + } - } catch (NotRegisteredException e) { + private boolean residentUnclaim(WorldCoord worldCoord) throws TownyException { + if (worldCoord.isWilderness()) throw new TownyException(Translatable.of("msg_not_own_place")); - } + TownBlock townBlock = worldCoord.getTownBlockOrNull(); + + townBlock.setResident(null); + townBlock.setPlotPrice(townBlock.getTownOrNull().getPlotTypePrice(townBlock.getType())); + + // Set the plot permissions to mirror the towns. + townBlock.setType(townBlock.getType()); + townBlock.save(); + + plugin.updateCache(worldCoord); return true; } @@ -395,22 +386,16 @@ private void residentUnclaimAll() { */ private void adminClaim(WorldCoord worldCoord) throws TownyException { - try { - TownBlock townBlock = worldCoord.getTownBlock(); - @SuppressWarnings("unused") // Used to make sure a plot/town is here. - Town town = townBlock.getTown(); - - townBlock.setPlotPrice(-1); - townBlock.setResident(resident); - townBlock.setType(townBlock.getType()); - townBlock.save(); - - TownyMessaging.sendMsg(resident, Translatable.of("msg_admin_has_given_you_a_plot", worldCoord.toString())); - } catch (NotRegisteredException e) { - //Probably not owned by a town. - throw new TownyException(Translatable.of("msg_not_claimed_1")); + if (worldCoord.isWilderness()) + throw new TownyException(Translatable.of("msg_not_claimed_1")); - } + TownBlock townBlock = worldCoord.getTownBlockOrNull(); + townBlock.setPlotPrice(-1); + townBlock.setResident(resident); + townBlock.setType(townBlock.getType()); + townBlock.save(); + + TownyMessaging.sendMsg(resident, Translatable.of("msg_admin_has_given_you_a_plot", worldCoord.toString())); } } diff --git a/src/com/palmergames/bukkit/towny/utils/AreaSelectionUtil.java b/src/com/palmergames/bukkit/towny/utils/AreaSelectionUtil.java index 7e12cec639f..add567691d7 100644 --- a/src/com/palmergames/bukkit/towny/utils/AreaSelectionUtil.java +++ b/src/com/palmergames/bukkit/towny/utils/AreaSelectionUtil.java @@ -2,9 +2,7 @@ import com.palmergames.bukkit.towny.TownyMessaging; import com.palmergames.bukkit.towny.TownySettings; -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; import com.palmergames.bukkit.towny.exceptions.TownyException; -import com.palmergames.bukkit.towny.object.Coord; import com.palmergames.bukkit.towny.object.PlotGroup; import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.Town; @@ -182,7 +180,7 @@ private static List selectWorldCoordAreaRect(int maxSelectionSize, W * Calculate how many townblocks will be needed to claim the desired radius, * dropping the radius if it will be required, to make a perfect a perfect square. */ - int needed = pos.getTownBlock().hasTown() ? 0 : 1; + int needed = pos.hasTownBlock() ? 0 : 1; int claimRadius = 1; while (claimRadius <= r && needed < maxSelectionSize) { needed += (claimRadius * 8); @@ -435,17 +433,17 @@ public static HashSet getPlotGroupsFromSelection(List sel HashSet seenGroups = new HashSet<>(); for (WorldCoord coord : selection) { - - PlotGroup group = null; - try { - group = coord.getTownBlock().getPlotObjectGroup(); - } catch (NotRegisteredException ignored) {} - + if (coord.isWilderness()) + continue; + + PlotGroup group = coord.getTownBlockOrNull().getPlotObjectGroup(); + if (group == null) + continue; + if (seenGroups.contains(group)) continue; - + seenGroups.add(group); - } return seenGroups; @@ -459,19 +457,20 @@ public static HashSet getPlotGroupsFromSelection(List sel public static List filterPlotsForSale(List selection) { List out = new ArrayList<>(); - for (WorldCoord worldCoord : selection) - try { - // Plot Groups do not set a townblock's individual plot price. - if (worldCoord.getTownBlock().hasPlotObjectGroup() && worldCoord.getTownBlock().getPlotObjectGroup().getPrice() != -1) { - out.clear(); // Remove any other plots from the selection. - out.add(worldCoord); // Put in the one plot-group-having townblock, the rest of the group will be added later. - return out; // Return the one plot-group-having townblock. - } - - if (worldCoord.getTownBlock().isForSale()) - out.add(worldCoord); - } catch (NotRegisteredException ignored) { + for (WorldCoord worldCoord : selection) { + if (worldCoord.isWilderness()) + continue; + TownBlock tb = worldCoord.getTownBlockOrNull(); + // Plot Groups do not set a townblock's individual plot price. + if (tb.hasPlotObjectGroup() && tb.getPlotObjectGroup().getPrice() != -1) { + out.clear(); // Remove any other plots from the selection. + out.add(worldCoord); // Put in the one plot-group-having townblock, the rest of the group will be added later. + return out; // Return the one plot-group-having townblock. } + + if (tb.isForSale()) + out.add(worldCoord); + } return out; } @@ -484,11 +483,8 @@ public static List filterPlotsNotForSale(List selection) List out = new ArrayList<>(); for (WorldCoord worldCoord : selection) - try { - if (!worldCoord.getTownBlock().isForSale()) - out.add(worldCoord); - } catch (NotRegisteredException ignored) { - } + if (!worldCoord.isWilderness() && !worldCoord.getTownBlockOrNull().isForSale()) + out.add(worldCoord); return out; } @@ -503,12 +499,13 @@ public static List filterPlotsNotForSale(List selection) public static List filterOutResidentBlocks(Resident resident, List selection) { List out = new ArrayList<>(); - for (WorldCoord worldCoord : selection) - try { - if (!worldCoord.getTownBlock().hasResident() || (worldCoord.getTownBlock().hasResident() && worldCoord.getTownBlock().getResidentOrNull().equals(resident))) - out.add(worldCoord); - } catch (NotRegisteredException ignored) { - } + for (WorldCoord worldCoord : selection) { + if (worldCoord.isWilderness()) + continue; + TownBlock tb = worldCoord.getTownBlockOrNull(); + if (!tb.hasResident() || tb.hasResident(resident)) + out.add(worldCoord); + } return out; } @@ -523,16 +520,13 @@ public static int getAreaSelectPivot(String[] args) { public static boolean isOnEdgeOfOwnership(TownBlockOwner owner, WorldCoord worldCoord) { - int[][] offset = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; - for (int i = 0; i < 4; i++) - try { - TownBlock edgeTownBlock = worldCoord.getTownyWorld().getTownBlock(new Coord(worldCoord.getX() + offset[i][0], worldCoord.getZ() + offset[i][1])); - if (!edgeTownBlock.isOwner(owner)) { - return true; - } - } catch (NotRegisteredException e) { - return true; - } + for (WorldCoord wc : worldCoord.getCardinallyAdjacentWorldCoords()) { + if (wc.isWilderness()) + continue; + if (!wc.getTownBlockOrNull().isOwner(owner)) + continue; + return true; + } return false; } } diff --git a/src/com/palmergames/bukkit/towny/utils/MoneyUtil.java b/src/com/palmergames/bukkit/towny/utils/MoneyUtil.java index bafa36c7930..afcd5abcea3 100644 --- a/src/com/palmergames/bukkit/towny/utils/MoneyUtil.java +++ b/src/com/palmergames/bukkit/towny/utils/MoneyUtil.java @@ -144,7 +144,8 @@ public static void nationDeposit(Player player, Resident resident, Nation nation * @throws TownyException thrown if any of the tests are failed. */ private static void commonTests(int amount, Resident resident, Town town, Location loc, boolean nation, boolean withdraw) throws TownyException { - + Nation townNation = nation ? town.getNationOrNull() : null; + if (!TownyEconomyHandler.isActive()) throw new TownyException(Translatable.of("msg_err_no_economy")); @@ -160,15 +161,15 @@ private static void commonTests(int amount, Resident resident, Town town, Locati if (withdraw && ((nation && !TownySettings.getNationBankAllowWithdrawls()) || (!nation && !TownySettings.getTownBankAllowWithdrawls()))) throw new TownyException(Translatable.of("msg_err_withdraw_disabled")); - if (!withdraw && ((!nation && TownySettings.getTownBankCap(town) > 0) || (nation && TownySettings.getNationBankCap(town.getNationOrNull()) > 0))) { + if (!withdraw && ((!nation && TownySettings.getTownBankCap(town) > 0) || (nation && TownySettings.getNationBankCap(townNation) > 0))) { double bankcap = 0; double balance = 0; if (!nation && town.getBankCap() > 0) { bankcap = town.getBankCap(); balance = town.getAccount().getHoldingBalance(); - } else if (nation && town.getNationOrNull().getBankCap() > 0) { - bankcap = town.getNationOrNull().getBankCap(); - balance = town.getNation().getAccount().getHoldingBalance(); + } else if (nation && townNation.getBankCap() > 0) { + bankcap = townNation.getBankCap(); + balance = townNation.getAccount().getHoldingBalance(); } if (bankcap > 0 && amount + balance > bankcap) throw new TownyException(Translatable.of("msg_err_deposit_capped", bankcap)); diff --git a/src/com/palmergames/bukkit/towny/utils/OutpostUtil.java b/src/com/palmergames/bukkit/towny/utils/OutpostUtil.java index 4da87a599cb..4db10ab51fe 100644 --- a/src/com/palmergames/bukkit/towny/utils/OutpostUtil.java +++ b/src/com/palmergames/bukkit/towny/utils/OutpostUtil.java @@ -39,7 +39,7 @@ public static boolean OutpostTests(Town town, Resident resident, TownyWorld worl // Outposts can be limited per resident, with permission nodes. int maxOutposts = TownySettings.getMaxResidentOutposts(resident); - if (!isAdmin && maxOutposts != -1 && (maxOutposts <= resident.getTown().getAllOutpostSpawns().size())) + if (!isAdmin && maxOutposts != -1 && (maxOutposts <= town.getAllOutpostSpawns().size())) throw new TownyException(Translatable.of("msg_max_outposts_own", maxOutposts)); // Outposts can have a minimum required distance from homeblocks. diff --git a/src/com/palmergames/bukkit/towny/utils/PlayerCacheUtil.java b/src/com/palmergames/bukkit/towny/utils/PlayerCacheUtil.java index d5ea10fe7a0..67da171de6f 100644 --- a/src/com/palmergames/bukkit/towny/utils/PlayerCacheUtil.java +++ b/src/com/palmergames/bukkit/towny/utils/PlayerCacheUtil.java @@ -6,7 +6,6 @@ import com.palmergames.bukkit.towny.TownySettings; import com.palmergames.bukkit.towny.TownyUniverse; import com.palmergames.bukkit.towny.event.player.PlayerCacheGetTownBlockStatusEvent; -import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.hooks.PluginIntegrations; import com.palmergames.bukkit.towny.object.Coord; import com.palmergames.bukkit.towny.object.Nation; @@ -297,58 +296,52 @@ public static TownBlockStatus getTownBlockStatus(Player player, WorldCoord world } } - try { - if (town.isMayor(resident)) - return TownBlockStatus.TOWN_OWNER; - - if (town.hasTrustedResident(resident)) - return TownBlockStatus.TOWN_TRUSTED; - - if (townBlock.hasTrustedResident(resident) && !townBlock.hasResident(resident)) - return TownBlockStatus.PLOT_TRUSTED; - - // Resident Plot rights - if (townBlock.hasResident()) { - Resident owner = townBlock.getResidentOrNull(); - if (resident == owner) - return TownBlockStatus.PLOT_OWNER; - else if (owner.hasFriend(resident)) - return TownBlockStatus.PLOT_FRIEND; - else if (resident.hasTown() && CombatUtil.isSameTown(owner.getTown(), resident.getTown())) - return TownBlockStatus.PLOT_TOWN; - else if (resident.hasTown() && CombatUtil.isAlly(owner.getTown(), resident.getTown())) - return TownBlockStatus.PLOT_ALLY; - else - return TownBlockStatus.OUTSIDER; - } - - // Resident with no town. - if (!resident.hasTown()) + if (town.isMayor(resident)) + return TownBlockStatus.TOWN_OWNER; + + if (town.hasTrustedResident(resident)) + return TownBlockStatus.TOWN_TRUSTED; + + if (townBlock.hasTrustedResident(resident) && !townBlock.hasResident(resident)) + return TownBlockStatus.PLOT_TRUSTED; + + // Resident Plot rights + if (townBlock.hasResident()) { + Resident owner = townBlock.getResidentOrNull(); + if (resident == owner) + return TownBlockStatus.PLOT_OWNER; + else if (owner.hasFriend(resident)) + return TownBlockStatus.PLOT_FRIEND; + else if (resident.hasTown() && CombatUtil.isSameTown(owner, resident)) + return TownBlockStatus.PLOT_TOWN; + else if (resident.hasTown() && CombatUtil.isAlly(owner, resident)) + return TownBlockStatus.PLOT_ALLY; + else return TownBlockStatus.OUTSIDER; - - // Town has this resident, who isn't the mayor. - if (town.hasResident(resident)) - return TownBlockStatus.TOWN_RESIDENT; - - // Nation group. - if (CombatUtil.isSameNation(town, resident.getTown())) - return TownBlockStatus.TOWN_NATION; - - // Ally group. - if (CombatUtil.isAlly(town, resident.getTown())) - return TownBlockStatus.TOWN_ALLY; - - // Enemy. - if (CombatUtil.isEnemy(resident.getTown(), town)) - return TownBlockStatus.ENEMY; + } - // Nothing left but Outsider. + // Resident with no town. + if (!resident.hasTown()) return TownBlockStatus.OUTSIDER; + + // Town has this resident, who isn't the mayor. + if (town.hasResident(resident)) + return TownBlockStatus.TOWN_RESIDENT; + + // Nation group. + if (CombatUtil.isSameNation(town, resident.getTownOrNull())) + return TownBlockStatus.TOWN_NATION; + + // Ally group. + if (CombatUtil.isAlly(town, resident.getTownOrNull())) + return TownBlockStatus.TOWN_ALLY; + + // Enemy. + if (CombatUtil.isEnemy(resident.getTownOrNull(), town)) + return TownBlockStatus.ENEMY; - } catch (TownyException e) { - // Outsider destroy rights - return TownBlockStatus.OUTSIDER; - } + // Nothing left but Outsider. + return TownBlockStatus.OUTSIDER; } /** diff --git a/src/com/palmergames/bukkit/towny/utils/TownRuinUtil.java b/src/com/palmergames/bukkit/towny/utils/TownRuinUtil.java index 551b821fd97..01f8b7fd29e 100644 --- a/src/com/palmergames/bukkit/towny/utils/TownRuinUtil.java +++ b/src/com/palmergames/bukkit/towny/utils/TownRuinUtil.java @@ -123,10 +123,8 @@ public static void putTownIntoRuinedState(Town town) { * Processes a player request to reclaim a ruined town * * @param player The player reclaiming a ruined town. - * @param plugin Instance of {@link Towny} */ - public static void processRuinedTownReclaimRequest(Player player, Towny plugin) { - Town town; + public static void processRuinedTownReclaimRequest(Player player) { try { Resident resident = TownyUniverse.getInstance().getResident(player.getUniqueId()); @@ -134,7 +132,7 @@ public static void processRuinedTownReclaimRequest(Player player, Towny plugin) throw new TownyException(Translatable.of("msg_err_dont_belong_town")); //Ensure town is ruined - town = resident.getTown(); + Town town = resident.getTownOrNull(); if (!town.isRuined()) throw new TownyException(Translatable.of("msg_err_cannot_reclaim_town_unless_ruined"));