Reworked fish rarities to allow fishes to be caught in both water and lava and make the rarities easier to configure

This commit is contained in:
Teriuihi 2023-09-25 02:00:30 +02:00
parent 9a8a38f4a4
commit fb511d27e2
14 changed files with 169 additions and 134 deletions

View File

@ -9,6 +9,7 @@ import com.alttd.fishingevent.fish_generator.WaterFishGenerator;
import com.alttd.fishingevent.gui.GUIListener;
import com.alttd.fishingevent.listeners.CatchFish;
import com.alttd.fishingevent.npc.NPCManager;
import com.alttd.fishingevent.objects.RarityManager;
import com.alttd.fishingevent.points.LoadTask;
import com.alttd.fishingevent.points.PointsManagement;
import com.alttd.fishingevent.points.SaveTask;
@ -34,6 +35,7 @@ public final class FishingEvent extends JavaPlugin {
Bukkit.getPluginManager().disablePlugin(this);
return;
}
reloadFishConfigs();
registerEvents(getServer().getPluginManager());
//add a way to stop and start the fishing event and a way to stop all fishing (so 3 modes normal, active, disabled)
if (new LoadTask(PointsManagement.getInstance(), this, logger).loadOldPointsData())
@ -42,7 +44,6 @@ public final class FishingEvent extends JavaPlugin {
Bukkit.getScheduler().runTaskTimerAsynchronously(this, saveTask,
TimeUnit.MINUTES.toSeconds(5) * 20,
TimeUnit.MINUTES.toSeconds(5) * 20);
reloadFishConfigs();
registerCommands();
NPCManager.spawnNPCs(this, logger);
}
@ -61,7 +62,7 @@ public final class FishingEvent extends JavaPlugin {
}
private void registerEvents(@NotNull PluginManager pluginManager) {
pluginManager.registerEvents(new CatchFish(logger, new WaterFishGenerator(Fishes.WATER_FISH.RARITY_FISH_MAP, logger), PointsManagement.getInstance()), this);
pluginManager.registerEvents(new CatchFish(logger, new WaterFishGenerator(Fishes.FISH.RARITY_WATER_FISH_MAP, new RarityManager(Config.RARITY.RARITY_SET), logger), PointsManagement.getInstance()), this);
pluginManager.registerEvents(new GUIListener(), this);
}

View File

