package choonster.testmod3.inventory.itemhandler;
import choonster.testmod3.util.IWorldContainer;
import choonster.testmod3.util.InventoryUtils;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntityLockableLoot;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.storage.loot.ILootContainer;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.world.storage.loot.LootTable;
import net.minecraftforge.common.util.Constants;
import javax.annotation.Nullable;
import java.util.Random;
/**
* An inventory that generates its contents from a {@link LootTable} the first time it's accessed by a player.
* <p>
* Adapted from {@link TileEntityLockableLoot}.
*
* @author Choonster
*/
public class ItemHandlerLoot extends ItemHandlerNameable implements ILootContainer {
/**
* The {@link IWorldContainer} to get the {@link World} from.
*/
protected final IWorldContainer worldContainer;
/**
* The location of the {@link LootTable} to generate loot from.
* <p>
* This will be {@code null} if no {@link LootTable} has been set or loot has already been generated.
*/
protected ResourceLocation lootTableLocation;
/**
* The random seed to use when generating loot.
*/
protected long lootTableSeed;
public ItemHandlerLoot(ITextComponent defaultName, IWorldContainer worldContainer) {
super(defaultName);
this.worldContainer = worldContainer;
}
public ItemHandlerLoot(int size, ITextComponent defaultName, IWorldContainer worldContainer) {
super(size, defaultName);
this.worldContainer = worldContainer;
}
public ItemHandlerLoot(NonNullList<ItemStack> stacks, ITextComponent defaultName, IWorldContainer worldContainer) {
super(stacks, defaultName);
this.worldContainer = worldContainer;
}
/**
* Write the {@link LootTable} location and seed to NBT if they're present.
*
* @param compound The compound tag
* @return Was the location written to NBT?
*/
protected boolean checkLootAndWrite(NBTTagCompound compound) {
if (lootTableLocation != null) {
compound.setString("LootTable", lootTableLocation.toString());
if (lootTableSeed != 0L) {
compound.setLong("LootTableSeed", lootTableSeed);
}
return true;
} else {
return false;
}
}
/**
* Read the {@link LootTable} location and seed from NBT if they're present.
*
* @param compound The compound tag
* @return Was the location read from NBT?
*/
protected boolean checkLootAndRead(NBTTagCompound compound) {
if (compound.hasKey("LootTable", Constants.NBT.TAG_STRING)) {
lootTableLocation = new ResourceLocation(compound.getString("LootTable"));
lootTableSeed = compound.getLong("LootTableSeed");
return true;
} else {
return false;
}
}
@Override
public NBTTagCompound serializeNBT() {
final NBTTagCompound tagCompound = super.serializeNBT();
if (checkLootAndWrite(tagCompound)) { // If the LootTable location exists, don't write the inventory contents to NBT
tagCompound.removeTag("Items");
}
return tagCompound;
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
if (checkLootAndRead(nbt)) { // If the LootTable location exists, don't read the inventory contents from NBT
setSize(nbt.hasKey("Size", Constants.NBT.TAG_INT) ? nbt.getInteger("Size") : stacks.size());
onLoad();
} else {
super.deserializeNBT(nbt);
}
}
/**
* Fill this inventory with loot.
* <p>
* Does nothing if no loot table has been set, loot has already been generated or this is being called on the client side.
*
* @param player The player whose Luck to use when generating loot
*/
public void fillWithLoot(@Nullable EntityPlayer player) {
final World world = worldContainer.getContainedWorld();
if (lootTableLocation != null && !world.isRemote) {
final LootTable lootTable = world.getLootTableManager().getLootTableFromLocation(lootTableLocation);
lootTableLocation = null;
final Random random = lootTableSeed == 0 ? new Random() : new Random(lootTableSeed);
final LootContext.Builder builder = new LootContext.Builder((WorldServer) world);
if (player != null) {
builder.withLuck(player.getLuck());
}
InventoryUtils.fillItemHandlerWithLoot(this, lootTable, random, builder.build());
}
}
@Override
public ItemStack getStackInSlot(int slot) {
fillWithLoot(null);
return super.getStackInSlot(slot);
}
@Override
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
fillWithLoot(null);
return super.insertItem(slot, stack, simulate);
}
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate) {
fillWithLoot(null);
return super.extractItem(slot, amount, simulate);
}
@Override
public void setStackInSlot(int slot, ItemStack stack) {
fillWithLoot(null);
super.setStackInSlot(slot, stack);
}
@Nullable
@Override
public ResourceLocation getLootTable() {
return lootTableLocation;
}
}