From f0f3398172aa20a2ea1f29bf69799c4a920f24e3 Mon Sep 17 00:00:00 2001 From: Senmori Date: Sun, 12 Aug 2018 18:23:28 +1000 Subject: SPIGOT-1936: LootTable API --- src/main/java/org/bukkit/Bukkit.java | 11 ++ src/main/java/org/bukkit/Server.java | 9 ++ src/main/java/org/bukkit/block/Chest.java | 3 +- src/main/java/org/bukkit/block/Dispenser.java | 3 +- src/main/java/org/bukkit/block/Dropper.java | 3 +- src/main/java/org/bukkit/block/Hopper.java | 3 +- src/main/java/org/bukkit/block/ShulkerBox.java | 3 +- src/main/java/org/bukkit/entity/Mob.java | 4 +- .../org/bukkit/entity/minecart/HopperMinecart.java | 3 +- .../bukkit/entity/minecart/StorageMinecart.java | 3 +- src/main/java/org/bukkit/loot/LootContext.java | 168 +++++++++++++++++++++ src/main/java/org/bukkit/loot/LootTable.java | 37 +++++ src/main/java/org/bukkit/loot/LootTables.java | 128 ++++++++++++++++ src/main/java/org/bukkit/loot/Lootable.java | 51 +++++++ 14 files changed, 421 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/bukkit/loot/LootContext.java create mode 100644 src/main/java/org/bukkit/loot/LootTable.java create mode 100644 src/main/java/org/bukkit/loot/LootTables.java create mode 100644 src/main/java/org/bukkit/loot/Lootable.java (limited to 'src') diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java index bdd5a753..5bea055b 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java @@ -33,6 +33,7 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Merchant; import org.bukkit.inventory.Recipe; +import org.bukkit.loot.LootTable; import org.bukkit.map.MapView; import org.bukkit.permissions.Permissible; import org.bukkit.plugin.PluginManager; @@ -1253,6 +1254,16 @@ public final class Bukkit { return server.getTag(registry, tag, clazz); } + /** + * Gets the specified {@link LootTable}. + * + * @param key the name of the LootTable + * @return the LootTable, or null if no LootTable is found with that name + */ + public static LootTable getLootTable(NamespacedKey key) { + return server.getLootTable(key); + } + /** * @see UnsafeValues * @return the unsafe values instance diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java index 4daee3b0..c3535e90 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -33,6 +33,7 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Merchant; import org.bukkit.inventory.Recipe; +import org.bukkit.loot.LootTable; import org.bukkit.map.MapView; import org.bukkit.permissions.Permissible; import org.bukkit.plugin.PluginManager; @@ -1036,6 +1037,14 @@ public interface Server extends PluginMessageRecipient { */ Tag getTag(String registry, NamespacedKey tag, Class clazz); + /** + * Gets the specified {@link LootTable}. + * + * @param key the name of the LootTable + * @return the LootTable, or null if no LootTable is found with that name + */ + LootTable getLootTable(NamespacedKey key); + /** * @see UnsafeValues * @return the unsafe values instance diff --git a/src/main/java/org/bukkit/block/Chest.java b/src/main/java/org/bukkit/block/Chest.java index 97dc7813..815d79a5 100644 --- a/src/main/java/org/bukkit/block/Chest.java +++ b/src/main/java/org/bukkit/block/Chest.java @@ -2,11 +2,12 @@ package org.bukkit.block; import org.bukkit.Nameable; import org.bukkit.inventory.Inventory; +import org.bukkit.loot.Lootable; /** * Represents a captured state of a chest. */ -public interface Chest extends Container, Nameable { +public interface Chest extends Container, Nameable, Lootable { /** * Gets the inventory of the chest block represented by this block state. diff --git a/src/main/java/org/bukkit/block/Dispenser.java b/src/main/java/org/bukkit/block/Dispenser.java index 108332df..2741625d 100644 --- a/src/main/java/org/bukkit/block/Dispenser.java +++ b/src/main/java/org/bukkit/block/Dispenser.java @@ -1,12 +1,13 @@ package org.bukkit.block; import org.bukkit.Nameable; +import org.bukkit.loot.Lootable; import org.bukkit.projectiles.BlockProjectileSource; /** * Represents a captured state of a dispenser. */ -public interface Dispenser extends Container, Nameable { +public interface Dispenser extends Container, Nameable, Lootable { /** * Gets the BlockProjectileSource object for the dispenser. diff --git a/src/main/java/org/bukkit/block/Dropper.java b/src/main/java/org/bukkit/block/Dropper.java index ba091374..2e8c3f71 100644 --- a/src/main/java/org/bukkit/block/Dropper.java +++ b/src/main/java/org/bukkit/block/Dropper.java @@ -1,11 +1,12 @@ package org.bukkit.block; import org.bukkit.Nameable; +import org.bukkit.loot.Lootable; /** * Represents a captured state of a dropper. */ -public interface Dropper extends Container, Nameable { +public interface Dropper extends Container, Nameable, Lootable { /** * Tries to drop a randomly selected item from the dropper's inventory, diff --git a/src/main/java/org/bukkit/block/Hopper.java b/src/main/java/org/bukkit/block/Hopper.java index bc3aeef2..73fce5f3 100644 --- a/src/main/java/org/bukkit/block/Hopper.java +++ b/src/main/java/org/bukkit/block/Hopper.java @@ -1,8 +1,9 @@ package org.bukkit.block; import org.bukkit.Nameable; +import org.bukkit.loot.Lootable; /** * Represents a captured state of a hopper. */ -public interface Hopper extends Container, Nameable { } +public interface Hopper extends Container, Nameable, Lootable { } diff --git a/src/main/java/org/bukkit/block/ShulkerBox.java b/src/main/java/org/bukkit/block/ShulkerBox.java index 4c1740e7..8e061e4a 100644 --- a/src/main/java/org/bukkit/block/ShulkerBox.java +++ b/src/main/java/org/bukkit/block/ShulkerBox.java @@ -2,11 +2,12 @@ package org.bukkit.block; import org.bukkit.DyeColor; import org.bukkit.Nameable; +import org.bukkit.loot.Lootable; /** * Represents a captured state of a ShulkerBox. */ -public interface ShulkerBox extends Container, Nameable { +public interface ShulkerBox extends Container, Nameable, Lootable { /** * Get the {@link DyeColor} corresponding to this ShulkerBox diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java index 15dee0ee..d029d34e 100644 --- a/src/main/java/org/bukkit/entity/Mob.java +++ b/src/main/java/org/bukkit/entity/Mob.java @@ -1,9 +1,11 @@ package org.bukkit.entity; +import org.bukkit.loot.Lootable; + /** * Represents a Mob. Mobs are living entities with simple AI. */ -public interface Mob extends LivingEntity { +public interface Mob extends LivingEntity, Lootable { /** * Instructs this Mob to set the specified LivingEntity as its target. diff --git a/src/main/java/org/bukkit/entity/minecart/HopperMinecart.java b/src/main/java/org/bukkit/entity/minecart/HopperMinecart.java index 03304319..8ced5403 100644 --- a/src/main/java/org/bukkit/entity/minecart/HopperMinecart.java +++ b/src/main/java/org/bukkit/entity/minecart/HopperMinecart.java @@ -2,11 +2,12 @@ package org.bukkit.entity.minecart; import org.bukkit.entity.Minecart; import org.bukkit.inventory.InventoryHolder; +import org.bukkit.loot.Lootable; /** * Represents a Minecart with a Hopper inside it */ -public interface HopperMinecart extends Minecart, InventoryHolder { +public interface HopperMinecart extends Minecart, InventoryHolder, Lootable { /** * Checks whether or not this Minecart will pick up diff --git a/src/main/java/org/bukkit/entity/minecart/StorageMinecart.java b/src/main/java/org/bukkit/entity/minecart/StorageMinecart.java index 4f04ab40..9ea403e6 100644 --- a/src/main/java/org/bukkit/entity/minecart/StorageMinecart.java +++ b/src/main/java/org/bukkit/entity/minecart/StorageMinecart.java @@ -2,11 +2,12 @@ package org.bukkit.entity.minecart; import org.bukkit.entity.Minecart; import org.bukkit.inventory.InventoryHolder; +import org.bukkit.loot.Lootable; /** * Represents a minecart with a chest. These types of {@link Minecart * minecarts} have their own inventory that can be accessed using methods * from the {@link InventoryHolder} interface. */ -public interface StorageMinecart extends Minecart, InventoryHolder { +public interface StorageMinecart extends Minecart, InventoryHolder, Lootable { } diff --git a/src/main/java/org/bukkit/loot/LootContext.java b/src/main/java/org/bukkit/loot/LootContext.java new file mode 100644 index 00000000..a2c83e58 --- /dev/null +++ b/src/main/java/org/bukkit/loot/LootContext.java @@ -0,0 +1,168 @@ +package org.bukkit.loot; + +import org.apache.commons.lang.Validate; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.HumanEntity; + +/** + * Represents additional information a {@link LootTable} can use to modify it's + * generated loot. + */ +public final class LootContext { + + public static final int DEFAULT_LOOT_MODIFIER = -1; + + private final Location location; + private final float luck; + private final int lootingModifier; + private final Entity lootedEntity; + private final HumanEntity killer; + + private LootContext(Location location, float luck, int lootingModifier, Entity lootedEntity, HumanEntity killer) { + Validate.notNull(location, "LootContext location cannot be null"); + Validate.notNull(location.getWorld(), "LootContext World cannot be null"); + this.location = location; + this.luck = luck; + this.lootingModifier = lootingModifier; + this.lootedEntity = lootedEntity; + this.killer = killer; + } + + /** + * The {@link Location} to store where the loot will be generated. + * + * @return the Location of where the loot will be generated + */ + public Location getLocation() { + return location; + } + + /** + * Represents the {@link org.bukkit.potion.PotionEffectType#LUCK} that an + * entity can have. The higher the value the better chance of receiving more + * loot. + * + * @return luck + */ + public float getLuck() { + return luck; + } + + /** + * Represents the + * {@link org.bukkit.enchantments.Enchantment#LOOT_BONUS_MOBS} the + * {@link #getKiller()} entity has on their equipped item. + * + * This value is only set via + * {@link LootContext.Builder#lootingModifier(int)}. If not set, the + * {@link #getKiller()} entity's looting level will be used instead. + * + * @return the looting level + */ + public int getLootingModifier() { + return lootingModifier; + } + + /** + * Get the {@link Entity} that was killed. Can be null. + * + * @return the looted entity or null + */ + public Entity getLootedEntity() { + return lootedEntity; + } + + /** + * Get the {@link HumanEntity} who killed the {@link #getLootedEntity()}. + * Can be null. + * + * @return the killer entity, or null. + */ + public HumanEntity getKiller() { + return killer; + } + + /** + * Utility class to make building {@link LootContext} easier. The only + * required argument is {@link Location} with a valid (non-null) + * {@link org.bukkit.World}. + */ + public static class Builder { + + private final Location location; + private float luck; + private int lootingModifier = LootContext.DEFAULT_LOOT_MODIFIER; + private Entity lootedEntity; + private HumanEntity killer; + + /** + * Creates a new LootContext.Builder instance to facilitate easy + * creation of {@link LootContext}s. + * + * @param location the location the LootContext should use + */ + public Builder(Location location) { + this.location = location; + } + + /** + * Set how much luck to have when generating loot. + * + * @param luck the luck level + * @return the Builder + */ + public Builder luck(float luck) { + this.luck = luck; + return this; + } + + /** + * Set the {@link org.bukkit.enchantments.Enchantment#LOOT_BONUS_MOBS} + * level equivalent to use when generating loot. Values less than or + * equal to 0 will force the {@link LootTable} to only return a single + * {@link org.bukkit.inventory.ItemStack} per pool. + * + * @param modifier the looting level modifier + * @return the Builder + */ + public Builder lootingModifier(int modifier) { + this.lootingModifier = modifier; + return this; + } + + /** + * The entity that was killed. + * + * @param lootedEntity the looted entity + * @return the Builder + */ + public Builder lootedEntity(Entity lootedEntity) { + this.lootedEntity = lootedEntity; + return this; + } + + /** + * Set the {@link org.bukkit.entity.HumanEntity} that killed + * {@link #getLootedEntity()}. This entity will be used to get the + * looting level if {@link #lootingModifier(int)} is not set. + * + * @param killer the killer entity + * @return the Builder + */ + public Builder killer(HumanEntity killer) { + this.killer = killer; + return this; + } + + /** + * Create a new {@link LootContext} instance using the supplied + * parameters. + * + * @return a new {@link LootContext} instance + */ + public LootContext build() { + return new LootContext(location, luck, lootingModifier, lootedEntity, killer); + } + } +} diff --git a/src/main/java/org/bukkit/loot/LootTable.java b/src/main/java/org/bukkit/loot/LootTable.java new file mode 100644 index 00000000..30b16200 --- /dev/null +++ b/src/main/java/org/bukkit/loot/LootTable.java @@ -0,0 +1,37 @@ +package org.bukkit.loot; + +import org.bukkit.Keyed; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.Collection; +import java.util.Random; + +/** + * LootTables are technical files that represent what items should be in + * naturally generated containers, what items should be dropped when killing a + * mob, or what items can be fished. + * + * See the + * Minecraft Wiki for more information. + */ +public interface LootTable extends Keyed { + + /** + * Returns a mutable list of loot generated by this LootTable. + * + * @param random the random instance to use to generate loot + * @param context context within to populate loot + * @return a list of ItemStacks + */ + Collection populateLoot(Random random, LootContext context); + + /** + * Attempt to fill an inventory with this LootTable's loot. + * + * @param inventory the inventory to fill + * @param random the random instance to use to generate loot + * @param context context within to populate loot + */ + void fillInventory(Inventory inventory, Random random, LootContext context); +} diff --git a/src/main/java/org/bukkit/loot/LootTables.java b/src/main/java/org/bukkit/loot/LootTables.java new file mode 100644 index 00000000..613a198e --- /dev/null +++ b/src/main/java/org/bukkit/loot/LootTables.java @@ -0,0 +1,128 @@ +package org.bukkit.loot; + +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; + +/** + * This enum holds a list of all known {@link LootTable}s offered by Mojang. + * This list is not guaranteed to be accurate in future versions. + * + * See the + * + * Minecraft Wiki for more information on loot tables. + */ +public enum LootTables implements Keyed { + + EMPTY("empty"), + // Chests/Dispensers - treasure chests + ABANDONED_MINESHAFT("chests/abandoned_mineshaft"), + BURIED_TREASURE("chests/buried_treasure"), + DESERT_PYRAMID("chests/desert_pyramid"), + END_CITY_TREASURE("chests/end_city_treasure"), + IGLOO_CHEST("chests/igloo_chest"), + JUNGLE_TEMPLE("chests/jungle_temple"), + JUNGLE_TEMPLE_DISPENSER("chests/jungle_temple_dispenser"), + NETHER_BRIDGE("chests/nether_bridge"), + SHIPWRECK_MAP("chests/shipwreck_map"), + SHIPWRECK_SUPPLY("chests/shipwreck_supply"), + SHIPWRECK_TREASURE("chests/shipwreck_treasure"), + SIMPLE_DUNGEON("chests/simple_dungeon"), + SPAWN_BONUS_CHEST("chests/spawn_bonus_chest"), + STRONGHOLD_CORRIDOR("chests/stronghold_corridor"), + STRONGHOLD_CROSSING("chests/stronghold_crossing"), + STRONGHOLD_LIBRARY("chests/stronghold_library"), + UNDERWATER_RUIN_BIG("chests/underwater_ruin_big"), + UNDERWATER_RUIN_SMALL("chests/underwater_ruin_small"), + VILLAGE_BLACKSMITH("chests/village_blacksmith"), + WOODLAND_MANSION("chests/woodland_mansion"), + // Entities + BAT("entities/bat"), + BLAZE("entities/blaze"), + CAVE_SPIDER("entities/cave_spider"), + CHICKEN("entities/chicken"), + COD("entities/cod"), + COW("entities/cow"), + CREEPER("entities/creeper"), + DOLPHIN("entities/dolphin"), + DONKEY("entities/donkey"), + DROWNED("entities/drowned"), + ELDER_GUARDIAN("entities/elder_guardian"), + ENDERMAN("entities/enderman"), + ENDERMITE("entities/endermite"), + ENDER_DRAGON("entities/ender_dragon"), + EVOKER("entities/evoker"), + GHAST("entities/ghast"), + GIANT("entities/giant"), + GUARDIAN("entities/guardian"), + HORSE("entities/horse"), + HUSK("entities/husk"), + IRON_GOLEM("entities/iron_golem"), + LLAMA("entities/llama"), + MAGMA_CUBE("entities/magma_cube"), + MULE("entities/mule"), + MUSHROOM_COW("entities/mushroom_cow"), + OCELOT("entities/ocelot"), + PARROT("entities/parrot"), + PHANTOM("entities/phantom"), + PIG("entities/pig"), + POLAR_BEAR("entities/polar_bear"), + PUFFERFISH("entities/pufferfish"), + RABBIT("entities/rabbit"), + SALMON("entities/salmon"), + // Sheep entry here, moved below for organizational purposes + SHULKER("entities/shulker"), + SILVERFISH("entities/silverfish"), + SKELETON("entities/skeleton"), + SKELETON_HORSE("entities/skeleton_horse"), + SLIME("entities/slime"), + SNOW_GOLEM("entities/snow_golem"), + SPIDER("entities/spider"), + SQUID("entities/squid"), + STRAY("entities/stray"), + TROPICAL_FISH("entities/tropical_fish"), + TURTLE("entities/turtle"), + VEX("entities/vex"), + VILLAGER("entities/villager"), + VINDICATOR("entities/vindicator"), + WITCH("entities/witch"), + WITHER_SKELETON("entities/wither_skeleton"), + WOLF("entities/wolf"), + ZOMBIE("entities/zombie"), + ZOMBIE_HORSE("entities/zombie_horse"), + ZOMBIE_PIGMAN("entities/zombie_pigman"), + ZOMBIE_VILLAGER("entities/zombie_villager"), + // Gameplay + FISHING("gameplay/fishing"), + FISHING_FISH("gameplay/fishing/fish"), + FISHING_JUNK("gameplay/fishing/junk"), + FISHING_TREASURE("gameplay/fishing/treasure"), + // Sheep + SHEEP("entities/sheep"), + SHEEP_BLACK("entities/sheep/black"), + SHEEP_BLUE("entities/sheep/blue"), + SHEEP_BROWN("entities/sheep/brown"), + SHEEP_CYAN("entities/sheep/cyan"), + SHEEP_GRAY("entities/sheep/gray"), + SHEEP_GREEN("entities/sheep/green"), + SHEEP_LIGHT_BLUE("entities/sheep/light_blue"), + SHEEP_LIME("entities/sheep/lime"), + SHEEP_MAGENTA("entities/sheep/magenta"), + SHEEP_ORANGE("entities/sheep/orange"), + SHEEP_PINK("entities/sheep/pink"), + SHEEP_PURPLE("entities/sheep/purple"), + SHEEP_RED("entities/sheep/red"), + SHEEP_WHITE("entities/sheep/white"), + SHEEP_YELLOW("entities/sheep/yellow"), + ; + + private final String location; + + private LootTables(String location) { + this.location = location; + } + + @Override + public NamespacedKey getKey() { + return NamespacedKey.minecraft(location); + } +} diff --git a/src/main/java/org/bukkit/loot/Lootable.java b/src/main/java/org/bukkit/loot/Lootable.java new file mode 100644 index 00000000..f4b3d021 --- /dev/null +++ b/src/main/java/org/bukkit/loot/Lootable.java @@ -0,0 +1,51 @@ +package org.bukkit.loot; + +/** + * Represents a {@link org.bukkit.block.Container} or a + * {@link org.bukkit.entity.Mob} that can have a loot table. + *
+ * Container loot will only generate upon opening, and only when the container + * is first opened. + *
+ * Entities will only generate loot upon death. + */ +public interface Lootable { + + /** + * Set the loot table for a container or entity. + *
+ * To remove a loot table use null. Do not use {@link LootTables#EMPTY} to + * clear a LootTable. + * + * @param table the Loot Table this {@link org.bukkit.block.Container} or + * {@link org.bukkit.entity.Mob} will have. + */ + void setLootTable(LootTable table); + + /** + * Gets the Loot Table attached to this block or entity. + *
+ * + * If an block/entity does not have a loot table, this will return null, NOT + * an empty loot table. + * + * @return the Loot Table attached to this block or entity. + */ + LootTable getLootTable(); + + /** + * Set the seed used when this Loot Table generates loot. + * + * @param seed the seed to used to generate loot. Default is 0. + */ + void setSeed(long seed); + + /** + * Get the Loot Table's seed. + *
+ * The seed is used when generating loot. + * + * @return the seed + */ + long getSeed(); +} -- cgit v1.2.3