From 3a225ed53f25082e4532db03ffe69a2969103922 Mon Sep 17 00:00:00 2001 From: Vftdan Date: Fri, 28 Feb 2025 22:00:04 +0100 Subject: [PATCH 1/2] Implement a chance to override fished items with additional loot tables Can be used as a fix for https://github.com/oddlama/vane/issues/292 --- .../java/org/oddlama/vane/core/LootTable.java | 19 ++++++++ .../org/oddlama/vane/core/module/Module.java | 48 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/vane-core/src/main/java/org/oddlama/vane/core/LootTable.java b/vane-core/src/main/java/org/oddlama/vane/core/LootTable.java index 15b13eeb..4d2dbdaf 100644 --- a/vane-core/src/main/java/org/oddlama/vane/core/LootTable.java +++ b/vane-core/src/main/java/org/oddlama/vane/core/LootTable.java @@ -1,5 +1,6 @@ package org.oddlama.vane.core; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -43,6 +44,24 @@ public void generate_loot(final List output, final Random random) { } } + public ItemStack generate_override(final Random random) { + double total_chance = 0; + final double threshold = random.nextDouble(); + final List result_container = new ArrayList<>(1); + for (final var set : possible_loot.values()) { + for (final var loot : set) { + total_chance += loot.chance; + if (total_chance > threshold) { + loot.add_sample(result_container, random); + } + if (!result_container.isEmpty()) { + return result_container.get(0); + } + } + } + return null; + } + public static class LootTableEntry { public double chance; diff --git a/vane-core/src/main/java/org/oddlama/vane/core/module/Module.java b/vane-core/src/main/java/org/oddlama/vane/core/module/Module.java index d79fef2f..8a89d6a3 100644 --- a/vane-core/src/main/java/org/oddlama/vane/core/module/Module.java +++ b/vane-core/src/main/java/org/oddlama/vane/core/module/Module.java @@ -27,12 +27,19 @@ import org.bstats.bukkit.Metrics; import org.bukkit.NamespacedKey; import org.bukkit.OfflinePlayer; +import org.bukkit.attribute.Attribute; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.FishHook; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerFishEvent; import org.bukkit.event.world.LootGenerateEvent; +import org.bukkit.inventory.ItemStack; import org.bukkit.loot.LootTables; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionAttachment; @@ -515,4 +522,45 @@ public void on_module_loot_generate(final LootGenerateEvent event) { (loc.getBlockZ() & (0xffff << 48))); additional_loot_table.generate_loot(event.getLoot(), local_random); } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void on_module_player_caught_fish(final PlayerFishEvent event) { + // This is a dirty non-commutative way to apply fishing loot tables + // that skews subtable probabilities, + // consider somehow programmatically generating datapacks or + // modifying loot tables directly instead. + if (event.getState() != PlayerFishEvent.State.CAUGHT_FISH) { + return; + } + if (event.getCaught() instanceof Item item_entity) { + final Player player = event.getPlayer(); + final FishHook hook_entity = event.getHook(); + final double player_luck = player.getAttribute(Attribute.LUCK).getValue(); + final ItemStack rod_stack = player.getInventory().getItem(event.getHand()); + final double rod_luck = rod_stack.getEnchantmentLevel(Enchantment.LUCK_OF_THE_SEA); // Can bukkit provide access to fishing_luck_bonus of 1.24 item component system? + final double total_luck = player_luck + rod_luck; + final double weight_fish = Math.max(0, 85 + total_luck * -1); + final double weight_junk = Math.max(0, 10 + total_luck * -2); + final double weight_treasure = hook_entity.isInOpenWater() ? Math.max(0, 5 + total_luck * 2) : 0; + final double roll = random.nextDouble() * (weight_fish + weight_junk + weight_treasure); + NamespacedKey key; + if (roll < weight_fish) { + key = LootTables.FISHING_FISH.getKey(); + } else if (roll < weight_fish + weight_junk) { + key = LootTables.FISHING_JUNK.getKey(); + } else { + key = LootTables.FISHING_TREASURE.getKey(); + } + final var additional_loot_table = additional_loot_tables.get(key); + if (additional_loot_table == null) { + // Do not modify the caught item + return; + } + final var new_item = additional_loot_table.generate_override(new Random(random.nextInt())); + if (new_item == null) { + return; + } + item_entity.setItemStack(new_item); + } + } } From c19286a4e5d8e840b806d941ca4ba5af264b0192 Mon Sep 17 00:00:00 2001 From: Vftdan Date: Sat, 1 Mar 2025 15:23:35 +0100 Subject: [PATCH 2/2] Shuffle elements of an additional loot table when generating a single item Guarantee that every item has a chance to be chosen even when the sum of chances surpasses 100% --- .../java/org/oddlama/vane/core/LootTable.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/vane-core/src/main/java/org/oddlama/vane/core/LootTable.java b/vane-core/src/main/java/org/oddlama/vane/core/LootTable.java index 4d2dbdaf..9d68cfd9 100644 --- a/vane-core/src/main/java/org/oddlama/vane/core/LootTable.java +++ b/vane-core/src/main/java/org/oddlama/vane/core/LootTable.java @@ -1,6 +1,7 @@ package org.oddlama.vane.core; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -34,6 +35,12 @@ public Map> possible_loot() { return possible_loot; } + public List flat_copy() { + List list = new ArrayList<>(); + possible_loot.values().forEach(list::addAll); + return list; + } + public void generate_loot(final List output, final Random random) { for (final var set : possible_loot.values()) { for (final var loot : set) { @@ -48,15 +55,15 @@ public ItemStack generate_override(final Random random) { double total_chance = 0; final double threshold = random.nextDouble(); final List result_container = new ArrayList<>(1); - for (final var set : possible_loot.values()) { - for (final var loot : set) { - total_chance += loot.chance; - if (total_chance > threshold) { - loot.add_sample(result_container, random); - } - if (!result_container.isEmpty()) { - return result_container.get(0); - } + final var loot_list = flat_copy(); + Collections.shuffle(loot_list, random); + for (final var loot : loot_list) { + total_chance += loot.chance; + if (total_chance > threshold) { + loot.add_sample(result_container, random); + } + if (!result_container.isEmpty()) { + return result_container.get(0); } } return null;