This commit is contained in:
BuildTools 2023-11-28 19:45:48 +05:00
parent 9d7c98cddb
commit ce3877bd07
16 changed files with 253 additions and 117 deletions

View File

@ -84,7 +84,9 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
this.tierManager.shutdown();
this.tierManager = null;
}
if (EngineUtils.hasPlaceholderAPI()) {
PlaceholderHook.shutdown();
}
this.registry.shutdown();
}
@ -124,7 +126,7 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
@Override
public void registerHooks() {
if (EngineUtils.hasPlaceholderAPI()) {
PlaceholderHook.setup();
PlaceholderHook.setup(this);
}
}

View File

@ -3,7 +3,6 @@ package su.nightexpress.excellentenchants.api.enchantment;
import org.bukkit.Keyed;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.EventPriority;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@ -51,7 +51,7 @@ public class BookCommand extends AbstractCommand<ExcellentEnchants> {
return;
}
Player player = plugin.getServer().getPlayer(result.getArg(1));
Player player = PlayerUtil.getPlayer(result.getArg(1));
if (player == null) {
this.errorPlayer(sender);
return;

View File

@ -53,7 +53,7 @@ public class TierbookCommand extends AbstractCommand<ExcellentEnchants> {
return;
}
Player player = plugin.getServer().getPlayer(result.getArg(1));
Player player = PlayerUtil.getPlayer(result.getArg(1));
if (player == null) {
this.errorPlayer(sender);
return;

View File

@ -6,14 +6,13 @@ import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.Colorizer;
import su.nexmedia.engine.utils.Colors2;
import su.nexmedia.engine.utils.StringUtil;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.enchantment.type.ObtainType;
import su.nightexpress.excellentenchants.tier.Tier;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -139,4 +138,24 @@ public class Config {
ObtainSettings settings = OBTAIN_SETTINGS.get().get(obtainType);
return settings == null || !settings.isEnabled() ? Optional.empty() : Optional.of(settings);
}
@NotNull
public static List<Tier> getDefaultTiers() {
List<Tier> list = new ArrayList<>();
list.add(new Tier("common", 1, "Common", Colors2.WHITE, getObtainWeight(50D)));
list.add(new Tier("rare", 2, "Rare", Colors2.GREEN, getObtainWeight(25D)));
list.add(new Tier("unique", 3, "Unique", Colors2.YELLOW, getObtainWeight(15D)));
list.add(new Tier("legendary", 4, "Legendary", Colors2.ORANGE, getObtainWeight(5D)));
list.add(new Tier("cursed", 0, "Cursed", Colors2.RED, getObtainWeight(5D)));
return list;
}
@NotNull
private static Map<ObtainType, Double> getObtainWeight(double weight) {
Map<ObtainType, Double> map = new HashMap<>();
for (ObtainType obtainType : ObtainType.values()) {
map.put(obtainType, weight);
}
return map;
}
}

View File

@ -3,7 +3,7 @@ package su.nightexpress.excellentenchants.config;
import su.nexmedia.engine.api.lang.LangKey;
import su.nexmedia.engine.lang.EngineLang;
import static su.nexmedia.engine.utils.Colors.*;
import static su.nexmedia.engine.utils.Colors2.*;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class Lang extends EngineLang {
@ -12,18 +12,18 @@ public class Lang extends EngineLang {
public static final LangKey COMMAND_ENCHANT_USAGE = LangKey.of("Command.Enchant.Usage", "<enchant> <level> [player] [slot]");
public static final LangKey COMMAND_ENCHANT_DESC = LangKey.of("Command.Enchant.Desc", "Enchants the item in your hand.");
public static final LangKey COMMAND_ENCHANT_DONE_SELF = LangKey.of("Command.Enchant.Done.Self", ORANGE + GENERIC_ITEM + LIGHT_YELLOW + " enchanted with " + GENERIC_ENCHANT + " " + GENERIC_LEVEL + LIGHT_YELLOW + "!");
public static final LangKey COMMAND_ENCHANT_DONE_OTHERS = LangKey.of("Command.Enchant.Done.Others", ORANGE + PLAYER_NAME + LIGHT_YELLOW + "'s " + ORANGE + GENERIC_ITEM + LIGHT_YELLOW + " enchanted with " + GENERIC_ENCHANT + " " + GENERIC_LEVEL + LIGHT_YELLOW + "!");
public static final LangKey COMMAND_ENCHANT_DONE_SELF = LangKey.of("Command.Enchant.Done.Self", LIGHT_ORANGE + GENERIC_ITEM + LIGHT_YELLOW + " enchanted with " + GENERIC_ENCHANT + " " + GENERIC_LEVEL + LIGHT_YELLOW + "!");
public static final LangKey COMMAND_ENCHANT_DONE_OTHERS = LangKey.of("Command.Enchant.Done.Others", LIGHT_ORANGE + PLAYER_DISPLAY_NAME + LIGHT_YELLOW + "'s " + LIGHT_ORANGE + GENERIC_ITEM + LIGHT_YELLOW + " enchanted with " + GENERIC_ENCHANT + " " + GENERIC_LEVEL + LIGHT_YELLOW + "!");
public static final LangKey COMMAND_ENCHANT_ERROR_NO_ITEM = LangKey.of("Command.Enchant.Error.NoItem", RED + "There is no item to enchant!");
public static final LangKey COMMAND_BOOK_USAGE = LangKey.of("Command.Book.Usage", "<player> <enchant> <level>");
public static final LangKey COMMAND_BOOK_DESC = LangKey.of("Command.Book.Desc", "Gives custom enchanted book.");
public static final LangKey COMMAND_BOOK_DONE = LangKey.of("Command.Book.Done", LIGHT_YELLOW + "Given " + ORANGE + GENERIC_ENCHANT + LIGHT_YELLOW + " enchanted book to " + ORANGE + PLAYER_DISPLAY_NAME + LIGHT_YELLOW + ".");
public static final LangKey COMMAND_BOOK_DONE = LangKey.of("Command.Book.Done", LIGHT_YELLOW + "Given " + LIGHT_ORANGE + GENERIC_ENCHANT + LIGHT_YELLOW + " enchanted book to " + LIGHT_ORANGE + PLAYER_DISPLAY_NAME + LIGHT_YELLOW + ".");
public static final LangKey COMMAND_TIER_BOOK_USAGE = LangKey.of("Command.TierBook.Usage", "<player> <tier> <level>");
public static final LangKey COMMAND_TIER_BOOK_DESC = LangKey.of("Command.TierBook.Desc", "Gives an enchanted book.");
public static final LangKey COMMAND_TIER_BOOK_ERROR = LangKey.of("Command.TierBook.Error", RED + "Invalid tier!");
public static final LangKey COMMAND_TIER_BOOK_DONE = LangKey.of("Command.TierBook.Done", LIGHT_YELLOW + "Given " + ORANGE + TIER_NAME + LIGHT_YELLOW + " enchanted book to " + ORANGE + PLAYER_DISPLAY_NAME + LIGHT_YELLOW + ".");
public static final LangKey COMMAND_TIER_BOOK_DONE = LangKey.of("Command.TierBook.Done", LIGHT_YELLOW + "Given " + LIGHT_ORANGE + TIER_NAME + LIGHT_YELLOW + " enchanted book to " + LIGHT_ORANGE + PLAYER_DISPLAY_NAME + LIGHT_YELLOW + ".");
public static final LangKey ERROR_NO_ENCHANT = LangKey.of("Error.NoEnchant", RED + "Invalid enchantment.");

View File

@ -2,18 +2,18 @@ package su.nightexpress.excellentenchants.enchantment.config;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nexmedia.engine.utils.Scaler;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.utils.StringUtil;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.util.Evaluator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.*;
public class EnchantScaler extends Scaler {
public class EnchantScaler {
public EnchantScaler(@NotNull ExcellentEnchant enchant, @NotNull String path) {
super(enchant.getConfig(), path, Placeholders.ENCHANTMENT_LEVEL, enchant.getStartLevel(), enchant.getMaxLevel());
this(enchant.getConfig(), path, Placeholders.ENCHANTMENT_LEVEL, enchant.getStartLevel(), enchant.getMaxLevel());
}
@NotNull
@ -27,4 +27,54 @@ public class EnchantScaler extends Scaler {
}
return new EnchantScaler(enchant, path);
}
private final int levelMin;
private final int levelMax;
private final TreeMap<Integer, Double> values;
public EnchantScaler(@NotNull JYML cfg, @NotNull String path, @NotNull String levelPlaceholder, int levelMin, int levelMax) {
this.levelMin = levelMin;
this.levelMax = levelMax;
this.values = new TreeMap<>();
// Load different values for each object level.
Set<String> lvlKeys = cfg.getSection(path);
if (!lvlKeys.isEmpty()) {
for (String sLvl : lvlKeys) {
int eLvl = StringUtil.getInteger(sLvl, 0);
if (eLvl < this.getLevelMin() || eLvl > this.getLevelMax()) continue;
String formula = cfg.getString(path + "." + sLvl, "0").replace(levelPlaceholder, sLvl);
values.put(eLvl, Evaluator.evaluate(formula));
}
return;
}
// Load the single formula for all object levels.
for (int lvl = this.getLevelMin(); lvl < (this.getLevelMax() + 1); lvl++) {
String sLvl = String.valueOf(lvl);
String exChance = cfg.getString(path, "").replace(levelPlaceholder, sLvl);
if (exChance.isEmpty()) continue;
values.put(lvl, Evaluator.evaluate(exChance));
}
}
public int getLevelMin() {
return this.levelMin;
}
public int getLevelMax() {
return this.levelMax;
}
@NotNull
public TreeMap<Integer, Double> getValues() {
return this.values;
}
public double getValue(int level) {
Map.Entry<Integer, Double> en = this.values.floorEntry(level);
return en != null ? en.getValue() : 0D;
}
}

View File

@ -70,7 +70,7 @@ public abstract class ExcellentEnchant extends Enchantment implements IEnchantme
.add(Placeholders.ENCHANTMENT_LEVEL_MIN, () -> String.valueOf(this.getStartLevel()))
.add(Placeholders.ENCHANTMENT_LEVEL_MAX, () -> String.valueOf(this.getMaxLevel()))
.add(Placeholders.ENCHANTMENT_TIER, () -> this.getTier().getName())
.add(Placeholders.ENCHANTMENT_TIER_COLOR, () -> String.valueOf(this.getTier().getColor()))
.add(Placeholders.ENCHANTMENT_TIER_COLOR, () -> this.getTier().getColor())
.add(Placeholders.ENCHANTMENT_FIT_ITEM_TYPES, () -> String.join(", ", Stream.of(this.getFitItemTypes()).map(type -> plugin.getLangManager().getEnum(type)).toList()))
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_ENCHANTING, () -> NumberUtil.format(this.getObtainChance(ObtainType.ENCHANTING)))
.add(Placeholders.ENCHANTMENT_OBTAIN_CHANCE_VILLAGER, () -> NumberUtil.format(this.getObtainChance(ObtainType.VILLAGER)))

View File

@ -33,12 +33,12 @@ public class EnchantAnvilListener extends AbstractListener<ExcellentEnchants> {
}
@EventHandler(priority = EventPriority.HIGH)
public void onAnvilRename(PrepareAnvilEvent e) {
AnvilInventory inventory = e.getInventory();
public void onAnvilRename(PrepareAnvilEvent event) {
AnvilInventory inventory = event.getInventory();
ItemStack first = inventory.getItem(0);
ItemStack second = inventory.getItem(1);
ItemStack result = e.getResult();
ItemStack result = event.getResult();
if (first == null) first = new ItemStack(Material.AIR);
if (second == null) second = new ItemStack(Material.AIR);
@ -47,10 +47,10 @@ public class EnchantAnvilListener extends AbstractListener<ExcellentEnchants> {
// Check if source item is an enchantable single item.
if (first.getType().isAir() || first.getAmount() > 1 || !EnchantUtils.isEnchantable(first)) return;
if (this.handleRename(e, first, second, result)) return;
if (this.handleRecharge(e, first, second, result)) return;
if (this.handleRename(event, first, second, result)) return;
if (this.handleRecharge(event, first, second, result)) return;
this.handleEnchantMerging(e, first, second, result);
this.handleEnchantMerging(event, first, second, result);
}
private boolean handleRename(@NotNull PrepareAnvilEvent event,

View File

@ -235,15 +235,20 @@ public class EnchantRegistry extends AbstractManager<ExcellentEnchants> {
}
@NotNull
public static Set<PassiveEnchant> getPeriodicTalents() {
public static Set<PassiveEnchant> getPeriodicEnchants() {
return getEnchantments(PassiveEnchant.class);
}
@NotNull
@SuppressWarnings("unchecked")
public static <T extends IEnchantment> Set<T> getEnchantments(@NotNull Class<T> clazz) {
Set<? super T> set = new HashSet<>(ENCHANTS_MAP.getOrDefault(clazz, Collections.emptySet()));
return (Set<T>) set;
Set<T> enchants = new HashSet<>();
ENCHANTS_MAP.getOrDefault(clazz, Collections.emptySet()).forEach(talent -> {
enchants.add(clazz.cast(talent));
});
return enchants;
//Set<? super T> set = new HashSet<>(ENCHANTS_MAP.getOrDefault(clazz, Collections.emptySet()));
//return (Set<T>) set;
}
@Nullable

View File

@ -0,0 +1,94 @@
package su.nightexpress.excellentenchants.enchantment.util;
import org.jetbrains.annotations.NotNull;
public class Evaluator {
public static double evaluate(@NotNull final String str) {
return new Object() {
int pos = -1, ch;
void nextChar() {
ch = (++pos < str.length()) ? str.charAt(pos) : -1;
}
boolean eat(int charToEat) {
while (ch == ' ') nextChar();
if (ch == charToEat) {
nextChar();
return true;
}
return false;
}
double parse() {
nextChar();
double x = parseExpression();
if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch);
return x;
}
// Grammar:
// expression = term | expression `+` term | expression `-` term
// term = factor | term `*` factor | term `/` factor
// factor = `+` factor | `-` factor | `(` expression `)` | number
// | functionName `(` expression `)` | functionName factor
// | factor `^` factor
double parseExpression() {
double x = parseTerm();
for (;;) {
if (eat('+')) x += parseTerm(); // addition
else if (eat('-')) x -= parseTerm(); // subtraction
else return x;
}
}
double parseTerm() {
double x = parseFactor();
for (;;) {
if (eat('*')) x *= parseFactor(); // multiplication
else if (eat('/')) x /= parseFactor(); // division
else return x;
}
}
double parseFactor() {
if (eat('+')) return +parseFactor(); // unary plus
if (eat('-')) return -parseFactor(); // unary minus
double x;
int startPos = this.pos;
if (eat('(')) { // parentheses
x = parseExpression();
if (!eat(')')) throw new RuntimeException("Missing ')'");
} else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
x = Double.parseDouble(str.substring(startPos, this.pos));
} else if (ch >= 'a' && ch <= 'z') { // functions
while (ch >= 'a' && ch <= 'z') nextChar();
String func = str.substring(startPos, this.pos);
if (eat('(')) {
x = parseExpression();
if (!eat(')')) throw new RuntimeException("Missing ')' after argument to " + func);
} else {
x = parseFactor();
}
x = switch (func) {
case "sqrt" -> Math.sqrt(x);
case "sin" -> Math.sin(Math.toRadians(x));
case "cos" -> Math.cos(Math.toRadians(x));
case "tan" -> Math.tan(Math.toRadians(x));
default -> throw new RuntimeException("Unknown function: " + func);
};
} else {
throw new RuntimeException("Unexpected: " + (char)ch);
}
if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation
return x;
}
}.parse();
}
}

View File

@ -8,6 +8,7 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nexmedia.engine.utils.StringUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.ExcellentEnchantsAPI;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.registry.EnchantRegistry;
@ -16,9 +17,9 @@ public class PlaceholderHook {
private static EnchantsExpansion expansion;
public static void setup() {
public static void setup(@NotNull ExcellentEnchants plugin) {
if (expansion == null) {
expansion = new EnchantsExpansion();
expansion = new EnchantsExpansion(plugin);
expansion.register();
}
}
@ -32,22 +33,28 @@ public class PlaceholderHook {
static class EnchantsExpansion extends PlaceholderExpansion {
private final ExcellentEnchants plugin;
public EnchantsExpansion(@NotNull ExcellentEnchants plugin) {
this.plugin = plugin;
}
@Override
@NotNull
public String getIdentifier() {
return "excellentenchants";
return this.plugin.getName().toLowerCase();
}
@Override
@NotNull
public String getAuthor() {
return ExcellentEnchantsAPI.PLUGIN.getDescription().getAuthors().get(0);
return this.plugin.getDescription().getAuthors().get(0);
}
@Override
@NotNull
public String getVersion() {
return ExcellentEnchantsAPI.PLUGIN.getDescription().getVersion();
return this.plugin.getDescription().getVersion();
}
@Override

View File

@ -1,7 +1,7 @@
package su.nightexpress.excellentenchants.tier;
import net.md_5.bungee.api.ChatColor;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.api.placeholder.Placeholder;
import su.nexmedia.engine.api.placeholder.PlaceholderMap;
import su.nexmedia.engine.utils.Colorizer;
@ -16,16 +16,16 @@ public class Tier implements Placeholder {
private final String id;
private final int priority;
private final String name;
private final ChatColor color;
private final String color;
private final Map<ObtainType, Double> chance;
private final PlaceholderMap placeholderMap;
public Tier(@NotNull String id, int priority, @NotNull String name, @NotNull ChatColor color,
public Tier(@NotNull String id, int priority, @NotNull String name, @NotNull String color,
@NotNull Map<ObtainType, Double> chance) {
this.id = id.toLowerCase();
this.priority = priority;
this.name = Colorizer.apply(name);
this.color = color;
this.color = Colorizer.apply(color);
this.chance = chance;
this.placeholderMap = new PlaceholderMap()
.add(Placeholders.TIER_ID, this::getId)
@ -38,6 +38,16 @@ public class Tier implements Placeholder {
;
}
public void write(@NotNull JYML cfg, @NotNull String path) {
cfg.set(path + ".Name", this.getName());
cfg.set(path + ".Color", this.getColor());
cfg.set(path + ".Priority", this.getPriority());
cfg.remove(path + ".Obtain_Chance");
this.getChance().forEach((type, chance) -> {
cfg.set(path + ".Obtain_Chance." + type.name(), chance);
});
}
@Override
@NotNull
public PlaceholderMap getPlaceholders() {
@ -59,7 +69,7 @@ public class Tier implements Placeholder {
}
@NotNull
public ChatColor getColor() {
public String getColor() {
return this.color;
}

View File

@ -1,48 +1,43 @@
package su.nightexpress.excellentenchants.tier;
import net.md_5.bungee.api.ChatColor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.api.manager.AbstractManager;
import su.nexmedia.engine.utils.Colors2;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.enchantment.type.ObtainType;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class TierManager extends AbstractManager<ExcellentEnchants> {
public static final String FILE_NAME = "tiers.yml";
private JYML config;
private final Map<String, Tier> tiers;
private final Map<String, Tier> tierMap;
public TierManager(@NotNull ExcellentEnchants plugin) {
super(plugin);
this.tiers = new ConcurrentHashMap<>();
this.tierMap = new HashMap<>();
}
@Override
protected void onLoad() {
this.config = JYML.loadOrExtract(plugin, FILE_NAME);
JYML config = this.getConfig();
if (config.getSection("").isEmpty()) {
Config.getDefaultTiers().forEach(tier -> tier.write(config, tier.getId()));
}
for (String sId : config.getSection("")) {
String path = sId + ".";
int priority = config.getInt(path + "Priority");
String name = config.getString(path + "Name", sId);
ChatColor color;
try {
color = ChatColor.of(config.getString(path + "Color", ChatColor.WHITE.getName()));
}
catch (IllegalArgumentException e) {
color = ChatColor.WHITE;
}
String color = config.getString(path + "Color", Colors2.WHITE);
Map<ObtainType, Double> chance = new HashMap<>();
for (ObtainType obtainType : ObtainType.values()) {
@ -53,35 +48,41 @@ public class TierManager extends AbstractManager<ExcellentEnchants> {
}
Tier tier = new Tier(sId, priority, name, color, chance);
this.tiers.put(tier.getId(), tier);
this.tierMap.put(tier.getId(), tier);
}
config.saveChanges();
this.plugin.info("Tiers Loaded: " + this.tiers.size());
this.plugin.info("Tiers Loaded: " + this.tierMap.size());
}
@Override
protected void onShutdown() {
this.tiers.clear();
this.tierMap.clear();
}
@NotNull
public JYML getConfig() {
return config;
return JYML.loadOrExtract(plugin, FILE_NAME);
}
@Nullable
public Tier getTierById(@NotNull String id) {
return this.tiers.get(id.toLowerCase());
@NotNull
public Map<String, Tier> getTierMap() {
return tierMap;
}
@NotNull
public Collection<Tier> getTiers() {
return this.tiers.values();
return this.getTierMap().values();
}
@Nullable
public Tier getTierById(@NotNull String id) {
return this.getTierMap().get(id.toLowerCase());
}
@NotNull
public List<String> getTierIds() {
return new ArrayList<>(this.tiers.keySet());
return new ArrayList<>(this.getTierMap().keySet());
}
@Nullable

View File

@ -2,9 +2,8 @@ Command:
List:
Desc: 'Меню дополнительных зачарований.'
Enchant:
Usage: '<зачарование> <уровень>'
Usage: '<зачарование> <уровень> [игрок] [слот]'
Desc: 'Зачарование предмета в руке.'
Done: '&aУспешно зачаровано!'
Book:
Usage: '<игрок> <зачарование> <уровень>'
Desc: 'Выдача книги с указанным зачарованием.'

View File

@ -1,50 +0,0 @@
common:
Name: 'Common'
Color: 'WHITE'
Priority: 1
Obtain_Chance:
ENCHANTING: 80.0
VILLAGER: 80.0
LOOT_GENERATION: 80.0
FISHING: 80.0
MOB_SPAWNING: 80.0
rare:
Name: 'Rare'
Color: 'GREEN'
Priority: 2
Obtain_Chance:
ENCHANTING: 50.0
VILLAGER: 50.0
LOOT_GENERATION: 50.0
FISHING: 50.0
MOB_SPAWNING: 50.0
exotic:
Name: 'Exotic'
Color: 'YELLOW'
Priority: 3
Obtain_Chance:
ENCHANTING: 25.0
VILLAGER: 25.0
LOOT_GENERATION: 25.0
FISHING: 25.0
MOB_SPAWNING: 25.0
legendary:
Name: 'Legendary'
Color: 'GOLD'
Priority: 4
Obtain_Chance:
ENCHANTING: 10.0
VILLAGER: 10.0
LOOT_GENERATION: 10.0
FISHING: 10.0
MOB_SPAWNING: 10.0
cursed:
Name: 'Cursed'
Color: 'RED'
Priority: 0
Obtain_Chance:
ENCHANTING: 0.0
VILLAGER: 5.0
LOOT_GENERATION: 7.0
FISHING: 12.0
MOB_SPAWNING: 0.0