diff --git a/src/main/java/com/alttd/fishingevent/FishingEvent.java b/src/main/java/com/alttd/fishingevent/FishingEvent.java index 0141ffc..66c8b42 100644 --- a/src/main/java/com/alttd/fishingevent/FishingEvent.java +++ b/src/main/java/com/alttd/fishingevent/FishingEvent.java @@ -5,7 +5,7 @@ import com.alttd.fishingevent.config.Config; import com.alttd.fishingevent.config.Fishes; import com.alttd.fishingevent.config.Messages; import com.alttd.fishingevent.config.NPCLocationConfig; -import com.alttd.fishingevent.fish_generator.WaterFishGenerator; +import com.alttd.fishingevent.fish_generator.FishGenerator; import com.alttd.fishingevent.gui.GUIListener; import com.alttd.fishingevent.listeners.CatchFish; import com.alttd.fishingevent.npc.NPCManager; @@ -63,7 +63,7 @@ public final class FishingEvent extends JavaPlugin { } private void registerEvents(@NotNull PluginManager pluginManager) { - 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 CatchFish(this, logger, new FishGenerator(Fishes.FISH.RARITY_WATER_FISH_MAP, new RarityManager(Config.RARITY.RARITY_SET), logger), PointsManagement.getInstance()), this); pluginManager.registerEvents(new GUIListener(), this); } diff --git a/src/main/java/com/alttd/fishingevent/fish_generator/FishGenerator.java b/src/main/java/com/alttd/fishingevent/fish_generator/FishGenerator.java index e4a054b..aba068e 100644 --- a/src/main/java/com/alttd/fishingevent/fish_generator/FishGenerator.java +++ b/src/main/java/com/alttd/fishingevent/fish_generator/FishGenerator.java @@ -1,13 +1,45 @@ package com.alttd.fishingevent.fish_generator; import com.alttd.fishingevent.fish.Fish; -import com.alttd.fishingevent.objects.FishType; +import com.alttd.fishingevent.objects.*; +import com.alttd.fishingevent.util.Logger; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; +import java.util.HashMap; +import java.util.List; import java.util.Optional; -public interface FishGenerator { +public class FishGenerator { - Optional getFish(ItemStack fishingRod, FishType fishType); + private final HashMap> possibleFishMap; + private final RandomListItem randomListItem = new RandomListItem<>(); + private final RarityManager rarityManager; + private final Logger logger; + public FishGenerator(HashMap> possibleFishMap, RarityManager rarityManager, Logger logger) { + this.possibleFishMap = possibleFishMap; + this.rarityManager = rarityManager; + this.logger = logger; + } + + public Optional getFish(ItemStack fishingRod, FishType fishType) { + if (!fishingRod.getType().equals(Material.FISHING_ROD)) + return Optional.empty(); + int luckLevel = fishingRod.getEnchantmentLevel(Enchantment.LUCK); + int maxChanceRange = rarityManager.getMaxChanceRange(fishType); + int rarityValue = CustomRandom.generateNumber(0, maxChanceRange, luckLevel + 1); + Optional optionalRarity = rarityManager.getRarityFromNumber(fishType, rarityValue); + if (optionalRarity.isEmpty()) + return Optional.empty(); + + Rarity rarity = optionalRarity.get(); + List fish = possibleFishMap.get(rarity); + if (fish == null) { + logger.warning("Empty fish map for rarity [%]", rarity.toString()); + return Optional.empty(); + } + return randomListItem.getRandomObject(fish); + } } diff --git a/src/main/java/com/alttd/fishingevent/fish_generator/WaterFishGenerator.java b/src/main/java/com/alttd/fishingevent/fish_generator/WaterFishGenerator.java deleted file mode 100644 index f309c5b..0000000 --- a/src/main/java/com/alttd/fishingevent/fish_generator/WaterFishGenerator.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.alttd.fishingevent.fish_generator; - -import com.alttd.fishingevent.fish.Fish; -import com.alttd.fishingevent.objects.*; -import com.alttd.fishingevent.util.Logger; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.ItemStack; - -import java.util.HashMap; -import java.util.List; -import java.util.Optional; - -public class WaterFishGenerator implements FishGenerator { - - private final HashMap> possibleFishMap; - private final RandomListItem randomListItem = new RandomListItem<>(); - private final RarityManager rarityManager; - private final Logger logger; - - public WaterFishGenerator(HashMap> possibleFishMap, RarityManager rarityManager, Logger logger) { - this.possibleFishMap = possibleFishMap; - this.rarityManager = rarityManager; - this.logger = logger; - } - - @Override - public Optional getFish(ItemStack fishingRod, FishType fishType) { - if (!fishingRod.getType().equals(Material.FISHING_ROD)) - return Optional.empty(); - int luckLevel = fishingRod.getEnchantmentLevel(Enchantment.LUCK); - int maxChanceRange = rarityManager.getMaxChanceRange(fishType); - int rarityValue = CustomRandom.generateNumber(0, maxChanceRange, luckLevel + 1); - Optional optionalRarity = rarityManager.getRarityFromNumber(fishType, rarityValue); - if (optionalRarity.isEmpty()) - return Optional.empty(); - - Rarity rarity = optionalRarity.get(); - List fish = possibleFishMap.get(rarity); - if (fish == null) { - logger.warning("Empty fish map for rarity [%]", rarity.toString()); - return Optional.empty(); - } - return randomListItem.getRandomObject(fish); - } -} diff --git a/src/main/java/com/alttd/fishingevent/listeners/CatchFish.java b/src/main/java/com/alttd/fishingevent/listeners/CatchFish.java index 7e41907..25c9d3a 100644 --- a/src/main/java/com/alttd/fishingevent/listeners/CatchFish.java +++ b/src/main/java/com/alttd/fishingevent/listeners/CatchFish.java @@ -1,13 +1,20 @@ package com.alttd.fishingevent.listeners; +import com.alttd.fishingevent.FishingEvent; import com.alttd.fishingevent.config.Messages; import com.alttd.fishingevent.fish.Fish; import com.alttd.fishingevent.fish_generator.FishGenerator; +import com.alttd.fishingevent.objects.CaughtFishData; import com.alttd.fishingevent.objects.FishType; import com.alttd.fishingevent.points.PointsManagement; import com.alttd.fishingevent.scoreboard.ScoreboardManager; import com.alttd.fishingevent.timer.EventManager; import com.alttd.fishingevent.util.Logger; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.kyori.adventure.title.Title; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -18,8 +25,10 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerFishEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; +import org.bukkit.scheduler.BukkitRunnable; -import java.util.Optional; +import java.util.*; public class CatchFish implements Listener { @@ -27,8 +36,11 @@ public class CatchFish implements Listener { private final FishGenerator waterFishGenerator; private final PointsManagement pointsManagement; private final EventManager eventManager = EventManager.getInstance(); + private final FishingEvent fishingEvent; + private final HashMap activeLavaFishers = new HashMap<>(); - public CatchFish(Logger logger, FishGenerator waterFishGenerator, PointsManagement pointsManagement) { + public CatchFish(FishingEvent fishingEvent, Logger logger, FishGenerator waterFishGenerator, PointsManagement pointsManagement) { + this.fishingEvent = fishingEvent; this.logger = logger; this.waterFishGenerator = waterFishGenerator; this.pointsManagement = pointsManagement; @@ -41,25 +53,67 @@ public class CatchFish implements Listener { event.setCancelled(true); return; } + Player player = event.getPlayer(); + if (fishingRodBroken(player)) { + player.showTitle(Title.title(Component.empty(), MiniMessage.miniMessage().deserialize("Your rod is too damaged to fish"))); + event.setCancelled(true); + return; + } if (event.getState().equals(PlayerFishEvent.State.FISHING)) { //if fishing rod in lava continue else return + new BukkitRunnable() { + @Override + public void run() { + if (event.getHook().getLocation().getBlock().getType().equals(Material.LAVA)) { + player.showTitle(Title.title(Component.empty(), MiniMessage.miniMessage().deserialize("You are now fishing in lava..."))); //TODO move to config + LavaFishing lavaFishing = new LavaFishing(1, 1, player, logger, event.getHook().getLocation()); + activeLavaFishers.put(player.getUniqueId(), lavaFishing); + lavaFishing.runTaskTimerAsynchronously(fishingEvent, 1, 1); + logger.debug("in lava above"); + } else + logger.debug("Not in lava"); // logger.debug("% might have caught a lava fish", event.getPlayer().getName()); // handleLavaFishCaught(event); + } + }.runTaskLater(fishingEvent, 50); + } else if (event.getState().equals(PlayerFishEvent.State.CAUGHT_FISH)) { if (event.getCaught() == null) { - logger.debug("% caught a water fish but it was null", event.getPlayer().getName()); + logger.debug("% caught a water fish but it was null", player.getName()); return; } - logger.debug("% caught a water fish", event.getPlayer().getName()); + logger.debug("% caught a water fish", player.getName()); handleFishCaught(event); } else if (event.getState().equals(PlayerFishEvent.State.IN_GROUND)) { - logger.debug("% reeled in fishing rod that was in the ground", event.getPlayer().getName()); + logger.debug("% reeled in fishing rod that was in the ground", player.getName()); + handleLavaFishCaught(event); } else { logger.debug("Registered different fish state [%]", event.getState().toString()); } } + private boolean fishingRodBroken(Player player) { + Optional optionalFishingROd = getFishingRod(player); + if (optionalFishingROd.isEmpty()) { + logger.warning("No fishing rod found for %", player.getName()); + return true; + } + ItemStack fishingRod = optionalFishingROd.get(); + if (fishingRod.getItemMeta() instanceof Damageable damageable) { + int damage = damageable.getDamage(); + return damage >= 63; + } + return false; + } + + private Optional getFishingRod(Player player) { + return Arrays.stream(player.getInventory().getStorageContents()) + .filter(Objects::nonNull) + .filter(itemStack -> itemStack.getType().equals(Material.FISHING_ROD)) + .findFirst(); + } + private void handleLavaFish(PlayerFishEvent event) { Location location = event.getHook().getLocation(); Block block = location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() + 1, location.getBlockZ()); @@ -69,7 +123,32 @@ public class CatchFish implements Listener { } private void handleLavaFishCaught(PlayerFishEvent event) { - + Player player = event.getPlayer(); + LavaFishing lavaFishing = activeLavaFishers.get(player.getUniqueId()); + if (lavaFishing == null) { + logger.debug("Reeled in but was not lava fishing"); + return; + } + activeLavaFishers.remove(player.getUniqueId()); + lavaFishing.cancel(); + if (!lavaFishing.canCatchFish()) { + logger.debug("Reeled in in lava but too early"); + return; + } + Optional optionalFishData = getFishData(event, player, FishType.LAVA); + if (optionalFishData.isEmpty()) + return; + CaughtFishData caughtFishData = optionalFishData.get(); + player.getInventory().addItem(caughtFishData.fishItem()).values() + .forEach(item -> player.getWorld().dropItem(player.getLocation(), item).setOwner(player.getUniqueId())); + player.updateInventory(); + ScoreboardManager.getInstance().updateScoreboard(player, caughtFishData.length(), caughtFishData.fish()); + player.showTitle(Title.title(Component.empty(), MiniMessage.miniMessage().deserialize("You caught a fish cm", //TODO move to config + TagResolver.resolver( + Placeholder.component("rarity", caughtFishData.fish().getRarity().displayName()), + Placeholder.component("name", caughtFishData.fish().fishName()), + Placeholder.parsed("length", String.valueOf(caughtFishData.length())) + )))); } private void handleFishCaught(PlayerFishEvent event) { @@ -82,13 +161,33 @@ public class CatchFish implements Listener { logger.debug(String.valueOf(item.getItemStack().getType())); Player player = event.getPlayer(); + Optional optionalFishData = getFishData(event, player, FishType.WATER); + if (optionalFishData.isEmpty()) + return; + CaughtFishData caughtFishData = optionalFishData.get(); + item.setItemStack(caughtFishData.fishItem()); + logger.debug(String.valueOf(item.getItemStack().getType())); + item.setOwner(player.getUniqueId()); + logger.debug("[%] caught a [%] with length [%] and rarity [%] for [%] points", + player.getName(), caughtFishData.fish().normalFishName(), String.format("%.2f", caughtFishData.length()), + caughtFishData.fish().getRarity().displayNameString(), String.valueOf(caughtFishData.pointsValue())); + ScoreboardManager.getInstance().updateScoreboard(player, caughtFishData.length(), caughtFishData.fish()); + player.showTitle(Title.title(Component.empty(), MiniMessage.miniMessage().deserialize("You caught a fish cm", //TODO move to config + TagResolver.resolver( + Placeholder.component("rarity", caughtFishData.fish().getRarity().displayName()), + Placeholder.component("name", caughtFishData.fish().fishName()), + Placeholder.parsed("length", String.valueOf(caughtFishData.length())) + )))); + } + + private Optional getFishData(PlayerFishEvent event, Player player, FishType fishType) { ItemStack activeItem = player.getInventory().getItemInMainHand(); if (!activeItem.getType().equals(Material.FISHING_ROD)) activeItem = player.getInventory().getItemInOffHand(); - Optional optionalFish = waterFishGenerator.getFish(activeItem, FishType.WATER); + Optional optionalFish = waterFishGenerator.getFish(activeItem, fishType); if (optionalFish.isEmpty()) { logger.warning("Unable to get water fish for %", event.getPlayer().getName()); - return; + return Optional.empty(); } Fish fish = optionalFish.get(); @@ -98,14 +197,8 @@ public class CatchFish implements Listener { if (fishItem.isEmpty()) { player.sendMiniMessage(Messages.OTHER_ERRORS.UNABLE_TO_CREATE_FISH, null); event.setCancelled(true); - return; + return Optional.empty(); } - 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), - fish.getRarity().displayNameString(), String.valueOf(pointsValue)); - ScoreboardManager.getInstance().updateScoreboard(player, length, fish); + return Optional.of(new CaughtFishData(fish, fishItem.get(), length, pointsValue)); } } diff --git a/src/main/java/com/alttd/fishingevent/listeners/LavaFishing.java b/src/main/java/com/alttd/fishingevent/listeners/LavaFishing.java new file mode 100644 index 0000000..c2d8d62 --- /dev/null +++ b/src/main/java/com/alttd/fishingevent/listeners/LavaFishing.java @@ -0,0 +1,137 @@ +package com.alttd.fishingevent.listeners; + +import com.alttd.fishingevent.util.Logger; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.meta.Damageable; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.Random; + +public class LavaFishing extends BukkitRunnable { + + private int timeUntilHooked; + private int timeUntilLured; + private final int lure; + private final int fireProtection; + private final int minWaitTime = 100; + private final int maxWaitTime = 600; + private boolean isBiting; + private int timeUntilHookDamage; + private boolean shouldDamageHook; + private final Random random = new Random(); + private final Player player; + private final Logger logger; + private final Location hookLocation; + + public LavaFishing(int lure, int fireProtection, Player player, Logger logger, Location hookLocation) { + this.lure = lure; + this.fireProtection = Math.min(5, fireProtection); + this.player = player; + this.logger = logger; + this.hookLocation = hookLocation; + this.shouldDamageHook = fireProtection >= 5; + resetTimeUntilHookDamage(); + resetTimeUntilLured(); + } + + private void resetTimeUntilLured() { + isBiting = false; + this.timeUntilLured = random.nextInt(minWaitTime, maxWaitTime); + this.timeUntilLured = Math.max(timeUntilLured - this.lure * 100, minWaitTime); + } + + private void damageHook() { + if (!shouldDamageHook) + return; + if (timeUntilHookDamage > 0) { + timeUntilHookDamage--; + return; + } + resetTimeUntilHookDamage(); + PlayerInventory inventory = player.getInventory(); + int fishingRodSlot = findFishingRodSlot(inventory); + if (fishingRodSlot < 0) { + logger.warning("Unable to find fishing rod slot"); + return; + } + ItemStack item = inventory.getItem(fishingRodSlot); + if (item == null) { + logger.warning("Unable to find fishing rod"); + return; + } + if (item.getItemMeta() instanceof Damageable damageable) { + int damage = damageable.getDamage(); + damageable.setDamage(Math.min(++damage, 63)); + item.setItemMeta(damageable); + } else { + logger.warning("This item can't be damaged"); + } + } + + private int findFishingRodSlot(Inventory inventory) { + ItemStack[] contents = inventory.getContents(); + + for (int i = 0; i < contents.length; i++) { + ItemStack item = contents[i]; + + if (item != null && item.getType().equals(Material.FISHING_ROD)) { + return i; + } + } + return -1; + } + + private void resetTimeUntilHookDamage() { + timeUntilHookDamage = random.nextInt(fireProtection, 5 + fireProtection); + } + + private void spawnLavaParticles() { + // Customize the particle effect + Particle particle = Particle.LAVA; + int count = 10; // Number of particles to spawn + double offsetX = 0.2; // X-axis offset + double offsetY = 1.0; // Y-axis offset (positive value for upward direction) + double offsetZ = 0.2; // Z-axis offset + double extra = 0.1; // Extra random offset + + // Spawn the lava particles + hookLocation.getWorld().spawnParticle(particle, hookLocation, count, offsetX, offsetY, offsetZ, extra); + } + + @Override + public void run() { + damageHook(); + if (!isBiting && timeUntilLured > 0) { + timeUntilLured--; + if (timeUntilLured % 5 == 0) + logger.debug("Time until lured: %", String.valueOf(timeUntilLured)); + return; + } + if (!isBiting) { + isBiting = true; + this.timeUntilHooked = random.nextInt(20, 60); + spawnLavaParticles(); + logger.debug("Fish on hook in lava"); + return; + } + if (this.timeUntilHooked > 0) { + this.timeUntilHooked--; + if (timeUntilHooked % 5 == 0) + logger.debug("Time until hooked: %", String.valueOf(timeUntilLured)); + if (this.timeUntilHooked % 5 == 0) + spawnLavaParticles(); + return; + } + resetTimeUntilLured(); + } + + public boolean canCatchFish() { + return isBiting; + } +} diff --git a/src/main/java/com/alttd/fishingevent/objects/CaughtFishData.java b/src/main/java/com/alttd/fishingevent/objects/CaughtFishData.java new file mode 100644 index 0000000..a18d148 --- /dev/null +++ b/src/main/java/com/alttd/fishingevent/objects/CaughtFishData.java @@ -0,0 +1,7 @@ +package com.alttd.fishingevent.objects; + +import com.alttd.fishingevent.fish.Fish; +import org.bukkit.inventory.ItemStack; + +public record CaughtFishData(Fish fish, ItemStack fishItem, double length, int pointsValue) { +}