blob: a940eb73da39013609ad4c2b2d160571ac6027e6 [file] [log] [blame] [raw]
package mekanism.common.tile;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import mekanism.api.Coord4D;
import mekanism.api.ISalinationSolar;
import mekanism.api.Range4D;
import mekanism.client.SparkleAnimation.INodeChecker;
import mekanism.common.Mekanism;
import mekanism.common.base.IActiveState;
import mekanism.common.base.ITankManager;
import mekanism.common.content.tank.TankUpdateProtocol;
import mekanism.common.network.PacketTileEntity.TileEntityMessage;
import mekanism.common.recipe.RecipeHandler;
import mekanism.common.recipe.RecipeHandler.Recipe;
import mekanism.common.recipe.inputs.FluidInput;
import mekanism.common.recipe.machines.SolarEvaporationRecipe;
import mekanism.common.util.MekanismUtils;
import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class TileEntitySolarEvaporationController extends TileEntitySolarEvaporationBlock implements IActiveState, ITankManager
{
public static final int MAX_OUTPUT = 10000;
public static final int MAX_SOLARS = 4;
public static final int WARMUP = 10000;
public FluidTank inputTank = new FluidTank(0);
public FluidTank outputTank = new FluidTank(MAX_OUTPUT);
public Set<TileEntitySolarEvaporationBlock> tankParts = new HashSet<TileEntitySolarEvaporationBlock>();
public ISalinationSolar[] solars = new ISalinationSolar[4];
public boolean temperatureSet = false;
public double partialInput = 0;
public double partialOutput = 0;
public float biomeTemp = 0;
public float temperature = 0;
public int height = 0;
public boolean structured = false;
public boolean controllerConflict = false;
public boolean isLeftOnFace;
public boolean updatedThisTick = false;
public int clientSolarAmount;
public boolean cacheStructure = false;
public float prevScale;
public TileEntitySolarEvaporationController()
{
super("SolarEvaporationController");
inventory = new ItemStack[4];
}
@Override
public void onUpdate()
{
super.onUpdate();
if(!worldObj.isRemote)
{
updatedThisTick = false;
if(ticker == 5)
{
refresh();
}
updateTemperature();
manageBuckets();
SolarEvaporationRecipe recipe = getRecipe();
if(canOperate(recipe))
{
int outputNeeded = outputTank.getCapacity()-outputTank.getFluidAmount();
int inputStored = inputTank.getFluidAmount();
partialInput += Math.min(inputTank.getFluidAmount(), getTemperature()*recipe.recipeInput.ingredient.amount);
if(partialInput >= 1)
{
int inputInt = (int)Math.floor(partialInput);
inputTank.drain(inputInt, true);
partialInput %= 1;
partialOutput += ((double)inputInt)/recipe.recipeInput.ingredient.amount;
}
if(partialOutput >= 1)
{
int outputInt = (int)Math.floor(partialOutput);
outputTank.fill(new FluidStack(recipe.recipeOutput.output.getFluid(), outputInt), true);
partialOutput %= 1;
}
}
if(structured)
{
if(Math.abs((float)inputTank.getFluidAmount()/inputTank.getCapacity()-prevScale) > 0.01)
{
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList())), new Range4D(Coord4D.get(this)));
prevScale = (float)inputTank.getFluidAmount()/inputTank.getCapacity();
}
}
}
}
public SolarEvaporationRecipe getRecipe()
{
return RecipeHandler.getSolarEvaporationRecipe(new FluidInput(inputTank.getFluid()));
}
@Override
public void onChunkUnload()
{
super.onChunkUnload();
refresh();
}
@Override
public void onNeighborChange(Block block)
{
super.onNeighborChange(block);
refresh();
}
public boolean hasRecipe(Fluid fluid)
{
if(fluid == null)
{
return false;
}
return Recipe.SOLAR_EVAPORATION_PLANT.containsRecipe(fluid);
}
protected void refresh()
{
if(!worldObj.isRemote)
{
if(!updatedThisTick)
{
boolean prev = structured;
clearStructure();
structured = buildStructure();
if(structured != prev)
{
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList())), new Range4D(Coord4D.get(this)));
}
if(structured)
{
inputTank.setCapacity(getMaxFluid());
if(inputTank.getFluid() != null)
{
inputTank.getFluid().amount = Math.min(inputTank.getFluid().amount, getMaxFluid());
}
temperature = Math.min(getMaxTemperature(), getTemperature());
}
else {
clearStructure();
}
}
}
}
public boolean canOperate(SolarEvaporationRecipe recipe)
{
if(!structured || height < 3 || height > 18 || inputTank.getFluid() == null || getTempMultiplier() == 0)
{
return false;
}
if(recipe != null && recipe.canOperate(inputTank, outputTank))
{
return true;
}
return false;
}
private void manageBuckets()
{
if(inventory[2] != null)
{
if(outputTank.getFluid() != null && outputTank.getFluid().amount >= FluidContainerRegistry.BUCKET_VOLUME)
{
if(FluidContainerRegistry.isEmptyContainer(inventory[2]))
{
ItemStack tempStack = FluidContainerRegistry.fillFluidContainer(outputTank.getFluid(), inventory[2]);
if(tempStack != null)
{
if(inventory[3] == null)
{
outputTank.drain(FluidContainerRegistry.BUCKET_VOLUME, true);
inventory[3] = tempStack;
inventory[2].stackSize--;
if(inventory[2].stackSize <= 0)
{
inventory[2] = null;
}
markDirty();
}
else if(tempStack.isItemEqual(inventory[3]) && tempStack.getMaxStackSize() > inventory[3].stackSize)
{
outputTank.drain(FluidContainerRegistry.BUCKET_VOLUME, true);
inventory[3].stackSize++;
inventory[2].stackSize--;
if(inventory[2].stackSize <= 0)
{
inventory[2] = null;
}
markDirty();
}
}
}
}
}
if(structured)
{
if(FluidContainerRegistry.isFilledContainer(inventory[0]))
{
FluidStack itemFluid = FluidContainerRegistry.getFluidForFilledItem(inventory[0]);
if((inputTank.getFluid() == null && itemFluid.amount <= getMaxFluid()) || inputTank.getFluid().amount+itemFluid.amount <= getMaxFluid())
{
if(!hasRecipe(itemFluid.getFluid()) || (inputTank.getFluid() != null && !inputTank.getFluid().isFluidEqual(itemFluid)))
{
return;
}
ItemStack containerItem = inventory[0].getItem().getContainerItem(inventory[0]);
boolean filled = false;
if(containerItem != null)
{
if(inventory[1] == null || (inventory[1].isItemEqual(containerItem) && inventory[1].stackSize+1 <= containerItem.getMaxStackSize()))
{
inventory[0] = null;
if(inventory[1] == null)
{
inventory[1] = containerItem;
}
else {
inventory[1].stackSize++;
}
filled = true;
}
}
else {
inventory[0].stackSize--;
if(inventory[0].stackSize == 0)
{
inventory[0] = null;
}
filled = true;
}
if(filled)
{
inputTank.fill(itemFluid, true);
}
}
}
}
}
private void updateTemperature()
{
float max = getMaxTemperature();
float incr = (max/WARMUP)*getTempMultiplier();
if(getTempMultiplier() == 0)
{
temperature = Math.max(0, getTemperature()-(max/WARMUP));
}
else {
temperature = Math.min(max, getTemperature()+incr);
}
}
public float getTemperature()
{
return temperature;
}
public float getMaxTemperature()
{
if(!structured)
{
return 0;
}
return 1 + (height-3)*0.5F;
}
public float getTempMultiplier()
{
if(!temperatureSet)
{
biomeTemp = worldObj.getBiomeGenForCoordsBody(xCoord, zCoord).getFloatTemperature(xCoord, yCoord, zCoord);
temperatureSet = true;
}
return biomeTemp*((float)getActiveSolars()/MAX_SOLARS);
}
public int getActiveSolars()
{
if(worldObj.isRemote)
{
return clientSolarAmount;
}
int ret = 0;
for(ISalinationSolar solar : solars)
{
if(solar != null && solar.seesSun())
{
ret++;
}
}
return ret;
}
public boolean buildStructure()
{
ForgeDirection right = MekanismUtils.getRight(facing);
height = 0;
controllerConflict = false;
updatedThisTick = true;
if(!scanBottomLayer())
{
height = 0;
return false;
}
Coord4D startPoint = Coord4D.get(this).getFromSide(right);
startPoint = isLeftOnFace ? startPoint.getFromSide(right) : startPoint;
while(startPoint.getFromSide(ForgeDirection.UP).getTileEntity(worldObj) instanceof TileEntitySolarEvaporationBlock)
{
startPoint.step(ForgeDirection.UP);
}
int middle = 0;
Coord4D middlePointer = startPoint.getFromSide(ForgeDirection.DOWN);
while(scanMiddleLayer(middlePointer))
{
middlePointer = middlePointer.getFromSide(ForgeDirection.DOWN);
middle++;
}
if(height < 3 || height > 18 || middle != height-2)
{
height = 0;
return false;
}
structured = scanTopLayer(startPoint);
height = structured ? height : 0;
markDirty();
return structured;
}
public boolean scanTopLayer(Coord4D current)
{
ForgeDirection left = MekanismUtils.getLeft(facing);
ForgeDirection back = MekanismUtils.getBack(facing);
for(int x = 0; x < 4; x++)
{
for(int z = 0; z < 4; z++)
{
Coord4D pointer = current.getFromSide(left, x).getFromSide(back, z);
int corner = getCorner(x, z);
if(corner != -1)
{
if(addSolarPanel(pointer.getTileEntity(worldObj), corner))
{
continue;
}
else if(!addTankPart(pointer.getTileEntity(worldObj)))
{
return false;
}
}
else {
if((x == 1 || x == 2) && (z == 1 || z == 2))
{
if(!pointer.isAirBlock(worldObj))
{
return false;
}
}
else {
TileEntity pointerTile = pointer.getTileEntity(worldObj);
if(!addTankPart(pointerTile))
{
return false;
}
}
}
}
}
return true;
}
public int getMaxFluid()
{
return height*4*TankUpdateProtocol.FLUID_PER_TANK;
}
public int getCorner(int x, int z)
{
if(x == 0 && z == 0)
{
return 0;
}
else if(x == 0 && z == 3)
{
return 1;
}
else if(x == 3 && z == 0)
{
return 2;
}
else if(x == 3 && z == 3)
{
return 3;
}
return -1;
}
public boolean scanMiddleLayer(Coord4D current)
{
ForgeDirection left = MekanismUtils.getLeft(facing);
ForgeDirection back = MekanismUtils.getBack(facing);
for(int x = 0; x < 4; x++)
{
for(int z = 0; z < 4; z++)
{
Coord4D pointer = current.getFromSide(left, x).getFromSide(back, z);
if((x == 1 || x == 2) && (z == 1 || z == 2))
{
if(!pointer.isAirBlock(worldObj))
{
return false;
}
}
else {
TileEntity pointerTile = pointer.getTileEntity(worldObj);
if(!addTankPart(pointerTile))
{
return false;
}
}
}
}
return true;
}
public boolean scanBottomLayer()
{
height = 1;
Coord4D baseBlock = Coord4D.get(this);
while(baseBlock.getFromSide(ForgeDirection.DOWN).getTileEntity(worldObj) instanceof TileEntitySolarEvaporationBlock)
{
baseBlock.step(ForgeDirection.DOWN);
height++;
}
ForgeDirection left = MekanismUtils.getLeft(facing);
ForgeDirection right = MekanismUtils.getRight(facing);
if(!scanBottomRow(baseBlock))
{
return false;
};
if(!scanBottomRow(baseBlock.getFromSide(left)))
{
return false;
};
if(!scanBottomRow(baseBlock.getFromSide(right)))
{
return false;
};
boolean twoLeft = scanBottomRow(baseBlock.getFromSide(left).getFromSide(left));
boolean twoRight = scanBottomRow(baseBlock.getFromSide(right).getFromSide(right));
if(twoLeft == twoRight)
{
return false;
}
isLeftOnFace = twoRight;
return true;
}
/**
* Scans the bottom row of this multiblock, going in a line across the base.
* @param start
* @return
*/
public boolean scanBottomRow(Coord4D start)
{
ForgeDirection back = MekanismUtils.getBack(facing);
Coord4D current = start;
for(int i = 1; i <= 4; i++)
{
TileEntity tile = current.getTileEntity(worldObj);
if(!addTankPart(tile))
{
return false;
}
current = current.getFromSide(back);
}
return true;
}
public boolean addTankPart(TileEntity tile)
{
if(tile instanceof TileEntitySolarEvaporationBlock && (tile == this || !(tile instanceof TileEntitySolarEvaporationController)))
{
if(tile != this)
{
((TileEntitySolarEvaporationBlock)tile).addToStructure(this);
tankParts.add((TileEntitySolarEvaporationBlock)tile);
}
return true;
}
else {
if(tile != this && tile instanceof TileEntitySolarEvaporationController)
{
controllerConflict = true;
}
return false;
}
}
public boolean addSolarPanel(TileEntity tile, int i)
{
if(tile instanceof ISalinationSolar && !tile.isInvalid())
{
solars[i] = (ISalinationSolar)tile;
return true;
}
else {
return false;
}
}
public int getScaledInputLevel(int i)
{
return getMaxFluid() > 0 ? (inputTank.getFluid() != null ? inputTank.getFluid().amount*i / getMaxFluid() : 0) : 0;
}
public int getScaledOutputLevel(int i)
{
return outputTank.getFluid() != null ? outputTank.getFluid().amount*i / MAX_OUTPUT : 0;
}
public int getScaledTempLevel(int i)
{
return (int)(getMaxTemperature() == 0 ? 0 : getTemperature()*i/getMaxTemperature());
}
public Coord4D getRenderLocation()
{
if(!structured)
{
return null;
}
ForgeDirection right = MekanismUtils.getRight(facing);
Coord4D startPoint = Coord4D.get(this).getFromSide(right);
startPoint = isLeftOnFace ? startPoint.getFromSide(right) : startPoint;
startPoint = startPoint.getFromSide(right.getOpposite()).getFromSide(MekanismUtils.getBack(facing));
startPoint.translate(0, -(height-2), 0);
return startPoint;
}
@Override
public void handlePacketData(ByteBuf dataStream)
{
super.handlePacketData(dataStream);
if(dataStream.readBoolean())
{
inputTank.setFluid(new FluidStack(dataStream.readInt(), dataStream.readInt()));
}
else {
inputTank.setFluid(null);
}
if(dataStream.readBoolean())
{
outputTank.setFluid(new FluidStack(dataStream.readInt(), dataStream.readInt()));
}
else {
outputTank.setFluid(null);
}
boolean prev = structured;
structured = dataStream.readBoolean();
controllerConflict = dataStream.readBoolean();
clientSolarAmount = dataStream.readInt();
height = dataStream.readInt();
temperature = dataStream.readFloat();
biomeTemp = dataStream.readFloat();
isLeftOnFace = dataStream.readBoolean();
if(structured != prev)
{
inputTank.setCapacity(getMaxFluid());
worldObj.func_147479_m(xCoord, yCoord, zCoord);
if(structured)
{
Mekanism.proxy.doGenericSparkle(this, new INodeChecker() {
@Override
public boolean isNode(TileEntity tile)
{
return tile instanceof TileEntitySolarEvaporationBlock;
}
});
}
}
MekanismUtils.updateBlock(worldObj, xCoord, yCoord, zCoord);
}
@Override
public ArrayList getNetworkedData(ArrayList data)
{
super.getNetworkedData(data);
if(inputTank.getFluid() != null)
{
data.add(true);
data.add(inputTank.getFluid().fluidID);
data.add(inputTank.getFluid().amount);
}
else {
data.add(false);
}
if(outputTank.getFluid() != null)
{
data.add(true);
data.add(outputTank.getFluid().fluidID);
data.add(outputTank.getFluid().amount);
}
else {
data.add(false);
}
data.add(structured);
data.add(controllerConflict);
data.add(getActiveSolars());
data.add(height);
data.add(temperature);
data.add(biomeTemp);
data.add(isLeftOnFace);
return data;
}
@Override
public void readFromNBT(NBTTagCompound nbtTags)
{
super.readFromNBT(nbtTags);
inputTank.readFromNBT(nbtTags.getCompoundTag("waterTank"));
outputTank.readFromNBT(nbtTags.getCompoundTag("brineTank"));
temperature = nbtTags.getFloat("temperature");
partialInput = nbtTags.getDouble("partialWater");
partialOutput = nbtTags.getDouble("partialBrine");
}
@Override
public void writeToNBT(NBTTagCompound nbtTags)
{
super.writeToNBT(nbtTags);
nbtTags.setTag("waterTank", inputTank.writeToNBT(new NBTTagCompound()));
nbtTags.setTag("brineTank", outputTank.writeToNBT(new NBTTagCompound()));
nbtTags.setFloat("temperature", temperature);
nbtTags.setDouble("partialWater", partialInput);
nbtTags.setDouble("partialBrine", partialOutput);
}
@Override
public boolean canSetFacing(int side)
{
return side != 0 && side != 1;
}
public void clearStructure()
{
for(TileEntitySolarEvaporationBlock tankPart : tankParts)
{
tankPart.controllerGone();
}
tankParts.clear();
solars = new ISalinationSolar[] {null, null, null, null};
}
@Override
@SideOnly(Side.CLIENT)
public AxisAlignedBB getRenderBoundingBox()
{
return INFINITE_EXTENT_AABB;
}
@Override
public boolean getActive()
{
return structured;
}
@Override
public void setActive(boolean active)
{
}
@Override
public boolean renderUpdate()
{
return false;
}
@Override
public boolean lightUpdate()
{
return false;
}
@Override
public Object[] getTanks()
{
return new Object[] {inputTank, outputTank};
}
}