2025-02-16 23:16:26 +01:00

506 lines
14 KiB
Java

package com.hbm.tileentity.machine.rbmk;
import com.hbm.blocks.ModBlocks;
import com.hbm.blocks.machine.rbmk.RBMKBase;
import com.hbm.blocks.machine.rbmk.RBMKRod;
import com.hbm.entity.projectile.EntityRBMKDebris.DebrisType;
import com.hbm.handler.CompatHandler;
import com.hbm.handler.neutron.NeutronNodeWorld;
import com.hbm.handler.neutron.RBMKNeutronHandler;
import com.hbm.handler.radiation.ChunkRadiationManager;
import com.hbm.handler.neutron.RBMKNeutronHandler.RBMKNeutronNode;
import com.hbm.handler.neutron.NeutronStream;
import com.hbm.inventory.container.ContainerRBMKRod;
import com.hbm.inventory.gui.GUIRBMKRod;
import com.hbm.items.ModItems;
import com.hbm.items.machine.ItemRBMKRod;
import com.hbm.tileentity.machine.rbmk.TileEntityRBMKConsole.ColumnType;
import com.hbm.util.CompatEnergyControl;
import com.hbm.util.ParticleUtil;
import api.hbm.tile.IInfoProviderEC;
import com.hbm.util.fauxpointtwelve.BlockPos;
import cpw.mods.fml.common.Optional;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import li.cil.oc.api.machine.Arguments;
import li.cil.oc.api.machine.Callback;
import li.cil.oc.api.machine.Context;
import li.cil.oc.api.network.SimpleComponent;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.MathHelper;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import java.util.ArrayList;
import java.util.List;
@Optional.InterfaceList({@Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers")})
public class TileEntityRBMKRod extends TileEntityRBMKSlottedBase implements IRBMKFluxReceiver, IRBMKLoadable, SimpleComponent, IInfoProviderEC, CompatHandler.OCComponent {
// New system!!
// Used for receiving flux (calculating outbound flux/burning rods)
public double fluxFastRatio;
public double fluxQuantity;
public double lastFluxQuantity;
public double lastFluxRatio;
public boolean hasRod;
public TileEntityRBMKRod() {
super(1);
}
@Override
public String getName() {
return "container.rbmkRod";
}
@Override
public boolean isModerated() {
return ((RBMKRod)this.getBlockType()).moderated;
}
@Override
public int trackingRange() {
return 25;
}
@Override
public void receiveFlux(NeutronStream stream) {
double fastFlux = this.fluxQuantity * this.fluxFastRatio;
double fastFluxIn = stream.fluxQuantity * stream.fluxRatio;
this.fluxQuantity += stream.fluxQuantity;
fluxFastRatio = (fastFlux + fastFluxIn) / fluxQuantity;
}
@Override
public void updateEntity() {
if(!worldObj.isRemote) {
if(slots[0] != null && slots[0].getItem() instanceof ItemRBMKRod) {
ItemRBMKRod rod = ((ItemRBMKRod)slots[0].getItem());
double fluxRatioOut;
double fluxQuantityOut;
// Experimental flux ratio curve rods!
// Again, nothing really uses this so its just idle code at the moment.
if (rod.specialFluxCurve) {
fluxRatioOut = rod.fluxRatioOut(this.fluxFastRatio, ItemRBMKRod.getEnrichment(slots[0]));
double fluxIn;
fluxIn = rod.fluxFromRatio(this.fluxQuantity, this.fluxFastRatio);
fluxQuantityOut = rod.burn(worldObj, slots[0], fluxIn);
} else {
NType rType = rod.rType;
if (rType == NType.SLOW)
fluxRatioOut = 0;
else
fluxRatioOut = 1;
double fluxIn = fluxFromType(rod.nType);
fluxQuantityOut = rod.burn(worldObj, slots[0], fluxIn);
}
rod.updateHeat(worldObj, slots[0], 1.0D);
this.heat += rod.provideHeat(worldObj, slots[0], heat, 1.0D);
if(!this.hasLid()) {
ChunkRadiationManager.proxy.incrementRad(worldObj, xCoord, yCoord, zCoord, (float) (this.fluxQuantity * 0.05F));
}
super.updateEntity();
if(this.heat > this.maxHeat()) {
if(RBMKDials.getMeltdownsDisabled(worldObj)) {
ParticleUtil.spawnGasFlame(worldObj, xCoord + 0.5, yCoord + RBMKDials.getColumnHeight(worldObj) + 0.5, zCoord + 0.5, 0, 0.2, 0);
} else {
this.meltdown();
}
this.lastFluxRatio = 0;
this.lastFluxQuantity = 0;
this.fluxQuantity = 0;
return;
}
if(this.heat > 10_000) this.heat = 10_000;
//for spreading, we want the buffered flux to be 0 because we want to know exactly how much gets reflected back
this.lastFluxQuantity = this.fluxQuantity;
this.lastFluxRatio = this.fluxFastRatio;
this.fluxQuantity = 0;
this.fluxFastRatio = 0;
spreadFlux(fluxQuantityOut, fluxRatioOut);
hasRod = true;
} else {
this.lastFluxRatio = 0;
this.lastFluxQuantity = 0;
this.fluxQuantity = 0;
this.fluxFastRatio = 0;
hasRod = false;
super.updateEntity();
}
}
}
private double fluxFromType(NType type) {
double fastFlux = this.fluxQuantity * this.fluxFastRatio;
double slowFlux = this.fluxQuantity * (1 - this.fluxFastRatio);
switch(type) {
case SLOW: return slowFlux + fastFlux * 0.5;
case FAST: return fastFlux + slowFlux * 0.3;
case ANY: return this.fluxQuantity;
}
return 0.0D;
}
public static final ForgeDirection[] fluxDirs = new ForgeDirection[] {
ForgeDirection.NORTH,
ForgeDirection.EAST,
ForgeDirection.SOUTH,
ForgeDirection.WEST
};
private BlockPos pos;
public void spreadFlux(double flux, double ratio) {
if(pos == null)
pos = new BlockPos(this);
if (flux == 0) {
// simple way to remove the node from the cache when no flux is going into it!
NeutronNodeWorld.removeNode(pos);
return;
}
RBMKNeutronNode node = (RBMKNeutronNode) NeutronNodeWorld.getNode(pos);
if(node == null) {
node = RBMKNeutronHandler.makeNode(this);
NeutronNodeWorld.addNode(node);
}
for(ForgeDirection dir : fluxDirs) {
Vec3 neutronVector = Vec3.createVectorHelper(dir.offsetX, dir.offsetY, dir.offsetZ);
// Create new neutron streams
new RBMKNeutronHandler.RBMKNeutronStream(node, neutronVector, flux, ratio);
}
}
@Override
public void readFromNBT(NBTTagCompound nbt) {
super.readFromNBT(nbt);
if (nbt.hasKey("fluxFast") || nbt.hasKey("fluxSlow")) {
// recalculate new values to keep stable operations
this.fluxQuantity = nbt.getDouble("fluxFast") + nbt.getDouble("fluxSlow");
if (this.fluxQuantity > 0)
this.fluxFastRatio = nbt.getDouble("fluxFast") / fluxQuantity;
else
this.fluxFastRatio = 0;
} else {
this.fluxQuantity = nbt.getDouble("fluxQuantity");
this.fluxFastRatio = nbt.getDouble("fluxMod");
}
this.hasRod = nbt.getBoolean("hasRod");
}
@Override
public void writeToNBT(NBTTagCompound nbt) {
super.writeToNBT(nbt);
if (!diag) {
nbt.setDouble("fluxQuantity", this.lastFluxQuantity);
nbt.setDouble("fluxMod", this.lastFluxRatio);
} else {
nbt.setDouble("fluxSlow", this.fluxQuantity * (1 - fluxFastRatio));
nbt.setDouble("fluxFast", this.fluxQuantity * fluxFastRatio);
}
nbt.setBoolean("hasRod", this.hasRod);
}
@Override
public void serialize(ByteBuf buf) {
super.serialize(buf);
buf.writeDouble(this.lastFluxQuantity);
buf.writeDouble(this.lastFluxRatio);
buf.writeBoolean(this.hasRod);
}
@Override
public void deserialize(ByteBuf buf) {
super.deserialize(buf);
this.fluxQuantity = buf.readDouble();
this.fluxFastRatio = buf.readDouble();
this.hasRod = buf.readBoolean();
}
public void getDiagData(NBTTagCompound nbt) {
diag = true;
this.writeToNBT(nbt);
diag = false;
if(slots[0] != null && slots[0].getItem() instanceof ItemRBMKRod) {
ItemRBMKRod rod = ((ItemRBMKRod)slots[0].getItem());
nbt.setString("f_yield", rod.getYield(slots[0]) + " / " + rod.yield + " (" + (rod.getEnrichment(slots[0]) * 100) + "%)");
nbt.setString("f_xenon", rod.getPoison(slots[0]) + "%");
nbt.setString("f_heat", rod.getCoreHeat(slots[0]) + " / " + rod.getHullHeat(slots[0]) + " / " + rod.meltingPoint);
}
}
@Override
public void onMelt(int reduce) {
boolean moderated = this.isModerated();
int h = RBMKDials.getColumnHeight(worldObj);
reduce = MathHelper.clamp_int(reduce, 1, h);
if(worldObj.rand.nextInt(3) == 0)
reduce++;
boolean corium = slots[0] != null && slots[0].getItem() instanceof ItemRBMKRod;
if(corium && slots[0].getItem() == ModItems.rbmk_fuel_drx)
RBMKBase.digamma = true;
slots[0] = null;
if(corium) {
for(int i = h; i >= 0; i--) {
worldObj.setBlock(xCoord, yCoord + i, zCoord, ModBlocks.corium_block, 5, 3);
worldObj.markBlockForUpdate(xCoord, yCoord + i, zCoord);
}
int count = 1 + worldObj.rand.nextInt(RBMKDials.getColumnHeight(worldObj));
for(int i = 0; i < count; i++) {
spawnDebris(DebrisType.FUEL);
}
} else {
this.standardMelt(reduce);
}
if(moderated) {
int count = 2 + worldObj.rand.nextInt(2);
for(int i = 0; i < count; i++) {
spawnDebris(DebrisType.GRAPHITE);
}
}
spawnDebris(DebrisType.ELEMENT);
if(this.getBlockMetadata() == RBMKBase.DIR_NORMAL_LID.ordinal() + RBMKBase.offset)
spawnDebris(DebrisType.LID);
}
@Override
public RBMKNeutronHandler.RBMKType getRBMKType() {
return RBMKNeutronHandler.RBMKType.ROD;
}
@Override
public ColumnType getConsoleType() {
return ColumnType.FUEL;
}
@Override
public NBTTagCompound getNBTForConsole() {
NBTTagCompound data = new NBTTagCompound();
if(slots[0] != null && slots[0].getItem() instanceof ItemRBMKRod) {
ItemRBMKRod rod = ((ItemRBMKRod)slots[0].getItem());
data.setDouble("enrichment", rod.getEnrichment(slots[0]));
data.setDouble("xenon", rod.getPoison(slots[0]));
data.setDouble("c_heat", rod.getHullHeat(slots[0]));
data.setDouble("c_coreHeat", rod.getCoreHeat(slots[0]));
data.setDouble("c_maxHeat", rod.meltingPoint);
}
return data;
}
@Override
public boolean canLoad(ItemStack toLoad) {
return toLoad != null && slots[0] == null;
}
@Override
public void load(ItemStack toLoad) {
slots[0] = toLoad.copy();
this.markDirty();
}
@Override
public boolean canUnload() {
return slots[0] != null;
}
@Override
public ItemStack provideNext() {
return slots[0];
}
@Override
public void unload() {
slots[0] = null;
this.markDirty();
}
// do some opencomputer stuff
@Override
@Optional.Method(modid = "OpenComputers")
public String getComponentName() {
return "rbmk_fuel_rod";
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getHeat(Context context, Arguments args) {
return new Object[] {heat};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getFluxQuantity(Context context, Arguments args) {
return new Object[] {fluxQuantity};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getFluxRatio(Context context, Arguments args) {
return new Object[] {fluxFastRatio};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getDepletion(Context context, Arguments args) {
if(slots[0] != null && slots[0].getItem() instanceof ItemRBMKRod) {
return new Object[] {ItemRBMKRod.getEnrichment(slots[0])};
}
return new Object[] {"N/A"};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getXenonPoison(Context context, Arguments args) {
if(slots[0] != null && slots[0].getItem() instanceof ItemRBMKRod) {
return new Object[] {ItemRBMKRod.getPoison(slots[0])};
}
return new Object[] {"N/A"};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getCoreHeat(Context context, Arguments args) {
if(slots[0] != null && slots[0].getItem() instanceof ItemRBMKRod) {
return new Object[] {ItemRBMKRod.getCoreHeat(slots[0])};
}
return new Object[] {"N/A"};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getSkinHeat(Context context, Arguments args) {
if(slots[0] != null && slots[0].getItem() instanceof ItemRBMKRod) {
return new Object[] {ItemRBMKRod.getHullHeat(slots[0])};
}
return new Object[] {"N/A"};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getType(Context context, Arguments args) {
if(slots[0] != null && slots[0].getItem() instanceof ItemRBMKRod) {
return new Object[] {slots[0].getItem().getUnlocalizedName()};
}
return new Object[] {"N/A"};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getInfo(Context context, Arguments args) {
List<Object> returnValues = new ArrayList<>();
if(slots[0] != null && slots[0].getItem() instanceof ItemRBMKRod) {
returnValues.add(ItemRBMKRod.getHullHeat(slots[0]));
returnValues.add(ItemRBMKRod.getCoreHeat(slots[0]));
returnValues.add(ItemRBMKRod.getEnrichment(slots[0]));
returnValues.add(ItemRBMKRod.getPoison(slots[0]));
returnValues.add(slots[0].getItem().getUnlocalizedName());
} else
for (int i = 0; i < 5; i++)
returnValues.add("N/A");
return new Object[] {
heat, returnValues.get(0), returnValues.get(1),
fluxQuantity, fluxFastRatio, returnValues.get(2), returnValues.get(3), returnValues.get(4),
((RBMKRod)this.getBlockType()).moderated, xCoord, yCoord, zCoord};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getModerated(Context context, Arguments args) {
return new Object[] {((RBMKRod)this.getBlockType()).moderated};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getCoordinates(Context context, Arguments args) {
return new Object[] {xCoord, yCoord, zCoord};
}
@Override
public Container provideContainer(int ID, EntityPlayer player, World world, int x, int y, int z) {
return new ContainerRBMKRod(player.inventory, this);
}
@Override
@SideOnly(Side.CLIENT)
public Object provideGUI(int ID, EntityPlayer player, World world, int x, int y, int z) {
return new GUIRBMKRod(player.inventory, this);
}
@Override
public void provideExtraInfo(NBTTagCompound data) {
if(slots[0] != null && slots[0].getItem() instanceof ItemRBMKRod) {
data.setDouble(CompatEnergyControl.D_DEPLETION_PERCENT, ((1.0D - ItemRBMKRod.getEnrichment(slots[0])) * 100_000.0D) / 1_000.0D);
data.setDouble(CompatEnergyControl.D_XENON_PERCENT, ItemRBMKRod.getPoison(slots[0]));
data.setDouble(CompatEnergyControl.D_SKIN_C, ItemRBMKRod.getHullHeat(slots[0]));
data.setDouble(CompatEnergyControl.D_CORE_C, ItemRBMKRod.getCoreHeat(slots[0]));
data.setDouble(CompatEnergyControl.D_MELT_C, ((ItemRBMKRod) slots[0].getItem()).meltingPoint);
}
}
}