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 8e9b2168..aab07cd2 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 @@ -88,6 +88,7 @@ public class ContextKeys { public static final ContextKeys SLOT = of("hand", EquipmentSlot.class); public static final ContextKeys BONUS = of("bonus", Double.class); public static final ContextKeys BASE = of("base", Double.class); + public static final ContextKeys LOOT_ORDER = of("loot_order", Integer.class); private final String key; private final Class type; 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 e9467687..71ad76e8 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 @@ -502,7 +502,9 @@ public class CustomFishingHook { context.arg(ContextKeys.SIZE_ADDER, tempFinalEffect.sizeAdder()); boolean directlyToInventory = nextLoot.toInventory().evaluate(context) != 0; for (int i = 0; i < amount; i++) { + int order = i; plugin.getScheduler().sync().runLater(() -> { + context.arg(ContextKeys.LOOT_ORDER, order); if (directlyToInventory) { ItemStack stack = plugin.getItemManager().getItemLoot(context, gears.getItem(FishingGears.GearType.ROD).stream().findAny().orElseThrow().right(), hook); if (stack.getType() != Material.AIR) { @@ -544,6 +546,7 @@ public class CustomFishingHook { } } case BLOCK -> { + context.arg(ContextKeys.LOOT_ORDER, 1); FallingBlock fallingBlock = plugin.getBlockManager().summonBlockLoot(context); FishingLootSpawnEvent spawnEvent = new FishingLootSpawnEvent(context, hook.getLocation(), nextLoot, fallingBlock); Bukkit.getPluginManager().callEvent(spawnEvent); @@ -554,6 +557,7 @@ public class CustomFishingHook { doSuccessActions(); } case ENTITY -> { + context.arg(ContextKeys.LOOT_ORDER, 1); Entity entity = plugin.getEntityManager().summonEntityLoot(context); FishingLootSpawnEvent spawnEvent = new FishingLootSpawnEvent(context, hook.getLocation(), nextLoot, entity); Bukkit.getPluginManager().callEvent(spawnEvent); diff --git a/api/src/main/java/net/momirealms/customfishing/api/util/MiscUtils.java b/api/src/main/java/net/momirealms/customfishing/api/util/MiscUtils.java new file mode 100644 index 00000000..1faa5f9a --- /dev/null +++ b/api/src/main/java/net/momirealms/customfishing/api/util/MiscUtils.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) <2024> + * + * 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.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MiscUtils { + + public static List getAsStringList(Object o) { + List list = new ArrayList<>(); + if (o instanceof List) { + for (Object object : (List) o) { + list.add(object.toString()); + } + } else if (o instanceof String) { + list.add((String) o); + } else { + list.add(o.toString()); + } + return list; + } + + public static List getAsFloatList(Object o) { + List list = new ArrayList<>(); + if (o instanceof List) { + for (Object object : (List) o) { + if (object instanceof Number) { + list.add(((Number) object).floatValue()); + } else if (object instanceof String) { + try { + list.add(Float.parseFloat((String) object)); + } catch (NumberFormatException e) { + throw new RuntimeException("Cannot convert " + object + " to float"); + } + } else { + throw new RuntimeException("Cannot convert " + object + " to float"); + } + } + } else if (o instanceof Float) { + list.add((Float) o); + } else if (o instanceof String) { + try { + list.add(Float.parseFloat((String) o)); + } catch (NumberFormatException e) { + throw new RuntimeException("Cannot convert " + o + " to float"); + } + } else { + throw new RuntimeException("Cannot convert " + o + " to float"); + } + return list; + } + + public static int getAsInt(Object o) { + if (o instanceof Integer) { + return (Integer) o; + } else if (o instanceof String) { + try { + return Integer.parseInt((String) o); + } catch (NumberFormatException e) { + throw new RuntimeException("Cannot convert " + o + " to int"); + } + } else if (o instanceof Boolean) { + return (Boolean) o ? 1 : 0; + } else if (o instanceof Number) { + return ((Number) o).intValue(); + } + throw new RuntimeException("Cannot convert " + o + " to int"); + } + + public static double getAsDouble(Object o) { + if (o instanceof Double) { + return (Double) o; + } else if (o instanceof String) { + try { + return Double.parseDouble((String) o); + } catch (NumberFormatException e) { + throw new RuntimeException("Cannot convert " + o + " to double"); + } + } else if (o instanceof Number) { + return ((Number) o).doubleValue(); + } + throw new RuntimeException("Cannot convert " + o + " to double"); + } + + public static float getAsFloat(Object o) { + if (o instanceof Float) { + return (Float) o; + } else if (o instanceof String) { + try { + return Float.parseFloat((String) o); + } catch (NumberFormatException e) { + throw new RuntimeException("Cannot convert " + o + " to float"); + } + } else if (o instanceof Number) { + return ((Number) o).floatValue(); + } + throw new RuntimeException("Cannot convert " + o + " to float"); + } + + @SuppressWarnings("unchecked") + public static List deepCopyList(List originalList, Map replacements) { + List copiedList = new ArrayList<>(); + for (T item : originalList) { + if (item instanceof List) { + copiedList.add((T) deepCopyList((List) item, replacements)); + } else if (item instanceof Map) { + copiedList.add((T) deepCopyMap((Map) item, replacements)); + } else if (item instanceof String s) { + copiedList.add((T) replacements.getOrDefault(s, s)); + } else { + copiedList.add(item); + } + } + return copiedList; + } + + @SuppressWarnings("unchecked") + public static Map deepCopyMap(Map originalMap, Map replacements) { + Map copiedMap = new HashMap<>(); + for (Map.Entry entry : originalMap.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof List) { + copiedMap.put(key, deepCopyList((List) value, replacements)); + } else if (value instanceof Map) { + copiedMap.put(key, deepCopyMap((Map) value, replacements)); + } else if (value instanceof String s) { + copiedMap.put(key, replacements.getOrDefault(s, s)); + } else { + copiedMap.put(key, value); + } + } + return copiedMap; + } +} diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/BukkitCustomFishingPluginImpl.java b/core/src/main/java/net/momirealms/customfishing/bukkit/BukkitCustomFishingPluginImpl.java index 12cf2f1f..61368bf8 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/BukkitCustomFishingPluginImpl.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/BukkitCustomFishingPluginImpl.java @@ -143,8 +143,7 @@ public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin { this.commandManager = new BukkitCommandManager(this); this.commandManager.registerDefaultFeatures(); - this.reload(); - if (ConfigManager.metrics()) new Metrics((JavaPlugin) getBootstrap(), 16648); + if (ConfigManager.metrics()) new Metrics(getBootstrap(), 16648); boolean downloadFromPolymart = polymart.equals("1"); boolean downloadFromBBB = buildByBit.equals("true"); @@ -166,6 +165,12 @@ public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin { } }); } + + if (VersionHelper.isFolia()) { + Bukkit.getGlobalRegionScheduler().run(getBootstrap(), (scheduledTask) -> this.reload()); + } else { + Bukkit.getScheduler().runTask(getBootstrap(), this::reload); + } } @Override 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 51cd7ba0..5570caaa 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 @@ -172,6 +172,7 @@ public class BukkitActionManager implements ActionManager { this.registerHologramAction(); this.registerFakeItemAction(); this.registerTitleAction(); + this.registerInsertArgumentAction(); } private void registerMessageAction() { @@ -734,6 +735,26 @@ public class BukkitActionManager implements ActionManager { }, "plugin-exp"); } + private void registerInsertArgumentAction() { + registerAction((args, chance) -> { + if (args instanceof Section section) { + List>> argList = new ArrayList<>(); + for (Map.Entry entry : section.getStringRouteMappedValues(false).entrySet()) { + argList.add(Pair.of(entry.getKey(), TextValue.auto(entry.getValue().toString()))); + } + return context -> { + if (Math.random() > chance.evaluate(context)) return; + for (Pair> pair : argList) { + context.arg(ContextKeys.of(pair.left(), String.class), pair.right().render(context)); + } + }; + } else { + plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at context-arg action which is expected to be `Section`"); + return Action.empty(); + } + }, "context-arg"); + } + private void registerTitleAction() { registerAction((args, chance) -> { if (args instanceof Section section) { 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 756d53a6..1ae0ab7a 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 @@ -21,6 +21,7 @@ import dev.dejvokep.boostedyaml.YamlDocument; import dev.dejvokep.boostedyaml.block.implementation.Section; import net.momirealms.customfishing.api.BukkitCustomFishingPlugin; import net.momirealms.customfishing.api.mechanic.context.Context; +import net.momirealms.customfishing.api.mechanic.context.ContextKeys; import net.momirealms.customfishing.api.mechanic.effect.Effect; import net.momirealms.customfishing.api.mechanic.loot.Loot; import net.momirealms.customfishing.api.mechanic.loot.LootManager; 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 f74a7965..0357545f 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 @@ -35,6 +35,7 @@ import net.momirealms.customfishing.api.mechanic.requirement.RequirementExpansio import net.momirealms.customfishing.api.mechanic.requirement.RequirementFactory; import net.momirealms.customfishing.api.mechanic.requirement.RequirementManager; import net.momirealms.customfishing.api.mechanic.totem.ActiveTotemList; +import net.momirealms.customfishing.api.util.MiscUtils; import net.momirealms.customfishing.api.util.MoonPhase; import net.momirealms.customfishing.bukkit.integration.VaultHook; import net.momirealms.customfishing.common.util.ClassUtils; @@ -204,6 +205,9 @@ public class BukkitRequirementManager implements RequirementManager { this.registerEquipmentRequirement(); this.registerLiquidDepthRequirement(); this.registerTotemRequirement(); + this.registerIsFirstLootRequirement(); + this.registerHasPlayerLootRequirement(); + this.registerLootOrderRequirement(); } private void registerImpossibleRequirement() { @@ -1188,7 +1192,6 @@ public class BukkitRequirementManager implements RequirementManager { if (args instanceof Section section) { TextValue v1 = TextValue.auto(section.getString("value1", "")); TextValue v2 = TextValue.auto(section.getString("value2", "")); - return context -> { if (v1.render(context, true).equals(v2.render(context, true))) return true; if (runActions) ActionManager.trigger(context, actions); @@ -1296,6 +1299,43 @@ public class BukkitRequirementManager implements RequirementManager { }, "gamemode"); } + protected void registerIsFirstLootRequirement() { + registerRequirement((args, actions, advanced) -> { + boolean is = (boolean) args; + return context -> { + int order = Optional.ofNullable(context.arg(ContextKeys.LOOT_ORDER)).orElse(1); + if (is && order == 1) return true; + if (!is && order != 1) return true; + if (advanced) ActionManager.trigger(context, actions); + return false; + }; + }, "is-first-loot"); + } + + protected void registerLootOrderRequirement() { + registerRequirement((args, actions, advanced) -> { + int order = MiscUtils.getAsInt(args); + return context -> { + int actualOrder = Optional.ofNullable(context.arg(ContextKeys.LOOT_ORDER)).orElse(1); + if (order == actualOrder) return true; + if (advanced) ActionManager.trigger(context, actions); + return false; + }; + }, "loot-order"); + } + + protected void registerHasPlayerLootRequirement() { + registerRequirement((args, actions, advanced) -> { + boolean has = (boolean) args; + return context -> { + if (has && context.holder() != null) return true; + if (!has && context.holder() == null) return true; + if (advanced) ActionManager.trigger(context, actions); + return false; + }; + }, "has-player"); + } + /** * Loads requirement expansions from external JAR files located in the expansion folder. * Each expansion JAR should contain classes that extends the RequirementExpansion class. diff --git a/gradle.properties b/gradle.properties index 40c21c41..dc63f517 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=2.3.2 +project_version=2.3.3 config_version=38 project_group=net.momirealms @@ -29,16 +29,16 @@ cloud_paper_version=2.0.0-beta.10 cloud_minecraft_extras_version=2.0.0-beta.10 boosted_yaml_version=1.3.7 mojang_brigadier_version=1.0.18 -mongodb_driver_version=5.2.1 -mariadb_driver_version=3.5.0 -mysql_driver_version=9.1.0 +mongodb_driver_version=5.3.1 +mariadb_driver_version=3.5.1 +mysql_driver_version=9.2.0 hikari_version=5.1.0 commons_pool_version=2.12.0 bstats_version=3.1.0 geantyref_version=1.3.16 caffeine_version=3.1.8 rtag_version=1.5.9 -jedis_version=5.1.5 +jedis_version=5.2.0 exp4j_version=0.4.8 placeholder_api_version=2.11.6 vault_version=1.7