diff --git a/api/src/main/java/net/momirealms/customfishing/api/CustomFishingPlugin.java b/api/src/main/java/net/momirealms/customfishing/api/CustomFishingPlugin.java index c8a3c892..cee14285 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/CustomFishingPlugin.java +++ b/api/src/main/java/net/momirealms/customfishing/api/CustomFishingPlugin.java @@ -45,6 +45,7 @@ public abstract class CustomFishingPlugin extends JavaPlugin { protected PlaceholderManager placeholderManager; protected StatisticsManager statisticsManager; protected TotemManager totemManager; + protected HookManager hookManager; private static CustomFishingPlugin instance; @@ -128,6 +129,10 @@ public abstract class CustomFishingPlugin extends JavaPlugin { return totemManager; } + public HookManager getHookManager() { + return hookManager; + } + public IntegrationManager getIntegrationManager() { return integrationManager; } diff --git a/api/src/main/java/net/momirealms/customfishing/api/manager/FishingManager.java b/api/src/main/java/net/momirealms/customfishing/api/manager/FishingManager.java index 7606fc0b..c29df9d5 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/manager/FishingManager.java +++ b/api/src/main/java/net/momirealms/customfishing/api/manager/FishingManager.java @@ -55,4 +55,6 @@ public interface FishingManager { void startFishingGame(Player player, Condition condition, Effect effect); void startFishingGame(Player player, GameSettings settings, GameInstance gameInstance); + + boolean hasPlayerCastHook(UUID uuid); } diff --git a/api/src/main/java/net/momirealms/customfishing/api/manager/HookManager.java b/api/src/main/java/net/momirealms/customfishing/api/manager/HookManager.java new file mode 100644 index 00000000..040473a8 --- /dev/null +++ b/api/src/main/java/net/momirealms/customfishing/api/manager/HookManager.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customfishing.api.manager; + +import net.momirealms.customfishing.api.mechanic.hook.HookSetting; +import org.jetbrains.annotations.Nullable; + +public interface HookManager { + @Nullable + HookSetting getHookSetting(String id); +} diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/condition/FishingPreparation.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/condition/FishingPreparation.java index e1b3f8e8..545cd18d 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/condition/FishingPreparation.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/condition/FishingPreparation.java @@ -17,6 +17,8 @@ package net.momirealms.customfishing.api.mechanic.condition; +import de.tr7zw.changeme.nbtapi.NBTCompound; +import de.tr7zw.changeme.nbtapi.NBTItem; import net.momirealms.customfishing.api.CustomFishingPlugin; import net.momirealms.customfishing.api.mechanic.GlobalSettings; import net.momirealms.customfishing.api.mechanic.action.Action; @@ -38,12 +40,10 @@ import java.util.List; public class FishingPreparation extends Condition { - private @Nullable EffectCarrier baitEffect; - private final @Nullable EffectCarrier rodEffect; + private boolean hasBait = false; private @Nullable ItemStack baitItemStack; private final @NotNull ItemStack rodItemStack; - private final List utilEffects; - private final List enchantEffects; + private final List effects; private boolean canFish = true; public FishingPreparation(Player player, CustomFishingPlugin plugin) { @@ -53,74 +53,74 @@ public class FishingPreparation extends Condition { ItemStack mainHandItem = playerInventory.getItemInMainHand(); ItemStack offHandItem = playerInventory.getItemInOffHand(); - this.utilEffects = new ArrayList<>(); - this.enchantEffects = new ArrayList<>(); + this.effects = new ArrayList<>(); boolean rodOnMainHand = mainHandItem.getType() == Material.FISHING_ROD; this.rodItemStack = rodOnMainHand ? mainHandItem : offHandItem; String rodItemID = plugin.getItemManager().getAnyItemID(this.rodItemStack); - this.rodEffect = plugin.getEffectManager().getEffect("rod", rodItemID); + EffectCarrier rodEffect = plugin.getEffectManager().getEffect("rod", rodItemID); + if (rodEffect != null) effects.add(rodEffect); super.insertArg("{rod}", rodItemID); + NBTItem nbtItem = new NBTItem(rodItemStack); + NBTCompound cfCompound = nbtItem.getCompound("CustomFishing"); + if (cfCompound != null && cfCompound.hasTag("hook_id")) { + String hookID = cfCompound.getString("hook_id"); + super.insertArg("{hook}", rodItemID); + EffectCarrier carrier = plugin.getEffectManager().getEffect("hook", hookID); + if (carrier != null) { + this.effects.add(carrier); + } + } + String baitItemID = plugin.getItemManager().getAnyItemID(rodOnMainHand ? offHandItem : mainHandItem); EffectCarrier baitEffect = plugin.getEffectManager().getEffect("bait", baitItemID); if (baitEffect != null) { this.baitItemStack = rodOnMainHand ? offHandItem : mainHandItem; - this.baitEffect = baitEffect; + this.effects.add(baitEffect); + this.hasBait = true; + super.insertArg("{bait}", baitItemID); } if (plugin.getBagManager().isEnabled()) { Inventory fishingBag = plugin.getBagManager().getOnlineBagInventory(player.getUniqueId()); HashSet uniqueUtils = new HashSet<>(4); if (fishingBag != null) { + this.insertArg("{in-bag}", "true"); for (int i = 0; i < fishingBag.getSize(); i++) { ItemStack itemInBag = fishingBag.getItem(i); String bagItemID = plugin.getItemManager().getItemID(itemInBag); if (bagItemID == null) continue; - if (this.baitEffect == null) { + if (!hasBait) { EffectCarrier effect = plugin.getEffectManager().getEffect("bait", bagItemID); if (effect != null) { this.baitItemStack = itemInBag; - this.baitEffect = effect; + this.effects.add(effect); + super.insertArg("{bait}", bagItemID); continue; } } EffectCarrier utilEffect = plugin.getEffectManager().getEffect("util", bagItemID); if (utilEffect != null && !uniqueUtils.contains(bagItemID)) { - if (!utilEffect.isConditionMet(this)) { - this.canFish = false; - return; - } - utilEffects.add(utilEffect); + effects.add(utilEffect); uniqueUtils.add(bagItemID); } } - } - } - - if (this.baitEffect != null) { - if (!this.baitEffect.isConditionMet(this)) { - this.canFish = false; - return; - } - super.insertArg("{bait}", this.baitEffect.getKey().value()); - } - - if (this.rodEffect != null) { - if (!this.rodEffect.isConditionMet(this)) { - this.canFish = false; - return; + this.delArg("{in-bag}"); } } for (String enchant : plugin.getIntegrationManager().getEnchantments(rodItemStack)) { EffectCarrier enchantEffect = plugin.getEffectManager().getEffect("enchant", enchant); if (enchantEffect != null) { - if (!enchantEffect.isConditionMet(this)) { - this.canFish = false; - return; - } - this.enchantEffects.add(enchantEffect); + this.effects.add(enchantEffect); + } + } + + for (EffectCarrier effectCarrier : effects) { + if (!effectCarrier.isConditionMet(this)) { + this.canFish = false; + return; } } } @@ -135,38 +135,13 @@ public class FishingPreparation extends Condition { return baitItemStack; } - @Nullable - public EffectCarrier getBaitEffect() { - return baitEffect; - } - - @Nullable - public EffectCarrier getRodEffect() { - return rodEffect; - } - public boolean canFish() { return this.canFish; } public void mergeEffect(FishingEffect effect) { - if (this.rodEffect != null) { - for (EffectModifier modifier : rodEffect.getEffectModifiers()) { - modifier.modify(effect, this); - } - } - if (this.baitEffect != null) { - for (EffectModifier modifier : baitEffect.getEffectModifiers()) { - modifier.modify(effect, this); - } - } - for (EffectCarrier util : utilEffects) { - for (EffectModifier modifier : util.getEffectModifiers()) { - modifier.modify(effect, this); - } - } - for (EffectCarrier enchant : enchantEffects) { - for (EffectModifier modifier : enchant.getEffectModifiers()) { + for (EffectCarrier effectCarrier : effects) { + for (EffectModifier modifier : effectCarrier.getEffectModifiers()) { modifier.modify(effect, this); } } @@ -174,17 +149,8 @@ public class FishingPreparation extends Condition { public void triggerActions(ActionTrigger actionTrigger) { GlobalSettings.triggerRodActions(actionTrigger, this); - if (rodEffect != null) { - Action[] actions = rodEffect.getActions(actionTrigger); - if (actions != null) - for (Action action : actions) { - action.trigger(this); - } - } - - if (baitEffect != null) { - GlobalSettings.triggerBaitActions(actionTrigger, this); - Action[] actions = baitEffect.getActions(actionTrigger); + for (EffectCarrier effectCarrier : effects) { + Action[] actions = effectCarrier.getActions(actionTrigger); if (actions != null) for (Action action : actions) { action.trigger(this); diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/hook/HookSetting.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/hook/HookSetting.java new file mode 100644 index 00000000..9c4222f0 --- /dev/null +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/hook/HookSetting.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customfishing.api.mechanic.hook; + +import java.util.ArrayList; +import java.util.List; + +public class HookSetting { + + private final String key; + private int maxDurability; + private List lore; + + public HookSetting(String key) { + this.key = key; + } + + public String getKey() { + return key; + } + + public int getMaxDurability() { + return maxDurability; + } + + public List getLore() { + return lore == null ? new ArrayList<>() : lore; + } + + public static class Builder { + + private final HookSetting setting; + + public Builder(String key) { + this.setting = new HookSetting(key); + } + + public Builder durability(int maxDurability) { + setting.maxDurability = maxDurability; + return this; + } + + public Builder lore(List lore) { + setting.lore = lore; + return this; + } + + public HookSetting build() { + return setting; + } + } +} diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index 7b332c39..edfe90b9 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -34,7 +34,7 @@ dependencies { compileOnly("com.h2database:h2:2.2.220") compileOnly("org.mongodb:mongodb-driver-sync:4.10.2") compileOnly("com.zaxxer:HikariCP:5.0.1") - compileOnly("redis.clients:jedis:4.4.3") + compileOnly("redis.clients:jedis:5.0.0") // others compileOnly("com.github.LoneDev6:api-itemsadder:3.5.0c-r5") @@ -74,7 +74,7 @@ dependencies { implementation(files("libs/BiomeAPI.jar")) // anvil - implementation("net.wesjd:anvilgui:1.7.0-SNAPSHOT") + implementation("net.wesjd:anvilgui:1.9.0-SNAPSHOT") } tasks { diff --git a/plugin/src/main/java/net/momirealms/customfishing/CustomFishingPluginImpl.java b/plugin/src/main/java/net/momirealms/customfishing/CustomFishingPluginImpl.java index 10ca5fc2..2957a191 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/CustomFishingPluginImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/CustomFishingPluginImpl.java @@ -37,6 +37,7 @@ import net.momirealms.customfishing.mechanic.effect.EffectManagerImpl; import net.momirealms.customfishing.mechanic.entity.EntityManagerImpl; import net.momirealms.customfishing.mechanic.fishing.FishingManagerImpl; import net.momirealms.customfishing.mechanic.game.GameManagerImpl; +import net.momirealms.customfishing.mechanic.hook.HookManagerImpl; import net.momirealms.customfishing.mechanic.item.ItemManagerImpl; import net.momirealms.customfishing.mechanic.loot.LootManagerImpl; import net.momirealms.customfishing.mechanic.market.MarketManagerImpl; @@ -100,6 +101,7 @@ public class CustomFishingPluginImpl extends CustomFishingPlugin { this.statisticsManager = new StatisticsManagerImpl(this); this.coolDownManager = new CoolDownManager(this); this.totemManager = new TotemManagerImpl(this); + this.hookManager = new HookManagerImpl(this); this.reload(); if (CFConfig.updateChecker) this.versionManager.checkUpdate().thenAccept(result -> { @@ -129,6 +131,7 @@ public class CustomFishingPluginImpl extends CustomFishingPlugin { ((StatisticsManagerImpl) this.statisticsManager).disable(); ((ActionManagerImpl) this.actionManager).disable(); ((TotemManagerImpl) this.totemManager).disable(); + ((HookManagerImpl) this.hookManager).disable(); this.coolDownManager.disable(); this.commandManager.unload(); HandlerList.unregisterAll(this); @@ -170,6 +173,8 @@ public class CustomFishingPluginImpl extends CustomFishingPlugin { ((StatisticsManagerImpl) this.statisticsManager).load(); ((PlaceholderManagerImpl) this.placeholderManager).unload(); ((PlaceholderManagerImpl) this.placeholderManager).load(); + ((HookManagerImpl) this.hookManager).unload(); + ((HookManagerImpl) this.hookManager).load(); this.commandManager.unload(); this.commandManager.load(); this.coolDownManager.unload(); @@ -177,24 +182,24 @@ public class CustomFishingPluginImpl extends CustomFishingPlugin { } private void loadDependencies() { - String libRepo = TimeZone.getDefault().getID().startsWith("Asia") ? + String mavenRepo = TimeZone.getDefault().getID().startsWith("Asia") ? "https://maven.aliyun.com/repository/public/" : "https://repo.maven.apache.org/maven2/"; LibraryLoader.loadDependencies( - "org.apache.commons:commons-pool2:2.11.1", libRepo, - "redis.clients:jedis:4.4.2", libRepo, - "dev.dejvokep:boosted-yaml:1.3.1", libRepo, - "com.zaxxer:HikariCP:5.0.1", libRepo, - "net.objecthunter:exp4j:0.4.8", libRepo, - "org.mariadb.jdbc:mariadb-java-client:3.1.4", libRepo, - "mysql:mysql-connector-java:8.0.30", libRepo, - "commons-io:commons-io:2.13.0", libRepo, - "com.google.code.gson:gson:2.10.1", libRepo, - "com.h2database:h2:2.2.220", libRepo, - "org.mongodb:mongodb-driver-sync:4.10.2", libRepo, - "org.mongodb:mongodb-driver-core:4.10.2", libRepo, - "org.mongodb:bson:4.10.2", libRepo, - "org.xerial:sqlite-jdbc:3.42.0.0", libRepo, - "dev.jorel:commandapi-bukkit-shade:9.1.0", libRepo + "org.apache.commons:commons-pool2:2.11.1", mavenRepo, + "redis.clients:jedis:5.0.0", mavenRepo, + "dev.dejvokep:boosted-yaml:1.3.1", mavenRepo, + "com.zaxxer:HikariCP:5.0.1", mavenRepo, + "net.objecthunter:exp4j:0.4.8", mavenRepo, + "org.mariadb.jdbc:mariadb-java-client:3.2.0", mavenRepo, + "mysql:mysql-connector-java:8.0.30", mavenRepo, + "commons-io:commons-io:2.13.0", mavenRepo, + "com.google.code.gson:gson:2.10.1", mavenRepo, + "com.h2database:h2:2.2.220", mavenRepo, + "org.mongodb:mongodb-driver-sync:4.10.2", mavenRepo, + "org.mongodb:mongodb-driver-core:4.10.2", mavenRepo, + "org.mongodb:bson:4.10.2", mavenRepo, + "org.xerial:sqlite-jdbc:3.42.0.0", mavenRepo, + "dev.jorel:commandapi-bukkit-shade:9.1.0", mavenRepo ); } diff --git a/plugin/src/main/java/net/momirealms/customfishing/command/sub/ItemCommand.java b/plugin/src/main/java/net/momirealms/customfishing/command/sub/ItemCommand.java index a6389866..b3a86140 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/command/sub/ItemCommand.java +++ b/plugin/src/main/java/net/momirealms/customfishing/command/sub/ItemCommand.java @@ -27,8 +27,8 @@ import net.momirealms.customfishing.api.CustomFishingPlugin; import net.momirealms.customfishing.api.common.Key; import net.momirealms.customfishing.api.mechanic.condition.Condition; import net.momirealms.customfishing.api.mechanic.item.BuildableItem; -import net.momirealms.customfishing.mechanic.item.ItemManagerImpl; import net.momirealms.customfishing.setting.CFLocale; +import net.momirealms.customfishing.util.ItemUtils; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -48,7 +48,8 @@ public class ItemCommand { getSubCommand("item"), getSubCommand("util"), getSubCommand("bait"), - getSubCommand("rod") + getSubCommand("rod"), + getSubCommand("hook") ); } @@ -80,7 +81,7 @@ public class ItemCommand { int amount = (int) args.getOrDefault("amount", 1); ItemStack item = CustomFishingPlugin.get().getItemManager().build(player, namespace, id, new Condition(player).getArgs()); if (item != null) { - int actual = ItemManagerImpl.giveCertainAmountOfItem(player, item, amount); + int actual = ItemUtils.giveCertainAmountOfItem(player, item, amount); AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, CFLocale.MSG_Get_Item.replace("{item}", id).replace("{amount}", String.valueOf(actual))); } else { AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, CFLocale.MSG_Item_Not_Exists); @@ -106,7 +107,7 @@ public class ItemCommand { assert players != null; for (Player player : players) { ItemStack item = CustomFishingPlugin.get().getItemManager().build(player, namespace, id, new Condition(player).getArgs()); - int actual = ItemManagerImpl.giveCertainAmountOfItem(player, item, amount); + int actual = ItemUtils.giveCertainAmountOfItem(player, item, amount); AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, CFLocale.MSG_Give_Item.replace("{item}", id).replace("{amount}", String.valueOf(actual)).replace("{player}", player.getName())); } } else { diff --git a/plugin/src/main/java/net/momirealms/customfishing/libraries/libraryloader/LibraryLoader.java b/plugin/src/main/java/net/momirealms/customfishing/libraries/libraryloader/LibraryLoader.java index 3bc61b80..3ab873c3 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/libraries/libraryloader/LibraryLoader.java +++ b/plugin/src/main/java/net/momirealms/customfishing/libraries/libraryloader/LibraryLoader.java @@ -88,7 +88,7 @@ public final class LibraryLoader { } public static void load(Dependency d) { - LogUtils.info(String.format("Loading dependency %s:%s:%s from %s", d.groupId, d.artifactId, d.version, d.repoUrl)); + LogUtils.info(String.format("Loading dependency %s:%s:%s", d.groupId, d.artifactId, d.version)); String name = d.artifactId() + "-" + d.version(); File saveLocation = new File(getLibFolder(d), name + ".jar"); if (!saveLocation.exists()) { diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/action/ActionManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/action/ActionManagerImpl.java index 489aef76..721ad13e 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/action/ActionManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/action/ActionManagerImpl.java @@ -34,7 +34,6 @@ import net.momirealms.customfishing.api.mechanic.requirement.Requirement; import net.momirealms.customfishing.api.util.LogUtils; import net.momirealms.customfishing.compatibility.VaultHook; import net.momirealms.customfishing.compatibility.papi.PlaceholderManagerImpl; -import net.momirealms.customfishing.mechanic.item.ItemManagerImpl; import net.momirealms.customfishing.setting.CFLocale; import net.momirealms.customfishing.util.*; import org.bukkit.Bukkit; @@ -463,9 +462,9 @@ public class ActionManagerImpl implements ActionManager { Player player = condition.getPlayer(); ItemStack itemStack = player.getInventory().getItem(slot); if (amount > 0) { - ItemUtils.addDurability(itemStack, amount); + ItemUtils.addDurability(itemStack, amount, true); } else { - ItemUtils.loseDurability(itemStack, -amount); + ItemUtils.loseDurability(itemStack, -amount, true); } }; } else { @@ -483,7 +482,7 @@ public class ActionManagerImpl implements ActionManager { return condition -> { if (Math.random() > chance) return; Player player = condition.getPlayer(); - ItemManagerImpl.giveCertainAmountOfItem(player, CustomFishingPlugin.get().getItemManager().buildAnyItemByID(player, id), amount); + ItemUtils.giveCertainAmountOfItem(player, CustomFishingPlugin.get().getItemManager().buildAnyItemByID(player, id), amount); }; } else { LogUtils.warn("Illegal value format found at action: give-item"); diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/block/BlockManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/block/BlockManagerImpl.java index 2c503dfc..2f9694ad 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/block/BlockManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/block/BlockManagerImpl.java @@ -134,7 +134,6 @@ public class BlockManagerImpl implements BlockManager, Listener { public void load() { this.loadConfig(); Bukkit.getPluginManager().registerEvents(this, plugin); - LogUtils.info("Loaded " + blockConfigMap.size() + " blocks."); } private void registerInbuiltProperties() { diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/competition/CompetitionManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/competition/CompetitionManagerImpl.java index d3bb32eb..17d9f1aa 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/competition/CompetitionManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/competition/CompetitionManagerImpl.java @@ -64,7 +64,6 @@ public class CompetitionManagerImpl implements CompetitionManager { 1, TimeUnit.SECONDS ); - LogUtils.info("Loaded " + commandConfigMap.size() + " competitions."); } public void unload() { diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/effect/EffectManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/effect/EffectManagerImpl.java index ff0b66d5..23abeac5 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/effect/EffectManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/effect/EffectManagerImpl.java @@ -72,7 +72,7 @@ public class EffectManagerImpl implements EffectManager { @SuppressWarnings("DuplicatedCode") public void load() { Deque fileDeque = new ArrayDeque<>(); - for (String type : List.of("rod", "bait", "enchant", "util", "totem")) { + for (String type : List.of("rod", "bait", "enchant", "util", "totem", "hook")) { File typeFolder = new File(plugin.getDataFolder() + File.separator + "contents" + File.separator + type); if (!typeFolder.exists()) { if (!typeFolder.mkdirs()) return; diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/entity/EntityManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/entity/EntityManagerImpl.java index afd8c765..e7baee0b 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/entity/EntityManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/entity/EntityManagerImpl.java @@ -48,7 +48,6 @@ public class EntityManagerImpl implements EntityManager { public void load() { this.loadConfig(); - LogUtils.info("Loaded " + entityConfigMap.size() + " entities."); } public void unload() { diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/FishingManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/FishingManagerImpl.java index a8211c65..914605a2 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/FishingManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/FishingManagerImpl.java @@ -229,7 +229,7 @@ public class FishingManagerImpl implements Listener, FishingManager { if (compound != null && compound.hasTag("max_dur")) { event.setCancelled(true); hook.remove(); - ItemUtils.loseDurability(itemStack, 2); + ItemUtils.loseDurability(itemStack, 2, true); } } } @@ -330,7 +330,7 @@ public class FishingManagerImpl implements Listener, FishingManager { if (nbtCompound != null && nbtCompound.hasTag("max_dur")) { event.getHook().remove(); event.setCancelled(true); - ItemUtils.loseDurability(itemStack, 5); + ItemUtils.loseDurability(itemStack, 5, true); } } } @@ -479,7 +479,8 @@ public class FishingManagerImpl implements Listener, FishingManager { if (damageEvent.isCancelled()) { break outer; } - ItemUtils.loseDurability(rod, 1); + ItemUtils.reduceHookDurability(rod, false); + ItemUtils.loseDurability(rod, 1, true); } fishHook.remove(); @@ -518,6 +519,8 @@ public class FishingManagerImpl implements Listener, FishingManager { GlobalSettings.triggerLootActions(ActionTrigger.FAILURE, fishingPreparation); loot.triggerActions(ActionTrigger.FAILURE, fishingPreparation); fishingPreparation.triggerActions(ActionTrigger.FAILURE); + + ItemUtils.reduceHookDurability(fishingPreparation.getRodItemStack(), true); } public void success(TempFishingState state, FishHook hook) { @@ -687,6 +690,17 @@ public class FishingManagerImpl implements Listener, FishingManager { } } + @Override + public boolean hasPlayerCastHook(UUID uuid) { + FishHook fishHook = hookCacheMap.get(uuid); + if (fishHook == null) return false; + if (!fishHook.isValid()) { + hookCacheMap.remove(uuid); + return false; + } + return true; + } + @Override public void setTempFishingState(Player player, TempFishingState tempFishingState) { tempFishingStateMap.put(player.getUniqueId(), tempFishingState); diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/HookCheckTimerTask.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/HookCheckTimerTask.java index e3eb3679..0aeb666f 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/HookCheckTimerTask.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/fishing/HookCheckTimerTask.java @@ -161,6 +161,9 @@ public class HookCheckTimerTask implements Runnable { this.loot = nextLoot; fishingPreparation.insertArg("{nick}", nextLoot.getNick()); fishingPreparation.insertArg("{loot}", nextLoot.getID()); + fishingPreparation.insertArg("{x}", String.valueOf(fishHook.getLocation().getBlockX())); + fishingPreparation.insertArg("{y}", String.valueOf(fishHook.getLocation().getBlockY())); + fishingPreparation.insertArg("{z}", String.valueOf(fishHook.getLocation().getBlockZ())); CustomFishingPlugin.get().getScheduler().runTaskAsync(() -> manager.setTempFishingState(fishingPreparation.getPlayer(), new TempFishingState( initialEffect, fishingPreparation, diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/game/GameManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/game/GameManagerImpl.java index 480c16f7..af9c4250 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/game/GameManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/game/GameManagerImpl.java @@ -162,7 +162,7 @@ public class GameManagerImpl implements GameManager { var totalWidth = chances.size() * widthPerSection - 1; var pointerOffset = section.getInt("arguments.pointer-offset"); var pointerWidth = section.getInt("arguments.pointer-width"); - var title = section.getString("title"); + var title = section.getStringList("title"); var font = section.getString("subtitle.font"); var barImage = section.getString("subtitle.bar"); var pointerImage = section.getString("subtitle.pointer"); @@ -171,6 +171,7 @@ public class GameManagerImpl implements GameManager { private int progress; private boolean face; + private String sendTitle = title.get(ThreadLocalRandom.current().nextInt(title.size())); @Override public void arrangeTask() { @@ -203,7 +204,7 @@ public class GameManagerImpl implements GameManager { + OffsetUtils.getOffsetChars(pointerOffset + progress) + FontUtils.surroundWithFont(pointerImage, font) + OffsetUtils.getOffsetChars(totalWidth - progress - pointerWidth); - AdventureManagerImpl.getInstance().sendTitle(player, title, bar,0,500,0); + AdventureManagerImpl.getInstance().sendTitle(player, sendTitle, bar,0,500,0); } @Override diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/hook/HookManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/hook/HookManagerImpl.java new file mode 100644 index 00000000..7feacafa --- /dev/null +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/hook/HookManagerImpl.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customfishing.mechanic.hook; + +import de.tr7zw.changeme.nbtapi.NBTCompound; +import de.tr7zw.changeme.nbtapi.NBTItem; +import net.momirealms.customfishing.api.CustomFishingPlugin; +import net.momirealms.customfishing.api.manager.HookManager; +import net.momirealms.customfishing.api.manager.RequirementManager; +import net.momirealms.customfishing.api.mechanic.condition.Condition; +import net.momirealms.customfishing.api.mechanic.effect.EffectCarrier; +import net.momirealms.customfishing.api.mechanic.hook.HookSetting; +import net.momirealms.customfishing.util.ItemUtils; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.*; + +public class HookManagerImpl implements Listener, HookManager { + + private final CustomFishingPlugin plugin; + private final HashMap hookSettingMap; + + public HookManagerImpl(CustomFishingPlugin plugin) { + this.plugin = plugin; + this.hookSettingMap = new HashMap<>(); + } + + public void load() { + Bukkit.getPluginManager().registerEvents(this, plugin); + loadConfig(); + } + + public void unload() { + HandlerList.unregisterAll(this); + hookSettingMap.clear(); + } + + public void disable() { + unload(); + } + + @SuppressWarnings("DuplicatedCode") + private void loadConfig() { + Deque fileDeque = new ArrayDeque<>(); + for (String type : List.of("hook")) { + File typeFolder = new File(plugin.getDataFolder() + File.separator + "contents" + File.separator + type); + if (!typeFolder.exists()) { + if (!typeFolder.mkdirs()) return; + plugin.saveResource("contents" + File.separator + type + File.separator + "default.yml", false); + } + fileDeque.push(typeFolder); + while (!fileDeque.isEmpty()) { + File file = fileDeque.pop(); + File[] files = file.listFiles(); + if (files == null) continue; + for (File subFile : files) { + if (subFile.isDirectory()) { + fileDeque.push(subFile); + } else if (subFile.isFile() && subFile.getName().endsWith(".yml")) { + this.loadSingleFile(subFile); + } + } + } + } + } + + private void loadSingleFile(File file) { + YamlConfiguration config = YamlConfiguration.loadConfiguration(file); + for (Map.Entry entry : config.getValues(false).entrySet()) { + if (entry.getValue() instanceof ConfigurationSection section) { + var setting = new HookSetting.Builder(entry.getKey()) + .durability(section.getInt("max-durability", 16)) + .lore(section.getStringList("lore-on-rod").stream().map(it -> "" + it).toList()) + .build(); + hookSettingMap.put(entry.getKey(), setting); + } + } + } + + @Nullable + @Override + public HookSetting getHookSetting(String id) { + return hookSettingMap.get(id); + } + + @EventHandler + public void onDragDrop(InventoryClickEvent event) { + if (event.isCancelled()) + return; + final Player player = (Player) event.getWhoClicked(); + if (event.getClickedInventory() != player.getInventory()) + return; + ItemStack clicked = event.getCurrentItem(); + if (clicked == null || clicked.getType() != Material.FISHING_ROD) + return; + if (player.getGameMode() != GameMode.SURVIVAL) + return; + + ItemStack cursor = event.getCursor(); + if (cursor == null || cursor.getType() == Material.AIR) { + if (event.getClick() == ClickType.RIGHT) { + if (plugin.getFishingManager().hasPlayerCastHook(player.getUniqueId())) { + return; + } + + NBTItem nbtItem = new NBTItem(clicked); + NBTCompound cfCompound = nbtItem.getCompound("CustomFishing"); + if (cfCompound == null) + return; + if (cfCompound.hasTag("hook_id")) { + event.setCancelled(true); + ItemStack hook = cfCompound.getItemStack("hook_item"); + ItemUtils.setDurability(hook, cfCompound.getInteger("hook_dur"), true); + cfCompound.removeKey("hook_id"); + cfCompound.removeKey("hook_item"); + cfCompound.removeKey("hook_dur"); + event.setCursor(hook); + ItemUtils.updateNBTItemLore(nbtItem); + clicked.setItemMeta(nbtItem.getItem().getItemMeta()); + } + } + return; + } + + String hookID = plugin.getItemManager().getAnyItemID(cursor); + HookSetting setting = getHookSetting(hookID); + if (setting == null) + return; + + Condition condition = new Condition(player, new HashMap<>()); + condition.insertArg("{rod}", plugin.getItemManager().getAnyItemID(clicked)); + EffectCarrier effectCarrier = plugin.getEffectManager().getEffect("hook", hookID); + if (effectCarrier != null) { + if (!RequirementManager.isRequirementsMet(effectCarrier.getRequirements(), condition)) { + return; + } + } + + event.setCancelled(true); + + NBTItem rodNBTItem = new NBTItem(clicked); + NBTCompound cfCompound = rodNBTItem.getOrCreateCompound("CustomFishing"); + String previousHookID = cfCompound.getString("hook_id"); + + ItemStack clonedHook = cursor.clone(); + clonedHook.setAmount(1); + cursor.setAmount(cursor.getAmount() - 1); + + if (previousHookID != null && !previousHookID.equals("")) { + int previousHookDurability = cfCompound.getInteger("hook_dur"); + ItemStack previousItemStack = cfCompound.getItemStack("hook_item"); + ItemUtils.setDurability(previousItemStack, previousHookDurability, true); + if (cursor.getAmount() == 0) { + event.setCursor(previousItemStack); + } else { + ItemUtils.giveCertainAmountOfItem(player, previousItemStack, 1); + } + } + + cfCompound.setString("hook_id", hookID); + cfCompound.setItemStack("hook_item", clonedHook); + cfCompound.setInteger("hook_dur", ItemUtils.getDurability(clonedHook)); + + ItemUtils.updateNBTItemLore(rodNBTItem); + clicked.setItemMeta(rodNBTItem.getItem().getItemMeta()); + } +} diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/item/ItemManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/item/ItemManagerImpl.java index 5d4d0617..e852091f 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/item/ItemManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/item/ItemManagerImpl.java @@ -60,9 +60,7 @@ import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.event.player.PlayerItemMendEvent; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.Damageable; -import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -89,7 +87,6 @@ public class ItemManagerImpl implements ItemManager, Listener { public void load() { this.loadItemsFromPluginFolder(); - LogUtils.info("Loaded " + buildableItemMap.size() + " items."); Bukkit.getPluginManager().registerEvents(this, plugin); } @@ -117,7 +114,7 @@ public class ItemManagerImpl implements ItemManager, Listener { @SuppressWarnings("DuplicatedCode") public void loadItemsFromPluginFolder() { Deque fileDeque = new ArrayDeque<>(); - for (String type : List.of("item", "bait", "rod", "util")) { + for (String type : List.of("item", "bait", "rod", "util", "hook")) { File typeFolder = new File(plugin.getDataFolder() + File.separator + "contents" + File.separator + type); if (!typeFolder.exists()) { if (!typeFolder.mkdirs()) return; @@ -216,6 +213,13 @@ public class ItemManagerImpl implements ItemManager, Listener { } } + @Override + public boolean isCustomFishingItem(ItemStack itemStack) { + if (itemStack == null || itemStack.getType() == Material.AIR) return false; + NBTItem nbtItem = new NBTItem(itemStack); + return nbtItem.hasTag("CustomFishing"); + } + @Nullable @Override public String getItemID(ItemStack itemStack) { @@ -269,6 +273,7 @@ public class ItemManagerImpl implements ItemManager, Listener { for (ItemBuilder.ItemPropertyEditor editor : builder.getEditors()) { editor.edit(player, nbtItem, placeholders); } + ItemUtils.updateNBTItemLore(nbtItem); return nbtItem.getItem(); } @@ -631,70 +636,6 @@ public class ItemManagerImpl implements ItemManager, Listener { } } - public static int giveCertainAmountOfItem(Player player, ItemStack itemStack, int amount) { - PlayerInventory inventory = player.getInventory(); - ItemMeta meta = itemStack.getItemMeta(); - int maxStackSize = itemStack.getMaxStackSize(); - - if (amount > maxStackSize * 100) { - LogUtils.warn("Detected too many items spawning. Lowering the amount to " + (maxStackSize * 100)); - amount = maxStackSize * 100; - } - - int actualAmount = amount; - - for (ItemStack other : inventory.getStorageContents()) { - if (other != null) { - if (other.getType() == itemStack.getType() && other.getItemMeta().equals(meta)) { - if (other.getAmount() < maxStackSize) { - int delta = maxStackSize - other.getAmount(); - if (amount > delta) { - other.setAmount(maxStackSize); - amount -= delta; - } else { - other.setAmount(amount + other.getAmount()); - return actualAmount; - } - } - } - } - } - - if (amount > 0) { - for (ItemStack other : inventory.getStorageContents()) { - if (other == null) { - if (amount > maxStackSize) { - amount -= maxStackSize; - ItemStack cloned = itemStack.clone(); - cloned.setAmount(maxStackSize); - inventory.addItem(cloned); - } else { - ItemStack cloned = itemStack.clone(); - cloned.setAmount(amount); - inventory.addItem(cloned); - return actualAmount; - } - } - } - } - - if (amount > 0) { - for (int i = 0; i < amount / maxStackSize; i++) { - ItemStack cloned = itemStack.clone(); - cloned.setAmount(maxStackSize); - player.getWorld().dropItem(player.getLocation(), cloned); - } - int left = amount % maxStackSize; - if (left != 0) { - ItemStack cloned = itemStack.clone(); - cloned.setAmount(left); - player.getWorld().dropItem(player.getLocation(), cloned); - } - } - - return actualAmount; - } - @EventHandler public void onPickUp(PlayerAttemptPickupItemEvent event) { if (event.isCancelled()) return; @@ -756,7 +697,7 @@ public class ItemManagerImpl implements ItemManager, Listener { NBTCompound compound = nbtItem.getCompound("CustomFishing"); if (compound == null) return; event.setCancelled(true); - ItemUtils.addDurability(itemStack, event.getRepairAmount()); + ItemUtils.addDurability(itemStack, event.getRepairAmount(), true); } @EventHandler @@ -782,11 +723,4 @@ public class ItemManagerImpl implements ItemManager, Listener { action.trigger(condition); } } - - @Override - public boolean isCustomFishingItem(ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) return false; - NBTItem nbtItem = new NBTItem(itemStack); - return nbtItem.hasTag("CustomFishing"); - } } \ No newline at end of file diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/market/MarketGUI.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/market/MarketGUI.java index 4fb4bf9b..cb93943d 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/market/MarketGUI.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/market/MarketGUI.java @@ -22,7 +22,7 @@ import net.momirealms.customfishing.api.data.EarningData; import net.momirealms.customfishing.api.mechanic.market.MarketGUIHolder; import net.momirealms.customfishing.api.util.InventoryUtils; import net.momirealms.customfishing.api.util.LogUtils; -import net.momirealms.customfishing.mechanic.item.ItemManagerImpl; +import net.momirealms.customfishing.util.ItemUtils; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; @@ -197,7 +197,7 @@ public class MarketGUI { for (int slot : itemElement.getSlots()) { ItemStack itemStack = inventory.getItem(slot); if (itemStack != null && itemStack.getType() != Material.AIR) { - ItemManagerImpl.giveCertainAmountOfItem(owner, itemStack, itemStack.getAmount()); + ItemUtils.giveCertainAmountOfItem(owner, itemStack, itemStack.getAmount()); inventory.setItem(slot, new ItemStack(Material.AIR)); } } diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/requirement/RequirementManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/requirement/RequirementManagerImpl.java index 25564cd3..0519d7f7 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/requirement/RequirementManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/requirement/RequirementManagerImpl.java @@ -145,6 +145,8 @@ public class RequirementManagerImpl implements RequirementManager { this.registerRegexRequirement(); this.registerItemInHandRequirement(); this.registerMoneyRequirement(); + this.registerInBagRequirement(); + this.registerHookRequirement(); } public ConditionalElement getConditionalElements(ConfigurationSection section) { @@ -950,6 +952,40 @@ public class RequirementManagerImpl implements RequirementManager { }); } + private void registerHookRequirement() { + registerRequirement("hook", (args, actions, advanced) -> { + List hooks = ConfigUtils.stringListArgs(args); + return condition -> { + String id = condition.getArg("{hook}"); + if (hooks.contains(id)) return true; + if (advanced) triggerActions(actions, condition); + return false; + }; + }); + registerRequirement("!hook", (args, actions, advanced) -> { + List hooks = ConfigUtils.stringListArgs(args); + return condition -> { + String id = condition.getArg("{hook}"); + if (!hooks.contains(id)) return true; + if (advanced) triggerActions(actions, condition); + return false; + }; + }); + } + + private void registerInBagRequirement() { + registerRequirement("in-fishingbag", (args, actions, advanced) -> { + boolean arg = (boolean) args; + return condition -> { + String inBag = condition.getArg("{in-bag}"); + if (inBag == null && !arg) return true; + if (inBag != null && inBag.equals(String.valueOf(arg))) return true; + if (advanced) triggerActions(actions, condition); + return false; + }; + }); + } + private void registerPluginLevelRequirement() { registerRequirement("plugin-level", (args, actions, advanced) -> { if (args instanceof ConfigurationSection section) { diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/statistic/StatisticsManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/statistic/StatisticsManagerImpl.java index dabba5fa..ed8833cb 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/statistic/StatisticsManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/statistic/StatisticsManagerImpl.java @@ -21,7 +21,6 @@ import net.momirealms.customfishing.api.CustomFishingPlugin; import net.momirealms.customfishing.api.data.user.OnlineUser; import net.momirealms.customfishing.api.manager.StatisticsManager; import net.momirealms.customfishing.api.mechanic.statistic.Statistics; -import net.momirealms.customfishing.api.util.LogUtils; import org.bukkit.configuration.file.YamlConfiguration; import org.jetbrains.annotations.Nullable; @@ -40,7 +39,6 @@ public class StatisticsManagerImpl implements StatisticsManager { public void load() { this.loadCategoriesFromPluginFolder(); - LogUtils.info("Loaded " + categoryMap.size() + " categories."); } public void unload() { diff --git a/plugin/src/main/java/net/momirealms/customfishing/setting/CFConfig.java b/plugin/src/main/java/net/momirealms/customfishing/setting/CFConfig.java index ab93ce83..b84ca6ef 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/setting/CFConfig.java +++ b/plugin/src/main/java/net/momirealms/customfishing/setting/CFConfig.java @@ -40,7 +40,7 @@ import java.util.Objects; public class CFConfig { // config version - public static String configVersion = "26"; + public static String configVersion = "27"; // language public static String language; @@ -89,6 +89,8 @@ public class CFConfig { // Legacy color code support public static boolean legacyColorSupport; + // Durability lore + public static List durabilityLore; public static void load() { try { @@ -147,6 +149,8 @@ public class CFConfig { lockData = config.getBoolean("other-settings.lock-data", true); legacyColorSupport = config.getBoolean("other-settings.legacy-color-code-support", false); + durabilityLore = config.getStringList("other-settings.custom-durability-format").stream().map(it -> "" + it).toList(); + OffsetUtils.loadConfig(config.getConfigurationSection("other-settings.offset-characters")); } } diff --git a/plugin/src/main/java/net/momirealms/customfishing/util/ItemUtils.java b/plugin/src/main/java/net/momirealms/customfishing/util/ItemUtils.java index 969af453..7bf42a6f 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/util/ItemUtils.java +++ b/plugin/src/main/java/net/momirealms/customfishing/util/ItemUtils.java @@ -19,66 +19,254 @@ package net.momirealms.customfishing.util; import de.tr7zw.changeme.nbtapi.NBTCompound; import de.tr7zw.changeme.nbtapi.NBTItem; +import de.tr7zw.changeme.nbtapi.NBTList; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ScoreComponent; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.momirealms.customfishing.adventure.AdventureManagerImpl; +import net.momirealms.customfishing.api.CustomFishingPlugin; +import net.momirealms.customfishing.api.mechanic.hook.HookSetting; +import net.momirealms.customfishing.api.util.LogUtils; +import net.momirealms.customfishing.setting.CFConfig; +import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.Damageable; +import org.bukkit.inventory.meta.ItemMeta; public class ItemUtils { - public static void loseDurability(ItemStack itemStack, int amount) { - if (itemStack.getItemMeta() instanceof Damageable damageable) { - if (damageable.isUnbreakable()) { - return; - } - int unBreakingLevel = itemStack.getEnchantmentLevel(Enchantment.DURABILITY); - if (Math.random() > (double) 1 / (unBreakingLevel + 1)) { - return; - } + public static NBTItem updateNBTItemLore(NBTItem nbtItem) { + NBTCompound cfCompound = nbtItem.getCompound("CustomFishing"); + if (cfCompound == null) + return nbtItem; - NBTItem nbtItem = new NBTItem(itemStack); - NBTCompound cfCompound = nbtItem.getCompound("CustomFishing"); - if (cfCompound != null && cfCompound.hasTag("max_dur")) { - int max = cfCompound.getInteger("max_dur"); - int current = cfCompound.getInteger("cur_dur") - amount; - cfCompound.setInteger("cur_dur", current); - int damage = (int) (itemStack.getType().getMaxDurability() * (1 - ((double) current / max))); - nbtItem.setInteger("Damage", damage); - if (current > 0) { - itemStack.setItemMeta(nbtItem.getItem().getItemMeta()); - } else { - itemStack.setAmount(0); - } + boolean hasLoreUpdate = cfCompound.hasTag("hook_id") || cfCompound.hasTag("max_dur"); + if (!hasLoreUpdate) return nbtItem; + + NBTCompound displayCompound = nbtItem.getOrCreateCompound("display"); + NBTList lore = displayCompound.getStringList("Lore"); + lore.removeIf(it -> GsonComponentSerializer.gson().deserialize(it) instanceof ScoreComponent scoreComponent && scoreComponent.name().equals("cf")); + + if (cfCompound.hasTag("hook_id")) { + String hookID = cfCompound.getString("hook_id"); + HookSetting setting = CustomFishingPlugin.get().getHookManager().getHookSetting(hookID); + if (setting == null) { + cfCompound.removeKey("hook_id"); + cfCompound.removeKey("hook_item"); + cfCompound.removeKey("hook_dur"); } else { - int damage = damageable.getDamage() + amount; - if (damage > itemStack.getType().getMaxDurability()) { - itemStack.setAmount(0); - } else { - damageable.setDamage(damage); - itemStack.setItemMeta(damageable); + for (String newLore : setting.getLore()) { + ScoreComponent.Builder builder = Component.score().name("cf").objective("hook"); + builder.append(AdventureManagerImpl.getInstance().getComponentFromMiniMessage( + newLore.replace("{dur}", String.valueOf(cfCompound.getInteger("hook_dur"))) + .replace("{max}", String.valueOf(setting.getMaxDurability())) + )); + lore.add(GsonComponentSerializer.gson().serialize(builder.build())); } } } + + if (cfCompound.hasTag("max_dur")) { + int max = cfCompound.getInteger("max_dur"); + int current = cfCompound.getInteger("cur_dur"); + for (String newLore : CFConfig.durabilityLore) { + ScoreComponent.Builder builder = Component.score().name("cf").objective("durability"); + builder.append(AdventureManagerImpl.getInstance().getComponentFromMiniMessage( + newLore.replace("{dur}", String.valueOf(current)) + .replace("{max}", String.valueOf(max)) + )); + lore.add(GsonComponentSerializer.gson().serialize(builder.build())); + } + } + return nbtItem; } - public static void addDurability(ItemStack itemStack, int amount) { - if (itemStack.getItemMeta() instanceof Damageable damageable) { - if (damageable.isUnbreakable()) { - return; + public static void updateItemLore(ItemStack itemStack) { + if (itemStack == null || itemStack.getType() == Material.AIR) + return; + NBTItem nbtItem = updateNBTItemLore(new NBTItem(itemStack)); + itemStack.setItemMeta(nbtItem.getItem().getItemMeta()); + } + + public static void reduceHookDurability(ItemStack itemStack, boolean updateLore) { + if (itemStack == null || itemStack.getType() == Material.AIR) + return; + NBTItem nbtItem = new NBTItem(itemStack); + NBTCompound cfCompound = nbtItem.getCompound("CustomFishing"); + if (cfCompound != null && cfCompound.hasTag("hook_dur")) { + int hookDur = cfCompound.getInteger("hook_dur"); + if (hookDur > 0) { + cfCompound.setInteger("hook_dur", hookDur - 1); + } else if (hookDur != -1) { + cfCompound.removeKey("hook_id"); + cfCompound.removeKey("hook_dur"); + cfCompound.removeKey("hook_id"); } - NBTItem nbtItem = new NBTItem(itemStack); - NBTCompound cfCompound = nbtItem.getCompound("CustomFishing"); - if (cfCompound != null && cfCompound.hasTag("max_dur")) { - int max = cfCompound.getInteger("max_dur"); - int current = Math.min(max, cfCompound.getInteger("cur_dur") + amount); - cfCompound.setInteger("cur_dur", current); - int damage = (int) (itemStack.getType().getMaxDurability() * (1 - ((double) current / max))); - nbtItem.setInteger("Damage", damage); + } + if (updateLore) updateNBTItemLore(nbtItem); + itemStack.setItemMeta(nbtItem.getItem().getItemMeta()); + } + + public static void loseDurability(ItemStack itemStack, int amount, boolean updateLore) { + if (itemStack == null || itemStack.getType() == Material.AIR) + return; + int unBreakingLevel = itemStack.getEnchantmentLevel(Enchantment.DURABILITY); + if (Math.random() > (double) 1 / (unBreakingLevel + 1)) { + return; + } + NBTItem nbtItem = new NBTItem(itemStack); + if (nbtItem.getByte("Unbreakable") == 1) { + return; + } + NBTCompound cfCompound = nbtItem.getCompound("CustomFishing"); + if (cfCompound != null && cfCompound.hasTag("max_dur")) { + int max = cfCompound.getInteger("max_dur"); + int current = cfCompound.getInteger("cur_dur") - amount; + cfCompound.setInteger("cur_dur", current); + int damage = (int) (itemStack.getType().getMaxDurability() * (1 - ((double) current / max))); + nbtItem.setInteger("Damage", damage); + if (current > 0) { + if (updateLore) updateNBTItemLore(nbtItem); itemStack.setItemMeta(nbtItem.getItem().getItemMeta()); } else { - int damage = Math.max(damageable.getDamage() - amount, 0); - damageable.setDamage(damage); - itemStack.setItemMeta(damageable); + itemStack.setAmount(0); + } + } else { + int damage = nbtItem.getInteger("Damage") + amount; + if (damage > itemStack.getType().getMaxDurability()) { + itemStack.setAmount(0); + } else { + nbtItem.setInteger("Damage", damage); + itemStack.setItemMeta(nbtItem.getItem().getItemMeta()); } } } + + public static void addDurability(ItemStack itemStack, int amount, boolean updateLore) { + if (itemStack == null || itemStack.getType() == Material.AIR) + return; + NBTItem nbtItem = new NBTItem(itemStack); + if (nbtItem.getByte("Unbreakable") == 1) { + return; + } + NBTCompound cfCompound = nbtItem.getCompound("CustomFishing"); + if (cfCompound != null && cfCompound.hasTag("max_dur")) { + int max = cfCompound.getInteger("max_dur"); + int current = Math.min(max, cfCompound.getInteger("cur_dur") + amount); + cfCompound.setInteger("cur_dur", current); + int damage = (int) (itemStack.getType().getMaxDurability() * (1 - ((double) current / max))); + nbtItem.setInteger("Damage", damage); + if (updateLore) updateNBTItemLore(nbtItem); + } else { + int damage = Math.max(nbtItem.getInteger("Damage") - amount, 0); + nbtItem.setInteger("Damage", damage); + } + itemStack.setItemMeta(nbtItem.getItem().getItemMeta()); + } + + public static void setDurability(ItemStack itemStack, int amount, boolean updateLore) { + if (itemStack == null || itemStack.getType() == Material.AIR) + return; + if (amount <= 0) { + itemStack.setAmount(0); + return; + } + NBTItem nbtItem = new NBTItem(itemStack); + if (nbtItem.getByte("Unbreakable") == 1) { + return; + } + NBTCompound cfCompound = nbtItem.getCompound("CustomFishing"); + if (cfCompound != null && cfCompound.hasTag("max_dur")) { + int max = cfCompound.getInteger("max_dur"); + amount = Math.min(amount, max); + cfCompound.setInteger("cur_dur", amount); + int damage = (int) (itemStack.getType().getMaxDurability() * (1 - ((double) amount / max))); + nbtItem.setInteger("Damage", damage); + if (updateLore) updateNBTItemLore(nbtItem); + } else { + nbtItem.setInteger("Damage", itemStack.getType().getMaxDurability() - amount); + } + itemStack.setItemMeta(nbtItem.getItem().getItemMeta()); + } + + public static int getDurability(ItemStack itemStack) { + if (!(itemStack.getItemMeta() instanceof Damageable damageable)) + return -1; + if (damageable.isUnbreakable()) + return -1; + NBTItem nbtItem = new NBTItem(itemStack); + NBTCompound cfCompound = nbtItem.getCompound("CustomFishing"); + if (cfCompound != null && cfCompound.hasTag("max_dur")) { + return cfCompound.getInteger("cur_dur"); + } else { + return itemStack.getType().getMaxDurability() - damageable.getDamage(); + } + } + + public static int giveCertainAmountOfItem(Player player, ItemStack itemStack, int amount) { + PlayerInventory inventory = player.getInventory(); + ItemMeta meta = itemStack.getItemMeta(); + int maxStackSize = itemStack.getMaxStackSize(); + + if (amount > maxStackSize * 100) { + LogUtils.warn("Detected too many items spawning. Lowering the amount to " + (maxStackSize * 100)); + amount = maxStackSize * 100; + } + + int actualAmount = amount; + + for (ItemStack other : inventory.getStorageContents()) { + if (other != null) { + if (other.getType() == itemStack.getType() && other.getItemMeta().equals(meta)) { + if (other.getAmount() < maxStackSize) { + int delta = maxStackSize - other.getAmount(); + if (amount > delta) { + other.setAmount(maxStackSize); + amount -= delta; + } else { + other.setAmount(amount + other.getAmount()); + return actualAmount; + } + } + } + } + } + + if (amount > 0) { + for (ItemStack other : inventory.getStorageContents()) { + if (other == null) { + if (amount > maxStackSize) { + amount -= maxStackSize; + ItemStack cloned = itemStack.clone(); + cloned.setAmount(maxStackSize); + inventory.addItem(cloned); + } else { + ItemStack cloned = itemStack.clone(); + cloned.setAmount(amount); + inventory.addItem(cloned); + return actualAmount; + } + } + } + } + + if (amount > 0) { + for (int i = 0; i < amount / maxStackSize; i++) { + ItemStack cloned = itemStack.clone(); + cloned.setAmount(maxStackSize); + player.getWorld().dropItem(player.getLocation(), cloned); + } + int left = amount % maxStackSize; + if (left != 0) { + ItemStack cloned = itemStack.clone(); + cloned.setAmount(left); + player.getWorld().dropItem(player.getLocation(), cloned); + } + } + + return actualAmount; + } } diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml index 3560deeb..2b34a65d 100644 --- a/plugin/src/main/resources/config.yml +++ b/plugin/src/main/resources/config.yml @@ -1,6 +1,6 @@ # Developer: @Xiao-MoMi # Wiki: https://mo-mi.gitbook.io/xiaomomi-plugins/ -config-version: '26' +config-version: '27' # Debug debug: false @@ -168,6 +168,10 @@ other-settings: block-detection-order: - vanilla + custom-durability-format: + - '' + - 'Durability: {dur} / {max}' + # Offset characters' unicodes # Never edit this unless you know what you are doing offset-characters: diff --git a/plugin/src/main/resources/contents/hook/default.yml b/plugin/src/main/resources/contents/hook/default.yml new file mode 100644 index 00000000..9c8f27e5 --- /dev/null +++ b/plugin/src/main/resources/contents/hook/default.yml @@ -0,0 +1,25 @@ +delicate_hook: + material: SHEARS + display: + name: '<#1E90FF>Delicate hook' + lore: + - '' + - '<#7FFFD4>Desciption:' + - ' - An embodiment of craftsmanship and allure, the hook' + - ' - is not your average piece of tackle. Polished to' + - ' - perfection and intricately designed, it gleams in the' + - ' - water, irresistibly drawing high-quality fish closer.' + - '' + - '<#FFD700>Effects:' + - ' - Increase the chance of getting high quality fish' + max-durability: 16 + lore-on-rod: + - '' + - '<#7FFFAA>Equipped hook:' + - ' - Delicate hook: {dur} times left' + effects: + group: + type: group-mod + value: + - silver_star:+1 + - golden_star:+1 \ No newline at end of file diff --git a/plugin/src/main/resources/contents/rod/default.yml b/plugin/src/main/resources/contents/rod/default.yml index f6d7e767..bd71091f 100644 --- a/plugin/src/main/resources/contents/rod/default.yml +++ b/plugin/src/main/resources/contents/rod/default.yml @@ -29,6 +29,7 @@ beginner_rod: - ' - Increase the hook time' - ' - Reduces the challenge of fishing' custom-model-data: 50001 + max-durability: 64 effects: time_effect: type: hook-time @@ -51,6 +52,7 @@ silver_rod: - '<#FFD700>Effects:' - ' - Increase the chance of getting silver star fish' custom-model-data: 50002 + max-durability: 96 effects: group: type: group-mod @@ -71,6 +73,7 @@ golden_rod: - '<#FFD700>Effects:' - ' - Increase the chance of getting golden star fish' custom-model-data: 50003 + max-durability: 80 effects: group: type: group-mod @@ -93,6 +96,7 @@ star_rod: - '<#FFD700>Effects:' - ' - +15s Game Time' custom-model-data: 50004 + max-durability: 128 effects: time_effect: type: game-time @@ -116,6 +120,7 @@ bone_rod: - ' - Fishing in lava' - ' - Sometimes skeleton would grab the hook' custom-model-data: 50005 + max-durability: 32 effects: lava: type: lava-fishing @@ -141,6 +146,7 @@ magical_rod: - ' - 1x book bait' - ' - 10 exp levels' custom-model-data: 50006 + max-durability: 16 requirements: requirement_1: type: level @@ -191,6 +197,7 @@ master_rod: - ' - Increase the challenge of fishing' - ' - Higher chance of getting quality fish' custom-model-data: 50007 + max-durability: 128 effects: time_effect: type: hook-time