Skip to content

Commit f11882d

Browse files
committed
add config with per-enchant options for max level and cost
1 parent ec31ee0 commit f11882d

File tree

4 files changed

+277
-9
lines changed

4 files changed

+277
-9
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package pro.cloudnode.smp.enchantbookplus;
2+
3+
import org.bukkit.enchantments.Enchantment;
4+
import org.jetbrains.annotations.NotNull;
5+
import org.jetbrains.annotations.Nullable;
6+
7+
import java.util.ArrayList;
8+
import java.util.HashMap;
9+
import java.util.List;
10+
import java.util.Objects;
11+
import java.util.Optional;
12+
import java.util.stream.Collectors;
13+
14+
public final class ConfigEnchantmentEntry {
15+
/**
16+
* Name of the enchantment.
17+
*/
18+
private final @NotNull String name;
19+
20+
/**
21+
* Maximum level of the enchantment.
22+
*/
23+
private final @Nullable Integer maxLevel;
24+
25+
/**
26+
* Max level relative
27+
*/
28+
private final boolean maxLevelRelative;
29+
30+
/**
31+
* Cost of the enchantment.
32+
*/
33+
private final int cost;
34+
35+
/**
36+
* Multiply cost by level.
37+
*/
38+
private final boolean multiplyCostByLevel;
39+
40+
/**
41+
* Name of the enchantment.
42+
*/
43+
public @NotNull String getName() {
44+
return name;
45+
}
46+
47+
/**
48+
* Maximum level of the enchantment.
49+
* @param enchantment The enchantment
50+
*/
51+
public @NotNull Optional<Integer> getMaxLevel(final @NotNull Enchantment enchantment) {
52+
if (Optional.ofNullable(maxLevel).isEmpty()) return Optional.empty();
53+
if (maxLevelRelative) return Optional.of(enchantment.getMaxLevel() + maxLevel);
54+
return Optional.of(maxLevel);
55+
}
56+
57+
/**
58+
* Cost of the enchantment.
59+
*/
60+
public int getCost() {
61+
return cost;
62+
}
63+
64+
/**
65+
* Multiply cost by level.
66+
*/
67+
public boolean getMultiplyCostByLevel() {
68+
return multiplyCostByLevel;
69+
}
70+
71+
/**
72+
* @param name Name of the enchantment.
73+
* @param maxLevel Maximum level of the enchantment.
74+
* @param maxLevelRelative Max level relative
75+
* @param cost Cost of the enchantment.
76+
* @param multiplyCostByLevel Multiply cost by level.
77+
*/
78+
public ConfigEnchantmentEntry(final @NotNull String name, final @Nullable Integer maxLevel, final boolean maxLevelRelative, final int cost, final boolean multiplyCostByLevel) {
79+
this.name = name;
80+
this.maxLevel = maxLevel;
81+
this.maxLevelRelative = maxLevelRelative;
82+
this.cost = cost;
83+
this.multiplyCostByLevel = multiplyCostByLevel;
84+
}
85+
86+
/**
87+
* From config object
88+
*
89+
* @param configValue Config object
90+
*/
91+
public static ConfigEnchantmentEntry configValue(final @NotNull HashMap<@NotNull String, @NotNull Object> configValue) {
92+
final @NotNull String name = (String) Objects.requireNonNull(configValue.get("name"));
93+
final @Nullable Integer maxLevel;
94+
final boolean maxLevelRelative;
95+
if (configValue.containsKey("max-level")) {
96+
if (configValue.get("max-level") instanceof final @NotNull String string) {
97+
if (string.startsWith("+")) {
98+
maxLevel = Integer.parseInt(string.substring(1));
99+
maxLevelRelative = true;
100+
}
101+
else {
102+
maxLevel = Integer.parseInt(string);
103+
maxLevelRelative = false;
104+
}
105+
}
106+
else {
107+
maxLevel = (Integer) configValue.get("max-level");
108+
maxLevelRelative = false;
109+
}
110+
}
111+
else {
112+
maxLevel = null;
113+
maxLevelRelative = false;
114+
}
115+
final boolean multiplyCostByLevel;
116+
final int cost;
117+
if (configValue.containsKey("cost")) {
118+
if (configValue.get("cost") instanceof final @NotNull String costString) {
119+
if (costString.startsWith("*")) {
120+
multiplyCostByLevel = true;
121+
cost = Integer.parseInt(costString.substring(1));
122+
}
123+
else {
124+
multiplyCostByLevel = false;
125+
cost = Integer.parseInt(costString);
126+
}
127+
}
128+
else {
129+
multiplyCostByLevel = false;
130+
cost = (Integer) configValue.get("cost");
131+
}
132+
}
133+
else {
134+
multiplyCostByLevel = false;
135+
cost = 0;
136+
}
137+
return new ConfigEnchantmentEntry(name, maxLevel, maxLevelRelative, cost, multiplyCostByLevel);
138+
}
139+
140+
141+
/**
142+
* From config object array
143+
*
144+
* @param configValue Config object array
145+
*/
146+
public static @NotNull List<@NotNull ConfigEnchantmentEntry> configArray(final @NotNull ArrayList<@NotNull HashMap<@NotNull String, @NotNull Object>> configValue) {
147+
return configValue.stream().map(ConfigEnchantmentEntry::configValue).collect(Collectors.toList());
148+
}
149+
150+
/**
151+
* Check if valid config object
152+
*
153+
* @param configValue Config object
154+
*/
155+
private static boolean isValidConfigValue(final @Nullable Object configValue) {
156+
if (configValue == null) return false;
157+
if (!(configValue instanceof final @NotNull ArrayList<?> arrayList)) return false;
158+
for (final @NotNull Object object : arrayList) {
159+
if (!(object instanceof final @NotNull HashMap<?, ?> hashMap)) return false;
160+
if (!hashMap.containsKey("name")) return false;
161+
if (!(hashMap.get("name") instanceof String)) return false;
162+
if (hashMap.containsKey("max-level") && !(hashMap.get("max-level") instanceof String) && !(hashMap.get("max-level") instanceof Integer)) return false;
163+
if (hashMap.containsKey("cost") && !(hashMap.get("cost") instanceof String) && !(hashMap.get("cost") instanceof Integer)) return false;
164+
}
165+
return true;
166+
}
167+
168+
/**
169+
* From config
170+
*
171+
* @param configValue Config object
172+
*/
173+
public static @NotNull List<@NotNull ConfigEnchantmentEntry> config(final @Nullable Object configValue) throws IllegalArgumentException {
174+
if (!isValidConfigValue(configValue)) throw new IllegalArgumentException("Invalid config value");
175+
return configArray((ArrayList<HashMap<String, Object>>) configValue);
176+
}
177+
}

