From 4f637469716bb3c81bfbc804910d049ac5a5daee Mon Sep 17 00:00:00 2001 From: PainOchoco Date: Tue, 25 Oct 2022 21:10:25 +0200 Subject: [PATCH 1/5] Added max residents per nation --- resources/lang/en-US.yml | 4 +++- src/com/palmergames/bukkit/config/ConfigNodes.java | 7 +++++++ src/com/palmergames/bukkit/towny/TownySettings.java | 4 ++++ .../palmergames/bukkit/towny/command/NationCommand.java | 8 ++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/resources/lang/en-US.yml b/resources/lang/en-US.yml index b4a51f0042..fb98a97ca7 100644 --- a/resources/lang/en-US.yml +++ b/resources/lang/en-US.yml @@ -1781,4 +1781,6 @@ msg_x_has_been_withdrawn_for_upkeep_of_prisoner_x: '%s withdrawn from Town bank msg_x_has_been_withdrawn_for_jailing_of_prisoner_x: '%s withdrawn from Town bank to pay for jailing of %s.' #Message shown in the confirmation for /ta resetbanks {amount}. -confirmation_are_you_sure_you_want_to_reset_all_banks: 'Are you sure you want to reset all town and nation banks to %s?' \ No newline at end of file +confirmation_are_you_sure_you_want_to_reset_all_banks: 'Are you sure you want to reset all town and nation banks to %s?' + +msg_err_nation_over_resident_limit: '&cYour nation has reached the maximum number of allowed residents-per-nation: %s.' \ No newline at end of file diff --git a/src/com/palmergames/bukkit/config/ConfigNodes.java b/src/com/palmergames/bukkit/config/ConfigNodes.java index ec13bfdbb4..6a1a4f057b 100644 --- a/src/com/palmergames/bukkit/config/ConfigNodes.java +++ b/src/com/palmergames/bukkit/config/ConfigNodes.java @@ -1099,6 +1099,13 @@ public enum ConfigNodes { "", "# If higher than 0, it will limit how many towns can be joined into a nation.", "# Does not affect existing nations that are already over the limit."), + GNATION_SETTINGS_MAX_RESIDENTS_PER_NATION( + "global_nation_settings.max_residents_per_nation", + "0", + "", + "# If higher than 0, it will limit how many residents can join a nation.", + "# Does not affect existing nations that are already over the limit." + ), GNATION_SETTINGS_ALLOWED_NATION_COLORS( "global_nation_settings.allowed_map_colors", "aqua:00ffff, azure:f0ffff, beige:f5f5dc, black:000000, blue:0000ff, brown:a52a2a, cyan:00ffff, darkblue:00008b, darkcyan:008b8b, darkgrey:a9a9a9, darkgreen:006400, darkkhaki:bdb76b, darkmagenta:8b008b, darkolivegreen:556b2f, darkorange:ff8c00, darkorchid:9932cc, darkred:8b0000, darksalmon:e9967a, darkviolet:9400d3, fuchsia:ff00ff, gold:ffd700, green:008000, indigo:4b0082, khaki:f0e68c, lightblue:add8e6, lightcyan:e0ffff, lightgreen:90ee90, lightgrey:d3d3d3, lightpink:ffb6c1, lightyellow:ffffe0, lime:00ff00, magenta:ff00ff, maroon:800000, navy:000080, olive:808000, orange:ffa500, pink:ffc0cb, purple:800080, violet:800080, red:ff0000, silver:c0c0c0, white:ffffff, yellow:ffff00", diff --git a/src/com/palmergames/bukkit/towny/TownySettings.java b/src/com/palmergames/bukkit/towny/TownySettings.java index d46988f871..ca7a782892 100644 --- a/src/com/palmergames/bukkit/towny/TownySettings.java +++ b/src/com/palmergames/bukkit/towny/TownySettings.java @@ -2876,6 +2876,10 @@ public static boolean isNationSpawnOnlyAllowedInCapital() { public static int getMaxTownsPerNation() { return getInt(ConfigNodes.GNATION_SETTINGS_MAX_TOWNS_PER_NATION); } + + public static int getMaxResidentsPerNation() { + return getInt(ConfigNodes.GNATION_SETTINGS_MAX_RESIDENTS_PER_NATION); + } public static double getSpawnTravelCost() { return getDouble(ConfigNodes.ECO_PRICE_TOWN_SPAWN_TRAVEL_PUBLIC); diff --git a/src/com/palmergames/bukkit/towny/command/NationCommand.java b/src/com/palmergames/bukkit/towny/command/NationCommand.java index da39fe6f8d..f74490b50e 100644 --- a/src/com/palmergames/bukkit/towny/command/NationCommand.java +++ b/src/com/palmergames/bukkit/towny/command/NationCommand.java @@ -669,6 +669,11 @@ private void parseNationJoin(Player player, String[] args) { if (nation.getTowns().size() >= TownySettings.getMaxTownsPerNation()) throw new TownyException(Translatable.of("msg_err_nation_over_town_limit", TownySettings.getMaxTownsPerNation())); + if (TownySettings.getMaxResidentsPerNation() > 0) { + if (nation.getResidents().size() >= TownySettings.getMaxResidentsPerNation()) + throw new TownyException(Translatable.of("msg_err_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation())); + } + if (TownySettings.getNationRequiresProximity() > 0) { Coord capitalCoord = nation.getCapital().getHomeBlock().getCoord(); Coord townCoord = town.getHomeBlock().getCoord(); @@ -1192,6 +1197,9 @@ public void nationAdd(Player player, String[] names) throws TownyException { if (TownySettings.getMaxTownsPerNation() > 0 && nation.getTowns().size() >= TownySettings.getMaxTownsPerNation()) throw new TownyException(Translatable.of("msg_err_nation_over_town_limit", TownySettings.getMaxTownsPerNation())); + if (TownySettings.getMaxResidentsPerNation() > 0 && nation.getResidents().size() >= TownySettings.getMaxResidentsPerNation()) + throw new TownyException(Translatable.of("msg_err_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation())); + // The list of valid invites. List newtownlist = new ArrayList<>(); // List of invites to be removed. From e1339889e058b2e183afef490367b5248bd3699b Mon Sep 17 00:00:00 2001 From: PainOchoco Date: Tue, 25 Oct 2022 21:34:48 +0200 Subject: [PATCH 2/5] Fixes --- .../bukkit/towny/command/NationCommand.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/com/palmergames/bukkit/towny/command/NationCommand.java b/src/com/palmergames/bukkit/towny/command/NationCommand.java index f74490b50e..a47c4769dc 100644 --- a/src/com/palmergames/bukkit/towny/command/NationCommand.java +++ b/src/com/palmergames/bukkit/towny/command/NationCommand.java @@ -670,7 +670,7 @@ private void parseNationJoin(Player player, String[] args) { throw new TownyException(Translatable.of("msg_err_nation_over_town_limit", TownySettings.getMaxTownsPerNation())); if (TownySettings.getMaxResidentsPerNation() > 0) { - if (nation.getResidents().size() >= TownySettings.getMaxResidentsPerNation()) + if (nation.getResidents().size() + town.getResidents().size() >= TownySettings.getMaxResidentsPerNation()) throw new TownyException(Translatable.of("msg_err_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation())); } @@ -1197,9 +1197,6 @@ public void nationAdd(Player player, String[] names) throws TownyException { if (TownySettings.getMaxTownsPerNation() > 0 && nation.getTowns().size() >= TownySettings.getMaxTownsPerNation()) throw new TownyException(Translatable.of("msg_err_nation_over_town_limit", TownySettings.getMaxTownsPerNation())); - if (TownySettings.getMaxResidentsPerNation() > 0 && nation.getResidents().size() >= TownySettings.getMaxResidentsPerNation()) - throw new TownyException(Translatable.of("msg_err_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation())); - // The list of valid invites. List newtownlist = new ArrayList<>(); // List of invites to be removed. @@ -1216,6 +1213,14 @@ public void nationAdd(Player player, String[] names) throws TownyException { removeinvites.add(townname); continue; } + + if (TownySettings.getMaxResidentsPerNation() > 0 && + nation.getResidents().size() + TownyAPI.getInstance().getTown(townname).getResidents().size() >= TownySettings.getMaxResidentsPerNation()) { + // Town has too many residents to join the nation + removeinvites.add(townname); + continue; + } + // add them to adding. newtownlist.add(townname); } From 0da196a843b0526a4b8cd742b5d38658177114c3 Mon Sep 17 00:00:00 2001 From: PainOchoco Date: Thu, 27 Oct 2022 16:51:57 +0200 Subject: [PATCH 3/5] Changed lang node --- resources/lang/en-US.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/en-US.yml b/resources/lang/en-US.yml index fb98a97ca7..ab4858b158 100644 --- a/resources/lang/en-US.yml +++ b/resources/lang/en-US.yml @@ -1783,4 +1783,4 @@ msg_x_has_been_withdrawn_for_jailing_of_prisoner_x: '%s withdrawn from Town bank #Message shown in the confirmation for /ta resetbanks {amount}. confirmation_are_you_sure_you_want_to_reset_all_banks: 'Are you sure you want to reset all town and nation banks to %s?' -msg_err_nation_over_resident_limit: '&cYour nation has reached the maximum number of allowed residents-per-nation: %s.' \ No newline at end of file +msg_err_nation_over_resident_limit: '&cYou cannot join this nation as it would be over the residents-per-nation limit of %s.' \ No newline at end of file From b59e94c78b3493957f3acd248cce086e6b0144ef Mon Sep 17 00:00:00 2001 From: PainOchoco Date: Fri, 28 Oct 2022 08:13:50 +0200 Subject: [PATCH 4/5] Added lang string for reaching the limit on nation join --- resources/lang/en-US.yml | 3 ++- src/com/palmergames/bukkit/towny/command/NationCommand.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/lang/en-US.yml b/resources/lang/en-US.yml index ab4858b158..2033bb7d2f 100644 --- a/resources/lang/en-US.yml +++ b/resources/lang/en-US.yml @@ -1783,4 +1783,5 @@ msg_x_has_been_withdrawn_for_jailing_of_prisoner_x: '%s withdrawn from Town bank #Message shown in the confirmation for /ta resetbanks {amount}. confirmation_are_you_sure_you_want_to_reset_all_banks: 'Are you sure you want to reset all town and nation banks to %s?' -msg_err_nation_over_resident_limit: '&cYou cannot join this nation as it would be over the residents-per-nation limit of %s.' \ No newline at end of file +msg_err_cannot_add_nation_over_resident_limit: '&cYour nation has reached the maximum number of allowed residents-per-nation: %s.' +msg_err_cannot_join_nation_over_resident_limit: '&cYou cannot join this nation as it would be over the residents-per-nation limit of %s.' \ No newline at end of file diff --git a/src/com/palmergames/bukkit/towny/command/NationCommand.java b/src/com/palmergames/bukkit/towny/command/NationCommand.java index a47c4769dc..f0b640a9cc 100644 --- a/src/com/palmergames/bukkit/towny/command/NationCommand.java +++ b/src/com/palmergames/bukkit/towny/command/NationCommand.java @@ -671,7 +671,7 @@ private void parseNationJoin(Player player, String[] args) { if (TownySettings.getMaxResidentsPerNation() > 0) { if (nation.getResidents().size() + town.getResidents().size() >= TownySettings.getMaxResidentsPerNation()) - throw new TownyException(Translatable.of("msg_err_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation())); + throw new TownyException(Translatable.of("msg_err_cannot_add_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation())); } if (TownySettings.getNationRequiresProximity() > 0) { @@ -1218,6 +1218,7 @@ public void nationAdd(Player player, String[] names) throws TownyException { nation.getResidents().size() + TownyAPI.getInstance().getTown(townname).getResidents().size() >= TownySettings.getMaxResidentsPerNation()) { // Town has too many residents to join the nation removeinvites.add(townname); + TownyMessaging.sendErrorMsg(player, Translatable.of("msg_err_cannot_join_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation())); continue; } From 0493e107c8e6d1c319ee2618026e096addde07a0 Mon Sep 17 00:00:00 2001 From: LlmDl Date: Fri, 28 Oct 2022 09:14:02 -0500 Subject: [PATCH 5/5] Fix exploitable post-invite tom-foolery - Recheck town/nations meet requirements before finally adding the town to the nation, something that occurs after a nation invite is accepted by a town. - Replace spaces with tabs. - Add another lang string for messaging feedback, add contexts for crowdin. --- resources/lang/en-US.yml | 8 +- .../bukkit/towny/command/NationCommand.java | 78 ++++++++++++++----- 2 files changed, 66 insertions(+), 20 deletions(-) diff --git a/resources/lang/en-US.yml b/resources/lang/en-US.yml index 2033bb7d2f..da70f9624e 100644 --- a/resources/lang/en-US.yml +++ b/resources/lang/en-US.yml @@ -1783,5 +1783,9 @@ msg_x_has_been_withdrawn_for_jailing_of_prisoner_x: '%s withdrawn from Town bank #Message shown in the confirmation for /ta resetbanks {amount}. confirmation_are_you_sure_you_want_to_reset_all_banks: 'Are you sure you want to reset all town and nation banks to %s?' -msg_err_cannot_add_nation_over_resident_limit: '&cYour nation has reached the maximum number of allowed residents-per-nation: %s.' -msg_err_cannot_join_nation_over_resident_limit: '&cYou cannot join this nation as it would be over the residents-per-nation limit of %s.' \ No newline at end of file +#Message shown when a nation cannot add a town because of the max-residents-limit. +msg_err_cannot_add_nation_over_resident_limit: '&cYour nation has reached the maximum number of allowed residents-per-nation, %s, and cannot add %s.' +#Message shown to a town when they cannot join a nation because of the max-residents-limit. +msg_err_cannot_join_nation_over_resident_limit: '&cYou cannot join this nation as it would be over the residents-per-nation limit of %s.' +#Message shown to a town because the nation has hit their max-towns-limit. +msg_err_cannot_join_nation_over_town_limit: '&cYou cannot join this nation, it has reached the maximum number of allowed towns-per-nation: %s.' \ No newline at end of file diff --git a/src/com/palmergames/bukkit/towny/command/NationCommand.java b/src/com/palmergames/bukkit/towny/command/NationCommand.java index f0b640a9cc..8a6613db17 100644 --- a/src/com/palmergames/bukkit/towny/command/NationCommand.java +++ b/src/com/palmergames/bukkit/towny/command/NationCommand.java @@ -662,17 +662,14 @@ private void parseNationJoin(Player player, String[] args) { if (!nation.isOpen()) throw new TownyException(Translatable.of("msg_err_nation_not_open", nation.getFormattedName())); - if ((TownySettings.getNumResidentsJoinNation() > 0) && (town.getNumResidents() < TownySettings.getNumResidentsJoinNation())) + if (!testTownHasEnoughResidents(town)) throw new TownyException(Translatable.of("msg_err_not_enough_residents_join_nation", town.getName())); - if (TownySettings.getMaxTownsPerNation() > 0) - if (nation.getTowns().size() >= TownySettings.getMaxTownsPerNation()) - throw new TownyException(Translatable.of("msg_err_nation_over_town_limit", TownySettings.getMaxTownsPerNation())); + if (!testNationMaxTowns(nation)) + throw new TownyException(Translatable.of("msg_err_nation_over_town_limit", TownySettings.getMaxTownsPerNation())); - if (TownySettings.getMaxResidentsPerNation() > 0) { - if (nation.getResidents().size() + town.getResidents().size() >= TownySettings.getMaxResidentsPerNation()) - throw new TownyException(Translatable.of("msg_err_cannot_add_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation())); - } + if (!testNationMaxResidents(nation, town)) + throw new TownyException(Translatable.of("msg_err_cannot_add_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation())); if (TownySettings.getNationRequiresProximity() > 0) { Coord capitalCoord = nation.getCapital().getHomeBlock().getCoord(); @@ -1194,7 +1191,7 @@ public void nationAdd(Player player, String[] names) throws TownyException { Nation nation = getNationFromPlayerOrThrow(player); - if (TownySettings.getMaxTownsPerNation() > 0 && nation.getTowns().size() >= TownySettings.getMaxTownsPerNation()) + if (testNationMaxTowns(nation)) throw new TownyException(Translatable.of("msg_err_nation_over_town_limit", TownySettings.getMaxTownsPerNation())); // The list of valid invites. @@ -1208,19 +1205,27 @@ public void nationAdd(Player player, String[] names) throws TownyException { continue; } - if (nation.hasTown(townname)) { + Town town = null; + try { + town = getTownOrThrow(townname); + } catch (NotRegisteredException e) { + // The Town doesn't actually exist or was mis-spelled. + removeinvites.add(townname); + continue; + } + + if (nation.hasTown(town) || town.hasNation()) { // Town is already part of the nation. removeinvites.add(townname); continue; } - if (TownySettings.getMaxResidentsPerNation() > 0 && - nation.getResidents().size() + TownyAPI.getInstance().getTown(townname).getResidents().size() >= TownySettings.getMaxResidentsPerNation()) { - // Town has too many residents to join the nation - removeinvites.add(townname); - TownyMessaging.sendErrorMsg(player, Translatable.of("msg_err_cannot_join_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation())); - continue; - } + if (testNationMaxResidents(nation, town)) { + // Town has too many residents to join the nation + removeinvites.add(townname); + TownyMessaging.sendErrorMsg(player, Translatable.of("msg_err_cannot_join_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation(), townname)); + continue; + } // add them to adding. newtownlist.add(townname); @@ -1261,7 +1266,7 @@ public static void nationAdd(Player player, Nation nation, List invited) t continue; } - if (TownySettings.getNumResidentsJoinNation() > 0 && town.getNumResidents() < TownySettings.getNumResidentsJoinNation()) { + if (!testTownHasEnoughResidents(town)) { remove.add(town); TownyMessaging.sendErrorMsg(player, Translatable.of("msg_err_not_enough_residents_join_nation", town.getName())); continue; @@ -1319,6 +1324,27 @@ public static void nationAdd(Player player, Nation nation, List invited) t public static void nationAdd(Nation nation, List towns) throws AlreadyRegisteredException { for (Town town : towns) { if (!town.hasNation()) { + if (!testNationMaxTowns(nation)) { + // Nation has hit the max-towns limit. + TownyMessaging.sendPrefixedNationMessage(nation, Translatable.of("msg_err_nation_over_town_limit", TownySettings.getMaxTownsPerNation())); + TownyMessaging.sendPrefixedTownMessage(town, Translatable.of("msg_err_cannot_join_nation_over_town_limit", TownySettings.getMaxTownsPerNation())); + continue; + } + + if (!testTownHasEnoughResidents(town)) { + // Town has dropped below min.-residents-to-join-nation limit. + TownyMessaging.sendPrefixedNationMessage(nation, Translatable.of("msg_err_not_enough_residents_join_nation", town.getName())); + TownyMessaging.sendPrefixedTownMessage(town, Translatable.of("msg_err_not_enough_residents_join_nation", town.getName())); + continue; + } + + if (!testNationMaxResidents(nation, town)) { + // Nation has hit the max-residents limit. + TownyMessaging.sendPrefixedNationMessage(nation, Translatable.of("msg_err_cannot_add_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation(), town.getName())); + TownyMessaging.sendPrefixedTownMessage(town, Translatable.of("msg_err_cannot_join_nation_over_resident_limit", TownySettings.getMaxResidentsPerNation())); + continue; + } + town.setNation(nation); town.save(); TownyMessaging.sendPrefixedNationMessage(nation, Translatable.of("msg_join_nation", town.getName())); @@ -1330,6 +1356,22 @@ public static void nationAdd(Nation nation, List towns) throws AlreadyRegi } + private static boolean testNationMaxResidents(Nation nation, Town town) { + int maxResidentPerNation = TownySettings.getMaxResidentsPerNation(); + if (maxResidentPerNation < 1) + return true; + return nation.getResidents().size() + town.getResidents().size() > maxResidentPerNation; + + } + + private static boolean testTownHasEnoughResidents(Town town) { + return TownySettings.getNumResidentsJoinNation() > 0 && town.getNumResidents() < TownySettings.getNumResidentsJoinNation(); + } + + private static boolean testNationMaxTowns(Nation nation) { + return TownySettings.getMaxTownsPerNation() > 0 && nation.getTowns().size() >= TownySettings.getMaxTownsPerNation(); + } + private static void nationRevokeInviteTown(CommandSender sender, Nation nation, List towns) { for (Town town : towns) {