9
0
mirror of https://github.com/Xiao-MoMi/Custom-Fishing.git synced 2025-12-28 11:29:15 +00:00
Files
Custom-Fishing/src/main/java/net/momirealms/customfishing/manager/FishingManager.java
XiaoMoMi 6be0be1e14 1.3.2.2
2023-07-16 00:46:27 +08:00

1107 lines
50 KiB
Java

/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.manager;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTItem;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.momirealms.customfishing.CustomFishing;
import net.momirealms.customfishing.api.CustomFishingAPI;
import net.momirealms.customfishing.api.event.*;
import net.momirealms.customfishing.fishing.Effect;
import net.momirealms.customfishing.fishing.*;
import net.momirealms.customfishing.fishing.action.Action;
import net.momirealms.customfishing.fishing.action.VanillaXPImpl;
import net.momirealms.customfishing.fishing.bar.FishingBar;
import net.momirealms.customfishing.fishing.bar.ModeOneBar;
import net.momirealms.customfishing.fishing.bar.ModeThreeBar;
import net.momirealms.customfishing.fishing.bar.ModeTwoBar;
import net.momirealms.customfishing.fishing.competition.Competition;
import net.momirealms.customfishing.fishing.competition.CompetitionGoal;
import net.momirealms.customfishing.fishing.loot.DroppedItem;
import net.momirealms.customfishing.fishing.loot.LootImpl;
import net.momirealms.customfishing.fishing.loot.Mob;
import net.momirealms.customfishing.fishing.mode.FishingGame;
import net.momirealms.customfishing.fishing.mode.ModeOneGame;
import net.momirealms.customfishing.fishing.mode.ModeThreeGame;
import net.momirealms.customfishing.fishing.mode.ModeTwoGame;
import net.momirealms.customfishing.fishing.requirements.RequirementInterface;
import net.momirealms.customfishing.fishing.totem.ActivatedTotem;
import net.momirealms.customfishing.fishing.totem.TotemConfig;
import net.momirealms.customfishing.integration.MobInterface;
import net.momirealms.customfishing.integration.item.McMMOTreasure;
import net.momirealms.customfishing.listener.*;
import net.momirealms.customfishing.object.Function;
import net.momirealms.customfishing.object.Pair;
import net.momirealms.customfishing.object.SimpleLocation;
import net.momirealms.customfishing.util.AdventureUtils;
import net.momirealms.customfishing.util.FakeItemUtils;
import net.momirealms.customfishing.util.ItemStackUtils;
import net.momirealms.customfishing.util.LocationUtils;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.*;
import org.bukkit.event.HandlerList;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class FishingManager extends Function {
private final CustomFishing plugin;
private final PlayerFishListener playerFishListener;
private final InteractListener interactListener;
private final ConsumeItemListener consumeItemListener;
private PickUpListener pickUpListener;
private JobsRebornXPListener jobsRebornXPListener;
private final JoinQuitListener joinQuitListener;
private final BreakBlockListener breakBlockListener;
private final HashMap<UUID, Long> coolDown;
private final HashMap<UUID, FishHook> hooks;
private final HashMap<UUID, LootImpl> nextLoot;
private final HashMap<UUID, Effect> nextEffect;
private final HashMap<UUID, VanillaLoot> vanillaLoot;
private final ConcurrentHashMap<UUID, FishingGame> fishingPlayerMap;
private final ConcurrentHashMap<SimpleLocation, ActivatedTotem> activeTotemMap;
private final ConcurrentHashMap<SimpleLocation, SimpleLocation> breakDetectionMap;
private final ConcurrentHashMap<UUID, BobberCheckTask> hookCheckTaskMap;
public FishingManager(CustomFishing plugin) {
this.plugin = plugin;
this.playerFishListener = new PlayerFishListener(this);
this.interactListener = new InteractListener(this);
this.breakBlockListener = new BreakBlockListener(this);
this.consumeItemListener = new ConsumeItemListener(this);
this.joinQuitListener = new JoinQuitListener(this);
this.coolDown = new HashMap<>();
this.hooks = new HashMap<>();
this.nextLoot = new HashMap<>();
this.nextEffect = new HashMap<>();
this.vanillaLoot = new HashMap<>();
this.fishingPlayerMap = new ConcurrentHashMap<>();
this.activeTotemMap = new ConcurrentHashMap<>();
this.hookCheckTaskMap = new ConcurrentHashMap<>();
this.breakDetectionMap = new ConcurrentHashMap<>();
load();
}
@Override
public void load() {
Bukkit.getPluginManager().registerEvents(this.playerFishListener, plugin);
Bukkit.getPluginManager().registerEvents(this.interactListener, plugin);
Bukkit.getPluginManager().registerEvents(this.breakBlockListener, plugin);
Bukkit.getPluginManager().registerEvents(this.consumeItemListener, plugin);
Bukkit.getPluginManager().registerEvents(this.joinQuitListener, plugin);
if (ConfigManager.preventPickUp) {
this.pickUpListener = new PickUpListener();
Bukkit.getPluginManager().registerEvents(this.pickUpListener, plugin);
}
if (ConfigManager.disableJobsXp) {
this.jobsRebornXPListener = new JobsRebornXPListener();
Bukkit.getPluginManager().registerEvents(this.jobsRebornXPListener, plugin);
}
}
@Override
public void unload() {
HandlerList.unregisterAll(this.playerFishListener);
HandlerList.unregisterAll(this.interactListener);
HandlerList.unregisterAll(this.breakBlockListener);
HandlerList.unregisterAll(this.consumeItemListener);
HandlerList.unregisterAll(this.joinQuitListener);
if (this.pickUpListener != null) HandlerList.unregisterAll(this.pickUpListener);
if (this.jobsRebornXPListener != null) HandlerList.unregisterAll(this.jobsRebornXPListener);
for (BobberCheckTask bobberCheckTask : hookCheckTaskMap.values()) {
bobberCheckTask.stop();
}
}
public void onFishing(PlayerFishEvent event) {
final Player player = event.getPlayer();
final FishHook fishHook = event.getHook();
hooks.put(player.getUniqueId(), fishHook);
boolean noBait = true;
boolean rodOnMainHand = false;
ItemStack baitAnimationItem = null;
ItemStack baitRealItem = null;
Effect initialEffect = new Effect();
initialEffect.setWeightMD(new HashMap<>(8));
initialEffect.setWeightAS(new HashMap<>(8));
final PlayerInventory inventory = player.getInventory();
final ItemStack mainHandItem = inventory.getItemInMainHand();
final ItemStack offHandItem = inventory.getItemInOffHand();
if (mainHandItem.getType() == Material.FISHING_ROD) {
rodOnMainHand = true;
}
String rod_id = Optional.ofNullable(plugin.getIntegrationManager().getItemID(rodOnMainHand ? mainHandItem : offHandItem)).orElse("vanilla");
final FishingCondition fishingCondition = new FishingCondition(player.getLocation(), player, rod_id, null);
String bait_id = plugin.getIntegrationManager().getItemID(rodOnMainHand ? offHandItem: mainHandItem);
if (bait_id != null) {
Effect baitEffect = plugin.getEffectManager().getBaitEffect(bait_id);
if (baitEffect != null && initialEffect.canAddEffect(baitEffect, fishingCondition)) {
initialEffect.addEffect(baitEffect);
baitAnimationItem = rodOnMainHand ? offHandItem.clone() : mainHandItem.clone();
baitRealItem = rodOnMainHand ? offHandItem : mainHandItem;
noBait = false;
}
}
for (ActivatedTotem activatedTotem : activeTotemMap.values()) {
if (activatedTotem.getNearbyPlayerSet().contains(player)) {
initialEffect.addEffect(activatedTotem.getTotem().getEffect());
break;
}
}
if (ConfigManager.enableFishingBag) {
Inventory fishingBag = plugin.getBagDataManager().getPlayerBagData(player.getUniqueId());
HashSet<String> uniqueUtils = new HashSet<>(4);
if (fishingBag != null) {
for (int i = 0; i < fishingBag.getSize(); i++) {
ItemStack itemStack = fishingBag.getItem(i);
String bagItemID = plugin.getIntegrationManager().getItemID(itemStack);
if (bagItemID == null) continue;
if (noBait) {
Effect effect = plugin.getEffectManager().getBaitEffect(bagItemID);
if (effect != null) {
if (initialEffect.canAddEffect(effect, fishingCondition)) {
initialEffect.addEffect(effect);
noBait = false;
bait_id = bagItemID;
baitAnimationItem = itemStack.clone();
baitRealItem = itemStack;
}
continue;
}
}
Effect utilEffect = plugin.getEffectManager().getUtilEffect(bagItemID);
if (utilEffect != null && !uniqueUtils.contains(bagItemID) && initialEffect.canAddEffect(utilEffect, fishingCondition)) {
initialEffect.addEffect(utilEffect);
uniqueUtils.add(bagItemID);
}
}
}
}
Effect rod_effect = plugin.getEffectManager().getRodEffect(rod_id);
if (rod_effect != null) {
if (initialEffect.canAddEffect(rod_effect, new FishingCondition(player.getLocation(), player, rod_id, bait_id))) {
initialEffect.addEffect(rod_effect);
} else {
event.setCancelled(true);
return;
}
initialEffect.setSpecialRodID(rod_id);
}
this.addEnchantEffect(initialEffect, rodOnMainHand ? mainHandItem : offHandItem, fishingCondition);
RodCastEvent rodCastEvent = new RodCastEvent(player, initialEffect);
Bukkit.getPluginManager().callEvent(rodCastEvent);
if (rodCastEvent.isCancelled()) {
event.setCancelled(true);
return;
}
if (baitRealItem != null) baitRealItem.setAmount(baitRealItem.getAmount() - 1);
int lureLevel = rodOnMainHand ? mainHandItem.getEnchantmentLevel(Enchantment.LURE) : offHandItem.getEnchantmentLevel(Enchantment.LURE);
fishHook.setMaxWaitTime((int) (fishHook.getMaxWaitTime() * initialEffect.getTimeModifier()));
fishHook.setMinWaitTime((int) (fishHook.getMinWaitTime() * initialEffect.getTimeModifier()));
this.nextEffect.put(player.getUniqueId(), initialEffect);
if (ConfigManager.needRodToFish && !initialEffect.hasSpecialRod()) {
this.nextLoot.put(player.getUniqueId(), LootImpl.EMPTY);
return;
}
int entityID = 0;
if (baitAnimationItem != null && ConfigManager.baitAnimation) {
baitAnimationItem.setAmount(1);
entityID = new Random().nextInt(Integer.MAX_VALUE);
CustomFishing.getProtocolManager().sendServerPacket(player, FakeItemUtils.getSpawnPacket(entityID, fishHook.getLocation()));
CustomFishing.getProtocolManager().sendServerPacket(player, FakeItemUtils.getMetaPacket(entityID, baitAnimationItem));
}
BobberCheckTask bobberCheckTask = new BobberCheckTask(plugin, player, initialEffect, fishHook, this, lureLevel, entityID, rod_id, bait_id);
this.hookCheckTaskMap.put(player.getUniqueId(), bobberCheckTask);
}
public void onBite(PlayerFishEvent event) {
if (ConfigManager.disableBar || !ConfigManager.instantBar) return;
showBar(event.getPlayer());
}
public void getNextLoot(Player player, Effect initialEffect, List<LootImpl> possibleLoots) {
List<LootImpl> availableLoots = new ArrayList<>();
if (possibleLoots.size() == 0){
nextLoot.put(player.getUniqueId(), null);
return;
}
HashMap<String, Integer> as = initialEffect.getWeightAS();
HashMap<String, Double> md = initialEffect.getWeightMD();
double[] weights = new double[possibleLoots.size()];
int index = 0;
for (LootImpl loot : possibleLoots){
double weight = loot.getWeight();
String group = loot.getGroup();
if (group != null){
if (as.get(group) != null){
weight += as.get(group);
}
if (md.get(group) != null){
weight *= md.get(group);
}
}
if (weight <= 0) continue;
availableLoots.add(loot);
weights[index++] = weight;
}
double total = Arrays.stream(weights).sum();
double[] weightRatios = new double[index];
for (int i = 0; i < index; i++){
weightRatios[i] = weights[i]/total;
}
double[] weightRange = new double[index];
double startPos = 0;
for (int i = 0; i < index; i++) {
weightRange[i] = startPos + weightRatios[i];
startPos += weightRatios[i];
}
double random = Math.random();
int pos = Arrays.binarySearch(weightRange, random);
if (pos < 0) {
pos = -pos - 1;
}
if (pos < weightRange.length && random < weightRange[pos]) {
nextLoot.put(player.getUniqueId(), availableLoots.get(pos));
return;
}
nextLoot.put(player.getUniqueId(), null);
}
public void onCaughtFish(PlayerFishEvent event) {
final Player player = event.getPlayer();
if (!(event.getCaught() instanceof Item item)) return;
UUID uuid = player.getUniqueId();
FishingGame fishingGame = fishingPlayerMap.remove(uuid);
// if the player is noy playing the game
if (fishingGame == null) {
// get his next loot
LootImpl loot = nextLoot.get(uuid);
if (loot == LootImpl.EMPTY) return;
if (ConfigManager.enableVanillaLoot) {
// Not a vanilla loot
if (ConfigManager.vanillaLootRatio < Math.random()) {
if (loot != null) {
vanillaLoot.remove(uuid);
if (loot.isDisableBar() || ConfigManager.disableBar) {
noBarWaterReelIn(event);
return;
}
showFishingBar(player, loot);
}
else {
vanillaLoot.put(uuid, new VanillaLoot(item.getItemStack(), event.getExpToDrop()));
if (ConfigManager.disableBar) {
noBarWaterReelIn(event);
return;
}
showFishingBar(player, plugin.getLootManager().getVanilla_loot());
}
event.setCancelled(true);
}
// Is vanilla loot
else {
if (!plugin.getLootManager().getVanilla_loot().isDisableBar() && !ConfigManager.disableBar) {
event.setCancelled(true);
vanillaLoot.put(uuid, new VanillaLoot(item.getItemStack(), event.getExpToDrop()));
showFishingBar(player, plugin.getLootManager().getVanilla_loot());
}
//else vanilla fishing mechanic
}
}
else {
// No custom loot
if (loot == null) {
event.setCancelled(true);
removeHook(uuid);
AdventureUtils.playerMessage(player, MessageManager.prefix + MessageManager.noLoot);
}
else {
if (loot.isDisableBar() || ConfigManager.disableBar) {
noBarWaterReelIn(event);
return;
}
event.setCancelled(true);
showFishingBar(player, loot);
}
}
}
else {
event.setCancelled(true);
removeHook(uuid);
proceedReelIn(event.getHook().getLocation(), player, fishingGame);
}
}
public void onReelIn(PlayerFishEvent event) {
final Player player = event.getPlayer();
if (ConfigManager.disableBar) {
noBarLavaReelIn(event);
return;
}
UUID uuid = player.getUniqueId();
//in fishing game
FishingGame fishingGame = fishingPlayerMap.remove(uuid);
if (fishingGame != null) {
proceedReelIn(event.getHook().getLocation(), player, fishingGame);
hookCheckTaskMap.remove(uuid);
return;
}
//not in fishing game
BobberCheckTask bobberCheckTask = hookCheckTaskMap.get(uuid);
if (bobberCheckTask != null && bobberCheckTask.isHooked()) {
LootImpl loot = nextLoot.get(uuid);
if (loot == LootImpl.EMPTY || loot == null) return;
if (loot.isDisableBar()) {
noBarLavaReelIn(event);
return;
}
showFishingBar(player, loot);
event.setCancelled(true);
}
}
public void onCaughtEntity(PlayerFishEvent event) {
final Player player = event.getPlayer();
final UUID uuid = player.getUniqueId();
FishingGame fishingGame = fishingPlayerMap.remove(uuid);
if (fishingGame != null) {
Entity entity = event.getCaught();
if (entity != null && entity.getType() == EntityType.ARMOR_STAND) {
proceedReelIn(event.getHook().getLocation(), player, fishingGame);
}
else {
fishingGame.cancel();
nextEffect.remove(uuid);
nextLoot.remove(uuid);
AdventureUtils.playerMessage(player, MessageManager.prefix + MessageManager.hookOther);
}
}
}
private void noBarWaterReelIn(PlayerFishEvent event) {
Entity entity = event.getCaught();
if (!(entity instanceof Item item)) {
return;
}
entity.remove();
event.setExpToDrop(0);
final Player player = event.getPlayer();
final UUID uuid = player.getUniqueId();
LootImpl loot = nextLoot.remove(uuid);
VanillaLoot vanilla = vanillaLoot.remove(uuid);
Effect effect = nextEffect.remove(uuid);
if (vanilla != null) {
dropVanillaLoot(player, vanilla, item.getLocation(), effect.getDoubleLootChance() > Math.random());
} else if (loot instanceof Mob mob) {
summonMob(player, loot, item.getLocation(), mob, effect.getScoreMultiplier());
} else if (loot instanceof DroppedItem droppedItem){
if (ConfigManager.enableMcMMOLoot && Math.random() < ConfigManager.mcMMOLootChance){
if (dropMcMMOLoot(player, item.getLocation(), effect.getDoubleLootChance() > Math.random())){
return;
}
}
dropCustomFishingLoot(player, item.getLocation(), droppedItem, effect.getDoubleLootChance() > Math.random(), effect.getScoreMultiplier(), effect.getSizeMultiplier());
}
}
private void noBarLavaReelIn(PlayerFishEvent event) {
final Player player = event.getPlayer();
final UUID uuid = player.getUniqueId();
BobberCheckTask bobberCheckTask = hookCheckTaskMap.remove(uuid);
if (bobberCheckTask != null && bobberCheckTask.isHooked()) {
LootImpl loot = nextLoot.remove(uuid);
VanillaLoot vanilla = vanillaLoot.remove(uuid);
Effect effect = nextEffect.remove(uuid);
if (vanilla != null) {
dropVanillaLoot(player, vanilla, event.getHook().getLocation(), effect.getDoubleLootChance() > Math.random());
} else if (loot instanceof Mob mob) {
summonMob(player, loot, event.getHook().getLocation(), mob, effect.getScoreMultiplier());
} else if (loot instanceof DroppedItem droppedItem) {
if (ConfigManager.enableMcMMOLoot && Math.random() < ConfigManager.mcMMOLootChance) {
if (dropMcMMOLoot(player, event.getHook().getLocation(), effect.getDoubleLootChance() > Math.random())){
return;
}
}
dropCustomFishingLoot(player, event.getHook().getLocation(), droppedItem, effect.getDoubleLootChance() > Math.random(), effect.getScoreMultiplier(), effect.getSizeMultiplier());
}
}
}
public void proceedReelIn(Location hookLoc, Player player, FishingGame fishingGame) {
fishingGame.cancel();
final UUID uuid = player.getUniqueId();
LootImpl loot = nextLoot.remove(uuid);
VanillaLoot vanilla = vanillaLoot.remove(uuid);
Effect effect = nextEffect.remove(uuid);
player.removePotionEffect(PotionEffectType.SLOW);
if (fishingGame.isSuccess()) {
if (ConfigManager.rodLoseDurability) loseDurability(player);
if (hookLoc.getBlock().getType() == Material.LAVA) {
hookLoc.add(0,0.3,0);
}
if (vanilla != null) {
dropVanillaLoot(player, vanilla, hookLoc, effect.getDoubleLootChance() > Math.random());
} else if (loot instanceof Mob mob) {
summonMob(player, loot, hookLoc, mob, effect.getScoreMultiplier());
} else if (loot instanceof DroppedItem droppedItem){
if (ConfigManager.enableMcMMOLoot && Math.random() < ConfigManager.mcMMOLootChance){
if (dropMcMMOLoot(player, hookLoc, effect.getDoubleLootChance() > Math.random())){
return;
}
}
dropCustomFishingLoot(player, hookLoc, droppedItem, effect.getDoubleLootChance() > Math.random(), effect.getScoreMultiplier(), effect.getSizeMultiplier());
}
} else {
fail(player, loot, vanilla != null);
}
}
private void dropCustomFishingLoot(Player player, Location location, DroppedItem droppedItem, boolean isDouble, double scoreMultiplier, double sizeMultiplier) {
Pair<ItemStack, FishMeta> dropPair = getCustomFishingLootItemStack(droppedItem, player, sizeMultiplier);
FishResultEvent fishResultEvent = new FishResultEvent(player, FishResult.CATCH_SPECIAL_ITEM, isDouble, dropPair.left(), droppedItem.getKey(), droppedItem);
Bukkit.getPluginManager().callEvent(fishResultEvent);
if (fishResultEvent.isCancelled()) {
return;
}
if (Competition.currentCompetition != null) {
float score = Competition.currentCompetition.getGoal() == CompetitionGoal.MAX_SIZE
|| Competition.currentCompetition.getGoal() == CompetitionGoal.TOTAL_SIZE
? dropPair.right().size() : (float) ((float) droppedItem.getScore() * scoreMultiplier);
Competition.currentCompetition.refreshData(player, score, fishResultEvent.isDouble());
Competition.currentCompetition.tryJoinCompetition(player);
}
if (droppedItem.getSuccessActions() != null)
for (Action action : droppedItem.getSuccessActions())
action.doOn(player, null, dropPair.right());
if (plugin.getVersionHelper().isFolia()) {
plugin.getScheduler().runTask(() -> dropItem(player, location, fishResultEvent.isDouble(), dropPair.left()), location);
} else {
dropItem(player, location, fishResultEvent.isDouble(), dropPair.left());
}
addStats(player, droppedItem, isDouble ? 2 : 1);
sendSuccessTitle(player, droppedItem.getNick());
}
public ItemStack getCustomFishingLootItemStack(DroppedItem droppedItem, Player player) {
return getCustomFishingLootItemStack(droppedItem, player, 1).left();
}
public Pair<ItemStack, FishMeta> getCustomFishingLootItemStack(DroppedItem droppedItem, @Nullable Player player, double sizeMultiplier) {
ItemStack drop = plugin.getIntegrationManager().build(droppedItem.getMaterial(), player);
FishMeta fishMeta = null;
if (drop.getType() != Material.AIR) {
if (droppedItem.getRandomEnchants() != null)
ItemStackUtils.addRandomEnchants(drop, droppedItem.getRandomEnchants());
if (droppedItem.isRandomDurability())
ItemStackUtils.addRandomDamage(drop);
if (ConfigManager.preventPickUp && player != null)
ItemStackUtils.addOwner(drop, player.getName());
fishMeta = ItemStackUtils.addExtraMeta(drop, droppedItem, sizeMultiplier, player);
}
return Pair.of(drop, fishMeta);
}
private boolean dropMcMMOLoot(Player player, Location location, boolean isDouble) {
ItemStack itemStack = McMMOTreasure.getTreasure(player);
if (itemStack == null) return false;
FishResultEvent fishResultEvent = new FishResultEvent(player, FishResult.CATCH_VANILLA_ITEM, isDouble, itemStack, "mcMMO", null);
Bukkit.getPluginManager().callEvent(fishResultEvent);
if (fishResultEvent.isCancelled()) {
return true;
}
doVanillaActions(player, location, itemStack, fishResultEvent.isDouble());
new VanillaXPImpl(new Random().nextInt(24), true, 1).doOn(player);
return true;
}
private void dropVanillaLoot(Player player, VanillaLoot vanillaLoot, Location location, boolean isDouble) {
ItemStack itemStack = vanillaLoot.getItemStack();
if (ConfigManager.enableMcMMOLoot && Math.random() < ConfigManager.mcMMOLootChance){
ItemStack mcMMOItemStack = McMMOTreasure.getTreasure(player);
if (mcMMOItemStack != null){
itemStack = mcMMOItemStack;
}
}
FishResultEvent fishResultEvent = new FishResultEvent(player, FishResult.CATCH_VANILLA_ITEM, isDouble, itemStack, "vanilla", null);
Bukkit.getPluginManager().callEvent(fishResultEvent);
if (fishResultEvent.isCancelled()) {
return;
}
doVanillaActions(player, location, itemStack, fishResultEvent.isDouble());
new VanillaXPImpl(vanillaLoot.getXp(), true, 1).doOn(player);
}
private void doVanillaActions(Player player, Location location, ItemStack itemStack, boolean isDouble) {
if (Competition.currentCompetition != null) {
Competition.currentCompetition.refreshData(player, (float) plugin.getLootManager().getVanilla_loot().getScore(), isDouble);
Competition.currentCompetition.tryJoinCompetition(player);
}
LootImpl vanilla = plugin.getLootManager().getVanilla_loot();
addStats(player, vanilla, isDouble ? 2 : 1);
if (vanilla.getSuccessActions() != null)
for (Action action : vanilla.getSuccessActions())
action.doOn(player);
AdventureUtils.playerSound(player, Sound.Source.PLAYER, Key.key("minecraft:entity.experience_orb.pickup"), 1, 1);
if (plugin.getVersionHelper().isFolia()) {
plugin.getScheduler().runTask(() -> dropItem(player, location, isDouble, itemStack), location);
} else {
dropItem(player, location, isDouble, itemStack);
}
sendSuccessTitle(player, itemStack);
}
private void dropItem(Player player, Location location, boolean isDouble, ItemStack itemStack) {
if (itemStack.getType() == Material.AIR) return;
Entity item = location.getWorld().dropItem(location, itemStack);
Vector vector = player.getLocation().subtract(location).toVector().multiply(0.105);
vector = vector.setY((vector.getY() + 0.2) * 1.18);
item.setVelocity(vector);
if (isDouble) {
Entity item2 = location.getWorld().dropItem(location, itemStack);
item2.setVelocity(vector);
}
}
private void addStats(Player player, LootImpl loot, int amount) {
player.setStatistic(Statistic.FISH_CAUGHT, player.getStatistic(Statistic.FISH_CAUGHT) + 1);
if (!ConfigManager.enableStatistics) return;
if (loot.isDisableStats()) return;
plugin.getStatisticsManager().addFishAmount(player.getUniqueId(), loot, amount);
}
private void summonMob(Player player, LootImpl loot, Location location, Mob mob, double scoreMultiplier) {
MobInterface mobInterface = plugin.getIntegrationManager().getMobInterface();
if (mobInterface == null) return;
FishResultEvent fishResultEvent = new FishResultEvent(player, FishResult.CATCH_MOB, false, null, loot.getKey(), loot);
if (fishResultEvent.isCancelled()) {
return;
}
if (Competition.currentCompetition != null) {
float score = Competition.currentCompetition.getGoal() == CompetitionGoal.MAX_SIZE || Competition.currentCompetition.getGoal() == CompetitionGoal.TOTAL_SIZE ? 0 : (float) loot.getScore();
Competition.currentCompetition.refreshData(player, (float) (score * scoreMultiplier), false);
Competition.currentCompetition.tryJoinCompetition(player);
}
if (loot.getSuccessActions() != null)
for (Action action : loot.getSuccessActions())
action.doOn(player);
mobInterface.summon(player.getLocation(), location, mob);
addStats(player, mob, 1);
sendSuccessTitle(player, loot.getNick());
}
@NotNull
private Component getTitleComponent(ItemStack itemStack, String text) {
Component titleComponent = Component.text("");
int startIndex = 0;
int lootIndex;
while ((lootIndex = text.indexOf("{loot}", startIndex)) != -1) {
String before = text.substring(startIndex, lootIndex);
titleComponent = titleComponent.append(AdventureUtils.getComponentFromMiniMessage(before));
startIndex = lootIndex + 6;
titleComponent = titleComponent.append(getDisplayName(itemStack));
}
String after = text.substring(startIndex);
titleComponent = titleComponent.append(AdventureUtils.getComponentFromMiniMessage(after));
return titleComponent;
}
private void sendSuccessTitle(Player player, String loot) {
if (!ConfigManager.enableSuccessTitle) return;
plugin.getScheduler().runTaskAsyncLater(() -> AdventureUtils.playerTitle(
player,
ConfigManager.successTitle[new Random().nextInt(ConfigManager.successTitle.length)]
.replace("{loot}", loot)
.replace("{player}", player.getName()),
ConfigManager.successSubTitle[new Random().nextInt(ConfigManager.successSubTitle.length)]
.replace("{loot}", loot)
.replace("{player}", player.getName()),
ConfigManager.successFadeIn,
ConfigManager.successFadeStay,
ConfigManager.successFadeOut
), 400, TimeUnit.MILLISECONDS);
}
private void sendSuccessTitle(Player player, ItemStack itemStack) {
if (!ConfigManager.enableSuccessTitle) return;
String title = ConfigManager.successTitle[new Random().nextInt(ConfigManager.successTitle.length)];
Component titleComponent = getTitleComponent(itemStack, title);
String subTitle = ConfigManager.successSubTitle[new Random().nextInt(ConfigManager.successSubTitle.length)];
Component subtitleComponent = getTitleComponent(itemStack, subTitle);
plugin.getScheduler().runTaskAsyncLater(() -> AdventureUtils.playerTitle(
player,
titleComponent,
subtitleComponent,
ConfigManager.successFadeIn,
ConfigManager.successFadeStay,
ConfigManager.successFadeOut
), 400, TimeUnit.MILLISECONDS);
}
private void loseDurability(Player player) {
if (player.getGameMode() == GameMode.CREATIVE) return;
plugin.getScheduler().runTaskAsyncLater(() -> {
ItemStack rod = getFishingRod(player);
if (rod != null) {
plugin.getIntegrationManager().loseCustomDurability(rod, player);
}
}, 50, TimeUnit.MILLISECONDS);
}
private ItemStack getFishingRod(Player player) {
ItemStack mainHand = player.getInventory().getItemInMainHand();
if (mainHand.getType() == Material.FISHING_ROD) {
return mainHand;
}
ItemStack offHand = player.getInventory().getItemInOffHand();
if (offHand.getType() == Material.FISHING_ROD) {
return offHand;
}
return null;
}
public void fail(Player player, LootImpl loot, boolean isVanilla) {
FishResultEvent fishResultEvent = new FishResultEvent(player, FishResult.FAILURE, false, null, null, null);
Bukkit.getServer().getPluginManager().callEvent(fishResultEvent);
if (fishResultEvent.isCancelled()) {
return;
}
if (!isVanilla && loot != null && loot.getFailureActions() != null) {
for (Action action : loot.getFailureActions())
action.doOn(player);
}
if (!ConfigManager.enableFailureTitle) return;
plugin.getScheduler().runTaskAsyncLater(() -> AdventureUtils.playerTitle(
player,
ConfigManager.failureTitle[new Random().nextInt(ConfigManager.failureTitle.length)],
ConfigManager.failureSubTitle[new Random().nextInt(ConfigManager.failureSubTitle.length)],
ConfigManager.failureFadeIn,
ConfigManager.failureFadeStay,
ConfigManager.failureFadeOut
), 400, TimeUnit.MILLISECONDS);
}
public void showBar(Player player) {
final UUID uuid = player.getUniqueId();
if (fishingPlayerMap.get(uuid) != null) return;
LootImpl loot = nextLoot.get(uuid);
if (loot != null) {
if (loot == LootImpl.EMPTY) return;
showFishingBar(player, loot);
}
}
public boolean isCoolDown(Player player, long delay) {
long time = System.currentTimeMillis();
long last = coolDown.getOrDefault(player.getUniqueId(), time - delay);
if (last + delay > time) {
return true;
} else {
coolDown.put(player.getUniqueId(), time);
return false;
}
}
private void addEnchantEffect(Effect initialEffect, ItemStack itemStack, FishingCondition fishingCondition) {
for (String key : plugin.getIntegrationManager().getEnchantmentInterface().getEnchants(itemStack)) {
Effect enchantEffect = plugin.getEffectManager().getEnchantEffect(key);
if (enchantEffect != null && enchantEffect.canAddEffect(enchantEffect, fishingCondition)) {
initialEffect.addEffect(enchantEffect);
}
}
}
public List<LootImpl> getPossibleLootList(FishingCondition fishingCondition, boolean finder, Collection<LootImpl> values) {
Stream<LootImpl> stream = values.stream();
if (finder) {
stream = stream.filter(LootImpl::isShowInFinder);
}
return stream.filter(loot -> {
RequirementInterface[] requirements = loot.getRequirements();
if (requirements == null) {
return true;
}
for (RequirementInterface requirement : requirements) {
if (!requirement.isConditionMet(fishingCondition)) {
return false;
}
}
return true;
}).collect(Collectors.toList());
}
@Override
public void onInteract(PlayerInteractEvent event) {
ItemStack itemStack = event.getItem();
final Player player = event.getPlayer();
if (itemStack == null || itemStack.getType() == Material.AIR) return;
NBTItem nbtItem = new NBTItem(itemStack);
NBTCompound cfCompound = nbtItem.getCompound("CustomFishing");
if (cfCompound != null && cfCompound.getString("type").equals("util") && cfCompound.getString("id").equals("fishfinder")) {
if (isCoolDown(player, 1000)) return;
useFinder(event.getPlayer());
return;
}
Block block = event.getClickedBlock();
if (block == null) return;
String totemID = nbtItem.getString("Totem");
if (totemID.equals("")) return;
TotemConfig totem = plugin.getTotemManager().getTotem(totemID);
if (totem == null) return;
if (isCoolDown(player, 1000)) return;
String blockID = plugin.getIntegrationManager().getBlockInterface().getID(block);
if (blockID == null) return;
List<TotemConfig> totemList = plugin.getTotemManager().getTotemsByCoreID(blockID);
if (totemList == null || !totemList.contains(totem)) return;
FishingCondition fishingCondition = new FishingCondition(block.getLocation(), player, null, null);
if (totem.getRequirements() != null)
for (RequirementInterface requirement : totem.getRequirements()) {
if (!requirement.isConditionMet(fishingCondition)) {
return;
}
}
Location coreLoc = block.getLocation();
int direction = plugin.getTotemManager().checkLocationModel(totem.getOriginalModel(), coreLoc);
if (direction == 0) return;
TotemActivationEvent totemActivationEvent = new TotemActivationEvent(player, coreLoc, totem);
Bukkit.getPluginManager().callEvent(totemActivationEvent);
if (totemActivationEvent.isCancelled()) {
return;
}
if (activeTotemMap.get(LocationUtils.getSimpleLocation(coreLoc)) != null) {
activeTotemMap.get(LocationUtils.getSimpleLocation(coreLoc)).stop();
}
plugin.getTotemManager().removeModel(totem.getFinalModel(), coreLoc, direction);
if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1);
if (totem.getActivatorActions() != null)
for (Action action : totem.getActivatorActions()) {
action.doOn(player);
}
if (totem.getNearbyActions() != null)
for (Action action : totem.getNearbyActions()) {
for (Player nearby : LocationUtils.getNearbyPlayers(coreLoc, totem.getRadius())) {
action.doOn(nearby, player);
}
}
ActivatedTotem activatedTotem = new ActivatedTotem(coreLoc, totem, this, direction, player.getName());
activeTotemMap.put(LocationUtils.getSimpleLocation(coreLoc), activatedTotem);
}
private void useFinder(Player player) {
if (!ConfigManager.getWorldsList().contains(player.getWorld().getName())) {
return;
}
FishingCondition fishingCondition = new FishingCondition(player.getLocation(), player, null, null);
List<LootImpl> possibleLoots = getPossibleLootList(fishingCondition, true, plugin.getLootManager().getAllLoots());
FishFinderEvent fishFinderEvent = new FishFinderEvent(player, possibleLoots);
Bukkit.getPluginManager().callEvent(fishFinderEvent);
if (fishFinderEvent.isCancelled()) {
return;
}
if (possibleLoots.size() == 0) {
AdventureUtils.playerMessage(player, MessageManager.prefix + MessageManager.noLoot);
return;
}
StringJoiner stringJoiner = new StringJoiner(MessageManager.splitChar);
possibleLoots.forEach(loot -> stringJoiner.add(loot.getNick()));
AdventureUtils.playerMessage(player, MessageManager.prefix + MessageManager.possibleLoots + stringJoiner);
}
private void showFishingBar(Player player, @NotNull LootImpl loot) {
MiniGameConfig game = loot.getFishingGames() != null
? loot.getFishingGames()[new Random().nextInt(loot.getFishingGames().length)]
: plugin.getBarMechanicManager().getRandomGame();
int difficult = game.getRandomDifficulty() + nextEffect.getOrDefault(player.getUniqueId(), new Effect()).getDifficulty();
MiniGameStartEvent miniGameStartEvent = new MiniGameStartEvent(player, Math.min(10, Math.max(1, difficult)));
Bukkit.getPluginManager().callEvent(miniGameStartEvent);
if (miniGameStartEvent.isCancelled()) {
return;
}
FishingBar fishingBar = game.getRandomBar();
FishingGame fishingGame = null;
Location hookLoc = getHookLocation(player);
if (hookLoc == null) return;
if (fishingBar instanceof ModeOneBar modeOneBar) {
fishingGame = new ModeOneGame(plugin, this, System.currentTimeMillis() + game.getTime() * 1000L, player, miniGameStartEvent.getDifficulty(), modeOneBar);
}
else if (fishingBar instanceof ModeTwoBar modeTwoBar) {
fishingGame = new ModeTwoGame(plugin, this, System.currentTimeMillis() + game.getTime() * 1000L, player, miniGameStartEvent.getDifficulty(), modeTwoBar, hookLoc);
}
else if (fishingBar instanceof ModeThreeBar modeThreeBar) {
fishingGame = new ModeThreeGame(plugin, this, System.currentTimeMillis() + game.getTime() * 1000L, player, miniGameStartEvent.getDifficulty(), modeThreeBar);
}
if (fishingGame != null) {
fishingPlayerMap.put(player.getUniqueId(), fishingGame);
}
if (loot.getHookActions() != null) {
for (Action action : loot.getHookActions()) {
action.doOn(player);
}
}
player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, game.getTime() * 20,3));
}
@Override
public void onQuit(Player player) {
final UUID uuid = player.getUniqueId();
coolDown.remove(uuid);
nextLoot.remove(uuid);
nextEffect.remove(uuid);
vanillaLoot.remove(uuid);
BobberCheckTask task = hookCheckTaskMap.remove(uuid);
if (task != null) task.stop();
removeHook(uuid);
}
public void removeFishingPlayer(Player player) {
fishingPlayerMap.remove(player.getUniqueId());
}
private Component getDisplayName(ItemStack itemStack){
NBTItem nbtItem = new NBTItem(itemStack);
NBTCompound nbtCompound = nbtItem.getCompound("display");
if (nbtCompound != null){
String name = nbtCompound.getString("Name");
if (!name.equals("")){
return GsonComponentSerializer.gson().deserialize(name);
}
}
String type = itemStack.getType().toString().toLowerCase();
if (itemStack.getType().isBlock()) return GsonComponentSerializer.gson().deserialize("{\"translate\":\"block.minecraft." + type + "\"}");
else return GsonComponentSerializer.gson().deserialize("{\"translate\":\"item.minecraft." + type + "\"}");
}
public void removeTotem(Location coreLoc) {
activeTotemMap.remove(LocationUtils.getSimpleLocation(coreLoc));
}
public void removePlayerFromLavaFishing(Player player) {
this.hookCheckTaskMap.remove(player.getUniqueId());
}
public float getSize(ItemStack itemStack) {
NBTCompound fishMeta = new NBTItem(itemStack).getCompound("FishMeta");
return fishMeta != null ? fishMeta.getFloat("size") : 0;
}
public void addTotemBreakDetectToCache(SimpleLocation part, SimpleLocation coreLoc) {
breakDetectionMap.put(part, coreLoc);
}
public void removeTotemBreakDetectFromCache(SimpleLocation part) {
breakDetectionMap.remove(part);
}
@Override
public void onBreakBlock(BlockBreakEvent event) {
SimpleLocation coreLoc = breakDetectionMap.get(LocationUtils.getSimpleLocation(event.getBlock().getLocation()));
if (coreLoc != null) {
ActivatedTotem activatedTotem = activeTotemMap.get(coreLoc);
if (activatedTotem != null) {
activatedTotem.stop();
}
}
}
public void removeHook(UUID uuid) {
FishHook fishHook = hooks.remove(uuid);
if (fishHook != null) {
if (plugin.getVersionHelper().isFolia()) {
plugin.getScheduler().runTask(fishHook::remove, fishHook.getLocation());
} else {
fishHook.remove();
}
}
}
@Nullable
public FishHook getHook(UUID uuid) {
return hooks.get(uuid);
}
@Nullable
public Location getHookLocation(Player player) {
FishHook fishHook = hooks.get(player.getUniqueId());
if (fishHook != null) {
return fishHook.getLocation();
}
return null;
}
@Override
public void onConsumeItem(PlayerItemConsumeEvent event) {
ItemStack itemStack = event.getItem();
NBTCompound nbtCompound = new NBTItem(itemStack).getCompound("CustomFishing");
if (nbtCompound == null) return;
if (!nbtCompound.getString("type").equals("loot")) return;
String lootKey = nbtCompound.getString("id");
LootImpl loot = plugin.getLootManager().getLoot(lootKey);
if (loot == null) return;
if (!(loot instanceof DroppedItem droppedItem)) return;
final Player player = event.getPlayer();
if (droppedItem.getConsumeActions() != null)
for (Action action : droppedItem.getConsumeActions())
action.doOn(player);
}
public Effect getInitialEffect(Player player) {
boolean noBait = true;
boolean rodOnMainHand = false;
Effect initialEffect = new Effect();
initialEffect.setWeightMD(new HashMap<>(8));
initialEffect.setWeightAS(new HashMap<>(8));
final PlayerInventory inventory = player.getInventory();
final ItemStack mainHandItem = inventory.getItemInMainHand();
final ItemStack offHandItem = inventory.getItemInOffHand();
if (mainHandItem.getType() == Material.FISHING_ROD) {
rodOnMainHand = true;
}
String rod_id = Optional.ofNullable(rodOnMainHand ? CustomFishingAPI.getRodID(mainHandItem) : CustomFishingAPI.getRodID(offHandItem)).orElse("vanilla");
final FishingCondition fishingCondition = new FishingCondition(player.getLocation(), player, rod_id, null);
String bait_id = Optional.ofNullable(rodOnMainHand ? CustomFishingAPI.getBaitID(offHandItem) : CustomFishingAPI.getBaitID(mainHandItem)).orElse("");
Effect baitEffect = plugin.getEffectManager().getBaitEffect(bait_id);
if (baitEffect != null && initialEffect.canAddEffect(baitEffect, fishingCondition)) {
initialEffect.addEffect(baitEffect);
noBait = false;
}
for (ActivatedTotem activatedTotem : activeTotemMap.values()) {
if (activatedTotem.getNearbyPlayerSet().contains(player)) {
initialEffect.addEffect(activatedTotem.getTotem().getEffect());
break;
}
}
if (ConfigManager.enableFishingBag) {
Inventory fishingBag = plugin.getBagDataManager().getPlayerBagData(player.getUniqueId());
HashSet<String> uniqueUtils = new HashSet<>(4);
if (fishingBag != null) {
for (int i = 0; i < fishingBag.getSize(); i++) {
ItemStack itemStack = fishingBag.getItem(i);
if (itemStack == null || itemStack.getType() == Material.AIR) continue;
NBTCompound cfCompound = new NBTItem(itemStack).getCompound("CustomFishing");
if (cfCompound == null) continue;
String type = cfCompound.getString("type"); String id = cfCompound.getString("id");
if (noBait && type.equals("bait")) {
Effect effect = plugin.getEffectManager().getBaitEffect(id);
if (effect != null && itemStack.getAmount() > 0 && initialEffect.canAddEffect(effect, fishingCondition)) {
initialEffect.addEffect(effect);
noBait = false;
bait_id = id;
}
} else if (type.equals("util")) {
Effect utilEffect = plugin.getEffectManager().getUtilEffect(id);
if (utilEffect != null && !uniqueUtils.contains(id)) {
initialEffect.addEffect(utilEffect);
uniqueUtils.add(id);
}
}
}
}
}
Effect rod_effect = plugin.getEffectManager().getRodEffect(rod_id);
if (rod_effect != null) {
if (initialEffect.canAddEffect(rod_effect, new FishingCondition(player.getLocation(), player, rod_id, bait_id))) {
initialEffect.addEffect(rod_effect);
} else {
return null;
}
initialEffect.setSpecialRodID(rod_id);
}
this.addEnchantEffect(initialEffect, rodOnMainHand ? mainHandItem : offHandItem, fishingCondition);
return initialEffect;
}
}