diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/ConfigManager.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/ConfigManager.java index 400194b8..b6e9781e 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/ConfigManager.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/ConfigManager.java @@ -46,6 +46,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.inventory.ItemStack; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; @@ -329,9 +330,9 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable { @Override public YamlDocument loadConfig(String filePath, char routeSeparator) { - try { + try (InputStream inputStream = new FileInputStream(resolveConfig(filePath).toFile())) { return YamlDocument.create( - resolveConfig(filePath).toFile(), + inputStream, plugin.getResourceStream(filePath), GeneralSettings.builder().setRouteSeparator(routeSeparator).build(), LoaderSettings @@ -352,8 +353,8 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable { @Override public YamlDocument loadData(File file) { - try { - return YamlDocument.create(file); + try (InputStream inputStream = new FileInputStream(file)) { + return YamlDocument.create(inputStream); } catch (IOException e) { plugin.getPluginLogger().severe("Failed to load config " + file, e); throw new RuntimeException(e); @@ -362,8 +363,8 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable { @Override public YamlDocument loadData(File file, char routeSeparator) { - try { - return YamlDocument.create(file, GeneralSettings.builder().setRouteSeparator(routeSeparator).build()); + try (InputStream inputStream = new FileInputStream(file)) { + return YamlDocument.create(inputStream, GeneralSettings.builder().setRouteSeparator(routeSeparator).build()); } catch (IOException e) { plugin.getPluginLogger().severe("Failed to load config " + file, e); throw new RuntimeException(e); diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/ItemConfigParser.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/ItemConfigParser.java index 8147451c..95ffc6be 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/ItemConfigParser.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/ItemConfigParser.java @@ -50,6 +50,11 @@ public class ItemConfigParser { this.id = id; this.material = section.getString("material"); if (!section.contains("tag")) section.set("tag", true); + if (!section.contains("nick")) { + if (section.contains("display.name")) { + section.set("nick", section.getString("display.name")); + } + } analyze(section, functionMap); } diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/Context.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/Context.java index 7fd0b0ad..460900e4 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/Context.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/Context.java @@ -76,6 +76,9 @@ public interface Context { @Nullable C arg(ContextKeys key); + @Nullable + C remove(ContextKeys key); + /** * Gets the holder of this context. * diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/ContextKeys.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/ContextKeys.java index 71bf5597..eefc8aa4 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/ContextKeys.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/ContextKeys.java @@ -54,10 +54,10 @@ public class ContextKeys { public static final ContextKeys SCORE = of("score", Double.class); public static final ContextKeys CUSTOM_SCORE = of("custom_score", Double.class); public static final ContextKeys RANK = of("rank", String.class); - public static final ContextKeys HOOK_LOCATION = of("hook_location", Location.class); - public static final ContextKeys HOOK_X = of("hook_x", Integer.class); - public static final ContextKeys HOOK_Y = of("hook_y", Integer.class); - public static final ContextKeys HOOK_Z = of("hook_z", Integer.class); + public static final ContextKeys OTHER_LOCATION = of("other_location", Location.class); + public static final ContextKeys OTHER_X = of("other_x", Integer.class); + public static final ContextKeys OTHER_Y = of("other_y", Integer.class); + public static final ContextKeys OTHER_Z = of("other_z", Integer.class); public static final ContextKeys MONEY = of("money", String.class); public static final ContextKeys MONEY_FORMATTED = of("money_formatted", String.class); public static final ContextKeys REST = of("rest", String.class); diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/PlayerContextImpl.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/PlayerContextImpl.java index f40a1bb1..30963aeb 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/PlayerContextImpl.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/PlayerContextImpl.java @@ -86,6 +86,14 @@ public final class PlayerContextImpl implements Context { return (C) args.get(key); } + @Nullable + @SuppressWarnings("unchecked") + @Override + public C remove(ContextKeys key) { + placeholderMap.remove("{" + key.key() + "}"); + return (C) args.remove(key); + } + @Override public Player getHolder() { return player; diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/CustomFishingHook.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/CustomFishingHook.java index 9b0230a0..2f17f9c6 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/CustomFishingHook.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/CustomFishingHook.java @@ -134,10 +134,10 @@ public class CustomFishingHook { } } - context.arg(ContextKeys.HOOK_LOCATION, hook.getLocation()); - context.arg(ContextKeys.HOOK_X, hook.getLocation().getBlockX()); - context.arg(ContextKeys.HOOK_Y, hook.getLocation().getBlockY()); - context.arg(ContextKeys.HOOK_Z, hook.getLocation().getBlockZ()); + context.arg(ContextKeys.OTHER_LOCATION, hook.getLocation()); + context.arg(ContextKeys.OTHER_X, hook.getLocation().getBlockX()); + context.arg(ContextKeys.OTHER_Y, hook.getLocation().getBlockY()); + context.arg(ContextKeys.OTHER_Z, hook.getLocation().getBlockZ()); // get the next loot Loot loot = plugin.getLootManager().getNextLoot(effect, context); @@ -226,7 +226,7 @@ public class CustomFishingHook { public void onBite() { if (isPlayingGame()) return; - plugin.getEventManager().trigger(context, nextLoot.id(), MechanicType.getTypeByID(nextLoot.id()), ActionTrigger.BITE); + plugin.getEventManager().trigger(context, nextLoot.id(), MechanicType.LOOT, ActionTrigger.BITE); gears.trigger(ActionTrigger.BITE, context); if (RequirementManager.isSatisfied(context, ConfigManager.autoFishingRequirements())) { handleSuccessfulFishing(); @@ -306,10 +306,10 @@ public class CustomFishingHook { public void handleFailedFishing() { // update the hook location - context.arg(ContextKeys.HOOK_LOCATION, hook.getLocation()); - context.arg(ContextKeys.HOOK_X, hook.getLocation().getBlockX()); - context.arg(ContextKeys.HOOK_Y, hook.getLocation().getBlockY()); - context.arg(ContextKeys.HOOK_Z, hook.getLocation().getBlockZ()); + context.arg(ContextKeys.OTHER_LOCATION, hook.getLocation()); + context.arg(ContextKeys.OTHER_X, hook.getLocation().getBlockX()); + context.arg(ContextKeys.OTHER_Y, hook.getLocation().getBlockY()); + context.arg(ContextKeys.OTHER_Z, hook.getLocation().getBlockZ()); gears.trigger(ActionTrigger.FAILURE, context); plugin.getEventManager().trigger(context, nextLoot.id(), MechanicType.LOOT, ActionTrigger.FAILURE); @@ -318,10 +318,10 @@ public class CustomFishingHook { public void handleSuccessfulFishing() { // update the hook location - context.arg(ContextKeys.HOOK_LOCATION, hook.getLocation()); - context.arg(ContextKeys.HOOK_X, hook.getLocation().getBlockX()); - context.arg(ContextKeys.HOOK_Y, hook.getLocation().getBlockY()); - context.arg(ContextKeys.HOOK_Z, hook.getLocation().getBlockZ()); + context.arg(ContextKeys.OTHER_LOCATION, hook.getLocation()); + context.arg(ContextKeys.OTHER_X, hook.getLocation().getBlockX()); + context.arg(ContextKeys.OTHER_Y, hook.getLocation().getBlockY()); + context.arg(ContextKeys.OTHER_Z, hook.getLocation().getBlockZ()); LootType lootType = context.arg(ContextKeys.LOOT); Objects.requireNonNull(lootType, "Missing loot type"); @@ -429,7 +429,6 @@ public class CustomFishingHook { String id = context.arg(ContextKeys.ID); Player player = context.getHolder(); - MechanicType type = MechanicType.getTypeByID(id); if (!nextLoot.disableStats()) { plugin.getStorageManager().getOnlineUser(player.getUniqueId()).ifPresent( @@ -441,14 +440,14 @@ public class CustomFishingHook { context.arg(ContextKeys.RECORD, max); context.arg(ContextKeys.RECORD_FORMATTED, String.format("%.2f", max)); if (userData.statistics().updateSize(nextLoot.statisticKey().sizeKey(), size)) { - plugin.getEventManager().trigger(context, id, type, ActionTrigger.NEW_SIZE_RECORD); + plugin.getEventManager().trigger(context, id, MechanicType.LOOT, ActionTrigger.NEW_SIZE_RECORD); } }); } ); } - plugin.getEventManager().trigger(context, id, type, ActionTrigger.SUCCESS); + plugin.getEventManager().trigger(context, id, MechanicType.LOOT, ActionTrigger.SUCCESS); player.setStatistic(Statistic.FISH_CAUGHT, player.getStatistic(Statistic.FISH_CAUGHT) + 1); } } diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/FishingGears.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/FishingGears.java index 0c40b18f..491b48d0 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/FishingGears.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/FishingGears.java @@ -121,8 +121,8 @@ public class FishingGears { // set bait if it is boolean hasBait = false; String anotherItemID = BukkitCustomFishingPlugin.getInstance().getItemManager().getItemID(rodOnMainHand ? offHandItem : mainHandItem); - MechanicType type = MechanicType.getTypeByID(anotherItemID); - if (type == MechanicType.BAIT) { + List type = MechanicType.getTypeByID(anotherItemID); + if (type != null && type.contains(MechanicType.BAIT)) { fishingGears.gears.put(GearType.BAIT, List.of(Pair.of(anotherItemID, rodOnMainHand ? offHandItem : mainHandItem))); context.arg(ContextKeys.BAIT, anotherItemID); BukkitCustomFishingPlugin.getInstance().getEffectManager().getEffectModifier(anotherItemID, MechanicType.BAIT).ifPresent(fishingGears.modifiers::add); @@ -140,15 +140,17 @@ public class FishingGears { ItemStack itemInBag = bag.getItem(i); if (itemInBag == null) continue; String bagItemID = BukkitCustomFishingPlugin.getInstance().getItemManager().getItemID(itemInBag); - MechanicType bagItemType = MechanicType.getTypeByID(bagItemID); - if (!hasBait && bagItemType == MechanicType.BAIT) { - fishingGears.gears.put(GearType.BAIT, List.of(Pair.of(bagItemID, itemInBag))); - context.arg(ContextKeys.BAIT, bagItemID); - BukkitCustomFishingPlugin.getInstance().getEffectManager().getEffectModifier(bagItemID, MechanicType.BAIT).ifPresent(fishingGears.modifiers::add); - hasBait = true; - } - if (bagItemType == MechanicType.UTIL) { - uniqueUtils.put(bagItemID, itemInBag); + List bagItemType = MechanicType.getTypeByID(bagItemID); + if (bagItemType != null) { + if (!hasBait && bagItemType.contains(MechanicType.BAIT)) { + fishingGears.gears.put(GearType.BAIT, List.of(Pair.of(bagItemID, itemInBag))); + context.arg(ContextKeys.BAIT, bagItemID); + BukkitCustomFishingPlugin.getInstance().getEffectManager().getEffectModifier(bagItemID, MechanicType.BAIT).ifPresent(fishingGears.modifiers::add); + hasBait = true; + } + if (bagItemType.contains(MechanicType.UTIL)) { + uniqueUtils.put(bagItemID, itemInBag); + } } } if (!uniqueUtils.isEmpty()) { diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/ItemManager.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/ItemManager.java index 45fa79e6..e5828cc6 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/ItemManager.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/ItemManager.java @@ -50,12 +50,6 @@ public interface ItemManager extends Reloadable { @Nullable String getCustomFishingItemID(@NotNull ItemStack itemStack); - @Nullable - MechanicType getItemType(@NotNull ItemStack itemStack); - - @Nullable - MechanicType getItemType(@NotNull String id); - @Nullable Item dropItemLoot(@NotNull Context context, ItemStack rod, FishHook hook); diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/MechanicType.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/MechanicType.java index e5b06312..e52db77e 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/MechanicType.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/MechanicType.java @@ -22,12 +22,14 @@ import net.momirealms.customfishing.api.BukkitCustomFishingPlugin; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Objects; public class MechanicType { - private static final HashMap types = new HashMap<>(); + private static final HashMap> types = new HashMap<>(); public static final MechanicType LOOT = of("loot"); public static final MechanicType ROD = of("rod"); @@ -65,18 +67,13 @@ public class MechanicType { @ApiStatus.Internal public static void register(String id, MechanicType type) { - MechanicType previous = types.put(id, type); - if (previous != null) { - BukkitCustomFishingPlugin.getInstance().getPluginLogger().warn( - "Attempted to register item type " + id + " twice, this is not a safe behavior. [" - + type.getType() + "," + previous.getType() + "]" - ); - } + List previous = types.computeIfAbsent(id, k -> new ArrayList<>()); + previous.add(type); } @Nullable @ApiStatus.Internal - public static MechanicType getTypeByID(String id) { + public static List getTypeByID(String id) { return types.get(id); } diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/component/ComponentEditor.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/component/ComponentEditor.java new file mode 100644 index 00000000..039ca887 --- /dev/null +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/component/ComponentEditor.java @@ -0,0 +1,10 @@ +package net.momirealms.customfishing.api.mechanic.item.component; + +import com.saicone.rtag.RtagItem; +import net.momirealms.customfishing.api.mechanic.context.Context; +import org.bukkit.entity.Player; + +public interface ComponentEditor { + + void apply(RtagItem item, Context context); +} diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagEditor.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagEditor.java new file mode 100644 index 00000000..be2f8ff3 --- /dev/null +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagEditor.java @@ -0,0 +1,11 @@ +package net.momirealms.customfishing.api.mechanic.item.tag; + +import com.saicone.rtag.RtagItem; +import net.momirealms.customfishing.api.mechanic.context.Context; +import org.bukkit.entity.Player; + +@FunctionalInterface +public interface TagEditor { + + void apply(RtagItem item, Context context); +} diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagListType.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagListType.java new file mode 100644 index 00000000..af92d782 --- /dev/null +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagListType.java @@ -0,0 +1,6 @@ +package net.momirealms.customfishing.api.mechanic.item.tag; + +public enum TagListType { + TAG, + VALUE +} diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagMap.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagMap.java new file mode 100644 index 00000000..7a73b735 --- /dev/null +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagMap.java @@ -0,0 +1,11 @@ +package net.momirealms.customfishing.api.mechanic.item.tag; + +import net.momirealms.customfishing.api.mechanic.context.Context; +import org.bukkit.entity.Player; + +import java.util.Map; + +public interface TagMap { + + Map apply(Context context); +} diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagValueType.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagValueType.java new file mode 100644 index 00000000..78fc8982 --- /dev/null +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/item/tag/TagValueType.java @@ -0,0 +1,13 @@ +package net.momirealms.customfishing.api.mechanic.item.tag; + +public enum TagValueType { + BYTE, + INT, + DOUBLE, + LONG, + FLOAT, + SHORT, + STRING, + BYTEARRAY, + INTARRAY +} diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/loot/Loot.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/loot/Loot.java index 3c54d6cd..c8dc965b 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/loot/Loot.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/loot/Loot.java @@ -29,7 +29,7 @@ public interface Loot { public static boolean DEFAULT_INSTANT_GAME = false; public static boolean DEFAULT_DISABLE_GAME = false; public static boolean DEFAULT_DISABLE_STATS = false; - public static boolean DEFAULT_SHOW_IN_FINDER = false; + public static boolean DEFAULT_SHOW_IN_FINDER = true; } LootType DEFAULT_TYPE = LootType.ITEM; diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/loot/LootManager.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/loot/LootManager.java index 0d3dfea7..02316584 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/loot/LootManager.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/loot/LootManager.java @@ -38,7 +38,7 @@ public interface LootManager extends Reloadable { @NotNull Optional getLoot(String key); - Map getWeightedLoots(Context context); + Map getWeightedLoots(Effect effect, Context context); @Nullable Loot getNextLoot(Effect effect, Context context); diff --git a/common/src/main/java/net/momirealms/customfishing/common/item/AbstractItem.java b/common/src/main/java/net/momirealms/customfishing/common/item/AbstractItem.java index 380bd907..579b5a82 100644 --- a/common/src/main/java/net/momirealms/customfishing/common/item/AbstractItem.java +++ b/common/src/main/java/net/momirealms/customfishing/common/item/AbstractItem.java @@ -150,4 +150,8 @@ public class AbstractItem implements Item { public void update() { factory.update(item); } + + public R getRTagItem() { + return item; + } } diff --git a/common/src/main/java/net/momirealms/customfishing/common/locale/MessageConstants.java b/common/src/main/java/net/momirealms/customfishing/common/locale/MessageConstants.java index 77caf1f3..58a416b3 100644 --- a/common/src/main/java/net/momirealms/customfishing/common/locale/MessageConstants.java +++ b/common/src/main/java/net/momirealms/customfishing/common/locale/MessageConstants.java @@ -41,6 +41,8 @@ public interface MessageConstants { TranslatableComponent.Builder COMMAND_ITEM_FAILURE_NOT_EXIST = Component.translatable().key("command.item.failure.not_exist"); TranslatableComponent.Builder COMMAND_ITEM_GIVE_SUCCESS = Component.translatable().key("command.item.give.success"); TranslatableComponent.Builder COMMAND_ITEM_GET_SUCCESS = Component.translatable().key("command.item.get.success"); + TranslatableComponent.Builder COMMAND_ITEM_IMPORT_FAILURE_NO_ITEM = Component.translatable().key("command.item.import.failure.no_item"); + TranslatableComponent.Builder COMMAND_ITEM_IMPORT_SUCCESS = Component.translatable().key("command.item.import.success"); TranslatableComponent.Builder COMMAND_FISH_FINDER_POSSIBLE_LOOTS = Component.translatable().key("command.fish_finder.possible_loots"); TranslatableComponent.Builder COMMAND_FISH_FINDER_NO_LOOT = Component.translatable().key("command.fish_finder.no_loot"); TranslatableComponent.Builder COMMAND_FISH_FINDER_SPLIT_CHAR = Component.translatable().key("command.fish_finder.split_char"); diff --git a/common/src/main/java/net/momirealms/customfishing/common/util/ArrayUtils.java b/common/src/main/java/net/momirealms/customfishing/common/util/ArrayUtils.java index e9c6662a..a7403b13 100644 --- a/common/src/main/java/net/momirealms/customfishing/common/util/ArrayUtils.java +++ b/common/src/main/java/net/momirealms/customfishing/common/util/ArrayUtils.java @@ -19,6 +19,7 @@ package net.momirealms.customfishing.common.util; import java.lang.reflect.Array; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class ArrayUtils { @@ -51,4 +52,10 @@ public class ArrayUtils { } return result; } + + public static T[] appendElementToArray(T[] array, T element) { + T[] newArray = Arrays.copyOf(array, array.length + 1); + newArray[array.length] = element; + return newArray; + } } diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/action/BukkitActionManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/action/BukkitActionManager.java index dc39e753..07abf7e9 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/action/BukkitActionManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/action/BukkitActionManager.java @@ -25,6 +25,9 @@ import net.kyori.adventure.text.Component; import net.momirealms.customfishing.api.BukkitCustomFishingPlugin; import net.momirealms.customfishing.api.mechanic.action.*; import net.momirealms.customfishing.api.mechanic.context.ContextKeys; +import net.momirealms.customfishing.api.mechanic.effect.Effect; +import net.momirealms.customfishing.api.mechanic.fishing.CustomFishingHook; +import net.momirealms.customfishing.api.mechanic.fishing.FishingGears; import net.momirealms.customfishing.api.mechanic.misc.placeholder.BukkitPlaceholderManager; import net.momirealms.customfishing.api.mechanic.misc.value.MathValue; import net.momirealms.customfishing.api.mechanic.misc.value.TextValue; @@ -783,7 +786,7 @@ public class BukkitActionManager implements ActionManager { return context -> { if (Math.random() > chance) return; Player owner = context.getHolder(); - Location location = position ? requireNonNull(context.arg(ContextKeys.HOOK_LOCATION)).clone() : owner.getLocation().clone(); + Location location = position ? requireNonNull(context.arg(ContextKeys.OTHER_LOCATION)).clone() : owner.getLocation().clone(); location.add(x.evaluate(context), y.evaluate(context) - 1, z.evaluate(context)); if (opposite) location.setYaw(-owner.getLocation().getYaw()); else location.setYaw((float) yaw.evaluate(context)); @@ -832,7 +835,7 @@ public class BukkitActionManager implements ActionManager { return context -> { if (Math.random() > chance) return; Player owner = context.getHolder(); - Location location = position ? requireNonNull(context.arg(ContextKeys.HOOK_LOCATION)).clone() : owner.getLocation().clone(); + Location location = position ? requireNonNull(context.arg(ContextKeys.OTHER_LOCATION)).clone() : owner.getLocation().clone(); location.add(x.evaluate(context), y.evaluate(context), z.evaluate(context)); FakeArmorStand armorStand = SparrowHeart.getInstance().createFakeArmorStand(location); armorStand.invisible(true); @@ -874,16 +877,27 @@ public class BukkitActionManager implements ActionManager { if (Math.random() > chance) return; String previous = context.arg(ContextKeys.SURROUNDING); context.arg(ContextKeys.SURROUNDING, surrounding); - Collection loots = plugin.getLootManager().getWeightedLoots(context).keySet(); + Collection loots = plugin.getLootManager().getWeightedLoots(Effect.newInstance(), context).keySet(); StringJoiner stringJoiner = new StringJoiner(TranslationManager.miniMessageTranslation(MessageConstants.COMMAND_FISH_FINDER_SPLIT_CHAR.build().key())); for (String loot : loots) { - stringJoiner.add(loot); + plugin.getLootManager().getLoot(loot).ifPresent(lootIns -> { + System.out.println("loot: " + loot + " : " + lootIns.showInFinder()); + if (lootIns.showInFinder()) { + if (!lootIns.nick().equals("UNDEFINED")) { + stringJoiner.add(lootIns.nick()); + } + } + }); + } + if (previous == null) { + context.remove(ContextKeys.SURROUNDING); + } else { + context.arg(ContextKeys.SURROUNDING, previous); } - context.arg(ContextKeys.SURROUNDING, previous); if (loots.isEmpty()) { plugin.getSenderFactory().wrap(context.getHolder()).sendMessage(TranslationManager.render(MessageConstants.COMMAND_FISH_FINDER_NO_LOOT.build())); } else { - plugin.getSenderFactory().wrap(context.getHolder()).sendMessage(TranslationManager.render(MessageConstants.COMMAND_FISH_FINDER_POSSIBLE_LOOTS.arguments(Component.text(stringJoiner.toString())).build())); + plugin.getSenderFactory().wrap(context.getHolder()).sendMessage(TranslationManager.render(MessageConstants.COMMAND_FISH_FINDER_POSSIBLE_LOOTS.arguments(AdventureHelper.miniMessage(stringJoiner.toString())).build())); } }; }); diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/bag/BukkitBagManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/bag/BukkitBagManager.java index 8568804f..eadef8a5 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/bag/BukkitBagManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/bag/BukkitBagManager.java @@ -59,6 +59,11 @@ public class BukkitBagManager implements BagManager, Listener { private Action[] collectLootActions; private Action[] bagFullActions; private boolean bagStoreLoots; + private boolean bagStoreRods; + private boolean bagStoreBaits; + private boolean bagStoreHooks; + private boolean bagStoreUtils; + private final HashSet storedTypes = new HashSet<>(); private boolean enable; private String bagTitle; private List bagWhiteListItems = new ArrayList<>(); @@ -78,6 +83,7 @@ public class BukkitBagManager implements BagManager, Listener { @Override public void unload() { HandlerList.unregisterAll(this); + storedTypes.clear(); } @Override @@ -137,10 +143,20 @@ public class BukkitBagManager implements BagManager, Listener { enable = config.getBoolean("enable", true); bagTitle = config.getString("bag-title", ""); bagStoreLoots = config.getBoolean("can-store-loot", false); + bagStoreRods = config.getBoolean("can-store-rod", true); + bagStoreBaits = config.getBoolean("can-store-bait", true); + bagStoreHooks = config.getBoolean("can-store-hook", true); + bagStoreUtils = config.getBoolean("can-store-util", true); bagWhiteListItems = config.getStringList("whitelist-items").stream().map(it -> Material.valueOf(it.toUpperCase(Locale.ENGLISH))).toList(); collectLootActions = plugin.getActionManager().parseActions(config.getSection("collect-actions")); bagFullActions = plugin.getActionManager().parseActions(config.getSection("full-actions")); collectRequirements = plugin.getRequirementManager().parseRequirements(config.getSection("collect-requirements"), false); + + if (bagStoreLoots) storedTypes.add(MechanicType.LOOT); + if (bagStoreRods) storedTypes.add(MechanicType.ROD); + if (bagStoreBaits) storedTypes.add(MechanicType.BAIT); + if (bagStoreHooks) storedTypes.add(MechanicType.HOOK); + if (bagStoreUtils) storedTypes.add(MechanicType.UTIL); } @Override @@ -205,15 +221,16 @@ public class BukkitBagManager implements BagManager, Listener { if (movedItem == null || movedItem.getType() == Material.AIR || bagWhiteListItems.contains(movedItem.getType())) return; String id = plugin.getItemManager().getItemID(movedItem); - MechanicType type = MechanicType.getTypeByID(id); + List type = MechanicType.getTypeByID(id); if (type == null) { event.setCancelled(true); return; } - if (type == MechanicType.LOOT && bagStoreLoots) - return; - if (type == MechanicType.BAIT || type == MechanicType.ROD || type == MechanicType.UTIL || type == MechanicType.HOOK) - return; + for (MechanicType mechanicType : type) { + if (storedTypes.contains(mechanicType)) { + return; + } + } event.setCancelled(true); } diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/block/BukkitBlockManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/block/BukkitBlockManager.java index 4f90cca4..5aa8a20c 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/block/BukkitBlockManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/block/BukkitBlockManager.java @@ -227,7 +227,7 @@ public class BukkitBlockManager implements BlockManager, Listener { } else { blockData = blockProviders.get("vanilla").blockData(context, blockID, config.dataModifier()); } - Location hookLocation = requireNonNull(context.arg(ContextKeys.HOOK_LOCATION)); + Location hookLocation = requireNonNull(context.arg(ContextKeys.OTHER_LOCATION)); Location playerLocation = requireNonNull(context.getHolder()).getLocation(); FallingBlock fallingBlock = hookLocation.getWorld().spawn(hookLocation, FallingBlock.class, (fb -> fb.setBlockData(blockData))); fallingBlock.getPersistentDataContainer().set( diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/command/BukkitCommandManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/command/BukkitCommandManager.java index 834a8e79..b62ad251 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/command/BukkitCommandManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/command/BukkitCommandManager.java @@ -39,6 +39,7 @@ public class BukkitCommandManager extends AbstractCommandManager new SellFishCommand(this), new GetItemCommand(this), new GiveItemCommand(this), + new ImportItemCommand(this), new EndCompetitionCommand(this), new StopCompetitionCommand(this), new StartCompetitionCommand(this), diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/command/feature/ImportItemCommand.java b/core/src/main/java/net/momirealms/customfishing/bukkit/command/feature/ImportItemCommand.java new file mode 100644 index 00000000..ffe6dfab --- /dev/null +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/command/feature/ImportItemCommand.java @@ -0,0 +1,86 @@ +/* + * 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.bukkit.command.feature; + +import dev.dejvokep.boostedyaml.YamlDocument; +import dev.dejvokep.boostedyaml.block.implementation.Section; +import net.kyori.adventure.text.Component; +import net.momirealms.customfishing.api.BukkitCustomFishingPlugin; +import net.momirealms.customfishing.bukkit.command.BukkitCommandFeature; +import net.momirealms.customfishing.bukkit.util.ItemStackUtils; +import net.momirealms.customfishing.common.command.CustomFishingCommandManager; +import net.momirealms.customfishing.common.locale.MessageConstants; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.parser.standard.StringParser; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; +import java.util.Map; + +@SuppressWarnings("DuplicatedCode") +public class ImportItemCommand extends BukkitCommandFeature { + + public ImportItemCommand(CustomFishingCommandManager commandManager) { + super(commandManager); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .senderType(Player.class) + .required("id", StringParser.stringParser()) + .flag(manager.flagBuilder("silent").withAliases("s").build()) + .handler(context -> { + Player player = context.sender(); + ItemStack itemStack = player.getInventory().getItemInMainHand(); + String id = context.get("id"); + if (itemStack.getType() == Material.AIR) { + handleFeedback(context, MessageConstants.COMMAND_ITEM_IMPORT_FAILURE_NO_ITEM); + return; + } + File saved = new File(BukkitCustomFishingPlugin.getInstance().getDataFolder(), "imported_items.yml"); + if (!saved.exists()) { + try { + saved.createNewFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + YamlDocument document = BukkitCustomFishingPlugin.getInstance().getConfigManager().loadData(saved); + Map map = ItemStackUtils.itemStackToMap(itemStack); + document.set(id, map); + try { + document.save(saved); + handleFeedback(context, MessageConstants.COMMAND_ITEM_IMPORT_SUCCESS, Component.text(id)); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + @Override + public String getFeatureID() { + return "import_item"; + } +} diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/config/BukkitConfigManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/config/BukkitConfigManager.java index 4f58a36b..e6859edd 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/config/BukkitConfigManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/config/BukkitConfigManager.java @@ -17,6 +17,7 @@ package net.momirealms.customfishing.bukkit.config; +import com.saicone.rtag.RtagItem; import dev.dejvokep.boostedyaml.YamlDocument; import dev.dejvokep.boostedyaml.block.implementation.Section; import dev.dejvokep.boostedyaml.dvs.versioning.BasicVersioning; @@ -35,6 +36,7 @@ import net.momirealms.customfishing.api.mechanic.effect.Effect; import net.momirealms.customfishing.api.mechanic.effect.EffectProperties; import net.momirealms.customfishing.api.mechanic.event.EventManager; import net.momirealms.customfishing.api.mechanic.item.MechanicType; +import net.momirealms.customfishing.api.mechanic.item.tag.TagEditor; import net.momirealms.customfishing.api.mechanic.loot.Loot; import net.momirealms.customfishing.api.mechanic.misc.value.MathValue; import net.momirealms.customfishing.api.mechanic.misc.value.TextValue; @@ -52,8 +54,10 @@ import net.momirealms.customfishing.api.mechanic.totem.block.type.TypeCondition; import net.momirealms.customfishing.api.util.OffsetUtils; import net.momirealms.customfishing.bukkit.totem.particle.DustParticleSetting; import net.momirealms.customfishing.bukkit.totem.particle.ParticleSetting; +import net.momirealms.customfishing.bukkit.util.ItemStackUtils; import net.momirealms.customfishing.common.dependency.DependencyProperties; import net.momirealms.customfishing.common.helper.AdventureHelper; +import net.momirealms.customfishing.common.item.AbstractItem; import net.momirealms.customfishing.common.item.Item; import net.momirealms.customfishing.common.util.*; import org.bukkit.*; @@ -65,7 +69,9 @@ import org.bukkit.event.EventPriority; import org.bukkit.inventory.ItemStack; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.util.*; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -94,9 +100,9 @@ public class BukkitConfigManager extends ConfigManager { @Override public void load() { String configVersion = DependencyProperties.getDependencyVersion("config"); - try { + try (InputStream inputStream = new FileInputStream(resolveConfig("config.yml").toFile())) { MAIN_CONFIG = YamlDocument.create( - resolveConfig("config.yml").toFile(), + inputStream, plugin.getResourceStream("config.yml"), GeneralSettings.builder() .setRouteSeparator('.') @@ -287,26 +293,6 @@ public class BukkitConfigManager extends ConfigManager { } private void registerBuiltInItemProperties() { - Function, Context>> f2 = arg -> { - Section section = (Section) arg; - boolean stored = Objects.equals(section.getNameAsString(), "stored-random-enchantments"); - List> enchantments = getPossibleEnchantments(section); - return (item, context) -> { - HashSet ids = new HashSet<>(); - for (Tuple pair : enchantments) { - if (Math.random() < pair.left() && !ids.contains(pair.mid())) { - if (stored) { - item.addStoredEnchantment(Key.fromString(pair.mid()), pair.right()); - } else { - item.addEnchantment(Key.fromString(pair.mid()), pair.right()); - } - ids.add(pair.mid()); - } - } - }; - }; - this.registerItemParser(f2, 4850, "random-stored-enchantments"); - this.registerItemParser(f2, 4750, "random-enchantments"); Function, Context>> f1 = arg -> { Section section = (Section) arg; boolean stored = Objects.equals(section.getNameAsString(), "stored-enchantment-pool"); @@ -365,6 +351,26 @@ public class BukkitConfigManager extends ConfigManager { }; this.registerItemParser(f1, 4800, "stored-enchantment-pool"); this.registerItemParser(f1, 4700, "enchantment-pool"); + Function, Context>> f2 = arg -> { + Section section = (Section) arg; + boolean stored = Objects.equals(section.getNameAsString(), "stored-random-enchantments"); + List> enchantments = getPossibleEnchantments(section); + return (item, context) -> { + HashSet ids = new HashSet<>(); + for (Tuple pair : enchantments) { + if (Math.random() < pair.left() && !ids.contains(pair.mid())) { + if (stored) { + item.addStoredEnchantment(Key.fromString(pair.mid()), pair.right()); + } else { + item.addEnchantment(Key.fromString(pair.mid()), pair.right()); + } + ids.add(pair.mid()); + } + } + }; + }; + this.registerItemParser(f2, 4850, "random-stored-enchantments"); + this.registerItemParser(f2, 4750, "random-enchantments"); this.registerItemParser(arg -> { Section section = (Section) arg; Map map = getEnchantments(section); @@ -432,6 +438,16 @@ public class BukkitConfigManager extends ConfigManager { context.arg(ContextKeys.PRICE_FORMATTED, String.format("%.2f", price)); }; }, 1_500, "price"); + this.registerItemParser(arg -> { + Section section = (Section) arg; + ArrayList editors = new ArrayList<>(); + ItemStackUtils.sectionToEditor(section, editors); + return (item, context) -> { + for (TagEditor editor : editors) { + editor.apply(((AbstractItem) item).getRTagItem(), context); + } + }; + }, 1_750, "nbt"); } private void registerBuiltInEffectModifierParser() { diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/entity/BukkitEntityManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/entity/BukkitEntityManager.java index 05759f1a..e1478bb4 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/entity/BukkitEntityManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/entity/BukkitEntityManager.java @@ -104,7 +104,7 @@ public class BukkitEntityManager implements EntityManager { public Entity summonEntityLoot(Context context) { String id = context.arg(ContextKeys.ID); EntityConfig config = requireNonNull(entities.get(id), "Entity " + id + " not found"); - Location hookLocation = requireNonNull(context.arg(ContextKeys.HOOK_LOCATION)); + Location hookLocation = requireNonNull(context.arg(ContextKeys.OTHER_LOCATION)); Location playerLocation = requireNonNull(context.getHolder().getLocation()); String entityID = config.entityID(); Entity entity; diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/event/BukkitEventManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/event/BukkitEventManager.java index 1a775969..14b66eb4 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/event/BukkitEventManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/event/BukkitEventManager.java @@ -20,11 +20,14 @@ package net.momirealms.customfishing.bukkit.event; import net.momirealms.customfishing.api.BukkitCustomFishingPlugin; import net.momirealms.customfishing.api.mechanic.action.ActionTrigger; import net.momirealms.customfishing.api.mechanic.context.Context; +import net.momirealms.customfishing.api.mechanic.context.ContextKeys; import net.momirealms.customfishing.api.mechanic.event.EventCarrier; import net.momirealms.customfishing.api.mechanic.event.EventManager; import net.momirealms.customfishing.api.mechanic.item.MechanicType; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; @@ -78,14 +81,15 @@ public class BukkitEventManager implements EventManager, Listener { if (itemStack.getType() == Material.AIR || itemStack.getAmount() == 0) return; String id = this.plugin.getItemManager().getItemID(itemStack); - Optional.ofNullable(this.carriers.get(id)).ifPresent(carrier -> { - carrier.trigger(Context.player(event.getPlayer()), ActionTrigger.INTERACT); - }); + Context context = Context.player(event.getPlayer()); + Block clicked = event.getClickedBlock(); + context.arg(ContextKeys.OTHER_LOCATION, clicked == null ? event.getPlayer().getLocation() : clicked.getLocation()); + trigger(context, id, MechanicType.UTIL, ActionTrigger.INTERACT); } @EventHandler (ignoreCancelled = true) public void onConsumeItem(PlayerItemConsumeEvent event) { - Optional.ofNullable(carriers.get(plugin.getItemManager().getItemID(event.getItem()))) - .ifPresent(carrier -> carrier.trigger(Context.player(event.getPlayer()), ActionTrigger.CONSUME)); + Context context = Context.player(event.getPlayer()); + trigger(context, plugin.getItemManager().getItemID(event.getItem()), MechanicType.LOOT, ActionTrigger.CONSUME); } } diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/item/BukkitItemManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/item/BukkitItemManager.java index 359047d5..f79fb082 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/item/BukkitItemManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/item/BukkitItemManager.java @@ -159,18 +159,6 @@ public class BukkitItemManager implements ItemManager, Listener { return (String) factory.wrap(itemStack).getTag("CustomFishing", "id").orElse(null); } - @Nullable - @Override - public MechanicType getItemType(@NotNull ItemStack itemStack) { - return MechanicType.getTypeByID(getCustomFishingItemID(itemStack)); - } - - @Nullable - @Override - public MechanicType getItemType(@NotNull String id) { - return MechanicType.getTypeByID(id); - } - @Nullable @Override public org.bukkit.entity.Item dropItemLoot(@NotNull Context context, ItemStack rod, FishHook hook) { @@ -188,7 +176,7 @@ public class BukkitItemManager implements ItemManager, Listener { Player player = context.getHolder(); Location playerLocation = player.getLocation(); - Location hookLocation = requireNonNull(context.arg(ContextKeys.HOOK_LOCATION)); + Location hookLocation = requireNonNull(context.arg(ContextKeys.OTHER_LOCATION)); double d0 = playerLocation.getX() - hookLocation.getX(); double d1 = playerLocation.getY() - hookLocation.getY(); diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/loot/BukkitLootManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/loot/BukkitLootManager.java index 58b93a4c..baf31ac1 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/loot/BukkitLootManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/loot/BukkitLootManager.java @@ -129,8 +129,21 @@ public class BukkitLootManager implements LootManager { } @Override - public HashMap getWeightedLoots(Context context) { - return null; + public HashMap getWeightedLoots(Effect effect, Context context) { + HashMap lootWeightMap = new HashMap<>(); + for (ConditionalElement, Double, Double>>>, Player> conditionalElement : lootConditions.values()) { + modifyWeightMap(lootWeightMap, context, conditionalElement); + } + for (Pair, Double, Double>> pair : effect.weightOperations()) { + double previous = lootWeightMap.getOrDefault(pair.left(), 0d); + if (previous > 0) + lootWeightMap.put(pair.left(), pair.right().apply(context, previous)); + } + for (Pair, Double, Double>> pair : effect.weightOperationsIgnored()) { + double previous = lootWeightMap.getOrDefault(pair.left(), 0d); + lootWeightMap.put(pair.left(), pair.right().apply(context, previous)); + } + return lootWeightMap; } @Nullable diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/requirement/BukkitRequirementManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/requirement/BukkitRequirementManager.java index 9205f49c..dff85941 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/requirement/BukkitRequirementManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/requirement/BukkitRequirementManager.java @@ -665,7 +665,7 @@ public class BukkitRequirementManager implements RequirementManager { registerRequirement("ice-fishing", (args, actions, runActions) -> { boolean iceFishing = (boolean) args; return context -> { - Location location = requireNonNull(context.arg(ContextKeys.HOOK_LOCATION)); + Location location = requireNonNull(context.arg(ContextKeys.OTHER_LOCATION)); int water = 0, ice = 0; for (int i = -2; i <= 2; i++) for (int j = -1; j <= 2; j++) @@ -727,7 +727,7 @@ public class BukkitRequirementManager implements RequirementManager { registerRequirement("biome", (args, actions, runActions) -> { HashSet biomes = new HashSet<>(ListUtils.toList(args)); return context -> { - Location location = requireNonNull(Optional.ofNullable(context.arg(ContextKeys.HOOK_LOCATION)).orElse(context.arg(ContextKeys.LOCATION))); + Location location = requireNonNull(Optional.ofNullable(context.arg(ContextKeys.OTHER_LOCATION)).orElse(context.arg(ContextKeys.LOCATION))); String currentBiome = SparrowHeart.getInstance().getBiomeResourceLocation(location); if (biomes.contains(currentBiome)) return true; @@ -738,7 +738,7 @@ public class BukkitRequirementManager implements RequirementManager { registerRequirement("!biome", (args, actions, runActions) -> { HashSet biomes = new HashSet<>(ListUtils.toList(args)); return context -> { - Location location = requireNonNull(Optional.ofNullable(context.arg(ContextKeys.HOOK_LOCATION)).orElse(context.arg(ContextKeys.LOCATION))); + Location location = requireNonNull(Optional.ofNullable(context.arg(ContextKeys.OTHER_LOCATION)).orElse(context.arg(ContextKeys.LOCATION))); String currentBiome = SparrowHeart.getInstance().getBiomeResourceLocation(location); if (!biomes.contains(currentBiome)) return true; diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/util/ItemStackUtils.java b/core/src/main/java/net/momirealms/customfishing/bukkit/util/ItemStackUtils.java index b8391df3..23c0efaf 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/util/ItemStackUtils.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/util/ItemStackUtils.java @@ -17,10 +17,17 @@ package net.momirealms.customfishing.bukkit.util; -import com.saicone.rtag.RtagMirror; -import com.saicone.rtag.item.ItemObject; -import com.saicone.rtag.tag.TagCompound; +import com.saicone.rtag.item.ItemTagStream; +import dev.dejvokep.boostedyaml.block.implementation.Section; +import net.momirealms.customfishing.api.mechanic.item.tag.TagEditor; +import net.momirealms.customfishing.api.mechanic.item.tag.TagListType; +import net.momirealms.customfishing.api.mechanic.item.tag.TagValueType; +import net.momirealms.customfishing.api.mechanic.misc.value.MathValue; +import net.momirealms.customfishing.api.mechanic.misc.value.TextValue; +import net.momirealms.customfishing.common.util.ArrayUtils; +import net.momirealms.customfishing.common.util.Pair; import org.bukkit.Material; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.util.io.BukkitObjectInputStream; import org.bukkit.util.io.BukkitObjectOutputStream; @@ -29,7 +36,7 @@ import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.Map; +import java.util.*; public class ItemStackUtils { @@ -69,24 +76,208 @@ public class ItemStackUtils { } } - public static Map toReadableMap(ItemStack item) { - return toMap(item); + public static Map itemStackToMap(ItemStack itemStack) { + Map map = ItemTagStream.INSTANCE.toMap(itemStack); + map.remove("rtagDataVersion"); + map.remove("count"); + map.remove("id"); + map.put("material", itemStack.getType().name().toLowerCase(Locale.ENGLISH)); + map.put("amount", itemStack.getAmount()); + Object tag = map.remove("tags"); + if (tag != null) { + map.put("nbt", tag); + } + return map; } - private static Map toMap(ItemStack object) { - return TagCompound.getValue(RtagMirror.INSTANCE, toCompound(object)); - } - - private static Object toCompound(ItemStack object) { - if (object == null) { - return null; - } else { - Object compound = extract(object); - return TagCompound.isTagCompound(compound) ? compound : null; + // TODO Improve the map parser and refactor this method to make it more readable + public static void sectionToEditor(Section section, List tagEditors, String... route) { + for (Map.Entry entry : section.getStringRouteMappedValues(false).entrySet()) { + Object value = entry.getValue(); + String key = entry.getKey(); + String[] currentRoute = ArrayUtils.appendElementToArray(route, key); + if (value instanceof Section inner) { + sectionToEditor(inner, tagEditors, currentRoute); + } else if (value instanceof List list) { + TagListType type = getListType(list); + if (type == TagListType.TAG) { +// List maps = new ArrayList<>(); +// for (Object o : list) { +// Map map = (Map) o; +// +// } + tagEditors.add(((item, context) -> { +// List> parsed = maps.stream().map(render -> render.apply(context)).toList(); + item.set(list, (Object[]) currentRoute); + })); + } else { + Object first = list.get(0); + if (first instanceof String str) { + Pair pair = toTypeAndData(str); + switch (pair.left()) { + case INT -> { + List> values = new ArrayList<>(); + for (Object o : list) { + values.add(MathValue.auto(toTypeAndData((String) o).right())); + } + tagEditors.add(((item, context) -> { + List integers = values.stream().map(unparsed -> (int) unparsed.evaluate(context)).toList(); + item.set(integers, (Object[]) currentRoute); + })); + } + case BYTE -> { + List> values = new ArrayList<>(); + for (Object o : list) { + values.add(MathValue.auto(toTypeAndData((String) o).right())); + } + tagEditors.add(((item, context) -> { + List bytes = values.stream().map(unparsed -> (byte) unparsed.evaluate(context)).toList(); + item.set(bytes, (Object[]) currentRoute); + })); + } + case LONG -> { + List> values = new ArrayList<>(); + for (Object o : list) { + values.add(MathValue.auto(toTypeAndData((String) o).right())); + } + tagEditors.add(((item, context) -> { + List longs = values.stream().map(unparsed -> (long) unparsed.evaluate(context)).toList(); + item.set(longs, (Object[]) currentRoute); + })); + } + case FLOAT -> { + List> values = new ArrayList<>(); + for (Object o : list) { + values.add(MathValue.auto(toTypeAndData((String) o).right())); + } + tagEditors.add(((item, context) -> { + List floats = values.stream().map(unparsed -> (float) unparsed.evaluate(context)).toList(); + item.set(floats, (Object[]) currentRoute); + })); + } + case DOUBLE -> { + List> values = new ArrayList<>(); + for (Object o : list) { + values.add(MathValue.auto(toTypeAndData((String) o).right())); + } + tagEditors.add(((item, context) -> { + List doubles = values.stream().map(unparsed -> (double) unparsed.evaluate(context)).toList(); + item.set(doubles, (Object[]) currentRoute); + })); + } + case STRING -> { + List> values = new ArrayList<>(); + for (Object o : list) { + values.add(TextValue.auto(toTypeAndData((String) o).right())); + } + tagEditors.add(((item, context) -> { + List texts = values.stream().map(unparsed -> unparsed.render(context)).toList(); + item.set(texts, (Object[]) currentRoute); + })); + } + } + } else { + tagEditors.add(((item, context) -> { + item.set(list, (Object[]) currentRoute); + })); + } + } + } else if (value instanceof String str) { + Pair pair = toTypeAndData(str); + switch (pair.left()) { + case INT -> { + MathValue mathValue = MathValue.auto(pair.right()); + tagEditors.add(((item, context) -> { + item.set((int) mathValue.evaluate(context), (Object[]) currentRoute); + })); + } + case BYTE -> { + MathValue mathValue = MathValue.auto(pair.right()); + tagEditors.add(((item, context) -> { + item.set((byte) mathValue.evaluate(context), (Object[]) currentRoute); + })); + } + case LONG -> { + MathValue mathValue = MathValue.auto(pair.right()); + tagEditors.add(((item, context) -> { + item.set((long) mathValue.evaluate(context), (Object[]) currentRoute); + })); + } + case SHORT -> { + MathValue mathValue = MathValue.auto(pair.right()); + tagEditors.add(((item, context) -> { + item.set((short) mathValue.evaluate(context), (Object[]) currentRoute); + })); + } + case DOUBLE -> { + MathValue mathValue = MathValue.auto(pair.right()); + tagEditors.add(((item, context) -> { + item.set((double) mathValue.evaluate(context), (Object[]) currentRoute); + })); + } + case FLOAT -> { + MathValue mathValue = MathValue.auto(pair.right()); + tagEditors.add(((item, context) -> { + item.set((float) mathValue.evaluate(context), (Object[]) currentRoute); + })); + } + case STRING -> { + TextValue textValue = TextValue.auto(pair.right()); + tagEditors.add(((item, context) -> { + item.set(textValue.render(context), (Object[]) currentRoute); + })); + } + case INTARRAY -> { + String[] split = splitValue(str); + int[] array = Arrays.stream(split).mapToInt(Integer::parseInt).toArray(); + tagEditors.add(((item, context) -> { + item.set(array, (Object[]) currentRoute); + })); + } + case BYTEARRAY -> { + String[] split = splitValue(str); + byte[] bytes = new byte[split.length]; + for (int i = 0; i < split.length; i++){ + bytes[i] = Byte.parseByte(split[i]); + } + tagEditors.add(((item, context) -> { + item.set(bytes, (Object[]) currentRoute); + })); + } + } + } else { + tagEditors.add(((item, context) -> { + item.set(value, (Object[]) currentRoute); + })); + } } } - private static Object extract(ItemStack object) { - return ItemObject.save(ItemObject.asNMSCopy(object)); + private static TagListType getListType(List list) { + Object o = list.get(0); + if (o instanceof Map map) { + return TagListType.TAG; + } else { + return TagListType.VALUE; + } + } + + public static Pair toTypeAndData(String str) { + String[] parts = str.split("\\s+", 2); + if (parts.length == 1) { + return Pair.of(TagValueType.STRING, parts[0]); + } + if (parts.length != 2) { + throw new IllegalArgumentException("Invalid value format: " + str); + } + TagValueType type = TagValueType.valueOf(parts[0].substring(1, parts[0].length() - 1).toUpperCase(Locale.ENGLISH)); + String data = parts[1]; + return Pair.of(type, data); + } + + private static String[] splitValue(String value) { + return value.substring(value.indexOf('[') + 1, value.lastIndexOf(']')) + .replaceAll("\\s", "") + .split(","); } } diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 29035fb4..d192edbd 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -159,8 +159,12 @@ mechanics: # Other whitelist-items whitelist-items: - fishing_rod - # Can fishing bag store fishing loots? + # Decide the items that can be stored in bag can-store-loot: false + can-store-rod: true + can-store-bait: true + can-store-hook: true + can-store-util: true # Requirements for automatically collecting collect-requirements: permission: fishingbag.collectloot diff --git a/core/src/main/resources/translations/en.yml b/core/src/main/resources/translations/en.yml index 26864eaf..a64c0cc3 100644 --- a/core/src/main/resources/translations/en.yml +++ b/core/src/main/resources/translations/en.yml @@ -42,6 +42,8 @@ command.reload.success: "Reloaded. Took ms.Item [] not exists." command.item.give.success: "Successfully given x ." command.item.get.success: "Successfully got x ." +command.item.import.failure.no_item: "You can't import air" +command.item.import.success: "Item [] has been saved to /plugins/CustomFishing/imported_items.yml" command.fish_finder.possible_loots: "Possible loots here: " command.fish_finder.no_loot: "No loot found here" command.fish_finder.split_char: ", " diff --git a/gradle.properties b/gradle.properties index bc50d1e2..b5c8c477 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,7 +24,7 @@ cloud_brigadier_version=2.0.0-beta.8 cloud_bukkit_version=2.0.0-beta.8 cloud_paper_version=2.0.0-beta.8 cloud_minecraft_extras_version=2.0.0-beta.8 -boosted_yaml_version=1.3.4 +boosted_yaml_version=1.3.6 byte_buddy_version=1.14.14 mojang_brigadier_version=1.0.18 mongodb_driver_version=5.1.0