SPIGOT-1936: LootTable API

By: Senmori <thesenmori@gmail.com>
This commit is contained in:
Bukkit/Spigot 2018-08-12 18:23:28 +10:00
parent 15d9fd30b9
commit f50aec2a42
14 changed files with 421 additions and 8 deletions

View file

@ -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

View file

@ -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 {
*/
<T extends Keyed> Tag<T> getTag(String registry, NamespacedKey tag, Class<T> 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

View file

@ -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.

View file

@ -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.

View file

@ -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,

View file

@ -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 { }

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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 {
}

View file

@ -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);
}
}
}

View file

@ -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 <a href="https://minecraft.gamepedia.com/Loot_table">
* Minecraft Wiki</a> 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<ItemStack> 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);
}

View file

@ -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
* <a href="https://minecraft.gamepedia.com/Loot_table#List_of_loot_tables">
* Minecraft Wiki</a> 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);
}
}

View file

@ -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.
* <br>
* Container loot will only generate upon opening, and only when the container
* is <i>first</i> opened.
* <br>
* Entities will only generate loot upon death.
*/
public interface Lootable {
/**
* Set the loot table for a container or entity.
* <br>
* 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.
* <br>
*
* 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.
* <br>
* The seed is used when generating loot.
*
* @return the seed
*/
long getSeed();
}