package slimeknights.tconstruct.smeltery.tileentity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import java.util.Arrays;
import javax.annotation.Nonnull;
import slimeknights.mantle.tileentity.TileInventory;
import slimeknights.tconstruct.smeltery.multiblock.MultiblockDetection;
/** Represents a structure that has an inventory where it heats its items. Like a smeltery. */
public abstract class TileHeatingStructure<T extends MultiblockDetection> extends TileMultiblock<T> {
public static final String TAG_FUEL = "fuel";
public static final String TAG_TEMPERATURE = "temperature";
public static final String TAG_NEEDS_FUEL = "needsFuel";
public static final String TAG_ITEM_TEMPERATURES = "itemTemperatures";
public static final String TAG_ITEM_TEMP_REQUIRED = "itemTempRequired";
protected static final int TIME_FACTOR = 8; // basically an "accuracy" so the heat can be more fine grained. required temp is multiplied by this
protected int fuel; // Ticks left until the current fuel is depleted and fuel is taken from the tanks. Depletes every tick
protected int temperature; // internal temperature of the smeltery == speed of the smeltery
protected boolean needsFuel; // If the last tick executed an operation that required fuel.
protected int[] itemTemperatures; // current temperature of each item in the corresponding slot
protected int[] itemTempRequired; // Temperature where the items want to goooooo
public TileHeatingStructure(String name, int inventorySize, int maxStackSize) {
super(name, inventorySize, maxStackSize);
itemTemperatures = new int[0];
itemTempRequired = new int[0];
}
@Override
public void resize(int size) {
super.resize(size);
this.itemTemperatures = Arrays.copyOf(itemTemperatures, size);
this.itemTempRequired = Arrays.copyOf(itemTempRequired, size);
}
public boolean canHeat(int index) {
return temperature >= getHeatRequiredForSlot(index);
}
public float getProgress(int index) {
if(index >= itemTemperatures.length) {
return 0f;
}
return (float) itemTemperatures[index] / (float) itemTempRequired[index];
}
protected void setHeatRequiredForSlot(int index, int heat) {
if(index < itemTempRequired.length) {
itemTempRequired[index] = heat * TIME_FACTOR;
}
}
protected int getHeatRequiredForSlot(int index) {
if(index >= itemTempRequired.length) {
return 0;
}
return itemTempRequired[index] / TIME_FACTOR;
}
/**
* Calculate the heat required for the given slot
*/
protected abstract void updateHeatRequired(int index);
protected void heatItems() {
boolean heatedItem = false;
for(int i = 0; i < getSizeInventory(); i++) {
ItemStack stack = getStackInSlot(i);
if(stack != null) {
// heat item if possible
if(itemTempRequired[i] > 0) {
// fuel is present, turn up the heat
if(hasFuel()) {
// are we done heating?
if(itemTemperatures[i] >= itemTempRequired[i]) {
if(onItemFinishedHeating(stack, i)) {
itemTemperatures[i] = 0;
itemTempRequired[i] = 0;
}
}
// otherwise turn up the heat
else {
itemTemperatures[i] += heatSlot(i);
heatedItem = true;
}
}
else {
// can't heat. no fuel. abort and try to get fuel for next tick
this.needsFuel = true;
return;
}
}
}
else {
itemTemperatures[i] = 0;
}
}
if(heatedItem) {
fuel--;
}
}
protected int heatSlot(int i) {
return temperature / 100; // if your smeltery has <100 heat then it deserves to not create any heat .
}
public int getTemperature(int i) {
if(i < 0 || i >= itemTemperatures.length) {
return 0;
}
return itemTemperatures[i];
}
public int getTempRequired(int i) {
if(i < 0 || i >= itemTempRequired.length) {
return 0;
}
return itemTempRequired[i];
}
public int getTemperature() {
return temperature;
}
@Override
public void setInventorySlotContents(int slot, ItemStack itemstack) {
// reset heat if set to null or a different item
if(itemstack == null || (getStackInSlot(slot) != null && !ItemStack.areItemStacksEqual(itemstack, getStackInSlot(slot)))) {
itemTemperatures[slot] = 0;
}
super.setInventorySlotContents(slot, itemstack);
// when an item gets added, check for its heat required
updateHeatRequired(slot);
}
/**
* Called when an item finished heating up.
* Return true if the processing was successful, then the heating data will be cleared.
*/
protected abstract boolean onItemFinishedHeating(ItemStack stack, int slot);
/**
* Consume fuel if possible and increase the fuel-value accordingly
*/
protected abstract void consumeFuel();
protected void addFuel(int fuel, int newTemperature) {
this.fuel += fuel;
this.needsFuel = false;
this.temperature = newTemperature;
}
public boolean hasFuel() {
return fuel > 0;
}
/* Networking */
public int getFuel() {
return fuel;
}
@SideOnly(Side.CLIENT)
public void updateTemperatureFromPacket(int index, int heat) {
if(index < 0 || index > getSizeInventory() - 1) {
return;
}
itemTemperatures[index] = heat;
}
@SideOnly(Side.CLIENT)
public void updateTempRequiredFromPacket(int index, int heat) {
if(index < 0 || index > getSizeInventory() - 1) {
return;
}
itemTempRequired[index] = heat;
}
/* Loading and Saving */
@SideOnly(Side.CLIENT)
public void updateTemperatureFromPacket(int temperature) {
this.temperature = temperature;
}
@Nonnull
@Override
public NBTTagCompound writeToNBT(NBTTagCompound tags) {
tags = super.writeToNBT(tags);
tags.setInteger(TAG_FUEL, fuel);
tags.setInteger(TAG_TEMPERATURE, temperature);
tags.setBoolean(TAG_NEEDS_FUEL, needsFuel);
tags.setIntArray(TAG_ITEM_TEMPERATURES, itemTemperatures);
tags.setIntArray(TAG_ITEM_TEMP_REQUIRED, itemTempRequired);
return tags;
}
@Override
public void readFromNBT(NBTTagCompound tags) {
super.readFromNBT(tags);
fuel = tags.getInteger(TAG_FUEL);
temperature = tags.getInteger(TAG_TEMPERATURE);
needsFuel = tags.getBoolean(TAG_NEEDS_FUEL);
itemTemperatures = tags.getIntArray(TAG_ITEM_TEMPERATURES);
itemTempRequired = tags.getIntArray(TAG_ITEM_TEMP_REQUIRED);
}
}