From c58fa1f804de6d998617202e664a6e84466d35ee Mon Sep 17 00:00:00 2001 From: MattDeWeerd Date: Tue, 11 Aug 2026 09:19:38 -0400 Subject: [PATCH] Add option to preserve ruin permissions --- .../bukkit/config/ConfigNodes.java | 25 +++++++---- .../bukkit/towny/TownySettings.java | 6 ++- .../bukkit/towny/utils/TownRuinUtil.java | 45 ++++++++++++++----- Towny/src/main/resources/ChangeLog.txt | 8 +++- .../towny/config/TownRuinConfigTests.java | 43 ++++++++++++++++++ 5 files changed, 105 insertions(+), 22 deletions(-) create mode 100644 Towny/src/test/java/com/palmergames/bukkit/towny/config/TownRuinConfigTests.java diff --git a/Towny/src/main/java/com/palmergames/bukkit/config/ConfigNodes.java b/Towny/src/main/java/com/palmergames/bukkit/config/ConfigNodes.java index 0e8b5e4b92..23bebbac23 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/config/ConfigNodes.java +++ b/Towny/src/main/java/com/palmergames/bukkit/config/ConfigNodes.java @@ -3521,15 +3521,22 @@ public enum ConfigNodes { "false", "", "# When this is true, players who have no town can also reclaim the ruin. While false, only residents of the Town can reclaim the ruin."), - TOWN_RUINING_TOWN_DEPOSITS_BANK_TO_NATION( - "town_ruining.town_ruins.town_bank_is_sent_to_nation", - "false", - "", - "# If this is true, when a town becomes a ruin, and they are a member of a nation, any money in the town bank will be deposited to the nation bank."), - TOWN_RUINING_TOWN_PLOTS_PERMISSIONS_OPEN_UP_PROGRESSIVELY( - "town_ruining.town_ruins.do_plots_permissions_change_to_allow_all", - "false", - "", + TOWN_RUINING_TOWN_DEPOSITS_BANK_TO_NATION( + "town_ruining.town_ruins.town_bank_is_sent_to_nation", + "false", + "", + "# If this is true, when a town becomes a ruin, and they are a member of a nation, any money in the town bank will be deposited to the nation bank."), + TOWN_RUINING_TOWN_PERMISSIONS_CHANGE_ON_RUIN( + "town_ruining.town_ruins.do_permissions_change_on_ruin", + "true", + "", + "# If this is false, a town's and its plots' permission settings will not change when the town becomes a ruin or is reclaimed.", + "# The ruins_become_open setting is independent and can still make the ruined town open to join.", + "# The do_plots_permissions_change_to_allow_all setting has no effect while this is false."), + TOWN_RUINING_TOWN_PLOTS_PERMISSIONS_OPEN_UP_PROGRESSIVELY( + "town_ruining.town_ruins.do_plots_permissions_change_to_allow_all", + "false", + "", "# If this is true, when a town becomes a ruin, every hour more and more of their plots will have their permissions turned to allow", "# build, destroy, switch, itemuse to on. This will affect the newest claims first and progress until the first claims made are opened up", "# right before the max_duration_hours have passed. When a town has more claims than max_duration_hours, multiple plots will be opened up", diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/TownySettings.java b/Towny/src/main/java/com/palmergames/bukkit/towny/TownySettings.java index 1eeba92233..8c0ae6387f 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/TownySettings.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/TownySettings.java @@ -3933,8 +3933,12 @@ public static boolean areRuinedTownsBanksPaidToNation() { return getBoolean(ConfigNodes.TOWN_RUINING_TOWN_DEPOSITS_BANK_TO_NATION); } + public static boolean doRuinsPermissionsChange() { + return getBoolean(ConfigNodes.TOWN_RUINING_TOWN_PERMISSIONS_CHANGE_ON_RUIN); + } + public static boolean doRuinsPlotPermissionsProgressivelyAllowAll() { - return getBoolean(ConfigNodes.TOWN_RUINING_TOWN_PLOTS_PERMISSIONS_OPEN_UP_PROGRESSIVELY); + return doRuinsPermissionsChange() && getBoolean(ConfigNodes.TOWN_RUINING_TOWN_PLOTS_PERMISSIONS_OPEN_UP_PROGRESSIVELY); } public static boolean isHideTownRuinedStatusEnabled() { diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/utils/TownRuinUtil.java b/Towny/src/main/java/com/palmergames/bukkit/towny/utils/TownRuinUtil.java index cb19afdb82..3f8f02db9c 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/utils/TownRuinUtil.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/utils/TownRuinUtil.java @@ -20,6 +20,7 @@ import com.palmergames.bukkit.towny.exceptions.TownyException; import com.palmergames.bukkit.towny.object.District; import com.palmergames.bukkit.towny.object.Nation; +import com.palmergames.bukkit.towny.object.PermissionData; import com.palmergames.bukkit.towny.object.PlotGroup; import com.palmergames.bukkit.towny.object.Resident; @@ -39,8 +40,12 @@ import java.util.ArrayList; import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; @@ -69,7 +74,7 @@ public static boolean isPlayersTownRuined(@NotNull Player player) { * Put town into ruined state: * 1. Remove town from nation * 2. Set mayor to NPC - * 3. Enable all perms + * 3. Enable all perms, if configured * 4. Now, the residents cannot run /plot commands, and some /t commands * 5. Town will later be deleted full, unless it is reclaimed * @param town The town to put into a "ruined" state. @@ -112,18 +117,34 @@ public static void putTownIntoRuinedState(Town town) { town.setRuinedTime(System.currentTimeMillis()); town.setPublic(TownySettings.areRuinsMadePublic()); town.setOpen(TownySettings.areRuinsMadeOpen()); - town.getPermissions().setAll(true); + final boolean changePermissions = TownySettings.doRuinsPermissionsChange(); + if (changePermissions) + town.getPermissions().setAll(true); //Return town blocks to the basic, unowned, type for(TownBlock townBlock: town.getTownBlocks()) { + final String existingPermissions = changePermissions ? null : townBlock.getPermissions().toString(); + final Map existingPermissionOverrides = !changePermissions && townBlock.hasPermissionOverrides() + ? new LinkedHashMap<>(townBlock.getPermissionOverrides()) + : null; + final Set existingTrustedResidents = !changePermissions && townBlock.hasTrustedResidents() + ? new LinkedHashSet<>(townBlock.getTrustedResidents()) + : null; if (townBlock.hasResident()) townBlock.removeResident(); // Removes any personal ownership. townBlock.setType(TownBlockType.RESIDENTIAL); // Sets the townblock's perm line to the Town's perm line set above. townBlock.setPlotPrice(-1); // Makes the plot not for sale. townBlock.removePlotObjectGroup(); // Removes plotgroup if it were present. townBlock.removeDistrict(); // Removes district if it were present. - townBlock.setPermissionOverrides(null); // Removes all permission overrides from the plot. - townBlock.setTrustedResidents(null); // Removes all trusted residents. + if (changePermissions) { + townBlock.setPermissionOverrides(null); // Removes all permission overrides from the plot. + townBlock.setTrustedResidents(null); // Removes all trusted residents. + } else { + townBlock.setPermissions(existingPermissions); + townBlock.setChanged(!existingPermissions.equals(town.getPermissions().toString())); + townBlock.setPermissionOverrides(existingPermissionOverrides); + townBlock.setTrustedResidents(existingTrustedResidents); + } townBlock.save(); } @@ -228,12 +249,14 @@ public static void reclaimTown(@NotNull Resident resident, @NotNull Town town) { if (!resident.equals(town.getMayor())) setMayor(town, resident); //Set player as mayor (and remove npc) - // Set permission line to the config's default settings. - town.getPermissions().loadDefault(town); - for (TownBlock townBlock : town.getTownBlocks()) { - townBlock.getPermissions().loadDefault(town); - townBlock.setChanged(false); - townBlock.save(); + if (TownySettings.doRuinsPermissionsChange()) { + // Set permission line to the config's default settings. + town.getPermissions().loadDefault(town); + for (TownBlock townBlock : town.getTownBlocks()) { + townBlock.getPermissions().loadDefault(town); + townBlock.setChanged(false); + townBlock.save(); + } } town.save(); @@ -364,4 +387,4 @@ private static boolean tryAndAllowPermsInPlot(TownBlock tb, TownyPermission open }); return true; } -} \ No newline at end of file +} diff --git a/Towny/src/main/resources/ChangeLog.txt b/Towny/src/main/resources/ChangeLog.txt index ca1f98409b..d8269a23d4 100644 --- a/Towny/src/main/resources/ChangeLog.txt +++ b/Towny/src/main/resources/ChangeLog.txt @@ -10994,4 +10994,10 @@ c - Fix non-player portal creation not working when the town is the same on both ends. - Closes #8262. 0.103.2.0: - - Bump version for Release. \ No newline at end of file + - Bump version for Release. + - Add an option to preserve town and plot permission settings while towns are ruined. + - New Config Option: town_ruining.town_ruins.do_permissions_change_on_ruin + - Default: true + - When false, town and plot permission settings remain unchanged when a town becomes a ruin or is reclaimed. + - ruins_become_open still controls whether the ruined town is open to join. + - do_plots_permissions_change_to_allow_all has no effect while this option is false. diff --git a/Towny/src/test/java/com/palmergames/bukkit/towny/config/TownRuinConfigTests.java b/Towny/src/test/java/com/palmergames/bukkit/towny/config/TownRuinConfigTests.java new file mode 100644 index 0000000000..87a0db8d09 --- /dev/null +++ b/Towny/src/test/java/com/palmergames/bukkit/towny/config/TownRuinConfigTests.java @@ -0,0 +1,43 @@ +package com.palmergames.bukkit.towny.config; + +import com.palmergames.bukkit.config.ConfigNodes; +import com.palmergames.bukkit.towny.TownySettings; +import com.palmergames.bukkit.towny.test.TownyConfigExtension; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(TownyConfigExtension.class) +public class TownRuinConfigTests { + @BeforeEach + void reset() { + TownySettings.getConfig().set(ConfigNodes.TOWN_RUINING_TOWN_PERMISSIONS_CHANGE_ON_RUIN.getRoot(), true); + TownySettings.getConfig().set(ConfigNodes.TOWN_RUINING_TOWN_PLOTS_PERMISSIONS_OPEN_UP_PROGRESSIVELY.getRoot(), false); + TownySettings.getConfig().set(ConfigNodes.TOWN_RUINING_TOWNS_BECOME_OPEN.getRoot(), false); + } + + @Test + void testRuinPermissionsChangeByDefault() { + assertTrue(TownySettings.doRuinsPermissionsChange()); + } + + @Test + void testProgressivePermissionChangesAreDisabledWhenRuinPermissionsArePreserved() { + TownySettings.getConfig().set(ConfigNodes.TOWN_RUINING_TOWN_PERMISSIONS_CHANGE_ON_RUIN.getRoot(), false); + TownySettings.getConfig().set(ConfigNodes.TOWN_RUINING_TOWN_PLOTS_PERMISSIONS_OPEN_UP_PROGRESSIVELY.getRoot(), true); + + assertFalse(TownySettings.doRuinsPlotPermissionsProgressivelyAllowAll()); + } + + @Test + void testRuinsBecomeOpenIndependentlyOfPermissionChanges() { + TownySettings.getConfig().set(ConfigNodes.TOWN_RUINING_TOWN_PERMISSIONS_CHANGE_ON_RUIN.getRoot(), false); + TownySettings.getConfig().set(ConfigNodes.TOWN_RUINING_TOWNS_BECOME_OPEN.getRoot(), true); + + assertTrue(TownySettings.areRuinsMadeOpen()); + assertFalse(TownySettings.doRuinsPermissionsChange()); + } +}