/*
* Copyright (c) CovertJaguar, 2014 http://railcraft.info
*
* This code is the property of CovertJaguar
* and may only be used with explicit written
* permission unless otherwise specified on the
* license page at http://railcraft.info/wiki/info:license.
*/
package mods.railcraft.common.blocks.machine.alpha;
import buildcraft.api.statements.IActionExternal;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.*;
import mods.railcraft.common.blocks.RailcraftBlocks;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.IIcon;
import net.minecraftforge.common.util.ForgeDirection;
import mods.railcraft.common.blocks.machine.IEnumMachine;
import mods.railcraft.common.blocks.machine.MultiBlockPattern;
import mods.railcraft.common.blocks.machine.TileMultiBlock;
import mods.railcraft.common.blocks.machine.TileMultiBlockInventory;
import mods.railcraft.common.blocks.machine.beta.ISteamUser;
import mods.railcraft.common.gui.EnumGui;
import mods.railcraft.common.gui.GuiHandler;
import mods.railcraft.common.fluids.Fluids;
import mods.railcraft.common.util.inventory.InvTools;
import mods.railcraft.common.util.inventory.wrappers.InventoryMapper;
import mods.railcraft.common.fluids.FluidHelper;
import mods.railcraft.common.fluids.TankManager;
import mods.railcraft.common.fluids.tanks.StandardTank;
import mods.railcraft.common.fluids.tanks.FakeTank;
import mods.railcraft.common.fluids.tanks.FilteredTank;
import mods.railcraft.common.plugins.buildcraft.actions.Actions;
import mods.railcraft.common.plugins.buildcraft.triggers.IHasWork;
import mods.railcraft.common.util.effects.EffectManager;
import mods.railcraft.common.util.misc.Game;
import mods.railcraft.common.util.misc.MiscTools;
import mods.railcraft.common.util.sounds.SoundHelper;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.IFluidHandler;
import static net.minecraftforge.common.util.ForgeDirection.DOWN;
import static net.minecraftforge.common.util.ForgeDirection.UP;
public class TileSteamOven extends TileMultiBlockInventory implements IFluidHandler, ISidedInventory, ISteamUser, IHasWork {
public static void placeSteamOven(World world, int x, int y, int z, List<ItemStack> input, List<ItemStack> output) {
for (MultiBlockPattern pattern : TileSteamOven.patterns) {
Map<Character, Integer> blockMapping = new HashMap<Character, Integer>();
blockMapping.put('B', EnumMachineAlpha.STEAM_OVEN.ordinal());
TileEntity tile = pattern.placeStructure(world, x, y, z, RailcraftBlocks.getBlockMachineAlpha(), blockMapping);
if (tile instanceof TileSteamOven) {
TileSteamOven master = (TileSteamOven) tile;
for (int slot = 0; slot < 9; slot++) {
if (input != null && slot < input.size())
master.inv.setInventorySlotContents(TileSteamOven.SLOT_INPUT + slot, input.get(slot));
if (output != null && slot < output.size())
master.inv.setInventorySlotContents(TileSteamOven.SLOT_OUTPUT + slot, output.get(slot));
}
}
return;
}
}
enum Texture {
DOOR_TL(6), DOOR_TR(7), DOOR_BL(8), DOOR_BR(9), SIDE(2), CAP(0);
private final int index;
private Texture(int index) {
this.index = index;
}
public IIcon getIcon() {
return EnumMachineAlpha.STEAM_OVEN.getTexture(index);
}
}
private static final ForgeDirection[] UP_DOWN_AXES = new ForgeDirection[]{UP, DOWN};
private static final int STEAM_PER_BATCH = 8000;
private static final int TOTAL_COOK_TIME = 256;
private static final int COOK_STEP = 16;
private static final int ITEMS_SMELTED = 9;
public static final int SLOT_INPUT = 0;
public static final int SLOT_OUTPUT = 9;
private static final int[] SLOTS = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
private static final int TANK_CAPACITY = 8 * FluidHelper.BUCKET_VOLUME;
private final static List<MultiBlockPattern> patterns = new ArrayList<MultiBlockPattern>();
private ForgeDirection facing = ForgeDirection.NORTH;
public int cookTime;
public boolean finishedCycle = false;
private boolean paused = false;
private final TankManager tankManager = new TankManager();
private final StandardTank tank;
private final IInventory invInput = new InventoryMapper(this, SLOT_INPUT, 9);
private final IInventory invOutput = new InventoryMapper(this, SLOT_OUTPUT, 9, false);
private final Set<IActionExternal> actions = new HashSet<IActionExternal>();
static {
char[][][] map = {
{
{'*', 'O', 'O', '*'},
{'O', 'O', 'O', 'O'},
{'O', 'O', 'O', 'O'},
{'*', 'O', 'O', '*'},},
{
{'*', 'O', 'O', '*'},
{'O', 'B', 'B', 'O'},
{'O', 'B', 'B', 'O'},
{'*', 'O', 'O', '*'}
},
{
{'*', 'O', 'O', '*'},
{'O', 'B', 'B', 'O'},
{'O', 'B', 'B', 'O'},
{'*', 'O', 'O', '*'}
},
{
{'*', 'O', 'O', '*'},
{'O', 'O', 'O', 'O'},
{'O', 'O', 'O', 'O'},
{'*', 'O', 'O', '*'},},};
patterns.add(new MultiBlockPattern(map));
}
public TileSteamOven() {
super("railcraft.gui.steam.oven", 18, patterns);
tank = new FilteredTank(TANK_CAPACITY, Fluids.STEAM.get(), this);
tankManager.add(tank);
}
@Override
public IEnumMachine getMachineType() {
return EnumMachineAlpha.STEAM_OVEN;
}
public TankManager getTankManager() {
TileSteamOven mBlock = (TileSteamOven) getMasterBlock();
if (mBlock != null)
return mBlock.tankManager;
return null;
}
@Override
public IIcon getIcon(int side) {
if (isStructureValid() && side == getFacing().ordinal())
switch (side) {
case 2:
if (getPatternPositionY() == 2) {
if (getPatternPositionX() == 2)
return Texture.DOOR_TL.getIcon();
return Texture.DOOR_TR.getIcon();
}
if (getPatternPositionX() == 2)
return Texture.DOOR_BL.getIcon();
return Texture.DOOR_BR.getIcon();
case 3:
if (getPatternPositionY() == 2) {
if (getPatternPositionX() == 1)
return Texture.DOOR_TL.getIcon();
return Texture.DOOR_TR.getIcon();
}
if (getPatternPositionX() == 1)
return Texture.DOOR_BL.getIcon();
return Texture.DOOR_BR.getIcon();
case 4:
if (getPatternPositionY() == 2) {
if (getPatternPositionZ() == 1)
return Texture.DOOR_TL.getIcon();
return Texture.DOOR_TR.getIcon();
}
if (getPatternPositionZ() == 1)
return Texture.DOOR_BL.getIcon();
return Texture.DOOR_BR.getIcon();
case 5:
if (getPatternPositionY() == 2) {
if (getPatternPositionZ() == 2)
return Texture.DOOR_TL.getIcon();
return Texture.DOOR_TR.getIcon();
}
if (getPatternPositionZ() == 2)
return Texture.DOOR_BL.getIcon();
return Texture.DOOR_BR.getIcon();
}
if (side > 1)
return Texture.SIDE.getIcon();
return Texture.CAP.getIcon();
}
public int getCookProgressScaled(int i) {
int scale = (getCookTime() * i) / TOTAL_COOK_TIME;
scale = Math.min(scale, i);
scale = Math.max(scale, 0);
return scale;
}
public int getCookTime() {
TileSteamOven masterOven = (TileSteamOven) getMasterBlock();
if (masterOven != null)
return masterOven.cookTime;
return -1;
}
public ForgeDirection getFacing() {
TileSteamOven masterOven = (TileSteamOven) getMasterBlock();
if (masterOven != null)
return masterOven.facing;
return facing;
}
public boolean hasFinishedCycle() {
TileSteamOven mBlock = (TileSteamOven) getMasterBlock();
return mBlock != null && mBlock.finishedCycle;
}
public void setHasFinishedCycle(boolean finished) {
if (finishedCycle != finished) {
finishedCycle = finished;
sendUpdateToClient();
}
}
@Override
public void updateEntity() {
super.updateEntity();
if (Game.isNotHost(getWorld())) {
if (hasFinishedCycle())
EffectManager.instance.steamEffect(worldObj, this, +0.25);
return;
}
if (isMaster()) {
if (clock % 16 == 0)
processActions();
if (clock % COOK_STEP == 0) {
setHasFinishedCycle(false);
if (!paused)
if (hasRecipe()) {
if (cookTime <= 0 && drainSteam())
cookTime = 1;
else if (cookTime > 0) {
cookTime += COOK_STEP;
if (cookTime >= TOTAL_COOK_TIME)
if (smeltItems()) {
cookTime = 0;
setHasFinishedCycle(true);
SoundHelper.playSound(worldObj, xCoord, yCoord, zCoord, SoundHelper.SOUND_STEAM_BURST, 1, (float) (1 + MiscTools.getRand().nextGaussian() * 0.1));
}
}
} else
cookTime = 0;
}
}
}
private boolean drainSteam() {
FluidStack steam = tank.drain(STEAM_PER_BATCH, false);
if (steam != null && steam.amount >= STEAM_PER_BATCH) {
tank.drain(STEAM_PER_BATCH, true);
return true;
}
return false;
}
private boolean hasRecipe() {
for (int slot = 0; slot < 9; slot++) {
ItemStack stack = invInput.getStackInSlot(slot);
if (stack != null && FurnaceRecipes.smelting().getSmeltingResult(stack) != null)
return true;
}
return false;
}
private boolean smeltItems() {
int count = 0;
boolean changed = true;
boolean smelted = false;
while (count < ITEMS_SMELTED && changed) {
changed = false;
for (int slot = 0; slot < 9 && count < ITEMS_SMELTED; slot++) {
ItemStack stack = invInput.getStackInSlot(slot);
if (stack != null) {
ItemStack output = FurnaceRecipes.smelting().getSmeltingResult(stack);
if (output != null && InvTools.isRoomForStack(output, invOutput)) {
ItemStack remainder = InvTools.moveItemStack(output.copy(), invOutput);
if (remainder == null) {
invInput.decrStackSize(slot, 1);
changed = true;
count++;
}
}
}
}
smelted |= changed;
}
return smelted;
}
@Override
public void onBlockPlacedBy(EntityLivingBase player) {
super.onBlockPlacedBy(player);
facing = MiscTools.getHorizontalSideClosestToPlayer(worldObj, xCoord, yCoord, zCoord, player);
}
@Override
public boolean rotateBlock(ForgeDirection axis) {
if (axis == UP || axis == DOWN)
return false;
TileSteamOven master = (TileSteamOven) getMasterBlock();
if (master != null) {
if (master.facing == axis)
master.facing = axis.getOpposite();
else
master.facing = axis;
master.scheduleMasterRetest();
return true;
}
return false;
}
@Override
public ForgeDirection[] getValidRotations() {
return UP_DOWN_AXES;
}
@Override
public boolean openGui(EntityPlayer player) {
TileMultiBlock masterBlock = getMasterBlock();
if (masterBlock != null) {
GuiHandler.openGui(EnumGui.STEAN_OVEN, player, worldObj, masterBlock.xCoord, masterBlock.yCoord, masterBlock.zCoord);
return true;
}
return false;
}
@Override
public void writeToNBT(NBTTagCompound data) {
super.writeToNBT(data);
tankManager.writeTanksToNBT(data);
data.setInteger("cookTime", cookTime);
data.setByte("facing", (byte) facing.ordinal());
}
@Override
public void readFromNBT(NBTTagCompound data) {
super.readFromNBT(data);
tankManager.readTanksFromNBT(data);
cookTime = data.getInteger("cookTime");
facing = ForgeDirection.getOrientation(data.getByte("facing"));
}
@Override
public void writePacketData(DataOutputStream data) throws IOException {
super.writePacketData(data);
data.writeByte(facing.ordinal());
data.writeBoolean(finishedCycle);
}
@Override
public void readPacketData(DataInputStream data) throws IOException {
super.readPacketData(data);
byte f = data.readByte();
finishedCycle = data.readBoolean();
if (f != facing.ordinal()) {
facing = ForgeDirection.getOrientation(f);
markBlockForUpdate();
}
}
@Override
public int fill(ForgeDirection from, FluidStack resource, boolean doFill) {
if (resource == null) return 0;
TankManager tMan = getTankManager();
if (tMan == null)
return 0;
return tMan.fill(0, resource, doFill);
}
@Override
public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) {
return null;
}
@Override
public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) {
return null;
}
@Override
public boolean canFill(ForgeDirection from, Fluid fluid) {
return fluid == null || Fluids.STEAM.is(fluid);
}
@Override
public boolean canDrain(ForgeDirection from, Fluid fluid) {
return false;
}
@Override
public FluidTankInfo[] getTankInfo(ForgeDirection dir) {
TankManager tMan = getTankManager();
if (tMan != null)
return tMan.getTankInfo();
return FakeTank.INFO;
}
@Override
public int[] getAccessibleSlotsFromSide(int side) {
return SLOTS;
}
@Override
public boolean canInsertItem(int slot, ItemStack stack, int side) {
return isItemValidForSlot(slot, stack);
}
@Override
public boolean canExtractItem(int slot, ItemStack itemstack, int side) {
return slot >= SLOT_OUTPUT;
}
@Override
public boolean isItemValidForSlot(int slot, ItemStack stack) {
if (stack == null)
return false;
if (slot >= SLOT_OUTPUT)
return false;
return FurnaceRecipes.smelting().getSmeltingResult(stack) != null;
}
@Override
public boolean hasWork() {
TileSteamOven mBlock = (TileSteamOven) getMasterBlock();
if (mBlock != null)
return mBlock.cookTime > 0;
return false;
}
private void processActions() {
paused = false;
for (IActionExternal action : actions) {
if (action == Actions.PAUSE)
paused = true;
}
actions.clear();
}
@Override
public void actionActivated(IActionExternal action) {
TileSteamOven mBlock = (TileSteamOven) getMasterBlock();
if (mBlock != null)
mBlock.actions.add(action);
}
}