@ -8,10 +8,7 @@ import com.alttd.fishingevent.npc.types.PrizeNPC;
import com.alttd.fishingevent.npc.types.SellNPC;
import com.alttd.fishingevent.npc.types.TutorialNPC;
import com.alttd.fishingevent.npc.types.UpgradeNPC;
import com.alttd.fishingevent.objects.EnchantmentData;
import com.alttd.fishingevent.objects.EnchantmentTrack;
import com.alttd.fishingevent.objects.Prize;
import com.alttd.fishingevent.objects.Rarity;
import com.alttd.fishingevent.objects.*;
import com.alttd.fishingevent.util.Logger;
import com.alttd.fishingevent.util.NPCCreateData;
import com.alttd.fishingevent.util.Skin;
@ -59,16 +56,43 @@ public class Config extends AbstractConfig {
}
}
public static class RARITY_MULTIPLIERS {
private static final String prefix = "rarity-multipliers.";
public static HashMap<Rarity, Float> MULTIPLIER_MAP = new HashMap<>();
public static class RARITY {
private static final String prefix = "rarity.";
public static Set<Rarity> RARITY_SET = new HashSet<>();
@SuppressWarnings("unused")
private static void load() {
MULTIPLIER_MAP.clear();
for (Rarity rarity : Rarity.values()) {
MULTIPLIER_MAP.put(rarity, (float) config.getDouble(prefix, rarity.configName(), 1));
RARITY_SET.clear();
ConfigurationSection configurationSection = config.getConfigurationSection("rarity");
if (configurationSection == null) {
config.logger.severe("No rarities found");
return;
}
for (String key : configurationSection.getKeys(false)) {
String rarityPrefix = prefix + key + ".";
Rarity rarity = new Rarity(
config.getString(rarityPrefix, "internal-name", "rarity-example"),
config.getString(rarityPrefix, "display-name", "Rarity Example"),
getFishTypes(rarityPrefix),
config.getInt(rarityPrefix, "chance", 1),
config.getDouble(rarityPrefix, "multiplier", 1.0),
config.getInt(rarityPrefix, "rarity-value", 1)
);
RARITY_SET.add(rarity);
}
}
private static Set<FishType> getFishTypes(String rarityPrefix) {
Set<FishType> fishTypes = new HashSet<>();
List<String> typeList = config.getStringList(rarityPrefix, "fish-type", Arrays.stream(FishType.values()).map(Enum::toString).collect(Collectors.toList()));
for (String fishType : typeList) {
try {
fishTypes.add(FishType.valueOf(fishType));
} catch (IllegalArgumentException ignored) {
config.logger.warning("Invalid fish type: %", fishType);
}
}
return fishTypes;
}
}
@ -204,6 +228,7 @@ public class Config extends AbstractConfig {
bookMeta.lore(config.getStringList(npcPrefix, "book.item-lore", List.of("<green>book</green>", "<red>lore</red>")).stream()
.map(line -> MiniMessage.miniMessage().deserialize(line))
.collect(Collectors.toList()));
bookMeta.title(bookMeta.displayName());
bookMeta.author(MiniMessage.miniMessage().deserialize(config.getString(npcPrefix, "book.author-name", "<gold>Server</gold>")))
.pages(config.getStringList(npcPrefix, "book.pages", List.of("<green>example</green>", "<red>text</red>")).stream()
.map(line -> MiniMessage.miniMessage().deserialize(line))

View File

@ -2,18 +2,15 @@ package com.alttd.fishingevent.config;
import com.alttd.fishingevent.FishingEvent;
import com.alttd.fishingevent.fish.Fish;
import com.alttd.fishingevent.fish.LavaFish;
import com.alttd.fishingevent.fish.WaterFish;
import com.alttd.fishingevent.objects.FishType;
import com.alttd.fishingevent.objects.Rarity;
import com.alttd.fishingevent.util.FishConfigHelper;
import com.alttd.fishingevent.util.Logger;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.*;
public class Fishes extends AbstractConfig {
@ -49,64 +46,17 @@ public class Fishes extends AbstractConfig {
}
}
public static class LAVA_FISH {
public static class FISH {
public static List<Fish> FISH = new ArrayList<>();
public static HashMap<Rarity, List<Fish>> RARITY_FISH_MAP = new HashMap<>();
public static List<Fish> WATER_FISH = new ArrayList<>();
public static List<Fish> LAVA_FISH = new ArrayList<>();
public static HashMap<Rarity, List<Fish>> RARITY_WATER_FISH_MAP = new HashMap<>();
public static HashMap<Rarity, List<Fish>> RARITY_LAVA_FISH_MAP = new HashMap<>();
@SuppressWarnings("unused")
private static void load() {
FISH.clear();
ConfigurationSection configurationSection = config.getConfigurationSection("lava-fish");
if (configurationSection == null) {
return;
}
for (String key : configurationSection.getKeys(false)) {
ConfigurationSection fishSection = configurationSection.getConfigurationSection(key);
if (fishSection == null) {
config.logger.warning("Invalid lava fish section: " + configurationSection.getCurrentPath() + "." + key);
continue;
}
loadLavaFish(fishSection);
}
}
private static void loadLavaFish(ConfigurationSection fishSection) {
Optional<Rarity> rarity = FishConfigHelper.getRarity(config.logger, fishSection);
if (rarity.isEmpty())
return;
Optional<ItemStack> optionalItemStack = FishConfigHelper.loadFishItem(config.logger, fishSection);
if (optionalItemStack.isEmpty()) {
config.logger.warning("Invalid lava fish item for " + fishSection.getCurrentPath());
return;
}
FISH.add(new LavaFish(
config.fishingEvent,
config.logger,
(float) fishSection.getDouble("min-length", 0),
(float) fishSection.getDouble("max-length", 0),
fishSection.getString("fish-name", "default name"),
rarity.get(),
optionalItemStack.get(),
null) //TODO implement particles or make them hardcoded
);
for (Fish fish : FISH) {
RARITY_FISH_MAP.computeIfAbsent(fish.getRarity(), list -> new ArrayList<>()).add(fish);
}
}
}
public static class WATER_FISH {
public static List<Fish> FISH = new ArrayList<>();
public static HashMap<Rarity, List<Fish>> RARITY_FISH_MAP = new HashMap<>();
@SuppressWarnings("unused")
private static void load() {
FISH.clear();
RARITY_FISH_MAP.clear();
WATER_FISH.clear();
RARITY_WATER_FISH_MAP.clear();
ConfigurationSection configurationSection = config.getConfigurationSection("water-fish");
if (configurationSection == null) {
return;
@ -117,15 +67,20 @@ public class Fishes extends AbstractConfig {
config.logger.warning("Invalid water fish section: " + configurationSection.getCurrentPath() + "." + key);
continue;
}
loadWaterFish(fishSection);
loadFish(fishSection);
}
for (Fish fish : FISH) {
config.logger.debug("Adding fish [%] with rarity [%]", fish.normalFishName(), fish.getRarity().toString());
RARITY_FISH_MAP.computeIfAbsent(fish.getRarity(), list -> new ArrayList<>()).add(fish);
for (Fish fish : WATER_FISH) {
config.logger.debug("Adding water fish [%] with rarity [%]", fish.normalFishName(), fish.getRarity().toString());
RARITY_WATER_FISH_MAP.computeIfAbsent(fish.getRarity(), list -> new ArrayList<>()).add(fish);
}
for (Fish fish : LAVA_FISH) {
config.logger.debug("Adding lava fish [%] with rarity [%]", fish.normalFishName(), fish.getRarity().toString());
RARITY_LAVA_FISH_MAP.computeIfAbsent(fish.getRarity(), list -> new ArrayList<>()).add(fish);
}
}
private static void loadWaterFish(ConfigurationSection fishSection) {
private static void loadFish(ConfigurationSection fishSection) {
Optional<Rarity> rarity = FishConfigHelper.getRarity(config.logger, fishSection);
if (rarity.isEmpty())
return;
@ -136,15 +91,39 @@ public class Fishes extends AbstractConfig {
return;
}
FISH.add(new WaterFish(
config.fishingEvent,
config.logger,
(float) fishSection.getDouble("min-length", 0),
(float) fishSection.getDouble("max-length", 0),
fishSection.getString("fish-name", "default name"),
rarity.get(),
optionalItemStack.get())
);
Set<FishType> fishTypes = getFishTypes(fishSection);
for (FishType fishType : fishTypes) {
switch (fishType) {
case WATER -> {
WATER_FISH.add(new WaterFish(
config.fishingEvent,
config.logger,
(float) fishSection.getDouble("min-length", 0),
(float) fishSection.getDouble("max-length", 0),
fishSection.getString("fish-name", "default name"),
rarity.get(),
optionalItemStack.get())
);
}
case LAVA -> {
//TODO make lava fish and add it
}
}
}
}
private static Set<FishType> getFishTypes(ConfigurationSection fishSection) {
Set<FishType> fishTypes = new HashSet<>();
List<String> typeList = fishSection.getStringList("fish-type");
for (String fishType : typeList) {
try {
fishTypes.add(FishType.valueOf(fishType));
} catch (IllegalArgumentException ignored) {
config.logger.warning("Invalid fish type: %", fishType);
}
}
return fishTypes;
}
}
}

View File

@ -1,7 +1,6 @@
package com.alttd.fishingevent.fish;
import com.alttd.fishingevent.FishingEvent;
import com.alttd.fishingevent.config.Config;
import com.alttd.fishingevent.config.Fishes;
import com.alttd.fishingevent.objects.Rarity;
import com.alttd.fishingevent.util.Logger;
@ -14,7 +13,6 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Optional;
@ -84,13 +82,4 @@ public abstract class Fish {
return Optional.of(fishItem);
}
/**
* Gives back the amount of points for this type of fish with the specified length
* @param length The length to calculate points for
* @return points based on the length and rarity of this fish
*/
public int getPoints(float length) {
return Math.round(Config.RARITY_MULTIPLIERS.MULTIPLIER_MAP.get(getRarity()) * length);
}
}

View File

@ -1,12 +1,13 @@
package com.alttd.fishingevent.fish_generator;
import com.alttd.fishingevent.fish.Fish;
import com.alttd.fishingevent.objects.FishType;
import org.bukkit.inventory.ItemStack;
import java.util.Optional;
public interface FishGenerator {
Optional<Fish> getFish(ItemStack fishingRod);
Optional<Fish> getFish(ItemStack fishingRod, FishType fishType);
}

View File

@ -1,9 +1,7 @@
package com.alttd.fishingevent.fish_generator;
import com.alttd.fishingevent.fish.Fish;
import com.alttd.fishingevent.objects.CustomRandom;
import com.alttd.fishingevent.objects.RandomListItem;
import com.alttd.fishingevent.objects.Rarity;
import com.alttd.fishingevent.objects.*;
import com.alttd.fishingevent.util.Logger;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
@ -17,20 +15,27 @@ public class WaterFishGenerator implements FishGenerator {
private final HashMap<Rarity, List<Fish>> possibleFishMap;
private final RandomListItem<Fish> randomListItem = new RandomListItem<>();
private final RarityManager rarityManager;
private final Logger logger;
public WaterFishGenerator(HashMap<Rarity, List<Fish>> possibleFishMap, Logger logger) {
public WaterFishGenerator(HashMap<Rarity, List<Fish>> possibleFishMap, RarityManager rarityManager, Logger logger) {
this.possibleFishMap = possibleFishMap;
this.rarityManager = rarityManager;
this.logger = logger;
}
@Override
public Optional<Fish> getFish(ItemStack fishingRod) {
public Optional<Fish> getFish(ItemStack fishingRod, FishType fishType) {
if (!fishingRod.getType().equals(Material.FISHING_ROD))
return Optional.empty();
int luckLevel = fishingRod.getEnchantmentLevel(Enchantment.LUCK);
int rarityValue = CustomRandom.generateNumber(0, Rarity.values().length - 1, luckLevel + 1);
Rarity rarity = Rarity.values()[rarityValue];
int maxChanceRange = rarityManager.getMaxChanceRange(fishType);
int rarityValue = CustomRandom.generateNumber(0, maxChanceRange, luckLevel + 1);
Optional<Rarity> optionalRarity = rarityManager.getRarityFromNumber(fishType, rarityValue);
if (optionalRarity.isEmpty())
return Optional.empty();
Rarity rarity = optionalRarity.get();
List<Fish> fish = possibleFishMap.get(rarity);
if (fish == null) {
logger.warning("Empty fish map for rarity [%]", rarity.toString());

View File

@ -86,8 +86,7 @@ public class UpgradeWindow extends GUI {
}
private Optional<ItemStack> getEnchantmentItem(EnchantmentTrack enchantmentTrack, int trackLevel) {
if (enchantmentTrack.getMaxLevel() == trackLevel) { //TODO fix this won't work if there are 2+ enchantments in a track and the second has more levels
logger.debug("Player got maxed out track");
if (enchantmentTrack.getMaxLevel() == trackLevel) {
return Optional.empty();
}
ItemStack itemStack = new ItemStack(Material.ENCHANTED_BOOK, 1);

View File

@ -3,6 +3,7 @@ package com.alttd.fishingevent.listeners;
import com.alttd.fishingevent.config.Messages;
import com.alttd.fishingevent.fish.Fish;
import com.alttd.fishingevent.fish_generator.FishGenerator;
import com.alttd.fishingevent.objects.FishType;
import com.alttd.fishingevent.points.PointsManagement;
import com.alttd.fishingevent.util.Logger;
import org.bukkit.Location;
@ -66,16 +67,18 @@ public class CatchFish implements Listener {
private void handleFishCaught(PlayerFishEvent event) {
Entity caught = event.getCaught();
logger.debug(caught == null ? "null" : caught.toString());
if (!(caught instanceof Item item)) {
logger.debug("% did not catch an item", event.getPlayer().getName());
return;
}
logger.debug(String.valueOf(item.getItemStack().getType()));
Player player = event.getPlayer();
ItemStack activeItem = player.getInventory().getItemInMainHand();
if (!activeItem.getType().equals(Material.FISHING_ROD))
activeItem = player.getInventory().getItemInOffHand();
Optional<Fish> optionalFish = waterFishGenerator.getFish(activeItem);
Optional<Fish> optionalFish = waterFishGenerator.getFish(activeItem, FishType.WATER);
if (optionalFish.isEmpty()) {
logger.warning("Unable to get water fish for %", event.getPlayer().getName());
return;
@ -91,6 +94,7 @@ public class CatchFish implements Listener {
return;
}
item.setItemStack(fishItem.get());
logger.debug(String.valueOf(item.getItemStack().getType()));
item.setOwner(player.getUniqueId());
logger.debug("[%] caught a [%] with length [%] and rarity [%] for [%] points",
player.getName(), fish.normalFishName(), String.format("%.2f", length),

View File

@ -8,9 +8,10 @@ public class CustomRandom {
public static int generateNumber(int min, int max, int attempts) {
int highestValue = 0;
for (int i = 0; i < attempts; i++) {
max = Math.max(max, random.nextInt(min, max + 1));
int tmp = Math.min(max, random.nextInt(min, max + 1));
if (tmp > highestValue)
highestValue = tmp;
}
return highestValue;
}

View File

@ -0,0 +1,6 @@
package com.alttd.fishingevent.objects;
public enum FishType {
WATER,
LAVA;
}

View File

@ -1,23 +1,7 @@
package com.alttd.fishingevent.objects;
public enum Rarity {
NORMAL("Normal"),
LEGENDARY("Legendary")
;
import java.util.Set;
private final String displayName;
private final String configName;
public record Rarity(String internalName, String displayName, Set<FishType> fishTypes, int chance, double multiplier, int rarityValue) {
public String displayName() {
return displayName;
}
public String configName() {
return configName;
}
Rarity(String displayName) {
configName = this.name().toLowerCase().replaceAll(" ", "-");
this.displayName = displayName;
}
}

View File

@ -0,0 +1,42 @@
package com.alttd.fishingevent.objects;
import java.util.*;
public class RarityManager {
private final HashMap<FishType, SortedSet<Rarity>> rarityMap;
private final HashMap<FishType, Integer> rarityChanceMap;
public RarityManager(Set<Rarity> rarities) {
rarityMap = new HashMap<>();
rarities.forEach(rarity ->
rarity.fishTypes().forEach(fishType ->
rarityMap.computeIfAbsent(fishType, k -> new TreeSet<>(Comparator.comparing(Rarity::rarityValue))).add(rarity)
)
);
rarityChanceMap = new HashMap<>();
rarities.forEach(rarity ->
rarity.fishTypes().forEach(fishType ->
rarityChanceMap.compute(fishType, (k, v) -> v == null ? rarity.chance() : v + rarity.chance())
)
);
}
public Optional<Rarity> getRarityFromNumber(FishType fishType, int random) {
SortedSet<Rarity> rarities = rarityMap.get(fishType);
if (rarities == null)
return Optional.empty();
for (Rarity rarity : rarities) {
random -= rarity.chance();
if (random <= 0)
return Optional.of(rarity);
}
return Optional.empty();
}
public int getMaxChanceRange(FishType fishType) {
return rarityChanceMap.getOrDefault(fishType, 0);
}
}

View File

@ -1,6 +1,5 @@
package com.alttd.fishingevent.points;
import com.alttd.fishingevent.config.Config;
import com.alttd.fishingevent.objects.Rarity;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
@ -24,7 +23,7 @@ public class PointsManagement {
}
public int calculatePoints(Rarity rarity, float length) {
return (int) (Config.RARITY_MULTIPLIERS.MULTIPLIER_MAP.get(rarity) * length);
return (int) (rarity.multiplier() * length);
}
public synchronized int addPoints(UUID uuid, int points) {

View File

@ -1,5 +1,6 @@
package com.alttd.fishingevent.util;
import com.alttd.fishingevent.config.Config;
import com.alttd.fishingevent.objects.Rarity;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@ -16,14 +17,13 @@ import java.util.UUID;
public class FishConfigHelper {
public static Optional<Rarity> getRarity(Logger logger, ConfigurationSection fishSection) {
Rarity rarity;
try {
rarity = Rarity.valueOf(fishSection.getString("rarity", "REPLACE").toUpperCase());
} catch (IllegalArgumentException e) {
String fishRarityString = fishSection.getString("rarity", "rarity-key").toLowerCase();
Optional<Rarity> rarity = Config.RARITY.RARITY_SET.stream().filter(val -> val.internalName().equals(fishRarityString)).findFirst();
if (rarity.isEmpty()) {
logger.warning("Invalid rarity for " + fishSection.getCurrentPath());
return Optional.empty();
}
return Optional.of(rarity);
return rarity;
}
@SuppressWarnings("deprecation")