From d6cdc69c899b873bd252329eafd581e32b9dae26 Mon Sep 17 00:00:00 2001 From: Boblet Date: Thu, 22 Jun 2023 14:59:54 +0200 Subject: [PATCH] pressure --- changelog | 44 +++ .../hbm/fluid/IFluidStandardTransceiver.java | 8 +- .../hbm/blocks/machine/MachineCompressor.java | 19 +- .../hbm/inventory/fluid/tank/FluidTank.java | 3 + .../com/hbm/inventory/gui/GUICompressor.java | 43 ++- .../inventory/recipes/CompressorRecipes.java | 17 +- .../inventory/recipes/OutgasserRecipes.java | 2 + .../recipes/loader/JSONLoaderBase.java | 177 ------------ .../recipes/loader/SerializableRecipe.java | 5 +- .../com/hbm/items/tool/ItemBlowtorch.java | 2 +- .../render/tileentity/RenderCompressor.java | 11 +- .../machine/TileEntityMachineCompressor.java | 251 +++++++++++++++++- .../textures/models/machines/compressor.png | Bin 3463 -> 5337 bytes 13 files changed, 386 insertions(+), 196 deletions(-) delete mode 100644 src/main/java/com/hbm/inventory/recipes/loader/JSONLoaderBase.java diff --git a/changelog b/changelog index e69de29bb..7e7de1c66 100644 --- a/changelog +++ b/changelog @@ -0,0 +1,44 @@ +## Added +* Glpyhids + * Hives will spawn randomly in the world + * Hives will constantly spawn new glyphids + * If explosed to soot, hives will create glyphid scouts, which when far enough from another hive will explode and generate a new hive + * Higher soot levels create stronger glyphids + * Glyphids possess armor which has a chance of breaking off and fully abrosrbing damage + * Each glyphid has five armor plates + * Glyphid types include multiple tiers of melee glyphids as well as a few ranged ones, the scout, and a nuclear variant +* Compressor + * Can compress fluids, turning them into higher pressure variants + * Can also turn steam into higher pressure types +* A new rocket artillery ammo type that creates volcanic lava on impact +* BDCL + * A type of lubricant that is easy to make and can be used in hydraulic piston and electric press recipes instead of regular lubricant +* FBI drones + * A configurable amount of drones can now spawn during FBI raids + * They will hover over players, dropping bombs + +## Changed +* Updated russian localization +* Fluid traits can now be configured, any fluid can now have any fluid with variable stats assigned to them +* Large explosions now load the central chunk they are in, this can be disabled in the config +* Burning leaded fuels now releases poisonous heavy metals into the atmosphere +* The pollution detector now displays rounded values +* More machines and especially destroyed ones now release soot +* The iGen has been rebalanced again, delete your machine config file for the changes to take effect + * The lubrican power multiplier has been increased from 1.1 to 1.5 + * The fluid divisor has been lowered from 5,000 to 1,000, meaning the iGen now burns flammable liquids at full efficiency +* Removed the config for having an additional keybind for dashing, the keybind is now always active since it no longer conflicts with crouching +* Crucible recipes no longer use foundry scraps to visualize the recipes, instead they use a lava-like texture +* Fusion reactors are now made from welded magnets which are created by weling a cast steel plate onto a magnet + * Due to the cost of the cast plates, fusion reactor magnets are now cheaper to compensate + * Consequently, particle accelerators are now also cheaper due to being made from mostly fusion reactor magnets +* The blowtorch now consumes only 250mB per operation, allowing for up to 16 things to be welded with a single fill +* The page and notebook items have been replaced with more dynamic book items that get their data from NBT +* C4 can now be made by irradiating PVC + * Play stupid games, win stupid prizes + +## Fixed +* Fixed potential crash or logspam regarding the pollution handler +* Fixed missiles leaving behind a 3x3 grid of loaded chunks after being destroyed +* Fixed coal ore yielding coal in the crucible instead of making carbon +* Fixed a potential issue where BuildCraft generators can't supply the RF to HE converter \ No newline at end of file diff --git a/src/main/java/api/hbm/fluid/IFluidStandardTransceiver.java b/src/main/java/api/hbm/fluid/IFluidStandardTransceiver.java index eb7092ad8..4012ab63f 100644 --- a/src/main/java/api/hbm/fluid/IFluidStandardTransceiver.java +++ b/src/main/java/api/hbm/fluid/IFluidStandardTransceiver.java @@ -26,7 +26,7 @@ public interface IFluidStandardTransceiver extends IFluidUser { public default long getTotalFluidForSend(FluidType type, int pressure) { for(FluidTank tank : getSendingTanks()) { - if(tank.getTankType() == type) { + if(tank.getTankType() == type && tank.getPressure() == pressure) { return tank.getFill(); } } @@ -38,7 +38,7 @@ public interface IFluidStandardTransceiver extends IFluidUser { public default void removeFluidForTransfer(FluidType type, int pressure, long amount) { for(FluidTank tank : getSendingTanks()) { - if(tank.getTankType() == type) { + if(tank.getTankType() == type && tank.getPressure() == pressure) { tank.setFill(tank.getFill() - (int) amount); return; } @@ -49,7 +49,7 @@ public interface IFluidStandardTransceiver extends IFluidUser { public default long getDemand(FluidType type, int pressure) { for(FluidTank tank : getReceivingTanks()) { - if(tank.getTankType() == type) { + if(tank.getTankType() == type && tank.getPressure() == pressure) { return tank.getMaxFill() - tank.getFill(); } } @@ -61,7 +61,7 @@ public interface IFluidStandardTransceiver extends IFluidUser { public default long transferFluid(FluidType type, int pressure, long amount) { for(FluidTank tank : getReceivingTanks()) { - if(tank.getTankType() == type) { + if(tank.getTankType() == type && tank.getPressure() == pressure) { tank.setFill(tank.getFill() + (int) amount); if(tank.getFill() > tank.getMaxFill()) { diff --git a/src/main/java/com/hbm/blocks/machine/MachineCompressor.java b/src/main/java/com/hbm/blocks/machine/MachineCompressor.java index 791ad2f77..f22bc3fc1 100644 --- a/src/main/java/com/hbm/blocks/machine/MachineCompressor.java +++ b/src/main/java/com/hbm/blocks/machine/MachineCompressor.java @@ -1,6 +1,8 @@ package com.hbm.blocks.machine; import com.hbm.blocks.BlockDummyable; +import com.hbm.handler.MultiblockHandlerXR; +import com.hbm.tileentity.TileEntityProxyCombo; import com.hbm.tileentity.machine.TileEntityMachineCompressor; import net.minecraft.block.material.Material; @@ -18,6 +20,7 @@ public class MachineCompressor extends BlockDummyable { @Override public TileEntity createNewTileEntity(World world, int meta) { if(meta >= 12) return new TileEntityMachineCompressor(); + if(meta >= extra) return new TileEntityProxyCombo().fluid().power(); return null; } @@ -39,11 +42,25 @@ public class MachineCompressor extends BlockDummyable { @Override protected boolean checkRequirement(World world, int x, int y, int z, ForgeDirection dir, int o) { - return super.checkRequirement(world, x, y, z, dir, o); + return super.checkRequirement(world, x, y, z, dir, o) && + MultiblockHandlerXR.checkSpace(world, x + dir.offsetX * o, y + dir.offsetY * o, z + dir.offsetZ * o, new int[] {3, -3, 1, 1, 1, 1}, x, y, z, dir) && + MultiblockHandlerXR.checkSpace(world, x + dir.offsetX * o, y + dir.offsetY * o, z + dir.offsetZ * o, new int[] {8, -4, 0, 0, 1, 1}, x, y, z, dir); } @Override public void fillSpace(World world, int x, int y, int z, ForgeDirection dir, int o) { super.fillSpace(world, x, y, z, dir, o); + + MultiblockHandlerXR.fillSpace(world, x + dir.offsetX * o, y + dir.offsetY * o, z + dir.offsetZ * o, new int[] {3, -3, 1, 1, 1, 1}, this, dir); + MultiblockHandlerXR.fillSpace(world, x + dir.offsetX * o, y + dir.offsetY * o, z + dir.offsetZ * o, new int[] {8, -4, 0, 0, 1, 1}, this, dir); + + x += dir.offsetX * o; + z += dir.offsetZ * o; + + ForgeDirection rot = dir.getRotation(ForgeDirection.UP); + + this.makeExtra(world, x - dir.offsetX, y, z - dir.offsetZ); + this.makeExtra(world, x + rot.offsetX, y, z + rot.offsetZ); + this.makeExtra(world, x - rot.offsetX, y, z - rot.offsetZ); } } diff --git a/src/main/java/com/hbm/inventory/fluid/tank/FluidTank.java b/src/main/java/com/hbm/inventory/fluid/tank/FluidTank.java index 90e8b3bbf..c9e94b9ee 100644 --- a/src/main/java/com/hbm/inventory/fluid/tank/FluidTank.java +++ b/src/main/java/com/hbm/inventory/fluid/tank/FluidTank.java @@ -44,6 +44,9 @@ public class FluidTank { } public FluidTank withPressure(int pressure) { + + if(this.pressure != pressure) this.setFill(0); + this.pressure = pressure; return this; } diff --git a/src/main/java/com/hbm/inventory/gui/GUICompressor.java b/src/main/java/com/hbm/inventory/gui/GUICompressor.java index c31ee0baf..9e2f758e8 100644 --- a/src/main/java/com/hbm/inventory/gui/GUICompressor.java +++ b/src/main/java/com/hbm/inventory/gui/GUICompressor.java @@ -4,21 +4,25 @@ import org.lwjgl.opengl.GL11; import com.hbm.inventory.container.ContainerCompressor; import com.hbm.lib.RefStrings; +import com.hbm.packet.NBTControlPacket; +import com.hbm.packet.PacketDispatcher; import com.hbm.tileentity.machine.TileEntityMachineCompressor; import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; public class GUICompressor extends GuiInfoContainer { private static ResourceLocation texture = new ResourceLocation(RefStrings.MODID + ":textures/gui/processing/gui_compressor.png"); - private TileEntityMachineCompressor solidifier; + private TileEntityMachineCompressor compressor; public GUICompressor(InventoryPlayer invPlayer, TileEntityMachineCompressor tedf) { super(new ContainerCompressor(invPlayer, tedf)); - solidifier = tedf; + compressor = tedf; this.xSize = 176; this.ySize = 204; @@ -28,14 +32,31 @@ public class GUICompressor extends GuiInfoContainer { public void drawScreen(int mouseX, int mouseY, float f) { super.drawScreen(mouseX, mouseY, f); - //solidifier.tank.renderTankInfo(this, mouseX, mouseY, guiLeft + 35, guiTop + 36, 16, 52); - //this.drawElectricityInfo(this, mouseX, mouseY, guiLeft + 134, guiTop + 18, 16, 52, solidifier.power, solidifier.maxPower); + compressor.tanks[0].renderTankInfo(this, mouseX, mouseY, guiLeft + 17, guiTop + 18, 16, 52); + compressor.tanks[1].renderTankInfo(this, mouseX, mouseY, guiLeft + 107, guiTop + 18, 16, 52); + this.drawElectricityInfo(this, mouseX, mouseY, guiLeft + 152, guiTop + 18, 16, 52, compressor.power, compressor.maxPower); + } + + @Override + protected void mouseClicked(int x, int y, int i) { + super.mouseClicked(x, y, i); + + for(int j = 0; j < 5; j++) { + + if(guiLeft + 43 + j * 11 <= x && guiLeft + 43 + 8 + j * 11 > x && guiTop + 46 < y && guiTop + 46 + 14 >= y) { + + mc.getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F)); + NBTTagCompound data = new NBTTagCompound(); + data.setInteger("compression", j); + PacketDispatcher.wrapper.sendToServer(new NBTControlPacket(data, compressor.xCoord, compressor.yCoord, compressor.zCoord)); + } + } } @Override protected void drawGuiContainerForegroundLayer(int i, int j) { - String name = this.solidifier.hasCustomInventoryName() ? this.solidifier.getInventoryName() : I18n.format(this.solidifier.getInventoryName()); + String name = this.compressor.hasCustomInventoryName() ? this.compressor.getInventoryName() : I18n.format(this.compressor.getInventoryName()); this.fontRendererObj.drawString(name, 70 - this.fontRendererObj.getStringWidth(name) / 2, 6, 0xC7C1A3); this.fontRendererObj.drawString(I18n.format("container.inventory"), 8, this.ySize - 96 + 2, 4210752); @@ -46,5 +67,17 @@ public class GUICompressor extends GuiInfoContainer { GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); Minecraft.getMinecraft().getTextureManager().bindTexture(texture); drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); + + if(compressor.power >= 1_000) { + drawTexturedModalRect(guiLeft + 156, guiTop + 4, 176, 52, 9, 12); + } + + drawTexturedModalRect(guiLeft + 43 + compressor.tanks[0].getPressure() * 11, guiTop + 46, 193, 18, 8, 124); + + int i = compressor.progress * 55 / compressor.processTime; + drawTexturedModalRect(guiLeft + 42, guiTop + 26, 192, 0, i, 17); + + compressor.tanks[0].renderTank(guiLeft + 17, guiTop + 70, this.zLevel, 16, 52); + compressor.tanks[1].renderTank(guiLeft + 107, guiTop + 70, this.zLevel, 16, 52); } } diff --git a/src/main/java/com/hbm/inventory/recipes/CompressorRecipes.java b/src/main/java/com/hbm/inventory/recipes/CompressorRecipes.java index 15f5b2baa..2e22d2e8b 100644 --- a/src/main/java/com/hbm/inventory/recipes/CompressorRecipes.java +++ b/src/main/java/com/hbm/inventory/recipes/CompressorRecipes.java @@ -2,11 +2,14 @@ package com.hbm.inventory.recipes; import java.io.IOException; import java.util.HashMap; +import java.util.Map.Entry; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.google.gson.stream.JsonWriter; import com.hbm.inventory.FluidStack; import com.hbm.inventory.fluid.FluidType; +import com.hbm.inventory.fluid.Fluids; import com.hbm.inventory.recipes.loader.SerializableRecipe; import com.hbm.util.Tuple.Pair; @@ -16,7 +19,9 @@ public class CompressorRecipes extends SerializableRecipe { @Override public void registerDefaults() { - + recipes.put(new Pair(Fluids.STEAM, 0), new CompressorRecipe(1_000, new FluidStack(Fluids.HOTSTEAM, 100))); + recipes.put(new Pair(Fluids.HOTSTEAM, 0), new CompressorRecipe(1_000, new FluidStack(Fluids.SUPERHOTSTEAM, 100))); + recipes.put(new Pair(Fluids.SUPERHOTSTEAM, 0), new CompressorRecipe(1_000, new FluidStack(Fluids.ULTRAHOTSTEAM, 100))); } public static class CompressorRecipe { @@ -47,11 +52,21 @@ public class CompressorRecipes extends SerializableRecipe { @Override public void readRecipe(JsonElement recipe) { + JsonObject obj = recipe.getAsJsonObject(); + + FluidStack input = this.readFluidStack(obj.get("input").getAsJsonArray()); + FluidStack output = this.readFluidStack(obj.get("output").getAsJsonArray()); + recipes.put(new Pair(input.type, input.pressure), new CompressorRecipe(input.fill, output)); } @Override public void writeRecipe(Object recipe, JsonWriter writer) throws IOException { + Entry, CompressorRecipe> entry = (Entry) recipe; + writer.name("input"); + this.writeFluidStack(new FluidStack(entry.getKey().getKey(), entry.getValue().inputAmount, entry.getKey().getValue()), writer); + writer.name("output"); + this.writeFluidStack(entry.getValue().output, writer); } } diff --git a/src/main/java/com/hbm/inventory/recipes/OutgasserRecipes.java b/src/main/java/com/hbm/inventory/recipes/OutgasserRecipes.java index 1f1c72505..491a8595f 100644 --- a/src/main/java/com/hbm/inventory/recipes/OutgasserRecipes.java +++ b/src/main/java/com/hbm/inventory/recipes/OutgasserRecipes.java @@ -56,6 +56,8 @@ public class OutgasserRecipes extends SerializableRecipe { recipes.put(new OreDictStack(COAL.gem()), new Pair(DictFrame.fromOne(ModItems.oil_tar, EnumTarType.COAL, 1), new FluidStack(Fluids.SYNGAS, 50))); recipes.put(new OreDictStack(COAL.dust()), new Pair(DictFrame.fromOne(ModItems.oil_tar, EnumTarType.COAL, 1), new FluidStack(Fluids.SYNGAS, 50))); recipes.put(new OreDictStack(COAL.block()), new Pair(DictFrame.fromOne(ModItems.oil_tar, EnumTarType.COAL, 9), new FluidStack(Fluids.SYNGAS, 500))); + + recipes.put(new OreDictStack(PVC.ingot()), new Pair(new ItemStack(ModItems.ingot_c4), new FluidStack(Fluids.COLLOID, 250))); recipes.put(new ComparableStack(DictFrame.fromOne(ModItems.oil_tar, EnumTarType.COAL)), new Pair(null, new FluidStack(Fluids.COALOIL, 100))); recipes.put(new ComparableStack(DictFrame.fromOne(ModItems.oil_tar, EnumTarType.WAX)), new Pair(null, new FluidStack(Fluids.RADIOSOLVENT, 100))); diff --git a/src/main/java/com/hbm/inventory/recipes/loader/JSONLoaderBase.java b/src/main/java/com/hbm/inventory/recipes/loader/JSONLoaderBase.java deleted file mode 100644 index a2e8bc316..000000000 --- a/src/main/java/com/hbm/inventory/recipes/loader/JSONLoaderBase.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.hbm.inventory.recipes.loader; - -import java.io.File; -import java.io.FileReader; -import java.io.IOException; - -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.stream.JsonWriter; -import com.hbm.inventory.RecipesCommon.AStack; -import com.hbm.inventory.RecipesCommon.ComparableStack; -import com.hbm.inventory.RecipesCommon.OreDictStack; -import com.hbm.main.MainRegistry; - -import net.minecraft.item.Item; -import net.minecraftforge.oredict.OreDictionary; - -@Deprecated -public abstract class JSONLoaderBase { - - public File config; - public File template; - private final Gson gson = new Gson(); - - public JSONLoaderBase() { - - } - - public void loadRecipes() { - registerDefaults(); - //saveTemplateJSON(template); - - if(config != null) { - loadJSONRecipes(); - } - } - - protected abstract void registerDefaults(); - - protected void loadJSONRecipes() { - - try { - JsonObject json = gson.fromJson(new FileReader(config), JsonObject.class); - JsonElement recipes = json.get("recipes"); - - if(recipes instanceof JsonArray) { - - JsonArray recArray = recipes.getAsJsonArray(); - for(JsonElement recipe : recArray) { - - if(recipe.isJsonObject()) { - - } - } - } - } catch (Exception e) { } - } - - protected static AStack aStackFromArray(JsonArray array) { - - boolean dict = false; - String item = ""; - int stacksize = 1; - int meta = 0; - - if(array.size() < 2) - return null; - - /* - * EVAL "dict" OR "item" - */ - if(array.get(0).isJsonPrimitive()) { - - if(array.get(0).getAsString().equals("item")) { - dict = false; - } else if(array.get(0).getAsString().equals("dict")) { - dict = true; - } else { - MainRegistry.logger.error("Error reading recipe, stack array does not have 'item' or 'dict' label!"); - return null; - } - - } else { - MainRegistry.logger.error("Error reading recipe, label is not a valid data type!"); - return null; - } - - /* - * EVAL NAME - */ - if(array.get(1).isJsonPrimitive()) { - item = array.get(1).getAsString(); - } else { - MainRegistry.logger.error("Error reading recipe, item string is not a valid data type!"); - return null; - } - - /* - * EVAL STACKSIZE - */ - if(array.size() > 2 && array.get(2).isJsonPrimitive()) { - if(array.get(2).getAsJsonPrimitive().isNumber()) { - stacksize = Math.max(1, array.get(2).getAsJsonPrimitive().getAsNumber().intValue()); - } else { - MainRegistry.logger.error("Error reading recipe, stack size is not a valid data type!"); - return null; - } - } - - /* - * RESOLVE OREDICT - */ - if(dict) { - - if(OreDictionary.doesOreNameExist(item)) { - return new OreDictStack(item, stacksize); - } else { - - MainRegistry.logger.error("Error reading recipe, ore dict name does not exist!"); - return null; - } - - /* - * RESOLVE COMPARABLE - */ - } else { - - /* - * EVAL META - */ - if(array.size() > 3 && array.get(3).isJsonPrimitive()) { - if(array.get(3).getAsJsonPrimitive().isNumber()) { - meta = Math.max(0, array.get(3).getAsJsonPrimitive().getAsNumber().intValue()); - } else { - MainRegistry.logger.error("Error reading recipe, metadata is not a valid data type!"); - return null; - } - } - - Item it = (Item)Item.itemRegistry.getObject(item); - if(it == null) { - MainRegistry.logger.error("Item could not be found!"); - return null; - } - - return new ComparableStack(it, stacksize, meta); - } - } - - protected static void writeAStack(AStack astack, JsonWriter writer) throws IOException { - - writer.beginArray(); - writer.setIndent(""); - - if(astack instanceof ComparableStack) { - ComparableStack comp = (ComparableStack) astack; - - writer.value("item"); //ITEM identifier - writer.value(Item.itemRegistry.getNameForObject(comp.toStack().getItem())); //item name - if(comp.stacksize != 1) writer.value(comp.stacksize); //stack size - if(comp.meta > 0) writer.value(comp.meta); //metadata - } - - if(astack instanceof OreDictStack) { - OreDictStack ore = (OreDictStack) astack; - - writer.value("dict"); //DICT identifier - writer.value(ore.name); //dict name - writer.value(ore.stacksize); //stacksize - } - - writer.endArray(); - writer.setIndent(" "); - } -} diff --git a/src/main/java/com/hbm/inventory/recipes/loader/SerializableRecipe.java b/src/main/java/com/hbm/inventory/recipes/loader/SerializableRecipe.java index 92e378ef2..405cede7f 100644 --- a/src/main/java/com/hbm/inventory/recipes/loader/SerializableRecipe.java +++ b/src/main/java/com/hbm/inventory/recipes/loader/SerializableRecipe.java @@ -60,6 +60,7 @@ public abstract class SerializableRecipe { recipeHandlers.add(new FuelPoolRecipes()); recipeHandlers.add(new MixerRecipes()); recipeHandlers.add(new OutgasserRecipes()); + recipeHandlers.add(new CompressorRecipes()); recipeHandlers.add(new MatDistribution()); } @@ -266,7 +267,8 @@ public abstract class SerializableRecipe { try { FluidType type = Fluids.fromName(array.get(0).getAsString()); int fill = array.get(1).getAsInt(); - return new FluidStack(type, fill); + int pressure = array.size() < 3 ? 0 : array.get(2).getAsInt(); + return new FluidStack(type, fill, pressure); } catch(Exception ex) { } MainRegistry.logger.error("Error reading fluid array " + array.toString()); return new FluidStack(Fluids.NONE, 0); @@ -287,6 +289,7 @@ public abstract class SerializableRecipe { writer.setIndent(""); writer.value(stack.type.getName()); //fluid type writer.value(stack.fill); //amount in mB + if(stack.pressure != 0) writer.value(stack.pressure); writer.endArray(); writer.setIndent(" "); } diff --git a/src/main/java/com/hbm/items/tool/ItemBlowtorch.java b/src/main/java/com/hbm/items/tool/ItemBlowtorch.java index 172e0fa4a..211a203c6 100644 --- a/src/main/java/com/hbm/items/tool/ItemBlowtorch.java +++ b/src/main/java/com/hbm/items/tool/ItemBlowtorch.java @@ -137,7 +137,7 @@ public class ItemBlowtorch extends Item implements IFillableItem { if(!world.isRemote) { if(this == ModItems.blowtorch) { - this.setFill(stack, Fluids.GAS, this.getFill(stack, Fluids.GAS) - 1000); + this.setFill(stack, Fluids.GAS, this.getFill(stack, Fluids.GAS) - 250); } if(this == ModItems.acetylene_torch) { diff --git a/src/main/java/com/hbm/render/tileentity/RenderCompressor.java b/src/main/java/com/hbm/render/tileentity/RenderCompressor.java index 4c8eb0faa..6934ff5ac 100644 --- a/src/main/java/com/hbm/render/tileentity/RenderCompressor.java +++ b/src/main/java/com/hbm/render/tileentity/RenderCompressor.java @@ -4,6 +4,7 @@ import org.lwjgl.opengl.GL11; import com.hbm.blocks.BlockDummyable; import com.hbm.main.ResourceManager; +import com.hbm.tileentity.machine.TileEntityMachineCompressor; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.tileentity.TileEntity; @@ -28,18 +29,18 @@ public class RenderCompressor extends TileEntitySpecialRenderer { bindTexture(ResourceManager.compressor_tex); ResourceManager.compressor.renderPart("Compressor"); - double h = (System.currentTimeMillis() * 0.005) % 6D; - - if(h > 3) h = 6 - h; + TileEntityMachineCompressor compressor = (TileEntityMachineCompressor) tile; + float lift = compressor.prevPiston + (compressor.piston - compressor.prevPiston) * interp; + float fan = compressor.prevFanSpin + (compressor.fanSpin - compressor.prevFanSpin) * interp; GL11.glPushMatrix(); - GL11.glTranslated(0, h - 3, 0); + GL11.glTranslatef(0, lift * 3 - 3, 0); ResourceManager.compressor.renderPart("Pump"); GL11.glPopMatrix(); GL11.glPushMatrix(); GL11.glTranslated(0, 1.5, 0); - GL11.glRotated((System.currentTimeMillis() * -0.5) % 360, 1, 0, 0); + GL11.glRotatef(fan, 1, 0, 0); GL11.glTranslated(0, -1.5, 0); ResourceManager.compressor.renderPart("Fan"); GL11.glPopMatrix(); diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineCompressor.java b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineCompressor.java index 69c09f344..26c4210ef 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityMachineCompressor.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityMachineCompressor.java @@ -1,21 +1,52 @@ package com.hbm.tileentity.machine; +import com.hbm.blocks.BlockDummyable; +import com.hbm.interfaces.IControlReceiver; import com.hbm.inventory.container.ContainerCompressor; +import com.hbm.inventory.fluid.Fluids; +import com.hbm.inventory.fluid.tank.FluidTank; import com.hbm.inventory.gui.GUICompressor; +import com.hbm.inventory.recipes.CompressorRecipes; +import com.hbm.inventory.recipes.CompressorRecipes.CompressorRecipe; +import com.hbm.lib.Library; import com.hbm.tileentity.IGUIProvider; import com.hbm.tileentity.TileEntityMachineBase; +import com.hbm.util.Tuple.Pair; +import com.hbm.util.fauxpointtwelve.DirPos; +import api.hbm.energy.IEnergyUser; +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.MathHelper; import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; -public class TileEntityMachineCompressor extends TileEntityMachineBase implements IGUIProvider { +public class TileEntityMachineCompressor extends TileEntityMachineBase implements IGUIProvider, IControlReceiver, IEnergyUser, IFluidStandardTransceiver { + + public FluidTank[] tanks; + public long power; + public static final long maxPower = 1_000_000; + public boolean isOn; + public int progress; + public int processTime = 100; + + public float fanSpin; + public float prevFanSpin; + public float piston; + public float prevPiston; + public boolean pistonDir; public TileEntityMachineCompressor() { super(2); + this.tanks = new FluidTank[2]; + this.tanks[0] = new FluidTank(Fluids.NONE, 16_000); + this.tanks[1] = new FluidTank(Fluids.NONE, 16_000).withPressure(1); } @Override @@ -28,8 +59,148 @@ public class TileEntityMachineCompressor extends TileEntityMachineBase implement if(!worldObj.isRemote) { + if(worldObj.getTotalWorldTime() % 20 == 0) { + this.updateConnections(); + } + + this.power = Library.chargeTEFromItems(slots, 1, power, maxPower); + this.tanks[0].setType(0, slots); + this.setupTanks(); + + if(canProcess()) { + this.progress++; + this.isOn = true; + this.power -= 1_000; + + if(progress >= this.processTime) { + progress = 0; + this.process(); + this.markChanged(); + } + + } else { + this.progress = 0; + this.isOn = false; + } + + for(DirPos pos : getConPos()) { + this.sendFluid(tanks[1], worldObj, pos.getX(), pos.getY(), pos.getZ(), pos.getDir()); + } + + NBTTagCompound data = new NBTTagCompound(); + data.setInteger("progress", progress); + data.setLong("power", power); + tanks[0].writeToNBT(data, "0"); + tanks[1].writeToNBT(data, "1"); + data.setBoolean("isOn", isOn); + this.networkPack(data, 100); + + } else { + + this.prevFanSpin = this.fanSpin; + this.prevPiston = this.piston; + + if(this.isOn) { + this.fanSpin += 15; + + if(this.fanSpin >= 360) { + this.prevFanSpin -= 360; + this.fanSpin -= 360; + } + + if(this.pistonDir) { + this.piston -= 0.1F; + if(this.piston <= 0) this.pistonDir = !this.pistonDir; + } else { + this.piston += 0.05F; + if(this.piston >= 1) this.pistonDir = !this.pistonDir; + } + + this.piston = MathHelper.clamp_float(this.piston, 0F, 1F); + } } } + + public void networkUnpack(NBTTagCompound nbt) { + this.progress = nbt.getInteger("progress"); + this.power = nbt.getLong("power"); + tanks[0].readFromNBT(nbt, "0"); + tanks[1].readFromNBT(nbt, "1"); + this.isOn = nbt.getBoolean("isOn"); + } + + private void updateConnections() { + for(DirPos pos : getConPos()) { + this.trySubscribe(worldObj, pos.getX(), pos.getY(), pos.getZ(), pos.getDir()); + this.trySubscribe(tanks[0].getTankType(), worldObj, pos.getX(), pos.getY(), pos.getZ(), pos.getDir()); + } + } + + public DirPos[] getConPos() { + ForgeDirection dir = ForgeDirection.getOrientation(this.getBlockMetadata() - BlockDummyable.offset); + ForgeDirection rot = dir.getRotation(ForgeDirection.UP); + + return new DirPos[] { + new DirPos(xCoord + rot.offsetX * 2, yCoord, zCoord + rot.offsetZ * 2, rot), + new DirPos(xCoord - rot.offsetX * 2, yCoord, zCoord - rot.offsetZ * 2, rot.getOpposite()), + new DirPos(xCoord + dir.offsetX * 2, yCoord, zCoord + dir.offsetZ * 2, dir), + }; + } + + public boolean canProcess() { + + if(this.power <= 1_000) return false; + + CompressorRecipe recipe = CompressorRecipes.recipes.get(new Pair(tanks[0].getTankType(), tanks[0].getPressure())); + + if(recipe == null) { + return tanks[0].getFill() >= 1000 && tanks[1].getFill() + 1000 <= tanks[1].getMaxFill(); + } + + return tanks[0].getFill() > recipe.inputAmount && tanks[1].getFill() + recipe.output.fill <= tanks[1].getMaxFill(); + } + + public void process() { + + CompressorRecipe recipe = CompressorRecipes.recipes.get(new Pair(tanks[0].getTankType(), tanks[0].getPressure())); + + if(recipe == null) { + tanks[0].setFill(tanks[0].getFill() - 1_000); + tanks[1].setFill(tanks[1].getFill() + 1_000); + } else { + tanks[0].setFill(tanks[0].getFill() - recipe.inputAmount); + tanks[1].setFill(tanks[1].getFill() + recipe.output.fill); + } + } + + protected void setupTanks() { + + CompressorRecipe recipe = CompressorRecipes.recipes.get(new Pair(tanks[0].getTankType(), tanks[0].getPressure())); + + if(recipe == null) { + tanks[1].withPressure(tanks[0].getPressure() + 1).setTankType(tanks[0].getTankType()); + } else { + tanks[1].withPressure(recipe.output.pressure).setTankType(recipe.output.type); + } + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + super.readFromNBT(nbt); + power = nbt.getLong("power"); + progress = nbt.getInteger("progress"); + tanks[0].readFromNBT(nbt, "0"); + tanks[1].readFromNBT(nbt, "1"); + } + + @Override + public void writeToNBT(NBTTagCompound nbt) { + super.writeToNBT(nbt); + nbt.setLong("power", power); + nbt.setInteger("progress", progress); + tanks[0].writeToNBT(nbt, "0"); + tanks[1].writeToNBT(nbt, "1"); + } @Override public Container provideContainer(int ID, EntityPlayer player, World world, int x, int y, int z) { @@ -42,4 +213,82 @@ public class TileEntityMachineCompressor extends TileEntityMachineBase implement return new GUICompressor(player.inventory, this); } + @Override + public boolean hasPermission(EntityPlayer player) { + return this.isUseableByPlayer(player); + } + + @Override + public void receiveControl(NBTTagCompound data) { + int compression = data.getInteger("compression"); + + if(compression != tanks[0].getPressure()) { + tanks[0].withPressure(compression); + + CompressorRecipe recipe = CompressorRecipes.recipes.get(new Pair(tanks[0].getTankType(), compression)); + + if(recipe == null) { + tanks[1].withPressure(compression + 1); + } else { + tanks[1].withPressure(recipe.output.pressure).setTankType(recipe.output.type); + } + + this.markChanged(); + } + } + + @Override + public long getPower() { + return power; + } + + @Override + public void setPower(long power) { + this.power = power; + } + + @Override + public long getMaxPower() { + return maxPower; + } + + @Override + public FluidTank[] getAllTanks() { + return tanks; + } + + @Override + public FluidTank[] getSendingTanks() { + return new FluidTank[] {tanks[1]}; + } + + @Override + public FluidTank[] getReceivingTanks() { + return new FluidTank[] {tanks[0]}; + } + + AxisAlignedBB bb = null; + + @Override + public AxisAlignedBB getRenderBoundingBox() { + + if(bb == null) { + bb = AxisAlignedBB.getBoundingBox( + xCoord - 2, + yCoord, + zCoord - 2, + xCoord + 3, + yCoord + 9, + zCoord + 3 + ); + } + + return bb; + } + + @Override + @SideOnly(Side.CLIENT) + public double getMaxRenderDistanceSquared() { + return 65536.0D; + } } diff --git a/src/main/resources/assets/hbm/textures/models/machines/compressor.png b/src/main/resources/assets/hbm/textures/models/machines/compressor.png index af84d82fd7c4a0ac20022cb0fedf303b0dfd56a2..2b26f107a5bf031ba598fe512912382c560c174b 100644 GIT binary patch literal 5337 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 literal 3463 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