src/main/java/pro/cloudnode/smp/enchantbookplus/EnchantBookPlus.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,70 @@
11
package pro.cloudnode.smp.enchantbookplus;
22

33
import org.bukkit.plugin.java.JavaPlugin;
4+
import org.jetbrains.annotations.NotNull;
45
import pro.cloudnode.smp.enchantbookplus.event.PrepareAnvil;
56

7+
import java.util.ArrayList;
8+
import java.util.List;
9+
import java.util.Optional;
10+
import java.util.logging.Level;
11+
612
public final class EnchantBookPlus extends JavaPlugin {
13+
/**
14+
* Get plugin instance.
15+
*/
16+
public static EnchantBookPlus getInstance() {
17+
return getPlugin(EnchantBookPlus.class);
18+
}
19+
720
/**
821
* Register event listeners.
922
*/
1023
private void registerEvents() {
1124
getServer().getPluginManager().registerEvents(new PrepareAnvil(), this);
1225
}
1326

27+
/**
28+
* Config enchantments cache
29+
*/
30+
private @NotNull List<@NotNull ConfigEnchantmentEntry> configEnchantments = new ArrayList<>();
31+
32+
/**
33+
* Config enchantments cache
34+
*/
35+
public @NotNull List<@NotNull ConfigEnchantmentEntry> getConfigEnchantments() {
36+
if (configEnchantments.size() == 0) reload();
37+
return configEnchantments;
38+
}
39+
40+
/**
41+
* Get enchantment from cache
42+
*
43+
* @param name Name of the enchantment
44+
*/
45+
public @NotNull Optional<@NotNull ConfigEnchantmentEntry> getConfigEnchantment(final @NotNull String name) {
46+
return getConfigEnchantments().stream().filter(enchantment -> enchantment.getName().equalsIgnoreCase(name) || enchantment.getName().equalsIgnoreCase("ALL")).findFirst();
47+
}
48+
49+
/**
50+
* Reload config
51+
*/
52+
public void reload() {
53+
reloadConfig();
54+
try {
55+
configEnchantments = ConfigEnchantmentEntry.config(getConfig().get("enchantments"));
56+
}
57+
catch (final @NotNull Exception exception) {
58+
getLogger().log(Level.SEVERE, "Failed to load config", exception);
59+
getServer().getPluginManager().disablePlugin(this);
60+
}
61+
}
62+
1463
@Override
1564
public void onEnable() {
1665
registerEvents();
66+
saveDefaultConfig();
67+
reload();
1768
}
1869

1970
@Override

src/main/java/pro/cloudnode/smp/enchantbookplus/event/PrepareAnvil.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@
99
import org.bukkit.inventory.ItemStack;
1010
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
1111
import org.jetbrains.annotations.NotNull;
12+
import pro.cloudnode.smp.enchantbookplus.ConfigEnchantmentEntry;
13+
import pro.cloudnode.smp.enchantbookplus.EnchantBookPlus;
1214

13-
import java.util.*;
15+
import java.util.HashMap;
16+
import java.util.Map;
17+
import java.util.Objects;
18+
import java.util.Optional;
1419

15-
public class PrepareAnvil implements Listener {
20+
public final class PrepareAnvil implements Listener {
1621
@EventHandler
1722
public void onPrepareAnvil(final @NotNull PrepareAnvilEvent event) {
1823
final @NotNull Optional<@NotNull ItemStack> result = Optional.ofNullable(event.getResult());
@@ -26,27 +31,41 @@ public void onPrepareAnvil(final @NotNull PrepareAnvilEvent event) {
2631
final @NotNull Map<@NotNull Enchantment, @NotNull Integer> upgradeEnchants =
2732
upgrade.getType() == Material.ENCHANTED_BOOK && upgrade.getItemMeta() instanceof final @NotNull EnchantmentStorageMeta upgradeMeta ?
2833
upgradeMeta.getStoredEnchants() : upgrade.getEnchantments();
29-
if (itemEnchants.isEmpty() || upgradeEnchants.isEmpty()) return;
34+
if (upgradeEnchants.isEmpty()) return;
3035
final @NotNull HashMap<@NotNull Enchantment, @NotNull Integer> upgrades = new HashMap<>();
36+
int cost = 0;
3137
for (final @NotNull Map.Entry<@NotNull Enchantment, @NotNull Integer> entry : upgradeEnchants.entrySet()) {
3238
final @NotNull Enchantment enchantment = entry.getKey();
39+
if (enchantment.getMaxLevel() == 1) continue;
40+
final @NotNull Optional<@NotNull ConfigEnchantmentEntry> configEnchantment = EnchantBookPlus.getInstance().getConfigEnchantment(enchantment.getKey().getKey());
41+
if (configEnchantment.isEmpty()) continue;
3342
final int upgradeLevel = entry.getValue();
34-
if (upgradeLevel <= enchantment.getMaxLevel()) continue;
43+
final int finalLevel;
3544
if (itemEnchants.containsKey(enchantment)) {
3645
final int itemLevel = itemEnchants.get(enchantment);
37-
if (itemLevel > upgradeLevel) upgrades.put(enchantment, itemLevel);
38-
else if (itemLevel == upgradeLevel) upgrades.put(enchantment, upgradeLevel + 1);
39-
else upgrades.put(enchantment, upgradeLevel);
46+
if (itemLevel > upgradeLevel) finalLevel = itemLevel;
47+
else if (itemLevel == upgradeLevel) finalLevel = upgradeLevel + 1;
48+
else finalLevel = upgradeLevel;
4049
}
41-
else upgrades.put(enchantment, upgradeLevel);
50+
else finalLevel = upgradeLevel;
51+
if (finalLevel < enchantment.getMaxLevel()) continue;
52+
if (configEnchantment.get().getMaxLevel(enchantment).isPresent() && finalLevel > configEnchantment.get().getMaxLevel(enchantment).get()) continue;
53+
if (finalLevel > upgradeLevel) cost += configEnchantment.get().getMultiplyCostByLevel() ? configEnchantment.get().getCost() * (finalLevel - enchantment.getMaxLevel()) : configEnchantment.get().getCost();
54+
upgrades.put(enchantment, finalLevel);
4255
}
4356
if (upgrades.isEmpty()) return;
57+
final int vanillaCost = inventory.getRepairCost();
58+
inventory.setRepairCost(vanillaCost + cost);
4459
for (final @NotNull Map.Entry<@NotNull Enchantment, @NotNull Integer> entry : upgrades.entrySet()) {
4560
if (result.get().getItemMeta() instanceof final @NotNull EnchantmentStorageMeta resultMeta) {
61+
if (!resultMeta.getStoredEnchants().containsKey(entry.getKey())) continue;
4662
resultMeta.addStoredEnchant(entry.getKey(), entry.getValue(), true);
4763
result.get().setItemMeta(resultMeta);
4864
}
49-
else result.get().addUnsafeEnchantment(entry.getKey(), entry.getValue());
65+
else {
66+
if (!result.get().getEnchantments().containsKey(entry.getKey())) continue;
67+
result.get().addUnsafeEnchantment(entry.getKey(), entry.getValue());
68+
}
5069
}
5170
}
5271
}

src/main/resources/config.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# List of enchantments for which to enable upgrading above the vanilla max levels using an anvil.
2+
enchantments:
3+
# Enchantment name (same as in the /enchant command).
4+
# Set this to "ALL" to enable upgrading for all other enchantments not listed here.
5+
# NOTE: Enchantments that on Vanilla have a max level of 1 (e.g. Silk Touch, Mending, Curse of Vanishing, Infinity) etc. are always ignored by this plugin.
6+
- name: efficiency
7+
# Maximum level to which the enchantment can be upgraded.
8+
# For relative levels above the vanilla max level, use e.g. "+1". E.g. +1 for Protection will allow upgrading to Protection V. For Efficiency, +1 will allow upgrading to Efficiency VI.
9+
# If you use "+" make sure to set the value in quotes, e.g. "+1" instead of +1
10+
# To allow upgrading to any level, do not set this value. Note: enchantment levels above 255 are not supported by Minecraft.
11+
max-level: 10
12+
13+
# The XP cost (in levels) added to the vanilla cost
14+
# Use "*" prefix to multiply by the enchantment level, e.g. "*10" will cost XP levels per enchantment level above vanilla (e.g. 20XP for Efficiency VII)
15+
# If you use "*" make sure to set the value in quotes, e.g. "*10" instead of *10
16+
# You can also just provide a flat value for all levels, e.g. "10" will cost 10 XP levels regardless of the enchantment level
17+
cost: "*150"
18+
19+
- name: ALL
20+
max-level: "+1"
21+
cost: 100

0 commit comments

Comments
 (0)