433 lines
16 KiB
Java
433 lines
16 KiB
Java
package WayofTime.bloodmagic.tile;
|
|
|
|
import WayofTime.bloodmagic.api.event.BloodMagicCraftedEvent;
|
|
import WayofTime.bloodmagic.api.impl.BloodMagicAPI;
|
|
import WayofTime.bloodmagic.api.impl.recipe.RecipeAlchemyTable;
|
|
import WayofTime.bloodmagic.core.data.*;
|
|
import WayofTime.bloodmagic.core.registry.AlchemyTableRecipeRegistry;
|
|
import WayofTime.bloodmagic.iface.IBindable;
|
|
import WayofTime.bloodmagic.iface.ICustomAlchemyConsumable;
|
|
import WayofTime.bloodmagic.orb.BloodOrb;
|
|
import WayofTime.bloodmagic.orb.IBloodOrb;
|
|
import WayofTime.bloodmagic.recipe.alchemyTable.AlchemyTableRecipe;
|
|
import WayofTime.bloodmagic.util.Constants;
|
|
import WayofTime.bloodmagic.util.helper.NetworkHelper;
|
|
import net.minecraft.block.state.IBlockState;
|
|
import net.minecraft.inventory.ISidedInventory;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
import net.minecraft.tileentity.TileEntity;
|
|
import net.minecraft.util.EnumFacing;
|
|
import net.minecraft.util.ITickable;
|
|
import net.minecraft.util.math.BlockPos;
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
import net.minecraftforge.common.capabilities.Capability;
|
|
import net.minecraftforge.items.CapabilityItemHandler;
|
|
import net.minecraftforge.items.ItemHandlerHelper;
|
|
import org.apache.commons.lang3.ArrayUtils;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
public class TileAlchemyTable extends TileInventory implements ISidedInventory, ITickable {
|
|
public static final int orbSlot = 6;
|
|
public static final int toolSlot = 7;
|
|
public static final int outputSlot = 8;
|
|
|
|
public EnumFacing direction = EnumFacing.NORTH;
|
|
public boolean isSlave = false;
|
|
public int burnTime = 0;
|
|
public int ticksRequired = 1;
|
|
|
|
public BlockPos connectedPos = BlockPos.ORIGIN;
|
|
public boolean[] blockedSlots = new boolean[]{false, false, false, false, false, false};
|
|
|
|
public TileAlchemyTable() {
|
|
super(9, "alchemyTable");
|
|
}
|
|
|
|
public void setInitialTableParameters(EnumFacing direction, boolean isSlave, BlockPos connectedPos) {
|
|
this.isSlave = isSlave;
|
|
this.connectedPos = connectedPos;
|
|
|
|
if (!isSlave) {
|
|
this.direction = direction;
|
|
}
|
|
}
|
|
|
|
public boolean isInvisible() {
|
|
return isSlave();
|
|
}
|
|
|
|
public boolean isInputSlotAccessible(int slot) {
|
|
return !(slot < 6 && slot >= 0) || !blockedSlots[slot];
|
|
}
|
|
|
|
public void toggleInputSlotAccessible(int slot) {
|
|
if (slot < 6 && slot >= 0)
|
|
blockedSlots[slot] = !blockedSlots[slot];
|
|
}
|
|
|
|
@Override
|
|
public void deserialize(NBTTagCompound tag) {
|
|
super.deserialize(tag);
|
|
|
|
isSlave = tag.getBoolean("isSlave");
|
|
direction = EnumFacing.byIndex(tag.getInteger(Constants.NBT.DIRECTION));
|
|
connectedPos = new BlockPos(tag.getInteger(Constants.NBT.X_COORD), tag.getInteger(Constants.NBT.Y_COORD), tag.getInteger(Constants.NBT.Z_COORD));
|
|
|
|
burnTime = tag.getInteger("burnTime");
|
|
ticksRequired = tag.getInteger("ticksRequired");
|
|
|
|
byte[] array = tag.getByteArray("blockedSlots");
|
|
for (int i = 0; i < array.length; i++)
|
|
blockedSlots[i] = array[i] != 0;
|
|
}
|
|
|
|
@Override
|
|
public NBTTagCompound serialize(NBTTagCompound tag) {
|
|
super.serialize(tag);
|
|
|
|
tag.setBoolean("isSlave", isSlave);
|
|
tag.setInteger(Constants.NBT.DIRECTION, direction.getIndex());
|
|
tag.setInteger(Constants.NBT.X_COORD, connectedPos.getX());
|
|
tag.setInteger(Constants.NBT.Y_COORD, connectedPos.getY());
|
|
tag.setInteger(Constants.NBT.Z_COORD, connectedPos.getZ());
|
|
|
|
tag.setInteger("burnTime", burnTime);
|
|
tag.setInteger("ticksRequired", ticksRequired);
|
|
|
|
byte[] blockedSlotArray = new byte[blockedSlots.length];
|
|
for (int i = 0; i < blockedSlots.length; i++)
|
|
blockedSlotArray[i] = (byte) (blockedSlots[i] ? 1 : 0);
|
|
|
|
tag.setByteArray("blockedSlots", blockedSlotArray);
|
|
return tag;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
@Override
|
|
public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
|
|
if (facing != null && capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
|
|
if (this.isSlave()) {
|
|
TileEntity tile = getWorld().getTileEntity(connectedPos);
|
|
if (tile instanceof TileAlchemyTable && !((TileAlchemyTable) tile).isSlave) {
|
|
return (T) tile.getCapability(capability, facing);
|
|
}
|
|
} else {
|
|
return super.getCapability(capability, facing);
|
|
}
|
|
}
|
|
|
|
return super.getCapability(capability, facing);
|
|
}
|
|
|
|
@Override
|
|
public int[] getSlotsForFace(EnumFacing side) {
|
|
switch (side) {
|
|
case DOWN:
|
|
return new int[]{outputSlot};
|
|
case UP:
|
|
return new int[]{orbSlot, toolSlot};
|
|
default:
|
|
return new int[]{0, 1, 2, 3, 4, 5};
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean canInsertItem(int index, ItemStack stack, EnumFacing direction) {
|
|
switch (direction) {
|
|
case DOWN:
|
|
return index != outputSlot && index != orbSlot && index != toolSlot;
|
|
case UP:
|
|
if (index == orbSlot && !stack.isEmpty() && stack.getItem() instanceof IBloodOrb) {
|
|
return true;
|
|
} else if (index == toolSlot) {
|
|
return false; //TODO:
|
|
} else {
|
|
return true;
|
|
}
|
|
default:
|
|
if (this.isSlave) {
|
|
TileEntity tile = getWorld().getTileEntity(connectedPos);
|
|
if (tile instanceof TileAlchemyTable && !((TileAlchemyTable) tile).isSlave) {
|
|
return ((TileAlchemyTable) tile).canInsertItem(index, stack, direction);
|
|
}
|
|
}
|
|
return getAccessibleInputSlots(direction).contains(index);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean canExtractItem(int index, ItemStack stack, EnumFacing direction) {
|
|
switch (direction) {
|
|
case DOWN:
|
|
return index == outputSlot;
|
|
case UP:
|
|
if (index == orbSlot && !stack.isEmpty() && stack.getItem() instanceof IBloodOrb) {
|
|
return true;
|
|
} else if (index == toolSlot) {
|
|
return true; //TODO:
|
|
} else {
|
|
return true;
|
|
}
|
|
default:
|
|
if (this.isSlave) {
|
|
TileEntity tile = getWorld().getTileEntity(connectedPos);
|
|
if (tile instanceof TileAlchemyTable && !((TileAlchemyTable) tile).isSlave) {
|
|
return ((TileAlchemyTable) tile).canExtractItem(index, stack, direction);
|
|
}
|
|
}
|
|
return getAccessibleInputSlots(direction).contains(index);
|
|
}
|
|
}
|
|
|
|
public List<Integer> getAccessibleInputSlots(EnumFacing direction) {
|
|
List<Integer> list = new ArrayList<>();
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
if (isInputSlotAccessible(i)) {
|
|
list.add(i);
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
@Override
|
|
public void update() {
|
|
if (isSlave()) {
|
|
return;
|
|
}
|
|
|
|
List<ItemStack> inputList = new ArrayList<>();
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
if (!getStackInSlot(i).isEmpty()) {
|
|
inputList.add(getStackInSlot(i));
|
|
}
|
|
}
|
|
|
|
int tier = getTierOfOrb();
|
|
|
|
// special recipes like dying
|
|
AlchemyTableRecipe recipe = AlchemyTableRecipeRegistry.getMatchingRecipe(inputList, getWorld(), getPos());
|
|
if (recipe != null && (burnTime > 0 || (!getWorld().isRemote && tier >= recipe.getTierRequired() && this.getContainedLp() >= recipe.getLpDrained()))) {
|
|
if (burnTime == 1)
|
|
notifyUpdate();
|
|
|
|
if (canCraft(recipe.getRecipeOutput(inputList))) {
|
|
ticksRequired = recipe.getTicksRequired();
|
|
burnTime++;
|
|
|
|
if (burnTime == ticksRequired) {
|
|
if (!getWorld().isRemote) {
|
|
int requiredLp = recipe.getLpDrained();
|
|
if (requiredLp > 0) {
|
|
if (!getWorld().isRemote) {
|
|
consumeLp(requiredLp);
|
|
}
|
|
}
|
|
|
|
if (!getWorld().isRemote) {
|
|
craftItem(inputList, recipe);
|
|
}
|
|
}
|
|
|
|
burnTime = 0;
|
|
|
|
IBlockState state = getWorld().getBlockState(pos);
|
|
getWorld().notifyBlockUpdate(getPos(), state, state, 3);
|
|
} else if (burnTime > ticksRequired + 10) {
|
|
burnTime = 0;
|
|
}
|
|
} else {
|
|
burnTime = 0;
|
|
}
|
|
} else { // Simple recipes
|
|
RecipeAlchemyTable recipeAlchemyTable = BloodMagicAPI.INSTANCE.getRecipeRegistrar().getAlchemyTable(inputList);
|
|
if (recipeAlchemyTable != null && (burnTime > 0 || (!getWorld().isRemote && tier >= recipeAlchemyTable.getMinimumTier() && getContainedLp() >= recipeAlchemyTable.getSyphon()))) {
|
|
if (burnTime == 1)
|
|
notifyUpdate();
|
|
|
|
if (canCraft(recipeAlchemyTable.getOutput())) {
|
|
ticksRequired = recipeAlchemyTable.getTicks();
|
|
burnTime++;
|
|
if (burnTime >= ticksRequired) {
|
|
if (!getWorld().isRemote) {
|
|
if (recipeAlchemyTable.getSyphon() > 0) {
|
|
if (consumeLp(recipeAlchemyTable.getSyphon()) < recipeAlchemyTable.getSyphon()) {
|
|
//There was not enough LP to craft or there was no orb
|
|
burnTime = 0;
|
|
notifyUpdate();
|
|
return;
|
|
}
|
|
}
|
|
|
|
ItemStack[] inputs = new ItemStack[0];
|
|
for (ItemStack stack : inputList)
|
|
ArrayUtils.add(inputs, stack.copy());
|
|
|
|
BloodMagicCraftedEvent.AlchemyTable event = new BloodMagicCraftedEvent.AlchemyTable(recipeAlchemyTable.getOutput().copy(), inputs);
|
|
MinecraftForge.EVENT_BUS.post(event);
|
|
|
|
ItemStack outputSlotStack = getStackInSlot(outputSlot);
|
|
if (outputSlotStack.isEmpty())
|
|
setInventorySlotContents(outputSlot, event.getOutput());
|
|
else
|
|
outputSlotStack.grow(event.getOutput().getCount());
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
ItemStack currentStack = getStackInSlot(i);
|
|
if (currentStack.getItem().hasContainerItem(currentStack))
|
|
setInventorySlotContents(i, currentStack.getItem().getContainerItem(currentStack));
|
|
else if (currentStack.getItem() instanceof ICustomAlchemyConsumable)
|
|
setInventorySlotContents(i, ((ICustomAlchemyConsumable) currentStack.getItem()).drainUseOnAlchemyCraft(currentStack));
|
|
else
|
|
currentStack.shrink(1);
|
|
}
|
|
|
|
burnTime = 0;
|
|
notifyUpdate();
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
burnTime = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
public double getProgressForGui() {
|
|
return ((double) burnTime) / ticksRequired;
|
|
}
|
|
|
|
private boolean canCraft(ItemStack output) {
|
|
ItemStack currentOutputStack = getStackInSlot(outputSlot);
|
|
if (output.isEmpty())
|
|
return false;
|
|
if (currentOutputStack.isEmpty())
|
|
return true;
|
|
if (!ItemHandlerHelper.canItemStacksStack(output, currentOutputStack))
|
|
return false;
|
|
int result = currentOutputStack.getCount() + output.getCount();
|
|
return result <= getInventoryStackLimit() && result <= currentOutputStack.getMaxStackSize();
|
|
}
|
|
|
|
public int getTierOfOrb() {
|
|
ItemStack orbStack = getStackInSlot(orbSlot);
|
|
if (!orbStack.isEmpty()) {
|
|
if (orbStack.getItem() instanceof IBloodOrb) {
|
|
BloodOrb orb = ((IBloodOrb) orbStack.getItem()).getOrb(orbStack);
|
|
return orb == null ? 0 : orb.getTier();
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public int getContainedLp() {
|
|
ItemStack orbStack = getStackInSlot(orbSlot);
|
|
if (!orbStack.isEmpty()) {
|
|
if (orbStack.getItem() instanceof IBloodOrb) {
|
|
Binding binding = ((IBindable) orbStack.getItem()).getBinding(orbStack);
|
|
if (binding == null) {
|
|
return 0;
|
|
}
|
|
|
|
SoulNetwork network = NetworkHelper.getSoulNetwork(binding);
|
|
|
|
return network.getCurrentEssence();
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public void craftItem(List<ItemStack> inputList, AlchemyTableRecipe recipe) {
|
|
ItemStack outputStack = recipe.getRecipeOutput(inputList);
|
|
if (this.canCraft(outputStack)) {
|
|
ItemStack currentOutputStack = getStackInSlot(outputSlot);
|
|
|
|
ItemStack[] inputs = new ItemStack[0];
|
|
for (ItemStack stack : inputList)
|
|
ArrayUtils.add(inputs, stack.copy());
|
|
|
|
BloodMagicCraftedEvent.AlchemyTable event = new BloodMagicCraftedEvent.AlchemyTable(outputStack.copy(), inputs);
|
|
MinecraftForge.EVENT_BUS.post(event);
|
|
outputStack = event.getOutput();
|
|
|
|
if (currentOutputStack.isEmpty()) {
|
|
setInventorySlotContents(outputSlot, outputStack);
|
|
} else if (ItemHandlerHelper.canItemStacksStack(outputStack, currentOutputStack)) {
|
|
currentOutputStack.grow(outputStack.getCount());
|
|
}
|
|
|
|
consumeInventory(recipe);
|
|
}
|
|
}
|
|
|
|
public int consumeLp(int requested) {
|
|
ItemStack orbStack = getStackInSlot(orbSlot);
|
|
|
|
if (!orbStack.isEmpty()) {
|
|
if (orbStack.getItem() instanceof IBloodOrb) {
|
|
if (NetworkHelper.syphonFromContainer(orbStack, SoulTicket.item(orbStack, world, pos, requested))) {
|
|
return requested;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public void consumeInventory(AlchemyTableRecipe recipe) {
|
|
ItemStack[] input = new ItemStack[6];
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
input[i] = getStackInSlot(i);
|
|
}
|
|
|
|
ItemStack[] result = recipe.getRemainingItems(input);
|
|
for (int i = 0; i < 6; i++) {
|
|
setInventorySlotContents(i, result[i]);
|
|
}
|
|
}
|
|
|
|
public EnumFacing getDirection() {
|
|
return direction;
|
|
}
|
|
|
|
public boolean isSlave() {
|
|
return isSlave;
|
|
}
|
|
|
|
public int getBurnTime() {
|
|
return burnTime;
|
|
}
|
|
|
|
public int getTicksRequired() {
|
|
return ticksRequired;
|
|
}
|
|
|
|
public BlockPos getConnectedPos() {
|
|
return connectedPos;
|
|
}
|
|
|
|
public boolean[] getBlockedSlots() {
|
|
return blockedSlots;
|
|
}
|
|
|
|
public static int getOrbSlot() {
|
|
return orbSlot;
|
|
}
|
|
|
|
public static int getToolSlot() {
|
|
return toolSlot;
|
|
}
|
|
|
|
public static int getOutputSlot() {
|
|
return outputSlot;
|
|
}
|
|
}
|