Hbm-s-Nuclear-Tech-GIT/src/main/java/com/hbm/tileentity/machine/TileEntityMachineTurbineGas.java
2023-06-30 11:57:28 +02:00

562 lines
18 KiB
Java

package com.hbm.tileentity.machine;
import java.util.HashMap;
import com.hbm.blocks.BlockDummyable;
import com.hbm.handler.pollution.PollutionHandler;
import com.hbm.handler.pollution.PollutionHandler.PollutionType;
import com.hbm.interfaces.IControlReceiver;
import com.hbm.inventory.fluid.tank.FluidTank;
import com.hbm.inventory.fluid.trait.FT_Combustible;
import com.hbm.inventory.fluid.trait.FT_Combustible.FuelGrade;
import com.hbm.inventory.gui.GUIMachineTurbineGas;
import com.hbm.inventory.container.ContainerMachineTurbineGas;
import com.hbm.inventory.fluid.FluidType;
import com.hbm.inventory.fluid.Fluids;
import com.hbm.items.machine.IItemFluidIdentifier;
import com.hbm.lib.Library;
import com.hbm.main.MainRegistry;
import com.hbm.sound.AudioWrapper;
import com.hbm.tileentity.IGUIProvider;
import com.hbm.tileentity.TileEntityMachinePolluting;
import api.hbm.energy.IEnergyGenerator;
import api.hbm.fluid.IFluidStandardTransceiver;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
public class TileEntityMachineTurbineGas extends TileEntityMachinePolluting implements IFluidStandardTransceiver, IEnergyGenerator, IControlReceiver, IGUIProvider {
public long power;
public static final long maxPower = 1000000L;
public int rpm; //0-100, crescent moon gauge, used for calculating the amount of power generated, starts past 10%
public int temp; //0-800, used for figuring out how much water to boil, starts boiling at 300°C
public int rpmIdle = 10;
public int tempIdle = 300;
public int powerSliderPos; //goes from 0 to 60, 0 is idle, 60 is max power
public int throttle; //the same thing, but goes from 0 to 100
public boolean autoMode;
public int state = 0; //0 is offline, -1 is startup, 1 is online
public int counter = 0; //used to startup and shutdown
public int instantPowerOutput;
public FluidTank[] tanks;
private AudioWrapper audio;
public static HashMap<FluidType, Double> fuelMaxCons = new HashMap(); //fuel consumption per tick at max power
static {
fuelMaxCons.put(Fluids.GAS, 50D); // natgas doesn't burn well so it burns faster to compensate
fuelMaxCons.put(Fluids.SYNGAS, 10D); // syngas just fucks
fuelMaxCons.put(Fluids.OXYHYDROGEN, 100D); // oxyhydrogen is terrible so it needs to burn a ton for the bare minimum
fuelMaxCons.put(Fluids.REFORMGAS, 2.5D); // halved because it's too powerful
// default to 5 if not in list
}
//TODO particles from heat exchanger maybe? maybe in a future
public TileEntityMachineTurbineGas() {
super(2, 5_000);
this.tanks = new FluidTank[4];
tanks[0] = new FluidTank(Fluids.GAS, 100000);
tanks[1] = new FluidTank(Fluids.LUBRICANT, 16000);
tanks[2] = new FluidTank(Fluids.WATER, 16000);
tanks[3] = new FluidTank(Fluids.HOTSTEAM, 160000);
}
@Override
public void updateEntity() {
if(!worldObj.isRemote) {
throttle = powerSliderPos * 100 / 60;
if(slots[1] != null && slots[1].getItem() instanceof IItemFluidIdentifier) {
FluidType fluid = ((IItemFluidIdentifier) slots[1].getItem()).getType(worldObj, xCoord, yCoord, zCoord, slots[1]);
if(fluid.hasTrait(FT_Combustible.class) && fluid.getTrait(FT_Combustible.class).getGrade() == FuelGrade.GAS) {
tanks[0].setTankType(fluid);
}
}
switch(state) { //what to do when turbine offline, starting up and online
case 0:
shutdown();
break;
case -1:
stopIfNotReady();
startup();
break;
case 1:
stopIfNotReady();
run();
break;
default:
break;
}
if(autoMode) { //power production depending on power requirement
//scales the slider proportionally to the power gauge
int powerSliderTarget = 60 - (int) (60 * power / maxPower);
if(powerSliderTarget > powerSliderPos) { //makes the auto slider slide instead of snapping into position
powerSliderPos++;
}
else if(powerSliderTarget < powerSliderPos) {
powerSliderPos--;
}
}
ForgeDirection dir = ForgeDirection.getOrientation(this.getBlockMetadata() - BlockDummyable.offset);
ForgeDirection rot = dir.getRotation(ForgeDirection.UP);
NBTTagCompound data = new NBTTagCompound();
data.setLong("power", Math.min(this.power, this.maxPower)); //set first to get an unmodified view of how much power was generated before deductions from the net
//do net/battery deductions first...
power = Library.chargeItemsFromTE(slots, 0, power, maxPower);
this.sendPower(worldObj, xCoord - dir.offsetZ * 5, yCoord + 1, zCoord + dir.offsetX * 5, rot); //sends out power
//...and then cap it. Prevents potential future cases where power would be limited due to the fuel being too strong and the buffer too small.
if(this.power > this.maxPower)
this.power = this.maxPower;
for(int i = 0; i < 2; i++) { //fuel and lube
this.trySubscribe(tanks[i].getTankType(), worldObj, xCoord - dir.offsetX * 2 + rot.offsetX, yCoord, zCoord - dir.offsetZ * 2 + rot.offsetZ, dir.getOpposite());
this.trySubscribe(tanks[i].getTankType(), worldObj, xCoord + dir.offsetX * 2 + rot.offsetX, yCoord, zCoord + dir.offsetZ * 2 + rot.offsetZ, dir);
this.sendSmoke(xCoord - dir.offsetX * 2 + rot.offsetX, yCoord, zCoord - dir.offsetZ * 2 + rot.offsetZ, dir.getOpposite());
this.sendSmoke(xCoord + dir.offsetX * 2 + rot.offsetX, yCoord, zCoord + dir.offsetZ * 2 + rot.offsetZ, dir);
}
//water
this.trySubscribe(tanks[2].getTankType(), worldObj, xCoord - dir.offsetX * 2 + rot.offsetX * -4, yCoord, zCoord - dir.offsetZ * 2 + rot.offsetZ * -4, dir.getOpposite());
this.trySubscribe(tanks[2].getTankType(), worldObj, xCoord + dir.offsetX * 2 + rot.offsetX * -4, yCoord, zCoord + dir.offsetZ * 2 + rot.offsetZ * -4, dir);
//steam
this.sendFluid(tanks[3], worldObj, xCoord + dir.offsetZ * 6, yCoord + 1, zCoord - dir.offsetX * 6, rot.getOpposite());
data.setInteger("rpm", this.rpm);
data.setInteger("temp", this.temp);
data.setInteger("state", this.state);
data.setBoolean("automode", this.autoMode);
data.setInteger("throttle", this.throttle);
data.setInteger("slidpos", this.powerSliderPos);
if(state != 1) {
data.setInteger("counter", this.counter); //sent during startup and shutdown
} else {
data.setInteger("instantPow", this.instantPowerOutput); //sent while running
}
tanks[0].writeToNBT(data, "fuel");
tanks[1].writeToNBT(data, "lube");
tanks[2].writeToNBT(data, "water");
tanks[3].writeToNBT(data, "steam");
this.networkPack(data, 150);
} else { //client side, for sounds n shit
if(rpm >= 10 && state != -1) { //if conditions are right, play the sound
if(audio == null) { //if there is no sound playing, start it
audio = MainRegistry.proxy.getLoopedSound("hbm:block.turbinegasRunning", xCoord, yCoord, zCoord, 1.0F, 20F, 1.0F);
audio.startSound();
} else if(!audio.isPlaying()) {
audio.stopSound();
audio = MainRegistry.proxy.getLoopedSound("hbm:block.turbinegasRunning", xCoord, yCoord, zCoord, 1.0F, 20F, 1.0F);
audio.startSound();
}
audio.updatePitch((float) (0.55 + 0.1 * rpm / 10)); //dynamic pitch update based on rpm
audio.updateVolume(100F); //yeah i need this
} else {
if(audio != null) {
audio.stopSound();
audio = null;
}
}
}
}
private void stopIfNotReady() {
if(tanks[0].getFill() == 0 || tanks[1].getFill() == 0) {
state = 0;
}
if(!hasAcceptableFuel()) {
state = 0;
}
}
public boolean hasAcceptableFuel() {
if(tanks[0].getTankType().hasTrait(FT_Combustible.class)) {
return tanks[0].getTankType().getTrait(FT_Combustible.class).getGrade() == FuelGrade.GAS;
}
return false;
}
private void startup() {
counter++;
if(counter <= 20) //rpm gauge 0-100-0
rpm = 5 * counter;
else if (counter > 20 && counter <= 40)
rpm = 100 - 5 * (counter - 20);
else if (counter > 50) {
rpm = (int) (rpmIdle * (counter - 50) / 530); //slowly ramps up temp and RPM
temp = (int) (tempIdle * (counter - 50) / 530);
}
if(counter == 50) {
worldObj.playSoundEffect(xCoord, yCoord + 2, zCoord, "hbm:block.turbinegasStartup", 1F, 1.0F);
}
if(counter == 580) {
state = 1;
}
}
int rpmLast; //used to progressively slow down and cool the turbine without immediatly setting rpm and temp to 0
int tempLast;
private void shutdown() {
autoMode = false;
instantPowerOutput = 0;
if(powerSliderPos > 0)
powerSliderPos--;
if(rpm <= 10 && counter > 0) {
if(counter == 225) {
worldObj.playSoundEffect(xCoord, yCoord + 2, zCoord, "hbm:block.turbinegasShutdown", 1F, 1.0F);
rpmLast = rpm;
tempLast = temp;
}
counter--;
rpm = (int) (rpmLast * (counter) / 225);
temp = (int) (tempLast * (counter) / 225);
} else if(rpm > 11) { //quickly slows down the turbine to idle before shutdown
counter = 42069; //absolutely necessary to avoid fuckeries on shutdown
rpm--;
} else if(rpm == 11) {
counter = 225;
rpm--;
}
}
/** Dynamically calculates a (hopefully) sensible burn heat from the combustion energy, scales from 300°C - 800°C */
protected int getFluidBurnTemp(FluidType type) {
double dFuel = type.hasTrait(FT_Combustible.class) ? type.getTrait(FT_Combustible.class).getCombustionEnergy() : 0;
return (int) Math.floor(800D - (Math.pow(Math.E, -dFuel / 100_000D)) * 300D);
}
private void run() {
if((int) (throttle * 0.9) > rpm - rpmIdle) { //simulates the rotor's moment of inertia
if(worldObj.getTotalWorldTime() % 5 == 0) {
rpm++;
}
} else if((int) (throttle * 0.9) < rpm - rpmIdle) {
if(worldObj.getTotalWorldTime() % 2 == 0) {
rpm--;
}
}
int maxTemp = getFluidBurnTemp(tanks[0].getTankType()); // fuelMaxTemp.get(tanks[0].getTankType())
if(throttle * 5 * (maxTemp - tempIdle) / 500 > temp - tempIdle) { //simulates the heat exchanger's resistance to temperature variation
if(worldObj.getTotalWorldTime() % 2 == 0) {
temp++;
}
} else if(throttle * 5 * (maxTemp - tempIdle) / 500 < temp - tempIdle) {
if(worldObj.getTotalWorldTime() % 2 == 0) {
temp--;
}
}
double consumption = fuelMaxCons.containsKey(tanks[0].getTankType()) ? fuelMaxCons.get(tanks[0].getTankType()) : 5D;
if(worldObj.getTotalWorldTime() % 20 == 0 && tanks[0].getTankType() != Fluids.OXYHYDROGEN) this.pollute(PollutionType.SOOT, PollutionHandler.SOOT_PER_SECOND * (float) consumption * 0.25F);
makePower(consumption, throttle);
}
double fuelToConsume; //used to consume 1 mb of fuel at a time when consumption is <1 mb/tick
double waterToBoil;
double waterPerTick = 0;
private void makePower(double consMax, int throttle) {
double idleConsumption = consMax * 0.05D;
double consumption = idleConsumption + consMax * throttle / 100;
fuelToConsume += consumption;
tanks[0].setFill(tanks[0].getFill() - (int) Math.floor(fuelToConsume));
fuelToConsume -= (int) Math.floor(fuelToConsume);
if(worldObj.getTotalWorldTime() % 10 == 0) //lube consumption
tanks[1].setFill(tanks[1].getFill() - 1);
if(tanks[0].getFill() < 0) { //avoids negative amounts of fluid
tanks[0].setFill(0);
state = 0;
}
if(tanks[1].getFill() < 0) {
tanks[1].setFill(0);
state = 0;
}
long energy = 0; //energy per mb of fuel
if(tanks[0].getTankType().hasTrait(FT_Combustible.class)) {
energy = tanks[0].getTankType().getTrait(FT_Combustible.class).getCombustionEnergy() / 1000L;
}
int rpmEff = rpm - rpmIdle; // RPM above idle level, 0-90
//consMax*energy is equivalent to power production at 100%
if(instantPowerOutput < (consMax * energy * rpmEff / 90)) { //this shit avoids power rising in steps of 2000 or so HE at a time, instead it does it smoothly
instantPowerOutput += Math.random() * 0.005 * consMax * energy;
if(instantPowerOutput > (consMax * energy * rpmEff / 90))
instantPowerOutput = (int) (consMax * energy * rpmEff / 90);
}
else if(instantPowerOutput > (consMax * energy * rpmEff / 90)) {
instantPowerOutput -= Math.random() * 0.011 * consMax * energy;
if(instantPowerOutput < (consMax * energy * rpmEff / 90))
instantPowerOutput = (int) (consMax * energy * rpmEff / 90);
}
this.power += instantPowerOutput;
waterPerTick = (consMax * energy * (temp - tempIdle) / 220000); //it just works fuck you
if(tanks[2].getFill() >= Math.ceil(waterPerTick)) { //checks if there's enough water to boil
waterToBoil += waterPerTick;
if(tanks[3].getFill() <= 160000 - waterToBoil * 10) { //checks if there's room for steam in the tank
tanks[2].setFill(tanks[2].getFill() - (int) Math.floor(waterToBoil));
tanks[3].setFill(tanks[3].getFill() + 10 * (int) Math.floor(waterToBoil));
waterToBoil -= (int) Math.floor(waterToBoil);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public void networkUnpack(NBTTagCompound nbt) {
this.power = nbt.getLong("power");
this.rpm = nbt.getInteger("rpm");
this.temp = nbt.getInteger("temp");
this.state = nbt.getInteger("state");
this.autoMode = nbt.getBoolean("automode");
this.powerSliderPos = nbt.getInteger("slidpos");
this.throttle = nbt.getInteger("throttle");
if(nbt.hasKey("counter"))
this.counter = nbt.getInteger("counter"); //state 0 and -1
else
this.instantPowerOutput = nbt.getInteger("instantPow"); //state 1
this.tanks[0].readFromNBT(nbt, "fuel");
this.tanks[1].readFromNBT(nbt, "lube");
this.tanks[2].readFromNBT(nbt, "water");
this.tanks[3].readFromNBT(nbt, "steam");
}
@Override
public void readFromNBT(NBTTagCompound nbt) {
super.readFromNBT(nbt);
this.tanks[0].readFromNBT(nbt, "gas");
this.tanks[1].readFromNBT(nbt, "lube");
this.tanks[2].readFromNBT(nbt, "water");
this.tanks[3].readFromNBT(nbt, "densesteam");
this.autoMode = nbt.getBoolean("automode");
this.power = nbt.getLong("power");
this.state = nbt.getInteger("state");
this.rpm = nbt.getInteger("rpm");
this.temp = nbt.getInteger("temperature");
this.powerSliderPos = nbt.getInteger("slidPos");
this.instantPowerOutput = nbt.getInteger("instPwr");
this.counter = nbt.getInteger("counter");
}
@Override
public void writeToNBT(NBTTagCompound nbt) {
super.writeToNBT(nbt);
tanks[0].writeToNBT(nbt, "gas");
tanks[1].writeToNBT(nbt, "lube");
tanks[2].writeToNBT(nbt, "water");
tanks[3].writeToNBT(nbt, "densesteam");
nbt.setBoolean("automode", autoMode);
nbt.setLong("power", power);
if(state == 1) {
nbt.setInteger("state", this.state);
nbt.setInteger("rpm", this.rpm);
nbt.setInteger("temperature", this.temp);
nbt.setInteger("slidPos", this.powerSliderPos);
nbt.setInteger("instPwr", instantPowerOutput);
nbt.setInteger("counter", 225);
} else {
nbt.setInteger("state", 0);
nbt.setInteger("rpm", 0);
nbt.setInteger("temperature", 20);
nbt.setInteger("slidPos", 0);
nbt.setInteger("instpwr", 0);
nbt.setInteger("counter", 0);
}
}
@Override
public void receiveControl(NBTTagCompound data) {
if(data.hasKey("slidPos"))
powerSliderPos = data.getInteger("slidPos");
if(data.hasKey("autoMode"))
autoMode = data.getBoolean("autoMode");
if(data.hasKey("state"))
state = data.getInteger("state");
this.markDirty();
}
@Override
public boolean hasPermission(EntityPlayer player) {
return Vec3.createVectorHelper(xCoord - player.posX, yCoord - player.posY, zCoord - player.posZ).lengthVector() < 25;
}
@Override
public void onChunkUnload() {
if(audio != null) {
audio.stopSound();
audio = null;
}
}
@Override
public void invalidate() {
super.invalidate();
if(audio != null) {
audio.stopSound();
audio = null;
}
}
@Override
public void setPower(long power) {
this.power = power;
}
@Override
public long getPower() {
return this.power;
}
@Override
public long getMaxPower() {
return this.maxPower;
}
AxisAlignedBB bb = null;
@Override
public AxisAlignedBB getRenderBoundingBox() {
if(bb == null) {
bb = AxisAlignedBB.getBoundingBox(
xCoord - 5,
yCoord,
zCoord - 5,
xCoord + 6,
yCoord + 3,
zCoord + 6
);
}
return bb;
}
@Override
@SideOnly(Side.CLIENT)
public double getMaxRenderDistanceSquared() {
return 65536.0D;
}
@Override
public String getName() {
return "container.turbinegas";
}
@Override
public FluidTank[] getAllTanks() {
return tanks;
}
@Override
public FluidTank[] getReceivingTanks() {
return new FluidTank[] { tanks[0], tanks[1], tanks[2] };
}
@Override
public FluidTank[] getSendingTanks() {
return new FluidTank[] { tanks[3], smoke, smoke_leaded, smoke_poison };
}
@Override
public boolean canConnect(ForgeDirection dir) {
return dir != ForgeDirection.DOWN;
}
@Override
public boolean canConnect(FluidType type, ForgeDirection dir) {
return dir != ForgeDirection.DOWN;
}
@Override
public Container provideContainer(int ID, EntityPlayer player, World world, int x, int y, int z) {
return new ContainerMachineTurbineGas(player.inventory, this);
}
@Override
@SideOnly(Side.CLIENT)
public GuiScreen provideGUI(int ID, EntityPlayer player, World world, int x, int y, int z) {
return new GUIMachineTurbineGas(player.inventory, this);
}
}