From 67ffd916412d44c763c85da69736ed1bd6abac79 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sat, 9 Jan 2021 02:25:36 -0700 Subject: [PATCH] add enchantment to loot tables --- .../terra/api/platform/handle/ItemHandle.java | 7 ++ .../platform/inventory/item/Enchantment.java | 14 ++++ .../api/platform/inventory/item/ItemMeta.java | 5 ++ .../terra/api/structures/loot/Entry.java | 16 ++++- .../loot/functions/AmountFunction.java | 4 +- .../loot/functions/DamageFunction.java | 4 +- .../loot/functions/EnchantFunction.java | 64 +++++++++++++++++++ .../{Function.java => LootFunction.java} | 2 +- .../bukkit/handles/BukkitItemHandle.java | 18 ++++++ .../terra/bukkit/util/BukkitConversions.java | 16 ----- .../terra/bukkit/util/MinecraftUtils.java | 8 +++ .../terra/bukkit/world/BukkitAdapter.java | 10 +++ .../world/inventory/BukkitItemMeta.java | 18 ++++++ .../inventory/meta/BukkitEnchantment.java | 38 +++++++++++ .../fabric/inventory/FabricItemHandle.java | 6 ++ 15 files changed, 206 insertions(+), 24 deletions(-) create mode 100644 common/src/main/java/com/dfsek/terra/api/platform/inventory/item/Enchantment.java create mode 100644 common/src/main/java/com/dfsek/terra/api/structures/loot/functions/EnchantFunction.java rename common/src/main/java/com/dfsek/terra/api/structures/loot/functions/{Function.java => LootFunction.java} (93%) delete mode 100644 platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/util/BukkitConversions.java create mode 100644 platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/util/MinecraftUtils.java create mode 100644 platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/inventory/meta/BukkitEnchantment.java diff --git a/common/src/main/java/com/dfsek/terra/api/platform/handle/ItemHandle.java b/common/src/main/java/com/dfsek/terra/api/platform/handle/ItemHandle.java index ce26fa2ac..fe2fe39d0 100644 --- a/common/src/main/java/com/dfsek/terra/api/platform/handle/ItemHandle.java +++ b/common/src/main/java/com/dfsek/terra/api/platform/handle/ItemHandle.java @@ -2,7 +2,14 @@ package com.dfsek.terra.api.platform.handle; import com.dfsek.terra.api.platform.block.MaterialData; import com.dfsek.terra.api.platform.inventory.ItemStack; +import com.dfsek.terra.api.platform.inventory.item.Enchantment; + +import java.util.Set; public interface ItemHandle { ItemStack newItemStack(MaterialData material, int amount); + + Enchantment getEnchantment(String id); + + Set getEnchantments(); } diff --git a/common/src/main/java/com/dfsek/terra/api/platform/inventory/item/Enchantment.java b/common/src/main/java/com/dfsek/terra/api/platform/inventory/item/Enchantment.java new file mode 100644 index 000000000..e8f404f34 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/platform/inventory/item/Enchantment.java @@ -0,0 +1,14 @@ +package com.dfsek.terra.api.platform.inventory.item; + +import com.dfsek.terra.api.platform.Handle; +import com.dfsek.terra.api.platform.inventory.ItemStack; + +public interface Enchantment extends Handle { + boolean canEnchantItem(ItemStack itemStack); + + String getID(); + + boolean conflictsWith(Enchantment other); + + int getMaxLevel(); +} diff --git a/common/src/main/java/com/dfsek/terra/api/platform/inventory/item/ItemMeta.java b/common/src/main/java/com/dfsek/terra/api/platform/inventory/item/ItemMeta.java index 6c20f2a4b..0189c5755 100644 --- a/common/src/main/java/com/dfsek/terra/api/platform/inventory/item/ItemMeta.java +++ b/common/src/main/java/com/dfsek/terra/api/platform/inventory/item/ItemMeta.java @@ -2,5 +2,10 @@ package com.dfsek.terra.api.platform.inventory.item; import com.dfsek.terra.api.platform.Handle; +import java.util.Map; + public interface ItemMeta extends Handle { + Map getEnchantments(); + + void addEnchantment(Enchantment enchantment, int level); } diff --git a/common/src/main/java/com/dfsek/terra/api/structures/loot/Entry.java b/common/src/main/java/com/dfsek/terra/api/structures/loot/Entry.java index 66a819baf..d676a1b25 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/loot/Entry.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/loot/Entry.java @@ -5,7 +5,8 @@ import com.dfsek.terra.api.platform.block.MaterialData; import com.dfsek.terra.api.platform.inventory.ItemStack; import com.dfsek.terra.api.structures.loot.functions.AmountFunction; import com.dfsek.terra.api.structures.loot.functions.DamageFunction; -import com.dfsek.terra.api.structures.loot.functions.Function; +import com.dfsek.terra.api.structures.loot.functions.EnchantFunction; +import com.dfsek.terra.api.structures.loot.functions.LootFunction; import com.dfsek.terra.api.util.GlueList; import net.jafama.FastMath; import org.json.simple.JSONArray; @@ -20,7 +21,7 @@ import java.util.Random; public class Entry { private final MaterialData item; private final long weight; - private final List functions = new GlueList<>(); + private final List functions = new GlueList<>(); private final TerraPlugin main; /** @@ -63,6 +64,15 @@ public class Entry { long minDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("min"); functions.add(new DamageFunction(FastMath.toIntExact(minDamage), FastMath.toIntExact(maxDamage))); break; + case "minecraft:enchant_with_levels": + case "enchant_with_levels": + long maxEnchant = (long) ((JSONObject) ((JSONObject) function).get("levels")).get("max"); + long minEnchant = (long) ((JSONObject) ((JSONObject) function).get("levels")).get("min"); + JSONArray disabled = null; + if(((JSONObject) function).containsKey("disabled_enchants")) + disabled = (JSONArray) ((JSONObject) function).get("disabled_enchants"); + functions.add(new EnchantFunction(FastMath.toIntExact(minEnchant), FastMath.toIntExact(maxEnchant), disabled, main)); + break; } } } @@ -76,7 +86,7 @@ public class Entry { */ public ItemStack getItem(Random r) { ItemStack item = main.getItemHandle().newItemStack(this.item, 1); - for(Function f : functions) { + for(LootFunction f : functions) { item = f.apply(item, r); } return item; diff --git a/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/AmountFunction.java b/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/AmountFunction.java index b268fb637..f83498fec 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/AmountFunction.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/AmountFunction.java @@ -6,9 +6,9 @@ import com.dfsek.terra.api.platform.inventory.ItemStack; import java.util.Random; /** - * Loot Function fot setting the amount of an item. + * Loot LootFunction fot setting the amount of an item. */ -public class AmountFunction implements Function { +public class AmountFunction implements LootFunction { private final int max; private final int min; diff --git a/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/DamageFunction.java b/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/DamageFunction.java index 3afb8ecdb..704fdcfa8 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/DamageFunction.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/DamageFunction.java @@ -7,9 +7,9 @@ import com.dfsek.terra.api.platform.inventory.item.ItemMeta; import java.util.Random; /** - * Loot Function for setting the damage on items in Loot Tables + * Loot LootFunction for setting the damage on items in Loot Tables */ -public class DamageFunction implements Function { +public class DamageFunction implements LootFunction { private final int max; private final int min; diff --git a/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/EnchantFunction.java b/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/EnchantFunction.java new file mode 100644 index 000000000..0debec4ee --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/EnchantFunction.java @@ -0,0 +1,64 @@ +package com.dfsek.terra.api.structures.loot.functions; + +import com.dfsek.terra.api.platform.TerraPlugin; +import com.dfsek.terra.api.platform.inventory.ItemStack; +import com.dfsek.terra.api.platform.inventory.item.Enchantment; +import com.dfsek.terra.api.platform.inventory.item.ItemMeta; +import com.dfsek.terra.api.util.GlueList; +import net.jafama.FastMath; +import org.json.simple.JSONArray; + +import java.util.Collections; +import java.util.List; +import java.util.Random; + +public class EnchantFunction implements LootFunction { + private final int min; + private final int max; + private final JSONArray disabled; + private final TerraPlugin main; + + + public EnchantFunction(int min, int max, JSONArray disabled, TerraPlugin main) { + this.max = max; + this.min = min; + this.disabled = disabled; + this.main = main; + } + + /** + * Applies the function to an ItemStack. + * + * @param original The ItemStack on which to apply the function. + * @param r The Random instance to use. + * @return - ItemStack - The mutated ItemStack. + */ + @Override + public ItemStack apply(ItemStack original, Random r) { + double enchant = (r.nextDouble() * (max - min)) + min; + List possible = new GlueList<>(); + for(Enchantment ench : main.getItemHandle().getEnchantments()) { + if(ench.canEnchantItem(original) && (disabled == null || !this.disabled.contains(ench.getID()))) { + possible.add(ench); + } + } + int numEnchant = (r.nextInt((int) FastMath.abs(enchant)) / 10 + 1); + Collections.shuffle(possible); + ItemMeta meta = original.getItemMeta(); + iter: + for(int i = 0; i < numEnchant && i < possible.size(); i++) { + Enchantment chosen = possible.get(i); + for(Enchantment ench : meta.getEnchantments().keySet()) { + if(chosen.conflictsWith(ench)) continue iter; + } + int lvl = r.nextInt(1 + (int) (((enchant / 40 > 1) ? 1 : enchant / 40) * (chosen.getMaxLevel()))); + try { + meta.addEnchantment(chosen, FastMath.max(lvl, 1)); + } catch(IllegalArgumentException e) { + main.getLogger().warning("Attempted to enchant " + original.getType() + " with " + chosen + " at level " + FastMath.max(lvl, 1) + ", but an unexpected exception occurred! Usually this is caused by a misbehaving enchantment plugin."); + } + } + original.setItemMeta(meta); + return original; + } +} diff --git a/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/Function.java b/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/LootFunction.java similarity index 93% rename from common/src/main/java/com/dfsek/terra/api/structures/loot/functions/Function.java rename to common/src/main/java/com/dfsek/terra/api/structures/loot/functions/LootFunction.java index b3993abe6..5b882c830 100644 --- a/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/Function.java +++ b/common/src/main/java/com/dfsek/terra/api/structures/loot/functions/LootFunction.java @@ -8,7 +8,7 @@ import java.util.Random; /** * Interface for mutating items in Loot Tables. */ -public interface Function { +public interface LootFunction { /** * Applies the function to an ItemStack. * diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/handles/BukkitItemHandle.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/handles/BukkitItemHandle.java index 8116e2f80..aa8531e67 100644 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/handles/BukkitItemHandle.java +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/handles/BukkitItemHandle.java @@ -3,12 +3,30 @@ package com.dfsek.terra.bukkit.handles; import com.dfsek.terra.api.platform.block.MaterialData; import com.dfsek.terra.api.platform.handle.ItemHandle; import com.dfsek.terra.api.platform.inventory.ItemStack; +import com.dfsek.terra.api.platform.inventory.item.Enchantment; +import com.dfsek.terra.bukkit.util.MinecraftUtils; +import com.dfsek.terra.bukkit.world.BukkitAdapter; import com.dfsek.terra.bukkit.world.block.BukkitMaterialData; import com.dfsek.terra.bukkit.world.inventory.BukkitItemStack; +import org.bukkit.NamespacedKey; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; public class BukkitItemHandle implements ItemHandle { @Override public ItemStack newItemStack(MaterialData material, int amount) { return new BukkitItemStack(new org.bukkit.inventory.ItemStack(((BukkitMaterialData) material).getHandle(), amount)); } + + @Override + public Enchantment getEnchantment(String id) { + return BukkitAdapter.adapt(org.bukkit.enchantments.Enchantment.getByKey(NamespacedKey.minecraft(MinecraftUtils.stripMinecraftNamespace(id)))); + } + + @Override + public Set getEnchantments() { + return Arrays.stream(org.bukkit.enchantments.Enchantment.values()).map(BukkitAdapter::adapt).collect(Collectors.toSet()); + } } diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/util/BukkitConversions.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/util/BukkitConversions.java deleted file mode 100644 index 9d0673950..000000000 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/util/BukkitConversions.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.dfsek.terra.bukkit.util; - -import com.dfsek.terra.api.math.vector.Vector3; -import com.dfsek.terra.bukkit.world.BukkitWorld; -import org.bukkit.Location; -import org.bukkit.util.Vector; - -public final class BukkitConversions { - public static Vector3 toTerraVector(Vector bukkit) { - return new Vector3(bukkit.getX(), bukkit.getY(), bukkit.getZ()); - } - - public static Location toBukkitLocation(com.dfsek.terra.api.math.vector.Location terra) { - return new Location(((BukkitWorld) terra.getWorld()).getHandle(), terra.getX(), terra.getY(), terra.getZ()); - } -} diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/util/MinecraftUtils.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/util/MinecraftUtils.java new file mode 100644 index 000000000..0c36bc946 --- /dev/null +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/util/MinecraftUtils.java @@ -0,0 +1,8 @@ +package com.dfsek.terra.bukkit.util; + +public final class MinecraftUtils { + public static String stripMinecraftNamespace(String in) { + if(in.startsWith("minecraft:")) return in.substring("minecraft:".length()); + return in; + } +} diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/BukkitAdapter.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/BukkitAdapter.java index b7ba7da2f..462474a4e 100644 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/BukkitAdapter.java +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/BukkitAdapter.java @@ -10,9 +10,11 @@ import com.dfsek.terra.api.platform.block.data.Rail; import com.dfsek.terra.api.platform.block.data.RedstoneWire; import com.dfsek.terra.api.platform.block.data.Slab; import com.dfsek.terra.api.platform.block.data.Stairs; +import com.dfsek.terra.api.platform.inventory.item.Enchantment; import com.dfsek.terra.api.platform.world.Chunk; import com.dfsek.terra.api.platform.world.World; import com.dfsek.terra.bukkit.BukkitCommandSender; +import com.dfsek.terra.bukkit.world.inventory.meta.BukkitEnchantment; import org.bukkit.Location; import org.bukkit.util.Vector; @@ -338,4 +340,12 @@ public final class BukkitAdapter { public static org.bukkit.Chunk adapt(Chunk chunk) { return (org.bukkit.Chunk) chunk.getHandle(); } + + public static Enchantment adapt(org.bukkit.enchantments.Enchantment enchantment) { + return new BukkitEnchantment(enchantment); + } + + public static org.bukkit.enchantments.Enchantment adapt(Enchantment enchantment) { + return ((BukkitEnchantment) enchantment).getHandle(); + } } diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/inventory/BukkitItemMeta.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/inventory/BukkitItemMeta.java index 3e9e4299f..a8bc30131 100644 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/inventory/BukkitItemMeta.java +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/inventory/BukkitItemMeta.java @@ -1,9 +1,15 @@ package com.dfsek.terra.bukkit.world.inventory; +import com.dfsek.terra.api.platform.inventory.item.Enchantment; import com.dfsek.terra.api.platform.inventory.item.ItemMeta; +import com.dfsek.terra.bukkit.world.BukkitAdapter; import com.dfsek.terra.bukkit.world.inventory.meta.BukkitDamageable; +import com.dfsek.terra.bukkit.world.inventory.meta.BukkitEnchantment; import org.bukkit.inventory.meta.Damageable; +import java.util.HashMap; +import java.util.Map; + public class BukkitItemMeta implements ItemMeta { private final org.bukkit.inventory.meta.ItemMeta delegate; @@ -20,4 +26,16 @@ public class BukkitItemMeta implements ItemMeta { public org.bukkit.inventory.meta.ItemMeta getHandle() { return delegate; } + + @Override + public Map getEnchantments() { + Map map = new HashMap<>(); + delegate.getEnchants().forEach((enchantment, integer) -> map.put(BukkitAdapter.adapt(enchantment), integer)); + return map; + } + + @Override + public void addEnchantment(Enchantment enchantment, int level) { + delegate.addEnchant(((BukkitEnchantment) enchantment).getHandle(), level, true); + } } diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/inventory/meta/BukkitEnchantment.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/inventory/meta/BukkitEnchantment.java new file mode 100644 index 000000000..577414c28 --- /dev/null +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/world/inventory/meta/BukkitEnchantment.java @@ -0,0 +1,38 @@ +package com.dfsek.terra.bukkit.world.inventory.meta; + +import com.dfsek.terra.api.platform.inventory.ItemStack; +import com.dfsek.terra.api.platform.inventory.item.Enchantment; +import com.dfsek.terra.bukkit.world.inventory.BukkitItemStack; + +public class BukkitEnchantment implements Enchantment { + private final org.bukkit.enchantments.Enchantment delegate; + + public BukkitEnchantment(org.bukkit.enchantments.Enchantment delegate) { + this.delegate = delegate; + } + + @Override + public org.bukkit.enchantments.Enchantment getHandle() { + return delegate; + } + + @Override + public boolean canEnchantItem(ItemStack itemStack) { + return delegate.canEnchantItem(((BukkitItemStack) itemStack).getHandle()); + } + + @Override + public String getID() { + return delegate.getKey().toString(); + } + + @Override + public boolean conflictsWith(Enchantment other) { + return delegate.conflictsWith(((BukkitEnchantment) other).getHandle()); + } + + @Override + public int getMaxLevel() { + return delegate.getMaxLevel(); + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/inventory/FabricItemHandle.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/inventory/FabricItemHandle.java index 203be849b..afe191821 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/inventory/FabricItemHandle.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/inventory/FabricItemHandle.java @@ -3,10 +3,16 @@ package com.dfsek.terra.fabric.inventory; import com.dfsek.terra.api.platform.block.MaterialData; import com.dfsek.terra.api.platform.handle.ItemHandle; import com.dfsek.terra.api.platform.inventory.ItemStack; +import com.dfsek.terra.api.platform.inventory.item.Enchantment; public class FabricItemHandle implements ItemHandle { @Override public ItemStack newItemStack(MaterialData material, int amount) { return null; } + + @Override + public Enchantment getEnchantment(String id) { + return null; + } }