Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add configurable plot type limits #6038

Merged
merged 3 commits into from
Aug 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions resources/config-migration.json
Original file line number Diff line number Diff line change
Expand Up @@ -307,5 +307,14 @@
"key": "migrate_notifications"
}
]
},
{
"version": "0.98.3.4",
"changes": [
{
"type": "RUNNABLE",
"key": "add_townblocktype_limits"
}
]
}
]
4 changes: 3 additions & 1 deletion resources/lang/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1756,4 +1756,6 @@ msg_comptype_upkeep: 'Upkeep'

# Added in 0.155
# Message shown when toggling town upkeep admin setting
msg_town_upkeep_setting_set_to: 'The town %s has had their upkeep setting set to %s.'
msg_town_upkeep_setting_set_to: 'The town %s has had their upkeep setting set to %s.'
#Shown when a player tries to set a plot type but their town has reached the limit, first number is the limit and the string is the type name.
msg_town_plot_type_limit_reached: 'Your town has reached the limit of %d %s plots.'
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class RunnableMigrations {

public RunnableMigrations() {
BY_NAME.put("migrate_notifications", MIGRATE_NOTIFICATIONS);
BY_NAME.put("add_townblocktype_limits", ADD_TOWNBLOCKTYPE_LIMITS);
}

@Nullable
Expand All @@ -36,4 +37,10 @@ else if (Boolean.parseBoolean(config.getString("notification.notifications_appea
else
config.set("notification.notifications_appear_as", "chat");
};

@SuppressWarnings("unchecked")
private final Consumer<CommentedConfiguration> ADD_TOWNBLOCKTYPE_LIMITS = config -> {
for (Map<?, ?> level : config.getMapList("levels.town_level"))
((Map<String, Object>) level).put("townBlockTypeLimits", new HashMap<>());
};
}
44 changes: 38 additions & 6 deletions src/com/palmergames/bukkit/towny/TownySettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
Expand All @@ -47,12 +48,14 @@
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class TownySettings {

// Town Level
@Desugar
public record TownLevel(String namePrefix, String namePostfix, String mayorPrefix, String mayorPostfix, int townBlockLimit, double upkeepModifier, int townOutpostLimit, int townBlockBuyBonusLimit, double debtCapModifier) {}
public record TownLevel(String namePrefix, String namePostfix, String mayorPrefix, String mayorPostfix, int townBlockLimit, double upkeepModifier, int townOutpostLimit, int townBlockBuyBonusLimit, double debtCapModifier, Map<String, Integer> townBlockTypeLimits) {}

// Nation Level
@Desugar
Expand All @@ -61,6 +64,7 @@ public record NationLevel(String namePrefix, String namePostfix, String capitalP
private static CommentedConfiguration config;
private static CommentedConfiguration newConfig;
private static int uuidCount;
private static boolean areLevelTypeLimitsConfigured;

private static final SortedMap<Integer, TownLevel> configTownLevel = Collections.synchronizedSortedMap(new TreeMap<>(Collections.reverseOrder()));
private static final SortedMap<Integer, NationLevel> configNationLevel = Collections.synchronizedSortedMap(new TreeMap<>(Collections.reverseOrder()));
Expand All @@ -69,7 +73,7 @@ public record NationLevel(String namePrefix, String namePostfix, String capitalP
private static final EnumSet<Material> switchUseMaterials = EnumSet.noneOf(Material.class);
private static final List<Class<?>> protectedMobs = new ArrayList<>();

public static void newTownLevel(int numResidents, String namePrefix, String namePostfix, String mayorPrefix, String mayorPostfix, int townBlockLimit, double townUpkeepMultiplier, int townOutpostLimit, int townBlockBuyBonusLimit, double debtCapModifier) {
public static void newTownLevel(int numResidents, String namePrefix, String namePostfix, String mayorPrefix, String mayorPostfix, int townBlockLimit, double townUpkeepMultiplier, int townOutpostLimit, int townBlockBuyBonusLimit, double debtCapModifier, Map<String, Integer> townBlockTypeLimits) {

configTownLevel.put(numResidents, new TownLevel(
namePrefix,
Expand All @@ -80,7 +84,8 @@ public static void newTownLevel(int numResidents, String namePrefix, String name
townUpkeepMultiplier,
townOutpostLimit,
townBlockBuyBonusLimit,
debtCapModifier
debtCapModifier,
townBlockTypeLimits.entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey().toLowerCase(Locale.ROOT), Map.Entry::getValue))
));
}

Expand Down Expand Up @@ -112,14 +117,26 @@ public static void newNationLevel(int numResidents, String namePrefix, String na
*
* @throws IOException if unable to load the Town Levels
*/
@SuppressWarnings("unchecked")
public static void loadTownLevelConfig() throws IOException {

// Some configs end up having their numResident: 0 level removed which causes big errors.
// Add a 0 level town_level here which may get replaced when the config's town_levels are loaded below.
newTownLevel(0, "", " Ruins", "Spirit", "", 1, 1.0, 0, 0, 1.0);
newTownLevel(0, "", " Ruins", "Spirit", "", 1, 1.0, 0, 0, 1.0, new HashMap<>());

List<Map<?, ?>> levels = config.getMapList("levels.town_level");
for (Map<?, ?> level : levels) {
for (Map<?, ?> genericLevel : levels) {

Map<String, Object> level = (Map<String, Object>) genericLevel;

Map<String, Integer> townBlockTypeLimits;
if (level.get("townBlockTypeLimits") instanceof List<?> list)
townBlockTypeLimits = ((List<Object>) list).stream().map(Object::toString).map(s -> s.replaceAll("[{}]", "")).collect(Collectors.toMap(e -> e.split("=")[0], e -> Integer.parseInt(e.split("=")[1])));
else
townBlockTypeLimits = new HashMap<>();

if (!townBlockTypeLimits.isEmpty())
areLevelTypeLimitsConfigured = true;

try {
/*
Expand All @@ -138,7 +155,8 @@ public static void loadTownLevelConfig() throws IOException {
Double.parseDouble(level.get("upkeepModifier").toString()),
Integer.parseInt(level.get("townOutpostLimit").toString()),
Integer.parseInt(level.get("townBlockBuyBonusLimit").toString()),
Double.parseDouble(level.get("debtCapModifier").toString())
Double.parseDouble(level.get("debtCapModifier").toString()),
townBlockTypeLimits
);
} catch (NullPointerException e) {
Towny.getPlugin().getLogger().warning("The town_level section of you Towny config.yml is out of date.");
Expand Down Expand Up @@ -523,6 +541,7 @@ private static void setDefaultLevels() {
level.put("townOutpostLimit", 0);
level.put("townBlockBuyBonusLimit", 0);
level.put("debtCapModifier", 1.0);
level.put("townBlockTypeLimits", new HashMap<>());
levels.add(new HashMap<>(level));
level.clear();
level.put("numResidents", 1);
Expand All @@ -535,6 +554,7 @@ private static void setDefaultLevels() {
level.put("townOutpostLimit", 0);
level.put("townBlockBuyBonusLimit", 0);
level.put("debtCapModifier", 1.0);
level.put("townBlockTypeLimits", new HashMap<>());
levels.add(new HashMap<>(level));
level.clear();
level.put("numResidents", 2);
Expand All @@ -547,6 +567,7 @@ private static void setDefaultLevels() {
level.put("townOutpostLimit", 1);
level.put("townBlockBuyBonusLimit", 0);
level.put("debtCapModifier", 1.0);
level.put("townBlockTypeLimits", new HashMap<>());
levels.add(new HashMap<>(level));
level.clear();
level.put("numResidents", 6);
Expand All @@ -559,6 +580,7 @@ private static void setDefaultLevels() {
level.put("townOutpostLimit", 1);
level.put("townBlockBuyBonusLimit", 0);
level.put("debtCapModifier", 1.0);
level.put("townBlockTypeLimits", new HashMap<>());
levels.add(new HashMap<>(level));
level.clear();
level.put("numResidents", 10);
Expand All @@ -571,6 +593,7 @@ private static void setDefaultLevels() {
level.put("townOutpostLimit", 2);
level.put("townBlockBuyBonusLimit", 0);
level.put("debtCapModifier", 1.0);
level.put("townBlockTypeLimits", new HashMap<>());
levels.add(new HashMap<>(level));
level.clear();
level.put("numResidents", 14);
Expand All @@ -583,6 +606,7 @@ private static void setDefaultLevels() {
level.put("townOutpostLimit", 2);
level.put("townBlockBuyBonusLimit", 0);
level.put("debtCapModifier", 1.0);
level.put("townBlockTypeLimits", new HashMap<>());
levels.add(new HashMap<>(level));
level.clear();
level.put("numResidents", 20);
Expand All @@ -595,6 +619,7 @@ private static void setDefaultLevels() {
level.put("townOutpostLimit", 3);
level.put("townBlockBuyBonusLimit", 0);
level.put("debtCapModifier", 1.0);
level.put("townBlockTypeLimits", new HashMap<>());
levels.add(new HashMap<>(level));
level.clear();
level.put("numResidents", 24);
Expand All @@ -607,6 +632,7 @@ private static void setDefaultLevels() {
level.put("townOutpostLimit", 3);
level.put("townBlockBuyBonusLimit", 0);
level.put("debtCapModifier", 1.0);
level.put("townBlockTypeLimits", new HashMap<>());
levels.add(new HashMap<>(level));
level.clear();
level.put("numResidents", 28);
Expand All @@ -619,6 +645,7 @@ private static void setDefaultLevels() {
level.put("townOutpostLimit", 4);
level.put("townBlockBuyBonusLimit", 0);
level.put("debtCapModifier", 1.0);
level.put("townBlockTypeLimits", new HashMap<>());
levels.add(new HashMap<>(level));
level.clear();
newConfig.set(ConfigNodes.LEVELS_TOWN_LEVEL.getRoot(), levels);
Expand Down Expand Up @@ -3214,5 +3241,10 @@ public static boolean areNumbersAllowedInTownNames() {
public static boolean areNumbersAllowedInNationNames() {
return getBoolean(ConfigNodes.GNATION_SETTINGS_ALLOW_NUMBERS_IN_NATION_NAME);
}

@ApiStatus.Internal
public static boolean areLevelTypeLimitsConfigured() {
return areLevelTypeLimitsConfigured;
}
}

13 changes: 13 additions & 0 deletions src/com/palmergames/bukkit/towny/object/Town.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
Expand Down Expand Up @@ -1706,6 +1707,18 @@ public int getManualTownLevel() {
public void setManualTownLevel(int manualTownLevel) {
this.manualTownLevel = manualTownLevel;
}

/**
* @param type The townblock type to get the limit for.
* @return The townblock type limit, or -1 if no limit is configured.
*/
@SuppressWarnings("unchecked")
public int getTownBlockTypeLimit(TownBlockType type) {
if (!TownySettings.areLevelTypeLimitsConfigured())
return -1;

return TownySettings.getTownLevel(this).townBlockTypeLimits().getOrDefault(type.getName().toLowerCase(Locale.ROOT), -1);
}

@Override
public @NotNull Iterable<? extends Audience> audiences() {
Expand Down
4 changes: 4 additions & 0 deletions src/com/palmergames/bukkit/towny/object/TownBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,10 @@ public void setType(int typeId) {
*/
public void setType(TownBlockType type, Resident resident) throws TownyException {

int typeLimit = town.getTownBlockTypeLimit(type);
if (typeLimit >= 0 && (typeLimit == 0 || town.getTownBlockTypeCache().getNumTownBlocks(type, TownBlockTypeCache.CacheType.ALL) >= typeLimit))
throw new TownyException(Translatable.of("msg_town_plot_type_limit_reached", typeLimit, type.getFormattedName()));

// Delete a jail if this is no longer going to be a jail.
if (this.isJail() && !TownBlockType.JAIL.equals(type) && getJail() != null) {
TownyUniverse.getInstance().getDataSource().removeJail(getJail());
Expand Down