diff options
Diffstat (limited to 'src/main/java/gregtech/common/tileentities/machines')
110 files changed, 32300 insertions, 0 deletions
diff --git a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_Bronze.java b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_Bronze.java new file mode 100644 index 0000000000..252cc6a5b8 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_Bronze.java @@ -0,0 +1,45 @@ +package gregtech.common.tileentities.machines; + +import gregtech.api.enums.Dyes; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicHull_NonElectric; +import gregtech.api.render.TextureFactory; + +public class GT_MetaTileEntity_BasicHull_Bronze extends GT_MetaTileEntity_BasicHull_NonElectric { + + public GT_MetaTileEntity_BasicHull_Bronze(int aID, String aName, String aNameRegional, int aTier, + String aDescription) { + super(aID, aName, aNameRegional, aTier, aDescription); + } + + public GT_MetaTileEntity_BasicHull_Bronze(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicHull_Bronze(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_BasicHull_Bronze(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + ITexture[][][] rTextures = new ITexture[3][17][]; + for (byte i = -1; i < 16; i = (byte) (i + 1)) { + rTextures[0][(i + 1)] = new ITexture[] { + TextureFactory.of(Textures.BlockIcons.MACHINE_BRONZE_BOTTOM, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + rTextures[1][(i + 1)] = new ITexture[] { + TextureFactory.of(Textures.BlockIcons.MACHINE_BRONZE_TOP, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + rTextures[2][(i + 1)] = new ITexture[] { + TextureFactory.of(Textures.BlockIcons.MACHINE_BRONZE_SIDE, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + } + return rTextures; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_BronzeBricks.java b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_BronzeBricks.java new file mode 100644 index 0000000000..ee788ba8c0 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_BronzeBricks.java @@ -0,0 +1,53 @@ +package gregtech.common.tileentities.machines; + +import gregtech.api.enums.Dyes; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicHull_NonElectric; +import gregtech.api.render.TextureFactory; + +public class GT_MetaTileEntity_BasicHull_BronzeBricks extends GT_MetaTileEntity_BasicHull_NonElectric { + + public GT_MetaTileEntity_BasicHull_BronzeBricks(int aID, String aName, String aNameRegional, int aTier, + String aDescription) { + super(aID, aName, aNameRegional, aTier, aDescription); + } + + public GT_MetaTileEntity_BasicHull_BronzeBricks(String aName, int aTier, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicHull_BronzeBricks(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_BasicHull_BronzeBricks( + this.mName, + this.mTier, + this.mDescriptionArray, + this.mTextures); + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + ITexture[][][] rTextures = new ITexture[3][17][]; + for (byte i = -1; i < 16; i = (byte) (i + 1)) { + ITexture[] tmp0 = { TextureFactory + .of(Textures.BlockIcons.MACHINE_BRONZEBRICKS_BOTTOM, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + rTextures[0][(i + 1)] = tmp0; + ITexture[] tmp1 = { TextureFactory + .of(Textures.BlockIcons.MACHINE_BRONZEBRICKS_TOP, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + rTextures[1][(i + 1)] = tmp1; + ITexture[] tmp2 = { TextureFactory + .of(Textures.BlockIcons.MACHINE_BRONZEBRICKS_SIDE, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + rTextures[2][(i + 1)] = tmp2; + } + return rTextures; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_Steel.java b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_Steel.java new file mode 100644 index 0000000000..85e461bf47 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_Steel.java @@ -0,0 +1,47 @@ +package gregtech.common.tileentities.machines; + +import gregtech.api.enums.Dyes; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicHull_NonElectric; +import gregtech.api.render.TextureFactory; + +public class GT_MetaTileEntity_BasicHull_Steel extends GT_MetaTileEntity_BasicHull_NonElectric { + + public GT_MetaTileEntity_BasicHull_Steel(int aID, String aName, String aNameRegional, int aTier, + String aDescription) { + super(aID, aName, aNameRegional, aTier, aDescription); + } + + public GT_MetaTileEntity_BasicHull_Steel(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicHull_Steel(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_BasicHull_Steel(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + ITexture[][][] rTextures = new ITexture[3][17][]; + for (byte i = -1; i < 16; i = (byte) (i + 1)) { + ITexture[] tmp0 = { + TextureFactory.of(Textures.BlockIcons.MACHINE_STEEL_BOTTOM, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + rTextures[0][(i + 1)] = tmp0; + ITexture[] tmp1 = { + TextureFactory.of(Textures.BlockIcons.MACHINE_STEEL_TOP, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + rTextures[1][(i + 1)] = tmp1; + ITexture[] tmp2 = { + TextureFactory.of(Textures.BlockIcons.MACHINE_STEEL_SIDE, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + rTextures[2][(i + 1)] = tmp2; + } + return rTextures; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_SteelBricks.java b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_SteelBricks.java new file mode 100644 index 0000000000..cd5f547d22 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_BasicHull_SteelBricks.java @@ -0,0 +1,53 @@ +package gregtech.common.tileentities.machines; + +import gregtech.api.enums.Dyes; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicHull_NonElectric; +import gregtech.api.render.TextureFactory; + +public class GT_MetaTileEntity_BasicHull_SteelBricks extends GT_MetaTileEntity_BasicHull_NonElectric { + + public GT_MetaTileEntity_BasicHull_SteelBricks(int aID, String aName, String aNameRegional, int aTier, + String aDescription) { + super(aID, aName, aNameRegional, aTier, aDescription); + } + + public GT_MetaTileEntity_BasicHull_SteelBricks(String aName, int aTier, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + public GT_MetaTileEntity_BasicHull_SteelBricks(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_BasicHull_SteelBricks( + this.mName, + this.mTier, + this.mDescriptionArray, + this.mTextures); + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + ITexture[][][] rTextures = new ITexture[3][17][]; + for (byte i = -1; i < 16; i = (byte) (i + 1)) { + ITexture[] tmp0 = { TextureFactory + .of(Textures.BlockIcons.MACHINE_STEELBRICKS_BOTTOM, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + rTextures[0][(i + 1)] = tmp0; + ITexture[] tmp1 = { TextureFactory + .of(Textures.BlockIcons.MACHINE_STEELBRICKS_TOP, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + rTextures[1][(i + 1)] = tmp1; + ITexture[] tmp2 = { TextureFactory + .of(Textures.BlockIcons.MACHINE_STEELBRICKS_SIDE, Dyes.getModulation(i, Dyes._NULL.mRGBa)) }; + rTextures[2][(i + 1)] = tmp2; + } + return rTextures; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_CraftingInput_ME.java b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_CraftingInput_ME.java new file mode 100644 index 0000000000..f7ba3af5f0 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_CraftingInput_ME.java @@ -0,0 +1,1039 @@ +package gregtech.common.tileentities.machines; + +import static gregtech.api.enums.GT_Values.TIER_COLORS; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_CRAFTING_INPUT_BUFFER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_CRAFTING_INPUT_BUS; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.fluids.FluidStack; + +import org.apache.commons.lang3.ArrayUtils; +import org.jetbrains.annotations.NotNull; + +import com.glodblock.github.common.item.ItemFluidPacket; +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Size; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.SlotGroup; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; + +import appeng.api.AEApi; +import appeng.api.implementations.ICraftingPatternItem; +import appeng.api.implementations.IPowerChannelState; +import appeng.api.networking.GridFlags; +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.ICraftingPatternDetails; +import appeng.api.networking.crafting.ICraftingProvider; +import appeng.api.networking.crafting.ICraftingProviderHelper; +import appeng.api.networking.events.MENetworkCraftingPatternChange; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.IActionHost; +import appeng.api.networking.security.MachineSource; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.AECableType; +import appeng.api.util.DimensionalCoord; +import appeng.api.util.IInterfaceViewable; +import appeng.core.AppEng; +import appeng.core.sync.GuiBridge; +import appeng.helpers.ICustomNameObject; +import appeng.items.misc.ItemEncodedPattern; +import appeng.items.tools.quartz.ToolQuartzCuttingKnife; +import appeng.me.GridAccessException; +import appeng.me.helpers.AENetworkProxy; +import appeng.me.helpers.IGridProxyable; +import appeng.util.IWideReadableNumberConverter; +import appeng.util.Platform; +import appeng.util.ReadableNumberConverter; +import gregtech.GT_Mod; +import gregtech.api.enums.ItemList; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.IConfigurationCircuitSupport; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IAddGregtechLogo; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.extensions.ArrayExt; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaTileEntity_Hatch_CraftingInput_ME extends GT_MetaTileEntity_Hatch_InputBus + implements IConfigurationCircuitSupport, IAddGregtechLogo, IAddUIWidgets, IPowerChannelState, ICraftingProvider, + IGridProxyable, IDualInputHatch, ICustomNameObject, IInterfaceViewable { + + // Each pattern slot in the crafting input hatch has its own internal inventory + public static class PatternSlot implements IDualInputInventory { + + public interface SharedItemGetter { + + ItemStack[] getSharedItem(); + } + + private final ItemStack pattern; + private final ICraftingPatternDetails patternDetails; + private final List<ItemStack> itemInventory; + private final List<FluidStack> fluidInventory; + private final SharedItemGetter sharedItemGetter; + + public PatternSlot(ItemStack pattern, World world, SharedItemGetter getter) { + this.pattern = pattern; + this.patternDetails = ((ICraftingPatternItem) Objects.requireNonNull(pattern.getItem())) + .getPatternForItem(pattern, world); + this.itemInventory = new ArrayList<>(); + this.fluidInventory = new ArrayList<>(); + this.sharedItemGetter = getter; + } + + public PatternSlot(ItemStack pattern, NBTTagCompound nbt, World world, SharedItemGetter getter) { + this.pattern = pattern; + this.patternDetails = ((ICraftingPatternItem) Objects.requireNonNull(pattern.getItem())) + .getPatternForItem(pattern, world); + this.itemInventory = new ArrayList<>(); + this.fluidInventory = new ArrayList<>(); + this.sharedItemGetter = getter; + NBTTagList inv = nbt.getTagList("inventory", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < inv.tagCount(); i++) { + NBTTagCompound tagItemStack = inv.getCompoundTagAt(i); + var item = GT_Utility.loadItem(tagItemStack); + if (item != null) { + if (item.stackSize > 0) { + itemInventory.add(item); + } + } else { + GT_Mod.GT_FML_LOGGER.warn( + "An error occurred while loading contents of ME Crafting Input Bus. This item has been voided: " + + tagItemStack); + } + } + NBTTagList fluidInv = nbt.getTagList("fluidInventory", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < fluidInv.tagCount(); i++) { + NBTTagCompound tagFluidStack = fluidInv.getCompoundTagAt(i); + var fluid = FluidStack.loadFluidStackFromNBT(tagFluidStack); + if (fluid != null) { + if (fluid.amount > 0) { + fluidInventory.add(fluid); + } + } else { + GT_Mod.GT_FML_LOGGER.warn( + "An error occurred while loading contents of ME Crafting Input Bus. This fluid has been voided: " + + tagFluidStack); + } + } + } + + public boolean hasChanged(ItemStack newPattern, World world) { + return newPattern == null + || (!ItemStack.areItemStacksEqual(pattern, newPattern) && !this.patternDetails.equals( + ((ICraftingPatternItem) Objects.requireNonNull(pattern.getItem())) + .getPatternForItem(newPattern, world))); + } + + private boolean isEmpty() { + // if one item / fluid is empty then it should be safe to assume all other is empty, + // or at least won't require a recipe check, as long as the pattern is sane + if (!itemInventory.isEmpty()) { + return itemInventory.get(0) == null || itemInventory.get(0).stackSize <= 0; + } + + if (!fluidInventory.isEmpty()) { + return fluidInventory.get(0) == null || fluidInventory.get(0).amount <= 0; + } + return true; + } + + @Override + public ItemStack[] getItemInputs() { + if (isEmpty()) return new ItemStack[0]; + return ArrayUtils.addAll(itemInventory.toArray(new ItemStack[0]), sharedItemGetter.getSharedItem()); + } + + @Override + public FluidStack[] getFluidInputs() { + if (isEmpty()) return new FluidStack[0]; + return fluidInventory.toArray(new FluidStack[0]); + } + + public ICraftingPatternDetails getPatternDetails() { + return patternDetails; + } + + public void refund(AENetworkProxy proxy, BaseActionSource src) throws GridAccessException { + IMEMonitor<IAEItemStack> sg = proxy.getStorage() + .getItemInventory(); + for (ItemStack itemStack : itemInventory) { + if (itemStack == null || itemStack.stackSize == 0) continue; + IAEItemStack rest = Platform.poweredInsert( + proxy.getEnergy(), + sg, + AEApi.instance() + .storage() + .createItemStack(itemStack), + src); + itemStack.stackSize = rest != null && rest.getStackSize() > 0 ? (int) rest.getStackSize() : 0; + } + IMEMonitor<IAEFluidStack> fsg = proxy.getStorage() + .getFluidInventory(); + for (FluidStack fluidStack : fluidInventory) { + if (fluidStack == null || fluidStack.amount == 0) continue; + IAEFluidStack rest = Platform.poweredInsert( + proxy.getEnergy(), + fsg, + AEApi.instance() + .storage() + .createFluidStack(fluidStack), + src); + fluidStack.amount = rest != null && rest.getStackSize() > 0 ? (int) rest.getStackSize() : 0; + } + } + + public boolean insertItemsAndFluids(InventoryCrafting inventoryCrafting) { + int errorIndex = -1; // overflow may occur at this index + for (int i = 0; i < inventoryCrafting.getSizeInventory(); ++i) { + ItemStack itemStack = inventoryCrafting.getStackInSlot(i); + if (itemStack == null) continue; + + boolean inserted = false; + if (itemStack.getItem() instanceof ItemFluidPacket) { // insert fluid + var fluidStack = ItemFluidPacket.getFluidStack(itemStack); + if (fluidStack == null) continue; + for (var fluid : fluidInventory) { + if (!fluid.isFluidEqual(fluidStack)) continue; + if (Integer.MAX_VALUE - fluidStack.amount < fluid.amount) { + // Overflow detected + errorIndex = i; + break; + } + fluid.amount += fluidStack.amount; + inserted = true; + break; + } + if (errorIndex != -1) break; + if (!inserted) { + fluidInventory.add(fluidStack); + } + } else { // insert item + for (var item : itemInventory) { + if (!itemStack.isItemEqual(item)) continue; + if (Integer.MAX_VALUE - itemStack.stackSize < item.stackSize) { + // Overflow detected + errorIndex = i; + break; + } + item.stackSize += itemStack.stackSize; + inserted = true; + break; + } + if (errorIndex != -1) break; + if (!inserted) { + itemInventory.add(itemStack); + } + } + } + if (errorIndex != -1) { // need to rollback + // Clean up the inserted items/liquids + for (int i = 0; i < errorIndex; ++i) { + var itemStack = inventoryCrafting.getStackInSlot(i); + if (itemStack == null) continue; + if (itemStack.getItem() instanceof ItemFluidPacket) { // remove fluid + var fluidStack = ItemFluidPacket.getFluidStack(itemStack); + if (fluidStack == null) continue; + for (var fluid : fluidInventory) { + if (fluid.isFluidEqual(fluidStack)) { + fluid.amount -= fluidStack.amount; + break; + } + } + } else { // remove item + for (var item : itemInventory) { + if (item.isItemEqual(itemStack)) { + item.stackSize -= itemStack.stackSize; + break; + } + } + } + } + return false; + } + return true; + } + + public NBTTagCompound writeToNBT(NBTTagCompound nbt) { + nbt.setTag("pattern", pattern.writeToNBT(new NBTTagCompound())); + + NBTTagList itemInventoryNbt = new NBTTagList(); + for (ItemStack itemStack : this.itemInventory) { + itemInventoryNbt.appendTag(GT_Utility.saveItem(itemStack)); + } + nbt.setTag("inventory", itemInventoryNbt); + + NBTTagList fluidInventoryNbt = new NBTTagList(); + for (FluidStack fluidStack : fluidInventory) { + fluidInventoryNbt.appendTag(fluidStack.writeToNBT(new NBTTagCompound())); + } + nbt.setTag("fluidInventory", fluidInventoryNbt); + + return nbt; + } + } + + // mInventory is used for storing patterns, circuit and manual slot (typically NC items) + private static final int MAX_PATTERN_COUNT = 4 * 9; + private static final int SLOT_MANUAL_SIZE = 9; + private static final int MAX_INV_COUNT = MAX_PATTERN_COUNT + SLOT_MANUAL_SIZE + 1; + private static final int SLOT_CIRCUIT = MAX_PATTERN_COUNT; + private static final int SLOT_MANUAL_START = SLOT_CIRCUIT + 1; + private static final int MANUAL_SLOT_WINDOW = 10; + private BaseActionSource requestSource = null; + private @Nullable AENetworkProxy gridProxy = null; + + // holds all internal inventories + private PatternSlot[] internalInventory = new PatternSlot[MAX_PATTERN_COUNT]; + + // a hash map for faster lookup of pattern slots, not necessarily all valid. + private Map<ICraftingPatternDetails, PatternSlot> patternDetailsPatternSlotMap = new HashMap<>(MAX_PATTERN_COUNT); + + private boolean needPatternSync = true; + private boolean justHadNewItems = false; + + private String customName = null; + private boolean supportFluids; + private boolean additionalConnection = false; + + public GT_MetaTileEntity_Hatch_CraftingInput_ME(int aID, String aName, String aNameRegional, + boolean supportFluids) { + super( + aID, + aName, + aNameRegional, + supportFluids ? 11 : 6, + MAX_INV_COUNT, + new String[] { "Advanced item input for Multiblocks", + "Hatch Tier: " + TIER_COLORS[supportFluids ? 11 : 6] + VN[supportFluids ? 11 : 6], + "Processes patterns directly from ME", + supportFluids ? "It supports patterns including fluids" + : "It does not support patterns including fluids", + "Change ME connection behavior by right-clicking with wire cutter" }); + disableSort = true; + this.supportFluids = supportFluids; + } + + public GT_MetaTileEntity_Hatch_CraftingInput_ME(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures, boolean supportFluids) { + super(aName, aTier, MAX_INV_COUNT, aDescription, aTextures); + this.supportFluids = supportFluids; + disableSort = true; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_CraftingInput_ME(mName, mTier, mDescriptionArray, mTextures, supportFluids); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return getTexturesInactive(aBaseTexture); + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, + TextureFactory.of(supportFluids ? OVERLAY_ME_CRAFTING_INPUT_BUFFER : OVERLAY_ME_CRAFTING_INPUT_BUS) }; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + super.onPostTick(aBaseMetaTileEntity, aTimer); + + if (getBaseMetaTileEntity().isServerSide()) { + if (needPatternSync && aTimer % 10 == 0) { + needPatternSync = !postMEPatternChange(); + } + if (aTimer % 20 == 0) { + getBaseMetaTileEntity().setActive(isActive()); + } + } + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + getProxy().onReady(); + } + + @Override + public IGridNode getGridNode(ForgeDirection dir) { + return getProxy().getNode(); + } + + @Override + public AECableType getCableConnectionType(ForgeDirection forgeDirection) { + return isOutputFacing(forgeDirection) ? AECableType.SMART : AECableType.NONE; + } + + private void updateValidGridProxySides() { + if (additionalConnection) { + getProxy().setValidSides(EnumSet.complementOf(EnumSet.of(ForgeDirection.UNKNOWN))); + } else { + getProxy().setValidSides(EnumSet.of(getBaseMetaTileEntity().getFrontFacing())); + } + } + + @Override + public void onFacingChange() { + updateValidGridProxySides(); + } + + @Override + public void securityBreak() {} + + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ) { + additionalConnection = !additionalConnection; + updateValidGridProxySides(); + aPlayer.addChatComponentMessage( + new ChatComponentTranslation("GT5U.hatch.additionalConnection." + additionalConnection)); + return true; + } + + @Override + public AENetworkProxy getProxy() { + if (gridProxy == null) { + gridProxy = new AENetworkProxy(this, "proxy", ItemList.Hatch_CraftingInput_Bus_ME.get(1), true); + gridProxy.setFlags(GridFlags.REQUIRE_CHANNEL); + updateValidGridProxySides(); + if (getBaseMetaTileEntity().getWorld() != null) gridProxy.setOwner( + getBaseMetaTileEntity().getWorld() + .getPlayerEntityByName(getBaseMetaTileEntity().getOwnerName())); + } + + return this.gridProxy; + } + + @Override + public DimensionalCoord getLocation() { + return new DimensionalCoord( + getBaseMetaTileEntity().getWorld(), + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord()); + } + + @Override + public int rows() { + return 4; + } + + @Override + public int rowSize() { + return 9; + } + + @Override + public IInventory getPatterns() { + return this; + } + + @Override + public String getName() { + if (hasCustomName()) { + return getCustomName(); + } + StringBuilder name = new StringBuilder(); + if (getCrafterIcon() != null) { + name.append(getCrafterIcon().getDisplayName()); + } else { + name.append(getLocalName()); + } + + if (mInventory[SLOT_CIRCUIT] != null) { + name.append(" - "); + name.append(mInventory[SLOT_CIRCUIT].getItemDamage()); + } + if (mInventory[SLOT_MANUAL_START] != null) { + name.append(" - "); + name.append(mInventory[SLOT_MANUAL_START].getDisplayName()); + } + return name.toString(); + } + + @Override + public TileEntity getTileEntity() { + return (TileEntity) getBaseMetaTileEntity(); + } + + @Override + public boolean shouldDisplay() { + return true; + } + + @Override + public void gridChanged() { + needPatternSync = true; + } + + @Override + public boolean isPowered() { + return getProxy() != null && getProxy().isPowered(); + } + + @Override + public boolean isActive() { + return getProxy() != null && getProxy().isActive(); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + + // save internalInventory + NBTTagList internalInventoryNBT = new NBTTagList(); + for (int i = 0; i < internalInventory.length; i++) { + if (internalInventory[i] != null) { + NBTTagCompound internalInventorySlotNBT = new NBTTagCompound(); + internalInventorySlotNBT.setInteger("patternSlot", i); + internalInventorySlotNBT + .setTag("patternSlotNBT", internalInventory[i].writeToNBT(new NBTTagCompound())); + internalInventoryNBT.appendTag(internalInventorySlotNBT); + } + } + aNBT.setTag("internalInventory", internalInventoryNBT); + if (customName != null) aNBT.setString("customName", customName); + aNBT.setBoolean("additionalConnection", additionalConnection); + getProxy().writeToNBT(aNBT); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + // load internalInventory + NBTTagList internalInventoryNBT = aNBT.getTagList("internalInventory", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < internalInventoryNBT.tagCount(); i++) { + NBTTagCompound internalInventorySlotNBT = internalInventoryNBT.getCompoundTagAt(i); + int patternSlot = internalInventorySlotNBT.getInteger("patternSlot"); + NBTTagCompound patternSlotNBT = internalInventorySlotNBT.getCompoundTag("patternSlotNBT"); + ItemStack pattern = ItemStack.loadItemStackFromNBT(patternSlotNBT.getCompoundTag("pattern")); + if (pattern != null) { + internalInventory[patternSlot] = new PatternSlot( + pattern, + patternSlotNBT, + getBaseMetaTileEntity().getWorld(), + this::getSharedItems); + } else { + GT_Mod.GT_FML_LOGGER.warn( + "An error occurred while loading contents of ME Crafting Input Bus. This pattern has been voided: " + + patternSlotNBT); + } + } + + // Migrate from 4x8 to 4x9 pattern inventory + int oldPatternCount = 4 * 8; + int oldSlotManual = oldPatternCount + 1; + int oldSlotCircuit = oldPatternCount; + + if (internalInventory[oldSlotManual] == null && mInventory[oldSlotManual] != null) { + mInventory[SLOT_MANUAL_START] = mInventory[oldSlotManual]; + mInventory[oldSlotManual] = null; + } + if (internalInventory[oldSlotCircuit] == null && mInventory[oldSlotCircuit] != null) { + mInventory[SLOT_CIRCUIT] = mInventory[oldSlotCircuit]; + mInventory[oldSlotCircuit] = null; + } + + // reconstruct patternDetailsPatternSlotMap + patternDetailsPatternSlotMap.clear(); + for (PatternSlot patternSlot : internalInventory) { + if (patternSlot != null) { + patternDetailsPatternSlotMap.put(patternSlot.getPatternDetails(), patternSlot); + } + } + + if (aNBT.hasKey("customName")) customName = aNBT.getString("customName"); + additionalConnection = aNBT.getBoolean("additionalConnection"); + + getProxy().readFromNBT(aNBT); + } + + @Override + public boolean isGivingInformation() { + return true; + } + + private String describePattern(ICraftingPatternDetails patternDetails) { + return Arrays.stream(patternDetails.getCondensedOutputs()) + .map( + aeItemStack -> aeItemStack.getItem() + .getItemStackDisplayName(aeItemStack.getItemStack())) + .collect(Collectors.joining(", ")); + } + + @Override + public String[] getInfoData() { + var ret = new ArrayList<String>(); + ret.add( + "The bus is " + ((getProxy() != null && getProxy().isActive()) ? EnumChatFormatting.GREEN + "online" + : EnumChatFormatting.RED + "offline" + getAEDiagnostics()) + EnumChatFormatting.RESET); + ret.add("Internal Inventory: "); + var i = 0; + for (var slot : internalInventory) { + if (slot == null) continue; + IWideReadableNumberConverter nc = ReadableNumberConverter.INSTANCE; + + i += 1; + ret.add( + "Slot " + i + + " " + + EnumChatFormatting.BLUE + + describePattern(slot.patternDetails) + + EnumChatFormatting.RESET); + for (var item : slot.itemInventory) { + if (item == null || item.stackSize == 0) continue; + ret.add( + item.getItem() + .getItemStackDisplayName(item) + ": " + + EnumChatFormatting.GOLD + + nc.toWideReadableForm(item.stackSize) + + EnumChatFormatting.RESET); + } + for (var fluid : slot.fluidInventory) { + if (fluid == null || fluid.amount == 0) continue; + ret.add( + fluid.getLocalizedName() + ": " + + EnumChatFormatting.AQUA + + nc.toWideReadableForm(fluid.amount) + + EnumChatFormatting.RESET); + } + } + return ret.toArray(new String[0]); + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public int getCircuitSlot() { + return SLOT_CIRCUIT; + } + + @Override + public int getCircuitSlotX() { + return 170; + } + + @Override + public int getCircuitSlotY() { + return 64; + } + + @Override + public boolean isValidSlot(int aIndex) { + return true; + } + + @Override + public int getGUIWidth() { + return super.getGUIWidth() + 16; + } + + @Override + public void addUIWidgets(ModularWindow.@NotNull Builder builder, UIBuildContext buildContext) { + buildContext.addSyncedWindow(MANUAL_SLOT_WINDOW, this::createSlotManualWindow); + builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 9) + .startFromSlot(0) + .endAtSlot(MAX_PATTERN_COUNT - 1) + .phantom(false) + .background(getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_PATTERN_ME) + .widgetCreator(slot -> new SlotWidget(slot) { + + @Override + protected ItemStack getItemStackForRendering(Slot slotIn) { + var stack = slot.getStack(); + if (stack == null || !(stack.getItem() instanceof ItemEncodedPattern patternItem)) { + return stack; + } + var output = patternItem.getOutput(stack); + return output != null ? output : stack; + } + }.setFilter(itemStack -> itemStack.getItem() instanceof ICraftingPatternItem) + .setChangeListener(() -> onPatternChange(slot.getSlotIndex(), slot.getStack()))) + .build() + .setPos(7, 9)) + .widget(new ButtonWidget().setOnClick((clickData, widget) -> { + if (clickData.mouseButton == 0) { + widget.getContext() + .openSyncedWindow(MANUAL_SLOT_WINDOW); + } + }) + .setPlayClickSound(true) + .setBackground(GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_PLUS_LARGE) + .addTooltips(ImmutableList.of("Place manual items")) + .setSize(16, 16) + .setPos(170, 45)) + .widget(new ButtonWidget().setOnClick((clickData, widget) -> { + if (clickData.mouseButton == 0) { + refundAll(); + } + }) + .setPlayClickSound(true) + .setBackground(GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_EXPORT) + .addTooltips(ImmutableList.of("Return all internally stored items back to AE")) + .setSize(16, 16) + .setPos(170, 28)); + } + + @Override + public void updateSlots() { + for (int slotId = SLOT_MANUAL_START; slotId < SLOT_MANUAL_START + SLOT_MANUAL_SIZE; ++slotId) { + if (mInventory[slotId] != null && mInventory[slotId].stackSize <= 0) mInventory[slotId] = null; + } + } + + private BaseActionSource getRequest() { + if (requestSource == null) requestSource = new MachineSource((IActionHost) getBaseMetaTileEntity()); + return requestSource; + } + + private void onPatternChange(int index, ItemStack newItem) { + if (!getBaseMetaTileEntity().isServerSide()) return; + + var world = getBaseMetaTileEntity().getWorld(); + + // remove old if applicable + var originalPattern = internalInventory[index]; + if (originalPattern != null) { + if (originalPattern.hasChanged(newItem, world)) { + try { + originalPattern.refund(getProxy(), getRequest()); + } catch (GridAccessException ignored) {} + internalInventory[index] = null; + needPatternSync = true; + } else { + return; // nothing has changed + } + } + + // original does not exist or has changed + if (newItem == null || !(newItem.getItem() instanceof ICraftingPatternItem)) return; + + var patternSlot = new PatternSlot(newItem, world, this::getSharedItems); + internalInventory[index] = patternSlot; + patternDetailsPatternSlotMap.put(patternSlot.getPatternDetails(), patternSlot); + + needPatternSync = true; + } + + public ItemStack[] getSharedItems() { + ItemStack[] sharedItems = new ItemStack[SLOT_MANUAL_SIZE + 1]; + sharedItems[0] = mInventory[SLOT_CIRCUIT]; + System.arraycopy(mInventory, SLOT_MANUAL_START, sharedItems, 1, SLOT_MANUAL_SIZE); + return ArrayExt.withoutNulls(sharedItems, ItemStack[]::new); + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + NBTTagCompound tag = accessor.getNBTData(); + if (tag.hasKey("name")) + currenttip.add(EnumChatFormatting.AQUA + tag.getString("name") + EnumChatFormatting.RESET); + if (tag.hasKey("inventory")) { + var inventory = tag.getTagList("inventory", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < inventory.tagCount(); ++i) { + var item = inventory.getCompoundTagAt(i); + var name = item.getString("name"); + var amount = item.getLong("amount"); + currenttip.add( + name + ": " + + EnumChatFormatting.GOLD + + ReadableNumberConverter.INSTANCE.toWideReadableForm(amount) + + EnumChatFormatting.RESET); + } + } + super.getWailaBody(itemStack, currenttip, accessor, config); + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + + NBTTagList inventory = new NBTTagList(); + HashMap<String, Long> nameToAmount = new HashMap<>(); + for (Iterator<PatternSlot> it = inventories(); it.hasNext();) { + var i = it.next(); + for (var item : i.itemInventory) { + if (item != null && item.stackSize > 0) { + var name = item.getDisplayName(); + var amount = nameToAmount.getOrDefault(name, 0L); + nameToAmount.put(name, amount + item.stackSize); + } + } + for (var fluid : i.fluidInventory) { + if (fluid != null && fluid.amount > 0) { + var name = fluid.getLocalizedName(); + var amount = nameToAmount.getOrDefault(name, 0L); + nameToAmount.put(name, amount + fluid.amount); + } + } + } + for (var entry : nameToAmount.entrySet()) { + var item = new NBTTagCompound(); + item.setString("name", entry.getKey()); + item.setLong("amount", entry.getValue()); + inventory.appendTag(item); + } + + tag.setTag("inventory", inventory); + if (!Objects.equals(getName(), getLocalName())) { + tag.setString("name", getName()); + } + super.getWailaNBTData(player, tile, tag, world, x, y, z); + } + + @Override + public void provideCrafting(ICraftingProviderHelper craftingTracker) { + if (!isActive()) return; + + for (PatternSlot slot : internalInventory) { + if (slot == null) continue; + ICraftingPatternDetails details = slot.getPatternDetails(); + if (details == null) { + GT_Mod.GT_FML_LOGGER.warn( + "Found an invalid pattern at " + getBaseMetaTileEntity().getCoords() + + " in dim " + + getBaseMetaTileEntity().getWorld().provider.dimensionId); + continue; + } + craftingTracker.addCraftingOption(this, details); + } + } + + @Override + public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table) { + if (!isActive()) return false; + + if (!supportFluids) { + for (int i = 0; i < table.getSizeInventory(); ++i) { + ItemStack itemStack = table.getStackInSlot(i); + if (itemStack == null) continue; + if (itemStack.getItem() instanceof ItemFluidPacket) return false; + } + } + if (!patternDetailsPatternSlotMap.get(patternDetails) + .insertItemsAndFluids(table)) { + return false; + } + justHadNewItems = true; + return true; + } + + @Override + public boolean isBusy() { + return false; + } + + @Override + public Iterator<PatternSlot> inventories() { + return Arrays.stream(internalInventory) + .filter(Objects::nonNull) + .iterator(); + } + + @Override + public void onBlockDestroyed() { + refundAll(); + super.onBlockDestroyed(); + } + + private void refundAll() { + for (var slot : internalInventory) { + if (slot == null) continue; + try { + slot.refund(getProxy(), getRequest()); + } catch (GridAccessException ignored) {} + } + } + + @Override + public boolean justUpdated() { + var ret = justHadNewItems; + justHadNewItems = false; + return ret; + } + + @Override + public void onLeftclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (!(aPlayer instanceof EntityPlayerMP)) return; + + ItemStack dataStick = aPlayer.inventory.getCurrentItem(); + if (!ItemList.Tool_DataStick.isStackEqual(dataStick, false, true)) return; + + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("type", "CraftingInputBuffer"); + tag.setInteger("x", aBaseMetaTileEntity.getXCoord()); + tag.setInteger("y", aBaseMetaTileEntity.getYCoord()); + tag.setInteger("z", aBaseMetaTileEntity.getZCoord()); + + dataStick.stackTagCompound = tag; + dataStick.setStackDisplayName( + "Crafting Input Buffer Link Data Stick (" + aBaseMetaTileEntity + .getXCoord() + ", " + aBaseMetaTileEntity.getYCoord() + ", " + aBaseMetaTileEntity.getZCoord() + ")"); + aPlayer.addChatMessage(new ChatComponentText("Saved Link Data to Data Stick")); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side, + float aX, float aY, float aZ) { + final ItemStack is = aPlayer.inventory.getCurrentItem(); + if (is != null && is.getItem() instanceof ToolQuartzCuttingKnife) { + if (ForgeEventFactory.onItemUseStart(aPlayer, is, 1) <= 0) return false; + var te = getBaseMetaTileEntity(); + aPlayer.openGui( + AppEng.instance(), + GuiBridge.GUI_RENAMER.ordinal() << 5 | (side.ordinal()), + te.getWorld(), + te.getXCoord(), + te.getYCoord(), + te.getZCoord()); + return true; + } + return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ); + } + + @Override + public ItemStack getCrafterIcon() { + return getMachineCraftingIcon(); + } + + private boolean postMEPatternChange() { + // don't post until it's active + if (!getProxy().isActive()) return false; + try { + getProxy().getGrid() + .postEvent(new MENetworkCraftingPatternChange(this, getProxy().getNode())); + } catch (GridAccessException ignored) { + return false; + } + return true; + } + + protected ModularWindow createSlotManualWindow(final EntityPlayer player) { + final int WIDTH = 68; + final int HEIGHT = 68; + final int PARENT_WIDTH = getGUIWidth(); + final int PARENT_HEIGHT = getGUIHeight(); + ModularWindow.Builder builder = ModularWindow.builder(WIDTH, HEIGHT); + builder.setBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); + builder.setGuiTint(getGUIColorization()); + builder.setDraggable(true); + // make sure the manual window is within the parent window + // otherwise picking up manual items would toss them + // See GuiContainer.java flag1 + builder.setPos( + (size, window) -> Alignment.Center.getAlignedPos(size, new Size(PARENT_WIDTH, PARENT_HEIGHT)) + .add(Alignment.TopRight.getAlignedPos(new Size(PARENT_WIDTH, PARENT_HEIGHT), new Size(WIDTH, HEIGHT)))); + builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 3) + .startFromSlot(SLOT_MANUAL_START) + .endAtSlot(SLOT_MANUAL_START + SLOT_MANUAL_SIZE - 1) + .phantom(false) + .background(getGUITextureSet().getItemSlot()) + .build() + .setPos(7, 7)); + return builder.build(); + } + + @Override + public void setInventorySlotContents(int aIndex, ItemStack aStack) { + super.setInventorySlotContents(aIndex, aStack); + if (aIndex >= MAX_PATTERN_COUNT) return; + onPatternChange(aIndex, aStack); + needPatternSync = true; + } + + @Override + public String getCustomName() { + return customName; + } + + @Override + public boolean hasCustomName() { + return customName != null; + } + + @Override + public void setCustomName(String name) { + customName = name; + } + + @Override + public Optional<IDualInputInventory> getFirstNonEmptyInventory() { + for (PatternSlot slot : internalInventory) { + if (slot != null && !slot.isEmpty()) return Optional.of(slot); + } + return Optional.empty(); + } + + @Override + public boolean supportsFluids() { + return this.supportFluids; + } + + @Override + public List<ItemStack> getItemsForHoloGlasses() { + List<ItemStack> list = new ArrayList<>(); + for (PatternSlot slot : internalInventory) { + if (slot == null) continue; + + IAEItemStack[] outputs = slot.getPatternDetails() + .getCondensedOutputs(); + list.add(outputs[0].getItemStack()); + } + return list; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_CraftingInput_Slave.java b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_CraftingInput_Slave.java new file mode 100644 index 0000000000..ee53e9494a --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_CraftingInput_Slave.java @@ -0,0 +1,262 @@ +package gregtech.common.tileentities.machines; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_CRAFTING_INPUT_SLAVE; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.ItemList; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; +import gregtech.api.render.TextureFactory; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaTileEntity_Hatch_CraftingInput_Slave extends GT_MetaTileEntity_Hatch_InputBus + implements IDualInputHatch { + + private GT_MetaTileEntity_Hatch_CraftingInput_ME master; // use getMaster() to access + private int masterX, masterY, masterZ; + private boolean masterSet = false; // indicate if values of masterX, masterY, masterZ are valid + + public GT_MetaTileEntity_Hatch_CraftingInput_Slave(int aID, String aName, String aNameRegional) { + super( + aID, + aName, + aNameRegional, + 6, + 0, + new String[] { "Slave for Crafting Input Buffer/Bus", + "Link with Crafting Input Buffer/Bus using Data Stick to share inventory", + "Left click on the Crafting Input Buffer/Bus, then right click on this block to link them", }); + disableSort = true; + } + + public GT_MetaTileEntity_Hatch_CraftingInput_Slave(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, 0, aDescription, aTextures); + disableSort = true; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_CraftingInput_Slave(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return getTexturesInactive(aBaseTexture); + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_CRAFTING_INPUT_SLAVE) }; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + super.onPostTick(aBaseMetaTileEntity, aTimer); + if (aTimer % 100 == 0 && masterSet && getMaster() == null) { + trySetMasterFromCoord(masterX, masterY, masterZ); + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + + if (aNBT.hasKey("master")) { + NBTTagCompound masterNBT = aNBT.getCompoundTag("master"); + masterX = masterNBT.getInteger("x"); + masterY = masterNBT.getInteger("y"); + masterZ = masterNBT.getInteger("z"); + masterSet = true; + } + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + if (masterSet) { + NBTTagCompound masterNBT = new NBTTagCompound(); + masterNBT.setInteger("x", masterX); + masterNBT.setInteger("y", masterY); + masterNBT.setInteger("z", masterZ); + aNBT.setTag("master", masterNBT); + } + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public String[] getInfoData() { + var ret = new ArrayList<String>(); + if (getMaster() != null) { + ret.add( + "This bus is linked to the Crafting Input Buffer at " + masterX + + ", " + + masterY + + ", " + + masterZ + + "."); + ret.addAll(Arrays.asList(getMaster().getInfoData())); + } else ret.add("This bus is not linked to any Crafting Input Buffer."); + return ret.toArray(new String[0]); + } + + public GT_MetaTileEntity_Hatch_CraftingInput_ME getMaster() { + if (master == null) return null; + if (master.getBaseMetaTileEntity() == null) { // master disappeared + master = null; + } + return master; + } + + @Override + public byte getTierForStructure() { + return getMaster() == null ? super.getTierForStructure() : getMaster().getTierForStructure(); + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public Iterator<GT_MetaTileEntity_Hatch_CraftingInput_ME.PatternSlot> inventories() { + return getMaster() != null ? getMaster().inventories() : Collections.emptyIterator(); + } + + @Override + public Optional<IDualInputInventory> getFirstNonEmptyInventory() { + return getMaster() != null ? getMaster().getFirstNonEmptyInventory() : Optional.empty(); + } + + @Override + public boolean supportsFluids() { + return getMaster() != null && getMaster().supportsFluids(); + } + + @Override + public boolean justUpdated() { + return getMaster() != null && getMaster().justUpdated(); + } + + public GT_MetaTileEntity_Hatch_CraftingInput_ME trySetMasterFromCoord(int x, int y, int z) { + var tileEntity = getBaseMetaTileEntity().getWorld() + .getTileEntity(x, y, z); + if (tileEntity == null) return null; + if (!(tileEntity instanceof IGregTechTileEntity gtTileEntity)) return null; + var metaTileEntity = gtTileEntity.getMetaTileEntity(); + if (!(metaTileEntity instanceof GT_MetaTileEntity_Hatch_CraftingInput_ME)) return null; + masterX = x; + masterY = y; + masterZ = z; + masterSet = true; + master = (GT_MetaTileEntity_Hatch_CraftingInput_ME) metaTileEntity; + return master; + } + + private boolean tryLinkDataStick(EntityPlayer aPlayer) { + ItemStack dataStick = aPlayer.inventory.getCurrentItem(); + + if (!ItemList.Tool_DataStick.isStackEqual(dataStick, false, true)) { + return false; + } + if (!dataStick.hasTagCompound() || !dataStick.stackTagCompound.getString("type") + .equals("CraftingInputBuffer")) { + return false; + } + + NBTTagCompound nbt = dataStick.stackTagCompound; + int x = nbt.getInteger("x"); + int y = nbt.getInteger("y"); + int z = nbt.getInteger("z"); + if (trySetMasterFromCoord(x, y, z) != null) { + aPlayer.addChatMessage(new ChatComponentText("Link successful")); + return true; + } + aPlayer.addChatMessage(new ChatComponentText("Link failed")); + return true; + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (!(aPlayer instanceof EntityPlayerMP)) { + return false; + } + if (tryLinkDataStick(aPlayer)) { + return true; + } + var master = getMaster(); + if (master != null) { + return master.onRightclick(master.getBaseMetaTileEntity(), aPlayer); + } + return false; + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + NBTTagCompound tag = accessor.getNBTData(); + currenttip.add((tag.getBoolean("linked") ? "Linked" : "Not linked")); + + if (tag.hasKey("masterX")) { + currenttip.add( + "Bound to " + tag + .getInteger("masterX") + ", " + tag.getInteger("masterY") + ", " + tag.getInteger("masterZ")); + } + + if (tag.hasKey("masterName")) { + currenttip.add(EnumChatFormatting.GOLD + tag.getString("masterName") + EnumChatFormatting.RESET); + } + + super.getWailaBody(itemStack, currenttip, accessor, config); + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + + tag.setBoolean("linked", getMaster() != null); + if (masterSet) { + tag.setInteger("masterX", masterX); + tag.setInteger("masterY", masterY); + tag.setInteger("masterZ", masterZ); + } + if (getMaster() != null) tag.setString("masterName", getMaster().getName()); + + super.getWailaNBTData(player, tile, tag, world, x, y, z); + } + + @Override + public List<ItemStack> getItemsForHoloGlasses() { + return getMaster() != null ? getMaster().getItemsForHoloGlasses() : null; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_InputBus_ME.java b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_InputBus_ME.java new file mode 100644 index 0000000000..6b5ce10387 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_InputBus_ME.java @@ -0,0 +1,804 @@ +package gregtech.common.tileentities.machines; + +import static gregtech.api.enums.GT_Values.TIER_COLORS; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_INPUT_HATCH; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_INPUT_HATCH_ACTIVE; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.List; + +import javax.annotation.Nullable; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.ModularUITextures; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Color; +import com.gtnewhorizons.modularui.api.math.Size; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.internal.wrapper.BaseSlot; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.SlotGroup; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; +import com.gtnewhorizons.modularui.common.widget.textfield.NumericWidget; + +import appeng.api.config.Actionable; +import appeng.api.config.PowerMultiplier; +import appeng.api.implementations.IPowerChannelState; +import appeng.api.networking.GridFlags; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.IActionHost; +import appeng.api.networking.security.MachineSource; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.util.AECableType; +import appeng.core.localization.WailaText; +import appeng.me.GridAccessException; +import appeng.me.helpers.AENetworkProxy; +import appeng.me.helpers.IGridProxyable; +import appeng.util.item.AEItemStack; +import gregtech.api.enums.ItemList; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.IConfigurationCircuitSupport; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IAddGregtechLogo; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; +import gregtech.common.gui.modularui.widget.AESlotWidget; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaTileEntity_Hatch_InputBus_ME extends GT_MetaTileEntity_Hatch_InputBus implements + IConfigurationCircuitSupport, IRecipeProcessingAwareHatch, IAddGregtechLogo, IAddUIWidgets, IPowerChannelState { + + private static final int SLOT_COUNT = 16; + private BaseActionSource requestSource = null; + private @Nullable AENetworkProxy gridProxy = null; + private final ItemStack[] shadowInventory = new ItemStack[SLOT_COUNT]; + private final int[] savedStackSizes = new int[SLOT_COUNT]; + private boolean processingRecipe = false; + private final boolean autoPullAvailable; + private boolean autoPullItemList = false; + private int minAutoPullStackSize = 1; + private int autoPullRefreshTime = 100; + private static final int CONFIG_WINDOW_ID = 10; + private boolean additionalConnection = false; + + public GT_MetaTileEntity_Hatch_InputBus_ME(int aID, boolean autoPullAvailable, String aName, String aNameRegional) { + super( + aID, + aName, + aNameRegional, + autoPullAvailable ? 6 : 3, + SLOT_COUNT * 2 + 2, + getDescriptionArray(autoPullAvailable)); + this.autoPullAvailable = autoPullAvailable; + disableSort = true; + } + + public GT_MetaTileEntity_Hatch_InputBus_ME(String aName, boolean autoPullAvailable, int aTier, + String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, SLOT_COUNT * 2 + 2, aDescription, aTextures); + this.autoPullAvailable = autoPullAvailable; + disableSort = true; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_InputBus_ME(mName, autoPullAvailable, mTier, mDescriptionArray, mTextures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_INPUT_HATCH_ACTIVE) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_INPUT_HATCH) }; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + if (getBaseMetaTileEntity().isServerSide()) { + if (aTimer % autoPullRefreshTime == 0 && autoPullItemList) { + refreshItemList(); + } + if (aTimer % 20 == 0) { + getBaseMetaTileEntity().setActive(isActive()); + } + } + super.onPostTick(aBaseMetaTileEntity, aTimer); + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + getProxy().onReady(); + } + + @Override + public AECableType getCableConnectionType(ForgeDirection forgeDirection) { + return isOutputFacing(forgeDirection) ? AECableType.SMART : AECableType.NONE; + } + + private void updateValidGridProxySides() { + if (additionalConnection) { + getProxy().setValidSides(EnumSet.complementOf(EnumSet.of(ForgeDirection.UNKNOWN))); + } else { + getProxy().setValidSides(EnumSet.of(getBaseMetaTileEntity().getFrontFacing())); + } + } + + @Override + public void onFacingChange() { + updateValidGridProxySides(); + } + + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ) { + additionalConnection = !additionalConnection; + updateValidGridProxySides(); + aPlayer.addChatComponentMessage( + new ChatComponentTranslation("GT5U.hatch.additionalConnection." + additionalConnection)); + return true; + } + + @Override + public AENetworkProxy getProxy() { + if (gridProxy == null) { + if (getBaseMetaTileEntity() instanceof IGridProxyable) { + gridProxy = new AENetworkProxy( + (IGridProxyable) getBaseMetaTileEntity(), + "proxy", + autoPullAvailable ? ItemList.Hatch_Input_Bus_ME_Advanced.get(1) + : ItemList.Hatch_Input_Bus_ME.get(1), + true); + gridProxy.setFlags(GridFlags.REQUIRE_CHANNEL); + updateValidGridProxySides(); + if (getBaseMetaTileEntity().getWorld() != null) gridProxy.setOwner( + getBaseMetaTileEntity().getWorld() + .getPlayerEntityByName(getBaseMetaTileEntity().getOwnerName())); + } + } + return this.gridProxy; + } + + @Override + public boolean isPowered() { + return getProxy() != null && getProxy().isPowered(); + } + + @Override + public boolean isActive() { + return getProxy() != null && getProxy().isActive(); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + int[] sizes = new int[16]; + for (int i = 0; i < 16; ++i) sizes[i] = mInventory[i + 16] == null ? 0 : mInventory[i + 16].stackSize; + aNBT.setIntArray("sizes", sizes); + aNBT.setBoolean("autoStock", autoPullItemList); + aNBT.setInteger("minAutoPullStackSize", minAutoPullStackSize); + aNBT.setBoolean("additionalConnection", additionalConnection); + aNBT.setInteger("refreshTime", autoPullRefreshTime); + getProxy().writeToNBT(aNBT); + } + + private void setAutoPullItemList(boolean pullItemList) { + if (!autoPullAvailable) { + return; + } + + autoPullItemList = pullItemList; + if (!autoPullItemList) { + for (int i = 0; i < SLOT_COUNT; i++) { + mInventory[i] = null; + } + } else { + refreshItemList(); + } + updateAllInformationSlots(); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (aNBT.hasKey("sizes")) { + int[] sizes = aNBT.getIntArray("sizes"); + if (sizes.length == 16) { + for (int i = 0; i < 16; ++i) { + if (sizes[i] != 0 && mInventory[i] != null) { + ItemStack s = mInventory[i].copy(); + s.stackSize = sizes[i]; + mInventory[i + 16] = s; + } + } + } + } + autoPullItemList = aNBT.getBoolean("autoStock"); + minAutoPullStackSize = aNBT.getInteger("minAutoPullStackSize"); + additionalConnection = aNBT.getBoolean("additionalConnection"); + if (aNBT.hasKey("refreshTime")) { + autoPullRefreshTime = aNBT.getInteger("refreshTime"); + } + getProxy().readFromNBT(aNBT); + + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public String[] getInfoData() { + return new String[] { + "The bus is " + ((getProxy() != null && getProxy().isActive()) ? EnumChatFormatting.GREEN + "online" + : EnumChatFormatting.RED + "offline" + getAEDiagnostics()) + EnumChatFormatting.RESET }; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (!autoPullAvailable) { + return; + } + + setAutoPullItemList(!autoPullItemList); + aPlayer.addChatMessage( + new ChatComponentTranslation( + "GT5U.machines.stocking_bus.auto_pull_toggle." + (autoPullItemList ? "enabled" : "disabled"))); + } + + @Override + public void updateSlots() { + if (mInventory[getManualSlot()] != null && mInventory[getManualSlot()].stackSize <= 0) + mInventory[getManualSlot()] = null; + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side, + float aX, float aY, float aZ) { + if (!(aPlayer instanceof EntityPlayerMP)) + return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ); + ItemStack dataStick = aPlayer.inventory.getCurrentItem(); + if (!ItemList.Tool_DataStick.isStackEqual(dataStick, false, true)) + return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ); + if (!dataStick.hasTagCompound() || !"stockingBus".equals(dataStick.stackTagCompound.getString("type"))) + return false; + + NBTTagCompound nbt = dataStick.stackTagCompound; + + ItemStack circuit = GT_Utility.loadItem(dataStick.stackTagCompound, "circuit"); + if (GT_Utility.isStackInvalid(circuit)) circuit = null; + + if (autoPullAvailable) { + setAutoPullItemList(nbt.getBoolean("autoPull")); + minAutoPullStackSize = nbt.getInteger("minStackSize"); + autoPullRefreshTime = nbt.getInteger("refreshTime"); + } + + additionalConnection = nbt.getBoolean("additionalConnection"); + if (!autoPullItemList) { + NBTTagList stockingItems = nbt.getTagList("itemsToStock", 10); + for (int i = 0; i < stockingItems.tagCount(); i++) { + this.mInventory[i] = GT_Utility.loadItem(stockingItems.getCompoundTagAt(i)); + } + } + setInventorySlotContents(getCircuitSlot(), circuit); + updateValidGridProxySides(); + aPlayer.addChatMessage(new ChatComponentTranslation("GT5U.machines.stocking_bus.loaded")); + return true; + } + + @Override + public void onLeftclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (!(aPlayer instanceof EntityPlayerMP)) return; + + ItemStack dataStick = aPlayer.inventory.getCurrentItem(); + if (!ItemList.Tool_DataStick.isStackEqual(dataStick, false, true)) return; + + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("type", "stockingBus"); + tag.setBoolean("autoPull", autoPullItemList); + tag.setInteger("minStackSize", minAutoPullStackSize); + tag.setInteger("refreshTime", autoPullRefreshTime); + tag.setBoolean("additionalConnection", additionalConnection); + tag.setTag("circuit", GT_Utility.saveItem(getStackInSlot(getCircuitSlot()))); + + NBTTagList stockingItems = new NBTTagList(); + + if (!autoPullItemList) { + for (int index = 0; index < SLOT_COUNT; index++) { + stockingItems.appendTag(GT_Utility.saveItem(mInventory[index])); + } + tag.setTag("itemsToStock", stockingItems); + } + dataStick.stackTagCompound = tag; + dataStick.setStackDisplayName("Stocking Input Bus Configuration"); + aPlayer.addChatMessage(new ChatComponentTranslation("GT5U.machines.stocking_bus.saved")); + } + + private int getManualSlot() { + return SLOT_COUNT * 2 + 1; + } + + @Override + public int getCircuitSlot() { + return SLOT_COUNT * 2; + } + + @Override + public int getCircuitSlotX() { + return 80; + } + + @Override + public int getCircuitSlotY() { + return 64; + } + + @Override + public boolean setStackToZeroInsteadOfNull(int aIndex) { + return aIndex != getManualSlot(); + } + + @Override + public ItemStack getStackInSlot(int aIndex) { + if (!processingRecipe) return super.getStackInSlot(aIndex); + if (aIndex < 0 || aIndex > mInventory.length) return null; + if (aIndex >= SLOT_COUNT && aIndex < SLOT_COUNT * 2) + // Display slots + return null; + if (aIndex == getCircuitSlot() || aIndex == getManualSlot()) return mInventory[aIndex]; + if (mInventory[aIndex] != null) { + AENetworkProxy proxy = getProxy(); + if (proxy == null || !proxy.isActive()) { + return null; + } + try { + IMEMonitor<IAEItemStack> sg = proxy.getStorage() + .getItemInventory(); + IAEItemStack request = AEItemStack.create(mInventory[aIndex]); + request.setStackSize(Integer.MAX_VALUE); + IAEItemStack result = sg.extractItems(request, Actionable.SIMULATE, getRequestSource()); + if (result != null) { + this.shadowInventory[aIndex] = result.getItemStack(); + this.savedStackSizes[aIndex] = this.shadowInventory[aIndex].stackSize; + this.setInventorySlotContents(aIndex + SLOT_COUNT, this.shadowInventory[aIndex]); + return this.shadowInventory[aIndex]; + } else { + // Request failed + this.setInventorySlotContents(aIndex + SLOT_COUNT, null); + return null; + } + } catch (final GridAccessException ignored) {} + return null; + } else { + // AE available but no items requested + this.setInventorySlotContents(aIndex + SLOT_COUNT, null); + } + return mInventory[aIndex]; + } + + private BaseActionSource getRequestSource() { + if (requestSource == null) requestSource = new MachineSource((IActionHost) getBaseMetaTileEntity()); + return requestSource; + } + + @Override + public void onExplosion() { + for (int i = 0; i < SLOT_COUNT; i++) { + mInventory[i] = null; + } + } + + @Override + public void startRecipeProcessing() { + processingRecipe = true; + updateAllInformationSlots(); + } + + private void refreshItemList() { + AENetworkProxy proxy = getProxy(); + try { + IMEMonitor<IAEItemStack> sg = proxy.getStorage() + .getItemInventory(); + Iterator<IAEItemStack> iterator = sg.getStorageList() + .iterator(); + int index = 0; + while (iterator.hasNext() && index < SLOT_COUNT) { + IAEItemStack currItem = iterator.next(); + if (currItem.getStackSize() >= minAutoPullStackSize) { + ItemStack itemstack = GT_Utility.copyAmount(1, currItem.getItemStack()); + this.mInventory[index] = itemstack; + index++; + } + } + for (int i = index; i < SLOT_COUNT; i++) { + mInventory[i] = null; + } + + } catch (final GridAccessException ignored) {} + } + + private void updateAllInformationSlots() { + for (int index = 0; index < SLOT_COUNT; index++) { + updateInformationSlot(index, mInventory[index]); + } + } + + @Override + public CheckRecipeResult endRecipeProcessing(GT_MetaTileEntity_MultiBlockBase controller) { + CheckRecipeResult checkRecipeResult = CheckRecipeResultRegistry.SUCCESSFUL; + for (int i = 0; i < SLOT_COUNT; ++i) { + if (savedStackSizes[i] != 0) { + ItemStack oldStack = shadowInventory[i]; + if (oldStack == null || oldStack.stackSize < savedStackSizes[i]) { + AENetworkProxy proxy = getProxy(); + try { + IMEMonitor<IAEItemStack> sg = proxy.getStorage() + .getItemInventory(); + IAEItemStack request = AEItemStack.create(mInventory[i]); + int toExtract = savedStackSizes[i] - (oldStack == null ? 0 : oldStack.stackSize); + request.setStackSize(toExtract); + IAEItemStack result = sg.extractItems(request, Actionable.MODULATE, getRequestSource()); + proxy.getEnergy() + .extractAEPower(request.getStackSize(), Actionable.MODULATE, PowerMultiplier.CONFIG); + setInventorySlotContents(i + SLOT_COUNT, oldStack); + if (result == null || result.getStackSize() != toExtract) { + controller.stopMachine(ShutDownReasonRegistry.CRITICAL_NONE); + checkRecipeResult = SimpleCheckRecipeResult + .ofFailurePersistOnShutdown("stocking_bus_fail_extraction"); + } + } catch (final GridAccessException ignored) { + controller.stopMachine(ShutDownReasonRegistry.CRITICAL_NONE); + checkRecipeResult = SimpleCheckRecipeResult + .ofFailurePersistOnShutdown("stocking_hatch_fail_extraction"); + } + } + savedStackSizes[i] = 0; + shadowInventory[i] = null; + if (mInventory[i + SLOT_COUNT] != null && mInventory[i + SLOT_COUNT].stackSize <= 0) { + mInventory[i + SLOT_COUNT] = null; + } + } + } + processingRecipe = false; + return checkRecipeResult; + } + + public ItemStack updateInformationSlot(int aIndex, ItemStack aStack) { + if (aIndex >= 0 && aIndex < SLOT_COUNT) { + if (aStack == null) { + super.setInventorySlotContents(aIndex + SLOT_COUNT, null); + } else { + AENetworkProxy proxy = getProxy(); + if (!proxy.isActive()) { + super.setInventorySlotContents(aIndex + SLOT_COUNT, null); + return null; + } + try { + IMEMonitor<IAEItemStack> sg = proxy.getStorage() + .getItemInventory(); + IAEItemStack request = AEItemStack.create(mInventory[aIndex]); + request.setStackSize(Integer.MAX_VALUE); + IAEItemStack result = sg.extractItems(request, Actionable.SIMULATE, getRequestSource()); + ItemStack s = (result != null) ? result.getItemStack() : null; + setInventorySlotContents(aIndex + SLOT_COUNT, s); + return s; + } catch (final GridAccessException ignored) {} + } + } + return null; + } + + /** + * Used to avoid slot update. + */ + public ItemStack getShadowItemStack(int index) { + if (index < 0 || index >= shadowInventory.length) { + return null; + } + return shadowInventory[index]; + } + + @Override + public boolean isValidSlot(int aIndex) { + return aIndex == getManualSlot(); + } + + @Override + public int getGUIHeight() { + return 179; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + final SlotWidget[] aeSlotWidgets = new SlotWidget[16]; + + if (autoPullAvailable) { + buildContext.addSyncedWindow(CONFIG_WINDOW_ID, this::createStackSizeConfigurationWindow); + } + + builder.widget( + SlotGroup.ofItemHandler(inventoryHandler, 4) + .startFromSlot(0) + .endAtSlot(15) + .phantom(true) + .slotCreator(index -> new BaseSlot(inventoryHandler, index, true) { + + @Override + public boolean isEnabled() { + return !autoPullItemList && super.isEnabled(); + } + }) + .widgetCreator(slot -> (SlotWidget) new SlotWidget(slot) { + + @Override + protected void phantomClick(ClickData clickData, ItemStack cursorStack) { + if (clickData.mouseButton != 0 || !getMcSlot().isEnabled()) return; + final int aSlotIndex = getMcSlot().getSlotIndex(); + if (cursorStack == null) { + getMcSlot().putStack(null); + } else { + if (containsSuchStack(cursorStack)) return; + getMcSlot().putStack(GT_Utility.copyAmount(1, cursorStack)); + } + if (getBaseMetaTileEntity().isServerSide()) { + final ItemStack newInfo = updateInformationSlot(aSlotIndex, cursorStack); + aeSlotWidgets[getMcSlot().getSlotIndex()].getMcSlot() + .putStack(newInfo); + } + } + + @Override + public IDrawable[] getBackground() { + IDrawable slot; + if (autoPullItemList) { + slot = GT_UITextures.SLOT_DARK_GRAY; + } else { + slot = ModularUITextures.ITEM_SLOT; + } + return new IDrawable[] { slot, GT_UITextures.OVERLAY_SLOT_ARROW_ME }; + } + + @Override + public List<String> getExtraTooltip() { + if (autoPullItemList) { + return Collections.singletonList( + StatCollector.translateToLocal("GT5U.machines.stocking_bus.cannot_set_slot")); + } else { + return Collections + .singletonList(StatCollector.translateToLocal("modularui.phantom.single.clear")); + } + } + + private boolean containsSuchStack(ItemStack tStack) { + for (int i = 0; i < 16; ++i) { + if (GT_Utility.areStacksEqual(mInventory[i], tStack, false)) return true; + } + return false; + } + }.dynamicTooltip(() -> { + if (autoPullItemList) { + return Collections.singletonList( + StatCollector.translateToLocal("GT5U.machines.stocking_bus.cannot_set_slot")); + } else { + return Collections.emptyList(); + } + }) + .setUpdateTooltipEveryTick(true)) + .build() + .setPos(7, 9)) + .widget( + SlotGroup.ofItemHandler(inventoryHandler, 4) + .startFromSlot(16) + .endAtSlot(31) + .phantom(true) + .background(GT_UITextures.SLOT_DARK_GRAY) + .widgetCreator( + slot -> aeSlotWidgets[slot.getSlotIndex() - 16] = new AESlotWidget(slot).disableInteraction()) + .build() + .setPos(97, 9)) + .widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_ARROW_DOUBLE) + .setPos(82, 30) + .setSize(12, 12)); + + if (autoPullAvailable) { + builder.widget(new ButtonWidget().setOnClick((clickData, widget) -> { + if (clickData.mouseButton == 0) { + setAutoPullItemList(!autoPullItemList); + } else if (clickData.mouseButton == 1 && !widget.isClient()) { + widget.getContext() + .openSyncedWindow(CONFIG_WINDOW_ID); + } + }) + .setBackground(() -> { + if (autoPullItemList) { + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD_PRESSED, + GT_UITextures.OVERLAY_BUTTON_AUTOPULL_ME }; + } else { + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD, + GT_UITextures.OVERLAY_BUTTON_AUTOPULL_ME_DISABLED }; + } + }) + .addTooltips( + Arrays.asList( + StatCollector.translateToLocal("GT5U.machines.stocking_bus.auto_pull.tooltip.1"), + StatCollector.translateToLocal("GT5U.machines.stocking_bus.auto_pull.tooltip.2"))) + .setSize(16, 16) + .setPos(80, 10)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> autoPullItemList, this::setAutoPullItemList)); + } + + builder.widget(TextWidget.dynamicString(() -> { + boolean isActive = isActive(); + boolean isPowered = isPowered(); + boolean isBooting = isBooting(); + EnumChatFormatting color = (isActive && isPowered) ? EnumChatFormatting.GREEN : EnumChatFormatting.DARK_RED; + return color + WailaText.getPowerState(isActive, isPowered, isBooting); + }) + .setTextAlignment(Alignment.Center) + .setSize(90, 9) + .setPos(43, 84)) + .widget( + new SlotWidget(inventoryHandler, getManualSlot()) + // ghost slots are prioritized over manual slot + .setShiftClickPriority(11) + .setPos(79, 45)); + } + + protected ModularWindow createStackSizeConfigurationWindow(final EntityPlayer player) { + final int WIDTH = 78; + final int HEIGHT = 80; + final int PARENT_WIDTH = getGUIWidth(); + final int PARENT_HEIGHT = getGUIHeight(); + ModularWindow.Builder builder = ModularWindow.builder(WIDTH, HEIGHT); + builder.setBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); + builder.setGuiTint(getGUIColorization()); + builder.setDraggable(true); + builder.setPos( + (size, window) -> Alignment.Center.getAlignedPos(size, new Size(PARENT_WIDTH, PARENT_HEIGHT)) + .add( + Alignment.TopRight.getAlignedPos(new Size(PARENT_WIDTH, PARENT_HEIGHT), new Size(WIDTH, HEIGHT)) + .add(WIDTH - 3, 0))); + builder.widget( + TextWidget.localised("GT5U.machines.stocking_bus.min_stack_size") + .setPos(3, 2) + .setSize(74, 14)) + .widget( + new NumericWidget().setSetter(val -> minAutoPullStackSize = (int) val) + .setGetter(() -> minAutoPullStackSize) + .setBounds(1, Integer.MAX_VALUE) + .setScrollValues(1, 4, 64) + .setTextAlignment(Alignment.Center) + .setTextColor(Color.WHITE.normal) + .setSize(70, 18) + .setPos(3, 18) + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD)); + builder.widget( + TextWidget.localised("GT5U.machines.stocking_bus.refresh_time") + .setPos(3, 42) + .setSize(74, 14)) + .widget( + new NumericWidget().setSetter(val -> autoPullRefreshTime = (int) val) + .setGetter(() -> autoPullRefreshTime) + .setBounds(1, Integer.MAX_VALUE) + .setScrollValues(1, 4, 64) + .setTextAlignment(Alignment.Center) + .setTextColor(Color.WHITE.normal) + .setSize(70, 18) + .setPos(3, 58) + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD)); + return builder.build(); + } + + @Override + public void addGregTechLogo(ModularWindow.Builder builder) { + builder.widget( + new DrawableWidget().setDrawable(getGUITextureSet().getGregTechLogo()) + .setSize(17, 17) + .setPos(80, 63)); + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + if (!autoPullAvailable) { + super.getWailaBody(itemStack, currenttip, accessor, config); + return; + } + + NBTTagCompound tag = accessor.getNBTData(); + boolean autopull = tag.getBoolean("autoPull"); + int minSize = tag.getInteger("minStackSize"); + currenttip.add( + StatCollector.translateToLocal("GT5U.waila.stocking_bus.auto_pull." + (autopull ? "enabled" : "disabled"))); + if (autopull) { + currenttip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.stocking_bus.min_stack_size", + GT_Utility.formatNumbers(minSize))); + } + super.getWailaBody(itemStack, currenttip, accessor, config); + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + if (!autoPullAvailable) { + super.getWailaNBTData(player, tile, tag, world, x, y, z); + return; + } + + tag.setBoolean("autoPull", autoPullItemList); + tag.setInteger("minStackSize", minAutoPullStackSize); + super.getWailaNBTData(player, tile, tag, world, x, y, z); + } + + private static String[] getDescriptionArray(boolean autoPullAvailable) { + List<String> strings = new ArrayList<>(8); + strings.add("Advanced item input for Multiblocks"); + strings.add("Hatch Tier: " + TIER_COLORS[autoPullAvailable ? 6 : 3] + VN[autoPullAvailable ? 6 : 3]); + strings.add("Retrieves directly from ME"); + strings.add("Keeps 16 item types in stock"); + + if (autoPullAvailable) { + strings.add( + "Auto-Pull from ME mode will automatically stock the first 16 items in the ME system, updated every 5 seconds."); + strings.add("Toggle by right-clicking with screwdriver, or use the GUI."); + strings + .add("Use the GUI to limit the minimum stack size for Auto-Pulling and adjust the slot refresh timer."); + } + + strings.add("Change ME connection behavior by right-clicking with wire cutter."); + strings.add("Configuration data can be copy+pasted using a data stick."); + return strings.toArray(new String[0]); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_Input_ME.java b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_Input_ME.java new file mode 100644 index 0000000000..18d4d669d1 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_Input_ME.java @@ -0,0 +1,884 @@ +package gregtech.common.tileentities.machines; + +import static gregtech.api.enums.GT_Values.TIER_COLORS; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_INPUT_FLUID_HATCH; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_INPUT_FLUID_HATCH_ACTIVE; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import javax.annotation.Nullable; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import com.gtnewhorizons.modularui.api.ModularUITextures; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.drawable.Text; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Color; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.math.Size; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.api.widget.Interactable; +import com.gtnewhorizons.modularui.common.fluid.FluidStackTank; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.FluidSlotWidget; +import com.gtnewhorizons.modularui.common.widget.SlotGroup; +import com.gtnewhorizons.modularui.common.widget.TextWidget; +import com.gtnewhorizons.modularui.common.widget.textfield.NumericWidget; + +import appeng.api.config.Actionable; +import appeng.api.config.PowerMultiplier; +import appeng.api.implementations.IPowerChannelState; +import appeng.api.networking.GridFlags; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.IActionHost; +import appeng.api.networking.security.MachineSource; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.util.AECableType; +import appeng.core.localization.WailaText; +import appeng.me.GridAccessException; +import appeng.me.helpers.AENetworkProxy; +import appeng.me.helpers.IGridProxyable; +import appeng.util.item.AEFluidStack; +import gregtech.api.enums.ItemList; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IAddGregtechLogo; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaTileEntity_Hatch_Input_ME extends GT_MetaTileEntity_Hatch_Input + implements IPowerChannelState, IAddGregtechLogo, IAddUIWidgets, IRecipeProcessingAwareHatch { + + private static final int SLOT_COUNT = 16; + + protected final FluidStack[] storedFluids = new FluidStack[SLOT_COUNT]; + protected final FluidStack[] storedInformationFluids = new FluidStack[SLOT_COUNT]; + + // these two fields should ALWAYS be mutated simultaneously + // in most cases, you should call setSavedFluid() instead of trying to write to the array directly + // a desync of these two fields can lead to catastrophe + protected final FluidStack[] shadowStoredFluids = new FluidStack[SLOT_COUNT]; + private final int[] savedStackSizes = new int[SLOT_COUNT]; + + private boolean additionalConnection = false; + + protected BaseActionSource requestSource = null; + + @Nullable + protected AENetworkProxy gridProxy = null; + + private final boolean autoPullAvailable; + protected boolean autoPullFluidList = false; + protected int minAutoPullAmount = 1; + private int autoPullRefreshTime = 100; + protected boolean processingRecipe = false; + + protected static final int CONFIG_WINDOW_ID = 10; + + protected static final FluidStack[] EMPTY_FLUID_STACK = new FluidStack[0]; + + public GT_MetaTileEntity_Hatch_Input_ME(int aID, boolean autoPullAvailable, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, autoPullAvailable ? 10 : 8, 1, getDescriptionArray(autoPullAvailable)); + this.autoPullAvailable = autoPullAvailable; + } + + public GT_MetaTileEntity_Hatch_Input_ME(String aName, boolean autoPullAvailable, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, 1, aTier, aDescription, aTextures); + this.autoPullAvailable = autoPullAvailable; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_Input_ME(mName, autoPullAvailable, mTier, mDescriptionArray, mTextures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_INPUT_FLUID_HATCH_ACTIVE) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_INPUT_FLUID_HATCH) }; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + if (getBaseMetaTileEntity().isServerSide()) { + if (aTimer % autoPullRefreshTime == 0 && autoPullFluidList) { + refreshFluidList(); + } + if (aTimer % 20 == 0) { + getBaseMetaTileEntity().setActive(isActive()); + } + } + super.onPostTick(aBaseMetaTileEntity, aTimer); + } + + private void refreshFluidList() { + AENetworkProxy proxy = getProxy(); + if (proxy == null || !proxy.isActive()) { + return; + } + + try { + IMEMonitor<IAEFluidStack> sg = proxy.getStorage() + .getFluidInventory(); + Iterator<IAEFluidStack> iterator = sg.getStorageList() + .iterator(); + + int index = 0; + while (iterator.hasNext() && index < SLOT_COUNT) { + IAEFluidStack currItem = iterator.next(); + if (currItem.getStackSize() >= minAutoPullAmount) { + FluidStack fluidStack = GT_Utility.copyAmount(1, currItem.getFluidStack()); + storedFluids[index] = fluidStack; + index++; + } + } + + for (int i = index; i < SLOT_COUNT; i++) { + storedFluids[i] = null; + } + } catch (final GridAccessException ignored) {} + } + + @Override + public boolean displaysStackSize() { + return true; + } + + protected void setSavedFluid(int i, FluidStack stack) { + shadowStoredFluids[i] = stack; + savedStackSizes[i] = stack == null ? 0 : stack.amount; + } + + public FluidStack[] getStoredFluids() { + if (!processingRecipe) { + return EMPTY_FLUID_STACK; + } + + AENetworkProxy proxy = getProxy(); + if (proxy == null || !proxy.isActive()) { + return EMPTY_FLUID_STACK; + } + + updateAllInformationSlots(); + + for (int i = 0; i < SLOT_COUNT; i++) { + if (storedFluids[i] == null) { + setSavedFluid(i, null); + continue; + } + + FluidStack fluidStackWithAmount = storedInformationFluids[i]; + // Nothing in stock, no need to save anything + if (fluidStackWithAmount == null) continue; + + setSavedFluid(i, fluidStackWithAmount); + } + + return shadowStoredFluids; + } + + @Override + public FluidStack drain(ForgeDirection side, FluidStack aFluid, boolean doDrain) { + // this is an ME input hatch. allowing draining via logistics would be very wrong (and against + // canTankBeEmptied()) but we do need to support draining from controller, which uses the UNKNOWN direction. + if (side != ForgeDirection.UNKNOWN) return null; + FluidStack stored = getMatchingFluidStack(aFluid); + if (stored == null) return null; + FluidStack drained = GT_Utility.copyAmount(Math.min(stored.amount, aFluid.amount), stored); + if (doDrain) { + stored.amount -= drained.amount; + } + return drained; + } + + @Override + public void startRecipeProcessing() { + processingRecipe = true; + updateAllInformationSlots(); + } + + @Override + public CheckRecipeResult endRecipeProcessing(GT_MetaTileEntity_MultiBlockBase controller) { + CheckRecipeResult checkRecipeResult = CheckRecipeResultRegistry.SUCCESSFUL; + AENetworkProxy proxy = getProxy(); + + for (int i = 0; i < SLOT_COUNT; ++i) { + FluidStack oldStack = shadowStoredFluids[i]; + int toExtract = savedStackSizes[i] - (oldStack != null ? oldStack.amount : 0); + if (toExtract <= 0) continue; + + try { + IMEMonitor<IAEFluidStack> sg = proxy.getStorage() + .getFluidInventory(); + + IAEFluidStack request = AEFluidStack.create(storedFluids[i]); + request.setStackSize(toExtract); + IAEFluidStack extractionResult = sg.extractItems(request, Actionable.MODULATE, getRequestSource()); + proxy.getEnergy() + .extractAEPower(toExtract, Actionable.MODULATE, PowerMultiplier.CONFIG); + + if (extractionResult == null || extractionResult.getStackSize() != toExtract) { + controller.stopMachine(ShutDownReasonRegistry.CRITICAL_NONE); + checkRecipeResult = SimpleCheckRecipeResult + .ofFailurePersistOnShutdown("stocking_hatch_fail_extraction"); + } + } catch (GridAccessException ignored) { + controller.stopMachine(ShutDownReasonRegistry.CRITICAL_NONE); + checkRecipeResult = SimpleCheckRecipeResult + .ofFailurePersistOnShutdown("stocking_hatch_fail_extraction"); + } + setSavedFluid(i, null); + if (storedInformationFluids[i] != null && storedInformationFluids[i].amount <= 0) { + storedInformationFluids[i] = null; + } + } + + processingRecipe = false; + return checkRecipeResult; + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + getProxy().onReady(); + } + + @Override + public AECableType getCableConnectionType(ForgeDirection forgeDirection) { + return isOutputFacing(forgeDirection) ? AECableType.SMART : AECableType.NONE; + } + + private void updateValidGridProxySides() { + if (additionalConnection) { + getProxy().setValidSides(EnumSet.complementOf(EnumSet.of(ForgeDirection.UNKNOWN))); + } else { + getProxy().setValidSides(EnumSet.of(getBaseMetaTileEntity().getFrontFacing())); + } + } + + @Override + public void onFacingChange() { + updateValidGridProxySides(); + } + + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ) { + additionalConnection = !additionalConnection; + updateValidGridProxySides(); + aPlayer.addChatComponentMessage( + new ChatComponentTranslation("GT5U.hatch.additionalConnection." + additionalConnection)); + return true; + } + + @Override + public AENetworkProxy getProxy() { + if (gridProxy == null) { + if (getBaseMetaTileEntity() instanceof IGridProxyable) { + gridProxy = new AENetworkProxy( + (IGridProxyable) getBaseMetaTileEntity(), + "proxy", + autoPullAvailable ? ItemList.Hatch_Input_ME_Advanced.get(1) : ItemList.Hatch_Input_ME.get(1), + true); + gridProxy.setFlags(GridFlags.REQUIRE_CHANNEL); + updateValidGridProxySides(); + if (getBaseMetaTileEntity().getWorld() != null) gridProxy.setOwner( + getBaseMetaTileEntity().getWorld() + .getPlayerEntityByName(getBaseMetaTileEntity().getOwnerName())); + } + } + return this.gridProxy; + } + + @Override + public boolean isPowered() { + return getProxy() != null && getProxy().isPowered(); + } + + @Override + public boolean isActive() { + return getProxy() != null && getProxy().isActive(); + } + + private void setAutoPullFluidList(boolean pullFluidList) { + if (!autoPullAvailable) { + return; + } + + autoPullFluidList = pullFluidList; + if (!autoPullFluidList) { + Arrays.fill(storedFluids, null); + } else { + refreshFluidList(); + } + updateAllInformationSlots(); + } + + private void updateAllInformationSlots() { + for (int index = 0; index < SLOT_COUNT; index++) { + updateInformationSlot(index); + } + } + + public void updateInformationSlot(int index) { + if (index < 0 || index >= SLOT_COUNT) { + return; + } + + FluidStack fluidStack = storedFluids[index]; + if (fluidStack == null) { + storedInformationFluids[index] = null; + return; + } + + AENetworkProxy proxy = getProxy(); + if (proxy == null || !proxy.isActive()) { + storedInformationFluids[index] = null; + return; + } + + try { + IMEMonitor<IAEFluidStack> sg = proxy.getStorage() + .getFluidInventory(); + IAEFluidStack request = AEFluidStack.create(fluidStack); + request.setStackSize(Integer.MAX_VALUE); + IAEFluidStack result = sg.extractItems(request, Actionable.SIMULATE, getRequestSource()); + FluidStack resultFluid = (result != null) ? result.getFluidStack() : null; + storedInformationFluids[index] = resultFluid; + } catch (final GridAccessException ignored) {} + } + + private BaseActionSource getRequestSource() { + if (requestSource == null) requestSource = new MachineSource((IActionHost) getBaseMetaTileEntity()); + return requestSource; + } + + public FluidStack getMatchingFluidStack(FluidStack fluidStack) { + if (fluidStack == null) return null; + + AENetworkProxy proxy = getProxy(); + if (proxy == null || !proxy.isActive()) { + return null; + } + + for (int i = 0; i < storedFluids.length; i++) { + if (storedFluids[i] == null) { + continue; + } + + if (GT_Utility.areFluidsEqual(fluidStack, storedFluids[i], false)) { + updateInformationSlot(i); + if (storedInformationFluids[i] != null) { + setSavedFluid(i, storedInformationFluids[i]); + return shadowStoredFluids[i]; + } + + setSavedFluid(i, null); + return null; + } + } + return null; + } + + /** + * Used to avoid slot update. + */ + public FluidStack getShadowFluidStack(int index) { + if (index < 0 || index >= storedFluids.length) { + return null; + } + + return shadowStoredFluids[index]; + } + + public int getFluidSlot(FluidStack fluidStack) { + if (fluidStack == null) return -1; + + for (int i = 0; i < storedFluids.length; i++) { + if (storedFluids[i] == null) { + continue; + } + + if (GT_Utility.areFluidsEqual(fluidStack, storedFluids[i], false)) { + return i; + } + } + + return -1; + } + + @Override + public boolean canTankBeEmptied() { + return false; + } + + @Override + public boolean canTankBeFilled() { + return false; + } + + @Override + public boolean doesEmptyContainers() { + return false; + } + + @Override + public boolean isValidSlot(int aIndex) { + return false; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + + NBTTagList nbtTagList = new NBTTagList(); + for (int i = 0; i < SLOT_COUNT; i++) { + FluidStack fluidStack = storedFluids[i]; + if (fluidStack == null) { + continue; + } + NBTTagCompound fluidTag = fluidStack.writeToNBT(new NBTTagCompound()); + if (storedInformationFluids[i] != null) + fluidTag.setInteger("informationAmount", storedInformationFluids[i].amount); + nbtTagList.appendTag(fluidTag); + } + + aNBT.setTag("storedFluids", nbtTagList); + aNBT.setBoolean("autoPull", autoPullFluidList); + aNBT.setInteger("minAmount", minAutoPullAmount); + aNBT.setBoolean("additionalConnection", additionalConnection); + aNBT.setInteger("refreshTime", autoPullRefreshTime); + getProxy().writeToNBT(aNBT); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (aNBT.hasKey("storedFluids")) { + NBTTagList nbtTagList = aNBT.getTagList("storedFluids", 10); + int c = Math.min(nbtTagList.tagCount(), SLOT_COUNT); + for (int i = 0; i < c; i++) { + NBTTagCompound nbtTagCompound = nbtTagList.getCompoundTagAt(i); + FluidStack fluidStack = GT_Utility.loadFluid(nbtTagCompound); + storedFluids[i] = fluidStack; + + if (nbtTagCompound.hasKey("informationAmount")) { + int informationAmount = nbtTagCompound.getInteger("informationAmount"); + storedInformationFluids[i] = GT_Utility.copyAmount(informationAmount, fluidStack); + } + } + } + + minAutoPullAmount = aNBT.getInteger("minAmount"); + autoPullFluidList = aNBT.getBoolean("autoPull"); + additionalConnection = aNBT.getBoolean("additionalConnection"); + if (aNBT.hasKey("refreshTime")) { + autoPullRefreshTime = aNBT.getInteger("refreshTime"); + } + getProxy().readFromNBT(aNBT); + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (!autoPullAvailable) { + return; + } + + setAutoPullFluidList(!autoPullFluidList); + aPlayer.addChatMessage( + new ChatComponentTranslation( + "GT5U.machines.stocking_hatch.auto_pull_toggle." + (autoPullFluidList ? "enabled" : "disabled"))); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side, + float aX, float aY, float aZ) { + if (!(aPlayer instanceof EntityPlayerMP)) + return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ); + ItemStack dataStick = aPlayer.inventory.getCurrentItem(); + if (!ItemList.Tool_DataStick.isStackEqual(dataStick, false, true)) + return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ); + if (!dataStick.hasTagCompound() || !"stockingHatch".equals(dataStick.stackTagCompound.getString("type"))) + return false; + + NBTTagCompound nbt = dataStick.stackTagCompound; + + if (autoPullAvailable) { + setAutoPullFluidList(nbt.getBoolean("autoPull")); + minAutoPullAmount = nbt.getInteger("minAmount"); + autoPullRefreshTime = nbt.getInteger("refreshTime"); + } + additionalConnection = nbt.getBoolean("additionalConnection"); + + if (!autoPullFluidList) { + NBTTagList stockingFluids = nbt.getTagList("fluidsToStock", 10); + for (int i = 0; i < stockingFluids.tagCount(); i++) { + storedFluids[i] = GT_Utility.loadFluid(stockingFluids.getCompoundTagAt(i)); + } + } + + updateValidGridProxySides(); + aPlayer.addChatMessage(new ChatComponentTranslation("GT5U.machines.stocking_bus.loaded")); + return true; + } + + @Override + public void onLeftclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (!(aPlayer instanceof EntityPlayerMP)) return; + + ItemStack dataStick = aPlayer.inventory.getCurrentItem(); + if (!ItemList.Tool_DataStick.isStackEqual(dataStick, false, true)) return; + + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("type", "stockingHatch"); + tag.setBoolean("autoPull", autoPullFluidList); + tag.setInteger("minAmount", minAutoPullAmount); + tag.setBoolean("additionalConnection", additionalConnection); + tag.setInteger("refreshTime", autoPullRefreshTime); + + NBTTagList stockingFluids = new NBTTagList(); + if (!autoPullFluidList) { + for (int index = 0; index < SLOT_COUNT; index++) { + FluidStack fluidStack = storedFluids[index]; + if (fluidStack == null) { + continue; + } + stockingFluids.appendTag(fluidStack.writeToNBT(new NBTTagCompound())); + } + tag.setTag("fluidsToStock", stockingFluids); + } + dataStick.stackTagCompound = tag; + dataStick.setStackDisplayName("Stocking Input Hatch Configuration"); + aPlayer.addChatMessage(new ChatComponentTranslation("GT5U.machines.stocking_bus.saved")); + } + + @Override + public void onExplosion() { + for (int i = 0; i < SLOT_COUNT; i++) { + mInventory[i] = null; + } + } + + public boolean containsSuchStack(FluidStack tStack) { + for (int i = 0; i < 16; ++i) { + if (GT_Utility.areFluidsEqual(storedFluids[i], tStack, false)) { + return true; + } + } + return false; + } + + @Override + public int getGUIHeight() { + return 179; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + if (autoPullAvailable) { + buildContext.addSyncedWindow(CONFIG_WINDOW_ID, this::createStackSizeConfigurationWindow); + } + + builder.widget( + SlotGroup.ofFluidTanks( + IntStream.range(0, SLOT_COUNT) + .mapToObj(index -> createTankForFluidStack(storedFluids, index, 1)) + .collect(Collectors.toList()), + 4) + .phantom(true) + .widgetCreator((slotIndex, h) -> (FluidSlotWidget) new FluidSlotWidget(h) { + + @Override + protected void tryClickPhantom(ClickData clickData, ItemStack cursorStack) { + if (clickData.mouseButton != 0 || autoPullFluidList) return; + + FluidStack heldFluid = getFluidForPhantomItem(cursorStack); + if (cursorStack == null) { + storedFluids[slotIndex] = null; + } else { + if (containsSuchStack(heldFluid)) return; + storedFluids[slotIndex] = heldFluid; + } + if (getBaseMetaTileEntity().isServerSide()) { + updateInformationSlot(slotIndex); + detectAndSendChanges(false); + } + } + + @Override + protected void tryScrollPhantom(int direction) {} + + @Override + public IDrawable[] getBackground() { + IDrawable slot; + if (autoPullFluidList) { + slot = GT_UITextures.SLOT_DARK_GRAY; + } else { + slot = ModularUITextures.FLUID_SLOT; + } + return new IDrawable[] { slot, GT_UITextures.OVERLAY_SLOT_ARROW_ME }; + } + + @Override + public void buildTooltip(List<Text> tooltip) { + FluidStack fluid = getContent(); + if (fluid != null) { + addFluidNameInfo(tooltip, fluid); + + if (!autoPullFluidList) { + tooltip.add(Text.localised("modularui.phantom.single.clear")); + } + } else { + tooltip.add( + Text.localised("modularui.fluid.empty") + .format(EnumChatFormatting.WHITE)); + } + + if (autoPullFluidList) { + tooltip.add(Text.localised("GT5U.machines.stocking_bus.cannot_set_slot")); + } + } + }.setUpdateTooltipEveryTick(true)) + .build() + .setPos(new Pos2d(7, 9))); + + builder.widget( + SlotGroup.ofFluidTanks( + IntStream.range(0, SLOT_COUNT) + .mapToObj(index -> createTankForFluidStack(storedInformationFluids, index, Integer.MAX_VALUE)) + .collect(Collectors.toList()), + 4) + .phantom(true) + .widgetCreator((slotIndex, h) -> (FluidSlotWidget) new FluidSlotWidget(h) { + + @Override + protected void tryClickPhantom(ClickData clickData, ItemStack cursorStack) {} + + @Override + protected void tryScrollPhantom(int direction) {} + + @Override + public void buildTooltip(List<Text> tooltip) { + FluidStack fluid = getContent(); + if (fluid != null) { + addFluidNameInfo(tooltip, fluid); + tooltip.add(Text.localised("modularui.fluid.phantom.amount", fluid.amount)); + addAdditionalFluidInfo(tooltip, fluid); + if (!Interactable.hasShiftDown()) { + tooltip.add(Text.EMPTY); + tooltip.add(Text.localised("modularui.tooltip.shift")); + } + } else { + tooltip.add( + Text.localised("modularui.fluid.empty") + .format(EnumChatFormatting.WHITE)); + } + } + }.setUpdateTooltipEveryTick(true)) + .background(GT_UITextures.SLOT_DARK_GRAY) + .controlsAmount(true) + .build() + .setPos(new Pos2d(97, 9))); + + if (autoPullAvailable) { + builder.widget(new ButtonWidget().setOnClick((clickData, widget) -> { + if (clickData.mouseButton == 0) { + setAutoPullFluidList(!autoPullFluidList); + } else if (clickData.mouseButton == 1 && !widget.isClient()) { + widget.getContext() + .openSyncedWindow(CONFIG_WINDOW_ID); + } + }) + .setPlayClickSound(true) + .setBackground(() -> { + if (autoPullFluidList) { + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD_PRESSED, + GT_UITextures.OVERLAY_BUTTON_AUTOPULL_ME }; + } else { + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD, + GT_UITextures.OVERLAY_BUTTON_AUTOPULL_ME_DISABLED }; + } + }) + .addTooltips( + Arrays.asList( + StatCollector.translateToLocal("GT5U.machines.stocking_hatch.auto_pull.tooltip.1"), + StatCollector.translateToLocal("GT5U.machines.stocking_hatch.auto_pull.tooltip.2"))) + .setSize(16, 16) + .setPos(80, 10)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> autoPullFluidList, this::setAutoPullFluidList)); + } + + builder.widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_ARROW_DOUBLE) + .setPos(82, 30) + .setSize(12, 12)) + .widget(TextWidget.dynamicString(() -> { + boolean isActive = isActive(); + boolean isPowered = isPowered(); + boolean isBooting = isBooting(); + EnumChatFormatting color = (isActive && isPowered) ? EnumChatFormatting.GREEN + : EnumChatFormatting.DARK_RED; + return color + WailaText.getPowerState(isActive, isPowered, isBooting); + }) + .setTextAlignment(Alignment.Center) + .setSize(90, 9) + .setPos(43, 84)); + } + + private FluidStackTank createTankForFluidStack(FluidStack[] fluidStacks, int slotIndex, int capacity) { + return new FluidStackTank(() -> fluidStacks[slotIndex], (stack) -> { + if (getBaseMetaTileEntity().isServerSide()) { + return; + } + + fluidStacks[slotIndex] = stack; + }, capacity); + } + + protected ModularWindow createStackSizeConfigurationWindow(final EntityPlayer player) { + final int WIDTH = 78; + final int HEIGHT = 80; + final int PARENT_WIDTH = getGUIWidth(); + final int PARENT_HEIGHT = getGUIHeight(); + ModularWindow.Builder builder = ModularWindow.builder(WIDTH, HEIGHT); + builder.setBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); + builder.setGuiTint(getGUIColorization()); + builder.setDraggable(true); + builder.setPos( + (size, window) -> Alignment.Center.getAlignedPos(size, new Size(PARENT_WIDTH, PARENT_HEIGHT)) + .add( + Alignment.TopRight.getAlignedPos(new Size(PARENT_WIDTH, PARENT_HEIGHT), new Size(WIDTH, HEIGHT)) + .add(WIDTH - 3, 0))); + builder.widget( + TextWidget.localised("GT5U.machines.stocking_hatch.min_amount") + .setPos(3, 2) + .setSize(74, 14)) + .widget( + new NumericWidget().setSetter(val -> minAutoPullAmount = (int) val) + .setGetter(() -> minAutoPullAmount) + .setBounds(1, Integer.MAX_VALUE) + .setScrollValues(1, 4, 64) + .setTextAlignment(Alignment.Center) + .setTextColor(Color.WHITE.normal) + .setSize(70, 18) + .setPos(3, 18) + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD)); + builder.widget( + TextWidget.localised("GT5U.machines.stocking_bus.refresh_time") + .setPos(3, 42) + .setSize(74, 14)) + .widget( + new NumericWidget().setSetter(val -> autoPullRefreshTime = (int) val) + .setGetter(() -> autoPullRefreshTime) + .setBounds(1, Integer.MAX_VALUE) + .setScrollValues(1, 4, 64) + .setTextAlignment(Alignment.Center) + .setTextColor(Color.WHITE.normal) + .setSize(70, 18) + .setPos(3, 58) + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD)); + return builder.build(); + } + + @Override + public void addGregTechLogo(ModularWindow.Builder builder) { + builder.widget( + new DrawableWidget().setDrawable(getGUITextureSet().getGregTechLogo()) + .setSize(17, 17) + .setPos(80, 63)); + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + if (!autoPullAvailable) { + super.getWailaBody(itemStack, currenttip, accessor, config); + return; + } + + NBTTagCompound tag = accessor.getNBTData(); + boolean autopull = tag.getBoolean("autoPull"); + int minSize = tag.getInteger("minAmount"); + currenttip.add( + StatCollector.translateToLocal("GT5U.waila.stocking_bus.auto_pull." + (autopull ? "enabled" : "disabled"))); + if (autopull) { + currenttip.add( + StatCollector.translateToLocalFormatted( + "GT5U.waila.stocking_hatch.min_amount", + GT_Utility.formatNumbers(minSize))); + } + super.getWailaBody(itemStack, currenttip, accessor, config); + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + if (!autoPullAvailable) { + super.getWailaNBTData(player, tile, tag, world, x, y, z); + return; + } + + tag.setBoolean("autoPull", autoPullFluidList); + tag.setInteger("minAmount", minAutoPullAmount); + super.getWailaNBTData(player, tile, tag, world, x, y, z); + } + + private static String[] getDescriptionArray(boolean autoPullAvailable) { + List<String> strings = new ArrayList<>(8); + strings.add("Advanced fluid input for Multiblocks"); + strings.add("Hatch Tier: " + TIER_COLORS[autoPullAvailable ? 10 : 8] + VN[autoPullAvailable ? 10 : 8]); + strings.add("Retrieves directly from ME"); + strings.add("Keeps 16 fluid types in stock"); + + if (autoPullAvailable) { + strings.add( + "Auto-Pull from ME mode will automatically stock the first 16 fluid in the ME system, updated every 5 seconds."); + strings.add("Toggle by right-clicking with screwdriver, or use the GUI."); + strings + .add("Use the GUI to limit the minimum stack size for Auto-Pulling and adjust the slot refresh timer."); + } + + strings.add("Change ME connection behavior by right-clicking with wire cutter."); + strings.add("Configuration data can be copy+pasted using a data stick."); + return strings.toArray(new String[0]); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_OutputBus_ME.java b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_OutputBus_ME.java new file mode 100644 index 0000000000..16817e1a9c --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_OutputBus_ME.java @@ -0,0 +1,327 @@ +package gregtech.common.tileentities.machines; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_HATCH; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_HATCH_ACTIVE; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +import javax.annotation.Nullable; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.common.util.ForgeDirection; + +import appeng.api.AEApi; +import appeng.api.implementations.IPowerChannelState; +import appeng.api.networking.GridFlags; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.IActionHost; +import appeng.api.networking.security.MachineSource; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.api.util.AECableType; +import appeng.me.GridAccessException; +import appeng.me.helpers.AENetworkProxy; +import appeng.me.helpers.IGridProxyable; +import appeng.util.IWideReadableNumberConverter; +import appeng.util.Platform; +import appeng.util.ReadableNumberConverter; +import gregtech.GT_Mod; +import gregtech.api.enums.ItemList; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_OutputBus; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Hatch_OutputBus_ME extends GT_MetaTileEntity_Hatch_OutputBus + implements IPowerChannelState { + + private BaseActionSource requestSource = null; + private @Nullable AENetworkProxy gridProxy = null; + final IItemList<IAEItemStack> itemCache = AEApi.instance() + .storage() + .createItemList(); + long lastOutputTick = 0; + long tickCounter = 0; + boolean lastOutputFailed = false; + boolean infiniteCache = true; + boolean additionalConnection = false; + + public GT_MetaTileEntity_Hatch_OutputBus_ME(int aID, String aName, String aNameRegional) { + super( + aID, + aName, + aNameRegional, + 3, + new String[] { "Item Output for Multiblocks", "Stores directly into ME", + "Can cache infinite amount of items.", "Change cache behavior by right-clicking with screwdriver.", + "Change ME connection behavior by right-clicking with wire cutter" }, + 0); + } + + public GT_MetaTileEntity_Hatch_OutputBus_ME(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, 0, aDescription, aTextures); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_OutputBus_ME(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_HATCH_ACTIVE) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_HATCH) }; + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + getProxy().onReady(); + } + + @Override + public boolean storeAll(ItemStack aStack) { + aStack.stackSize = store(aStack); + return aStack.stackSize == 0; + } + + /** + * Attempt to store items in connected ME network. Returns how many items did not fit (if the network was down e.g.) + * + * @param stack input stack + * @return amount of items left over + */ + public int store(final ItemStack stack) { + if (!infiniteCache && lastOutputFailed) return stack.stackSize; + itemCache.add( + AEApi.instance() + .storage() + .createItemStack(stack)); + return 0; + } + + private BaseActionSource getRequest() { + if (requestSource == null) requestSource = new MachineSource((IActionHost) getBaseMetaTileEntity()); + return requestSource; + } + + @Override + public AECableType getCableConnectionType(ForgeDirection forgeDirection) { + return isOutputFacing(forgeDirection) ? AECableType.SMART : AECableType.NONE; + } + + private void updateValidGridProxySides() { + if (additionalConnection) { + getProxy().setValidSides(EnumSet.complementOf(EnumSet.of(ForgeDirection.UNKNOWN))); + } else { + getProxy().setValidSides(EnumSet.of(getBaseMetaTileEntity().getFrontFacing())); + } + } + + @Override + public void onFacingChange() { + updateValidGridProxySides(); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + return false; + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (!getBaseMetaTileEntity().getCoverInfoAtSide(side) + .isGUIClickable()) return; + infiniteCache = !infiniteCache; + aPlayer.addChatComponentMessage(new ChatComponentTranslation("GT5U.hatch.infiniteCache." + infiniteCache)); + } + + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ) { + additionalConnection = !additionalConnection; + updateValidGridProxySides(); + aPlayer.addChatComponentMessage( + new ChatComponentTranslation("GT5U.hatch.additionalConnection." + additionalConnection)); + return true; + } + + @Override + public AENetworkProxy getProxy() { + if (gridProxy == null) { + if (getBaseMetaTileEntity() instanceof IGridProxyable) { + gridProxy = new AENetworkProxy( + (IGridProxyable) getBaseMetaTileEntity(), + "proxy", + ItemList.Hatch_Output_Bus_ME.get(1), + true); + gridProxy.setFlags(GridFlags.REQUIRE_CHANNEL); + updateValidGridProxySides(); + if (getBaseMetaTileEntity().getWorld() != null) gridProxy.setOwner( + getBaseMetaTileEntity().getWorld() + .getPlayerEntityByName(getBaseMetaTileEntity().getOwnerName())); + } + } + return this.gridProxy; + } + + private void flushCachedStack() { + lastOutputFailed = false; + AENetworkProxy proxy = getProxy(); + if (proxy == null) { + lastOutputFailed = true; + return; + } + try { + IMEMonitor<IAEItemStack> sg = proxy.getStorage() + .getItemInventory(); + for (IAEItemStack s : itemCache) { + if (s.getStackSize() == 0) continue; + IAEItemStack rest = Platform.poweredInsert(proxy.getEnergy(), sg, s, getRequest()); + if (rest != null && rest.getStackSize() > 0) { + lastOutputFailed = true; + s.setStackSize(rest.getStackSize()); + break; + } + s.setStackSize(0); + } + } catch (final GridAccessException ignored) { + lastOutputFailed = true; + } + lastOutputTick = tickCounter; + } + + @Override + public boolean isPowered() { + return getProxy() != null && getProxy().isPowered(); + } + + @Override + public boolean isActive() { + return getProxy() != null && getProxy().isActive(); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (getBaseMetaTileEntity().isServerSide()) { + tickCounter = aTick; + if (tickCounter > (lastOutputTick + 40)) flushCachedStack(); + if (tickCounter % 20 == 0) getBaseMetaTileEntity().setActive(isActive()); + } + super.onPostTick(aBaseMetaTileEntity, aTick); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + + NBTTagList items = new NBTTagList(); + for (IAEItemStack s : itemCache) { + if (s.getStackSize() == 0) continue; + NBTTagCompound tag = new NBTTagCompound(); + tag.setTag("itemStack", GT_Utility.saveItem(s.getItemStack())); + tag.setLong("size", s.getStackSize()); + items.appendTag(tag); + } + aNBT.setBoolean("infiniteCache", infiniteCache); + aNBT.setBoolean("additionalConnection", additionalConnection); + aNBT.setTag("cachedItems", items); + getProxy().writeToNBT(aNBT); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + + NBTBase t = aNBT.getTag("cachedStack"); // legacy + if (t instanceof NBTTagCompound) itemCache.add( + AEApi.instance() + .storage() + .createItemStack(GT_Utility.loadItem((NBTTagCompound) t))); + t = aNBT.getTag("cachedItems"); + if (t instanceof NBTTagList l) { + for (int i = 0; i < l.tagCount(); ++i) { + NBTTagCompound tag = l.getCompoundTagAt(i); + if (!tag.hasKey("itemStack")) { // legacy #868 + itemCache.add( + AEApi.instance() + .storage() + .createItemStack(GT_Utility.loadItem(l.getCompoundTagAt(i)))); + continue; + } + NBTTagCompound tagItemStack = tag.getCompoundTag("itemStack"); + final IAEItemStack s = AEApi.instance() + .storage() + .createItemStack(GT_Utility.loadItem(tagItemStack)); + if (s != null) { + s.setStackSize(tag.getLong("size")); + itemCache.add(s); + } else { + GT_Mod.GT_FML_LOGGER.warn( + "An error occurred while loading contents of ME Output Bus. This item has been voided: " + + tagItemStack); + } + } + } + if (aNBT.hasKey("infiniteCache")) { + infiniteCache = aNBT.getBoolean("infiniteCache"); + } + additionalConnection = aNBT.getBoolean("additionalConnection"); + getProxy().readFromNBT(aNBT); + } + + public boolean isLastOutputFailed() { + return lastOutputFailed; + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public String[] getInfoData() { + List<String> ss = new ArrayList<>(); + ss.add( + "The bus is " + ((getProxy() != null && getProxy().isActive()) ? EnumChatFormatting.GREEN + "online" + : EnumChatFormatting.RED + "offline" + getAEDiagnostics()) + EnumChatFormatting.RESET); + if (itemCache.isEmpty()) { + ss.add("The bus has no cached items"); + } else { + IWideReadableNumberConverter nc = ReadableNumberConverter.INSTANCE; + ss.add(String.format("The bus contains %d cached stacks: ", itemCache.size())); + int counter = 0; + for (IAEItemStack s : itemCache) { + ss.add( + s.getItem() + .getItemStackDisplayName(s.getItemStack()) + ": " + + EnumChatFormatting.GOLD + + nc.toWideReadableForm(s.getStackSize()) + + EnumChatFormatting.RESET); + if (++counter > 100) break; + } + } + return ss.toArray(new String[itemCache.size() + 2]); + } + + @Override + public boolean useModularUI() { + return false; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_Output_ME.java b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_Output_ME.java new file mode 100644 index 0000000000..4df8ff68c5 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/GT_MetaTileEntity_Hatch_Output_ME.java @@ -0,0 +1,383 @@ +package gregtech.common.tileentities.machines; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_FLUID_HATCH; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_ME_FLUID_HATCH_ACTIVE; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +import javax.annotation.Nullable; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import appeng.api.AEApi; +import appeng.api.config.Actionable; +import appeng.api.config.PowerMultiplier; +import appeng.api.implementations.IPowerChannelState; +import appeng.api.networking.GridFlags; +import appeng.api.networking.energy.IEnergySource; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.security.IActionHost; +import appeng.api.networking.security.MachineSource; +import appeng.api.networking.security.PlayerSource; +import appeng.api.storage.IMEInventory; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IItemList; +import appeng.api.util.AECableType; +import appeng.core.stats.Stats; +import appeng.me.GridAccessException; +import appeng.me.helpers.AENetworkProxy; +import appeng.me.helpers.IGridProxyable; +import appeng.util.IWideReadableNumberConverter; +import appeng.util.ReadableNumberConverter; +import gregtech.GT_Mod; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.ItemList; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Hatch_Output_ME extends GT_MetaTileEntity_Hatch_Output implements IPowerChannelState { + + private BaseActionSource requestSource = null; + private @Nullable AENetworkProxy gridProxy = null; + final IItemList<IAEFluidStack> fluidCache = AEApi.instance() + .storage() + .createFluidList(); + long lastOutputTick = 0; + long tickCounter = 0; + boolean lastOutputFailed = false; + boolean infiniteCache = true; + boolean additionalConnection = false; + + public GT_MetaTileEntity_Hatch_Output_ME(int aID, String aName, String aNameRegional) { + super( + aID, + aName, + aNameRegional, + 3, + new String[] { "Fluid Output for Multiblocks", "Stores directly into ME", + "Can cache infinite amount of fluids.", "Change cache behavior by right-clicking with screwdriver.", + "Change ME connection behavior by right-clicking with wire cutter" }, + 0); + } + + public GT_MetaTileEntity_Hatch_Output_ME(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 0, aDescription, aTextures); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_Output_ME(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_FLUID_HATCH_ACTIVE) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(OVERLAY_ME_FLUID_HATCH) }; + } + + @Override + public byte getTierForStructure() { + return (byte) (GT_Values.V.length - 2); + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + getProxy().onReady(); + } + + @Override + public int fill(FluidStack aFluid, boolean doFill) { + if (doFill) { + return tryFillAE(aFluid); + } else { + if ((!infiniteCache && lastOutputFailed) || aFluid == null) return 0; + return aFluid.amount; + } + } + + /** + * Attempt to store fluid in connected ME network. Returns how much fluid is accepted (if the network was down e.g.) + * + * @param aFluid input fluid + * @return amount of fluid filled + */ + public int tryFillAE(final FluidStack aFluid) { + if ((!infiniteCache && lastOutputFailed) || aFluid == null) return 0; + fluidCache.add( + AEApi.instance() + .storage() + .createFluidStack(aFluid)); + return aFluid.amount; + } + + private BaseActionSource getRequest() { + if (requestSource == null) requestSource = new MachineSource((IActionHost) getBaseMetaTileEntity()); + return requestSource; + } + + @Override + public AECableType getCableConnectionType(ForgeDirection side) { + return isOutputFacing(side) ? AECableType.SMART : AECableType.NONE; + } + + private void updateValidGridProxySides() { + if (additionalConnection) { + getProxy().setValidSides(EnumSet.complementOf(EnumSet.of(ForgeDirection.UNKNOWN))); + } else { + getProxy().setValidSides(EnumSet.of(getBaseMetaTileEntity().getFrontFacing())); + } + } + + @Override + public void onFacingChange() { + updateValidGridProxySides(); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + return false; + } + + @Override + public boolean isValidSlot(int aIndex) { + return true; + } + + @Override + public boolean doesFillContainers() { + return false; + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + // Don't allow to lock fluid in me fluid hatch + if (!getBaseMetaTileEntity().getCoverInfoAtSide(side) + .isGUIClickable()) return; + infiniteCache = !infiniteCache; + aPlayer.addChatComponentMessage(new ChatComponentTranslation("GT5U.hatch.infiniteCacheFluid." + infiniteCache)); + } + + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ) { + additionalConnection = !additionalConnection; + updateValidGridProxySides(); + aPlayer.addChatComponentMessage( + new ChatComponentTranslation("GT5U.hatch.additionalConnection." + additionalConnection)); + return true; + } + + @Override + public AENetworkProxy getProxy() { + if (gridProxy == null) { + if (getBaseMetaTileEntity() instanceof IGridProxyable) { + gridProxy = new AENetworkProxy( + (IGridProxyable) getBaseMetaTileEntity(), + "proxy", + ItemList.Hatch_Output_ME.get(1), + true); + gridProxy.setFlags(GridFlags.REQUIRE_CHANNEL); + updateValidGridProxySides(); + if (getBaseMetaTileEntity().getWorld() != null) gridProxy.setOwner( + getBaseMetaTileEntity().getWorld() + .getPlayerEntityByName(getBaseMetaTileEntity().getOwnerName())); + } + } + return this.gridProxy; + } + + private void flushCachedStack() { + if (fluidCache.isEmpty()) return; + lastOutputFailed = true; + AENetworkProxy proxy = getProxy(); + if (proxy == null) { + lastOutputFailed = true; + return; + } + try { + IMEMonitor<IAEFluidStack> sg = proxy.getStorage() + .getFluidInventory(); + for (IAEFluidStack s : fluidCache) { + if (s.getStackSize() == 0) continue; + IAEFluidStack rest = fluidAEInsert(proxy.getEnergy(), sg, s, getRequest()); + if (rest != null && rest.getStackSize() > 0) { + s.setStackSize(rest.getStackSize()); + continue; + } + lastOutputFailed = false; + s.setStackSize(0); + } + } catch (final GridAccessException ignored) { + lastOutputFailed = true; + } + lastOutputTick = tickCounter; + } + + @Override + public boolean isPowered() { + return getProxy() != null && getProxy().isPowered(); + } + + @Override + public boolean isActive() { + return getProxy() != null && getProxy().isActive(); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (getBaseMetaTileEntity().isServerSide()) { + tickCounter = aTick; + if (tickCounter > (lastOutputTick + 40)) flushCachedStack(); + if (tickCounter % 20 == 0) getBaseMetaTileEntity().setActive(isActive()); + } + super.onPostTick(aBaseMetaTileEntity, aTick); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + NBTTagList fluids = new NBTTagList(); + for (IAEFluidStack s : fluidCache) { + if (s.getStackSize() == 0) continue; + NBTTagCompound tag = new NBTTagCompound(); + NBTTagCompound tagFluidStack = new NBTTagCompound(); + s.getFluidStack() + .writeToNBT(tagFluidStack); + tag.setTag("fluidStack", tagFluidStack); + tag.setLong("size", s.getStackSize()); + fluids.appendTag(tag); + } + aNBT.setTag("cachedFluids", fluids); + aNBT.setBoolean("infiniteCache", infiniteCache); + aNBT.setBoolean("additionalConnection", additionalConnection); + getProxy().writeToNBT(aNBT); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + NBTBase t = aNBT.getTag("cachedFluids"); + if (t instanceof NBTTagList l) { + for (int i = 0; i < l.tagCount(); ++i) { + NBTTagCompound tag = l.getCompoundTagAt(i); + NBTTagCompound tagFluidStack = tag.getCompoundTag("fluidStack"); + final IAEFluidStack s = AEApi.instance() + .storage() + .createFluidStack(GT_Utility.loadFluid(tagFluidStack)); + if (s != null) { + s.setStackSize(tag.getLong("size")); + fluidCache.add(s); + } else { + GT_Mod.GT_FML_LOGGER.warn( + "An error occurred while loading contents of ME Output Hatch. This fluid has been voided: " + + tagFluidStack); + } + } + } + if (aNBT.hasKey("infiniteCache")) { + infiniteCache = aNBT.getBoolean("infiniteCache"); + } + additionalConnection = aNBT.getBoolean("additionalConnection"); + getProxy().readFromNBT(aNBT); + } + + public boolean isLastOutputFailed() { + return lastOutputFailed; + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public String[] getInfoData() { + List<String> ss = new ArrayList<>(); + ss.add( + "The hatch is " + ((getProxy() != null && getProxy().isActive()) ? EnumChatFormatting.GREEN + "online" + : EnumChatFormatting.RED + "offline" + getAEDiagnostics()) + EnumChatFormatting.RESET); + if (fluidCache.isEmpty()) { + ss.add("The bus has no cached fluids"); + } else { + IWideReadableNumberConverter nc = ReadableNumberConverter.INSTANCE; + ss.add(String.format("The hatch contains %d cached fluids: ", fluidCache.size())); + int counter = 0; + for (IAEFluidStack s : fluidCache) { + ss.add( + s.getFluidStack() + .getLocalizedName() + ": " + + EnumChatFormatting.GOLD + + nc.toWideReadableForm(s.getStackSize()) + + " mB" + + EnumChatFormatting.RESET); + if (++counter > 100) break; + } + } + return ss.toArray(new String[fluidCache.size() + 2]); + } + + public static IAEFluidStack fluidAEInsert(final IEnergySource energy, final IMEInventory<IAEFluidStack> cell, + final IAEFluidStack input, final BaseActionSource src) { + final IAEFluidStack possible = cell.injectItems(input.copy(), Actionable.SIMULATE, src); + + long stored = input.getStackSize(); + if (possible != null) { + stored -= possible.getStackSize(); + } + // 1000 mb fluid will be considered as 1 item + long power = Math.max(1, stored / 1000); + + final double availablePower = energy.extractAEPower(power, Actionable.SIMULATE, PowerMultiplier.CONFIG); + + final long itemToAdd = Math.min((long) (availablePower + 0.9) * 1000, stored); + + if (itemToAdd > 0) { + energy.extractAEPower(power, Actionable.MODULATE, PowerMultiplier.CONFIG); + + if (itemToAdd < input.getStackSize()) { + final long original = input.getStackSize(); + final IAEFluidStack split = input.copy(); + split.decStackSize(itemToAdd); + input.setStackSize(itemToAdd); + split.add(cell.injectItems(input, Actionable.MODULATE, src)); + + if (src.isPlayer()) { + final long diff = original - split.getStackSize(); + Stats.ItemsInserted.addToPlayer(((PlayerSource) src).player, (int) diff); + } + + return split; + } + + final IAEFluidStack ret = cell.injectItems(input, Actionable.MODULATE, src); + + if (src.isPlayer()) { + final long diff = ret == null ? input.getStackSize() : input.getStackSize() - ret.getStackSize(); + Stats.ItemsInserted.addToPlayer(((PlayerSource) src).player, (int) diff); + } + + return ret; + } + + return input; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/IDualInputHatch.java b/src/main/java/gregtech/common/tileentities/machines/IDualInputHatch.java new file mode 100644 index 0000000000..c89aaaff40 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/IDualInputHatch.java @@ -0,0 +1,21 @@ +package gregtech.common.tileentities.machines; + +import java.util.Iterator; +import java.util.Optional; + +import net.minecraft.item.ItemStack; + +public interface IDualInputHatch { + + boolean justUpdated(); + + Iterator<? extends IDualInputInventory> inventories(); + + void updateTexture(int id); + + void updateCraftingIcon(ItemStack icon); + + Optional<IDualInputInventory> getFirstNonEmptyInventory(); + + public boolean supportsFluids(); +} diff --git a/src/main/java/gregtech/common/tileentities/machines/IDualInputInventory.java b/src/main/java/gregtech/common/tileentities/machines/IDualInputInventory.java new file mode 100644 index 0000000000..01649fe181 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/IDualInputInventory.java @@ -0,0 +1,11 @@ +package gregtech.common.tileentities.machines; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +public interface IDualInputInventory { + + ItemStack[] getItemInputs(); + + FluidStack[] getFluidInputs(); +} diff --git a/src/main/java/gregtech/common/tileentities/machines/IRecipeProcessingAwareHatch.java b/src/main/java/gregtech/common/tileentities/machines/IRecipeProcessingAwareHatch.java new file mode 100644 index 0000000000..c7a97ce969 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/IRecipeProcessingAwareHatch.java @@ -0,0 +1,26 @@ +package gregtech.common.tileentities.machines; + +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; + +/** + * Implement this interface for {@link gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch} + * if it does special stuff while multiblock controller is processing recipe. + */ +public interface IRecipeProcessingAwareHatch { + + /** + * Called when multiblock controller starts processing. + * {@link #endRecipeProcessing} is called on the same tick. + */ + void startRecipeProcessing(); + + /** + * Called when multiblock controller ends processing. {@link #startRecipeProcessing} is called on the same tick. + * + * @param controller Caller of this method. + * @return Result of the process of this method. {@code !wasSuccessful()} means the returned result should + * overwrite the result calculated on multiblock whatever the reason is. + */ + CheckRecipeResult endRecipeProcessing(GT_MetaTileEntity_MultiBlockBase controller); +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_AdvSeismicProspector.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_AdvSeismicProspector.java new file mode 100644 index 0000000000..78ed9982fc --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_AdvSeismicProspector.java @@ -0,0 +1,309 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_ROCK_BREAKER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_ROCK_BREAKER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_ROCK_BREAKER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_ROCK_BREAKER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_ROCK_BREAKER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_ROCK_BREAKER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_ROCK_BREAKER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_ROCK_BREAKER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_ROCK_BREAKER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_ROCK_BREAKER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_ROCK_BREAKER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_ROCK_BREAKER_GLOW; +import static gregtech.common.GT_UndergroundOil.undergroundOilReadInformation; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.objects.ItemData; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; +import gregtech.common.blocks.GT_Block_Ores_Abstract; +import gregtech.common.blocks.GT_TileEntity_Ores; +import ic2.core.Ic2Items; + +public class GT_MetaTileEntity_AdvSeismicProspector extends GT_MetaTileEntity_BasicMachine { + + boolean ready = false; + final int radius; + final int step; + int cX; + int cZ; + + public GT_MetaTileEntity_AdvSeismicProspector(int aID, String aName, String aNameRegional, int aTier, int aRadius, + int aStep) { + super( + aID, + aName, + aNameRegional, + aTier, + 1, // amperage + "", + 1, // input slot count + 1, // output slot count + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_ROCK_BREAKER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_ROCK_BREAKER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_ROCK_BREAKER), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_ROCK_BREAKER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_ROCK_BREAKER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_ROCK_BREAKER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_ROCK_BREAKER), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_ROCK_BREAKER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_ROCK_BREAKER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ROCK_BREAKER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_ROCK_BREAKER), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ROCK_BREAKER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_ROCK_BREAKER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_ROCK_BREAKER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_ROCK_BREAKER), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_ROCK_BREAKER_GLOW) + .glow() + .build())); + radius = aRadius; + step = aStep; + } + + @Override + public String[] getDescription() { + return new String[] { "Place, activate with explosives", + "2 Powderbarrels, " + "4 Glyceryl Trinitrate, " + "16 TNT, or " + "8 ITNT", + "Use Data Stick, Scan Data Stick, Print Data Stick, Bind Pages into Book", + "Ore prospecting area = " + radius * 2 + "x" + radius * 2 + " ONLY blocks below prospector", + "Oil prospecting area 3x3 oilfields, each is 8x8 chunks" }; + } + + protected GT_MetaTileEntity_AdvSeismicProspector(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures, int aRadius, int aStep) { + super(aName, aTier, 1, aDescription, aTextures, 1, 1); + radius = aRadius; + step = aStep; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_AdvSeismicProspector( + this.mName, + this.mTier, + this.mDescriptionArray, + this.mTextures, + this.radius, + this.step); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (aBaseMetaTileEntity.isServerSide()) { + ItemStack aStack = aPlayer.getCurrentEquippedItem(); + + if (!ready && (GT_Utility.consumeItems(aPlayer, aStack, Item.getItemFromBlock(Blocks.tnt), 16) + || GT_Utility.consumeItems(aPlayer, aStack, Ic2Items.industrialTnt.getItem(), 8) + || GT_Utility.consumeItems(aPlayer, aStack, Materials.Glyceryl, 4) + || GT_Utility.consumeItems(aPlayer, aStack, ItemList.Block_Powderbarrel.getItem(), 2))) { + + this.ready = true; + this.mMaxProgresstime = (aPlayer.capabilities.isCreativeMode ? 20 : 800); + + } else if (ready && mMaxProgresstime == 0 + && aStack != null + && aStack.stackSize == 1 + && aStack.getItem() == ItemList.Tool_DataStick.getItem()) { + this.ready = false; + + // prospecting ores + HashMap<String, Integer> tOres = new HashMap<>(36); + + prospectOres(tOres); + + // prospecting oils + ArrayList<String> tOils = new ArrayList<>(); + prospectOils(tOils); + + GT_Utility.ItemNBT.setAdvancedProspectionData( + mTier, + aStack, + this.getBaseMetaTileEntity() + .getXCoord(), + this.getBaseMetaTileEntity() + .getYCoord(), + this.getBaseMetaTileEntity() + .getZCoord(), + this.getBaseMetaTileEntity() + .getWorld().provider.dimensionId, + tOils, + GT_Utility.sortByValueToList(tOres), + radius); + } + } + + return true; + } + + private void prospectOils(ArrayList<String> aOils) { + + int xChunk = (getBaseMetaTileEntity().getXCoord() >> 7) << 3; // oil field aligned chunk coords + int zChunk = (getBaseMetaTileEntity().getZCoord() >> 7) << 3; + + LinkedHashMap<ChunkCoordIntPair, FluidStack> tFluids = new LinkedHashMap<>(); + int oilFieldCount = 0; + + try { + final int oilfieldSize = 8; + for (int z = -1; z <= 1; ++z) { + for (int x = -1; x <= 1; ++x) { + ChunkCoordIntPair cInts = new ChunkCoordIntPair(x, z); + int min = Integer.MAX_VALUE; + int max = Integer.MIN_VALUE; + + for (int i = 0; i < oilfieldSize; i++) { + for (int j = 0; j < oilfieldSize; j++) { + Chunk tChunk = getBaseMetaTileEntity().getWorld() + .getChunkFromChunkCoords(xChunk + i + x * oilfieldSize, zChunk + j + z * oilfieldSize); + FluidStack tFluid = undergroundOilReadInformation(tChunk); + if (tFluid != null) { + if (tFluid.amount > max) max = tFluid.amount; + if (tFluid.amount < min) min = tFluid.amount; + if (!tFluids.containsKey(cInts)) { + tFluids.put(cInts, tFluid); + } + } + } + } + + aOils.add( + ++oilFieldCount + "," + + min + + "-" + + max + + "," + + tFluids.get(cInts) + .getLocalizedName()); + } + } + } catch (Exception ignored) {} + } + + private void prospectOres(Map<String, Integer> aOres) { + int tLeftXBound = this.getBaseMetaTileEntity() + .getXCoord() - radius; + int tRightXBound = tLeftXBound + 2 * radius; + + int tLeftZBound = this.getBaseMetaTileEntity() + .getZCoord() - radius; + int tRightZBound = tLeftZBound + 2 * radius; + + for (int i = tLeftXBound; i <= tRightXBound; i += step) { + if (Math.abs(i >> 4) % 3 != 1) continue; + for (int k = tLeftZBound; k <= tRightZBound; k += step) { + if (Math.abs(k >> 4) % 3 != 1) continue; + + cX = (i >> 4) << 4; + cZ = (k >> 4) << 4; + + String separator = (cX + 8) + "," + (cZ + 8) + " --------"; + aOres.put(separator, 1); + prospectHole(i, k, aOres); + } + } + } + + private void prospectHole(int i, int k, Map<String, Integer> aOres) { + String tFoundOre; + for (int j = this.getBaseMetaTileEntity() + .getYCoord(); j > 0; j--) { + tFoundOre = checkForOre(i, j, k); + if (tFoundOre != null) countOre(aOres, tFoundOre, cX, cZ); + } + } + + private String checkForOre(int x, int y, int z) { + Block tBlock = this.getBaseMetaTileEntity() + .getBlock(x, y, z); + + if (tBlock instanceof GT_Block_Ores_Abstract) { + TileEntity tTileEntity = getBaseMetaTileEntity().getWorld() + .getTileEntity(x, y, z); + + if ((tTileEntity instanceof GT_TileEntity_Ores) && (((GT_TileEntity_Ores) tTileEntity).mMetaData < 16000)) { // Filtering + // small + // ores + Materials tMaterial = GregTech_API.sGeneratedMaterials[((GT_TileEntity_Ores) tTileEntity).mMetaData + % 1000]; + + if ((tMaterial != null) && (tMaterial != Materials._NULL)) return tMaterial.mDefaultLocalName; + } + } else { + int tMetaID = getBaseMetaTileEntity().getWorld() + .getBlockMetadata(x, y, z); + ItemStack is = new ItemStack(tBlock, 1, tMetaID); + ItemData association = GT_OreDictUnificator.getAssociation(is); + if ((association != null) && (association.mPrefix.toString() + .startsWith("ore"))) return association.mMaterial.mMaterial.mDefaultLocalName; + else if (GT_Utility.isOre(tBlock, tMetaID)) return tBlock.getLocalizedName(); + } + return null; + } + + private static void countOre(Map<String, Integer> map, String ore, int cCX, int cCZ) { + ore = (cCX + 8) + "," + (cCZ + 8) + " has " + ore; + Integer oldCount = map.get(ore); + oldCount = (oldCount == null) ? 0 : oldCount; + + map.put(ore, oldCount + 1); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Boxinator.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Boxinator.java new file mode 100644 index 0000000000..6c908aadac --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Boxinator.java @@ -0,0 +1,231 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_BOXINATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_BOXINATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_BOXINATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_BOXINATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_BOXINATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_BOXINATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_BOXINATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_BOXINATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_BOXINATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_BOXINATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_BOXINATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_BOXINATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_BOXINATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_BOXINATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_BOXINATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_BOXINATOR_GLOW; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.MachineType; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Boxinator extends GT_MetaTileEntity_BasicMachine { + + ItemStack aInputCache; + ItemStack aOutputCache; + int aTypeCache = 0; + + public GT_MetaTileEntity_Boxinator(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 1, + MachineType.PACKAGER.tooltipDescription(), + 2, + 1, + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_BOXINATOR_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_BOXINATOR_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_BOXINATOR), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_BOXINATOR_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_BOXINATOR_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_BOXINATOR_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_BOXINATOR), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_BOXINATOR_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_BOXINATOR_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_BOXINATOR_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_BOXINATOR), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_BOXINATOR_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_BOXINATOR_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_BOXINATOR_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_BOXINATOR), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_BOXINATOR_GLOW) + .glow() + .build())); + } + + public GT_MetaTileEntity_Boxinator(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 1, aDescription, aTextures, 2, 1); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Boxinator(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.packagerRecipes; + } + + private boolean hasValidCache(ItemStack mItem, int mType, boolean mClearOnFailure) { + if (aInputCache != null && aOutputCache != null + && aTypeCache == mType + && aInputCache.isItemEqual(mItem) + && ItemStack.areItemStackTagsEqual(mItem, aInputCache)) return true; + // clear cache if it was invalid + if (mClearOnFailure) { + aInputCache = null; + aOutputCache = null; + aTypeCache = 0; + } + return false; + } + + private void cacheItem(ItemStack mInputItem, ItemStack mOutputItem, int mType) { + aTypeCache = mType; + aOutputCache = mOutputItem.copy(); + aInputCache = mInputItem.copy(); + } + + @Override + public int checkRecipe() { + int tCheck = super.checkRecipe(); + if (tCheck != DID_NOT_FIND_RECIPE) { + return tCheck; + } + ItemStack tSlot0 = getInputAt(0); + ItemStack tSlot1 = getInputAt(1); + if ((GT_Utility.isStackValid(tSlot0)) && (GT_Utility.isStackValid(tSlot1)) + && (GT_Utility.getContainerItem(tSlot0, true) == null)) { + if ((ItemList.Schematic_1by1.isStackEqual(tSlot1)) && (tSlot0.stackSize >= 1)) { + boolean tIsCached = hasValidCache(tSlot0, 1, true); + this.mOutputItems[0] = tIsCached ? aOutputCache.copy() : GT_ModHandler.getRecipeOutput(tSlot0); + if (this.mOutputItems[0] != null) { + if (canOutput(this.mOutputItems[0])) { + tSlot0.stackSize -= 1; + calculateOverclockedNess(30, 16); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + if (!tIsCached) cacheItem(tSlot0, this.mOutputItems[0], 1); + return FOUND_AND_SUCCESSFULLY_USED_RECIPE; + } + } + return DID_NOT_FIND_RECIPE; + } + if ((ItemList.Schematic_2by2.isStackEqual(tSlot1)) && (getInputAt(0).stackSize >= 4)) { + boolean tIsCached = hasValidCache(tSlot0, 2, true); + this.mOutputItems[0] = tIsCached ? aOutputCache.copy() + : GT_ModHandler.getRecipeOutput(tSlot0, tSlot0, null, tSlot0, tSlot0); + if (this.mOutputItems[0] != null) { + if (canOutput(this.mOutputItems[0])) { + getInputAt(0).stackSize -= 4; + calculateOverclockedNess(30, 32); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + if (!tIsCached) cacheItem(tSlot0, this.mOutputItems[0], 2); + return FOUND_AND_SUCCESSFULLY_USED_RECIPE; + } + } + return DID_NOT_FIND_RECIPE; + } + if ((ItemList.Schematic_3by3.isStackEqual(tSlot1)) && (getInputAt(0).stackSize >= 9)) { + boolean tIsCached = hasValidCache(tSlot0, 3, true); + this.mOutputItems[0] = tIsCached ? aOutputCache.copy() + : GT_ModHandler + .getRecipeOutput(tSlot0, tSlot0, tSlot0, tSlot0, tSlot0, tSlot0, tSlot0, tSlot0, tSlot0); + if (this.mOutputItems[0] != null) { + if (canOutput(this.mOutputItems[0])) { + getInputAt(0).stackSize -= 9; + calculateOverclockedNess(30, 64); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + if (!tIsCached) cacheItem(tSlot0, this.mOutputItems[0], 3); + return FOUND_AND_SUCCESSFULLY_USED_RECIPE; + } + } + return DID_NOT_FIND_RECIPE; + } + } + return DID_NOT_FIND_RECIPE; + } + + @Override + protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + if (!super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack)) { + return false; + } + ItemStack tInput1 = getInputAt(1); + if ((ItemList.Schematic_1by1.isStackEqual(tInput1)) || (ItemList.Schematic_2by2.isStackEqual(tInput1)) + || (ItemList.Schematic_3by3.isStackEqual(tInput1))) { + if (hasValidCache(aStack, aTypeCache, false)) return true; + if (RecipeMaps.packagerRecipes.findRecipe( + getBaseMetaTileEntity(), + true, + gregtech.api.enums.GT_Values.V[mTier], + null, + GT_Utility.copyAmount(64, aStack), + tInput1) != null) { + return true; + } + if (ItemList.Schematic_1by1.isStackEqual(getInputAt(1)) && GT_ModHandler.getRecipeOutput(aStack) != null) + return true; + if (ItemList.Schematic_2by2.isStackEqual(getInputAt(1)) + && GT_ModHandler.getRecipeOutput(aStack, aStack, null, aStack, aStack) != null) { + return true; + } + return ItemList.Schematic_3by3.isStackEqual(getInputAt(1)) && (GT_ModHandler + .getRecipeOutput(aStack, aStack, aStack, aStack, aStack, aStack, aStack, aStack, aStack) != null); + } else { + return RecipeMaps.packagerRecipes.containsInput(aStack); + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Charger.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Charger.java new file mode 100644 index 0000000000..de43fd715e --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Charger.java @@ -0,0 +1,110 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.GT_Values.V; + +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.BaseMetaTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicBatteryBuffer; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Charger extends GT_MetaTileEntity_BasicBatteryBuffer { + + public GT_MetaTileEntity_Charger(int aID, String aName, String aNameRegional, int aTier, String aDescription, + int aSlotCount) { + super(aID, aName, aNameRegional, aTier, aDescription, aSlotCount); + } + + public GT_MetaTileEntity_Charger(String aName, int aTier, String aDescription, ITexture[][][] aTextures, + int aSlotCount) { + super(aName, aTier, aDescription, aTextures, aSlotCount); + } + + public GT_MetaTileEntity_Charger(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures, + int aSlotCount) { + super(aName, aTier, aDescription, aTextures, aSlotCount); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Charger(mName, mTier, mDescriptionArray, mTextures, mInventory.length); + } + + @Override + public long getMinimumStoredEU() { + return V[mTier] * 64L * mInventory.length; + } + + @Override + public long maxEUStore() { + return V[mTier] * 256L * mInventory.length; + } + + @Override + public long maxAmperesIn() { + return Math.max(mChargeableCount * 8L, 4L); + } + + @Override + public long maxAmperesOut() { + return Math.max(mBatteryCount * 4L, 2L); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (this.getBaseMetaTileEntity() instanceof BaseMetaTileEntity) { + BaseMetaTileEntity mBaseMetaTileEntity = (BaseMetaTileEntity) getBaseMetaTileEntity(); + if (mBaseMetaTileEntity.getMetaTileEntity() instanceof MetaTileEntity mMetaTileEntity) { + // for (int t = 0; t < 6; t++) { + if (mMetaTileEntity.dechargerSlotCount() > 0 + && mBaseMetaTileEntity.getStoredEU() < mBaseMetaTileEntity.getEUCapacity()) { + for (int i = mMetaTileEntity.dechargerSlotStartIndex(), + k = mMetaTileEntity.dechargerSlotCount() + i; i < k; i++) { + if (mMetaTileEntity.mInventory[i] != null + && mBaseMetaTileEntity.getStoredEU() < mBaseMetaTileEntity.getEUCapacity()) { + mBaseMetaTileEntity.increaseStoredEnergyUnits( + GT_ModHandler.dischargeElectricItem( + mMetaTileEntity.mInventory[i], + GT_Utility.safeInt( + Math.min( + V[mTier] * 15, + mBaseMetaTileEntity.getEUCapacity() + - mBaseMetaTileEntity.getStoredEU())), + (int) Math.min(Integer.MAX_VALUE, mMetaTileEntity.getInputTier()), + true, + false, + false), + true); + if (mMetaTileEntity.mInventory[i].stackSize <= 0) mMetaTileEntity.mInventory[i] = null; + } + } + } + if (mMetaTileEntity.rechargerSlotCount() > 0 && mBaseMetaTileEntity.getStoredEU() > 0) { + for (int i = mMetaTileEntity.rechargerSlotStartIndex(), + k = mMetaTileEntity.rechargerSlotCount() + i; i < k; i++) { + if (mBaseMetaTileEntity.getStoredEU() > 0 && mMetaTileEntity.mInventory[i] != null) { + mBaseMetaTileEntity + .decreaseStoredEU( + GT_ModHandler.chargeElectricItem( + mMetaTileEntity.mInventory[i], + GT_Utility + .safeInt(Math.min(V[mTier] * 15, mBaseMetaTileEntity.getStoredEU())), + (int) Math.min(Integer.MAX_VALUE, mMetaTileEntity.getOutputTier()), + true, + false), + true); + if (mMetaTileEntity.mInventory[i].stackSize <= 0) mMetaTileEntity.mInventory[i] = null; + } + } + // } + } + } + } + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_IndustrialApiary.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_IndustrialApiary.java new file mode 100644 index 0000000000..50f544334c --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_IndustrialApiary.java @@ -0,0 +1,1560 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.GT_Values.AuthorKuba; +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_INDUSTRIAL_APIARY; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_INDUSTRIAL_APIARY_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_INDUSTRIAL_APIARY_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_INDUSTRIAL_APIARY_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_INDUSTRIAL_APIARY; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_INDUSTRIAL_APIARY_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_INDUSTRIAL_APIARY_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_INDUSTRIAL_APIARY_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_INDUSTRIAL_APIARY; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_INDUSTRIAL_APIARY_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_INDUSTRIAL_APIARY_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_INDUSTRIAL_APIARY_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_INDUSTRIAL_APIARY; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_INDUSTRIAL_APIARY_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_INDUSTRIAL_APIARY_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_INDUSTRIAL_APIARY_GLOW; +import static gregtech.api.metatileentity.BaseTileEntity.STALLED_STUTTERING_TOOLTIP; +import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; +import static gregtech.api.util.GT_Utility.moveMultipleItemStacks; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraftforge.common.util.ForgeDirection; + +import com.google.common.collect.ImmutableSet; +import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.forge.IItemHandlerModifiable; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.screen.ModularUIContext; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.builder.UIInfo; +import com.gtnewhorizons.modularui.common.internal.wrapper.BaseSlot; +import com.gtnewhorizons.modularui.common.internal.wrapper.ModularUIContainer; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.CycleButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.SlotGroup; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; +import com.mojang.authlib.GameProfile; + +import forestry.api.apiculture.BeeManager; +import forestry.api.apiculture.EnumBeeChromosome; +import forestry.api.apiculture.EnumBeeType; +import forestry.api.apiculture.FlowerManager; +import forestry.api.apiculture.IAlleleBeeAcceleratableEffect; +import forestry.api.apiculture.IAlleleBeeEffect; +import forestry.api.apiculture.IAlleleBeeSpecies; +import forestry.api.apiculture.IApiaristTracker; +import forestry.api.apiculture.IBee; +import forestry.api.apiculture.IBeeGenome; +import forestry.api.apiculture.IBeeHousing; +import forestry.api.apiculture.IBeeHousingInventory; +import forestry.api.apiculture.IBeeListener; +import forestry.api.apiculture.IBeeModifier; +import forestry.api.apiculture.IBeeRoot; +import forestry.api.apiculture.IBeekeepingLogic; +import forestry.api.apiculture.IBeekeepingMode; +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.core.BiomeHelper; +import forestry.api.core.EnumHumidity; +import forestry.api.core.EnumTemperature; +import forestry.api.core.ForestryAPI; +import forestry.api.core.IErrorLogic; +import forestry.api.core.IErrorState; +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IEffectData; +import forestry.api.genetics.IIndividual; +import forestry.apiculture.genetics.Bee; +import forestry.apiculture.genetics.alleles.AlleleEffectThrottled; +import forestry.core.errors.EnumErrorCode; +import forestry.plugins.PluginApiculture; +import gregtech.GT_Mod; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.recipe.BasicUIProperties; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ApiaryModifier; +import gregtech.api.util.GT_ApiaryUpgrade; +import gregtech.api.util.GT_Utility; +import gregtech.common.GT_Client; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaTileEntity_IndustrialApiary extends GT_MetaTileEntity_BasicMachine + implements IBeeHousing, IBeeHousingInventory, IErrorLogic, IBeeModifier, IBeeListener, IAddUIWidgets { + + public static final int beeCycleLength = 550; + public static final int baseEUtUsage = 37; + private static final int queen = 5; + private static final int drone = 6; + private static final int upgradeSlot = drone + 1; + private static final int upgradeSlotCount = 4; + private static Field AlleleBeeEffectThrottledField; + + final IBeeRoot beeRoot = (IBeeRoot) AlleleManager.alleleRegistry.getSpeciesRoot("rootBees"); + + public int mSpeed = 0; + public boolean mLockedSpeed = true; + public boolean mAutoQueen = true; + + private ItemStack usedQueen = null; + private IBee usedQueenBee = null; + private IEffectData[] effectData = new IEffectData[2]; + + public GT_MetaTileEntity_IndustrialApiary(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 4, + new String[] { "BEES GOES BRRRR", EnumChatFormatting.GRAY + AuthorKuba, + "Effective production chance as a percent is", "2.8 * b^0.52 * (p + t)^0.52 * s^0.37", + "where b is the base production chance as a percent,", + "p is the production modifier (2 w/o upgrades, or 4 * 1.2^n with n production upgrades),", + "t is 8 for the industrial apiary, and", "s is the speed value for the bee", + "Outputs are generated at the end of every bee tick (...)", + "Primary outputs are rolled once with base chance, once with half base" }, + 6, + 9, + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_INDUSTRIAL_APIARY_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_INDUSTRIAL_APIARY_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_INDUSTRIAL_APIARY), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_INDUSTRIAL_APIARY_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_INDUSTRIAL_APIARY_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_INDUSTRIAL_APIARY_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_INDUSTRIAL_APIARY), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_INDUSTRIAL_APIARY_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_INDUSTRIAL_APIARY_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_INDUSTRIAL_APIARY_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_INDUSTRIAL_APIARY), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_INDUSTRIAL_APIARY_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_INDUSTRIAL_APIARY_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_INDUSTRIAL_APIARY_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_INDUSTRIAL_APIARY), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_INDUSTRIAL_APIARY_GLOW) + .glow() + .build())); + } + + public GT_MetaTileEntity_IndustrialApiary(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, 4, aDescription, aTextures, 6, 9); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_IndustrialApiary(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (aBaseMetaTileEntity.isClientSide()) return true; + if (!GT_Mod.gregtechproxy.mForceFreeFace) { + openGUI(aBaseMetaTileEntity, aPlayer); + return true; + } + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + if (aBaseMetaTileEntity.getAirAtSide(side)) { + openGUI(aBaseMetaTileEntity, aPlayer); + return true; + } + } + GT_Utility.sendChatToPlayer(aPlayer, "No free Side!"); + return true; + } + + private void openGUI(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + IndustrialApiaryUI.open( + aPlayer, + aBaseMetaTileEntity.getWorld(), + aBaseMetaTileEntity.getXCoord(), + aBaseMetaTileEntity.getYCoord(), + aBaseMetaTileEntity.getZCoord()); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setInteger("mSpeed", mSpeed); + aNBT.setBoolean("mLockedSpeed", mLockedSpeed); + aNBT.setBoolean("mAutoQueen", mAutoQueen); + if (usedQueen != null) aNBT.setTag("usedQueen", usedQueen.writeToNBT(new NBTTagCompound())); + aNBT.setBoolean("retrievingPollenInThisOperation", retrievingPollenInThisOperation); + aNBT.setInteger("pollinationDelay", pollinationDelay); + aNBT.setFloat("usedBeeLife", usedBeeLife); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + mSpeed = aNBT.getInteger("mSpeed"); + mLockedSpeed = aNBT.getBoolean("mLockedSpeed"); + if (aNBT.hasKey("mAutoQueen")) mAutoQueen = aNBT.getBoolean("mAutoQueen"); + if (aNBT.hasKey("usedQueen")) usedQueen = ItemStack.loadItemStackFromNBT(aNBT.getCompoundTag("usedQueen")); + retrievingPollenInThisOperation = aNBT.getBoolean("retrievingPollenInThisOperation"); + pollinationDelay = aNBT.getInteger("pollinationDelay"); + usedBeeLife = aNBT.getFloat("usedBeeLife"); + } + + boolean retrievingPollenInThisOperation = false; + IIndividual retrievedpollen = null; + int pollinationDelay = 100; + float usedBeeLife = 0f; + + @Override + public int checkRecipe() { + updateModifiers(); + if (canWork()) { + + final ItemStack queen = getQueen(); + usedQueen = queen.copy(); + if (beeRoot.getType(queen) == EnumBeeType.QUEEN) { + final IBee bee = beeRoot.getMember(queen); + usedQueenBee = bee; + + // LIFE CYCLES + + float mod = this.getLifespanModifier(null, null, 1.f); + final IBeekeepingMode mode = beeRoot.getBeekeepingMode(this.getWorld()); + final IBeeModifier beemodifier = mode.getBeeModifier(); + mod *= beemodifier.getLifespanModifier(null, null, 1.f); + final int h = bee.getHealth(); + mod = 1.f / mod; + final float cycles = h / mod; + + // PRODUCTS + + final HashMap<GT_Utility.ItemId, ItemStack> pollen = new HashMap<>(); + + if (isRetrievingPollen && floweringMod > 0f) { + final int icycles = (int) cycles + + (getWorld().rand.nextFloat() < (cycles - (float) ((int) cycles)) ? 1 : 0); + for (int z = 0; z < icycles; z++) { + final IIndividual p = bee.retrievePollen(this); + if (p != null) { + final ItemStack s = p.getGenome() + .getSpeciesRoot() + .getMemberStack(p, EnumGermlingType.POLLEN.ordinal()); + if (s != null) { + final GT_Utility.ItemId id = GT_Utility.ItemId.createNoCopy(s); + pollen.computeIfAbsent(id, k -> { + final ItemStack ns = s.copy(); + ns.stackSize = 0; + return ns; + }); + pollen.get(id).stackSize += s.stackSize; + } + } + } + } + + retrievedpollen = null; + retrievingPollenInThisOperation = isRetrievingPollen; + + final IBeeGenome genome = bee.getGenome(); + final IAlleleBeeSpecies primary = genome.getPrimary(); + final IAlleleBeeSpecies secondary = genome.getSecondary(); + + final float speed = genome.getSpeed(); + final float prodMod = getProductionModifier(null, 0f) + beemodifier.getProductionModifier(null, 0f); + + final HashMap<GT_Utility.ItemId, Float> drops = new HashMap<>(); + final HashMap<GT_Utility.ItemId, ItemStack> dropstacks = new HashMap<>(); + + for (Map.Entry<ItemStack, Float> entry : primary.getProductChances() + .entrySet()) { + final GT_Utility.ItemId id = GT_Utility.ItemId.createNoCopy(entry.getKey()); + drops.merge( + id, + Bee.getFinalChance(entry.getValue(), speed, prodMod, 8f) * (float) entry.getKey().stackSize + * cycles, + Float::sum); + dropstacks.computeIfAbsent(id, k -> entry.getKey()); + } + for (Map.Entry<ItemStack, Float> entry : secondary.getProductChances() + .entrySet()) { + final GT_Utility.ItemId id = GT_Utility.ItemId.createNoCopy(entry.getKey()); + drops.merge( + id, + Bee.getFinalChance(entry.getValue() / 2f, speed, prodMod, 8f) * (float) entry.getKey().stackSize + * cycles, + Float::sum); + dropstacks.computeIfAbsent(id, k -> entry.getKey()); + } + if (primary.isJubilant(genome, this) && secondary.isJubilant(genome, this)) + for (Map.Entry<ItemStack, Float> entry : primary.getSpecialtyChances() + .entrySet()) { + final GT_Utility.ItemId id = GT_Utility.ItemId.createNoCopy(entry.getKey()); + drops.merge( + id, + Bee.getFinalChance(entry.getValue(), speed, prodMod, 8f) + * (float) entry.getKey().stackSize + * cycles, + Float::sum); + dropstacks.computeIfAbsent(id, k -> entry.getKey()); + } + + int i = 0; + final int imax = mOutputItems.length; + + final IApiaristTracker breedingTracker = beeRoot.getBreedingTracker(getWorld(), getOwner()); + + if (!bee.canSpawn()) { + final ItemStack convert = new ItemStack(PluginApiculture.items.beePrincessGE); + final NBTTagCompound nbttagcompound = new NBTTagCompound(); + queen.writeToNBT(nbttagcompound); + convert.setTagCompound(nbttagcompound); + this.mOutputItems[i++] = convert; + } else { + final IBee b = bee.spawnPrincess(this); + if (b != null) { + final ItemStack princess = beeRoot.getMemberStack(b, EnumBeeType.PRINCESS.ordinal()); + breedingTracker.registerPrincess(b); + this.mOutputItems[i++] = princess; + } + final IBee[] d = bee.spawnDrones(this); + if (d != null && d.length > 0) { + final HashMap<GT_Utility.ItemId, ItemStack> drones = new HashMap<>(d.length); + for (IBee dr : d) { + final ItemStack drone = beeRoot.getMemberStack(dr, EnumBeeType.DRONE.ordinal()); + breedingTracker.registerDrone(dr); + final GT_Utility.ItemId drid = GT_Utility.ItemId.createNoCopy(drone); + if (drones.containsKey(drid)) drones.get(drid).stackSize += drone.stackSize; + else { + this.mOutputItems[i++] = drone; + drones.put(drid, drone); + } + } + } + } + + final int imin = i; + + setQueen(null); + + for (Map.Entry<GT_Utility.ItemId, Float> entry : drops.entrySet()) { + final ItemStack s = dropstacks.get(entry.getKey()) + .copy(); + s.stackSize = entry.getValue() + .intValue() + + (getWorld().rand.nextFloat() < (entry.getValue() - (float) entry.getValue() + .intValue()) ? 1 : 0); + if (s.stackSize > 0 && i < imax) while (true) { + if (s.stackSize <= s.getMaxStackSize()) { + this.mOutputItems[i++] = s; + break; + } else this.mOutputItems[i++] = s.splitStack(s.getMaxStackSize()); + if (i >= imax) break; + } + } + + for (ItemStack s : pollen.values()) if (i < imax) this.mOutputItems[i++] = s; + else break; + + // Overclock + + usedBeeLife = cycles * (float) beeCycleLength; + this.mMaxProgresstime = (int) usedBeeLife; + final int timemaxdivider = this.mMaxProgresstime / 100; + final int useddivider = 1 << this.mSpeed; + int actualdivider = useddivider; + this.mMaxProgresstime /= Math.min(actualdivider, timemaxdivider); + actualdivider /= Math.min(actualdivider, timemaxdivider); + for (i--; i >= imin; i--) this.mOutputItems[i].stackSize *= actualdivider; + + pollinationDelay = Math.max((int) (this.mMaxProgresstime / cycles), 20); // don't run too often + + this.mProgresstime = 0; + this.mEUt = (int) ((float) baseEUtUsage * this.energyMod * useddivider); + if (useddivider == 2) this.mEUt += 32; + else if (useddivider > 2) this.mEUt += (32 * (useddivider << (this.mSpeed - 2))); + } else { + // Breeding time + + retrievingPollenInThisOperation = true; // Don't pollinate when breeding + + this.mMaxProgresstime = 100; + this.mProgresstime = 0; + final int useddivider = Math.min(100, 1 << this.mSpeed); + this.mMaxProgresstime /= useddivider; + this.mEUt = (int) ((float) baseEUtUsage * this.energyMod * useddivider); + if (useddivider == 2) this.mEUt += 32; + else if (useddivider > 2) this.mEUt += (32 * (useddivider << (this.mSpeed - 2))); + + final IBee princess = beeRoot.getMember(getQueen()); + usedQueenBee = princess; + final IBee drone = beeRoot.getMember(getDrone()); + princess.mate(drone); + final NBTTagCompound nbttagcompound = new NBTTagCompound(); + princess.writeToNBT(nbttagcompound); + this.mOutputItems[0] = new ItemStack(PluginApiculture.items.beeQueenGE); + this.mOutputItems[0].setTagCompound(nbttagcompound); + beeRoot.getBreedingTracker(getWorld(), getOwner()) + .registerQueen(princess); + + setQueen(null); + getDrone().stackSize -= 1; + if (getDrone().stackSize == 0) setDrone(null); + } + + return FOUND_AND_SUCCESSFULLY_USED_RECIPE; + } + + return DID_NOT_FIND_RECIPE; + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + updateModifiers(); + } + + @Override + protected boolean hasEnoughEnergyToCheckRecipe() { + return getBaseMetaTileEntity().isUniversalEnergyStored(V[mSpeed] * 8L); + } + + @Override + public long maxAmperesIn() { + return 4L; + } + + private void doEffect() { + final IBeeGenome genome = usedQueenBee.getGenome(); + final IAlleleBeeEffect effect = genome.getEffect(); + if (!(effect instanceof IAlleleBeeAcceleratableEffect)) { + effectData[0] = effect.validateStorage(effectData[0]); + effect.doEffect(genome, effectData[0], this); + } + + if (!effect.isCombinable()) return; + + final IAlleleBeeEffect secondary = (IAlleleBeeEffect) genome.getInactiveAllele(EnumBeeChromosome.EFFECT); + if (!secondary.isCombinable()) return; + + if (!(secondary instanceof IAlleleBeeAcceleratableEffect)) { + effectData[1] = secondary.validateStorage(effectData[1]); + secondary.doEffect(genome, effectData[1], this); + } + } + + private void doAcceleratedEffects() { + final IBeeGenome genome = usedQueenBee.getGenome(); + final IAlleleBeeEffect effect = genome.getEffect(); + try { + if (AlleleBeeEffectThrottledField == null) { + AlleleBeeEffectThrottledField = AlleleEffectThrottled.class.getDeclaredField("throttle"); + AlleleBeeEffectThrottledField.setAccessible(true); + } + if (effect instanceof IAlleleBeeAcceleratableEffect) { + effectData[0] = effect.validateStorage(effectData[0]); + effectData[0] = ((IAlleleBeeAcceleratableEffect) effect).doEffectAccelerated( + genome, + effectData[0], + this, + usedBeeLife / (effect instanceof AlleleEffectThrottled + ? (float) AlleleBeeEffectThrottledField.getInt(effect) + : 1f)); + } + + if (!effect.isCombinable()) return; + + final IAlleleBeeEffect secondary = (IAlleleBeeEffect) genome.getInactiveAllele(EnumBeeChromosome.EFFECT); + if (!secondary.isCombinable()) return; + + if (secondary instanceof IAlleleBeeAcceleratableEffect) { + effectData[1] = secondary.validateStorage(effectData[1]); + effectData[1] = ((IAlleleBeeAcceleratableEffect) secondary).doEffectAccelerated( + genome, + effectData[0], + this, + usedBeeLife / (secondary instanceof AlleleEffectThrottled + ? (float) AlleleBeeEffectThrottledField.getInt(secondary) + : 1f)); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isClientSide()) { + if (GT_Client.changeDetected == 4) { + /* + * Client tick counter that is set to 5 on hiding pipes and covers. It triggers a texture update next + * client tick when reaching 4, with provision for 3 more update tasks, spreading client change + * detection related work and network traffic on different ticks, until it reaches 0. + */ + aBaseMetaTileEntity.issueTextureUpdate(); + } + if (aBaseMetaTileEntity.isActive()) { + if (usedQueen != null) { + if (aTick % 2 == 0) { + // FX on client, effect on server + final IBee bee = beeRoot.getMember(usedQueen); + effectData = bee.doFX(effectData, this); + } + } + } + } + if (aBaseMetaTileEntity.isServerSide()) { + + mCharge = aBaseMetaTileEntity.getStoredEU() / 2 > aBaseMetaTileEntity.getEUCapacity() / 3; + mDecharge = aBaseMetaTileEntity.getStoredEU() < aBaseMetaTileEntity.getEUCapacity() / 3; + + doDisplayThings(); + + if (!aBaseMetaTileEntity.isActive()) { + if (aBaseMetaTileEntity.isAllowedToWork() + && (aBaseMetaTileEntity.hasInventoryBeenModified() || aTick % 600 == 0 + || aBaseMetaTileEntity.hasWorkJustBeenEnabled()) + && hasEnoughEnergyToCheckRecipe()) { + final int check = checkRecipe(); + if (check == FOUND_AND_SUCCESSFULLY_USED_RECIPE) { + aBaseMetaTileEntity.setActive(true); + } + } + } else { + + if (this.mProgresstime < 0) { + this.mProgresstime++; + return; + } + if (this.mStuttering) { + if (!aBaseMetaTileEntity.isAllowedToWork()) return; + if (aTick % 100 == 0) this.mStuttering = false; + return; + } + if (this.hasErrors()) { + if (!aBaseMetaTileEntity.isAllowedToWork()) return; + if (aTick % 100 == 0) if (!canWork(usedQueen)) this.stutterProcess(); + return; + } + + if (!drainEnergyForProcess(this.mEUt)) { + this.mStuttering = true; + this.stutterProcess(); + return; + } + this.mProgresstime++; + if (usedQueen != null) { + if (usedQueenBee == null) usedQueenBee = beeRoot.getMember(usedQueen); + doEffect(); + if (!retrievingPollenInThisOperation && floweringMod > 0f + && this.mProgresstime % pollinationDelay == 0) { + if (retrievedpollen == null) retrievedpollen = usedQueenBee.retrievePollen(this); + if (retrievedpollen != null && (usedQueenBee.pollinateRandom(this, retrievedpollen) + || this.mProgresstime % (pollinationDelay * 5) == 0)) retrievedpollen = null; + } + } + + if (this.mProgresstime % 100 == 0) { + if (!canWork(usedQueen)) { + this.stutterProcess(); + return; + } + } + + if (this.mProgresstime >= this.mMaxProgresstime) { + if (usedQueenBee != null) doAcceleratedEffects(); + updateModifiers(); + for (int i = 0; i < mOutputItems.length; i++) + if (mOutputItems[i] != null) for (int j = 0; j < mOutputItems.length; j++) { + if (j == 0 && isAutomated) { + if (beeRoot.isMember(mOutputItems[i], EnumBeeType.QUEEN.ordinal()) + || beeRoot.isMember(mOutputItems[i], EnumBeeType.PRINCESS.ordinal())) { + if (aBaseMetaTileEntity.addStackToSlot(queen, mOutputItems[i])) break; + } else if (beeRoot.isMember(mOutputItems[i], EnumBeeType.DRONE.ordinal())) + if (aBaseMetaTileEntity.addStackToSlot(drone, mOutputItems[i])) break; + } else if (mAutoQueen && i == 0 + && j == 0 + && beeRoot.isMember(mOutputItems[0], EnumBeeType.QUEEN.ordinal()) + && aBaseMetaTileEntity.addStackToSlot(queen, mOutputItems[0])) break; + if (aBaseMetaTileEntity + .addStackToSlot(getOutputSlot() + ((j + i) % mOutputItems.length), mOutputItems[i])) + break; + } + Arrays.fill(mOutputItems, null); + mEUt = 0; + mProgresstime = 0; + mMaxProgresstime = 0; + mStuttering = false; + aBaseMetaTileEntity.setActive(false); + + if (doesAutoOutput() && !isOutputEmpty() && aBaseMetaTileEntity.getFrontFacing() != mMainFacing) { + final TileEntity tTileEntity2 = aBaseMetaTileEntity + .getTileEntityAtSide(aBaseMetaTileEntity.getFrontFacing()); + final long tStoredEnergy = aBaseMetaTileEntity.getUniversalEnergyStored(); + int tMaxStacks = (int) (tStoredEnergy / 64L); + if (tMaxStacks > mOutputItems.length) tMaxStacks = mOutputItems.length; + + moveMultipleItemStacks( + aBaseMetaTileEntity, + tTileEntity2, + aBaseMetaTileEntity.getFrontFacing(), + aBaseMetaTileEntity.getBackFacing(), + null, + false, + (byte) 64, + (byte) 1, + (byte) 64, + (byte) 1, + tMaxStacks); + } + + if (aBaseMetaTileEntity.isAllowedToWork() && checkRecipe() == FOUND_AND_SUCCESSFULLY_USED_RECIPE) + aBaseMetaTileEntity.setActive(true); + } + } + } + } + + public void cancelProcess() { + if (this.getBaseMetaTileEntity() + .isActive() + && this.getBaseMetaTileEntity() + .isServerSide() + && usedQueen != null + && beeRoot.isMember(usedQueen, EnumBeeType.QUEEN.ordinal())) { + Arrays.fill(mOutputItems, null); + mEUt = 0; + mProgresstime = 0; + mMaxProgresstime = 0; + mStuttering = false; + this.getBaseMetaTileEntity() + .setActive(false); + setQueen(usedQueen); + this.getBaseMetaTileEntity() + .disableWorking(); + } + } + + @Override + public boolean isItemValidForSlot(int aIndex, ItemStack aStack) { + if (aStack == null) return false; + if (aIndex < getInputSlot()) return true; + if (aIndex == queen) return beeRoot.isMember(aStack, EnumBeeType.QUEEN.ordinal()) + || beeRoot.isMember(aStack, EnumBeeType.PRINCESS.ordinal()); + else if (aIndex == drone) return beeRoot.isMember(aStack, EnumBeeType.DRONE.ordinal()); + else if (aIndex < getOutputSlot()) { + if (!GT_ApiaryUpgrade.isUpgrade(aStack)) return false; + for (int i = upgradeSlot; i < upgradeSlot + upgradeSlotCount; i++) { + if (aIndex == i) continue; + final ItemStack s = getStackInSlot(i); + if (s == null) continue; + if (GT_Utility.areStacksEqual(getStackInSlot(i), aStack)) return false; + if (GT_ApiaryUpgrade.isUpgrade(aStack)) { + if (!GT_ApiaryUpgrade.getUpgrade(aStack) + .isAllowedToWorkWith(getStackInSlot(i))) return false; + } else if (GT_ApiaryUpgrade.isUpgrade(s)) { + if (!GT_ApiaryUpgrade.getUpgrade(s) + .isAllowedToWorkWith(aStack)) return false; + } + } + return true; + } else return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + if (!super.allowPutStack(aBaseMetaTileEntity, aIndex, side, aStack)) return false; + return isItemValidForSlot(aIndex, aStack); + } + + @Override + public void setInventorySlotContents(int aIndex, ItemStack aStack) { + if (aIndex == queen && aStack != null && getBaseMetaTileEntity().isClientSide()) usedQueen = aStack.copy(); + super.setInventorySlotContents(aIndex, aStack); + } + + // Gets called on slot click // + public void onInventoryUpdate(int aIndex) { + if (aIndex > drone && aIndex < getOutputSlot()) updateModifiers(); + } + + public ItemStack getUsedQueen() { + return usedQueen; + } + + // region IBeeHousing + + @Override + public Iterable<IBeeModifier> getBeeModifiers() { + return Collections.singletonList(this); + } + + @Override + public Iterable<IBeeListener> getBeeListeners() { + return Collections.singletonList(this); + } + + @Override + public IBeeHousingInventory getBeeInventory() { + return this; + } + + @Override + public IBeekeepingLogic getBeekeepingLogic() { + return dummylogic; + } + + @Override + public int getBlockLightValue() { + return this.getBaseMetaTileEntity() + .getLightLevelAtSide(ForgeDirection.UP); + } + + @Override + public boolean canBlockSeeTheSky() { + return this.getBaseMetaTileEntity() + .getSkyAtSide(ForgeDirection.UP); + } + + @Override + public World getWorld() { + return this.getBaseMetaTileEntity() + .getWorld(); + } + + GameProfile owner = null; + + @Override + public GameProfile getOwner() { + if (owner == null) owner = new GameProfile( + this.getBaseMetaTileEntity() + .getOwnerUuid(), + this.getBaseMetaTileEntity() + .getOwnerName()); + return owner; + } + + @Override + public Vec3 getBeeFXCoordinates() { + return Vec3.createVectorHelper( + getBaseMetaTileEntity().getXCoord() + 0.5, + getBaseMetaTileEntity().getYCoord() + 0.5, + getBaseMetaTileEntity().getZCoord() + 0.5); + } + + @Override + public BiomeGenBase getBiome() { + if (biomeOverride == null) return this.getBaseMetaTileEntity() + .getBiome(); + return biomeOverride; + } + + @Override + public EnumTemperature getTemperature() { + if (BiomeHelper.isBiomeHellish(getBiome())) return EnumTemperature.HELLISH; + return EnumTemperature.getFromValue(getBiome().temperature + temperatureMod); + } + + @Override + public EnumHumidity getHumidity() { + return EnumHumidity.getFromValue(getBiome().rainfall + humidityMod); + } + + @Override + public IErrorLogic getErrorLogic() { + return this; + } + + @Override + public ChunkCoordinates getCoordinates() { + return this.getBaseMetaTileEntity() + .getCoords(); + } + + // endregion + + // region IBeeHousingInventory + @Override + public ItemStack getQueen() { + return getStackInSlot(queen); + } + + @Override + public ItemStack getDrone() { + return getStackInSlot(drone); + } + + @Override + public void setQueen(ItemStack itemStack) { + setInventorySlotContents(queen, itemStack); + } + + @Override + public void setDrone(ItemStack itemStack) { + setInventorySlotContents(drone, itemStack); + } + + @Override + public boolean addProduct(ItemStack itemStack, boolean b) { + throw new RuntimeException("Should not happen :F"); + } + // endregion + + // region IErrorLogic + + public HashSet<IErrorState> mErrorStates = new HashSet<>(); + + @Override + public boolean setCondition(boolean b, IErrorState iErrorState) { + if (b) mErrorStates.add(iErrorState); + else mErrorStates.remove(iErrorState); + return b; + } + + @Override + public boolean contains(IErrorState iErrorState) { + return mErrorStates.contains(iErrorState); + } + + @Override + public boolean hasErrors() { + return !mErrorStates.isEmpty(); + } + + @Override + public void clearErrors() { + mErrorStates.clear(); + } + + @Override + public void writeData(DataOutputStream dataOutputStream) throws IOException { + dataOutputStream.write(mErrorStates.size()); + for (IErrorState s : mErrorStates) dataOutputStream.writeUTF(s.getUniqueName()); + } + + @Override + public void readData(DataInputStream dataInputStream) throws IOException { + for (int i = dataInputStream.readInt(); i > 0; i--) + mErrorStates.add(ForestryAPI.errorStateRegistry.getErrorState(dataInputStream.readUTF())); + } + + @Override + public ImmutableSet<IErrorState> getErrorStates() { + return ImmutableSet.copyOf(mErrorStates); + } + + private String flowerType = ""; + private ChunkCoordinates flowercoords = null; + private Block flowerBlock; + private int flowerBlockMeta; + + private boolean checkFlower(IBee bee) { + final String flowerType = bee.getGenome() + .getFlowerProvider() + .getFlowerType(); + if (!this.flowerType.equals(flowerType)) flowercoords = null; + if (flowercoords != null) { + if (getWorld().getBlock(flowercoords.posX, flowercoords.posY, flowercoords.posZ) != flowerBlock + || getWorld().getBlockMetadata(flowercoords.posX, flowercoords.posY, flowercoords.posZ) + != flowerBlockMeta) + if (!FlowerManager.flowerRegistry + .isAcceptedFlower(flowerType, getWorld(), flowercoords.posX, flowercoords.posY, flowercoords.posZ)) + flowercoords = null; + else { + flowerBlock = getWorld().getBlock(flowercoords.posX, flowercoords.posY, flowercoords.posZ); + flowerBlockMeta = getWorld() + .getBlockMetadata(flowercoords.posX, flowercoords.posY, flowercoords.posZ); + } + } + if (flowercoords == null) { + flowercoords = FlowerManager.flowerRegistry.getAcceptedFlowerCoordinates(this, bee, flowerType); + if (flowercoords != null) { + flowerBlock = getWorld().getBlock(flowercoords.posX, flowercoords.posY, flowercoords.posZ); + flowerBlockMeta = getWorld().getBlockMetadata(flowercoords.posX, flowercoords.posY, flowercoords.posZ); + this.flowerType = flowerType; + } + } + return flowercoords != null; + } + + private boolean canWork(ItemStack queen) { + clearErrors(); + if (queen == null) return true; // Reloaded the chunk ? + if (beeRoot.isMember(queen, EnumBeeType.PRINCESS.ordinal())) return true; + final IBee bee = beeRoot.getMember(queen); + for (IErrorState err : bee.getCanWork(this)) setCondition(true, err); + setCondition(!checkFlower(bee), EnumErrorCode.NO_FLOWER); + return !hasErrors(); + } + + private boolean canWork() { + clearErrors(); + final EnumBeeType beeType = beeRoot.getType(getQueen()); + if (beeType == EnumBeeType.PRINCESS) { + setCondition(!beeRoot.isDrone(getDrone()), EnumErrorCode.NO_DRONE); + return !hasErrors(); + } + if (beeType == EnumBeeType.QUEEN) { + final IBee bee = beeRoot.getMember(getQueen()); + for (IErrorState err : bee.getCanWork(this)) setCondition(true, err); + setCondition(!checkFlower(bee), EnumErrorCode.NO_FLOWER); + return !hasErrors(); + } else { + setCondition(true, EnumErrorCode.NO_QUEEN); + return false; + } + } + + // endregion + + // region IBeeModifier + + private float terrorityMod = 1f; + private float mutationMod = 1f; + private float lifespanMod = 1f; + private float productionMod = 2f; + private float floweringMod = 1f; + private float geneticDecayMod = 1f; + private float energyMod = 1f; + private boolean sealedMod = false; + private boolean selfLightedMod = false; + private boolean selfUnlightedMod = false; + private boolean sunlightSimulatedMod = false; + private BiomeGenBase biomeOverride = null; + private float humidityMod = 0f; + private float temperatureMod = 0f; + private boolean isAutomated = false; + private boolean isRetrievingPollen = false; + private int maxspeed = 0; + + public void updateModifiers() { + final GT_ApiaryModifier mods = new GT_ApiaryModifier(); + for (int i = 0; i < upgradeSlotCount; i++) { + final ItemStack s = getStackInSlot(upgradeSlot + i); + if (s == null) continue; + if (GT_ApiaryUpgrade.isUpgrade(s)) { + final GT_ApiaryUpgrade upgrade = GT_ApiaryUpgrade.getUpgrade(s); + upgrade.applyModifiers(mods, s); + } + } + + terrorityMod = mods.territory; + mutationMod = mods.mutation; + lifespanMod = mods.lifespan; + productionMod = mods.production; + floweringMod = mods.flowering; + geneticDecayMod = mods.geneticDecay; + energyMod = mods.energy; + sealedMod = mods.isSealed; + selfLightedMod = mods.isSelfLighted; + selfUnlightedMod = mods.isSelfUnlighted; + sunlightSimulatedMod = mods.isSunlightSimulated; + biomeOverride = mods.biomeOverride; + humidityMod = mods.humidity; + temperatureMod = mods.temperature; + isAutomated = mods.isAutomated; + isRetrievingPollen = mods.isCollectingPollen; + maxspeed = mods.maxSpeed; + + if (mLockedSpeed) mSpeed = maxspeed; + else mSpeed = Math.min(mSpeed, maxspeed); + } + + /** Tries to move as much of [stack] into a possible upgrade slot */ + public void addUpgrade(ItemStack stack) { + if (stack == null || !GT_ApiaryUpgrade.isUpgrade(stack)) return; + + int amount = stack.stackSize; + for (int i = upgradeSlot; i < upgradeSlot + upgradeSlotCount; i++) { + if (!isItemValidForSlot(i, stack)) continue; + + int maxStackSize = GT_ApiaryUpgrade.getUpgrade(stack) + .getMaxNumber(); + ItemStack stackInSlot = getStackInSlot(i); + + // Push into empty slot + if (stackInSlot == null) { + amount = Math.min(amount, maxStackSize); + setInventorySlotContents(i, stack.splitStack(amount)); + return; + } + + if (!GT_Utility.areStacksEqual(stack, stackInSlot)) continue; + amount = Math.max(Math.min(amount, maxStackSize - stackInSlot.stackSize), 0); + if (amount == 0) return; + stackInSlot.stackSize += amount; + stack.stackSize -= amount; + return; + } + } + + /** Returns installed upgrade in slot 0 <= [index] < getMaxUpgradeCount() */ + public ItemStack getUpgrade(int index) { + if (index < 0 || index >= upgradeSlotCount) return null; + return getStackInSlot(upgradeSlot + index); + } + + /** Tries to remove [amount] or less of the upgrade installed in slot [index]. Returns the removed ItemStack */ + public ItemStack removeUpgrade(int index, int amount) { + if (index < 0 || index >= upgradeSlotCount || amount <= 0) return null; + + ItemStack stackInSlot = getUpgrade(index); + if (stackInSlot == null) return null; + + amount = Math.min(amount, stackInSlot.stackSize); + ItemStack result = stackInSlot.splitStack(amount); + if (stackInSlot.stackSize <= 0) setInventorySlotContents(upgradeSlot + index, null); + return result; + } + + public static int getMaxUpgradeCount() { + return upgradeSlotCount; + } + + @Override + public float getTerritoryModifier(IBeeGenome iBeeGenome, float v) { + return Math.min(5, terrorityMod); + } + + @Override + public float getMutationModifier(IBeeGenome iBeeGenome, IBeeGenome iBeeGenome1, float v) { + return mutationMod; + } + + @Override + public float getLifespanModifier(IBeeGenome iBeeGenome, IBeeGenome iBeeGenome1, float v) { + return lifespanMod; + } + + @Override + public float getProductionModifier(IBeeGenome iBeeGenome, float v) { + return productionMod; + } + + @Override + public float getFloweringModifier(IBeeGenome iBeeGenome, float v) { + return floweringMod; + } + + @Override + public float getGeneticDecay(IBeeGenome iBeeGenome, float v) { + return geneticDecayMod; + } + + public float getEnergyModifier() { + return energyMod; + } + + @Override + public boolean isSealed() { + return sealedMod; + } + + @Override + public boolean isSelfLighted() { + return selfLightedMod; + } + + @Override + public boolean isSelfUnlighted() { + return selfUnlightedMod; + } + + @Override + public boolean isSunlightSimulated() { + return sunlightSimulatedMod; + } + + @Override + public boolean isHellish() { + return getBiome() == BiomeGenBase.hell; + } + + public int getMaxSpeed() { + return maxspeed; + } + + // endregion + + // region IBeeListener + + @Override + public void wearOutEquipment(int i) {} + + @Override + public void onQueenDeath() {} + + @Override + public boolean onPollenRetrieved(IIndividual iIndividual) { + return false; + } + + // endregion + + static final IBeekeepingLogic dummylogic = new IBeekeepingLogic() { + + @Override + public boolean canWork() { + return true; + } + + @Override + public void doWork() {} + + @Override + public void syncToClient() {} + + @Override + public void syncToClient(EntityPlayerMP entityPlayerMP) {} + + @Override + public int getBeeProgressPercent() { + return 0; + } + + @Override + public boolean canDoBeeFX() { + return false; + } + + @Override + public void doBeeFX() {} + + @Override + public void readFromNBT(NBTTagCompound nbtTagCompound) {} + + @Override + public void writeToNBT(NBTTagCompound nbtTagCompound) {} + }; + + private static final String POWER_SOURCE_POWER = "GT5U.machines.powersource.power", + CANCEL_PROCESS_TOOLTIP = "GT5U.machines.industrialapiary.cancel.tooltip", + SPEED_TOOLTIP = "GT5U.machines.industrialapiary.speed.tooltip", + SPEED_LOCKED_TOOLTIP = "GT5U.machines.industrialapiary.speedlocked.tooltip", + INFO_TOOLTIP = "GT5U.machines.industrialapiary.info.tooltip", + INFO_WITH_BEE_TOOLTIP = "GT5U.machines.industrialapiary.infoextended.tooltip", + UPGRADE_TOOLTIP = "GT5U.machines.industrialapiary.upgradeslot.tooltip", + AUTOQUEEN_TOOLTIP = "GT5U.machines.industrialapiary.autoqueen.tooltip"; + + @Override + public boolean useModularUI() { + return true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + builder + .widget( + new SlotWidget(new ApiarySlot(inventoryHandler, queen)) + .setBackground(getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_BEE_QUEEN) + .setPos(36, 21)) + .widget( + new SlotWidget(new ApiarySlot(inventoryHandler, drone)) + .setBackground(getGUITextureSet().getItemSlot(), GT_UITextures.OVERLAY_SLOT_BEE_DRONE) + .setPos(36, 41)) + .widget( + SlotGroup.ofItemHandler(inventoryHandler, 2) + .startFromSlot(7) + .endAtSlot(10) + .slotCreator(i -> new ApiarySlot(inventoryHandler, i)) + .applyForWidget( + widget -> widget.setGTTooltip(() -> mTooltipCache.getData(UPGRADE_TOOLTIP)) + .setTooltipShowUpDelay(TOOLTIP_DELAY)) + .build() + .setPos(61, 23)); + + super.addUIWidgets(builder, buildContext); + + builder.widget( + new ButtonWidget().setOnClick((clickData, widget) -> cancelProcess()) + .setBackground(GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_CROSS) + .setGTTooltip(() -> mTooltipCache.getData(CANCEL_PROCESS_TOOLTIP)) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setPos(7, 26) + .setSize(18, 18)) + .widget( + new CycleButtonWidget().setToggle(() -> mAutoQueen, x -> mAutoQueen = x) + .setTextureGetter( + i -> i == 0 ? GT_UITextures.OVERLAY_BUTTON_CROSS : GT_UITextures.OVERLAY_BUTTON_CHECKMARK) + .setGTTooltip(() -> mTooltipCache.getData(AUTOQUEEN_TOOLTIP)) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setPos(7, 44) + .setSize(18, 18) + .setBackground(GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_SLOT_BEE_QUEEN)) + .widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_INFORMATION) + .setGTTooltip(() -> { + final String energyreq = GT_Utility.formatNumbers( + (int) ((float) GT_MetaTileEntity_IndustrialApiary.baseEUtUsage * getEnergyModifier() + * getAcceleration()) + getAdditionalEnergyUsage()); + final String Temp = StatCollector.translateToLocal(getTemperature().getName()); + final String Hum = StatCollector.translateToLocal(getHumidity().getName()); + if (getUsedQueen() != null + && BeeManager.beeRoot.isMember(getUsedQueen(), EnumBeeType.QUEEN.ordinal())) { + final IBee bee = BeeManager.beeRoot.getMember(getUsedQueen()); + if (bee.isAnalyzed()) { + final IBeeGenome genome = bee.getGenome(); + final IBeeModifier mod = BeeManager.beeRoot.getBeekeepingMode(getWorld()) + .getBeeModifier(); + final float tmod = getTerritoryModifier(null, 1f) * mod.getTerritoryModifier(null, 1f); + final int[] t = Arrays.stream(genome.getTerritory()) + .map(i -> (int) ((float) i * tmod)) + .toArray(); + return mTooltipCache.getUncachedTooltipData( + INFO_WITH_BEE_TOOLTIP, + energyreq, + Temp, + Hum, + genome.getSpeed(), + getProductionModifier(null, 0f) + mod.getProductionModifier(null, 0f), + Math.round( + getFloweringModifier(null, 1f) * genome.getFlowering() + * mod.getFloweringModifier(null, 1f)), + Math.round( + getLifespanModifier(null, null, 1f) * genome.getLifespan() + * mod.getLifespanModifier(null, null, 1f)), + t[0], + t[1], + t[2]); + } + } + return mTooltipCache.getUncachedTooltipData(INFO_TOOLTIP, energyreq, Temp, Hum); + }) + .attachSyncer( + new FakeSyncWidget.ItemStackSyncer(() -> usedQueen, val -> usedQueen = val), + builder, + (widget, val) -> widget.notifyTooltipChange()) + .setPos(163, 5) + .setSize(7, 18)) + .widget(new ButtonWidget().setOnClick((clickData, widget) -> { + if (clickData.mouseButton == 0) { + if (mLockedSpeed) return; + if (!clickData.shift) { + mSpeed++; + if (mSpeed > getMaxSpeed()) mSpeed = 0; + } else { + mSpeed--; + if (mSpeed < 0) mSpeed = getMaxSpeed(); + } + } else if (clickData.mouseButton == 1) { + mLockedSpeed = !mLockedSpeed; + if (mLockedSpeed) mSpeed = getMaxSpeed(); + } + }) + .setGTTooltip( + () -> mTooltipCache.getUncachedTooltipData( + mLockedSpeed ? SPEED_LOCKED_TOOLTIP : SPEED_TOOLTIP, + getAcceleration(), + GT_Utility.formatNumbers(getAdditionalEnergyUsage()))) + .attachSyncer( + new FakeSyncWidget.IntegerSyncer(() -> mSpeed, val -> mSpeed = val), + builder, + (widget, val) -> widget.notifyTooltipChange()) + .attachSyncer( + new FakeSyncWidget.BooleanSyncer(() -> mLockedSpeed, val -> mLockedSpeed = val), + builder, + (widget, val) -> widget.notifyTooltipChange()) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setBackground(GT_UITextures.PICTURE_SQUARE_LIGHT_GRAY) + .setPos(25, 62) + .setSize(18, 18)) + .widget( + new TextWidget("x").setDefaultColor(COLOR_TEXT_GRAY.get()) + .setPos(30, 63)) + .widget( + TextWidget.dynamicString(() -> String.valueOf(1 << mSpeed)) + // mSpeed is already synced + .setSynced(false) + .setDefaultColor(COLOR_TEXT_GRAY.get()) + .setPos(26, 72)); + } + + private static final FallbackableUITexture progressBarTexture = GT_UITextures + .fallbackableProgressbar("iapiary", GT_UITextures.PROGRESSBAR_ARROW); + + @Override + protected BasicUIProperties getUIProperties() { + return super.getUIProperties().toBuilder() + .progressBarTexture(progressBarTexture) + .progressBarPos(new Pos2d(70, 3)) + .build(); + } + + @Override + protected SlotWidget createItemInputSlot(int index, IDrawable[] backgrounds, Pos2d pos) { + // we have custom input slots + return null; + } + + @Override + protected CycleButtonWidget createItemAutoOutputButton() { + return (CycleButtonWidget) super.createItemAutoOutputButton().setPos(7, 62); + } + + @Override + protected CycleButtonWidget createFluidAutoOutputButton() { + return null; + } + + @Override + protected SlotWidget createChargerSlot(int x, int y, String tooltipKey, Object[] tooltipArgs) { + return (SlotWidget) super.createChargerSlot(x, y, tooltipKey, tooltipArgs).setPos(79, 62); + } + + @Override + protected DrawableWidget createErrorStatusArea(ModularWindow.Builder builder, IDrawable picture) { + return (DrawableWidget) super.createErrorStatusArea(builder, picture).setPos(100, 62) + .attachSyncer( + new FakeSyncWidget.ListSyncer<>(() -> Arrays.asList(mErrorStates.toArray(new IErrorState[0])), val -> { + mErrorStates.clear(); + mErrorStates.addAll(new HashSet<>(val)); + }, + (buffer, val) -> buffer.writeShort(val.getID()), + buffer -> ForestryAPI.errorStateRegistry.getErrorState(buffer.readShort())), + builder, + (widget, val) -> widget.notifyTooltipChange()); + } + + @Override + protected List<String> getErrorDescriptions() { + if (!mErrorStates.isEmpty()) { + return mErrorStates.stream() + .map(state -> EnumChatFormatting.RED + StatCollector.translateToLocal("for." + state.getDescription())) + .collect(Collectors.toList()); + } else if (mStuttering) { + return mTooltipCache + .getData(STALLED_STUTTERING_TOOLTIP, StatCollector.translateToLocal(POWER_SOURCE_POWER)).text; + } else { + return Collections.emptyList(); + } + } + + @Override + protected List<String> getErrorDescriptionsShift() { + // Don't show shift tooltip of "Progress was lost" + // as this machine does not lose progress + return getErrorDescriptions(); + } + + private int getAcceleration() { + return 1 << mSpeed; + } + + private int getAdditionalEnergyUsage() { + final int accelerated = getAcceleration(); + int energyusage = 0; + if (accelerated == 2) energyusage = 32; + else if (accelerated > 2) energyusage = 32 * accelerated << (mSpeed - 2); + return energyusage; + } + + private class ApiarySlot extends BaseSlot { + + public ApiarySlot(IItemHandlerModifiable inventory, int index) { + super(inventory, index); + } + + @Override + public boolean isItemValidPhantom(ItemStack stack) { + return super.isItemValidPhantom(stack) && getBaseMetaTileEntity().isItemValidForSlot(getSlotIndex(), stack); + } + + @Override + public void onSlotChanged() { + super.onSlotChanged(); + onInventoryUpdate(getSlotIndex()); + } + } + + private static final UIInfo<?, ?> IndustrialApiaryUI = GT_UIInfos.GTTileEntityUIFactory + .apply(GT_ModularUIContainer_IndustrialApiary::new); + + private static class GT_ModularUIContainer_IndustrialApiary extends ModularUIContainer { + + public GT_ModularUIContainer_IndustrialApiary(ModularUIContext context, ModularWindow mainWindow) { + super(context, mainWindow); + } + + private final int playerInventorySlot = 36; + + @Override + public ItemStack slotClick(int aSlotNumber, int aMouseclick, int aShifthold, EntityPlayer aPlayer) { + if (!(aSlotNumber >= playerInventorySlot + 2 && aSlotNumber < playerInventorySlot + 2 + 4)) + return super.slotClick(aSlotNumber, aMouseclick, aShifthold, aPlayer); + if (aShifthold == 5) return null; + if (aShifthold != 0) return super.slotClick(aSlotNumber, aMouseclick, aShifthold, aPlayer); + if (aMouseclick > 1) return super.slotClick(aSlotNumber, aMouseclick, aShifthold, aPlayer); + final ItemStack s = aPlayer.inventory.getItemStack(); + if (s == null) return super.slotClick(aSlotNumber, aMouseclick, aShifthold, aPlayer); + final Slot slot = getSlot(aSlotNumber); + final ItemStack slotStack = slot.getStack(); + if (slotStack != null && !GT_Utility.areStacksEqual(slotStack, s)) return null; // super would replace item + if (slotStack == null && !slot.isItemValid(s)) + return super.slotClick(aSlotNumber, aMouseclick, aShifthold, aPlayer); + if (!GT_ApiaryUpgrade.isUpgrade(s)) return super.slotClick(aSlotNumber, aMouseclick, aShifthold, aPlayer); + int max = GT_ApiaryUpgrade.getUpgrade(s) + .getMaxNumber(); + if (slotStack != null) max = Math.max(0, max - slotStack.stackSize); + max = Math.min(max, s.stackSize); + if (max == 0) return null; + if (aMouseclick == 1) max = 1; + if (max == s.stackSize) return super.slotClick(aSlotNumber, aMouseclick, aShifthold, aPlayer); + final ItemStack newStack = s.splitStack(s.stackSize - max); + final ItemStack result = super.slotClick(aSlotNumber, aMouseclick, aShifthold, aPlayer); + aPlayer.inventory.setItemStack(newStack); + return result; + } + + @Override + public ItemStack transferStackInSlot(EntityPlayer aPlayer, int aSlotIndex) { + final Slot s = getSlot(aSlotIndex); + if (s == null) return super.transferStackInSlot(aPlayer, aSlotIndex); + if (aSlotIndex >= playerInventorySlot) return super.transferStackInSlot(aPlayer, aSlotIndex); + final ItemStack aStack = s.getStack(); + if (aStack == null) return super.transferStackInSlot(aPlayer, aSlotIndex); + if (!GT_ApiaryUpgrade.isUpgrade(aStack)) return super.transferStackInSlot(aPlayer, aSlotIndex); + for (int i = playerInventorySlot + 2; i < playerInventorySlot + 2 + 4; i++) { + final Slot iSlot = getSlot(i); + final ItemStack iStack = iSlot.getStack(); + if (iStack == null) { + if (!iSlot.isItemValid(aStack)) continue; + } else { + if (!GT_Utility.areStacksEqual(aStack, iStack)) continue; + } + int max = GT_ApiaryUpgrade.getUpgrade(aStack) + .getMaxNumber(); + if (iStack == null) { + max = Math.min(max, aStack.stackSize); + final ItemStack newstack = aStack.splitStack(max); + iSlot.putStack(newstack); + } else { + max = Math.max(0, max - iStack.stackSize); + max = Math.min(max, aStack.stackSize); + iStack.stackSize += max; + aStack.stackSize -= max; + iSlot.onSlotChanged(); + } + if (aStack.stackSize == 0) s.putStack(null); + else s.onSlotChanged(); + break; + } + return null; + } + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + super.getWailaBody(itemStack, currenttip, accessor, config); + final NBTTagCompound tag = accessor.getNBTData(); + if (tag.hasKey("queen")) { + currenttip.add( + "Current Queen: " + EnumChatFormatting.GREEN + StatCollector.translateToLocal(tag.getString("queen"))); + } + if (tag.hasKey("dummyProduction")) { + currenttip.add( + "Effective Production: " + EnumChatFormatting.AQUA + + String.format("b^0.52 * %.2f", tag.getFloat("dummyProduction"))); + } + if (tag.hasKey("errors")) { + NBTTagCompound errorNbt = tag.getCompoundTag("errors"); + for (int i = 0; i < errorNbt.getInteger("size"); i++) { + currenttip.add( + "Error: " + EnumChatFormatting.RED + + StatCollector.translateToLocal("for." + errorNbt.getString("e" + i))); + } + } + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + super.getWailaNBTData(player, tile, tag, world, x, y, z); + if (usedQueen != null) { + IBeeGenome genome = beeRoot.getMember(usedQueen) + .getGenome(); + tag.setString( + "queen", + genome.getPrimary() + .getUnlocalizedName()); + float prodModifier = getProductionModifier(genome, 0f); + prodModifier += beeRoot.getBeekeepingMode(world) + .getBeeModifier() + .getProductionModifier(genome, prodModifier); + float dummyProduction = 100f * Bee.getFinalChance(0.01f, genome.getSpeed(), prodModifier, 8f); + tag.setFloat("dummyProduction", dummyProduction); + } + if (hasErrors()) { + NBTTagCompound errorNbt = new NBTTagCompound(); + int errorCounter = 0; + for (IErrorState error : mErrorStates) { + errorNbt.setString("e" + errorCounter++, error.getDescription()); + } + errorNbt.setInteger("size", errorCounter); + tag.setTag("errors", errorNbt); + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Massfabricator.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Massfabricator.java new file mode 100644 index 0000000000..07e9977429 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Massfabricator.java @@ -0,0 +1,243 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_MASSFAB; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_MASSFAB_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_MASSFAB_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_MASSFAB_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_MASSFAB; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_MASSFAB_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_MASSFAB_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_MASSFAB_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_MASSFAB; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_MASSFAB_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_MASSFAB_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_MASSFAB_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_MASSFAB; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_MASSFAB_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_MASSFAB_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_MASSFAB_GLOW; + +import java.util.Arrays; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraftforge.fluids.FluidStack; + +import com.google.common.primitives.Ints; + +import gregtech.api.enums.ConfigCategories; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.MachineType; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.objects.overclockdescriber.EUOverclockDescriber; +import gregtech.api.objects.overclockdescriber.OverclockDescriber; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Config; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.MethodsReturnNonnullByDefault; + +public class GT_MetaTileEntity_Massfabricator extends GT_MetaTileEntity_BasicMachine { + + public static int sUUAperUUM = 1; + public static int sUUASpeedBonus = 4; + public static int sDurationMultiplier = 3215; + public static boolean sRequiresUUA = false; + public static int BASE_EUT = 256; + public static GT_Recipe nonUUARecipe; + public static GT_Recipe uuaRecipe; + + public GT_MetaTileEntity_Massfabricator(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 8, + MachineType.MATTER_FABRICATOR.tooltipDescription(), + 1, + 1, + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_MASSFAB_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_MASSFAB_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_MASSFAB), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_MASSFAB_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_MASSFAB_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_MASSFAB_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_MASSFAB), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_MASSFAB_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_MASSFAB_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_MASSFAB_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_MASSFAB), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_MASSFAB_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_MASSFAB_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_MASSFAB_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_MASSFAB), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_MASSFAB_GLOW) + .glow() + .build())); + } + + public GT_MetaTileEntity_Massfabricator(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 8, aDescription, aTextures, 1, 1); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Massfabricator(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public boolean allowSelectCircuit() { + return true; + } + + @Override + protected OverclockDescriber createOverclockDescriber() { + return new MassfabricatorOverclockDescriber(mTier, mAmperage); + } + + @Override + public void onConfigLoad(GT_Config aConfig) { + super.onConfigLoad(aConfig); + sDurationMultiplier = aConfig + .get(ConfigCategories.machineconfig, "Massfabricator.UUM_Duration_Multiplier", sDurationMultiplier); + sUUAperUUM = aConfig.get(ConfigCategories.machineconfig, "Massfabricator.UUA_per_UUM", sUUAperUUM); + sUUASpeedBonus = aConfig.get(ConfigCategories.machineconfig, "Massfabricator.UUA_Speed_Bonus", sUUASpeedBonus); + sRequiresUUA = aConfig.get(ConfigCategories.machineconfig, "Massfabricator.UUA_Requirement", sRequiresUUA); + Materials.UUAmplifier.mChemicalFormula = ("Mass Fabricator Eff/Speed Bonus: x" + sUUASpeedBonus); + } + + @Override + public long maxAmperesIn() { + return 10; + } + + @Override + public long maxEUStore() { + return V[mTier] * 512L; + } + + @Override + public int checkRecipe() { + FluidStack tFluid = getDrainableStack(); + if ((tFluid == null) || (tFluid.amount < getCapacity())) { + this.mOutputFluid = Materials.UUMatter.getFluid(1L); + calculateCustomOverclock(containsUUA(getFillableStack()) ? uuaRecipe : nonUUARecipe); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + if (containsUUA(tFluid = getFillableStack())) { + tFluid.amount -= sUUAperUUM; + return FOUND_AND_SUCCESSFULLY_USED_RECIPE; + } + return sRequiresUUA || Arrays.stream(getAllInputs()) + .anyMatch(s -> ItemList.Circuit_Integrated.isStackEqual(s, true, true)) + ? FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS + : FOUND_AND_SUCCESSFULLY_USED_RECIPE; + } + return DID_NOT_FIND_RECIPE; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.massFabFakeRecipes; + } + + @Override + public boolean isFluidInputAllowed(FluidStack aFluid) { + return aFluid.isFluidEqual(Materials.UUAmplifier.getFluid(1L)); + } + + @Override + public int getCapacity() { + return Math.max(sUUAperUUM, 1000); + } + + private boolean containsUUA(FluidStack aFluid) { + return aFluid != null && aFluid.amount >= sUUAperUUM && aFluid.isFluidEqual(Materials.UUAmplifier.getFluid(1L)); + } + + @ParametersAreNonnullByDefault + @MethodsReturnNonnullByDefault + protected class MassfabricatorOverclockDescriber extends EUOverclockDescriber { + + protected MassfabricatorOverclockDescriber(byte tier, int amperage) { + super(tier, amperage); + } + + @Override + public GT_OverclockCalculator createCalculator(GT_OverclockCalculator template, GT_Recipe recipe) { + return super.createCalculator(template, recipe).setEUt(Ints.saturatedCast(V[tier] * amperage)) + .setEUtIncreasePerOC(1) + .limitOverclockCount(tier - 1) + .setOneTickDiscount(false); + } + + @Override + protected boolean shouldShowAmperage(GT_OverclockCalculator calculator) { + return true; + } + + @Override + protected String getVoltageString(GT_OverclockCalculator calculator) { + // standard amperage calculation doesn't work here + return decorateWithOverclockLabel(GT_Utility.formatNumbers(V[mTier]) + " EU/t", calculator) + + GT_Utility.getTierNameWithParentheses(V[mTier]); + } + + @Override + protected String getAmperageString(GT_OverclockCalculator calculator) { + int amperage = this.amperage; + int denominator = 1; + for (int i = 1; i < mTier; i++) { + amperage >>= 1; + if (amperage == 0) { + denominator <<= 1; + } + } + if (amperage > 0) { + return GT_Utility.formatNumbers(amperage); + } else { + return "1/" + denominator; + } + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_MicrowaveEnergyTransmitter.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_MicrowaveEnergyTransmitter.java new file mode 100644 index 0000000000..fc6afbd06f --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_MicrowaveEnergyTransmitter.java @@ -0,0 +1,501 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASINGS; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER_GLOW; + +import java.util.function.Consumer; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.world.World; +import net.minecraftforge.common.DimensionManager; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import com.gtnewhorizons.modularui.api.NumberFormatMUI; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.ConfigCategories; +import gregtech.api.enums.Materials; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.gui.modularui.GUITextureSet; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.modularui.IAddGregtechLogo; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IEnergyConnected; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.BaseMetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicTank; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Config; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_MicrowaveEnergyTransmitter extends GT_MetaTileEntity_BasicTank + implements IAddGregtechLogo, IAddUIWidgets { + + private static boolean sInterDimensionalTeleportAllowed = true; + private static int mMaxLoss = 50; + private static int mMaxLossDistance = 10000; + private static boolean mPassiveEnergyUse = true; + public int mTargetX = 0; + public int mTargetY = 0; + public int mTargetZ = 0; + public int mTargetD = 0; + public boolean mDebug = false; + public boolean hasBlock = false; + public int tTargetX = 0; + public int tTargetY = 0; + public int tTargetZ = 0; + public int tTargetD = 0; + public TileEntity tTile = null; + + public GT_MetaTileEntity_MicrowaveEnergyTransmitter(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 3, + new String[] { "Transmits Energy Wirelessly", "Use Nitrogen Plasma", "for Inter-dimensional transmission", + "0.004EU Loss per 100 Blocks" }); + } + + public GT_MetaTileEntity_MicrowaveEnergyTransmitter(String aName, int aTier, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, 3, aDescription, aTextures); + } + + public GT_MetaTileEntity_MicrowaveEnergyTransmitter(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, 3, aDescription, aTextures); + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (aBaseMetaTileEntity.isClientSide()) return true; + this.hasBlock = checkForBlock(); + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_MicrowaveEnergyTransmitter( + this.mName, + this.mTier, + this.mDescriptionArray, + this.mTextures); + } + + @Override + public String[] getInfoData() { + return new String[] { "Coordinates:", + "X: " + EnumChatFormatting.GREEN + GT_Utility.formatNumbers(this.mTargetX) + EnumChatFormatting.RESET, + "Y: " + EnumChatFormatting.GREEN + GT_Utility.formatNumbers(this.mTargetY) + EnumChatFormatting.RESET, + "Z: " + EnumChatFormatting.GREEN + GT_Utility.formatNumbers(this.mTargetZ) + EnumChatFormatting.RESET, + "Dimension: " + EnumChatFormatting.GREEN + this.mTargetD + EnumChatFormatting.RESET, + "Dimension Valid: " + (GT_Utility.isRealDimension(this.mTargetD) + ? EnumChatFormatting.GREEN + "Yes" + EnumChatFormatting.RESET + : EnumChatFormatting.RED + "No" + EnumChatFormatting.RESET), + "Dimension Registered: " + (DimensionManager.isDimensionRegistered(this.mTargetD) + ? EnumChatFormatting.GREEN + "Yes" + EnumChatFormatting.RESET + : EnumChatFormatting.RED + "No" + EnumChatFormatting.RESET) }; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == ForgeDirection.DOWN) return new ITexture[] { MACHINE_CASINGS[mTier][colorIndex + 1] }; + if (aActive) return new ITexture[] { MACHINE_CASINGS[mTier][colorIndex + 1], + TextureFactory.of(OVERLAY_TELEPORTER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_TELEPORTER_ACTIVE_GLOW) + .glow() + .build() }; + return new ITexture[] { MACHINE_CASINGS[mTier][colorIndex + 1], TextureFactory.of(OVERLAY_TELEPORTER), + TextureFactory.builder() + .addIcon(OVERLAY_TELEPORTER_GLOW) + .glow() + .build() }; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + if (mFluid != null) aNBT.setTag("mFluid", mFluid.writeToNBT(new NBTTagCompound())); + aNBT.setInteger("mTargetX", this.mTargetX); + aNBT.setInteger("mTargetY", this.mTargetY); + aNBT.setInteger("mTargetZ", this.mTargetZ); + aNBT.setInteger("mTargetD", this.mTargetD); + aNBT.setBoolean("mDebug", this.mDebug); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + mFluid = FluidStack.loadFluidStackFromNBT(aNBT.getCompoundTag("mFluid")); + this.mTargetX = aNBT.getInteger("mTargetX"); + this.mTargetY = aNBT.getInteger("mTargetY"); + this.mTargetZ = aNBT.getInteger("mTargetZ"); + this.mTargetD = aNBT.getInteger("mTargetD"); + this.mDebug = aNBT.getBoolean("mDebug"); + } + + @Override + public void onConfigLoad(GT_Config aConfig) { + sInterDimensionalTeleportAllowed = aConfig + .get(ConfigCategories.machineconfig, "Teleporter.Interdimensional", true); + mMaxLoss = Math.max(aConfig.get(ConfigCategories.machineconfig, "MicrowaveTransmitter.MaxLoss", 50), 11); + mMaxLossDistance = aConfig.get(ConfigCategories.machineconfig, "MicrowaveTransmitter.MaxLossDistance", 10000); + mPassiveEnergyUse = aConfig.get(ConfigCategories.machineconfig, "MicrowaveTransmitter.PassiveEnergy", true); + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + if (aBaseMetaTileEntity.isServerSide()) { + if ((this.mTargetX == 0) && (this.mTargetY == 0) && (this.mTargetZ == 0) && (this.mTargetD == 0)) { + this.mTargetX = aBaseMetaTileEntity.getXCoord(); + this.mTargetY = aBaseMetaTileEntity.getYCoord(); + this.mTargetZ = aBaseMetaTileEntity.getZCoord(); + this.mTargetD = aBaseMetaTileEntity.getWorld().provider.dimensionId; + } + this.hasBlock = checkForBlock(); + } + } + + public boolean checkForBlock() { + for (byte i = -5; i <= 5; i = (byte) (i + 1)) { + for (byte j = -5; j <= 5; j = (byte) (j + 1)) { + for (byte k = -5; k <= 5; k = (byte) (k + 1)) { + if (getBaseMetaTileEntity().getBlockOffset(i, j, k) == GregTech_API.sBlockMetal5 + && getBaseMetaTileEntity().getMetaIDOffset(i, j, k) == 8) { // require osmiridium block + return true; + } + } + } + } + return false; + } + + public boolean hasDimensionalTeleportCapability() { + return this.mDebug || (sInterDimensionalTeleportAllowed && (this.hasBlock + || mFluid != null && mFluid.isFluidEqual(Materials.Nitrogen.getPlasma(1)) && mFluid.amount >= 1000)); + } + + public boolean isDimensionalTeleportAvailable() { + return this.mDebug || (hasDimensionalTeleportCapability() && GT_Utility.isRealDimension(this.mTargetD) + && GT_Utility.isRealDimension(getBaseMetaTileEntity().getWorld().provider.dimensionId)); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (mFluid == null) { + mFluid = Materials.Nitrogen.getPlasma(0); + } + super.onPostTick(aBaseMetaTileEntity, aTick); + if (getBaseMetaTileEntity().isServerSide()) { + if (getBaseMetaTileEntity().getTimer() % 100L == 50L) { + this.hasBlock = checkForBlock(); + } + if ((getBaseMetaTileEntity().isAllowedToWork()) && (getBaseMetaTileEntity().getRedstone())) { + if (getBaseMetaTileEntity().getStoredEU() > (V[mTier] * 16)) { + if (mPassiveEnergyUse) { + getBaseMetaTileEntity().decreaseStoredEnergyUnits(2L << (mTier - 1), false); + } + if (hasDimensionalTeleportCapability() + && this.mTargetD != getBaseMetaTileEntity().getWorld().provider.dimensionId + && mFluid.isFluidEqual(Materials.Nitrogen.getPlasma(1))) { + mFluid.amount--; + if (mFluid.amount < 1) { + mFluid = null; + } + } + if (tTargetD != mTargetD || tTargetX != mTargetX || tTargetY != mTargetY || tTargetZ != mTargetZ) { + tTargetD = mTargetD; + tTargetX = mTargetX; + tTargetY = mTargetY; + tTargetZ = mTargetZ; + if (this.mTargetD == getBaseMetaTileEntity().getWorld().provider.dimensionId) { + tTile = getBaseMetaTileEntity().getTileEntity(this.mTargetX, this.mTargetY, this.mTargetZ); + } else { + World tWorld = DimensionManager.getWorld(this.mTargetD); + if (tWorld != null) { + tTile = tWorld.getTileEntity(this.mTargetX, this.mTargetY, this.mTargetZ); + } + } + } + int tDistance = distanceCalculation(); + if (tTile != null) { + if (tTile instanceof IEnergyConnected) { + long packetSize = V[mTier]; + if (tTile instanceof IGregTechTileEntity) { + IMetaTileEntity mte = ((IGregTechTileEntity) tTile).getMetaTileEntity(); + if (mte instanceof BaseMetaTileEntity) { + packetSize = ((BaseMetaTileEntity) mte).getMaxSafeInput(); + } + } + long energyUse = 10; + if (mMaxLossDistance != 0) { + energyUse = GT_Utility + .safeInt(10L + (tDistance * Math.max(mMaxLoss - 10L, 0) / mMaxLossDistance)); + } + energyUse = packetSize + ((V[mTier] * energyUse) / 100); + if (getBaseMetaTileEntity().isUniversalEnergyStored(energyUse)) { + if (((IEnergyConnected) tTile).injectEnergyUnits(ForgeDirection.UNKNOWN, packetSize, 1) + > 0) { + getBaseMetaTileEntity().decreaseStoredEnergyUnits(energyUse, false); + } + } + } + } + } + getBaseMetaTileEntity().setActive(true); + } else { + getBaseMetaTileEntity().setActive(false); + } + } + } + + private int distanceCalculation() { + return Math.abs( + ((this.mTargetD != getBaseMetaTileEntity().getWorld().provider.dimensionId) + && (isDimensionalTeleportAvailable()) ? 100 : 1) + * (int) Math.sqrt( + Math.pow(getBaseMetaTileEntity().getXCoord() - this.mTargetX, 2.0D) + + Math.pow(getBaseMetaTileEntity().getYCoord() - this.mTargetY, 2.0D) + + Math.pow(getBaseMetaTileEntity().getZCoord() - this.mTargetZ, 2.0D))); + } + + @Override + public boolean isSimpleMachine() { + return false; + } + + @Override + public boolean isOverclockerUpgradable() { + return false; + } + + @Override + public boolean isTransformerUpgradable() { + return false; + } + + @Override + public boolean isElectric() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isEnetInput() { + return true; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return true; + } + + @Override + public boolean isOutputFacing(ForgeDirection side) { + return false; + } + + @Override + public boolean isTeleporterCompatible() { + return false; + } + + @Override + public long getMinimumStoredEU() { + return V[mTier] * 16; + } + + @Override + public long maxEUStore() { + return V[mTier] * 256; + } + + @Override + public long maxEUInput() { + return V[mTier]; + } + + @Override + public long maxSteamStore() { + return maxEUStore(); + } + + @Override + public long maxAmperesIn() { + return 3; + } + + @Override + public int getStackDisplaySlot() { + return 2; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public int getInputSlot() { + return 0; + } + + @Override + public int getOutputSlot() { + return 0; + } + + @Override + public int getCapacity() { + return 64000; + } + + @Override + public boolean doesFillContainers() { + return false; + } + + @Override + public boolean doesEmptyContainers() { + return false; + } + + @Override + public boolean canTankBeFilled() { + return true; + } + + @Override + public boolean canTankBeEmptied() { + return true; + } + + @Override + public boolean displaysItemStack() { + return false; + } + + @Override + public boolean displaysStackSize() { + return false; + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + return null; + } + + @Override + public boolean useModularUI() { + return true; + } + + protected static final NumberFormatMUI numberFormat = new NumberFormatMUI(); + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + builder.widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_SCREEN_BLACK) + .setSize(90, 72) + .setPos(43, 4)) + .widget( + new TextWidget().setStringSupplier(() -> "X: " + numberFormat.format(mTargetX)) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setPos(46, 8)) + .widget( + new TextWidget().setStringSupplier(() -> "Y: " + numberFormat.format(mTargetY)) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setPos(46, 16)) + .widget( + new TextWidget().setStringSupplier(() -> "Z: " + numberFormat.format(mTargetZ)) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setPos(46, 24)) + .widget( + new TextWidget().setStringSupplier(() -> "Dim: " + numberFormat.format(mTargetD)) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setPos(46, 32)) + .widget( + TextWidget.dynamicString(() -> "Dim Valid: " + (GT_Utility.isRealDimension(mTargetD) ? "Yes" : "No")) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> hasDimensionalTeleportCapability()) + .setPos(46, 40)) + .widget(new FakeSyncWidget.FluidStackSyncer(() -> mFluid, val -> mFluid = val)); + + addChangeNumberButtons(builder, GT_UITextures.OVERLAY_BUTTON_MINUS_LARGE, -512, -64, 7); + addChangeNumberButtons(builder, GT_UITextures.OVERLAY_BUTTON_MINUS_SMALL, -16, -1, 25); + addChangeNumberButtons(builder, GT_UITextures.OVERLAY_BUTTON_PLUS_SMALL, 16, 1, 133); + addChangeNumberButtons(builder, GT_UITextures.OVERLAY_BUTTON_PLUS_LARGE, 512, 64, 151); + + addChangeNumberButton( + builder, + GT_UITextures.OVERLAY_BUTTON_MINUS_LARGE, + val -> mTargetD += val, + -16, + -8, + 7, + 58); + addChangeNumberButton( + builder, + GT_UITextures.OVERLAY_BUTTON_MINUS_SMALL, + val -> mTargetD += val, + -4, + -1, + 25, + 58); + addChangeNumberButton(builder, GT_UITextures.OVERLAY_BUTTON_PLUS_SMALL, val -> mTargetD += val, 4, 1, 133, 58); + addChangeNumberButton(builder, GT_UITextures.OVERLAY_BUTTON_PLUS_LARGE, val -> mTargetD += val, 16, 8, 151, 58); + } + + private void addChangeNumberButtons(ModularWindow.Builder builder, IDrawable overlay, int addNumberShift, + int addNumber, int xPos) { + addChangeNumberButton(builder, overlay, val -> mTargetX += val, addNumberShift, addNumber, xPos, 4); + addChangeNumberButton(builder, overlay, val -> mTargetY += val, addNumberShift, addNumber, xPos, 22); + addChangeNumberButton(builder, overlay, val -> mTargetZ += val, addNumberShift, addNumber, xPos, 40); + } + + private void addChangeNumberButton(ModularWindow.Builder builder, IDrawable overlay, Consumer<Integer> setter, + int addNumberShift, int addNumber, int xPos, int yPos) { + builder.widget( + new ButtonWidget() + .setOnClick((clickData, widget) -> setter.accept(clickData.shift ? addNumberShift : addNumber)) + .setBackground(GT_UITextures.BUTTON_STANDARD, overlay) + .setSize(18, 18) + .setPos(xPos, yPos)); + } + + @Override + public GUITextureSet getGUITextureSet() { + return new GUITextureSet().setGregTechLogo(GT_UITextures.PICTURE_GT_LOGO_17x17_TRANSPARENT_GRAY); + } + + @Override + public void addGregTechLogo(ModularWindow.Builder builder) { + builder.widget( + new DrawableWidget().setDrawable(getGUITextureSet().getGregTechLogo()) + .setSize(17, 17) + .setPos(113, 56)); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Miner.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Miner.java new file mode 100644 index 0000000000..2acaea8050 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Miner.java @@ -0,0 +1,412 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.enums.GT_Values.debugBlockMiner; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.ChunkPosition; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture; + +import gregtech.api.enums.Textures; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.recipe.BasicUIProperties; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_Utility; +import gregtech.common.blocks.GT_Block_Ores_Abstract; +import gregtech.common.blocks.GT_TileEntity_Ores; +import gregtech.common.misc.GT_DrillingLogicDelegate; +import gregtech.common.misc.GT_IDrillingLogicDelegateOwner; + +public class GT_MetaTileEntity_Miner extends GT_MetaTileEntity_BasicMachine + implements GT_IDrillingLogicDelegateOwner, IAddUIWidgets { + + static final int[] RADIUS = { 8, 8, 16, 24, 32 }; // Miner radius per tier + static final int[] SPEED = { 160, 160, 80, 40, 20 }; // Miner cycle time per tier + static final int[] ENERGY = { 8, 8, 32, 128, 512 }; // Miner energy consumption per tier + + /** Miner configured radius */ + private int radiusConfig; + /** Found ore blocks cache of current drill depth */ + private final ArrayList<ChunkPosition> oreBlockPositions = new ArrayList<>(); + + /** General pipe accessor */ + private final GT_DrillingLogicDelegate pipe = new GT_DrillingLogicDelegate(this); + + private final int mSpeed; + + public GT_MetaTileEntity_Miner(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 1, + new String[] { "Digging ore instead of you", "Use Screwdriver to regulate work area", + "Use Soft Mallet to disable and retract the pipe", + String.format("%d EU/t, %d sec per block, no stuttering", ENERGY[aTier], SPEED[aTier] / 20), + String.format("Maximum work area %dx%d", (RADIUS[aTier] * 2 + 1), (RADIUS[aTier] * 2 + 1)), + String.format("Fortune bonus of %d", aTier) }, + 2, + 2, + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_SIDE_ACTIVE")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_SIDE_ACTIVE_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_SIDE")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_SIDE_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_FRONT_ACTIVE")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_FRONT_ACTIVE_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_FRONT")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_FRONT_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_TOP_ACTIVE")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_TOP_ACTIVE_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_TOP")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_TOP_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_BOTTOM_ACTIVE")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_BOTTOM_ACTIVE_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_BOTTOM")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/miner/OVERLAY_BOTTOM_GLOW")) + .glow() + .build())); + mSpeed = SPEED[aTier]; + radiusConfig = RADIUS[mTier]; + } + + public GT_MetaTileEntity_Miner(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 1, aDescription, aTextures, 2, 2); + mSpeed = SPEED[aTier]; + radiusConfig = RADIUS[mTier]; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Miner(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + pipe.findTipDepth(); + fillOreList(aBaseMetaTileEntity); + } + + @Override + protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack) // + && aStack.getItem() == GT_DrillingLogicDelegate.MINING_PIPE_STACK.getItem(); + } + + /** Both output slots must be free to work */ + public boolean hasFreeSpace() { + for (int i = getOutputSlot(); i < getOutputSlot() + 2; i++) { + if (mInventory[i] != null) { + return false; + } + } + return true; + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + super.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ); + if (side != getBaseMetaTileEntity().getFrontFacing() && side != mMainFacing) { + if (aPlayer.isSneaking()) { + if (radiusConfig >= 0) { + radiusConfig--; + } + if (radiusConfig < 0) { + radiusConfig = RADIUS[mTier]; + } + } else { + if (radiusConfig <= RADIUS[mTier]) { + radiusConfig++; + } + if (radiusConfig > RADIUS[mTier]) { + radiusConfig = 0; + } + } + + GT_Utility.sendChatToPlayer( + aPlayer, + String.format( + "%s %dx%d", + StatCollector.translateToLocal("GT5U.machines.workareaset"), + (radiusConfig * 2 + 1), + (radiusConfig * 2 + 1))); + + // Rebuild ore cache after change config + fillOreList(getBaseMetaTileEntity()); + } + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + + if (!aBaseMetaTileEntity.isServerSide()) { + return; + } + + // Pipe workaround + pipe.onOwnerPostTick(aBaseMetaTileEntity, aTick); + + if (!aBaseMetaTileEntity.isAllowedToWork()) { + mMaxProgresstime = 0; + if (debugBlockMiner) { + GT_Log.out.println("MINER: Disabled"); + } + return; + } + + if (!hasFreeSpace()) { + mMaxProgresstime = 0; + if (debugBlockMiner) { + GT_Log.out.println("MINER: No free space"); + } + return; + } + + if (!aBaseMetaTileEntity.isUniversalEnergyStored((long) ENERGY[mTier] * (mSpeed - mProgresstime))) { + mMaxProgresstime = 0; + if (debugBlockMiner) { + GT_Log.out.println( + "MINER: Not enough energy yet, want " + (ENERGY[mTier] * mSpeed) + + " have " + + aBaseMetaTileEntity.getUniversalEnergyStored()); + } + return; + } + + /* Checks if machine are waiting new mining pipe item */ + if (!pipe.canContinueDrilling(aTick)) { + mMaxProgresstime = 0; + return; + } + + mMaxProgresstime = mSpeed; + + aBaseMetaTileEntity.decreaseStoredEnergyUnits(ENERGY[mTier], true); + + // Real working only when progress done. TODO some legacy code... refactorings needed + if (mProgresstime == mSpeed - 1) { + if (pipe.getTipDepth() == 0 || oreBlockPositions.isEmpty()) { + boolean descends = pipe.descent(aBaseMetaTileEntity); + if (descends) { + fillOreList(aBaseMetaTileEntity); + } + } else { + int x; + int y; + int z; + Block oreBlock; + boolean isOre; + do { + ChunkPosition oreBlockPos = oreBlockPositions.remove(0); + oreBlock = aBaseMetaTileEntity + .getBlockOffset(oreBlockPos.chunkPosX, oreBlockPos.chunkPosY, oreBlockPos.chunkPosZ); + x = aBaseMetaTileEntity.getXCoord() + oreBlockPos.chunkPosX; + y = aBaseMetaTileEntity.getYCoord() + oreBlockPos.chunkPosY; + z = aBaseMetaTileEntity.getZCoord() + oreBlockPos.chunkPosZ; + isOre = GT_Utility.isOre( + oreBlock, + aBaseMetaTileEntity.getWorld() + .getBlockMetadata(x, y, z)); + } // someone else might have removed the block + while (!isOre && !oreBlockPositions.isEmpty()); + + if (isOre) { + pipe.mineBlock(aBaseMetaTileEntity, oreBlock, x, y, z); + } + } + } + } + + /** Finds the ores in current drill Y level */ + private void fillOreList(IGregTechTileEntity aBaseMetaTileEntity) { + if (pipe.getTipDepth() == 0) { + return; + } + oreBlockPositions.clear(); + for (int z = -radiusConfig; z <= radiusConfig; ++z) { + for (int x = -radiusConfig; x <= radiusConfig; ++x) { + Block block = aBaseMetaTileEntity.getBlockOffset(x, pipe.getTipDepth(), z); + int blockMeta = aBaseMetaTileEntity.getMetaIDOffset(x, pipe.getTipDepth(), z); + + // todo some weird checks. refactorings needed + if (block instanceof GT_Block_Ores_Abstract) { + TileEntity oreEntity = aBaseMetaTileEntity.getTileEntityOffset(x, pipe.getTipDepth(), z); + if (oreEntity instanceof GT_TileEntity_Ores && ((GT_TileEntity_Ores) oreEntity).mNatural) { + oreBlockPositions.add(new ChunkPosition(x, pipe.getTipDepth(), z)); + } + } else if (GT_Utility.isOre(block, blockMeta)) { + oreBlockPositions.add(new ChunkPosition(x, pipe.getTipDepth(), z)); + } + } + } + } + + /** Pulls (or check can pull) items from an input slots. */ + @Override + public boolean pullInputs(Item item, int count, boolean simulate) { + for (int i = 0; i < mInputSlotCount; i++) { + ItemStack stack = getInputAt(i); + if (stack != null && stack.getItem() == item && stack.stackSize >= count) { + if (simulate) { + return true; + } + stack.stackSize -= count; + if (stack.stackSize == 0) { + mInventory[getInputSlot() + i] = null; + } + return true; + } + } + return false; + } + + /** Pushes (or check can push) item to output slots. */ + @Override + public boolean pushOutputs(ItemStack stack, int count, boolean simulate, boolean allowInputSlots) { + return allowInputSlots && pushOutput(getInputSlot(), getInputSlot() + mInputSlotCount, stack, count, simulate) + || pushOutput(getOutputSlot(), getOutputSlot() + mOutputItems.length, stack, count, simulate); + } + + private boolean pushOutput(int startIndex, int endIndex, ItemStack stack, int count, boolean simulate) { + for (int i = startIndex; i < endIndex; i++) { + ItemStack slot = mInventory[i]; + if (slot == null || slot.stackSize == 0) { + if (!simulate) { + ItemStack copy = stack.copy(); + copy.stackSize = count; + mInventory[i] = copy; + } + return true; + } else if (GT_Utility.areStacksEqual(slot, stack) && slot.stackSize <= slot.getMaxStackSize() - count) { + if (!simulate) { + slot.stackSize += count; + } + return true; + } + } + return false; + } + + @Override + public long maxEUStore() { + return Math.max(V[mTier] * 64, 4096); + } + + @Override + public void setItemNBT(NBTTagCompound aNBT) { + super.setItemNBT(aNBT); + aNBT.setInteger("radiusConfig", radiusConfig); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setInteger("radiusConfig", radiusConfig); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (aNBT.hasKey("radiusConfig")) { + int newRadius = aNBT.getInteger("radiusConfig"); + if (RADIUS[mTier] <= newRadius && newRadius > 0) { + radiusConfig = newRadius; + } + } + } + + @Override + public String[] getInfoData() { + return new String[] { + String.format( + "%s%s%s", + EnumChatFormatting.BLUE, + StatCollector.translateToLocal("GT5U.machines.miner"), + EnumChatFormatting.RESET), + String.format( + "%s: %s%d%s %s", + StatCollector.translateToLocal("GT5U.machines.workarea"), + EnumChatFormatting.GREEN, + (radiusConfig * 2 + 1), + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.machines.blocks")) }; + } + + @Override + public int getMachineTier() { + return mTier; + } + + @Override + public int getMachineSpeed() { + return mSpeed; + } + + public GT_DrillingLogicDelegate getPipe() { + return pipe; + } + + @Override + public boolean useModularUI() { + return true; + } + + private static final FallbackableUITexture progressBarTexture = GT_UITextures + .fallbackableProgressbar("miner", GT_UITextures.PROGRESSBAR_CANNER); + + @Override + protected BasicUIProperties getUIProperties() { + return super.getUIProperties().toBuilder() + .progressBarTexture(progressBarTexture) + .build(); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_MonsterRepellent.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_MonsterRepellent.java new file mode 100644 index 0000000000..fde78cfa2e --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_MonsterRepellent.java @@ -0,0 +1,182 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASINGS; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER_GLOW; + +import java.util.Arrays; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TieredMachineBlock; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_SpawnEventHandler; + +public class GT_MetaTileEntity_MonsterRepellent extends GT_MetaTileEntity_TieredMachineBlock { + + public int mRange = 16; + + public GT_MetaTileEntity_MonsterRepellent(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 0, + "Repels nasty Creatures. Range: " + (4 + (12 * aTier)) + + " unpowered / " + + (16 + (48 * aTier)) + + " powered. Costs " + + (1L << (aTier * 2)) + + " EU/t"); + } + + public GT_MetaTileEntity_MonsterRepellent(String aName, int aTier, int aInvSlotCount, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + public GT_MetaTileEntity_MonsterRepellent(String aName, int aTier, int aInvSlotCount, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aInvSlotCount, aDescription, aTextures); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_MonsterRepellent( + this.mName, + this.mTier, + this.mInventory.length, + this.mDescriptionArray, + this.mTextures); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + if (sideDirection != ForgeDirection.UP) return new ITexture[] { MACHINE_CASINGS[mTier][colorIndex + 1] }; + if (active) return new ITexture[] { MACHINE_CASINGS[mTier][colorIndex + 1], + TextureFactory.of(OVERLAY_TELEPORTER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_TELEPORTER_ACTIVE_GLOW) + .glow() + .build() }; + return new ITexture[] { MACHINE_CASINGS[mTier][colorIndex + 1], TextureFactory.of(OVERLAY_TELEPORTER), + TextureFactory.builder() + .addIcon(OVERLAY_TELEPORTER_GLOW) + .glow() + .build() }; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + if (aBaseMetaTileEntity.isAllowedToWork() && aBaseMetaTileEntity.isServerSide()) { + int[] tCoords = { aBaseMetaTileEntity.getXCoord(), aBaseMetaTileEntity.getYCoord(), + aBaseMetaTileEntity.getZCoord(), aBaseMetaTileEntity.getWorld().provider.dimensionId }; + if ((aTimer % 600 == 0) && !GT_SpawnEventHandler.mobReps.contains(tCoords)) { + GT_SpawnEventHandler.mobReps.add(tCoords); + } + if (aBaseMetaTileEntity.isUniversalEnergyStored(getMinimumStoredEU()) + && aBaseMetaTileEntity.decreaseStoredEnergyUnits(1L << (this.mTier * 2), false)) { + mRange = GT_SpawnEventHandler.getPoweredRepellentRange(mTier); + } else { + mRange = GT_SpawnEventHandler.getUnpoweredRepellentRange(mTier); + } + } + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + int[] tCoords = { aBaseMetaTileEntity.getXCoord(), aBaseMetaTileEntity.getYCoord(), + aBaseMetaTileEntity.getZCoord(), aBaseMetaTileEntity.getWorld().provider.dimensionId }; + GT_SpawnEventHandler.mobReps.add(tCoords); + } + + @Override + public void onRemoval() { + int[] tCoords = { this.getBaseMetaTileEntity() + .getXCoord(), + this.getBaseMetaTileEntity() + .getYCoord(), + this.getBaseMetaTileEntity() + .getZCoord(), + this.getBaseMetaTileEntity() + .getWorld().provider.dimensionId }; + GT_SpawnEventHandler.mobReps.removeIf(coords -> Arrays.equals(coords, tCoords)); + } + + @Override + public boolean isSimpleMachine() { + return false; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isEnetInput() { + return true; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return true; + } + + @Override + public boolean isTeleporterCompatible() { + return false; + } + + @Override + public long getMinimumStoredEU() { + return 512L; + } + + @Override + public long maxEUStore() { + return 512L + V[mTier] * 50; + } + + @Override + public long maxEUInput() { + return V[mTier]; + } + + @Override + public long maxAmperesIn() { + return 2; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + return null; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) {} + + @Override + public void loadNBTData(NBTTagCompound aNBT) {} +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_PotionBrewer.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_PotionBrewer.java new file mode 100644 index 0000000000..15150abf67 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_PotionBrewer.java @@ -0,0 +1,235 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_POTIONBREWER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_POTIONBREWER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_POTIONBREWER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_POTIONBREWER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_POTIONBREWER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_POTIONBREWER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_POTIONBREWER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_POTIONBREWER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_POTIONBREWER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_POTIONBREWER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_POTIONBREWER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_POTIONBREWER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_POTIONBREWER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_POTIONBREWER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_POTIONBREWER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_POTIONBREWER_GLOW; + +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.MachineType; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_PotionBrewer extends GT_MetaTileEntity_BasicMachine { + + public GT_MetaTileEntity_PotionBrewer(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 1, + MachineType.BREWERY.tooltipDescription(), + 1, + 0, + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_POTIONBREWER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_POTIONBREWER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_POTIONBREWER), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_POTIONBREWER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_POTIONBREWER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_POTIONBREWER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_POTIONBREWER), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_POTIONBREWER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_POTIONBREWER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_POTIONBREWER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_POTIONBREWER), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_POTIONBREWER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_POTIONBREWER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_POTIONBREWER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_POTIONBREWER), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_POTIONBREWER_GLOW) + .glow() + .build())); + } + + public GT_MetaTileEntity_PotionBrewer(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 1, aDescription, aTextures, 1, 0); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_PotionBrewer(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.brewingRecipes; + } + + @Override + public int checkRecipe() { + int tCheck = super.checkRecipe(); + if (tCheck != DID_NOT_FIND_RECIPE) { + return tCheck; + } + + calculateOverclockedNess(4, 128); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + + FluidStack aFluid = getFillableStack(); + if ((getDrainableStack() == null) && (aFluid != null) && (getInputAt(0) != null)) { + String tInputName = aFluid.getFluid() + .getName(); + if (tInputName.startsWith("potion.")) { + tInputName = tInputName.replaceFirst("potion.", ""); + int tFirstDot = tInputName.indexOf('.') + 1; + String tModifier = tFirstDot <= 0 ? "" : tInputName.substring(tFirstDot); + if (!tModifier.isEmpty()) { + tInputName = tInputName.replaceFirst("." + tModifier, ""); + } + if (GT_Utility.areStacksEqual(new ItemStack(Items.fermented_spider_eye, 1, 0), getInputAt(0))) { + if (tInputName.equals("poison")) { + return setOutput("potion.damage" + tModifier); + } + if (tInputName.equals("health")) { + return setOutput("potion.damage" + tModifier); + } + if (tInputName.equals("waterbreathing")) { + return setOutput("potion.damage" + tModifier); + } + if (tInputName.equals("nightvision")) { + return setOutput("potion.invisibility" + tModifier); + } + if (tInputName.equals("fireresistance")) { + return setOutput("potion.slowness" + tModifier); + } + if (tInputName.equals("speed")) { + return setOutput("potion.slowness" + tModifier); + } + if (tInputName.equals("strength")) { + return setOutput("potion.weakness" + tModifier); + } + if (tInputName.equals("regen")) { + return setOutput("potion.poison" + tModifier); + } + return setOutput("potion.weakness"); + } + if (GT_Utility.areStacksEqual( + GT_OreDictUnificator.get(OrePrefixes.dust, Materials.Glowstone, 1L), + getInputAt(0))) { + if (!tModifier.startsWith("strong")) { + return setOutput( + "potion." + tInputName + ".strong" + (tModifier.isEmpty() ? "" : "." + tModifier)); + } + if (tModifier.startsWith("long")) { + return setOutput("potion." + tInputName + tModifier.replaceFirst("long", "")); + } + return setOutput("potion.thick"); + } + if (GT_Utility.areStacksEqual( + GT_OreDictUnificator.get(OrePrefixes.dust, Materials.Redstone, 1L), + getInputAt(0))) { + if (!tModifier.startsWith("long")) { + return setOutput( + "potion." + tInputName + ".long" + (tModifier.isEmpty() ? "" : "." + tModifier)); + } + if (tModifier.startsWith("strong")) { + return setOutput("potion." + tInputName + tModifier.replaceFirst("strong", "")); + } + return setOutput("potion.mundane"); + } + if (GT_Utility.areStacksEqual( + GT_OreDictUnificator.get(OrePrefixes.dust, Materials.Gunpowder, 1L), + getInputAt(0))) { + if (!tInputName.endsWith(".splash")) { + return setOutput("potion." + tInputName + ".splash"); + } + return setOutput("potion.mundane"); + } + } + } + return 0; + } + + private int setOutput(String aFluidName) { + if (getFillableStack().amount < 750) { + return 0; + } + + this.mOutputFluid = FluidRegistry.getFluidStack(aFluidName, 750); + if (this.mOutputFluid == null) { + this.mOutputFluid = FluidRegistry.getFluidStack("potion.mundane", getFillableStack().amount); + } + + getInputAt(0).stackSize -= 1; + getFillableStack().amount -= 750; + return 2; + } + + @Override + public boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack) + && getRecipeMap().containsInput(aStack); + } + + @Override + public boolean isFluidInputAllowed(FluidStack aFluid) { + return (aFluid.getFluid() + .getName() + .startsWith("potion.")) || (super.isFluidInputAllowed(aFluid)); + } + + @Override + public int getCapacity() { + return getCapacityForTier(mTier); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Pump.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Pump.java new file mode 100644 index 0000000000..8cac0c3df7 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Pump.java @@ -0,0 +1,851 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.GT_Values.debugBlockPump; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.ChunkPosition; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.IFluidBlock; + +import com.gtnewhorizons.modularui.api.drawable.FallbackableUITexture; + +import gregtech.api.enums.Textures; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.BaseTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.recipe.BasicUIProperties; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Utility; +import gregtech.common.misc.GT_DrillingLogicDelegate; + +public class GT_MetaTileEntity_Pump extends GT_MetaTileEntity_BasicMachine { + + private static final ItemStack MINING_PIPE = GT_ModHandler.getIC2Item("miningPipe", 0); + + private static final ItemStack MINING_PIPE_ONE = GT_ModHandler.getIC2Item("miningPipe", 1); + private static final Block MINING_PIPE_BLOCK = GT_Utility.getBlockFromStack(MINING_PIPE); + private static final Block MINING_PIPE_TIP_BLOCK = GT_Utility + .getBlockFromStack(GT_ModHandler.getIC2Item("miningPipeTip", 0)); + + public static int getMaxDistanceForTier(int aTier) { + return (10 * ((int) Math.pow(1.6D, aTier))); + } + + public static long getEuUsagePerTier(int aTier) { + return (16 * ((long) Math.pow(4, aTier))); + } + + public ArrayDeque<ChunkPosition> mPumpList = new ArrayDeque<>(); + public boolean wasPumping = false; + public int mPumpTimer = 0; + public int mPumpCountBelow = 0; + public Block mPrimaryPumpedBlock = null; + public Block mSecondaryPumpedBlock = null; + + private int radiusConfig; // Pump configured radius + private boolean mRetractDone = false; + + private boolean mDisallowRetract = true; + + public GT_MetaTileEntity_Pump(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 1, + new String[] { "The best way to empty Oceans!", + getEuUsagePerTier(aTier) + " EU/operation, " + + GT_Utility.safeInt(160 / 20 / (long) Math.pow(2, aTier)) + + " sec per bucket, no stuttering", + "Maximum pumping area: " + (getMaxDistanceForTier(aTier) * 2 + 1) + + "x" + + (getMaxDistanceForTier(aTier) * 2 + 1), + "Use Screwdriver to regulate pumping area", "Use Soft Mallet to disable and retract the pipe", + "Disable the bottom pump to retract the pipe!", + "Use Soldering Iron to auto retract the pipe when hitting a rock", }, + 2, + 2, + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_SIDE_ACTIVE")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_SIDE_ACTIVE_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_SIDE")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_SIDE_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_FRONT_ACTIVE")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_FRONT_ACTIVE_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_FRONT")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_FRONT_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_TOP_ACTIVE")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_TOP_ACTIVE_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_TOP")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_TOP_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_BOTTOM_ACTIVE")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_BOTTOM_ACTIVE_GLOW")) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_BOTTOM")), + TextureFactory.builder() + .addIcon(new Textures.BlockIcons.CustomIcon("basicmachines/pump/OVERLAY_BOTTOM_GLOW")) + .glow() + .build())); + + radiusConfig = getMaxDistanceForTier(mTier); + } + + public GT_MetaTileEntity_Pump(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 1, aDescription, aTextures, 2, 2); + radiusConfig = getMaxDistanceForTier(mTier); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Pump(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public boolean useModularUI() { + return true; + } + + private static final FallbackableUITexture progressBarTexture = GT_UITextures + .fallbackableProgressbar("pump", GT_UITextures.PROGRESSBAR_CANNER); + + @Override + protected BasicUIProperties getUIProperties() { + return BasicUIProperties.builder() + .maxItemInputs(2) + .maxItemOutputs(2) + .slotOverlays((index, isFluid, isOutput, isSpecial) -> { + if (!isFluid && !isOutput && !isSpecial) { + return GT_UITextures.OVERLAY_SLOT_MINING_PIPE; + } else { + return null; + } + }) + .maxFluidInputs(0) + .maxFluidOutputs(1) + .progressBarTexture(progressBarTexture) + .build(); + } + + @Override + public int getCapacity() { + return getCapacityForTier(mTier); + } + + @Override + protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack) + && aStack.getItem() == GT_DrillingLogicDelegate.MINING_PIPE_STACK.getItem(); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + boolean wasPumping = this.wasPumping || !this.mPumpList.isEmpty(); + if (debugBlockPump) { + GT_Log.out.println( + "PUMP: NBT:Save - WasPumping - " + wasPumping + + " blocks (" + + this.mPrimaryPumpedBlock + + ", " + + this.mSecondaryPumpedBlock + + ")"); + } + super.saveNBTData(aNBT); + aNBT.setString( + "mPumpedBlock1", + this.mPrimaryPumpedBlock == null ? "" : Block.blockRegistry.getNameForObject(this.mPrimaryPumpedBlock)); + aNBT.setString( + "mPumpedBlock2", + this.mSecondaryPumpedBlock == null ? "" : Block.blockRegistry.getNameForObject(this.mSecondaryPumpedBlock)); + aNBT.setBoolean("wasPumping", wasPumping); + aNBT.setInteger("radiusConfig", radiusConfig); + aNBT.setBoolean("mRetractDone", mRetractDone); + aNBT.setBoolean("mDisallowRetract", mDisallowRetract); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + this.wasPumping = aNBT.getBoolean("wasPumping"); + if (aNBT.hasKey("radiusConfig")) this.radiusConfig = aNBT.getInteger("radiusConfig"); + this.mPrimaryPumpedBlock = Block.getBlockFromName(aNBT.getString("mPumpedBlock1")); + this.mSecondaryPumpedBlock = Block.getBlockFromName(aNBT.getString("mPumpedBlock2")); + this.mRetractDone = aNBT.getBoolean("mRetractDone"); + this.mDisallowRetract = aNBT.getBoolean("mDisallowRetract"); + + // Transition from old TE which was derived from GT_MetaTileEntity_Hatch + if (!aNBT.hasKey("mEUt")) { + // Output of old pump always faces up. + getBaseMetaTileEntity().setFrontFacing(ForgeDirection.UP); + + // Automatic output on. + mFluidTransfer = true; + + // Fluid was stored in the hatch, now needs to go to the output. + if (mFluid != null && mFluid.amount > 0) { + fluidOutputTank.fill(mFluid, true); + mFluid = null; + } + + // Move pipes (or other things) from old slots to new ones. + if (mInventory[1] != null && mInventory[1].stackSize > 0) { + mInventory[getInputSlot() + 1] = mInventory[1]; + mInventory[1] = null; + } + + if (mInventory[0] != null && mInventory[0].stackSize > 0) { + mInventory[getInputSlot()] = mInventory[0]; + mInventory[0] = null; + } + } + + if (debugBlockPump) { + GT_Log.out.println( + "PUMP: NBT:Load - WasPumping - " + this.wasPumping + + "(" + + aNBT.getString("mPumpedBlock1") + + ") " + + this.mPrimaryPumpedBlock); + } + } + + @Override + public void setItemNBT(NBTTagCompound aNBT) { + super.setItemNBT(aNBT); + aNBT.setInteger("radiusConfig", radiusConfig); + aNBT.setBoolean("mDisallowRetract", mDisallowRetract); + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + super.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ); + + if (side == getBaseMetaTileEntity().getFrontFacing() || side == mMainFacing) { + // Configuring "input from output side allowed". + return; + } + + int max = getMaxPumpableDistance(); + if (aPlayer.isSneaking()) { + if (radiusConfig >= 0) { + radiusConfig--; + } + if (radiusConfig < 0) radiusConfig = max; + } else { + if (radiusConfig <= max) { + radiusConfig++; + } + if (radiusConfig > max) radiusConfig = 0; + } + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("GT5U.machines.workareaset") + " " + + (radiusConfig * 2 + 1) + + "x" + + (radiusConfig * 2 + 1)); // TODO Add translation support + + clearQueue(false); + } + + @Override + public boolean onSolderingToolRightClick(ForgeDirection side, ForgeDirection wrenchingSide, + EntityPlayer entityPlayer, float aX, float aY, float aZ) { + if (super.onSolderingToolRightClick(side, wrenchingSide, entityPlayer, aX, aY, aZ)) return true; + mDisallowRetract = !mDisallowRetract; + GT_Utility.sendChatToPlayer( + entityPlayer, + StatCollector.translateToLocal( + mDisallowRetract ? "GT5U.machines.autoretract.disabled" : "GT5U.machines.autoretract.enabled")); + return true; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + + if (getBaseMetaTileEntity().isServerSide()) { + this.mPumpTimer -= 1; + if ((getBaseMetaTileEntity() instanceof BaseTileEntity)) { + ((BaseTileEntity) getBaseMetaTileEntity()).ignoreUnloadedChunks = false; + } + this.doTickProfilingInThisTick = true; + this.mPumpCountBelow = 0; + + IGregTechTileEntity tTileEntity; + for (int i = 1; (i < 21) + && ((tTileEntity = getBaseMetaTileEntity() + .getIGregTechTileEntityAtSideAndDistance(ForgeDirection.DOWN, i)) != null) + && ((tTileEntity.getMetaTileEntity() instanceof GT_MetaTileEntity_Pump)); i++) { + // Apparently someone might stack 21 pumps on top of each other, so let's check for that + getBaseMetaTileEntity().setActive(tTileEntity.isActive()); + this.mPumpCountBelow += 1; + // The more pumps we have stacked, the faster the ones below go + ((GT_MetaTileEntity_Pump) tTileEntity.getMetaTileEntity()).mPumpTimer -= 1; + ((GT_MetaTileEntity_Pump) tTileEntity.getMetaTileEntity()).mProgresstime += 1; + } + if (debugBlockPump && (this.mPumpCountBelow != 0)) { + GT_Log.out.println("PUMP: Detected " + this.mPumpCountBelow + " pumps below this pump."); + } + if (this.mPumpCountBelow <= 0) { + // Only the bottom most pump does anything + if (getBaseMetaTileEntity().isAllowedToWork()) { + mRetractDone = false; + if ((getBaseMetaTileEntity().isUniversalEnergyStored(this.getEuUsagePerAction())) + && (fluidOutputTank.getFluidAmount() + 1000 <= fluidOutputTank.getCapacity())) { + boolean tMovedOneDown = false; + if ((this.mPumpList.isEmpty()) && (getBaseMetaTileEntity().getTimer() % 100L == 0L)) { + if (!this.wasPumping) { + tMovedOneDown = moveOneDown(); + if (!tMovedOneDown) { + if (canMoveDown( + getBaseMetaTileEntity().getXCoord(), + Math.max(getYOfPumpHead() - 1, 1), + getBaseMetaTileEntity().getZCoord())) { + if (debugBlockPump) { + GT_Log.out.println("PUMP: No pipe left. Idle for a little longer."); + } + this.mPumpTimer = 160; + } else { + getBaseMetaTileEntity().disableWorking(); + if (debugBlockPump) { + GT_Log.out.println("PUMP: Can't move. Retracting in next few ticks"); + } + } + } else if (debugBlockPump) { + GT_Log.out.println("PUMP: Moved down"); + } + } else if (debugBlockPump) { + GT_Log.out.println("PUMP: Was pumping, didn't move down"); + } + } + int x = getBaseMetaTileEntity().getXCoord(), z = getBaseMetaTileEntity().getZCoord(); + + if (!this.hasValidFluid()) { + // We don't have a valid block, let's try to find one + int y = getYOfPumpHead(); + + if (debugBlockPump && this.mPrimaryPumpedBlock != null) { + GT_Log.out.println( + "PUMP: Had an invalid pump block. Trying to find a fluid at Y: " + y + + " Previous blocks 1: " + + this.mPrimaryPumpedBlock + + " 2: " + + this.mSecondaryPumpedBlock); + } + // First look down + checkForFluidToPump(x, y - 1, z); + + // Then look all around + checkForFluidToPump(x, y, z + 1); + checkForFluidToPump(x, y, z - 1); + checkForFluidToPump(x + 1, y, z); + checkForFluidToPump(x - 1, y, z); + this.clearQueue(false); + + if (this.hasValidFluid()) { + // Don't move down and rebuild the queue if we now have a valid fluid + this.wasPumping = true; + } + + } else if (getYOfPumpHead() < getBaseMetaTileEntity().getYCoord()) { + // We didn't just look for a block, and the pump head is below the pump + if ((tMovedOneDown) || this.wasPumping + || ((this.mPumpList.isEmpty()) && (getBaseMetaTileEntity().getTimer() % 200L == 100L)) + || (getBaseMetaTileEntity().getTimer() % 72000L == 100L)) { + // Rebuild the list to pump if any of the following conditions are true: + // 1) We just moved down + // 2) We were previously pumping (and possibly just reloaded) + // 3) We have an empty queue and enough time has passed + // 4) A long while has passed + if (debugBlockPump) { + GT_Log.out.println( + "PUMP: Rebuilding pump list - Size " + this.mPumpList.size() + + " WasPumping: " + + this.wasPumping + + " Timer " + + getBaseMetaTileEntity().getTimer()); + } + int yPump = getBaseMetaTileEntity().getYCoord() - 1, yHead = getYOfPumpHead(); + + this.rebuildPumpQueue(x, yPump, z, yHead); + + if (debugBlockPump) { + GT_Log.out.println("PUMP: Rebuilt pump list - Size " + this.mPumpList.size()); + } + } + if ((!tMovedOneDown) && (this.mPumpTimer <= 0)) { + while ((!this.mPumpList.isEmpty())) { + ChunkPosition pos = this.mPumpList.pollLast(); + if (consumeFluid(pos.chunkPosX, pos.chunkPosY, pos.chunkPosZ)) { + // Keep trying until we consume something, or the list is empty + break; + } + } + this.mPumpTimer = GT_Utility.safeInt(160 / (long) Math.pow(2, this.mTier)); + this.mPumpTimer = mPumpTimer == 0 ? 1 : mPumpTimer; + + mMaxProgresstime = mPumpTimer; + mProgresstime = 0; + } + } else { + // We somehow have a valid fluid, but the head of the pump isn't below the pump. Perhaps + // someone broke some pipes + // -- Clear the queue and we should try to move down until we can find a valid fluid + this.clearQueue(false); + } + } else if (debugBlockPump) { + GT_Log.out.println("PUMP: Not enough energy? Free space?"); + } + } else { + mMaxProgresstime = 0; + + if (!mRetractDone && ((aTick % 5) == 0) && canOutput(MINING_PIPE_ONE)) { + // try retract if all of these conditions are met + // 1. not retracted yet + // 2. once per 5 tick + // 3. can hold retracted pipe in inventory + int tHeadY = getYOfPumpHead(); + if (tHeadY < this.getBaseMetaTileEntity() + .getYCoord()) { + final int tXCoord = this.getBaseMetaTileEntity() + .getXCoord(); + final int tZCoord = this.getBaseMetaTileEntity() + .getZCoord(); + this.getBaseMetaTileEntity() + .getWorld() + .setBlockToAir(tXCoord, tHeadY, tZCoord); + if (tHeadY < this.getBaseMetaTileEntity() + .getYCoord() - 1) { + getBaseMetaTileEntity().getWorld() + .setBlock(tXCoord, tHeadY + 1, tZCoord, MINING_PIPE_TIP_BLOCK); + } + + for (int i = 0; i < mOutputItems.length; ++i) { + if (aBaseMetaTileEntity.addStackToSlot(getOutputSlot() + i, MINING_PIPE_ONE.copy())) { + break; + } + } + + if (debugBlockPump) { + GT_Log.out.println("PUMP: Retracted one pipe"); + } + } else { + mRetractDone = true; + if (debugBlockPump) { + GT_Log.out.println("PUMP: Retract done"); + } + } + } + } + if (!mDisallowRetract) getBaseMetaTileEntity().setActive(!this.mPumpList.isEmpty()); + } + } + } + + private int getMaxPumpableDistance() { + return getMaxDistanceForTier(this.mTier); + } + + private long getEuUsagePerAction() { + return getEuUsagePerTier(this.mTier); + } + + private boolean hasValidFluid() { + return mPrimaryPumpedBlock != null && mSecondaryPumpedBlock != null; + } + + private boolean moveOneDown() { + boolean foundPipe = false; + + for (int i = 0; i < mInputSlotCount; i++) { + ItemStack stack = getInputAt(i); + if (stack != null && GT_Utility.areStacksEqual(stack, MINING_PIPE) && stack.stackSize > 0) { + foundPipe = true; + break; + } + } + + if (!foundPipe) { + // No mining pipes + if (debugBlockPump) { + GT_Log.out.println("PUMP: No mining pipes"); + } + return false; + } + + int yHead = getYOfPumpHead(); + if (yHead <= 1) { + // Let's not punch through bedrock + if (debugBlockPump) { + GT_Log.out.println("PUMP: At bottom"); + } + return false; + } + + int x = getBaseMetaTileEntity().getXCoord(), z = getBaseMetaTileEntity().getZCoord(); + + Block aBlock = getBaseMetaTileEntity().getBlock(x, yHead - 1, z); + boolean canReplaceBlock = aBlock.isReplaceable(getBaseMetaTileEntity().getWorld(), x, yHead - 1, z); + + // We specifically allow replacing water even if we can't consume it + // (e.g. pump holds a different fluid) to help avoid getting stuck on random water pockets. + if (!canReplaceBlock || (isFluid(aBlock) && !consumeFluid(x, yHead - 1, z) && !isWater(aBlock))) { + // Either we didn't consume a fluid, or it's a non-replaceable block, or it's water. + if (debugBlockPump) { + GT_Log.out.println("PUMP: Did not consume fluid, or non-replaceable block found"); + } + return false; + } + // Try to set the block below us to a tip + if (!GT_Utility.setBlockByFakePlayer( + getFakePlayer(getBaseMetaTileEntity()), + x, + yHead - 1, + z, + MINING_PIPE_TIP_BLOCK, + 0, + false)) { + if (debugBlockPump) { + GT_Log.out.println("PUMP: Could not set block below to new tip"); + } + return false; + } + // And change the previous block to a pipe -- as long as it isn't the pump itself! + if (yHead != getBaseMetaTileEntity().getYCoord()) { + getBaseMetaTileEntity().getWorld() + .setBlock(x, yHead, z, MINING_PIPE_BLOCK); + } + + // Remove pipe from inputs. + foundPipe = false; + + for (int i = 0; i < mInputSlotCount; i++) { + ItemStack stack = getInputAt(i); + if (stack != null && GT_Utility.areStacksEqual(stack, MINING_PIPE) && stack.stackSize > 0) { + foundPipe = true; + stack.stackSize -= 1; + if (stack.stackSize == 0) { + mInventory[getInputSlot() + i] = null; + } + break; + } + } + + if (debugBlockPump) { + if (foundPipe) { + GT_Log.out.println("PUMP: Using 1 pipe"); + } else { + GT_Log.err.println("PUMP: Lowered pipe but could not find pipe in input"); + } + } + + return true; + } + + private int getYOfPumpHead() { + // Let's play find the pump head! + + // TODO: Handle pipe|pipe|head|pipe|pipe + int y = getBaseMetaTileEntity().getYCoord() - 1, x = getBaseMetaTileEntity().getXCoord(), + z = getBaseMetaTileEntity().getZCoord(); + + while (y > 0) { + Block curBlock = getBaseMetaTileEntity().getBlock(x, y, z); + if (curBlock == MINING_PIPE_BLOCK) { + y--; + } else if (curBlock == MINING_PIPE_TIP_BLOCK) { + Block nextBlock = getBaseMetaTileEntity().getBlock(x, y - 1, z); + if (nextBlock == MINING_PIPE_BLOCK || nextBlock == MINING_PIPE_TIP_BLOCK) { + // We're running into an existing set of pipes -- Turn this block into a pipe and keep going + this.clearQueue(true); + getBaseMetaTileEntity().getWorld() + .setBlock(x, y, z, MINING_PIPE_BLOCK); + if (debugBlockPump) { + GT_Log.out.println("PUMP: Hit pipes already in place, trying to merge"); + } + } + y--; + + } else { + break; + } + } + + if (getBaseMetaTileEntity().getBlock(x, y, z) != MINING_PIPE_TIP_BLOCK) { + if (y != getBaseMetaTileEntity().getYCoord() - 1 + && getBaseMetaTileEntity().getBlock(x, y + 1, z) == MINING_PIPE_BLOCK) { + // We're below the pump at the bottom of the pipes, we haven't found a tip; make the previous pipe a + // tip! + this.clearQueue(true); + getBaseMetaTileEntity().getWorld() + .setBlock(x, y + 1, z, MINING_PIPE_TIP_BLOCK); + if (debugBlockPump) { + GT_Log.out.println("PUMP: Did not find a tip at bottom, setting last pipe as tip"); + } + } + return y + 1; + } + return y; + } + + private void clearQueue(boolean checkPumping) { + if (checkPumping) { + this.wasPumping = !this.mPumpList.isEmpty(); + } else { + this.wasPumping = false; + } + this.mPumpList.clear(); + } + + private void rebuildPumpQueue(int aX, int yStart, int aZ, int yEnd) { + int mDist = this.radiusConfig; + doTickProfilingInThisTick = false; + ArrayDeque<ChunkPosition> fluidsToSearch = new ArrayDeque<>(); + ArrayDeque<ChunkPosition> fluidsFound = new ArrayDeque<>(); + Set<ChunkPosition> checked = new HashSet<>(); + this.clearQueue(false); + + for (int aY = yStart; this.mPumpList.isEmpty() && aY >= yEnd; aY--) { + // Start at the top (presumably the block below the pump), and work our way down to the end (presumably the + // location of the pump Head) + // and build up a queue of fluids to pump + fluidsToSearch.add(new ChunkPosition(aX, aY, aZ)); + + while (!fluidsToSearch.isEmpty()) { + for (ChunkPosition tPos : fluidsToSearch) { + // Look all around + if (tPos.chunkPosX < aX + mDist) + queueFluid(tPos.chunkPosX + 1, tPos.chunkPosY, tPos.chunkPosZ, fluidsFound, checked); + if (tPos.chunkPosX > aX - mDist) + queueFluid(tPos.chunkPosX - 1, tPos.chunkPosY, tPos.chunkPosZ, fluidsFound, checked); + if (tPos.chunkPosZ < aZ + mDist) + queueFluid(tPos.chunkPosX, tPos.chunkPosY, tPos.chunkPosZ + 1, fluidsFound, checked); + if (tPos.chunkPosZ > aZ - mDist) + queueFluid(tPos.chunkPosX, tPos.chunkPosY, tPos.chunkPosZ - 1, fluidsFound, checked); + + // And then look up + queueFluid(tPos.chunkPosX, tPos.chunkPosY + 1, tPos.chunkPosZ, this.mPumpList, checked); + } + this.mPumpList.addAll(fluidsFound); + fluidsToSearch = fluidsFound; + fluidsFound = new ArrayDeque<>(); + } + + // Make sure we don't have the pipe location in the queue + this.mPumpList.remove(new ChunkPosition(aX, aY, aZ)); + } + } + + private boolean queueFluid(int aX, int aY, int aZ, ArrayDeque<ChunkPosition> fluidsFound, + Set<ChunkPosition> checked) { + // If we haven't already looked at this coordinate set, and it's not already in the list of fluids found, see if + // there is + // a valid fluid and add it to the fluids found + ChunkPosition tCoordinate = new ChunkPosition(aX, aY, aZ); + if (checked.add(tCoordinate) && !fluidsFound.contains(tCoordinate)) { + Block aBlock = getBaseMetaTileEntity().getBlock(aX, aY, aZ); + if ((this.mPrimaryPumpedBlock == aBlock) || (this.mSecondaryPumpedBlock == aBlock)) { + fluidsFound.addFirst(tCoordinate); + return true; + } + } + return false; + } + + private void checkForFluidToPump(int aX, int aY, int aZ) { + // If we don't currently have a valid fluid to pump, try pumping the fluid at the given coordinates + if (this.hasValidFluid()) return; + + Block aBlock = getBaseMetaTileEntity().getBlock(aX, aY, aZ); + if (aBlock != null) { + if (isWater(aBlock)) { + this.mPrimaryPumpedBlock = Blocks.water; + this.mSecondaryPumpedBlock = Blocks.flowing_water; + return; + } + if (isLava(aBlock)) { + this.mPrimaryPumpedBlock = Blocks.lava; + this.mSecondaryPumpedBlock = Blocks.flowing_lava; + return; + } + if ((aBlock instanceof IFluidBlock)) { + this.mPrimaryPumpedBlock = aBlock; + this.mSecondaryPumpedBlock = aBlock; + return; + } + } + this.mPrimaryPumpedBlock = null; + this.mSecondaryPumpedBlock = null; + } + + /** only check if block below can be replaced with pipe tip. pipe stockpile condition is ignored */ + private boolean canMoveDown(int aX, int aY, int aZ) { + if (!GT_Utility.eraseBlockByFakePlayer(getFakePlayer(getBaseMetaTileEntity()), aX, aY, aZ, true)) return false; + + Block aBlock = getBaseMetaTileEntity().getBlock(aX, aY, aZ); + + return aBlock != null && aBlock.isReplaceable(getBaseMetaTileEntity().getWorld(), aX, aY, aZ); + } + + private boolean consumeFluid(int aX, int aY, int aZ) { + // Try to consume a fluid at a location + // Returns true if something was consumed, otherwise false + if (!GT_Utility.eraseBlockByFakePlayer(getFakePlayer(getBaseMetaTileEntity()), aX, aY, aZ, true)) return false; + + Block aBlock = getBaseMetaTileEntity().getBlock(aX, aY, aZ); + if (!isFluid(aBlock)) { + return false; + } + + if (aBlock != null && ((this.mPrimaryPumpedBlock == aBlock) || (this.mSecondaryPumpedBlock == aBlock))) { + boolean isWaterOrLava = ((this.mPrimaryPumpedBlock == Blocks.water + || this.mPrimaryPumpedBlock == Blocks.lava)); + + if (isWaterOrLava && getBaseMetaTileEntity().getMetaID(aX, aY, aZ) != 0) { + // Water/Lava that isn't a source block - do nothing here, but set the block to air and consume energy + // below + if (debugBlockPump) { + GT_Log.out.println("PUMP: Water/Lava - Not a source block"); + } + + } else if (getDrainableStack() == null) { + // The pump has no internal fluid + if (this.mPrimaryPumpedBlock == Blocks.water) setDrainableStack(GT_ModHandler.getWater(1000L)); + else if (this.mPrimaryPumpedBlock == Blocks.lava) setDrainableStack(GT_ModHandler.getLava(1000L)); + else { + // Not water or lava; try to drain and set to air + setDrainableStack( + ((IFluidBlock) aBlock).drain(getBaseMetaTileEntity().getWorld(), aX, aY, aZ, true)); + } + + } else if (GT_ModHandler.isWater(getDrainableStack()) || GT_ModHandler.isLava(getDrainableStack()) + || getDrainableStack().isFluidEqual( + ((IFluidBlock) aBlock).drain(getBaseMetaTileEntity().getWorld(), aX, aY, aZ, false))) { + if (!isWaterOrLava) { + // Only set Block to Air for non lava/water fluids + this.getBaseMetaTileEntity() + .getWorld() + .setBlockToAir(aX, aY, aZ); + } + getDrainableStack().amount += 1000; + + } else { + if (debugBlockPump) { + GT_Log.out.println("PUMP: Couldn't consume " + aBlock); + } + // We didn't do anything + return false; + } + + getBaseMetaTileEntity().decreaseStoredEnergyUnits(this.getEuUsagePerAction(), true); + getBaseMetaTileEntity().getWorld() + .setBlock(aX, aY, aZ, Blocks.air, 0, 2); + return true; + } + return false; + } + + private static boolean isWater(Block aBlock) { + return aBlock == Blocks.water || aBlock == Blocks.flowing_water; + } + + private static boolean isLava(Block aBlock) { + return aBlock == Blocks.lava || aBlock == Blocks.flowing_lava; + } + + private static boolean isFluid(Block aBlock) { + return isWater(aBlock) || isLava(aBlock) || aBlock instanceof IFluidBlock; + } + + @Override + public ArrayList<String> getSpecialDebugInfo(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, + int aLogLevel, ArrayList<String> aList) { + aList.addAll( + Arrays.asList( + EnumChatFormatting.BLUE + StatCollector.translateToLocal("GT5U.machines.pump") + + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.machines.workarea") + ": " + + EnumChatFormatting.GREEN + + (radiusConfig * 2 + 1) + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.machines.blocks"), + "Primary pumping fluid: " + + (this.mPrimaryPumpedBlock != null ? this.mPrimaryPumpedBlock.getLocalizedName() : "None"), + "Secondary pumping fluid: " + + (this.mSecondaryPumpedBlock != null ? this.mSecondaryPumpedBlock.getLocalizedName() : "None"), + "Pumps below: " + mPumpCountBelow, + "Queue size: " + mPumpList.size(), + "Pump head at Y: " + getYOfPumpHead(), + "Pump timer: " + mPumpTimer, + "Meta Entity Timer: " + getBaseMetaTileEntity().getTimer())); + return aList; + } + + private FakePlayer mFakePlayer = null; + + protected FakePlayer getFakePlayer(IGregTechTileEntity aBaseTile) { + if (mFakePlayer == null) mFakePlayer = GT_Utility.getFakePlayer(aBaseTile); + mFakePlayer.setWorld(aBaseTile.getWorld()); + mFakePlayer.setPosition(aBaseTile.getXCoord(), aBaseTile.getYCoord(), aBaseTile.getZCoord()); + return mFakePlayer; + } + + @Override + public String[] getInfoData() { + return new String[] { + EnumChatFormatting.BLUE + StatCollector.translateToLocal("GT5U.machines.pump") + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.machines.workarea") + ": " + + EnumChatFormatting.GREEN + + (radiusConfig * 2 + 1) + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.machines.blocks") }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Replicator.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Replicator.java new file mode 100644 index 0000000000..a15d5b7f6d --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Replicator.java @@ -0,0 +1,127 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_REPLICATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_REPLICATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_REPLICATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_REPLICATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_REPLICATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_REPLICATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_REPLICATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_REPLICATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_REPLICATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_REPLICATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_REPLICATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_REPLICATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_REPLICATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_REPLICATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_REPLICATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_REPLICATOR_GLOW; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.MachineType; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; + +public class GT_MetaTileEntity_Replicator extends GT_MetaTileEntity_BasicMachine { + + public GT_MetaTileEntity_Replicator(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 1, + MachineType.REPLICATOR.tooltipDescription(), + 1, + 1, + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_REPLICATOR_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_REPLICATOR_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_REPLICATOR), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_REPLICATOR_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_REPLICATOR_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_REPLICATOR_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_REPLICATOR), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_REPLICATOR_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_REPLICATOR_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_REPLICATOR_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_REPLICATOR), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_REPLICATOR_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_REPLICATOR_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_REPLICATOR_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_REPLICATOR), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_REPLICATOR_GLOW) + .glow() + .build())); + } + + public GT_MetaTileEntity_Replicator(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 1, aDescription, aTextures, 1, 1); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Replicator(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.replicatorRecipes; + } + + @Override + protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack) + && ItemList.Cell_Empty.isStackEqual(aStack); + } + + @Override + public boolean isFluidInputAllowed(FluidStack aFluid) { + return aFluid.isFluidEqual(Materials.UUMatter.getFluid(1L)); + } + + @Override + public int getCapacity() { + return 3000; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_RockBreaker.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_RockBreaker.java new file mode 100644 index 0000000000..e632f4eeda --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_RockBreaker.java @@ -0,0 +1,169 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_ROCK_BREAKER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_ROCK_BREAKER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_ROCK_BREAKER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_ROCK_BREAKER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_ROCK_BREAKER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_ROCK_BREAKER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_ROCK_BREAKER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_ROCK_BREAKER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_ROCK_BREAKER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_ROCK_BREAKER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_ROCK_BREAKER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_ROCK_BREAKER_GLOW; + +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.MachineType; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_RockBreaker extends GT_MetaTileEntity_BasicMachine { + + public GT_MetaTileEntity_RockBreaker(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 1, + MachineType.ROCKBREAKER.tooltipDescription(), + 1, + 1, + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_ROCK_BREAKER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_ROCK_BREAKER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_ROCK_BREAKER), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_ROCK_BREAKER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_ROCK_BREAKER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ROCK_BREAKER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_ROCK_BREAKER), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ROCK_BREAKER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_ROCK_BREAKER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_ROCK_BREAKER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_ROCK_BREAKER), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_ROCK_BREAKER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_ROCK_BREAKER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_ROCK_BREAKER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_ROCK_BREAKER), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_ROCK_BREAKER_GLOW) + .glow() + .build())); + } + + public GT_MetaTileEntity_RockBreaker(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 1, aDescription, aTextures, 1, 1); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_RockBreaker(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.rockBreakerFakeRecipes; + } + + @Override + protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack) + && getRecipeMap().containsInput(aStack); + } + + @Override + public boolean allowSelectCircuit() { + return true; + } + + @Override + public int checkRecipe() { + IGregTechTileEntity aBaseMetaTileEntity = getBaseMetaTileEntity(); + if ((aBaseMetaTileEntity.getBlockOffset(0, 0, 1) == Blocks.water) + || (aBaseMetaTileEntity.getBlockOffset(0, 0, -1) == Blocks.water) + || (aBaseMetaTileEntity.getBlockOffset(-1, 0, 0) == Blocks.water) + || (aBaseMetaTileEntity.getBlockOffset(1, 0, 0) == Blocks.water)) { + ItemStack tOutput = null; + if (aBaseMetaTileEntity.getBlockOffset(0, 1, 0) == Blocks.lava) { + tOutput = new ItemStack(Blocks.stone, 1); + } else if ((aBaseMetaTileEntity.getBlockOffset(0, 0, 1) == Blocks.lava) + || (aBaseMetaTileEntity.getBlockOffset(0, 0, -1) == Blocks.lava) + || (aBaseMetaTileEntity.getBlockOffset(-1, 0, 0) == Blocks.lava) + || (aBaseMetaTileEntity.getBlockOffset(1, 0, 0) == Blocks.lava)) { + tOutput = new ItemStack(Blocks.cobblestone, 1); + } + if (tOutput != null) { + if (GT_Utility.areStacksEqual(getStackInSlot(getCircuitSlot()), GT_Utility.getIntegratedCircuit(1))) { + if (GT_Utility.areStacksEqual( + getInputAt(0), + GT_OreDictUnificator.get(OrePrefixes.dust, Materials.Redstone, 1L))) { + tOutput = new ItemStack(Blocks.obsidian, 1); + if (canOutput(tOutput)) { + getInputAt(0).stackSize -= 1; + calculateOverclockedNess(30, 128); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + this.mOutputItems[0] = tOutput; + return 2; + } + } + } else if (canOutput(tOutput)) { + calculateOverclockedNess(30, 16); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + this.mOutputItems[0] = tOutput; + return 2; + } + } + } + return 0; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Scanner.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Scanner.java new file mode 100644 index 0000000000..ba00be67f8 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Scanner.java @@ -0,0 +1,425 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.GT_Values.D1; +import static gregtech.api.enums.Mods.GalacticraftCore; +import static gregtech.api.enums.Mods.GalacticraftMars; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_SCANNER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_SCANNER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_SCANNER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_SCANNER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_SCANNER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_SCANNER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_SCANNER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_SCANNER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_SCANNER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_SCANNER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_SCANNER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_SCANNER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_SCANNER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_SCANNER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_SCANNER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_SCANNER_GLOW; +import static gregtech.api.recipe.RecipeMaps.scannerFakeRecipes; + +import java.util.Objects; + +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; + +import forestry.api.genetics.AlleleManager; +import forestry.api.genetics.IIndividual; +import gregtech.GT_Mod; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.MachineType; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine; +import gregtech.api.objects.ItemData; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_AssemblyLineUtils; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.common.items.behaviors.Behaviour_DataOrb; + +public class GT_MetaTileEntity_Scanner extends GT_MetaTileEntity_BasicMachine { + + public GT_MetaTileEntity_Scanner(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 1, + MachineType.SCANNER.tooltipDescription(), + 1, + 1, + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_SCANNER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_SCANNER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_SIDE_SCANNER), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_SCANNER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_SCANNER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_SCANNER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_FRONT_SCANNER), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_SCANNER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_SCANNER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_SCANNER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_SCANNER), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_SCANNER_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_SCANNER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_SCANNER_ACTIVE_GLOW) + .glow() + .build()), + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_SCANNER), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_SCANNER_GLOW) + .glow() + .build())); + } + + public GT_MetaTileEntity_Scanner(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 1, aDescription, aTextures, 1, 1); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Scanner(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public int checkRecipe() { + ItemStack aStack = getInputAt(0); + if (getOutputAt(0) != null) { + this.mOutputBlocked += 1; + } else if ((GT_Utility.isStackValid(aStack)) && (aStack.stackSize > 0)) { + if ((getFillableStack() != null) && (getFillableStack().containsFluid(Materials.Honey.getFluid(100L)))) { + try { + IIndividual tIndividual = AlleleManager.alleleRegistry.getIndividual(aStack); + if (tIndividual != null) { + if (tIndividual.analyze()) { + getFillableStack().amount -= 100; + this.mOutputItems[0] = GT_Utility.copyOrNull(aStack); + aStack.stackSize = 0; + NBTTagCompound tNBT = new NBTTagCompound(); + tIndividual.writeToNBT(tNBT); + this.mOutputItems[0].setTagCompound(tNBT); + calculateOverclockedNess(2, 500); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + return 2; + } + this.mOutputItems[0] = GT_Utility.copyOrNull(aStack); + aStack.stackSize = 0; + this.mMaxProgresstime = 1; + this.mEUt = 1; + return 2; + } + } catch (Throwable e) { + if (D1) { + e.printStackTrace(GT_Log.err); + } + } + } + if (ItemList.IC2_Crop_Seeds.isStackEqual(aStack, true, true)) { + NBTTagCompound tNBT = aStack.getTagCompound(); + if (tNBT == null) { + tNBT = new NBTTagCompound(); + } + if (tNBT.getByte("scan") < 4) { + tNBT.setByte("scan", (byte) 4); + calculateOverclockedNess(8, 160); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + } else { + this.mMaxProgresstime = 1; + this.mEUt = 1; + } + aStack.stackSize -= 1; + this.mOutputItems[0] = GT_Utility.copyAmount(1, aStack); + assert this.mOutputItems[0] != null; + this.mOutputItems[0].setTagCompound(tNBT); + return 2; + } + if (ItemList.Tool_DataOrb.isStackEqual(getSpecialSlot(), false, true)) { + if (ItemList.Tool_DataOrb.isStackEqual(aStack, false, true)) { + aStack.stackSize -= 1; + this.mOutputItems[0] = GT_Utility.copyAmount(1, getSpecialSlot()); + calculateOverclockedNess(30, 512); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + return 2; + } + ItemData tData = GT_OreDictUnificator.getAssociation(aStack); + if ((tData != null) && ((tData.mPrefix == OrePrefixes.dust) || (tData.mPrefix == OrePrefixes.cell)) + && (tData.mMaterial.mMaterial.mElement != null) + && (!tData.mMaterial.mMaterial.mElement.mIsIsotope) + && (tData.mMaterial.mMaterial != Materials.Magic) + && (tData.mMaterial.mMaterial.getMass() > 0L)) { + getSpecialSlot().stackSize -= 1; + aStack.stackSize -= 1; + + this.mOutputItems[0] = ItemList.Tool_DataOrb.get(1L); + Behaviour_DataOrb.setDataTitle(this.mOutputItems[0], "Elemental-Scan"); + Behaviour_DataOrb.setDataName(this.mOutputItems[0], tData.mMaterial.mMaterial.mElement.name()); + calculateOverclockedNess(30, GT_Utility.safeInt(tData.mMaterial.mMaterial.getMass() * 8192L)); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + return 2; + } + } + if (ItemList.Tool_DataStick.isStackEqual(getSpecialSlot(), false, true)) { + if (ItemList.Tool_DataStick.isStackEqual(aStack, false, true)) { + aStack.stackSize -= 1; + this.mOutputItems[0] = GT_Utility.copyAmount(1, getSpecialSlot()); + calculateOverclockedNess(30, 128); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + return 2; + } + if (aStack.getItem() == Items.written_book) { + getSpecialSlot().stackSize -= 1; + aStack.stackSize -= 1; + + this.mOutputItems[0] = GT_Utility.copyAmount(1, getSpecialSlot()); + assert this.mOutputItems[0] != null; + this.mOutputItems[0].setTagCompound(aStack.getTagCompound()); + calculateOverclockedNess(30, 128); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + return 2; + } + if (aStack.getItem() == Items.filled_map) { + getSpecialSlot().stackSize -= 1; + aStack.stackSize -= 1; + + this.mOutputItems[0] = GT_Utility.copyAmount(1, getSpecialSlot()); + assert this.mOutputItems[0] != null; + this.mOutputItems[0].setTagCompound( + GT_Utility + .getNBTContainingShort(new NBTTagCompound(), "map_id", (short) aStack.getItemDamage())); + calculateOverclockedNess(30, 128); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + return 2; + } + + if ((aStack.getItem() + .getUnlocalizedName() + .contains("Schematic") + || aStack.getItem() + .getUnlocalizedName() + .contains("schematic")) + && !aStack.getItem() + .getUnlocalizedName() + .contains("Schematics")) { + if (mTier < 3) return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + String sTier = ""; + + int stackItemID = Item.getIdFromItem(aStack.getItem()); + int stackItemDamage = aStack.getItemDamage(); + if (stackItemID == Item.getIdFromItem( + Objects.requireNonNull(GT_ModHandler.getModItem(GalacticraftCore.ID, "item.schematic", 1L, 0)) + .getItem())) { + if (stackItemDamage == 0 && aStack.toString() + .equals( + Objects + .requireNonNull( + GT_ModHandler.getModItem(GalacticraftCore.ID, "item.schematic", 1L, 0)) + .copy() + .toString())) + sTier = "100"; + else if (stackItemDamage == 1 && aStack.toString() + .equals( + Objects + .requireNonNull( + GT_ModHandler.getModItem(GalacticraftCore.ID, "item.schematic", 1L, 1)) + .copy() + .toString())) + sTier = "2"; + } else { + if (stackItemID == Item.getIdFromItem( + Objects + .requireNonNull(GT_ModHandler.getModItem(GalacticraftMars.ID, "item.schematic", 1L, 0)) + .getItem())) { + if (stackItemDamage == 0 && aStack.toString() + .equals( + Objects + .requireNonNull( + GT_ModHandler.getModItem(GalacticraftMars.ID, "item.schematic", 1L, 0)) + .copy() + .toString())) + sTier = "3"; + else if (stackItemDamage == 1 && aStack.toString() + .equals( + Objects + .requireNonNull( + GT_ModHandler.getModItem(GalacticraftMars.ID, "item.schematic", 1L, 1)) + .copy() + .toString())) + sTier = "101"; + else if (stackItemDamage == 2 && aStack.toString() + .equals( + Objects + .requireNonNull( + GT_ModHandler.getModItem(GalacticraftMars.ID, "item.schematic", 1L, 2)) + .copy() + .toString())) + sTier = "102"; + } else if (aStack.getUnlocalizedName() + .matches(".*\\d+.*")) + sTier = aStack.getUnlocalizedName() + .split("(?<=\\D)(?=\\d)")[1].substring(0, 1); + else sTier = "1"; + } + + getSpecialSlot().stackSize -= 1; + aStack.stackSize -= 1; + + this.mOutputItems[0] = GT_Utility.copyAmount(1, getSpecialSlot()); + assert this.mOutputItems[0] != null; + this.mOutputItems[0].setTagCompound( + GT_Utility.getNBTContainingShort(new NBTTagCompound(), "rocket_tier", Short.parseShort(sTier))); + + calculateOverclockedNess(480, 36000); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + return 2; + } + } + if (getSpecialSlot() == null && ItemList.Tool_DataStick.isStackEqual(aStack, false, true)) { + if (GT_Utility.ItemNBT.getBookTitle(aStack) + .equals("Raw Prospection Data")) { + GT_Utility.ItemNBT.setBookTitle(aStack, "Analyzed Prospection Data"); + GT_Utility.ItemNBT.convertProspectionData(aStack); + aStack.stackSize -= 1; + + this.mOutputItems[0] = GT_Utility.copyAmount(1, aStack); + calculateOverclockedNess(30, 1000); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + return 2; + } + } + if (ItemList.Tool_DataStick.isStackEqual(getSpecialSlot(), false, true)) { + for (GT_Recipe.GT_Recipe_AssemblyLine tRecipe : GT_Recipe.GT_Recipe_AssemblyLine.sAssemblylineRecipes) { + if (GT_Utility.areStacksEqual(tRecipe.mResearchItem, aStack, true)) { + boolean failScanner = true; + for (GT_Recipe scannerRecipe : scannerFakeRecipes.getAllRecipes()) { + if (GT_Utility.areStacksEqual(scannerRecipe.mInputs[0], aStack, true)) { + failScanner = false; + break; + } + } + if (failScanner) { + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + } + + this.mOutputItems[0] = GT_Utility.copyAmount(1, getSpecialSlot()); + + // Use Assline Utils + if (GT_AssemblyLineUtils.setAssemblyLineRecipeOnDataStick(this.mOutputItems[0], tRecipe)) { + aStack.stackSize -= 1; + calculateOverclockedNess(30, tRecipe.mResearchTime); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + getSpecialSlot().stackSize -= 1; + return 2; + } + } + } + } + } + return 0; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (mProgresstime >= (mMaxProgresstime - 1)) { + if ((this.mOutputItems[0] != null) && (this.mOutputItems[0].getUnlocalizedName() + .equals("gt.metaitem.01.32707"))) { + GT_Mod.achievements.issueAchievement( + aBaseMetaTileEntity.getWorld() + .getPlayerEntityByName(aBaseMetaTileEntity.getOwnerName()), + "scanning"); + } + } + super.onPostTick(aBaseMetaTileEntity, aTick); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return scannerFakeRecipes; + } + + @Override + public int getCapacity() { + return 1000; + } + + @Override + protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack) + && getRecipeMap().containsInput(aStack); + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_MAGNETIZER_LOOP, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Teleporter.java b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Teleporter.java new file mode 100644 index 0000000000..0666c55ac4 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/basic/GT_MetaTileEntity_Teleporter.java @@ -0,0 +1,609 @@ +package gregtech.common.tileentities.machines.basic; + +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASINGS; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER_SIDES; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TELEPORTER_SIDES_GLOW; + +import java.util.List; +import java.util.function.Consumer; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityHanging; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.boss.EntityDragonPart; +import net.minecraft.entity.effect.EntityWeatherEffect; +import net.minecraft.entity.item.EntityBoat; +import net.minecraft.entity.item.EntityEnderCrystal; +import net.minecraft.entity.item.EntityEnderEye; +import net.minecraft.entity.item.EntityFireworkRocket; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.item.EntityMinecart; +import net.minecraft.entity.item.EntityTNTPrimed; +import net.minecraft.entity.item.EntityXPOrb; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.entity.projectile.EntityFireball; +import net.minecraft.entity.projectile.EntityFishHook; +import net.minecraft.entity.projectile.EntityThrowable; +import net.minecraft.inventory.IInventory; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.world.World; +import net.minecraftforge.common.DimensionManager; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import com.gtnewhorizons.modularui.api.NumberFormatMUI; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import gregtech.api.enums.ConfigCategories; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.gui.modularui.GUITextureSet; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.modularui.IAddGregtechLogo; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicTank; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Config; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Teleporter extends GT_MetaTileEntity_BasicTank + implements IAddGregtechLogo, IAddUIWidgets { + + private static boolean sInterDimensionalTeleportAllowed = true; + private static int sPassiveEnergyDrain = 2048; + private static int sPowerMultiplyer = 100; + private static double sFPowerMultiplyer = 1.0; + public int mTargetX = 0; + public int mTargetY = 0; + public int mTargetZ = 0; + public int mTargetD = Integer.MIN_VALUE; + public boolean mDebug = false; + + public GT_MetaTileEntity_Teleporter(int aID, String aName, String aNameRegional, int aTier) { + super( + aID, + aName, + aNameRegional, + aTier, + 3, + new String[] { "Teleport long distances with this little device.", "Use a Dragon Egg or Nitrogen Plasma", + "for Inter-dimensional transmission" }); + } + + public GT_MetaTileEntity_Teleporter(String aName, int aTier, String aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 3, aDescription, aTextures); + } + + public GT_MetaTileEntity_Teleporter(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 3, aDescription, aTextures); + } + + private static float calculateWeight(Entity aEntity) { + if ((aEntity instanceof EntityFishHook)) { + return -1.0F; + } + if ((aEntity instanceof EntityDragonPart)) { + return -1.0F; + } + if ((aEntity instanceof EntityWeatherEffect)) { + return -1.0F; + } + if ((aEntity instanceof EntityPlayer tPlayer)) { + int tCount = 64; + for (int i = 0; i < 36; i++) { + if (tPlayer.inventory.getStackInSlot(i) != null) { + tCount += (tPlayer.inventory.getStackInSlot(i) + .getMaxStackSize() > 1 ? tPlayer.inventory.getStackInSlot(i).stackSize : 64); + } + } + for (int i = 0; i < 4; i++) { + if (tPlayer.inventory.armorInventory[i] != null) { + tCount += 256; + } + } + return Math.min(5.0F, tCount / 666.6F); + } + if (GT_Utility.getClassName(aEntity) + .equals("EntityItnt")) { + return 5.0F; + } + if (GT_Utility.getClassName(aEntity) + .equals("EntityNuke")) { + return 50.0F; + } + if ((aEntity instanceof EntityArrow)) { + return 0.001F; + } + if ((aEntity instanceof EntityBoat)) { + return 0.1F; + } + if ((aEntity instanceof EntityEnderCrystal)) { + return 2.0F; + } + if ((aEntity instanceof EntityEnderEye)) { + return 0.001F; + } + if ((aEntity instanceof EntityFireball)) { + return 0.001F; + } + if ((aEntity instanceof EntityFireworkRocket)) { + return 0.001F; + } + if ((aEntity instanceof EntityHanging)) { + return 0.005F; + } + if ((aEntity instanceof EntityItem)) { + return 0.001F; + } + if ((aEntity instanceof EntityLiving)) { + return 0.5F; + } + if ((aEntity instanceof EntityMinecart)) { + return 0.1F; + } + if ((aEntity instanceof EntityThrowable)) { + return 0.001F; + } + if ((aEntity instanceof EntityTNTPrimed)) { + return 5.0F; + } + if ((aEntity instanceof EntityXPOrb)) { + return 0.001F; + } + return -1.0F; + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (aBaseMetaTileEntity.isClientSide()) return true; + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Teleporter(this.mName, this.mTier, this.mDescriptionArray, this.mTextures); + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public String[] getInfoData() { + return new String[] { "Coordinates:", + "X: " + EnumChatFormatting.GREEN + GT_Utility.formatNumbers(this.mTargetX) + EnumChatFormatting.RESET, + "Y: " + EnumChatFormatting.GREEN + GT_Utility.formatNumbers(this.mTargetY) + EnumChatFormatting.RESET, + "Z: " + EnumChatFormatting.GREEN + GT_Utility.formatNumbers(this.mTargetZ) + EnumChatFormatting.RESET, + "Dimension: " + EnumChatFormatting.GREEN + this.mTargetD + EnumChatFormatting.RESET, + "Dimension Valid: " + (GT_Utility.isRealDimension(this.mTargetD) + ? EnumChatFormatting.GREEN + "Yes" + EnumChatFormatting.RESET + : EnumChatFormatting.RED + "No" + EnumChatFormatting.RESET), + "Dimension Registered: " + (DimensionManager.isDimensionRegistered(this.mTargetD) + ? EnumChatFormatting.GREEN + "Yes" + EnumChatFormatting.RESET + : EnumChatFormatting.RED + "No" + EnumChatFormatting.RESET) }; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side != this.getBaseMetaTileEntity() + .getFrontFacing()) + return new ITexture[] { MACHINE_CASINGS[mTier][colorIndex + 1], TextureFactory.of(OVERLAY_TELEPORTER_SIDES), + TextureFactory.builder() + .addIcon(OVERLAY_TELEPORTER_SIDES_GLOW) + .glow() + .build() }; + if (aActive) return new ITexture[] { MACHINE_CASINGS[mTier][colorIndex + 1], + TextureFactory.of(OVERLAY_TELEPORTER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_TELEPORTER_ACTIVE_GLOW) + .glow() + .build() }; + return new ITexture[] { MACHINE_CASINGS[mTier][colorIndex + 1], TextureFactory.of(OVERLAY_TELEPORTER), + TextureFactory.builder() + .addIcon(OVERLAY_TELEPORTER_GLOW) + .glow() + .build() }; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + if (mFluid != null) aNBT.setTag("mFluid", mFluid.writeToNBT(new NBTTagCompound())); + aNBT.setInteger("mTargetX", this.mTargetX); + aNBT.setInteger("mTargetY", this.mTargetY); + aNBT.setInteger("mTargetZ", this.mTargetZ); + aNBT.setInteger("mTargetD", this.mTargetD); + aNBT.setBoolean("mDebug", this.mDebug); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + mFluid = FluidStack.loadFluidStackFromNBT(aNBT.getCompoundTag("mFluid")); + this.mTargetX = aNBT.getInteger("mTargetX"); + this.mTargetY = aNBT.getInteger("mTargetY"); + this.mTargetZ = aNBT.getInteger("mTargetZ"); + this.mTargetD = aNBT.getInteger("mTargetD"); + this.mDebug = aNBT.getBoolean("mDebug"); + } + + @Override + public void onConfigLoad(GT_Config aConfig) { + sInterDimensionalTeleportAllowed = aConfig + .get(ConfigCategories.machineconfig, "Teleporter.Interdimensional", true); + sPassiveEnergyDrain = aConfig + .get(ConfigCategories.machineconfig, "Teleporter.PassiveDrain", sPassiveEnergyDrain); + sPowerMultiplyer = aConfig.get(ConfigCategories.machineconfig, "Teleporter.PowerMultipler", sPowerMultiplyer); + sFPowerMultiplyer = sPowerMultiplyer / 100.0; + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + if (getBaseMetaTileEntity().isServerSide()) { + if ((this.mTargetX == 0) && (this.mTargetY == 0) + && (this.mTargetZ == 0) + && (this.mTargetD == Integer.MIN_VALUE)) { + this.mTargetX = aBaseMetaTileEntity.getXCoord(); + this.mTargetY = aBaseMetaTileEntity.getYCoord(); + this.mTargetZ = aBaseMetaTileEntity.getZCoord(); + this.mTargetD = aBaseMetaTileEntity.getWorld().provider.dimensionId; + } + } + } + + public boolean hasDimensionalTeleportCapability() { + return this.mDebug || sInterDimensionalTeleportAllowed; + } + + public boolean isDimensionalTeleportAvailable() { + return this.mDebug || (hasDimensionalTeleportCapability() && GT_Utility.isRealDimension(this.mTargetD) + && GT_Utility.isRealDimension(getBaseMetaTileEntity().getWorld().provider.dimensionId)); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + + if (mFluid != null) { // Was if null -> Materials.Nitrogen.getPlasma(0); + mFluid = null; + } + super.onPostTick(aBaseMetaTileEntity, aTick); + if (getBaseMetaTileEntity().isServerSide()) { + if ((getBaseMetaTileEntity().isAllowedToWork()) && (getBaseMetaTileEntity().getRedstone())) { + if (getBaseMetaTileEntity().decreaseStoredEnergyUnits(sPassiveEnergyDrain, false)) { + int tDistance = distanceCalculation(); + if (mInventory[0] != null) { + TileEntity tTile = null; + if (this.mTargetD == getBaseMetaTileEntity().getWorld().provider.dimensionId) { + tTile = getBaseMetaTileEntity().getTileEntity(this.mTargetX, this.mTargetY, this.mTargetZ); + } else { + World tWorld = DimensionManager.getWorld(this.mTargetD); + if (tWorld != null) { + tTile = tWorld.getTileEntity(this.mTargetX, this.mTargetY, this.mTargetZ); + } + } + if (tTile instanceof IInventory) { + int tStacksize = mInventory[0].stackSize; + GT_Utility.moveOneItemStack( + this, + tTile, + ForgeDirection.DOWN, + ForgeDirection.DOWN, + null, + false, + (byte) 64, + (byte) 1, + (byte) 64, + (byte) 1); + if (mInventory[0] == null || mInventory[0].stackSize < tStacksize) { + getBaseMetaTileEntity().decreaseStoredEnergyUnits( + (long) (Math.pow(tDistance, 1.5) * tDistance + * (tStacksize - (mInventory[0] == null ? 0 : mInventory[0].stackSize)) + * sFPowerMultiplyer), + false); + } + } + } + List<Entity> entities_in_box = getBaseMetaTileEntity().getWorld() + .getEntitiesWithinAABB( + Entity.class, + AxisAlignedBB.getBoundingBox( + getBaseMetaTileEntity().getOffsetX(getBaseMetaTileEntity().getFrontFacing(), 2) - 1, + getBaseMetaTileEntity().getOffsetY(getBaseMetaTileEntity().getFrontFacing(), 2) - 1, + getBaseMetaTileEntity().getOffsetZ(getBaseMetaTileEntity().getFrontFacing(), 2) - 1, + getBaseMetaTileEntity().getOffsetX(getBaseMetaTileEntity().getFrontFacing(), 2) + 2, + getBaseMetaTileEntity().getOffsetY(getBaseMetaTileEntity().getFrontFacing(), 2) + 2, + getBaseMetaTileEntity().getOffsetZ(getBaseMetaTileEntity().getFrontFacing(), 2) + 2)); + + for (Object tObject : entities_in_box) { + if (((tObject instanceof Entity tEntity)) && (!((Entity) tObject).isDead)) { + if (getBaseMetaTileEntity().decreaseStoredEnergyUnits( + (long) (Math.pow(tDistance, 1.5) * calculateWeight(tEntity) * sFPowerMultiplyer), + false)) { + + if (tEntity.ridingEntity != null) { + tEntity.mountEntity(null); + } + if (tEntity.riddenByEntity != null) { + tEntity.riddenByEntity.mountEntity(null); + } + if ((this.mTargetD == getBaseMetaTileEntity().getWorld().provider.dimensionId) + || (!isDimensionalTeleportAvailable()) + || (!GT_Utility.moveEntityToDimensionAtCoords( + tEntity, + this.mTargetD, + this.mTargetX + 0.5D, + this.mTargetY + 0.5D, + this.mTargetZ + 0.5D))) { + if ((tEntity instanceof EntityLivingBase)) { + ((EntityLivingBase) tEntity).setPositionAndUpdate( + this.mTargetX + 0.5D, + this.mTargetY + 0.5D, + this.mTargetZ + 0.5D); + } else { + tEntity.setPosition( + this.mTargetX + 0.5D, + this.mTargetY + 0.5D, + this.mTargetZ + 0.5D); + } + } + } + } + } + } + getBaseMetaTileEntity().setActive(true); + } else { + getBaseMetaTileEntity().setActive(false); + } + } + } + + private int distanceCalculation() { + return Math.abs( + ((this.mTargetD != getBaseMetaTileEntity().getWorld().provider.dimensionId) + && (isDimensionalTeleportAvailable()) + ? 4000 + : (int) Math.sqrt( + Math.pow(getBaseMetaTileEntity().getXCoord() - this.mTargetX, 2.0D) + + Math.pow(getBaseMetaTileEntity().getYCoord() - this.mTargetY, 2.0D) + + Math.pow(getBaseMetaTileEntity().getZCoord() - this.mTargetZ, 2.0D)))); + } + + @Override + public boolean isSimpleMachine() { + return false; + } + + @Override + public boolean isOverclockerUpgradable() { + return false; + } + + @Override + public boolean isTransformerUpgradable() { + return false; + } + + @Override + public boolean isElectric() { + return true; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isEnetInput() { + return true; + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return true; + } + + @Override + public boolean isOutputFacing(ForgeDirection side) { + return false; + } + + @Override + public boolean isTeleporterCompatible() { + return false; + } + + @Override + public long getMinimumStoredEU() { + return V[mTier] * 16; + } + + @Override + public long maxEUStore() { + return 100000000; + } + + @Override + public long maxEUInput() { + return V[mTier]; + } + + @Override + public long maxSteamStore() { + return maxEUStore(); + } + + @Override + public long maxAmperesIn() { + return 2; + } + + @Override + public int getStackDisplaySlot() { + return 2; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public int getInputSlot() { + return 0; + } + + @Override + public int getOutputSlot() { + return 0; + } + + @Override + public int getCapacity() { + return 64000; + } + + @Override + public boolean doesFillContainers() { + return false; + } + + @Override + public boolean doesEmptyContainers() { + return false; + } + + @Override + public boolean canTankBeFilled() { + return true; + } + + @Override + public boolean canTankBeEmptied() { + return true; + } + + @Override + public boolean displaysItemStack() { + return false; + } + + @Override + public boolean displaysStackSize() { + return false; + } + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + return null; + } + + @Override + public boolean useModularUI() { + return true; + } + + protected static final NumberFormatMUI numberFormat = new NumberFormatMUI(); + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + builder.widget( + new DrawableWidget().setDrawable(GT_UITextures.PICTURE_SCREEN_BLACK) + .setSize(90, 72) + .setPos(43, 4)) + .widget( + new TextWidget().setStringSupplier(() -> "X: " + numberFormat.format(mTargetX)) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setPos(46, 8)) + .widget( + new TextWidget().setStringSupplier(() -> "Y: " + numberFormat.format(mTargetY)) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setPos(46, 16)) + .widget( + new TextWidget().setStringSupplier(() -> "Z: " + numberFormat.format(mTargetZ)) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setPos(46, 24)) + .widget( + new TextWidget().setStringSupplier(() -> "Dim: " + numberFormat.format(mTargetD)) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setPos(46, 32)) + .widget( + TextWidget.dynamicString(() -> "Dim Valid: " + (GT_Utility.isRealDimension(mTargetD) ? "Yes" : "No")) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> hasDimensionalTeleportCapability()) + .setPos(46, 40)) + .widget(new FakeSyncWidget.FluidStackSyncer(() -> mFluid, val -> mFluid = val)); + + addChangeNumberButtons(builder, GT_UITextures.OVERLAY_BUTTON_MINUS_LARGE, -512, -64, 7); + addChangeNumberButtons(builder, GT_UITextures.OVERLAY_BUTTON_MINUS_SMALL, -16, -1, 25); + addChangeNumberButtons(builder, GT_UITextures.OVERLAY_BUTTON_PLUS_SMALL, 16, 1, 133); + addChangeNumberButtons(builder, GT_UITextures.OVERLAY_BUTTON_PLUS_LARGE, 512, 64, 151); + + addChangeNumberButton( + builder, + GT_UITextures.OVERLAY_BUTTON_MINUS_LARGE, + val -> mTargetD += val, + -16, + -8, + 7, + 58); + addChangeNumberButton( + builder, + GT_UITextures.OVERLAY_BUTTON_MINUS_SMALL, + val -> mTargetD += val, + -4, + -1, + 25, + 58); + addChangeNumberButton(builder, GT_UITextures.OVERLAY_BUTTON_PLUS_SMALL, val -> mTargetD += val, 4, 1, 133, 58); + addChangeNumberButton(builder, GT_UITextures.OVERLAY_BUTTON_PLUS_LARGE, val -> mTargetD += val, 16, 8, 151, 58); + } + + private void addChangeNumberButtons(ModularWindow.Builder builder, IDrawable overlay, int addNumberShift, + int addNumber, int xPos) { + addChangeNumberButton(builder, overlay, val -> mTargetX += val, addNumberShift, addNumber, xPos, 4); + addChangeNumberButton(builder, overlay, val -> mTargetY += val, addNumberShift, addNumber, xPos, 22); + addChangeNumberButton(builder, overlay, val -> mTargetZ += val, addNumberShift, addNumber, xPos, 40); + } + + private void addChangeNumberButton(ModularWindow.Builder builder, IDrawable overlay, Consumer<Integer> setter, + int addNumberShift, int addNumber, int xPos, int yPos) { + builder.widget( + new ButtonWidget() + .setOnClick((clickData, widget) -> setter.accept(clickData.shift ? addNumberShift : addNumber)) + .setBackground(GT_UITextures.BUTTON_STANDARD, overlay) + .setSize(18, 18) + .setPos(xPos, yPos)); + } + + @Override + public GUITextureSet getGUITextureSet() { + return new GUITextureSet().setGregTechLogo(GT_UITextures.PICTURE_GT_LOGO_17x17_TRANSPARENT_GRAY); + } + + @Override + public void addGregTechLogo(ModularWindow.Builder builder) { + builder.widget( + new DrawableWidget().setDrawable(getGUITextureSet().getGregTechLogo()) + .setSize(17, 17) + .setPos(113, 56)); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/long_distance/GT_MetaTileEntity_LongDistancePipelineBase.java b/src/main/java/gregtech/common/tileentities/machines/long_distance/GT_MetaTileEntity_LongDistancePipelineBase.java new file mode 100644 index 0000000000..ff3048f4b2 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/long_distance/GT_MetaTileEntity_LongDistancePipelineBase.java @@ -0,0 +1,415 @@ +/** + * + * Inspired/ported from GregTech 6 under the LGPL license + * + * Copyright (c) 2020 GregTech-6 Team + * + * This file is part of GregTech. + * + * GregTech is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * GregTech is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License along with GregTech. If not, see + * <http://www.gnu.org/licenses/>. + */ +package gregtech.common.tileentities.machines.long_distance; + +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASINGS; +import static mcp.mobius.waila.api.SpecialChars.BLUE; +import static mcp.mobius.waila.api.SpecialChars.GOLD; +import static mcp.mobius.waila.api.SpecialChars.GREEN; +import static mcp.mobius.waila.api.SpecialChars.RED; +import static mcp.mobius.waila.api.SpecialChars.RESET; +import static mcp.mobius.waila.api.SpecialChars.YELLOW; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.items.GT_Block_LongDistancePipe; +import gregtech.api.metatileentity.BaseMetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicHull_NonElectric; +import gregtech.api.util.GT_Utility; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public abstract class GT_MetaTileEntity_LongDistancePipelineBase extends GT_MetaTileEntity_BasicHull_NonElectric { + + protected static final int INPUT_INDEX = 0; + protected static final int OUTPUT_INDEX = 1; + protected static final int SIDE_UP_DOWN_INDEX = 2; + protected static final int SIDE_LEFT_RIGHT_INDEX = 3; + + public static int minimalDistancePoints = 64; + + protected GT_MetaTileEntity_LongDistancePipelineBase mTarget = null; + // these two are updated by machine block update thread, so must be volatile + protected volatile GT_MetaTileEntity_LongDistancePipelineBase mSender = null; + protected volatile ChunkCoordinates mTargetPos = null; + protected GT_MetaTileEntity_LongDistancePipelineBase mTooCloseTarget = null, mTooCloseSender = null; + + public GT_MetaTileEntity_LongDistancePipelineBase(int aID, String aName, String aNameRegional, int aTier, + String aDescription) { + super(aID, aName, aNameRegional, aTier, aDescription); + } + + public GT_MetaTileEntity_LongDistancePipelineBase(String aName, int aTier, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + @Override + public String[] getDescription() { + return new String[] { "Only one Input and Output are allowed per pipeline", + "Only Input and Output have to be chunkloaded", "Transfer rate is solely limited by input rate", + "Minimum distance: " + minimalDistancePoints + " blocks" }; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + if (mTargetPos != null && mTarget != this) { + aNBT.setBoolean("target", true); + aNBT.setInteger("target.x", mTargetPos.posX); + aNBT.setInteger("target.y", mTargetPos.posY); + aNBT.setInteger("target.z", mTargetPos.posZ); + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (aNBT.hasKey("target")) { + mTargetPos = new ChunkCoordinates( + aNBT.getInteger("target.x"), + aNBT.getInteger("target.y"), + aNBT.getInteger("target.z")); + if (getDistanceToSelf(mTargetPos) < minimalDistancePoints) mTargetPos = null; + } + } + + public boolean isSameClass(GT_MetaTileEntity_LongDistancePipelineBase other) { + return false; + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (aBaseMetaTileEntity.isClientSide()) return true; + ItemStack tCurrentItem = aPlayer.inventory.getCurrentItem(); + if (tCurrentItem != null) { + if (GT_Utility.isStackInList(tCurrentItem, GregTech_API.sSoftHammerList)) { + scanPipes(); + return true; + } + } + return false; + } + + public boolean isDead() { + return getBaseMetaTileEntity() == null || getBaseMetaTileEntity().isDead(); + } + + public boolean checkTarget() { + final IGregTechTileEntity gt_tile = getBaseMetaTileEntity(); + if (gt_tile == null || !gt_tile.isAllowedToWork() || gt_tile.isClientSide()) return false; + World world = gt_tile.getWorld(); + if (world == null) return false; + + if (mTargetPos == null) { + // We don't have a target position, scan the pipes + scanPipes(); + } else if (mTarget == null || mTarget.isDead()) { + // We don't have a target, or it's dead. Try checking the target position + mTarget = null; + if (world.blockExists(mTargetPos.posX, mTargetPos.posY, mTargetPos.posZ)) { + // Only check if the target position is loaded + TileEntity te = world.getTileEntity(mTargetPos.posX, mTargetPos.posY, mTargetPos.posZ); + final IMetaTileEntity tMeta; + if (te instanceof BaseMetaTileEntity + && ((tMeta = ((BaseMetaTileEntity) te) + .getMetaTileEntity()) instanceof GT_MetaTileEntity_LongDistancePipelineBase) + && isSameClass((GT_MetaTileEntity_LongDistancePipelineBase) tMeta)) { + // It's the right type! + mTarget = (GT_MetaTileEntity_LongDistancePipelineBase) tMeta; + } else if (te != null) { + // It isn't the right type, kill the target position + mTargetPos = null; + } + } + } + if (mTooCloseTarget != null && mTooCloseTarget.mSender == null) mTooCloseTarget.mTooCloseSender = this; + if (mTooCloseSender != null && (mTooCloseSender.isDead() || mTooCloseSender.mTarget != null)) + mTooCloseSender = null; + if (mTarget == null || mTarget == this) return false; + if (mTarget.mSender == null || mTarget.mSender.isDead() + || mTarget.mSender.mTarget == null + || mTarget.mSender.mTarget.isDead()) { + mTarget.mSender = this; + mTarget.mTooCloseSender = null; + } + + return mTarget.mSender == this; + } + + @Override + public ArrayList<String> getSpecialDebugInfo(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, + int aLogLevel, ArrayList<String> aList) { + if (mSender != null && !mSender.isDead() && mSender.mTarget == this) { + final ChunkCoordinates coords = mSender.getCoords(); + aList.addAll( + Arrays.asList( + "Is Pipeline Output", + "Pipeline Input is at: X: " + coords.posX + " Y: " + coords.posY + " Z: " + coords.posZ)); + } else { + aList.addAll( + Arrays.asList( + checkTarget() ? "Is connected to Pipeline Output" : "Pipeline Output is not connected/chunkloaded", + "Pipeline Output should be around: X: " + mTargetPos.posX + + " Y: " + + mTargetPos.posY + + " Z: " + + mTargetPos.posZ)); + } + + return aList; + } + + // What meta should the pipes for this pipeline have + public abstract int getPipeMeta(); + + protected void scanPipes() { + if (mSender != null && !mSender.isDead() && mSender.mTarget == this) return; + + // Check if we need to scan anything + final IGregTechTileEntity gtTile = getBaseMetaTileEntity(); + if (gtTile == null) return; + + final World world = gtTile.getWorld(); + if (world == null) return; + + mTargetPos = getCoords(); + mTarget = this; + mSender = null; + + // Start scanning from the output side + Block aBlock = gtTile.getBlockAtSide(gtTile.getBackFacing()); + + if (aBlock instanceof GT_Block_LongDistancePipe) { + byte aMetaData = gtTile.getMetaIDAtSide(gtTile.getBackFacing()); + if (aMetaData != getPipeMeta()) return; + + HashSet<ChunkCoordinates> tVisited = new HashSet<>(Collections.singletonList(getCoords())), + tWires = new HashSet<>(); + Queue<ChunkCoordinates> tQueue = new LinkedList<>( + Collections.singletonList(getFacingOffset(gtTile, gtTile.getBackFacing()))); + + while (!tQueue.isEmpty()) { + final ChunkCoordinates aCoords = tQueue.poll(); + + if (world.getBlock(aCoords.posX, aCoords.posY, aCoords.posZ) == aBlock + && world.getBlockMetadata(aCoords.posX, aCoords.posY, aCoords.posZ) == aMetaData) { + // We've got another pipe/wire block + // TODO: Make sure it's the right type of pipe/wire via meta + ChunkCoordinates tCoords; + tWires.add(aCoords); + + // For each direction, if we haven't already visited that coordinate, add it to the end of the + // queue + if (tVisited.add(tCoords = new ChunkCoordinates(aCoords.posX + 1, aCoords.posY, aCoords.posZ))) + tQueue.add(tCoords); + if (tVisited.add(tCoords = new ChunkCoordinates(aCoords.posX - 1, aCoords.posY, aCoords.posZ))) + tQueue.add(tCoords); + if (tVisited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY + 1, aCoords.posZ))) + tQueue.add(tCoords); + if (tVisited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY - 1, aCoords.posZ))) + tQueue.add(tCoords); + if (tVisited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY, aCoords.posZ + 1))) + tQueue.add(tCoords); + if (tVisited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY, aCoords.posZ - 1))) + tQueue.add(tCoords); + } else { + // It's not a block - let's see if it's a tile entity + TileEntity tTileEntity = world.getTileEntity(aCoords.posX, aCoords.posY, aCoords.posZ); + if (tTileEntity != gtTile && tTileEntity instanceof BaseMetaTileEntity + && ((BaseMetaTileEntity) tTileEntity) + .getMetaTileEntity() instanceof GT_MetaTileEntity_LongDistancePipelineBase tGtTile) { + if (isSameClass(tGtTile) && tWires.contains( + tGtTile.getFacingOffset( + (BaseMetaTileEntity) tTileEntity, + ((BaseMetaTileEntity) tTileEntity).getFrontFacing()))) { + // If it's the same class, and we've scanned a wire in front of it (the input side), we've + // found our target + // still need to check if it's distant enough + int distance = getDistanceToSelf(aCoords); + if (distance > minimalDistancePoints) { + mTarget = tGtTile; + mTargetPos = tGtTile.getCoords(); + mTooCloseTarget = null; + return; + } else { + if (mTooCloseTarget == null) { + mTooCloseTarget = tGtTile; + } + } + } + + // Remove this block from the visited because we might end up back here from another wire that + // IS connected to the + // input side + tVisited.remove(aCoords); + } + } + } + } + } + + protected int getDistanceToSelf(ChunkCoordinates aCoords) { + return Math.abs(getBaseMetaTileEntity().getXCoord() - aCoords.posX) + + Math.abs(getBaseMetaTileEntity().getYCoord() - aCoords.posY) / 2 + + Math.abs(getBaseMetaTileEntity().getZCoord() - aCoords.posZ); + } + + public ChunkCoordinates getFacingOffset(IGregTechTileEntity gt_tile, ForgeDirection side) { + return new ChunkCoordinates( + gt_tile.getOffsetX(side, 1), + gt_tile.getOffsetY(side, 1), + gt_tile.getOffsetZ(side, 1)); + } + + public ChunkCoordinates getCoords() { + final IGregTechTileEntity gt_tile = getBaseMetaTileEntity(); + return new ChunkCoordinates(gt_tile.getXCoord(), gt_tile.getYCoord(), gt_tile.getZCoord()); + } + + @Override + public void onMachineBlockUpdate() { + mTargetPos = null; + mSender = null; + } + + @Override + public boolean shouldTriggerBlockUpdate() { + return true; + } + + abstract public ITexture[] getTextureOverlays(); + + @Override + public ITexture[][][] getTextureSet(ITexture[] aTextures) { + ITexture[][][] rTextures = new ITexture[4][17][]; + ITexture[] overlays = getTextureOverlays(); + for (int i = 0; i < rTextures[0].length; i++) { + rTextures[INPUT_INDEX][i] = new ITexture[] { MACHINE_CASINGS[mTier][i], overlays[INPUT_INDEX] }; + rTextures[OUTPUT_INDEX][i] = new ITexture[] { MACHINE_CASINGS[mTier][i], overlays[OUTPUT_INDEX] }; + rTextures[SIDE_UP_DOWN_INDEX][i] = new ITexture[] { MACHINE_CASINGS[mTier][i], + overlays[SIDE_UP_DOWN_INDEX] }; + rTextures[SIDE_LEFT_RIGHT_INDEX][i] = new ITexture[] { MACHINE_CASINGS[mTier][i], + overlays[SIDE_LEFT_RIGHT_INDEX] }; + } + return rTextures; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + colorIndex += 1; + if (sideDirection == facingDirection) return mTextures[INPUT_INDEX][colorIndex]; + else if (sideDirection == facingDirection.getOpposite()) return mTextures[OUTPUT_INDEX][colorIndex]; + else { + switch (facingDirection) { + case UP, DOWN -> { + return mTextures[SIDE_UP_DOWN_INDEX][colorIndex]; + } + case NORTH -> { + switch (sideDirection) { + case DOWN, UP -> { + return mTextures[SIDE_UP_DOWN_INDEX][colorIndex]; + } + case EAST, WEST -> { + return mTextures[SIDE_LEFT_RIGHT_INDEX][colorIndex]; + } + default -> {} + } + } + case SOUTH -> { + switch (sideDirection) { + case DOWN, UP -> { + return mTextures[SIDE_UP_DOWN_INDEX][colorIndex]; + } + case EAST, WEST -> { + return mTextures[SIDE_LEFT_RIGHT_INDEX][colorIndex]; + } + default -> {} + } + } + case EAST, WEST -> { + return mTextures[SIDE_LEFT_RIGHT_INDEX][colorIndex]; + } + default -> {} + } + } + return mTextures[INPUT_INDEX][colorIndex]; // dummy + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + final ForgeDirection facing = getBaseMetaTileEntity().getFrontFacing(); + final ForgeDirection side = accessor.getSide(); + + final NBTTagCompound tag = accessor.getNBTData(); + final boolean hasInput = tag.getBoolean("hasInput"); + final boolean hasInputTooClose = tag.getBoolean("hasInputTooClose"); + final boolean hasOutput = tag.getBoolean("hasOutput"); + final boolean hasOutputTooClose = tag.getBoolean("hasOutputTooClose"); + + if (side == facing) currentTip.add(GOLD + "Pipeline Input" + RESET); + else if (side == facing.getOpposite()) currentTip.add(BLUE + "Pipeline Output" + RESET); + else currentTip.add("Pipeline Side"); + + if (!hasInput && !hasInputTooClose && !hasOutput && !hasOutputTooClose) { + currentTip.add(YELLOW + "Not connected" + RESET); + } + + if (hasInput) currentTip.add(GREEN + "Connected to " + GOLD + "Input" + RESET); + else if (hasInputTooClose) currentTip.add(RED + "Connected Input too close" + RESET); + else if (hasOutput) currentTip.add(GREEN + "Connected to " + BLUE + "Output" + RESET); + else if (hasOutputTooClose) currentTip.add(RED + "Connected Output too close" + RESET); + + super.getWailaBody(itemStack, currentTip, accessor, config); + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + super.getWailaNBTData(player, tile, tag, world, x, y, z); + + tag.setBoolean("hasInput", mSender != null); + tag.setBoolean("hasInputTooClose", mTooCloseSender != null); + tag.setBoolean("hasOutput", mTarget != null && mTarget != this); + tag.setBoolean("hasOutputTooClose", mTooCloseTarget != null); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/long_distance/GT_MetaTileEntity_LongDistancePipelineFluid.java b/src/main/java/gregtech/common/tileentities/machines/long_distance/GT_MetaTileEntity_LongDistancePipelineFluid.java new file mode 100644 index 0000000000..70e295f3ad --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/long_distance/GT_MetaTileEntity_LongDistancePipelineFluid.java @@ -0,0 +1,125 @@ +/** + * + * Inspired/ported from GregTech 6 under the LGPL license + * + * Copyright (c) 2020 GregTech-6 Team + * + * This file is part of GregTech. + * + * GregTech is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * GregTech is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License along with GregTech. If not, see + * <http://www.gnu.org/licenses/>. + */ +package gregtech.common.tileentities.machines.long_distance; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_FLUID_BACK; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_FLUID_FRONT; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_FLUID_SIDE_LEFT_RIGHT; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_FLUID_SIDE_LEFT_RIGHT_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_FLUID_SIDE_UP_DOWN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_FLUID_SIDE_UP_DOWN_GLOW; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; +import net.minecraftforge.fluids.IFluidHandler; + +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.render.TextureFactory; + +public class GT_MetaTileEntity_LongDistancePipelineFluid extends GT_MetaTileEntity_LongDistancePipelineBase { + + static final FluidTankInfo[] emptyTank = { new FluidTankInfo(null, Integer.MAX_VALUE) }; + + public GT_MetaTileEntity_LongDistancePipelineFluid(int aID, String aName, String aNameRegional, int aTier) { + super(aID, aName, aNameRegional, aTier, "Sends fluids over long distances"); + } + + public GT_MetaTileEntity_LongDistancePipelineFluid(String aName, int aTier, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + @Override + public boolean isSameClass(GT_MetaTileEntity_LongDistancePipelineBase other) { + return other instanceof GT_MetaTileEntity_LongDistancePipelineFluid; + } + + @Override + public int getPipeMeta() { + return 0; + } + + public IFluidHandler getTank() { + final IGregTechTileEntity tTile = mTarget.getBaseMetaTileEntity(); + TileEntity tankTile = tTile.getTileEntityAtSide(tTile.getBackFacing()); + if (tankTile instanceof IFluidHandler) return (IFluidHandler) tankTile; + else return null; + } + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection side) { + if (checkTarget()) { + final IFluidHandler tankTile = getTank(); + if (tankTile != null) return tankTile.getTankInfo(side); + } + + return emptyTank; + } + + @Override + public int fill(ForgeDirection side, FluidStack aFluid, boolean aDoFill) { + if (checkTarget()) { + final IGregTechTileEntity tTile = mTarget.getBaseMetaTileEntity(); + final IFluidHandler tankTile = getTank(); + if (tankTile != null) return tankTile.fill(tTile.getFrontFacing(), aFluid, aDoFill); + } + return 0; + } + + @Override + public FluidStack drain(ForgeDirection side, FluidStack aFluid, boolean aDoDrain) { + return null; + } + + @Override + public FluidStack drain(ForgeDirection side, int aMaxDrain, boolean aDoDrain) { + return null; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LongDistancePipelineFluid(mName, mTier, getDescription()[0], mTextures); + } + + @Override + public ITexture[] getTextureOverlays() { + ITexture[] overlays = new ITexture[4]; + overlays[INPUT_INDEX] = TextureFactory.of(OVERLAY_PIPELINE_FLUID_FRONT); + overlays[OUTPUT_INDEX] = TextureFactory.of(OVERLAY_PIPELINE_FLUID_BACK); + overlays[SIDE_UP_DOWN_INDEX] = TextureFactory.of( + TextureFactory.of(OVERLAY_PIPELINE_FLUID_SIDE_UP_DOWN), + TextureFactory.builder() + .addIcon(OVERLAY_PIPELINE_FLUID_SIDE_UP_DOWN_GLOW) + .glow() + .build()); + overlays[SIDE_LEFT_RIGHT_INDEX] = TextureFactory.of( + TextureFactory.of(OVERLAY_PIPELINE_FLUID_SIDE_LEFT_RIGHT), + TextureFactory.builder() + .addIcon(OVERLAY_PIPELINE_FLUID_SIDE_LEFT_RIGHT_GLOW) + .glow() + .build()); + + return overlays; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/long_distance/GT_MetaTileEntity_LongDistancePipelineItem.java b/src/main/java/gregtech/common/tileentities/machines/long_distance/GT_MetaTileEntity_LongDistancePipelineItem.java new file mode 100644 index 0000000000..e1510f4d3d --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/long_distance/GT_MetaTileEntity_LongDistancePipelineItem.java @@ -0,0 +1,214 @@ +/** + * + * Inspired/ported from GregTech 6 under the LGPL license + * + * Copyright (c) 2020 GregTech-6 Team + * + * This file is part of GregTech. + * + * GregTech is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * GregTech is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License along with GregTech. If not, see + * <http://www.gnu.org/licenses/>. + */ +package gregtech.common.tileentities.machines.long_distance; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_ITEM_BACK; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_ITEM_FRONT; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_ITEM_SIDE_LEFT_RIGHT; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_ITEM_SIDE_LEFT_RIGHT_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_ITEM_SIDE_UP_DOWN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_PIPELINE_ITEM_SIDE_UP_DOWN_GLOW; + +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +import gregtech.api.enums.GT_Values; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.render.TextureFactory; + +public class GT_MetaTileEntity_LongDistancePipelineItem extends GT_MetaTileEntity_LongDistancePipelineBase { + + public GT_MetaTileEntity_LongDistancePipelineItem(int aID, String aName, String aNameRegional, int aTier) { + super(aID, aName, aNameRegional, aTier, "Sends Items over long distances"); + } + + public GT_MetaTileEntity_LongDistancePipelineItem(String aName, int aTier, String aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + @Override + public boolean isSameClass(GT_MetaTileEntity_LongDistancePipelineBase other) { + return other instanceof GT_MetaTileEntity_LongDistancePipelineItem; + } + + @Override + public int getPipeMeta() { + return 1; + } + + public IInventory getInventory() { + final IGregTechTileEntity tTile = mTarget.getBaseMetaTileEntity(); + TileEntity invTile = tTile.getTileEntityAtSide(tTile.getBackFacing()); + if (invTile instanceof IInventory) return (IInventory) invTile; + else return null; + } + + @Override + public ItemStack decrStackSize(int aSlot, int aDecrement) { + if (checkTarget()) { + IInventory iInventory = getInventory(); + if (iInventory != null) return iInventory.decrStackSize(aSlot, aDecrement); + } + return null; + } + + @Override + public ItemStack getStackInSlotOnClosing(int aSlot) { + if (checkTarget()) { + IInventory iInventory = getInventory(); + if (iInventory != null) return iInventory.getStackInSlotOnClosing(aSlot); + } + return null; + } + + @Override + public ItemStack getStackInSlot(int aSlot) { + if (checkTarget()) { + IInventory iInventory = getInventory(); + if (iInventory != null) return iInventory.getStackInSlot(aSlot); + } + return null; + } + + @Override + public String getInventoryName() { + if (checkTarget()) { + IInventory iInventory = getInventory(); + if (iInventory != null) return iInventory.getInventoryName(); + } + return super.getInventoryName(); + } + + @Override + public int getSizeInventory() { + if (checkTarget()) { + IInventory iInventory = getInventory(); + if (iInventory != null) return iInventory.getSizeInventory(); + } + return 0; + } + + @Override + public int getInventoryStackLimit() { + if (checkTarget()) { + IInventory iInventory = getInventory(); + if (iInventory != null) return iInventory.getInventoryStackLimit(); + } + return 0; + } + + @Override + public void setInventorySlotContents(int aSlot, ItemStack aStack) { + if (checkTarget()) { + IInventory iInventory = getInventory(); + if (iInventory != null) iInventory.setInventorySlotContents(aSlot, aStack); + } + } + + @Override + public boolean hasCustomInventoryName() { + if (checkTarget()) { + IInventory iInventory = getInventory(); + if (iInventory != null) return iInventory.hasCustomInventoryName(); + } + return false; + } + + @Override + public boolean isItemValidForSlot(int aSlot, ItemStack aStack) { + if (checkTarget()) { + IInventory iInventory = getInventory(); + if (iInventory != null) return iInventory.isItemValidForSlot(aSlot, aStack); + } + return false; + } + + // // Relay Sided Inventories + // + + @Override + public int[] getAccessibleSlotsFromSide(int ordinalSide) { + if (checkTarget()) { + final IGregTechTileEntity tTile = mTarget.getBaseMetaTileEntity(); + final IInventory iInventory = getInventory(); + if (iInventory instanceof ISidedInventory inv) return inv.getAccessibleSlotsFromSide( + tTile.getFrontFacing() + .ordinal()); + if (iInventory != null) { + final int[] tReturn = new int[iInventory.getSizeInventory()]; + for (int i = 0; i < tReturn.length; i++) tReturn[i] = i; + return tReturn; + } + } + + return GT_Values.emptyIntArray; + } + + @Override + public boolean canInsertItem(int aSlot, ItemStack aStack, int ordinalSide) { + if (checkTarget()) { + final IGregTechTileEntity tTile = mTarget.getBaseMetaTileEntity(); + IInventory iInventory = getInventory(); + if (iInventory instanceof ISidedInventory iSidedInventory) return iSidedInventory.canInsertItem( + aSlot, + aStack, + tTile.getFrontFacing() + .ordinal()); + return iInventory != null; + } + return false; + } + + @Override + public boolean canExtractItem(int aSlot, ItemStack aStack, int ordinalSide) { + return false; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LongDistancePipelineItem(mName, mTier, getDescription()[0], mTextures); + } + + @Override + public ITexture[] getTextureOverlays() { + ITexture[] overlays = new ITexture[4]; + overlays[INPUT_INDEX] = TextureFactory.of(OVERLAY_PIPELINE_ITEM_FRONT); + overlays[OUTPUT_INDEX] = TextureFactory.of(OVERLAY_PIPELINE_ITEM_BACK); + overlays[SIDE_UP_DOWN_INDEX] = TextureFactory.of( + TextureFactory.of(OVERLAY_PIPELINE_ITEM_SIDE_UP_DOWN), + TextureFactory.builder() + .addIcon(OVERLAY_PIPELINE_ITEM_SIDE_UP_DOWN_GLOW) + .glow() + .build()); + overlays[SIDE_LEFT_RIGHT_INDEX] = TextureFactory.of( + TextureFactory.of(OVERLAY_PIPELINE_ITEM_SIDE_LEFT_RIGHT), + TextureFactory.builder() + .addIcon(OVERLAY_PIPELINE_ITEM_SIDE_LEFT_RIGHT_GLOW) + .glow() + .build()); + + return overlays; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_AbstractMultiFurnace.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_AbstractMultiFurnace.java new file mode 100644 index 0000000000..01638c4427 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_AbstractMultiFurnace.java @@ -0,0 +1,56 @@ +package gregtech.common.tileentities.machines.multi; + +import net.minecraft.item.ItemStack; + +import gregtech.api.enums.HeatingCoilLevel; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; + +public abstract class GT_MetaTileEntity_AbstractMultiFurnace<T extends GT_MetaTileEntity_AbstractMultiFurnace<T>> + extends GT_MetaTileEntity_EnhancedMultiBlockBase<T> { + + private HeatingCoilLevel mCoilLevel; + + protected GT_MetaTileEntity_AbstractMultiFurnace(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected GT_MetaTileEntity_AbstractMultiFurnace(String aName) { + super(aName); + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + protected boolean addBottomHatch(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + return addMaintenanceToMachineList(aTileEntity, aBaseCasingIndex) + || addInputToMachineList(aTileEntity, aBaseCasingIndex) + || addOutputToMachineList(aTileEntity, aBaseCasingIndex) + || addEnergyInputToMachineList(aTileEntity, aBaseCasingIndex); + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + public HeatingCoilLevel getCoilLevel() { + return mCoilLevel; + } + + public void setCoilLevel(HeatingCoilLevel aCoilLevel) { + mCoilLevel = aCoilLevel; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_AssemblyLine.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_AssemblyLine.java new file mode 100644 index 0000000000..7c7c27c880 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_AssemblyLine.java @@ -0,0 +1,505 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.GT_Mod.GT_FML_LOGGER; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE_GLOW; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.ofHatchAdder; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Textures; +import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.enums.VoidingMode; +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_DataAccess; +import gregtech.api.multitileentity.multiblock.casing.Glasses; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_AssemblyLineUtils; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Recipe.GT_Recipe_AssemblyLine; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.IGT_HatchAdder; + +public class GT_MetaTileEntity_AssemblyLine extends + GT_MetaTileEntity_ExtendedPowerMultiBlockBase<GT_MetaTileEntity_AssemblyLine> implements ISurvivalConstructable { + + public ArrayList<GT_MetaTileEntity_Hatch_DataAccess> mDataAccessHatches = new ArrayList<>(); + private static final String STRUCTURE_PIECE_FIRST = "first"; + private static final String STRUCTURE_PIECE_LATER = "later"; + private static final String STRUCTURE_PIECE_LAST = "last"; + private static final IStructureDefinition<GT_MetaTileEntity_AssemblyLine> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_AssemblyLine>builder() + .addShape( + STRUCTURE_PIECE_FIRST, + transpose(new String[][] { { " ", "e", " " }, { "~", "l", "G" }, { "g", "m", "g" }, { "b", "i", "b" }, })) + .addShape( + STRUCTURE_PIECE_LATER, + transpose(new String[][] { { " ", "e", " " }, { "d", "l", "d" }, { "g", "m", "g" }, { "b", "I", "b" }, })) + .addShape( + STRUCTURE_PIECE_LAST, + transpose(new String[][] { { " ", "e", " " }, { "d", "l", "d" }, { "g", "m", "g" }, { "o", "i", "b" }, })) + .addElement('G', ofBlock(GregTech_API.sBlockCasings3, 10)) // grate machine casing + .addElement('l', ofBlock(GregTech_API.sBlockCasings2, 9)) // assembler machine casing + .addElement('m', ofBlock(GregTech_API.sBlockCasings2, 5)) // assembling line casing + .addElement('g', Glasses.chainAllGlasses()) + .addElement( + 'e', + ofChain( + Energy.newAny(16, 1, ForgeDirection.UP, ForgeDirection.NORTH, ForgeDirection.SOUTH), + ofBlock(GregTech_API.sBlockCasings2, 0))) + .addElement( + 'd', + buildHatchAdder(GT_MetaTileEntity_AssemblyLine.class).atLeast(DataHatchElement.DataAccess) + .dot(2) + .casingIndex(42) + .allowOnly(ForgeDirection.NORTH) + .buildAndChain(GregTech_API.sBlockCasings3, 10)) + .addElement( + 'b', + buildHatchAdder(GT_MetaTileEntity_AssemblyLine.class) + .atLeast(InputHatch, InputHatch, InputHatch, InputHatch, Maintenance) + .casingIndex(16) + .dot(3) + .allowOnly(ForgeDirection.DOWN) + .buildAndChain( + ofBlock(GregTech_API.sBlockCasings2, 0), + ofHatchAdder(GT_MetaTileEntity_AssemblyLine::addOutputToMachineList, 16, 4))) + .addElement( + 'I', + ofChain( + // all blocks nearby use solid steel casing, so let's use the texture of that + InputBus.newAny(16, 5, ForgeDirection.DOWN), + ofHatchAdder(GT_MetaTileEntity_AssemblyLine::addOutputToMachineList, 16, 4))) + .addElement('i', InputBus.newAny(16, 5, ForgeDirection.DOWN)) + .addElement('o', OutputBus.newAny(16, 4, ForgeDirection.DOWN)) + .build(); + + public GT_MetaTileEntity_AssemblyLine(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_AssemblyLine(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_AssemblyLine(this.mName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Assembling Line") + .addInfo("Controller block for the Assembling Line") + .addInfo("Used to make complex machine parts (LuV+)") + .addInfo("Does not make Assembler items") + .addInfo("Recipe tier is at most Energy Hatch tier + 1.") + .addSeparator() + .beginVariableStructureBlock(5, 16, 4, 4, 3, 3, false) // ? + .addStructureInfo("From Bottom to Top, Left to Right") + .addStructureInfo( + "Layer 1 - Solid Steel Machine Casing, Input Bus (last can be Output Bus), Solid Steel Machine Casing") + .addStructureInfo( + "Layer 2 - Borosilicate Glass(any)/Warded Glass/Reinforced Glass, Assembling Line Casing, Reinforced Glass") + .addStructureInfo("Layer 3 - Grate Machine Casing, Assembler Machine Casing, Grate Machine Casing") + .addStructureInfo("Layer 4 - Empty, Solid Steel Machine Casing, Empty") + .addStructureInfo("Up to 16 repeating slices, each one allows for 1 more item in recipes") + .addController("Either Grate on layer 3 of the first slice") + .addEnergyHatch("Any layer 4 casing", 1) + .addMaintenanceHatch("Any layer 1 casing", 3) + .addInputBus("As specified on layer 1", 4, 5) + .addInputHatch("Any layer 1 casing", 3) + .addOutputBus("Replaces Input Bus on final slice or on any solid steel casing on layer 1", 4) + .addOtherStructurePart("Data Access Hatch", "Optional, next to controller", 2) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + if (sideDirection == facingDirection) { + if (active) return new ITexture[] { BlockIcons.casingTexturePages[0][16], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { BlockIcons.casingTexturePages[0][16], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { Textures.BlockIcons.casingTexturePages[0][16] }; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.assemblylineVisualRecipes; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + if (GT_Values.D1) { + GT_FML_LOGGER.info("Start ALine recipe check"); + } + CheckRecipeResult result = CheckRecipeResultRegistry.NO_DATA_STICKS; + + ArrayList<ItemStack> tDataStickList = getDataItems(2); + if (tDataStickList.isEmpty()) { + return result; + } + if (GT_Values.D1) { + GT_FML_LOGGER.info("Stick accepted, " + tDataStickList.size() + " Data Sticks found"); + } + + int[] tStacks = new int[0]; + FluidStack[] tFluids = new FluidStack[0]; + long averageVoltage = getAverageInputVoltage(); + long maxAmp = mEnergyHatches.size() <= 1 ? 1 : getMaxInputAmps(); + int maxParallel = 1; + Map<GT_Utility.ItemId, ItemStack> inputsFromME = getStoredInputsFromME(); + Map<Fluid, FluidStack> fluidsFromME = getStoredFluidsFromME(); + + for (ItemStack tDataStick : tDataStickList) { + GT_AssemblyLineUtils.LookupResult tLookupResult = GT_AssemblyLineUtils + .findAssemblyLineRecipeFromDataStick(tDataStick, false); + + if (tLookupResult.getType() == GT_AssemblyLineUtils.LookupResultType.INVALID_STICK) { + result = CheckRecipeResultRegistry.NO_RECIPE; + continue; + } + + GT_Recipe_AssemblyLine tRecipe = tLookupResult.getRecipe(); + // Check if the recipe on the data stick is the current recipe for it's given output, if not we update it + // and continue to next. + if (tLookupResult.getType() != GT_AssemblyLineUtils.LookupResultType.VALID_STACK_AND_VALID_HASH) { + tRecipe = GT_AssemblyLineUtils.processDataStick(tDataStick); + if (tRecipe == null) { + result = CheckRecipeResultRegistry.NO_RECIPE; + continue; + } + } + + // Void protection check. + if (!canOutputAll(new ItemStack[] { tRecipe.mOutput })) { + result = CheckRecipeResultRegistry.ITEM_OUTPUT_FULL; + continue; + } + + // So here we check against the recipe found on the data stick. + // If we run into missing buses/hatches or bad inputs, we go to the next data stick. + // This check only happens if we have a valid up-to-date data stick. + + // first validate we have enough input busses and input hatches for this recipe + if (mInputBusses.size() < tRecipe.mInputs.length || mInputHatches.size() < tRecipe.mFluidInputs.length) { + if (GT_Values.D1) { + GT_FML_LOGGER.info( + "Not enough sources: Need ({}, {}), has ({}, {})", + mInputBusses.size(), + tRecipe.mInputs.length, + mInputHatches.size(), + tRecipe.mFluidInputs.length); + } + result = CheckRecipeResultRegistry.NO_RECIPE; + continue; + } + + // Check Inputs allign + int[] itemConsumptions = GT_Recipe_AssemblyLine.getItemConsumptionAmountArray(mInputBusses, tRecipe); + if (itemConsumptions == null || itemConsumptions.length == 0) { + result = CheckRecipeResultRegistry.NO_RECIPE; + continue; + } + maxParallel = (int) GT_Recipe_AssemblyLine + .maxParallelCalculatedByInputItems(mInputBusses, maxParallel, itemConsumptions, inputsFromME); + if (maxParallel <= 0) { + result = CheckRecipeResultRegistry.NO_RECIPE; + continue; + } + tStacks = itemConsumptions; + + if (GT_Values.D1) { + GT_FML_LOGGER.info("All Items accepted"); + } + + // Check Fluid Inputs allign + if (tRecipe.mFluidInputs.length > 0) { + maxParallel = (int) GT_Recipe_AssemblyLine + .maxParallelCalculatedByInputFluids(mInputHatches, maxParallel, tRecipe.mFluidInputs, fluidsFromME); + if (maxParallel <= 0) { + result = CheckRecipeResultRegistry.NO_RECIPE; + continue; + } + tFluids = tRecipe.mFluidInputs; + } + + if (GT_Values.D1) { + GT_FML_LOGGER.info("All fluids accepted"); + } + + if (GT_Values.D1) { + GT_FML_LOGGER.info("Check overclock"); + } + + // Recipe tier is limited to hatch tier + 1. + if (tRecipe.mEUt > averageVoltage * 4) { + result = CheckRecipeResultRegistry.insufficientPower(tRecipe.mEUt); + continue; + } + + // Insufficient power check. + if (tRecipe.mEUt > maxAmp * averageVoltage) { + result = CheckRecipeResultRegistry.insufficientPower(tRecipe.mEUt); + continue; + } + + calculateOverclockedNessMultiInternal(tRecipe.mEUt, tRecipe.mDuration, (int) maxAmp, averageVoltage, false); + // In case recipe is too OP for that machine + if (lEUt == Long.MAX_VALUE) { + if (GT_Values.D1) { + GT_FML_LOGGER.info("Recipe too OP"); + } + result = CheckRecipeResultRegistry.POWER_OVERFLOW; + continue; + } + + if (mMaxProgresstime == Integer.MAX_VALUE) { + if (GT_Values.D1) { + GT_FML_LOGGER.info("Recipe too OP"); + } + result = CheckRecipeResultRegistry.DURATION_OVERFLOW; + continue; + } + + if (GT_Values.D1) { + GT_FML_LOGGER.info("Find available recipe"); + } + result = CheckRecipeResultRegistry.SUCCESSFUL; + mOutputItems = new ItemStack[] { tRecipe.mOutput }; + break; + } + + if (!result.wasSuccessful()) { + return result; + } + + // Must be something wrong here... + if (tStacks.length == 0 || maxParallel <= 0) { + return CheckRecipeResultRegistry.INTERNAL_ERROR; + } + + if (GT_Values.D1) { + GT_FML_LOGGER.info("All checked start consuming inputs"); + } + + GT_Recipe_AssemblyLine.consumeInputItems(mInputBusses, maxParallel, tStacks, inputsFromME); + GT_Recipe_AssemblyLine.consumeInputFluids(mInputHatches, maxParallel, tFluids, fluidsFromME); + + if (this.lEUt > 0) { + this.lEUt = -this.lEUt; + } + this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); + this.mEfficiencyIncrease = 10000; + updateSlots(); + if (GT_Values.D1) { + GT_FML_LOGGER.info("Recipe successful"); + } + return result; + } + + @Override + public boolean onRunningTick(ItemStack aStack) { + for (GT_MetaTileEntity_Hatch_DataAccess hatch_dataAccess : mDataAccessHatches) { + hatch_dataAccess.setActive(true); + } + return super.onRunningTick(aStack); + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_AssemblyLine> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + mDataAccessHatches.clear(); + if (!checkPiece(STRUCTURE_PIECE_FIRST, 0, 1, 0)) return false; + return checkMachine(true) || checkMachine(false); + } + + private boolean checkMachine(boolean leftToRight) { + for (int i = 1; i < 16; i++) { + if (!checkPiece(STRUCTURE_PIECE_LATER, leftToRight ? -i : i, 1, 0)) return false; + if (!mOutputBusses.isEmpty()) + return !mEnergyHatches.isEmpty() && mMaintenanceHatches.size() == 1 && mDataAccessHatches.size() <= 1; + } + return false; + } + + /** + * @param state using bitmask, 1 for IntegratedCircuit, 2 for DataStick, 4 for DataOrb + */ + private boolean isCorrectDataItem(ItemStack aStack, int state) { + if ((state & 1) != 0 && ItemList.Circuit_Integrated.isStackEqual(aStack, true, true)) return true; + if ((state & 2) != 0 && ItemList.Tool_DataStick.isStackEqual(aStack, false, true)) return true; + return (state & 4) != 0 && ItemList.Tool_DataOrb.isStackEqual(aStack, false, true); + } + + /** + * @param state using bitmask, 1 for IntegratedCircuit, 2 for DataStick, 4 for DataOrb + */ + public ArrayList<ItemStack> getDataItems(int state) { + ArrayList<ItemStack> rList = new ArrayList<>(); + if (GT_Utility.isStackValid(mInventory[1]) && isCorrectDataItem(mInventory[1], state)) { + rList.add(mInventory[1]); + } + for (GT_MetaTileEntity_Hatch_DataAccess tHatch : filterValidMTEs(mDataAccessHatches)) { + for (int i = 0; i < tHatch.getBaseMetaTileEntity() + .getSizeInventory(); i++) { + if (tHatch.getBaseMetaTileEntity() + .getStackInSlot(i) != null && isCorrectDataItem( + tHatch.getBaseMetaTileEntity() + .getStackInSlot(i), + state)) + rList.add( + tHatch.getBaseMetaTileEntity() + .getStackInSlot(i)); + } + } + return rList; + } + + public boolean addDataAccessToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_DataAccess) { + ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); + return mDataAccessHatches.add((GT_MetaTileEntity_Hatch_DataAccess) aMetaTileEntity); + } + return false; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_FIRST, stackSize, hintsOnly, 0, 1, 0); + int tLength = Math.min(stackSize.stackSize + 1, 16); + for (int i = 1; i < tLength; i++) { + buildPiece(STRUCTURE_PIECE_LATER, stackSize, hintsOnly, -i, 1, 0); + } + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + int build = survivialBuildPiece(STRUCTURE_PIECE_FIRST, stackSize, 0, 1, 0, elementBudget, env, false, true); + if (build >= 0) return build; + int tLength = Math.min(stackSize.stackSize + 1, 16); + for (int i = 1; i < tLength - 1; i++) { + build = survivialBuildPiece(STRUCTURE_PIECE_LATER, stackSize, -i, 1, 0, elementBudget, env, false, true); + if (build >= 0) return build; + } + return survivialBuildPiece(STRUCTURE_PIECE_LAST, stackSize, 1 - tLength, 1, 0, elementBudget, env, false, true); + } + + @Override + public boolean supportsVoidProtection() { + return true; + } + + @Override + public Set<VoidingMode> getAllowedVoidingModes() { + return VoidingMode.ITEM_ONLY_MODES; + } + + private enum DataHatchElement implements IHatchElement<GT_MetaTileEntity_AssemblyLine> { + + DataAccess; + + @Override + public List<? extends Class<? extends IMetaTileEntity>> mteClasses() { + return Collections.singletonList(GT_MetaTileEntity_Hatch_DataAccess.class); + } + + @Override + public IGT_HatchAdder<GT_MetaTileEntity_AssemblyLine> adder() { + return GT_MetaTileEntity_AssemblyLine::addDataAccessToMachineList; + } + + @Override + public long count(GT_MetaTileEntity_AssemblyLine t) { + return t.mDataAccessHatches.size(); + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_BrickedBlastFurnace.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_BrickedBlastFurnace.java new file mode 100644 index 0000000000..a9cb7708cf --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_BrickedBlastFurnace.java @@ -0,0 +1,155 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.util.GT_Waila.getMachineProgressString; + +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import org.lwjgl.input.Keyboard; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.SteamVariant; +import gregtech.api.enums.Textures; +import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.interfaces.ISecondaryDescribable; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaTileEntity_BrickedBlastFurnace extends GT_MetaTileEntity_PrimitiveBlastFurnace + implements ISecondaryDescribable { + + private static final ITexture[] FACING_SIDE = { TextureFactory.of(Textures.BlockIcons.MACHINE_CASING_DENSEBRICKS) }; + private static final ITexture[] FACING_FRONT = { + TextureFactory.of(Textures.BlockIcons.MACHINE_CASING_BRICKEDBLASTFURNACE_INACTIVE) }; + private static final ITexture[] FACING_ACTIVE = { + TextureFactory.of(Textures.BlockIcons.MACHINE_CASING_BRICKEDBLASTFURNACE_ACTIVE), TextureFactory.builder() + .addIcon(BlockIcons.MACHINE_CASING_BRICKEDBLASTFURNACE_ACTIVE_GLOW) + .glow() + .build() }; + private GT_Multiblock_Tooltip_Builder tooltipBuilder; + + public GT_MetaTileEntity_BrickedBlastFurnace(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_BrickedBlastFurnace(String aName) { + super(aName); + } + + @Override + public String[] getDescription() { + return getCurrentDescription(); + } + + @Override + public boolean isDisplaySecondaryDescription() { + return Keyboard.isKeyDown(Keyboard.KEY_LSHIFT); + } + + public String[] getPrimaryDescription() { + return getTooltip().getInformation(); + } + + public String[] getSecondaryDescription() { + return getTooltip().getStructureInformation(); + } + + protected GT_Multiblock_Tooltip_Builder getTooltip() { + if (tooltipBuilder == null) { + tooltipBuilder = new GT_Multiblock_Tooltip_Builder(); + tooltipBuilder.addMachineType("Blast Furnace") + .addInfo("Controller Block for the Bricked Blast Furnace") + .addInfo("Usable for Steel and general Pyrometallurgy") + .addInfo("Has a useful interface, unlike other gregtech multis") + .addPollutionAmount(GT_Mod.gregtechproxy.mPollutionPrimitveBlastFurnacePerSecond) + .addSeparator() + .beginStructureBlock(3, 4, 3, true) + .addController("Front center") + .addOtherStructurePart("Firebricks", "Everything except the controller") + .addStructureInfo("The top block is also empty") + .addStructureInfo("You can share the walls of GT multis, so") + .addStructureInfo("each additional one costs less, up to 4") + .toolTipFinisher("Gregtech"); + } + return tooltipBuilder; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + return aActive ? FACING_ACTIVE : FACING_FRONT; + } + return FACING_SIDE; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_BrickedBlastFurnace(this.mName); + } + + @Override + protected Block getCasingBlock() { + return GregTech_API.sBlockCasings4; + } + + @Override + protected int getCasingMetaID() { + return 15; + } + + @Override + public String getName() { + return "Bricked Blast Furnace"; + } + + @Override + public SteamVariant getSteamVariant() { + return SteamVariant.PRIMITIVE; + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + super.getWailaBody(itemStack, currenttip, accessor, config); + if (!this.getBaseMetaTileEntity() + .isInvalidTileEntity()) { + NBTTagCompound nbt = accessor.getNBTData(); + currenttip.add( + getMachineProgressString( + this.getBaseMetaTileEntity() + .isActive(), + nbt.getInteger("mMaxProgressTime"), + nbt.getInteger("mProgressTime"))); + } + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + super.getWailaNBTData(player, tile, tag, world, x, y, z); + if (!this.getBaseMetaTileEntity() + .isInvalidTileEntity()) { + tag.setInteger("mProgressTime", this.getProgresstime()); + tag.setInteger("mMaxProgressTime", this.maxProgresstime()); + } + } + + @Override + public String[] getStructureDescription(ItemStack stackSize) { + return getTooltip().getStructureHint(); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Charcoal_Pit.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Charcoal_Pit.java new file mode 100644 index 0000000000..1af65465c1 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Charcoal_Pit.java @@ -0,0 +1,313 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ROCK_BREAKER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; + +import java.util.ArrayList; + +import javax.annotation.Nonnull; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.ChunkPosition; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.oredict.OreDictionary; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.ParticleFX; +import gregtech.api.interfaces.ISecondaryDescribable; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TooltipMultiBlockBase; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.WorldSpawnedEventBuilder; +import gregtech.common.GT_Pollution; + +public class GT_MetaTileEntity_Charcoal_Pit extends GT_MetaTileEntity_TooltipMultiBlockBase + implements ISecondaryDescribable { + + private boolean running = false; + + public GT_MetaTileEntity_Charcoal_Pit(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_Charcoal_Pit(String aName) { + super(aName); + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return (facing.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0; + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + // No GUI, do not capture right-click so it does not interfere when placing logs + return false; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Nonnull + @Override + public CheckRecipeResult checkProcessing() { + if (!checkRecursiveBlocks()) { + mEfficiency = 0; + mEfficiencyIncrease = 0; + mMaxProgresstime = 0; + running = false; + return CheckRecipeResultRegistry.NO_RECIPE; + } + + if (mEfficiency == 0) { + mEfficiency = 10000; + mEfficiencyIncrease = 10000; + mMaxProgresstime = Math.max(1, mMaxProgresstime); + + // adds all the pollution at once when the recipe starts + GT_Pollution.addPollution(getBaseMetaTileEntity(), mMaxProgresstime * getPollutionPerTick(null)); + return CheckRecipeResultRegistry.SUCCESSFUL; + } else { + mEfficiency = 0; + mEfficiencyIncrease = 0; + mMaxProgresstime = 0; + return CheckRecipeResultRegistry.NO_RECIPE; + } + } + + private boolean checkRecursiveBlocks() { + ArrayList<ChunkPosition> tList1 = new ArrayList<>(); + ArrayList<ChunkPosition> tList2 = new ArrayList<>(); + + Block tBlock = getBaseMetaTileEntity().getBlockOffset(0, -1, 0); + if (isWoodLog(tBlock, getBaseMetaTileEntity().getMetaIDOffset(0, -1, 0))) { + tList2.add(new ChunkPosition(0, -1, 0)); + } else return false; + while (!tList2.isEmpty()) { + ChunkPosition tPos = tList2.get(0); + tList2.remove(0); + if (!checkAllBlockSides(tPos.chunkPosX, tPos.chunkPosY, tPos.chunkPosZ, tList1, tList2)) { + return false; + } + } + if (running) { + for (ChunkPosition tPos : tList1) { + if (isWoodLog( + getBaseMetaTileEntity().getBlockOffset(tPos.chunkPosX, tPos.chunkPosY, tPos.chunkPosZ), + getBaseMetaTileEntity().getMetaIDOffset(tPos.chunkPosX, tPos.chunkPosY, tPos.chunkPosZ))) + getBaseMetaTileEntity().getWorld() + .setBlock( + getBaseMetaTileEntity().getXCoord() + tPos.chunkPosX, + getBaseMetaTileEntity().getYCoord() + tPos.chunkPosY, + getBaseMetaTileEntity().getZCoord() + tPos.chunkPosZ, + GregTech_API.sBlockReinforced, + 4, + 3); + } + running = false; + return false; + } else { + mMaxProgresstime = (int) Math.sqrt(tList1.size() * 240000); + } + running = true; + return true; + } + + private boolean isWoodLog(Block log, int meta) { + for (int id : OreDictionary.getOreIDs(new ItemStack(log, 1, meta))) { + if (OreDictionary.getOreName(id) + .equals("logWood")) return true; + } + String tTool = log.getHarvestTool(meta); + return OrePrefixes.log.contains(new ItemStack(log, 1, meta)) && ("axe".equals(tTool)) + && (log.getMaterial() == Material.wood); + } + + private boolean checkAllBlockSides(int aX, int aY, int aZ, ArrayList<? super ChunkPosition> aList1, + ArrayList<? super ChunkPosition> aList2) { + boolean expandToChunkXPos = false; + boolean expandToChunkXNeg = false; + boolean expandToChunkYPos = false; + boolean expandToChunkYNeg = false; + boolean expandToChunkZPos = false; + boolean expandToChunkZNeg = false; + + Block blockXPos = getBaseMetaTileEntity().getBlockOffset(aX + 1, aY, aZ); + if (aX + 1 < 6 && (isWoodLog(blockXPos, getBaseMetaTileEntity().getMetaIDOffset(aX + 1, aY, aZ)))) { + if (!aList1.contains(new ChunkPosition(aX + 1, aY, aZ)) + && (!aList2.contains(new ChunkPosition(aX + 1, aY, aZ)))) expandToChunkXPos = true; + } else if (!(blockXPos == Blocks.dirt || blockXPos == Blocks.grass)) { + return false; + } + + Block blockXNeg = getBaseMetaTileEntity().getBlockOffset(aX - 1, aY, aZ); + if (aX - 1 > -6 && (isWoodLog(blockXNeg, getBaseMetaTileEntity().getMetaIDOffset(aX - 1, aY, aZ)))) { + if (!aList1.contains(new ChunkPosition(aX - 1, aY, aZ)) + && (!aList2.contains(new ChunkPosition(aX - 1, aY, aZ)))) expandToChunkXNeg = true; + } else if (!(blockXNeg == Blocks.dirt || blockXNeg == Blocks.grass)) { + return false; + } + + Block blockYPos = getBaseMetaTileEntity().getBlockOffset(aX, aY + 1, aZ); + if (aY + 1 < 1 && (isWoodLog(blockYPos, getBaseMetaTileEntity().getMetaIDOffset(aX, aY + 1, aZ)))) { + if (!aList1.contains(new ChunkPosition(aX, aY + 1, aZ)) + && (!aList2.contains(new ChunkPosition(aX, aY + 1, aZ)))) expandToChunkYPos = true; + } else if (!(blockYPos == Blocks.dirt || blockYPos == Blocks.grass + || (aX == 0 && aY == -1 && aZ == 0 && blockYPos == GregTech_API.sBlockMachines))) { + return false; + } + + Block blockYNeg = getBaseMetaTileEntity().getBlockOffset(aX, aY - 1, aZ); + if (aY - 1 > -6 && (isWoodLog(blockYNeg, getBaseMetaTileEntity().getMetaIDOffset(aX, aY - 1, aZ)))) { + if (!aList1.contains(new ChunkPosition(aX, aY - 1, aZ)) + && (!aList2.contains(new ChunkPosition(aX, aY - 1, aZ)))) expandToChunkYNeg = true; + } else if (blockYNeg != Blocks.brick_block) { + return false; + } + + Block blockZPos = getBaseMetaTileEntity().getBlockOffset(aX, aY, aZ + 1); + if (aZ + 1 < 6 && (isWoodLog(blockZPos, getBaseMetaTileEntity().getMetaIDOffset(aX, aY, aZ + 1)))) { + if (!aList1.contains(new ChunkPosition(aX, aY, aZ + 1)) + && (!aList2.contains(new ChunkPosition(aX, aY, aZ + 1)))) expandToChunkZPos = true; + } else if (!(blockZPos == Blocks.dirt || blockZPos == Blocks.grass)) { + return false; + } + + Block blockZNeg = getBaseMetaTileEntity().getBlockOffset(aX, aY, aZ - 1); + if (aZ - 1 > -6 && (isWoodLog(blockZNeg, getBaseMetaTileEntity().getMetaIDOffset(aX, aY, aZ - 1)))) { + if (!aList1.contains(new ChunkPosition(aX, aY, aZ - 1)) + && (!aList2.contains(new ChunkPosition(aX, aY, aZ - 1)))) expandToChunkZNeg = true; + } else if (!(blockZNeg == Blocks.dirt || blockZNeg == Blocks.grass)) { + return false; + } + aList1.add(new ChunkPosition(aX, aY, aZ)); + if (expandToChunkXPos) aList2.add(new ChunkPosition(aX + 1, aY, aZ)); + if (expandToChunkXNeg) aList2.add(new ChunkPosition(aX - 1, aY, aZ)); + if (expandToChunkYPos) aList2.add(new ChunkPosition(aX, aY + 1, aZ)); + if (expandToChunkYNeg) aList2.add(new ChunkPosition(aX, aY - 1, aZ)); + if (expandToChunkZPos) aList2.add(new ChunkPosition(aX, aY, aZ + 1)); + if (expandToChunkZNeg) aList2.add(new ChunkPosition(aX, aY, aZ - 1)); + return true; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + mWrench = true; + mScrewdriver = true; + mSoftHammer = true; + mHardHammer = true; + mSolderingTool = true; + mCrowbar = true; + return true; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + return GT_Mod.gregtechproxy.mPollutionCharcoalPitPerSecond; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return null; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Charcoal_Pit(mName); + } + + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Charcoal Pile Igniter") + .addInfo("Controller for the Charcoal Pit") + .addInfo("Converts Logs into Brittle Charcoal blocks") + .addInfo("Will automatically start when valid") + .addPollutionAmount(getPollutionPerSecond(null)) + .addSeparator() + .beginVariableStructureBlock(3, 13, 3, 7, 3, 13, false) + .addStructureInfo("Can be up to 13x7x13 in size, including the dirt; shape doesn't matter") + .addOtherStructurePart("Controller", "Top layer, directly touching a wood log") + .addOtherStructurePart("Dirt/Grass", "Top and middle layers, covering wood logs") + .addOtherStructurePart("Bricks", "Bottom layer, under all wood logs") + .addOtherStructurePart("Wood Logs", "Up to 5 layers, inside the previously mentioned blocks") + .addStructureInfo("No air between logs allowed.") + .addStructureInfo( + "All logs must be within 6 x/z of the controller, so it must be dead-center for a full 11x11 square of wood.") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == ForgeDirection.UP) { + if (aActive) return new ITexture[] { casingTexturePages[0][10], + TextureFactory.of(OVERLAY_FRONT_ROCK_BREAKER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ROCK_BREAKER_ACTIVE_GLOW) + .glow() + .build() }; + return new ITexture[] { casingTexturePages[0][10], TextureFactory.of(OVERLAY_FRONT_ROCK_BREAKER), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ROCK_BREAKER_GLOW) + .glow() + .build(), }; + } + return new ITexture[] { casingTexturePages[0][10] }; + } + + @Override + public boolean polluteEnvironment(int aPollutionLevel) { + // Do nothing and don't choke on pollution. This is fine because we add + // all the pollution at once when the recipe starts + return true; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + super.onPostTick(aBaseMetaTileEntity, aTimer); + if ((aBaseMetaTileEntity.isClientSide()) && (aBaseMetaTileEntity.isActive())) { + + new WorldSpawnedEventBuilder.ParticleEventBuilder().setMotion(0D, 0.3D, 0D) + .setIdentifier(ParticleFX.LARGE_SMOKE) + .setPosition( + aBaseMetaTileEntity.getOffsetX(ForgeDirection.UP, 1) + XSTR_INSTANCE.nextFloat(), + aBaseMetaTileEntity.getOffsetY(ForgeDirection.UP, 1), + aBaseMetaTileEntity.getOffsetZ(ForgeDirection.UP, 1) + XSTR_INSTANCE.nextFloat()) + .setWorld(getBaseMetaTileEntity().getWorld()) + .run(); + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Cleanroom.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Cleanroom.java new file mode 100644 index 0000000000..cd31b9cc1e --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_Cleanroom.java @@ -0,0 +1,514 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.GT_Values.debugCleanroom; +import static gregtech.api.enums.Textures.BlockIcons.BLOCK_PLASCRETE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_CLEANROOM; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_CLEANROOM_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_CLEANROOM_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_CLEANROOM_GLOW; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Nonnull; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.config.ConfigCategory; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizon.structurelib.StructureLibAPI; +import com.gtnewhorizon.structurelib.alignment.constructable.IConstructable; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.TierEU; +import gregtech.api.interfaces.ICleanroom; +import gregtech.api.interfaces.ICleanroomReceiver; +import gregtech.api.interfaces.ISecondaryDescribable; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicHull; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TooltipMultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_Cleanroom extends GT_MetaTileEntity_TooltipMultiBlockBase + implements IConstructable, ISecondaryDescribable, ICleanroom { + + private final Set<ICleanroomReceiver> cleanroomReceivers = new HashSet<>(); + private int mHeight = -1; + + public GT_MetaTileEntity_Cleanroom(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_Cleanroom(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Cleanroom(mName); + } + + @Override + public int getCleanness() { + return mEfficiency; + } + + @Override + public boolean isValidCleanroom() { + return isValid() && mMachine; + } + + @Override + public void pollute() { + mEfficiency = 0; + mWrench = false; + mScrewdriver = false; + mSoftHammer = false; + mHardHammer = false; + mSolderingTool = false; + mCrowbar = false; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Cleanroom") + .addInfo("Controller block for the Cleanroom") + .addInfo("Consumes 40 EU/t when first turned on") + .addInfo("and 4 EU/t once at 100% efficiency") + .addInfo("If you use an LV energy hatch, it will actually accept 2A instead of just 1A.") + .addInfo( + "MV+ energy hatches just accept 1A as usual. For HV+ the cleanroom will overclock and gain efficiency faster.") + .addInfo("Time required to reach full efficiency is proportional to") + .addInfo("the height of empty space within") + .addInfo("Machines that cause pollution aren't allowed to be put in.") + .addSeparator() + .beginVariableStructureBlock(3, 15, 4, 15, 3, 15, true) + .addController("Top center") + .addCasingInfoRange("Plascrete", 20, 1007, false) + .addStructureInfo( + GT_Values.cleanroomGlass + + "% of the Plascrete can be replaced with Reinforced Glass (not counting the top layer)") + .addStructureInfo( + "Other material can be used in place of Plascrete, even in higher percentages. See config for detail") + .addOtherStructurePart("Filter Machine Casing", "Top besides controller and edges") + .addEnergyHatch("Any casing except top layer. Exactly one.") + .addMaintenanceHatch("Any casing except top layer") + .addStructureInfo("0-2x Reinforced Door (keep closed or efficiency will reduce)") + .addStructureInfo("Up to 1 Elevator, Rotating Elevator, and Travel Anchor each") + .addStructureInfo("Up to 10 Machine Hulls for Item & Energy transfer through walls") + .addStructureInfo("You can also use Diodes for more power") + .addStructureInfo("Diodes also count towards 10 Machine Hulls count limit") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public String[] getStructureDescription(ItemStack itemStack) { + return new String[] { "The base can be rectangular." }; + } + + @Nonnull + @Override + public CheckRecipeResult checkProcessing() { + mEfficiencyIncrease = 100; + final long inputVoltage = getMaxInputVoltage(); + + // only allow LV+ energy hatches + if (inputVoltage < TierEU.LV) { + return CheckRecipeResultRegistry.insufficientPower(40); + } + + // use the standard overclock mechanism to determine duration and estimate a maximum consumption + // if the cleanroom is powered by an LV energy hatch, it will actually accept 2A instead of just 1A. + calculateOverclockedNessMultiInternal( + 40, + 45 * Math.max(1, mHeight - 1), + inputVoltage == TierEU.LV ? 2 : 1, + inputVoltage, + false); + // negate it to trigger the special energy consumption function. divide by 10 to get the actual final + // consumption. + mEUt /= -10; + return SimpleCheckRecipeResult.ofSuccess("cleanroom_running"); + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return (facing.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + int x = 1; + int z = 1; + int y = 1; + int mDoorCount = 0; + int mHullCount = 0; + int mPlascreteCount = 0; + final HashMap<String, Integer> otherBlocks = new HashMap<>(); + boolean doorState = false; + this.mUpdate = 100; + cleanroomReceivers.forEach(r -> r.setCleanroom(null)); + cleanroomReceivers.clear(); + + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: Checking machine"); + } + for (int i = 1; i < 8; i++) { + final Block tBlock = aBaseMetaTileEntity.getBlockOffset(i, 0, 0); + final int tMeta = aBaseMetaTileEntity.getMetaIDOffset(i, 0, 0); + if (tBlock != GregTech_API.sBlockCasings3 || tMeta != 11) { + if (tBlock == GregTech_API.sBlockReinforced || tMeta == 2) { + x = i; + break; + } else { + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: Unable to detect room X edge?"); + } + return false; + } + } + } + for (int i = 1; i < 8; i++) { + final Block tBlock = aBaseMetaTileEntity.getBlockOffset(0, 0, i); + final int tMeta = aBaseMetaTileEntity.getMetaIDOffset(0, 0, i); + if (tBlock != GregTech_API.sBlockCasings3 || tMeta != 11) { + if (tBlock == GregTech_API.sBlockReinforced || tMeta == 2) { + z = i; + break; + } else { + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: Unable to detect room Z edge?"); + } + return false; + } + } + } + // detect rectangular area of filters + for (int i = -x + 1; i < x; i++) { + for (int j = -z + 1; j < z; j++) { + if (i == 0 && j == 0) continue; + final Block tBlock = aBaseMetaTileEntity.getBlockOffset(i, 0, j); + final int tMeta = aBaseMetaTileEntity.getMetaIDOffset(i, 0, j); + if (tBlock != GregTech_API.sBlockCasings3 && tMeta != 11) { + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: This is not a filter."); + } + return false; + } + } + } + + for (int i = -1; i > -16; i--) { + final Block tBlock = aBaseMetaTileEntity.getBlockOffset(x, i, z); + final int tMeta = aBaseMetaTileEntity.getMetaIDOffset(x, i, z); + if (tBlock != GregTech_API.sBlockReinforced || tMeta != 2) { + y = i + 1; + break; + } + } + if (y > -2) { + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: Room not tall enough?"); + } + return false; + } + for (int dX = -x; dX <= x; dX++) { + for (int dZ = -z; dZ <= z; dZ++) { + for (int dY = 0; dY >= y; dY--) { + if (dX == -x || dX == x || dY == 0 || dY == y || dZ == -z || dZ == z) { + Block tBlock = aBaseMetaTileEntity.getBlockOffset(dX, dY, dZ); + int tMeta = aBaseMetaTileEntity.getMetaIDOffset(dX, dY, dZ); + if (dY == 0) { // TOP + if (dX == -x || dX == x || dZ == -z || dZ == z) { // Top Border + if (tBlock != GregTech_API.sBlockReinforced || tMeta != 2) { + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: Non reinforced block on top edge? tMeta != 2"); + } + return false; + } + } else if (dX != 0 || dZ != 0) { // Top Inner exclude center + if (tBlock != GregTech_API.sBlockCasings3 || tMeta != 11) { + if (debugCleanroom) { + GT_Log.out.println( + "Cleanroom: Non reinforced block on top face interior? tMeta != 11"); + } + return false; + } + } + } else if (tBlock == GregTech_API.sBlockReinforced && tMeta == 2) { + mPlascreteCount++; + } else { + final IGregTechTileEntity tTileEntity = aBaseMetaTileEntity + .getIGregTechTileEntityOffset(dX, dY, dZ); + if ((!this.addMaintenanceToMachineList(tTileEntity, 210)) + && (!this.addEnergyInputToMachineList(tTileEntity, 210))) { + if (tBlock instanceof ic2.core.block.BlockIC2Door) { + if ((tMeta & 8) == 0) { + // let's not fiddle with bits anymore. + if (Math.abs(dZ) < z) // on side parallel to z axis + doorState = tMeta == 1 || tMeta == 3 || tMeta == 4 || tMeta == 6; + else if (Math.abs(dX) < x) // on side parallel to x axis + doorState = tMeta == 0 || tMeta == 2 || tMeta == 5 || tMeta == 7; + // corners ignored + } + mDoorCount++; + } else { + if (tTileEntity != null) { + final IMetaTileEntity aMetaTileEntity = tTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) { + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: Missing block? Not a aMetaTileEntity"); + } + return false; + } + if (aMetaTileEntity instanceof GT_MetaTileEntity_BasicHull) { + mHullCount++; + } else { + if (debugCleanroom) { + GT_Log.out.println( + "Cleanroom: Incorrect GT block? " + tBlock.getUnlocalizedName()); + } + return false; + } + } else { + String key = tBlock.getUnlocalizedName() + ":" + tMeta; + if (config.containsKey(key)) { // check with meta first + otherBlocks.compute(key, (k, v) -> v == null ? 1 : v + 1); + } else { + key = tBlock.getUnlocalizedName(); + if (config.containsKey(key)) { + otherBlocks.compute(key, (k, v) -> v == null ? 1 : v + 1); + } else { + if (debugCleanroom) { + GT_Log.out.println( + "Cleanroom: not allowed block " + tBlock.getUnlocalizedName()); + } + return false; + } + } + } + } + } + } + } + } + } + } + if (this.mMaintenanceHatches.size() != 1 || this.mEnergyHatches.size() != 1 + || mDoorCount > 4 + || mHullCount > 10) { + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: Incorrect number of doors, hulls, or hatches."); + } + return false; + } + if (mPlascreteCount < 20) { + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: Could not find 20 Plascrete."); + } + return false; + } + final float ratio = (((float) mPlascreteCount) / 100f); + for (Map.Entry<String, Integer> e : otherBlocks.entrySet()) { + final ConfigEntry ce = config.get(e.getKey()); + if (ce.allowedCount > 0) { // count has priority + if (e.getValue() > ce.allowedCount) { + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: Absolute count too high for a block."); + } + return false; + } + } else if (e.getValue() > ratio * ce.percentage) { + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: Relative count too high for a block."); + } + return false; + } + } + + setCleanroomReceivers(x, y, z, aBaseMetaTileEntity); + + if (doorState) { + this.mEfficiency = Math.max(0, this.mEfficiency - 200); + } + for (final ForgeDirection tSide : ForgeDirection.VALID_DIRECTIONS) { + final byte t = (byte) Math.max(1, (byte) (15 / (10000f / this.mEfficiency))); + aBaseMetaTileEntity.setInternalOutputRedstoneSignal(tSide, t); + } + this.mHeight = -y; + if (debugCleanroom) { + GT_Log.out.println("Cleanroom: Check successful."); + } + return true; + } + + private void setCleanroomReceivers(int x, int y, int z, IGregTechTileEntity aBaseMetaTileEntity) { + for (int dX = -x + 1; dX <= x - 1; dX++) { + for (int dZ = -z + 1; dZ <= z - 1; dZ++) for (int dY = -1; dY >= y + 1; dY--) { + TileEntity tTileEntity = aBaseMetaTileEntity.getTileEntityOffset(dX, dY, dZ); + if (tTileEntity instanceof ICleanroomReceiver receiver) { + receiver.setCleanroom(this); + cleanroomReceivers.add(receiver); + } + } + } + } + + @Override + public boolean allowGeneralRedstoneOutput() { + return true; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + if ((sideDirection.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) != 0) { + return new ITexture[] { TextureFactory.of(BLOCK_PLASCRETE), active + ? TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_CLEANROOM_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_CLEANROOM_ACTIVE_GLOW) + .glow() + .build()) + : TextureFactory.of( + TextureFactory.of(OVERLAY_TOP_CLEANROOM), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_CLEANROOM_GLOW) + .glow() + .build()) }; + } + return new ITexture[] { TextureFactory.of(BLOCK_PLASCRETE) }; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public void construct(ItemStack itemStack, boolean b) { + int i = Math.min(itemStack.stackSize, 7); + IGregTechTileEntity baseEntity = this.getBaseMetaTileEntity(); + World world = baseEntity.getWorld(); + int x = baseEntity.getXCoord(); + int y = baseEntity.getYCoord(); + int z = baseEntity.getZCoord(); + int yoff = Math.max(i * 2, 3); + for (int X = x - i; X <= x + i; X++) for (int Y = y; Y >= y - yoff; Y--) for (int Z = z - i; Z <= z + i; Z++) { + if (X == x && Y == y && Z == z) continue; + if (X == x - i || X == x + i || Z == z - i || Z == z + i || Y == y - yoff) { + if (b) StructureLibAPI.hintParticle(world, X, Y, Z, GregTech_API.sBlockReinforced, 2); + else world.setBlock(X, Y, Z, GregTech_API.sBlockReinforced, 2, 2); + } else if (Y == y) { + if (b) StructureLibAPI.hintParticle(world, X, Y, Z, GregTech_API.sBlockCasings3, 11); + else world.setBlock(X, Y, Z, GregTech_API.sBlockCasings3, 11, 2); + } + } + } + + private static class ConfigEntry { + + final int percentage; + final int allowedCount; + + ConfigEntry(int percentage, int count) { + this.percentage = percentage; + this.allowedCount = count; + } + } + + private static final HashMap<String, ConfigEntry> config = new HashMap<>(); + private static final String category = "cleanroom_allowed_blocks"; + + private static void setDefaultConfigValues(Configuration cfg) { + cfg.get("cleanroom_allowed_blocks.manaGlass", "Name", "tile.manaGlass"); + cfg.get("cleanroom_allowed_blocks.manaGlass", "Percentage", 50); + cfg.get("cleanroom_allowed_blocks.elfGlass", "Name", "tile.elfGlass"); + cfg.get("cleanroom_allowed_blocks.elfGlass", "Percentage", 50); + cfg.get("cleanroom_allowed_blocks.reinforced_glass", "Name", "blockAlloyGlass"); + cfg.get("cleanroom_allowed_blocks.reinforced_glass", "Percentage", 5); + cfg.get("cleanroom_allowed_blocks.bw_reinforced_glass_0", "Name", "BW_GlasBlocks"); + cfg.get("cleanroom_allowed_blocks.bw_reinforced_glass_0", "Percentage", 50); + cfg.get("cleanroom_allowed_blocks.bw_reinforced_glass_0", "Meta", 0); + cfg.get("cleanroom_allowed_blocks.bw_reinforced_glass", "Name", "BW_GlasBlocks"); + cfg.get("cleanroom_allowed_blocks.bw_reinforced_glass", "Percentage", 100); + cfg.get("cleanroom_allowed_blocks.elevator", "Name", "tile.openblocks.elevator"); + cfg.get("cleanroom_allowed_blocks.elevator", "Count", 1); + cfg.get("cleanroom_allowed_blocks.travel_anchor", "Name", "tile.blockTravelAnchor"); + cfg.get("cleanroom_allowed_blocks.travel_anchor", "Count", 1); + cfg.get("cleanroom_allowed_blocks.warded_glass", "Name", "tile.blockCosmeticOpaque"); + cfg.get("cleanroom_allowed_blocks.warded_glass", "Meta", 2); + cfg.get("cleanroom_allowed_blocks.warded_glass", "Percentage", 50); + } + + public static void loadConfig(Configuration cfg) { + if (!cfg.hasCategory(category)) setDefaultConfigValues(cfg); + for (ConfigCategory cc : cfg.getCategory(category) + .getChildren()) { + final String name = cc.get("Name") + .getString(); + if (cc.containsKey("Count")) { + if (cc.containsKey("Meta")) config.put( + name + ":" + + cc.get("Meta") + .getInt(), + new ConfigEntry( + 0, + cc.get("Count") + .getInt())); + else config.put( + name, + new ConfigEntry( + 0, + cc.get("Count") + .getInt())); + } else if (cc.containsKey("Percentage")) { + if (cc.containsKey("Meta")) config.put( + name + ":" + + cc.get("Meta") + .getInt(), + new ConfigEntry( + cc.get("Percentage") + .getInt(), + 0)); + else config.put( + name, + new ConfigEntry( + cc.get("Percentage") + .getInt(), + 0)); + } + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ConcreteBackfiller1.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ConcreteBackfiller1.java new file mode 100644 index 0000000000..e61cfc0feb --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ConcreteBackfiller1.java @@ -0,0 +1,53 @@ +package gregtech.common.tileentities.machines.multi; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_ConcreteBackfiller1 extends GT_MetaTileEntity_ConcreteBackfillerBase { + + public GT_MetaTileEntity_ConcreteBackfiller1(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_ConcreteBackfiller1(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + return createTooltip("Concrete Backfiller"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_ConcreteBackfiller1(mName); + } + + @Override + protected ItemList getCasingBlockItem() { + return ItemList.Casing_SolidSteel; + } + + @Override + protected Materials getFrameMaterial() { + return Materials.Steel; + } + + @Override + protected int getCasingTextureIndex() { + return 16; + } + + @Override + protected int getRadius() { + return 16; + } + + @Override + protected int getMinTier() { + return 2; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ConcreteBackfiller2.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ConcreteBackfiller2.java new file mode 100644 index 0000000000..c175d73cb1 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ConcreteBackfiller2.java @@ -0,0 +1,54 @@ +package gregtech.common.tileentities.machines.multi; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_ConcreteBackfiller2 extends GT_MetaTileEntity_ConcreteBackfillerBase { + + public GT_MetaTileEntity_ConcreteBackfiller2(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_ConcreteBackfiller2(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + return createTooltip("Advanced Concrete Backfiller"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_ConcreteBackfiller2(mName); + } + + @Override + protected ItemList getCasingBlockItem() { + return ItemList.Casing_StableTitanium; + } + + @Override + protected Materials getFrameMaterial() { + return Materials.Titanium; + } + + @Override + protected int getCasingTextureIndex() { + return 50; + } + + @Override + protected int getRadius() { + int tConfig = getTotalConfigValue() * 2; + return tConfig >= 128 ? 128 : tConfig <= 0 ? 64 : tConfig; + } + + @Override + protected int getMinTier() { + return 4; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ConcreteBackfillerBase.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ConcreteBackfillerBase.java new file mode 100644 index 0000000000..e520b87e43 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ConcreteBackfillerBase.java @@ -0,0 +1,180 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_Values.VN; + +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.modularui.api.NumberFormatMUI; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; + +public abstract class GT_MetaTileEntity_ConcreteBackfillerBase extends GT_MetaTileEntity_DrillerBase { + + private int mLastXOff = 0, mLastZOff = 0; + + /** Used to drive the readout in the GUI for the backfiller's current y-level. */ + private int clientYHead; + + public GT_MetaTileEntity_ConcreteBackfillerBase(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + initRecipeResults(); + } + + public GT_MetaTileEntity_ConcreteBackfillerBase(String aName) { + super(aName); + initRecipeResults(); + } + + private void initRecipeResults() { + addResultMessage(STATE_UPWARD, true, "backfiller_working"); + } + + protected GT_Multiblock_Tooltip_Builder createTooltip(String aStructureName) { + String casings = getCasingBlockItem().get(0) + .getDisplayName(); + + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Concrete Backfiller") + .addInfo("Controller Block for the " + aStructureName) + .addInfo("Will fill in areas below it with light concrete. This goes through walls") + .addInfo("Use it to remove any spawning locations beneath your base to reduce lag") + .addInfo("Will pull back the pipes after it finishes that layer") + .addInfo("Radius is " + getRadius() + " blocks") + .addSeparator() + .beginStructureBlock(3, 7, 3, false) + .addController("Front bottom") + .addOtherStructurePart(casings, "form the 3x1x3 Base") + .addOtherStructurePart(casings, "1x3x1 pillar above the center of the base (2 minimum total)") + .addOtherStructurePart(getFrameMaterial().mName + " Frame Boxes", "Each pillar's side and 1x3x1 on top") + .addEnergyHatch("1x " + VN[getMinTier()] + "+, Any base casing", 1) + .addMaintenanceHatch("Any base casing", 1) + .addInputBus("Mining Pipes, optional, any base casing", 1) + .addInputHatch("GT Concrete, any base casing", 1) + .addOutputBus("Mining Pipes, optional, any base casing", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + protected abstract int getRadius(); + + @Override + protected boolean checkHatches() { + return !mMaintenanceHatches.isEmpty() && !mInputHatches.isEmpty() && mEnergyHatches.size() == 1; + } + + @Override + protected List<IHatchElement<? super GT_MetaTileEntity_DrillerBase>> getAllowedHatches() { + return ImmutableList.of(InputHatch, InputBus, Maintenance, Energy); + } + + @Override + protected void setElectricityStats() { + this.mEfficiency = getCurrentEfficiency(null); + this.mEfficiencyIncrease = 10000; + int tier = Math.max(1, GT_Utility.getTier(getMaxInputVoltage())); + this.mEUt = -6 * (1 << (tier << 1)); + this.mMaxProgresstime = (workState == STATE_UPWARD ? 240 : 80) / (1 << tier); + this.mMaxProgresstime = Math.max(1, this.mMaxProgresstime); + } + + @Override + protected boolean workingUpward(ItemStack aStack, int xDrill, int yDrill, int zDrill, int xPipe, int zPipe, + int yHead, int oldYHead) { + if (isRefillableBlock(xPipe, yHead - 1, zPipe)) return tryRefillBlock(xPipe, yHead - 1, zPipe); + int radius = getRadius(); + if (mLastXOff == 0 && mLastZOff == 0) { + mLastXOff = -radius; + mLastZOff = -radius; + } + if (yHead != yDrill) { + for (int i = mLastXOff; i <= radius; i++) { + for (int j = (i == mLastXOff ? mLastZOff : -radius); j <= radius; j++) { + if (isRefillableBlock(xPipe + i, yHead, zPipe + j)) { + mLastXOff = i; + mLastZOff = j; + return tryRefillBlock(xPipe + i, yHead, zPipe + j); + } + } + } + } + + if (tryPickPipe()) { + mLastXOff = 0; + mLastZOff = 0; + return true; + } else { + workState = STATE_DOWNWARD; + stopMachine(ShutDownReasonRegistry.NONE); + setShutdownReason(StatCollector.translateToLocal("GT5U.gui.text.backfiller_finished")); + return false; + } + } + + private boolean isRefillableBlock(int aX, int aY, int aZ) { + IGregTechTileEntity aBaseTile = getBaseMetaTileEntity(); + if (!aBaseTile.getBlock(aX, aY, aZ) + .isAir(aBaseTile.getWorld(), aX, aY, aZ) || aBaseTile.getBlock(aX, aY, aZ) + .getMaterial() + .isSolid()) + return false; + return GT_Utility + .setBlockByFakePlayer(getFakePlayer(aBaseTile), aX, aY, aZ, GregTech_API.sBlockConcretes, 8, true); + } + + private boolean tryRefillBlock(int aX, int aY, int aZ) { + if (!tryConsumeFluid()) { + setRuntimeFailureReason(CheckRecipeResultRegistry.BACKFILLER_NO_CONCRETE); + return false; + } + getBaseMetaTileEntity().getWorld() + .setBlock(aX, aY, aZ, GregTech_API.sBlockConcretes, 8, 3); + return true; + } + + private boolean tryConsumeFluid() { + if (!depleteInput(Materials.Concrete.getMolten(144L))) { + mMaxProgresstime = 0; + return false; + } + return true; + } + + protected static final NumberFormatMUI numberFormat = new NumberFormatMUI(); + + @Override + protected void drawTexts(DynamicPositionedColumn screenElements, SlotWidget inventorySlot) { + super.drawTexts(screenElements, inventorySlot); + screenElements + .widget( + TextWidget + .dynamicString( + () -> StatCollector.translateToLocalFormatted( + "GT5U.gui.text.backfiller_current_area", + numberFormat.format(clientYHead))) + .setSynced(false) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled(widget -> getBaseMetaTileEntity().isActive() && workState == STATE_UPWARD)) + .widget(new FakeSyncWidget.IntegerSyncer(this::getYHead, newInt -> clientYHead = newInt)) + .widget(new FakeSyncWidget.IntegerSyncer(() -> workState, newInt -> workState = newInt)); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DieselEngine.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DieselEngine.java new file mode 100644 index 0000000000..6c77dc7f0d --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DieselEngine.java @@ -0,0 +1,416 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Dynamo; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.Muffler; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DIESEL_ENGINE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DIESEL_ENGINE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DIESEL_ENGINE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DIESEL_ENGINE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; +import gregtech.api.recipe.maps.FuelBackend; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_DieselEngine + extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_DieselEngine> implements ISurvivalConstructable { + + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final ClassValue<IStructureDefinition<GT_MetaTileEntity_DieselEngine>> STRUCTURE_DEFINITION = new ClassValue<>() { + + @Override + protected IStructureDefinition<GT_MetaTileEntity_DieselEngine> computeValue(Class<?> type) { + return StructureDefinition.<GT_MetaTileEntity_DieselEngine>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose( + new String[][] { { "---", "iii", "chc", "chc", "ccc", }, { "---", "i~i", "hgh", "hgh", "cdc", }, + { "---", "iii", "chc", "chc", "ccc", }, })) + .addElement('i', lazy(t -> ofBlock(t.getIntakeBlock(), t.getIntakeMeta()))) + .addElement('c', lazy(t -> ofBlock(t.getCasingBlock(), t.getCasingMeta()))) + .addElement('g', lazy(t -> ofBlock(t.getGearboxBlock(), t.getGearboxMeta()))) + .addElement('d', lazy(t -> Dynamo.newAny(t.getCasingTextureIndex(), 2))) + .addElement( + 'h', + lazy( + t -> buildHatchAdder(GT_MetaTileEntity_DieselEngine.class) + .atLeast(InputHatch, InputHatch, InputHatch, Muffler, Maintenance) + .casingIndex(t.getCasingTextureIndex()) + .dot(1) + .buildAndChain(t.getCasingBlock(), t.getCasingMeta()))) + .build(); + } + }; + protected int fuelConsumption = 0; + protected int fuelValue = 0; + protected int fuelRemaining = 0; + protected boolean boostEu = false; + + public GT_MetaTileEntity_DieselEngine(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_DieselEngine(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Combustion Generator") + .addInfo("Controller block for the Large Combustion Engine") + .addInfo("Supply Diesel Fuels and 1000L of Lubricant per hour to run") + .addInfo("Supply 40L/s of Oxygen to boost output (optional)") + .addInfo("Default: Produces 2048EU/t at 100% fuel efficiency") + .addInfo("Boosted: Produces 6144EU/t at 150% fuel efficiency") + .addInfo("You need to wait for it to reach 300% to output full power") + .addPollutionAmount(getPollutionPerSecond(null)) + .addSeparator() + .beginStructureBlock(3, 3, 4, false) + .addController("Front center") + .addCasingInfoRange("Stable Titanium Machine Casing", 16, 22, false) + .addOtherStructurePart("Titanium Gear Box Machine Casing", "Inner 2 blocks") + .addOtherStructurePart("Engine Intake Machine Casing", "8x, ring around controller") + .addStructureInfo("Engine Intake Casings must not be obstructed in front (only air blocks)") + .addDynamoHatch("Back center", 2) + .addMaintenanceHatch("One of the casings next to a Gear Box", 1) + .addMufflerHatch("Top middle back, above the rear Gear Box", 1) + .addInputHatch("Diesel Fuel, next to a Gear Box", 1) + .addInputHatch("Lubricant, next to a Gear Box", 1) + .addInputHatch("Oxygen, optional, next to a Gear Box", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { casingTexturePages[0][50], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DIESEL_ENGINE_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DIESEL_ENGINE_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { casingTexturePages[0][50], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DIESEL_ENGINE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DIESEL_ENGINE_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { casingTexturePages[0][50] }; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return getMaxEfficiency(aStack) > 0; + } + + @Override + public RecipeMap<FuelBackend> getRecipeMap() { + return RecipeMaps.dieselFuels; + } + + @Override + protected boolean filtersFluid() { + return false; + } + + /** + * The nominal energy output This can be further multiplied by {@link #getMaxEfficiency(ItemStack)} when boosted + */ + protected int getNominalOutput() { + return 2048; + } + + protected Materials getBooster() { + return Materials.Oxygen; + } + + /** + * x times fuel will be consumed when boosted This will however NOT increase power output Go tweak + * {@link #getMaxEfficiency(ItemStack)} and {@link #getNominalOutput()} instead + */ + protected int getBoostFactor() { + return 2; + } + + /** + * x times of additive will be consumed when boosted + */ + protected int getAdditiveFactor() { + return 1; + } + + /** + * Efficiency will increase by this amount every tick + */ + protected int getEfficiencyIncrease() { + return 15; + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + ArrayList<FluidStack> tFluids = getStoredFluids(); + + // fast track lookup + if (!tFluids.isEmpty()) { + double boostedFuelValue = 0; + double boostedOutput = 0; + double extraFuelFraction = 0; + for (FluidStack tFluid : tFluids) { + GT_Recipe tRecipe = getRecipeMap().getBackend() + .findFuel(tFluid); + if (tRecipe == null) continue; + fuelValue = tRecipe.mSpecialValue; + + FluidStack tLiquid = tFluid.copy(); + if (boostEu) { + boostedFuelValue = GT_Utility.safeInt((long) (fuelValue * 1.5)); + boostedOutput = getNominalOutput() * 3; + + fuelConsumption = tLiquid.amount = getBoostFactor() * getNominalOutput() / fuelValue; + + // HOG consumption rate is normally 1 L/t, when it's supposed to be around 1.64 L/t + // This code increases fuel consumption by 1 at random, but with a weighted chance + if (boostedFuelValue * 2 > boostedOutput) { + extraFuelFraction = boostedOutput / boostedFuelValue; + extraFuelFraction = extraFuelFraction - (int) extraFuelFraction; + double rand = Math.random(); + if (rand < extraFuelFraction) { + tLiquid.amount += 1; + } + } + + } else { + fuelConsumption = tLiquid.amount = getNominalOutput() / fuelValue; + } + + // Deplete that amount + if (!depleteInput(tLiquid)) return CheckRecipeResultRegistry.NO_FUEL_FOUND; + boostEu = depleteInput(getBooster().getGas(2L * getAdditiveFactor())); + + // Check to prevent burning HOG without consuming it, if not boosted + if (!boostEu && fuelValue > getNominalOutput()) { + return SimpleCheckRecipeResult.ofFailure("fuel_quality_too_high"); + } + + // Deplete Lubricant. 1000L should = 1 hour of runtime (if baseEU = 2048) + if ((mRuntime % 72 == 0 || mRuntime == 0) + && !depleteInput(Materials.Lubricant.getFluid((boostEu ? 2L : 1L) * getAdditiveFactor()))) + return SimpleCheckRecipeResult.ofFailure("no_lubricant"); + + fuelRemaining = tFluid.amount; // Record available fuel + this.mEUt = mEfficiency < 2000 ? 0 : getNominalOutput(); // Output 0 if startup is less than 20% + this.mProgresstime = 1; + this.mMaxProgresstime = 1; + this.mEfficiencyIncrease = getEfficiencyIncrease(); + return CheckRecipeResultRegistry.GENERATING; + } + } + this.mEUt = 0; + this.mEfficiency = 0; + return CheckRecipeResultRegistry.NO_FUEL_FOUND; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_DieselEngine> getStructureDefinition() { + return STRUCTURE_DEFINITION.get(getClass()); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + return checkPiece(STRUCTURE_PIECE_MAIN, 1, 1, 1) && !mMufflerHatches.isEmpty() + && mMaintenanceHatches.size() == 1; + } + + public Block getCasingBlock() { + return GregTech_API.sBlockCasings4; + } + + public byte getCasingMeta() { + return 2; + } + + public Block getIntakeBlock() { + return GregTech_API.sBlockCasings4; + } + + public byte getIntakeMeta() { + return 13; + } + + public Block getGearboxBlock() { + return GregTech_API.sBlockCasings2; + } + + public byte getGearboxMeta() { + return 4; + } + + public byte getCasingTextureIndex() { + return 50; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_DieselEngine(this.mName); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 1; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return boostEu ? 30000 : 10000; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + return GT_Mod.gregtechproxy.mPollutionLargeCombustionEnginePerSecond; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return true; + } + + @Override + public String[] getInfoData() { + int mPollutionReduction = 0; + for (GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) { + mPollutionReduction = Math.max(tHatch.calculatePollutionReduction(100), mPollutionReduction); + } + + long storedEnergy = 0; + long maxEnergy = 0; + for (GT_MetaTileEntity_Hatch_Dynamo tHatch : filterValidMTEs(mDynamoHatches)) { + storedEnergy += tHatch.getBaseMetaTileEntity() + .getStoredEU(); + maxEnergy += tHatch.getBaseMetaTileEntity() + .getEUCapacity(); + } + + return new String[] { EnumChatFormatting.BLUE + "Diesel Engine" + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(storedEnergy) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxEnergy) + + EnumChatFormatting.RESET + + " EU", + getIdealStatus() == getRepairStatus() + ? EnumChatFormatting.GREEN + StatCollector.translateToLocal("GT5U.turbine.maintenance.false") + + EnumChatFormatting.RESET + : EnumChatFormatting.RED + StatCollector.translateToLocal("GT5U.turbine.maintenance.true") + + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.engine.output") + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(((long) mEUt * mEfficiency / 10000)) + + EnumChatFormatting.RESET + + " EU/t", + StatCollector.translateToLocal("GT5U.engine.consumption") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(fuelConsumption) + + EnumChatFormatting.RESET + + " L/t", + StatCollector.translateToLocal("GT5U.engine.value") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(fuelValue) + + EnumChatFormatting.RESET + + " EU/L", + StatCollector.translateToLocal("GT5U.turbine.fuel") + ": " + + EnumChatFormatting.GOLD + + GT_Utility.formatNumbers(fuelRemaining) + + EnumChatFormatting.RESET + + " L", + StatCollector.translateToLocal("GT5U.engine.efficiency") + ": " + + EnumChatFormatting.YELLOW + + (mEfficiency / 100F) + + EnumChatFormatting.YELLOW + + " %", + StatCollector.translateToLocal("GT5U.multiblock.pollution") + ": " + + EnumChatFormatting.GREEN + + mPollutionReduction + + EnumChatFormatting.RESET + + " %" }; + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 1, 1, 1); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 1, 1, 1, elementBudget, env, false, true); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DistillationTower.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DistillationTower.java new file mode 100644 index 0000000000..dfc3a4928d --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DistillationTower.java @@ -0,0 +1,367 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.isAir; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_GLOW; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.ofHatchAdder; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.Textures; +import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.fluid.IFluidStore; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Output_ME; + +public class GT_MetaTileEntity_DistillationTower extends + GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_DistillationTower> implements ISurvivalConstructable { + + protected static final int CASING_INDEX = 49; + protected static final String STRUCTURE_PIECE_BASE = "base"; + protected static final String STRUCTURE_PIECE_LAYER = "layer"; + protected static final String STRUCTURE_PIECE_LAYER_HINT = "layerHint"; + protected static final String STRUCTURE_PIECE_TOP_HINT = "topHint"; + private static final IStructureDefinition<GT_MetaTileEntity_DistillationTower> STRUCTURE_DEFINITION; + + static { + IHatchElement<GT_MetaTileEntity_DistillationTower> layeredOutputHatch = OutputHatch + .withCount(GT_MetaTileEntity_DistillationTower::getCurrentLayerOutputHatchCount) + .withAdder(GT_MetaTileEntity_DistillationTower::addLayerOutputHatch); + STRUCTURE_DEFINITION = StructureDefinition.<GT_MetaTileEntity_DistillationTower>builder() + .addShape(STRUCTURE_PIECE_BASE, transpose(new String[][] { { "b~b", "bbb", "bbb" }, })) + .addShape(STRUCTURE_PIECE_LAYER, transpose(new String[][] { { "lll", "lcl", "lll" }, })) + .addShape(STRUCTURE_PIECE_LAYER_HINT, transpose(new String[][] { { "lll", "l-l", "lll" }, })) + .addShape(STRUCTURE_PIECE_TOP_HINT, transpose(new String[][] { { "LLL", "LLL", "LLL" }, })) + .addElement( + 'b', + ofChain( + buildHatchAdder(GT_MetaTileEntity_DistillationTower.class) + .atLeast(Energy, OutputBus, InputHatch, InputBus, Maintenance) + .casingIndex(CASING_INDEX) + .dot(1) + .build(), + onElementPass( + GT_MetaTileEntity_DistillationTower::onCasingFound, + ofBlock(GregTech_API.sBlockCasings4, 1)))) + .addElement( + 'l', + ofChain( + buildHatchAdder(GT_MetaTileEntity_DistillationTower.class).atLeast(layeredOutputHatch) + .casingIndex(CASING_INDEX) + .dot(2) + .disallowOnly(ForgeDirection.UP, ForgeDirection.DOWN) + .build(), + ofHatchAdder(GT_MetaTileEntity_DistillationTower::addEnergyInputToMachineList, CASING_INDEX, 2), + ofHatchAdder(GT_MetaTileEntity_DistillationTower::addLayerOutputHatch, CASING_INDEX, 2), + ofHatchAdder(GT_MetaTileEntity_DistillationTower::addMaintenanceToMachineList, CASING_INDEX, 2), + onElementPass( + GT_MetaTileEntity_DistillationTower::onCasingFound, + ofBlock(GregTech_API.sBlockCasings4, 1)))) + // hint element only used in top layer + .addElement( + 'L', + buildHatchAdder(GT_MetaTileEntity_DistillationTower.class).atLeast(layeredOutputHatch) + .casingIndex(CASING_INDEX) + .dot(2) + .disallowOnly(ForgeDirection.UP) + .buildAndChain(GregTech_API.sBlockCasings4, 1)) + .addElement( + 'c', + ofChain( + onElementPass( + t -> t.onTopLayerFound(false), + ofHatchAdder(GT_MetaTileEntity_DistillationTower::addOutputToMachineList, CASING_INDEX, 3)), + onElementPass( + t -> t.onTopLayerFound(false), + ofHatchAdder( + GT_MetaTileEntity_DistillationTower::addMaintenanceToMachineList, + CASING_INDEX, + 3)), + onElementPass(t -> t.onTopLayerFound(true), ofBlock(GregTech_API.sBlockCasings4, 1)), + isAir())) + .build(); + } + + protected final List<List<GT_MetaTileEntity_Hatch_Output>> mOutputHatchesByLayer = new ArrayList<>(); + protected int mHeight; + protected int mCasing; + protected boolean mTopLayerFound; + + public GT_MetaTileEntity_DistillationTower(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_DistillationTower(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_DistillationTower(this.mName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Distillery") + .addInfo("Controller block for the Distillation Tower") + .addInfo("Fluids are only put out at the correct height") + .addInfo("The correct height equals the slot number in the NEI recipe") + .addSeparator() + .beginVariableStructureBlock(3, 3, 3, 12, 3, 3, true) + .addController("Front bottom") + .addOtherStructurePart("Clean Stainless Steel Machine Casing", "7 x h - 5 (minimum)") + .addEnergyHatch("Any casing except top centre", 1, 2) + .addMaintenanceHatch("Any casing", 1, 2, 3) + .addInputHatch("Any bottom layer casing", 1) + .addOutputBus("Any bottom layer casing", 1) + .addOutputHatch("2-11x Output Hatches (At least one per layer except bottom layer)", 2, 3) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + if (sideDirection == facingDirection) { + if (active) return new ITexture[] { BlockIcons.getCasingTextureForId(CASING_INDEX), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { BlockIcons.getCasingTextureForId(CASING_INDEX), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(CASING_INDEX) }; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.distillationTowerRecipes; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic(); + } + + protected void onCasingFound() { + mCasing++; + } + + protected void onTopLayerFound(boolean aIsCasing) { + mTopLayerFound = true; + if (aIsCasing) onCasingFound(); + } + + protected int getCurrentLayerOutputHatchCount() { + return mOutputHatchesByLayer.size() < mHeight || mHeight <= 0 ? 0 + : mOutputHatchesByLayer.get(mHeight - 1) + .size(); + } + + protected boolean addLayerOutputHatch(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null || aTileEntity.isDead() + || !(aTileEntity.getMetaTileEntity() instanceof GT_MetaTileEntity_Hatch_Output tHatch)) return false; + while (mOutputHatchesByLayer.size() < mHeight) mOutputHatchesByLayer.add(new ArrayList<>()); + tHatch.updateTexture(aBaseCasingIndex); + return mOutputHatchesByLayer.get(mHeight - 1) + .add(tHatch); + } + + @Override + public List<? extends IFluidStore> getFluidOutputSlots(FluidStack[] toOutput) { + return getFluidOutputSlotsByLayer(toOutput, mOutputHatchesByLayer); + } + + @Override + protected IAlignmentLimits getInitialAlignmentLimits() { + // don't rotate a freaking tower, it won't work + return (d, r, f) -> (d.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0 && r.isNotRotated() + && !f.isVerticallyFliped(); + } + + @Override + public boolean isRotationChangeAllowed() { + return false; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_DistillationTower> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + // reset + mOutputHatchesByLayer.forEach(List::clear); + mHeight = 1; + mTopLayerFound = false; + mCasing = 0; + + // check base + if (!checkPiece(STRUCTURE_PIECE_BASE, 1, 0, 0)) return false; + + // check each layer + while (mHeight < 12) { + if (!checkPiece(STRUCTURE_PIECE_LAYER, 1, mHeight, 0)) { + return false; + } + if (mOutputHatchesByLayer.size() < mHeight || mOutputHatchesByLayer.get(mHeight - 1) + .isEmpty()) + // layer without output hatch + return false; + if (mTopLayerFound) { + break; + } + // not top + mHeight++; + } + + // validate final invariants... (actual height is mHeight+1) + return mCasing >= 7 * (mHeight + 1) - 5 && mHeight + 1 >= 3 + && mTopLayerFound + && mMaintenanceHatches.size() == 1; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + protected void addFluidOutputs(FluidStack[] mOutputFluids2) { + for (int i = 0; i < mOutputFluids2.length && i < mOutputHatchesByLayer.size(); i++) { + final FluidStack fluidStack = mOutputFluids2[i]; + if (fluidStack == null) continue; + FluidStack tStack = fluidStack.copy(); + if (!dumpFluid(mOutputHatchesByLayer.get(i), tStack, true)) + dumpFluid(mOutputHatchesByLayer.get(i), tStack, false); + } + } + + @Override + public boolean canDumpFluidToME() { + // All fluids can be dumped to ME only if each layer contains a ME Output Hatch. + return this.mOutputHatchesByLayer.stream() + .allMatch( + tLayerOutputHatches -> tLayerOutputHatches.stream() + .anyMatch(tHatch -> tHatch instanceof GT_MetaTileEntity_Hatch_Output_ME)); + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_BASE, stackSize, hintsOnly, 1, 0, 0); + int tTotalHeight = Math.min(12, stackSize.stackSize + 2); // min 2 output layer, so at least 1 + 2 height + for (int i = 1; i < tTotalHeight - 1; i++) { + buildPiece(STRUCTURE_PIECE_LAYER_HINT, stackSize, hintsOnly, 1, i, 0); + } + buildPiece(STRUCTURE_PIECE_TOP_HINT, stackSize, hintsOnly, 1, tTotalHeight - 1, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + mHeight = 0; + int built = survivialBuildPiece(STRUCTURE_PIECE_BASE, stackSize, 1, 0, 0, elementBudget, env, false, true); + if (built >= 0) return built; + int tTotalHeight = Math.min(12, stackSize.stackSize + 2); // min 2 output layer, so at least 1 + 2 height + for (int i = 1; i < tTotalHeight - 1; i++) { + mHeight = i; + built = survivialBuildPiece( + STRUCTURE_PIECE_LAYER_HINT, + stackSize, + 1, + i, + 0, + elementBudget, + env, + false, + true); + if (built >= 0) return built; + } + mHeight = tTotalHeight - 1; + return survivialBuildPiece( + STRUCTURE_PIECE_TOP_HINT, + stackSize, + 1, + tTotalHeight - 1, + 0, + elementBudget, + env, + false, + true); + } + + @Override + protected SoundResource getProcessStartSound() { + return SoundResource.GT_MACHINES_DISTILLERY_LOOP; + } + + @Override + public boolean supportsVoidProtection() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DrillerBase.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DrillerBase.java new file mode 100644 index 0000000000..db58a1152e --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_DrillerBase.java @@ -0,0 +1,985 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.Muffler; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.GT_Values.W; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ORE_DRILL; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ORE_DRILL_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ORE_DRILL_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ORE_DRILL_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.getCasingTextureForId; +import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.ofFrame; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.StatCollector; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.common.util.ForgeDirection; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Pos2d; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.gui.widgets.GT_LockedWhileActiveButton; +import gregtech.api.interfaces.IChunkLoader; +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_DataAccess; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy; +import gregtech.api.objects.GT_ChunkManager; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.IGT_HatchAdder; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; + +public abstract class GT_MetaTileEntity_DrillerBase + extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_DrillerBase> + implements IChunkLoader, ISurvivalConstructable { + + private static final ItemStack miningPipe = GT_ModHandler.getIC2Item("miningPipe", 0); + private static final ItemStack miningPipeTip = GT_ModHandler.getIC2Item("miningPipeTip", 0); + private static final Block miningPipeBlock = GT_Utility.getBlockFromStack(miningPipe); + private static final Block miningPipeTipBlock = GT_Utility.getBlockFromStack(miningPipeTip); + protected static final String STRUCTURE_PIECE_MAIN = "main"; + protected static final ClassValue<IStructureDefinition<GT_MetaTileEntity_DrillerBase>> STRUCTURE_DEFINITION = new ClassValue<>() { + + @Override + protected IStructureDefinition<GT_MetaTileEntity_DrillerBase> computeValue(Class<?> type) { + return StructureDefinition.<GT_MetaTileEntity_DrillerBase>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose( + new String[][] { { " ", " f ", " " }, { " ", " f ", " " }, { " ", " f ", " " }, + { " f ", "fcf", " f " }, { " f ", "fcf", " f " }, { " f ", "fcf", " f " }, + { "b~b", "bbb", "bbb" }, })) + .addElement('f', lazy(t -> ofFrame(t.getFrameMaterial()))) + .addElement( + 'c', + lazy( + t -> ofBlock( + t.getCasingBlockItem() + .getBlock(), + t.getCasingBlockItem() + .get(0) + .getItemDamage()))) + .addElement( + 'b', + lazy( + t -> buildHatchAdder(GT_MetaTileEntity_DrillerBase.class).atLeastList(t.getAllowedHatches()) + .adder(GT_MetaTileEntity_DrillerBase::addToMachineList) + .casingIndex(t.casingTextureIndex) + .dot(1) + .buildAndChain( + t.getCasingBlockItem() + .getBlock(), + t.getCasingBlockItem() + .get(0) + .getItemDamage()))) + .build(); + } + }; + + private Block casingBlock; + private int casingMeta; + private int frameMeta; + protected int casingTextureIndex; + protected boolean isPickingPipes; + + private ForgeDirection back; + + private int xDrill, yDrill, zDrill, xPipe, zPipe, yHead; + + protected int getXDrill() { + return xDrill; + } + + protected int getZDrill() { + return zDrill; + } + + protected int getYHead() { + return yHead; + } + + protected int workState; + protected static final int STATE_DOWNWARD = 0, STATE_AT_BOTTOM = 1, STATE_UPWARD = 2, STATE_ABORT = 3; + + protected boolean mChunkLoadingEnabled = true; + protected ChunkCoordIntPair mCurrentChunk = null; + protected boolean mWorkChunkNeedsReload = true; + + /** Stores default result messages for success/failures of each work state. */ + private final Map<ResultRegistryKey, CheckRecipeResult> resultRegistry = new HashMap<>(); + + /** Allows inheritors to supply custom runtime failure messages. */ + private CheckRecipeResult runtimeFailure = null; + private CheckRecipeResult lastRuntimeFailure = null; + + /** Allows inheritors to supply custom shutdown failure messages. */ + private @NotNull String shutdownReason = ""; + + /** Allows inheritors to suppress wiping the last error if the machine is forcibly turned off. */ + protected boolean suppressErrorWipe = false; + + public GT_MetaTileEntity_DrillerBase(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + initFields(); + } + + public GT_MetaTileEntity_DrillerBase(String aName) { + super(aName); + initFields(); + } + + private void initFields() { + casingBlock = getCasingBlockItem().getBlock(); + casingMeta = getCasingBlockItem().get(0) + .getItemDamage(); + int frameId = 4096 + getFrameMaterial().mMetaItemSubID; + frameMeta = GregTech_API.METATILEENTITIES[frameId] != null + ? GregTech_API.METATILEENTITIES[frameId].getTileEntityBaseType() + : W; + casingTextureIndex = getCasingTextureIndex(); + workState = STATE_DOWNWARD; + + // Inheritors can overwrite these to add custom operating messages. + addResultMessage(STATE_DOWNWARD, true, "deploying_pipe"); + addResultMessage(STATE_DOWNWARD, false, "extracting_pipe"); + addResultMessage(STATE_AT_BOTTOM, true, "drilling"); + addResultMessage(STATE_AT_BOTTOM, false, "no_mining_pipe"); + addResultMessage(STATE_UPWARD, true, "retracting_pipe"); + addResultMessage(STATE_UPWARD, false, "drill_generic_finished"); + addResultMessage(STATE_ABORT, true, "retracting_pipe"); + addResultMessage(STATE_ABORT, false, "drill_retract_pipes_finished"); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + if (sideDirection == facingDirection) { + if (active) return new ITexture[] { getCasingTextureForId(casingTextureIndex), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ORE_DRILL_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ORE_DRILL_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { getCasingTextureForId(casingTextureIndex), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ORE_DRILL) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ORE_DRILL_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { getCasingTextureForId(casingTextureIndex) }; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setInteger("workState", workState); + aNBT.setBoolean("chunkLoadingEnabled", mChunkLoadingEnabled); + aNBT.setBoolean("isChunkloading", mCurrentChunk != null); + if (mCurrentChunk != null) { + aNBT.setInteger("loadedChunkXPos", mCurrentChunk.chunkXPos); + aNBT.setInteger("loadedChunkZPos", mCurrentChunk.chunkZPos); + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + workState = aNBT.getInteger("workState"); + if (aNBT.hasKey("isPickingPipes")) + workState = aNBT.getBoolean("isPickingPipes") ? STATE_UPWARD : STATE_DOWNWARD; + if (aNBT.hasKey("chunkLoadingEnabled")) mChunkLoadingEnabled = aNBT.getBoolean("chunkLoadingEnabled"); + if (aNBT.getBoolean("isChunkloading")) { + mCurrentChunk = new ChunkCoordIntPair( + aNBT.getInteger("loadedChunkXPos"), + aNBT.getInteger("loadedChunkZPos")); + } + } + + @Override + public boolean onSolderingToolRightClick(ForgeDirection side, ForgeDirection wrenchingSide, + EntityPlayer entityPlayer, float aX, float aY, float aZ) { + if (side == getBaseMetaTileEntity().getFrontFacing()) { + mChunkLoadingEnabled = !mChunkLoadingEnabled; + GT_Utility.sendChatToPlayer( + entityPlayer, + mChunkLoadingEnabled ? GT_Utility.trans("502", "Mining chunk loading enabled") + : GT_Utility.trans("503", "Mining chunk loading disabled")); + return true; + } + return super.onSolderingToolRightClick(side, wrenchingSide, entityPlayer, aX, aY, aZ); + } + + @Override + public void onRemoval() { + if (mChunkLoadingEnabled) GT_ChunkManager.releaseTicket((TileEntity) getBaseMetaTileEntity()); + super.onRemoval(); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isServerSide() && mCurrentChunk != null + && !mWorkChunkNeedsReload + && !aBaseMetaTileEntity.isAllowedToWork()) { + // if machine has stopped, stop chunkloading + GT_ChunkManager.releaseTicket((TileEntity) aBaseMetaTileEntity); + mWorkChunkNeedsReload = true; + } + } + + protected boolean tryPickPipe() { + if (yHead == yDrill) return isPickingPipes = false; + if (tryOutputPipe()) { + if (checkBlockAndMeta(xPipe, yHead + 1, zPipe, miningPipeBlock, W)) getBaseMetaTileEntity().getWorld() + .setBlock(xPipe, yHead + 1, zPipe, miningPipeTipBlock); + getBaseMetaTileEntity().getWorld() + .setBlockToAir(xPipe, yHead, zPipe); + return isPickingPipes = true; + } + return isPickingPipes = false; + } + + /** + * Added for compability reasons + * + * @return true if the state is 0 false otherwise. + * @deprecated compatibility reason + */ + @Deprecated + protected boolean tryLowerPipe() { + return tryLowerPipeState(false) == 0; + } + + /** + * @return 0 for succeeded, 1 for invalid block, 2 for not having mining pipes, 3 for event canceled. + */ + protected int tryLowerPipeState() { + return tryLowerPipeState(false); + } + + /** + * @return 0 for succeeded, 1 for invalid block, 2 for not having mining pipes, 3 for event canceled. + */ + protected int tryLowerPipeState(boolean isSimulating) { + if (!isHasMiningPipes()) return 2; + switch (canLowerPipe()) { + case 1 -> { + return 1; + } + case 2 -> { + return 3; + } + } + + Block b = getBaseMetaTileEntity().getBlock(xPipe, yHead - 1, zPipe); + if (b != miningPipeTipBlock && !GT_Utility.setBlockByFakePlayer( + getFakePlayer(getBaseMetaTileEntity()), + xPipe, + yHead - 1, + zPipe, + miningPipeTipBlock, + 0, + isSimulating)) return 3; + if (!isSimulating) { + if (yHead != yDrill) getBaseMetaTileEntity().getWorld() + .setBlock(xPipe, yHead, zPipe, miningPipeBlock); + if (b != miningPipeBlock && b != miningPipeTipBlock) getBaseMetaTileEntity().decrStackSize(1, 1); + } + + return 0; + } + + private void putMiningPipesFromInputsInController() { + int maxPipes = miningPipe.getMaxStackSize(); + if (isHasMiningPipes(maxPipes)) return; + + ItemStack pipes = getStackInSlot(1); + if (pipes != null && !pipes.isItemEqual(miningPipe)) return; + for (ItemStack storedItem : getStoredInputs()) { + if (!storedItem.isItemEqual(miningPipe)) continue; + + if (pipes == null) { + setInventorySlotContents(1, GT_Utility.copyOrNull(miningPipe)); + pipes = getStackInSlot(1); + } + + if (pipes.stackSize == maxPipes) break; + + int needPipes = maxPipes - pipes.stackSize; + int transferPipes = Math.min(storedItem.stackSize, needPipes); + + pipes.stackSize += transferPipes; + storedItem.stackSize -= transferPipes; + } + updateSlots(); + } + + private boolean tryOutputPipe() { + if (!getBaseMetaTileEntity().addStackToSlot(1, GT_Utility.copyAmount(1, miningPipe))) + mOutputItems = new ItemStack[] { GT_Utility.copyAmount(1, miningPipe) }; + return true; + } + + /** + * @return 0 for available, 1 for invalid block, 2 for event canceled. + */ + protected int canLowerPipe() { + IGregTechTileEntity aBaseTile = getBaseMetaTileEntity(); + if (yHead > 0 && GT_Utility.getBlockHardnessAt(aBaseTile.getWorld(), xPipe, yHead - 1, zPipe) >= 0) { + return GT_Utility.eraseBlockByFakePlayer(getFakePlayer(aBaseTile), xPipe, yHead - 1, zPipe, true) ? 0 : 2; + } + return 1; + } + + protected boolean reachingVoidOrBedrock() { + return yHead <= 0 || checkBlockAndMeta(xPipe, yHead - 1, zPipe, Blocks.bedrock, W); + } + + private boolean isHasMiningPipes() { + return isHasMiningPipes(1); + } + + private boolean isHasMiningPipes(int minCount) { + ItemStack pipe = getStackInSlot(1); + return pipe != null && pipe.stackSize > minCount - 1 && pipe.isItemEqual(miningPipe); + } + + /** + * @deprecated Readded for compability + * @return if no pipes are present + */ + @Deprecated + protected boolean waitForPipes() { + return !isHasMiningPipes(); + } + + private boolean isEnergyEnough() { + long requiredEnergy = 512 + getMaxInputVoltage() * 4; + for (GT_MetaTileEntity_Hatch_Energy energyHatch : mEnergyHatches) { + requiredEnergy -= energyHatch.getEUVar(); + if (requiredEnergy <= 0) return true; + } + return false; + } + + protected boolean workingDownward(ItemStack aStack, int xDrill, int yDrill, int zDrill, int xPipe, int zPipe, + int yHead, int oldYHead) { + switch (tryLowerPipeState()) { + case 2 -> { + mMaxProgresstime = 0; + setRuntimeFailureReason(CheckRecipeResultRegistry.MISSING_MINING_PIPE); + return false; + } + case 3 -> { + workState = STATE_UPWARD; + return true; + } + case 1 -> { + workState = STATE_AT_BOTTOM; + return true; + } + default -> { + return true; + } + } + } + + protected boolean workingAtBottom(ItemStack aStack, int xDrill, int yDrill, int zDrill, int xPipe, int zPipe, + int yHead, int oldYHead) { + if (tryLowerPipeState(true) == 0) { + workState = STATE_DOWNWARD; + return true; + } + workState = STATE_UPWARD; + return true; + } + + protected boolean workingUpward(ItemStack aStack, int xDrill, int yDrill, int zDrill, int xPipe, int zPipe, + int yHead, int oldYHead) { + if (tryPickPipe()) { + return true; + } else { + workState = STATE_DOWNWARD; + stopMachine(ShutDownReasonRegistry.NONE); + return false; + } + } + + /** Called once when the abort button is clicked. Use to perform any needed cleanup (e.g. unloading chunks.) */ + protected void onAbort() {} + + protected void abortDrilling() { + if (workState != STATE_ABORT) { + workState = STATE_ABORT; + onAbort(); + setShutdownReason(""); + + if (!isAllowedToWork()) { + enableWorking(); + } + } + } + + // This is a distinct state from workingUpward, because some inheritors (like concrete backfiller) operate + // exclusively on the workingUpward phase. It also allows for more distinct status messages. + protected boolean workingToAbortOperation(@NotNull ItemStack aStack, int xDrill, int yDrill, int zDrill, int xPipe, + int zPipe, int yHead, int oldYHead) { + if (tryPickPipe()) { + return true; + } else { + workState = STATE_DOWNWARD; + stopMachine(ShutDownReasonRegistry.NONE); + return false; + } + } + + @Override + public void enableWorking() { + super.enableWorking(); + shutdownReason = ""; + } + + @Override + public void onDisableWorking() { + if (suppressErrorWipe) { + suppressErrorWipe = false; + } else { + super.onDisableWorking(); + } + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + ItemStack controllerStack = getControllerSlot(); + // Public pipe actions + setElectricityStats(); + int oldYHead = yHead; + if (!checkPipesAndSetYHead()) { + stopMachine(ShutDownReasonRegistry.NONE); + return SimpleCheckRecipeResult.ofFailure("no_mining_pipe"); + } else if (!isEnergyEnough()) { + stopMachine(ShutDownReasonRegistry.NONE); + return SimpleCheckRecipeResult.ofFailure("not_enough_energy"); + } + putMiningPipesFromInputsInController(); + + final boolean wasSuccessful; + switch (workState) { + case STATE_DOWNWARD -> wasSuccessful = workingDownward( + controllerStack, + xDrill, + yDrill, + zDrill, + xPipe, + zPipe, + yHead, + oldYHead); + case STATE_AT_BOTTOM -> wasSuccessful = workingAtBottom( + controllerStack, + xDrill, + yDrill, + zDrill, + xPipe, + zPipe, + yHead, + oldYHead); + case STATE_UPWARD -> wasSuccessful = workingUpward( + controllerStack, + xDrill, + yDrill, + zDrill, + xPipe, + zPipe, + yHead, + oldYHead); + case STATE_ABORT -> wasSuccessful = workingToAbortOperation( + controllerStack, + xDrill, + yDrill, + zDrill, + xPipe, + zPipe, + yHead, + oldYHead); + default -> wasSuccessful = false; + } + + if (runtimeFailure == null) { + if (wasSuccessful) { + lastRuntimeFailure = null; + } + + return resultRegistry.getOrDefault( + new ResultRegistryKey(workState, wasSuccessful), + SimpleCheckRecipeResult.ofFailure("no_mining_pipe")); + } else { + final CheckRecipeResult result; + result = lastRuntimeFailure = runtimeFailure; + runtimeFailure = null; + return result; + } + } + + /** + * Allow drills to set a specific failure reason specific to their situation. E.g.: out of drilling fluid. + * Should be used when the machine doesn't turn off due to the failure. + * + * @param newFailureReason A new failure reason + */ + protected void setRuntimeFailureReason(@NotNull CheckRecipeResult newFailureReason) { + runtimeFailure = newFailureReason; + } + + /** + * Gets a reason for why the drill turned off, for use in UIs and such. + * + * @return A reason, or empty if the machine is active or there is no message set yet. + */ + @NotNull + protected Optional<String> getFailureReason() { + if (getBaseMetaTileEntity().isActive()) { + return Optional.empty(); + } + + if (!shutdownReason.isEmpty()) { + return Optional.of(shutdownReason); + } + + return Optional.ofNullable(lastRuntimeFailure) + .map(CheckRecipeResult::getDisplayString); + } + + /** + * Sets a line in the UI to explain why the drill shut down. E.g.: operation finished. + * Should be used when the machine has been turned off due to an operating issue or completion. + * + * @param newReason The reason for the machine shutdown + */ + protected void setShutdownReason(@NotNull String newReason) { + shutdownReason = newReason; + } + + @Override + protected IAlignmentLimits getInitialAlignmentLimits() { + return (d, r, f) -> (d.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0 && r.isNotRotated() + && !f.isVerticallyFliped(); + } + + @Override + public boolean isRotationChangeAllowed() { + return false; + } + + @Override + public final IStructureDefinition<GT_MetaTileEntity_DrillerBase> getStructureDefinition() { + return STRUCTURE_DEFINITION.get(getClass()); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + updateCoordinates(); + return checkPiece(STRUCTURE_PIECE_MAIN, 1, 6, 0) && checkHatches() + && GT_Utility.getTier(getMaxInputVoltage()) >= getMinTier() + && mMaintenanceHatches.size() == 1; + } + + private void updateCoordinates() { + xDrill = getBaseMetaTileEntity().getXCoord(); + yDrill = getBaseMetaTileEntity().getYCoord(); + zDrill = getBaseMetaTileEntity().getZCoord(); + back = getBaseMetaTileEntity().getBackFacing(); + xPipe = xDrill + back.offsetX; + zPipe = zDrill + back.offsetZ; + } + + private boolean checkPipesAndSetYHead() { + yHead = yDrill - 1; + while (checkBlockAndMeta(xPipe, yHead, zPipe, miningPipeBlock, W)) yHead--; // skip pipes + // is pipe tip OR is controller layer + if (checkBlockAndMeta(xPipe, yHead, zPipe, miningPipeTipBlock, W) || ++yHead == yDrill) return true; + // pipe column is broken - try fix + getBaseMetaTileEntity().getWorld() + .setBlock(xPipe, yHead, zPipe, miningPipeTipBlock); + return true; + } + + @Deprecated + protected boolean checkCasingBlock(int xOff, int yOff, int zOff) { + return checkBlockAndMetaOffset(xOff, yOff, zOff, casingBlock, casingMeta); + } + + // meta of frame is getTileEntityBaseType; frame should be checked using its drops (possible a high weight + // operation) + @Deprecated + protected boolean checkFrameBlock(int xOff, int yOff, int zOff) { + return checkBlockAndMetaOffset(xOff, yOff, zOff, GregTech_API.sBlockMachines, frameMeta); + } + + @Deprecated + protected boolean checkBlockAndMetaOffset(int xOff, int yOff, int zOff, Block block, int meta) { + return checkBlockAndMeta(xDrill + xOff, yDrill + yOff, zDrill + zOff, block, meta); + } + + private boolean checkBlockAndMeta(int x, int y, int z, Block block, int meta) { + return (meta == W || getBaseMetaTileEntity().getMetaID(x, y, z) == meta) + && getBaseMetaTileEntity().getBlock(x, y, z) == block; + } + + private FakePlayer mFakePlayer = null; + + protected FakePlayer getFakePlayer(IGregTechTileEntity aBaseTile) { + if (mFakePlayer == null) mFakePlayer = GT_Utility.getFakePlayer(aBaseTile); + mFakePlayer.setWorld(aBaseTile.getWorld()); + mFakePlayer.setPosition(aBaseTile.getXCoord(), aBaseTile.getYCoord(), aBaseTile.getZCoord()); + return mFakePlayer; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + protected abstract ItemList getCasingBlockItem(); + + @Deprecated + protected String getCasingName() { + return null; + } + + protected abstract Materials getFrameMaterial(); + + protected abstract int getCasingTextureIndex(); + + protected abstract int getMinTier(); + + protected abstract boolean checkHatches(); + + protected abstract void setElectricityStats(); + + public int getTotalConfigValue() { + int config = 0; + ArrayList<ItemStack> tCircuitList = getDataItems(1); + for (ItemStack tCircuit : tCircuitList) config += tCircuit.getItemDamage(); + return config; + } + + public ArrayList<GT_MetaTileEntity_Hatch_DataAccess> mDataAccessHatches = new ArrayList<>(); + + /** + * @param state using bitmask, 1 for IntegratedCircuit, 2 for DataStick, 4 for DataOrb + */ + private boolean isCorrectDataItem(ItemStack aStack, int state) { + if ((state & 1) != 0 && ItemList.Circuit_Integrated.isStackEqual(aStack, true, true)) return true; + if ((state & 2) != 0 && ItemList.Tool_DataStick.isStackEqual(aStack, false, true)) return true; + return (state & 4) != 0 && ItemList.Tool_DataOrb.isStackEqual(aStack, false, true); + } + + /** + * @param state using bitmask, 1 for IntegratedCircuit, 2 for DataStick, 4 for DataOrb + */ + public ArrayList<ItemStack> getDataItems(int state) { + ArrayList<ItemStack> rList = new ArrayList<>(); + if (GT_Utility.isStackValid(mInventory[1]) && isCorrectDataItem(mInventory[1], state)) { + rList.add(mInventory[1]); + } + for (GT_MetaTileEntity_Hatch_DataAccess tHatch : filterValidMTEs(mDataAccessHatches)) { + for (int i = 0; i < tHatch.getBaseMetaTileEntity() + .getSizeInventory(); i++) { + if (tHatch.getBaseMetaTileEntity() + .getStackInSlot(i) != null && isCorrectDataItem( + tHatch.getBaseMetaTileEntity() + .getStackInSlot(i), + state)) + rList.add( + tHatch.getBaseMetaTileEntity() + .getStackInSlot(i)); + } + } + return rList; + } + + @Override + public boolean addToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + return super.addToMachineList(aTileEntity, aBaseCasingIndex) + || addDataAccessToMachineList(aTileEntity, aBaseCasingIndex); + } + + public boolean addDataAccessToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_DataAccess) { + ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture((byte) aBaseCasingIndex); + return mDataAccessHatches.add((GT_MetaTileEntity_Hatch_DataAccess) aMetaTileEntity); + } + return false; + } + + @Override + public ChunkCoordIntPair getActiveChunk() { + return mCurrentChunk; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 1, 6, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 1, 6, 0, elementBudget, env, false, true); + } + + @Override + protected void drawTexts(DynamicPositionedColumn screenElements, SlotWidget inventorySlot) { + super.drawTexts(screenElements, inventorySlot); + screenElements.widget( + TextWidget.dynamicString(() -> shutdownReason) + .setSynced(false) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled(widget -> !(getBaseMetaTileEntity().isActive() || shutdownReason.isEmpty()))) + .widget(new FakeSyncWidget.StringSyncer(() -> shutdownReason, newString -> shutdownReason = newString)); + } + + @Override + protected boolean showRecipeTextInGUI() { + return false; + } + + /** + * Adds additional buttons to the main button row. You do not need to set the position. + * + * @param builder Only use to attach SyncWidgets. + * @param buildContext Context for things like the player. + */ + protected List<ButtonWidget> getAdditionalButtons(ModularWindow.Builder builder, UIBuildContext buildContext) { + return ImmutableList.of(); + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + super.addUIWidgets(builder, buildContext); + final int BUTTON_Y_LEVEL = 91; + + builder.widget( + new GT_LockedWhileActiveButton(this.getBaseMetaTileEntity(), builder) + .setOnClick((clickData, widget) -> mChunkLoadingEnabled = !mChunkLoadingEnabled) + .setPlayClickSound(true) + .setBackground(() -> { + if (mChunkLoadingEnabled) { + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD_PRESSED, + GT_UITextures.OVERLAY_BUTTON_CHUNK_LOADING }; + } + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD, + GT_UITextures.OVERLAY_BUTTON_CHUNK_LOADING_OFF }; + }) + .attachSyncer( + new FakeSyncWidget.BooleanSyncer( + () -> mChunkLoadingEnabled, + newBoolean -> mChunkLoadingEnabled = newBoolean), + builder, + (widget, val) -> widget.notifyTooltipChange()) + .dynamicTooltip( + () -> ImmutableList.of( + StatCollector.translateToLocal( + mChunkLoadingEnabled ? "GT5U.gui.button.chunk_loading_on" + : "GT5U.gui.button.chunk_loading_off"))) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setPos(new Pos2d(80, BUTTON_Y_LEVEL)) + .setSize(16, 16)) + .widget( + new ButtonWidget().setOnClick((clickData, widget) -> abortDrilling()) + .setPlayClickSound(true) + .setBackground(() -> { + if (workState == STATE_ABORT) { + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD_PRESSED, + GT_UITextures.OVERLAY_BUTTON_RETRACT_PIPE, GT_UITextures.OVERLAY_BUTTON_LOCKED }; + } + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD, + GT_UITextures.OVERLAY_BUTTON_RETRACT_PIPE }; + }) + .attachSyncer( + new FakeSyncWidget.IntegerSyncer(() -> workState, (newInt) -> workState = newInt), + builder, + (widget, integer) -> widget.notifyTooltipChange()) + .dynamicTooltip( + () -> ImmutableList.of( + StatCollector.translateToLocalFormatted( + workState == STATE_ABORT ? "GT5U.gui.button.drill_retract_pipes_active" + : "GT5U.gui.button.drill_retract_pipes"))) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setPos(new Pos2d(174, 130)) + .setSize(16, 16)); + + int left = 98; + for (ButtonWidget button : getAdditionalButtons(builder, buildContext)) { + button.setPos(new Pos2d(left, BUTTON_Y_LEVEL)) + .setSize(16, 16); + builder.widget(button); + left += 18; + } + } + + protected List<IHatchElement<? super GT_MetaTileEntity_DrillerBase>> getAllowedHatches() { + return ImmutableList.of( + InputHatch, + OutputHatch, + InputBus, + OutputBus, + Muffler, + Maintenance, + Energy, + DataHatchElement.DataAccess); + } + + protected enum DataHatchElement implements IHatchElement<GT_MetaTileEntity_DrillerBase> { + + DataAccess; + + @Override + public List<? extends Class<? extends IMetaTileEntity>> mteClasses() { + return Collections.singletonList(GT_MetaTileEntity_Hatch_DataAccess.class); + } + + @Override + public IGT_HatchAdder<GT_MetaTileEntity_DrillerBase> adder() { + return GT_MetaTileEntity_DrillerBase::addDataAccessToMachineList; + } + + @Override + public long count(GT_MetaTileEntity_DrillerBase t) { + return t.mDataAccessHatches.size(); + } + } + + /** + * Sets or overrides the {@link CheckRecipeResult} for a given work state + * + * @param state A work state like {@link #STATE_DOWNWARD}. + * @param result A previously registered recipe result. + */ + protected void addResultMessage(final int state, @NotNull final CheckRecipeResult result) { + resultRegistry.put(new ResultRegistryKey(state, result.wasSuccessful()), result); + } + + /** + * Sets or overrides the {@link CheckRecipeResult} for a given work state and operation success type. + * + * @param state A work state like {@link #STATE_DOWNWARD}. + * @param wasSuccessful Whether the operation was successful. + * @param resultKey An I18N key for the message. + */ + protected void addResultMessage(final int state, final boolean wasSuccessful, @NotNull final String resultKey) { + addResultMessage( + state, + wasSuccessful ? SimpleCheckRecipeResult.ofSuccess(resultKey) + : SimpleCheckRecipeResult.ofFailure(resultKey)); + } + + @SuppressWarnings("ClassCanBeRecord") + private final static class ResultRegistryKey { + + private final int state; + private final boolean successful; + + public ResultRegistryKey(final int state, final boolean successful) { + this.state = state; + this.successful = successful; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ResultRegistryKey other)) { + return false; + } + + return (state == other.state && successful == other.successful); + } + + @Override + public int hashCode() { + return Objects.hash(state, successful); + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ElectricBlastFurnace.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ElectricBlastFurnace.java new file mode 100644 index 0000000000..8913e8fedd --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ElectricBlastFurnace.java @@ -0,0 +1,401 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.Muffler; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ELECTRIC_BLAST_FURNACE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ELECTRIC_BLAST_FURNACE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ELECTRIC_BLAST_FURNACE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ELECTRIC_BLAST_FURNACE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.ofCoil; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.HeatingCoilLevel; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.fluid.IFluidStore; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_ElectricBlastFurnace extends + GT_MetaTileEntity_AbstractMultiFurnace<GT_MetaTileEntity_ElectricBlastFurnace> implements ISurvivalConstructable { + + private int mHeatingCapacity = 0; + protected final ArrayList<GT_MetaTileEntity_Hatch_Output> mPollutionOutputHatches = new ArrayList<>(); + protected final FluidStack[] pollutionFluidStacks = { Materials.CarbonDioxide.getGas(1000), + Materials.CarbonMonoxide.getGas(1000), Materials.SulfurDioxide.getGas(1000) }; + + protected static final int CASING_INDEX = 11; + protected static final String STRUCTURE_PIECE_MAIN = "main"; + private static final IStructureDefinition<GT_MetaTileEntity_ElectricBlastFurnace> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_ElectricBlastFurnace>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose( + new String[][] { { "ttt", "tmt", "ttt" }, { "CCC", "C-C", "CCC" }, { "CCC", "C-C", "CCC" }, + { "b~b", "bbb", "bbb" } })) + .addElement( + 't', + buildHatchAdder(GT_MetaTileEntity_ElectricBlastFurnace.class) + .atLeast( + OutputHatch.withAdder(GT_MetaTileEntity_ElectricBlastFurnace::addOutputHatchToTopList) + .withCount(t -> t.mPollutionOutputHatches.size())) + .casingIndex(CASING_INDEX) + .dot(1) + .buildAndChain(GregTech_API.sBlockCasings1, CASING_INDEX)) + .addElement('m', Muffler.newAny(CASING_INDEX, 2)) + .addElement( + 'C', + ofCoil( + GT_MetaTileEntity_ElectricBlastFurnace::setCoilLevel, + GT_MetaTileEntity_ElectricBlastFurnace::getCoilLevel)) + .addElement( + 'b', + buildHatchAdder(GT_MetaTileEntity_ElectricBlastFurnace.class) + .atLeast(InputHatch, OutputHatch, InputBus, OutputBus, Maintenance, Energy) + .casingIndex(CASING_INDEX) + .dot(1) + .buildAndChain(GregTech_API.sBlockCasings1, CASING_INDEX)) + .build(); + + public GT_MetaTileEntity_ElectricBlastFurnace(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_ElectricBlastFurnace(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_ElectricBlastFurnace(this.mName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Blast Furnace") + .addInfo("Controller block for the Electric Blast Furnace") + .addInfo("You can use some fluids to reduce recipe time. Place the circuit in the Input Bus") + .addInfo("Each 900K over the min. Heat required reduces power consumption by 5% (multiplicatively)") + .addInfo("Each 1800K over the min. Heat allows for an overclock to be upgraded to a perfect overclock.") + .addInfo("That means the EBF will reduce recipe time by a factor 4 instead of 2 (giving 100% efficiency).") + .addInfo("Additionally gives +100K for every tier past MV") + .addPollutionAmount(getPollutionPerSecond(null)) + .addSeparator() + .beginStructureBlock(3, 4, 3, true) + .addController("Front bottom") + .addCasingInfoRange("Heat Proof Machine Casing", 0, 15, false) + .addOtherStructurePart("Heating Coils", "Two middle Layers") + .addEnergyHatch("Any bottom layer casing", 3) + .addMaintenanceHatch("Any bottom layer casing", 3) + .addMufflerHatch("Top middle", 2) + .addInputBus("Any bottom layer casing", 3) + .addInputHatch("Any bottom layer casing", 3) + .addOutputBus("Any bottom layer casing", 3) + .addOutputHatch("Fluid outputs, Any bottom layer casing") + .addOutputHatch("Pollution gases (CO2/CO/SO2), Any top layer casing", 1) + .addStructureInfo("Pollution gas output amount scales with Muffler Hatch tier") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { casingTexturePages[0][CASING_INDEX], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ELECTRIC_BLAST_FURNACE_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ELECTRIC_BLAST_FURNACE_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { casingTexturePages[0][CASING_INDEX], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ELECTRIC_BLAST_FURNACE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ELECTRIC_BLAST_FURNACE_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { casingTexturePages[0][CASING_INDEX] }; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + return GT_Mod.gregtechproxy.mPollutionEBFPerSecond; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.blastFurnaceRecipes; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_ElectricBlastFurnace> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @Nonnull + @Override + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) { + return super.createOverclockCalculator(recipe).setRecipeHeat(recipe.mSpecialValue) + .setMachineHeat(mHeatingCapacity) + .setHeatOC(true) + .setHeatDiscount(true); + } + + @Override + protected @Nonnull CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + return recipe.mSpecialValue <= mHeatingCapacity ? CheckRecipeResultRegistry.SUCCESSFUL + : CheckRecipeResultRegistry.insufficientHeat(recipe.mSpecialValue); + } + }; + } + + public boolean addOutputHatchToTopList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output) { + ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); + return mPollutionOutputHatches.add((GT_MetaTileEntity_Hatch_Output) aMetaTileEntity); + } + return false; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + this.mHeatingCapacity = 0; + + setCoilLevel(HeatingCoilLevel.None); + + mPollutionOutputHatches.clear(); + + if (!checkPiece(STRUCTURE_PIECE_MAIN, 1, 3, 0)) return false; + + if (getCoilLevel() == HeatingCoilLevel.None) return false; + + if (mMaintenanceHatches.size() != 1) return false; + + this.mHeatingCapacity = (int) getCoilLevel().getHeat() + 100 * (GT_Utility.getTier(getMaxInputVoltage()) - 2); + return true; + } + + @Override + public boolean addOutput(FluidStack aLiquid) { + if (aLiquid == null) return false; + FluidStack tLiquid = aLiquid.copy(); + ArrayList<GT_MetaTileEntity_Hatch_Output> tOutputHatches; + if (isPollutionFluid(tLiquid)) { + tOutputHatches = this.mPollutionOutputHatches; + multiplyPollutionFluidAmount(tLiquid); + } else { + tOutputHatches = this.mOutputHatches; + } + return dumpFluid(tOutputHatches, tLiquid, true) || dumpFluid(tOutputHatches, tLiquid, false); + } + + protected boolean isPollutionFluid(@Nullable FluidStack fluidStack) { + if (fluidStack == null) return false; + for (FluidStack pollutionFluidStack : pollutionFluidStacks) { + if (!fluidStack.isFluidEqual(pollutionFluidStack)) continue; + return true; + } + return false; + } + + @Override + public List<? extends IFluidStore> getFluidOutputSlots(FluidStack[] toOutput) { + if (Arrays.stream(toOutput) + .anyMatch(this::isPollutionFluid)) { + return filterValidMTEs(mPollutionOutputHatches); + } + return filterValidMTEs(mOutputHatches); + } + + /** + * @return 100 -> all released to air, 0 -> all dumped to hatch + */ + public int getPollutionReduction() { + int reduction = 100; + for (GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) { + reduction = Math.min(tHatch.calculatePollutionReduction(100), reduction); + } + return reduction; + } + + protected void multiplyPollutionFluidAmount(@Nonnull FluidStack fluid) { + fluid.amount = fluid.amount * Math.min(100 - getPollutionReduction(), 100) / 100; + } + + @Override + public String[] getInfoData() { + int mPollutionReduction = getPollutionReduction(); + long storedEnergy = 0; + long maxEnergy = 0; + for (GT_MetaTileEntity_Hatch_Energy tHatch : filterValidMTEs(mEnergyHatches)) { + storedEnergy += tHatch.getBaseMetaTileEntity() + .getStoredEU(); + maxEnergy += tHatch.getBaseMetaTileEntity() + .getEUCapacity(); + } + + return new String[] { + StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mProgresstime / 20) + + EnumChatFormatting.RESET + + " s / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mMaxProgresstime / 20) + + EnumChatFormatting.RESET + + " s", + StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(storedEnergy) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxEnergy) + + EnumChatFormatting.RESET + + " EU", + StatCollector.translateToLocal("GT5U.multiblock.usage") + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(-mEUt) + + EnumChatFormatting.RESET + + " EU/t", + StatCollector.translateToLocal("GT5U.multiblock.mei") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(getMaxInputVoltage()) + + EnumChatFormatting.RESET + + " EU/t(*2A) " + + StatCollector.translateToLocal("GT5U.machines.tier") + + ": " + + EnumChatFormatting.YELLOW + + VN[GT_Utility.getTier(getMaxInputVoltage())] + + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.multiblock.problems") + ": " + + EnumChatFormatting.RED + + (getIdealStatus() - getRepairStatus()) + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.multiblock.efficiency") + + ": " + + EnumChatFormatting.YELLOW + + mEfficiency / 100.0F + + EnumChatFormatting.RESET + + " %", + StatCollector.translateToLocal("GT5U.EBF.heat") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mHeatingCapacity) + + EnumChatFormatting.RESET + + " K", + StatCollector.translateToLocal("GT5U.multiblock.pollution") + ": " + + EnumChatFormatting.GREEN + + mPollutionReduction + + EnumChatFormatting.RESET + + " %" }; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 1, 3, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 1, 3, 0, elementBudget, env, false, true); + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + inputSeparation = !inputSeparation; + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("GT5U.machines.separatebus") + " " + inputSeparation); + } + + @Override + public void loadNBTData(final NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (aNBT.hasKey("isBussesSeparate")) { + // backward compatibility + inputSeparation = aNBT.getBoolean("isBussesSeparate"); + } + } + + @Override + public boolean supportsVoidProtection() { + return true; + } + + @Override + public boolean supportsInputSeparation() { + return true; + } + + @Override + public boolean supportsBatchMode() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ExtremeDieselEngine.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ExtremeDieselEngine.java new file mode 100644 index 0000000000..dace58a492 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ExtremeDieselEngine.java @@ -0,0 +1,237 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_EXTREME_DIESEL_ENGINE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_EXTREME_DIESEL_ENGINE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_EXTREME_DIESEL_ENGINE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_EXTREME_DIESEL_ENGINE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.maps.FuelBackend; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_ExtremeDieselEngine extends GT_MetaTileEntity_DieselEngine { + + public GT_MetaTileEntity_ExtremeDieselEngine(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_ExtremeDieselEngine(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Combustion Generator") + .addInfo("Controller block for the Extreme Combustion Engine") + .addInfo("Supply high rating fuel and 8000L of Lubricant per hour to run") + .addInfo("Supply 40L/s of Liquid Oxygen to boost output (optional)") + .addInfo("Default: Produces 10900EU/t at 100% fuel efficiency") + .addInfo("Boosted: Produces 32700EU/t at 150% fuel efficiency") + .addInfo("You need to wait for it to reach 300% to output full power") + .addPollutionAmount(getPollutionPerSecond(null)) + .addSeparator() + .beginStructureBlock(3, 3, 4, false) + .addController("Front center") + .addCasingInfoRange("Robust Tungstensteel Machine Casing", 16, 22, false) + .addOtherStructurePart("Titanium Gear Box Machine Casing", "Inner 2 blocks") + .addOtherStructurePart("Extreme Engine Intake Machine Casing", "8x, ring around controller") + .addStructureInfo("Extreme Engine Intake Casings must not be obstructed in front (only air blocks)") + .addDynamoHatch("Back center", 2) + .addMaintenanceHatch("One of the casings next to a Gear Box", 1) + .addMufflerHatch("Top middle back, above the rear Gear Box", 1) + .addInputHatch("HOG, next to a Gear Box", 1) + .addInputHatch("Lubricant, next to a Gear Box", 1) + .addInputHatch("Liquid Oxygen, optional, next to a Gear Box", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public RecipeMap<FuelBackend> getRecipeMap() { + return RecipeMaps.extremeDieselFuels; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { casingTexturePages[0][60], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_EXTREME_DIESEL_ENGINE_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_EXTREME_DIESEL_ENGINE_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { casingTexturePages[0][60], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_EXTREME_DIESEL_ENGINE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_EXTREME_DIESEL_ENGINE_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { casingTexturePages[0][60] }; + } + + @Override + public Block getCasingBlock() { + return GregTech_API.sBlockCasings4; + } + + @Override + public byte getCasingMeta() { + return 0; + } + + @Override + public Block getIntakeBlock() { + return GregTech_API.sBlockCasings8; + } + + @Override + public byte getIntakeMeta() { + return 4; + } + + @Override + public Block getGearboxBlock() { + return GregTech_API.sBlockCasings2; + } + + @Override + public byte getGearboxMeta() { + return 4; + } + + @Override + public byte getCasingTextureIndex() { + return 60; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_ExtremeDieselEngine(this.mName); + } + + @Override + protected int getNominalOutput() { + return 10900; + } + + @Override + protected int getBoostFactor() { + return 2; + } + + @Override + protected Materials getBooster() { + return Materials.LiquidOxygen; + } + + @Override + protected int getAdditiveFactor() { + return 1; + } + + @Override + protected int getEfficiencyIncrease() { + return 20; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return boostEu ? 30000 : 10000; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + return GT_Mod.gregtechproxy.mPollutionExtremeCombustionEnginePerSecond; + } + + @Override + public String[] getInfoData() { + int mPollutionReduction = 0; + for (GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) { + mPollutionReduction = Math.max(tHatch.calculatePollutionReduction(100), mPollutionReduction); + } + + long storedEnergy = 0; + long maxEnergy = 0; + for (GT_MetaTileEntity_Hatch_Dynamo tHatch : filterValidMTEs(mDynamoHatches)) { + storedEnergy += tHatch.getBaseMetaTileEntity() + .getStoredEU(); + maxEnergy += tHatch.getBaseMetaTileEntity() + .getEUCapacity(); + } + + return new String[] { EnumChatFormatting.BLUE + "Extreme Diesel Engine" + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(storedEnergy) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxEnergy) + + EnumChatFormatting.RESET + + " EU", + getIdealStatus() == getRepairStatus() + ? EnumChatFormatting.GREEN + StatCollector.translateToLocal("GT5U.turbine.maintenance.false") + + EnumChatFormatting.RESET + : EnumChatFormatting.RED + StatCollector.translateToLocal("GT5U.turbine.maintenance.true") + + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.engine.output") + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers((long) -mEUt * mEfficiency / 10000) + + EnumChatFormatting.RESET + + " EU/t", + StatCollector.translateToLocal("GT5U.engine.consumption") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(fuelConsumption) + + EnumChatFormatting.RESET + + " L/t", + StatCollector.translateToLocal("GT5U.engine.value") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(fuelValue) + + EnumChatFormatting.RESET + + " EU/L", + StatCollector.translateToLocal("GT5U.turbine.fuel") + ": " + + EnumChatFormatting.GOLD + + GT_Utility.formatNumbers(fuelRemaining) + + EnumChatFormatting.RESET + + " L", + StatCollector.translateToLocal("GT5U.engine.efficiency") + ": " + + EnumChatFormatting.YELLOW + + (mEfficiency / 100F) + + EnumChatFormatting.YELLOW + + " %", + StatCollector.translateToLocal("GT5U.multiblock.pollution") + ": " + + EnumChatFormatting.GREEN + + mPollutionReduction + + EnumChatFormatting.RESET + + " %" }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer.java new file mode 100644 index 0000000000..493546211c --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer.java @@ -0,0 +1,656 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASING_FUSION_GLASS; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASING_FUSION_GLASS_YELLOW; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASING_FUSION_GLASS_YELLOW_GLOW; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.filterByMTETier; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.Set; + +import javax.annotation.Nonnull; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableMap; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizons.modularui.api.NumberFormatMUI; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.ProgressBar; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import gregtech.GT_Mod; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.Textures; +import gregtech.api.enums.VoidingMode; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.gui.modularui.GUITextureSet; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.IOverclockDescriptionProvider; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; +import gregtech.api.objects.GT_ItemStack; +import gregtech.api.objects.overclockdescriber.FusionOverclockDescriber; +import gregtech.api.objects.overclockdescriber.OverclockDescriber; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_ParallelHelper; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.shutdown.ShutDownReason; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; + +public abstract class GT_MetaTileEntity_FusionComputer + extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_FusionComputer> + implements ISurvivalConstructable, IAddUIWidgets, IOverclockDescriptionProvider { + + private final OverclockDescriber overclockDescriber; + + public static final String STRUCTURE_PIECE_MAIN = "main"; + private static final ClassValue<IStructureDefinition<GT_MetaTileEntity_FusionComputer>> STRUCTURE_DEFINITION = new ClassValue<>() { + + @Override + protected IStructureDefinition<GT_MetaTileEntity_FusionComputer> computeValue(Class<?> type) { + return StructureDefinition.<GT_MetaTileEntity_FusionComputer>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose( + new String[][] { + { " ", " ihi ", " hh hh ", " h h ", + " h h ", " h h ", " i i ", " h h ", + " i i ", " h h ", " h h ", " h h ", + " hh hh ", " ihi ", " ", }, + { " xhx ", " hhccchh ", " eccxhxcce ", " eceh hece ", + " hce ech ", " hch hch ", "xcx xcx", "hch hch", + "xcx xcx", " hch hch ", " hce ech ", " eceh hece ", + " eccx~xcce ", " hhccchh ", " xhx ", }, + { " ", " ihi ", " hh hh ", " h h ", + " h h ", " h h ", " i i ", " h h ", + " i i ", " h h ", " h h ", " h h ", + " hh hh ", " ihi ", " ", } })) + .addElement('c', lazy(t -> ofBlock(t.getFusionCoil(), t.getFusionCoilMeta()))) + .addElement('h', lazy(t -> ofBlock(t.getCasing(), t.getCasingMeta()))) + .addElement( + 'i', + lazy( + t -> buildHatchAdder(GT_MetaTileEntity_FusionComputer.class) + .atLeast( + ImmutableMap.of(InputHatch.withAdder(GT_MetaTileEntity_FusionComputer::addInjector), 2)) + .hatchItemFilterAnd(t2 -> filterByMTETier(t2.tier(), Integer.MAX_VALUE)) + .casingIndex(53) + .dot(1) + .buildAndChain(t.getCasing(), t.getCasingMeta()))) + .addElement( + 'e', + lazy( + t -> buildHatchAdder(GT_MetaTileEntity_FusionComputer.class).atLeast( + ImmutableMap.of(Energy.withAdder(GT_MetaTileEntity_FusionComputer::addEnergyInjector), 16)) + .hatchItemFilterAnd(t2 -> filterByMTETier(t2.tier(), Integer.MAX_VALUE)) + .casingIndex(53) + .dot(2) + .buildAndChain(t.getCasing(), t.getCasingMeta()))) + .addElement( + 'x', + lazy( + t -> buildHatchAdder(GT_MetaTileEntity_FusionComputer.class) + .atLeast(OutputHatch.withAdder(GT_MetaTileEntity_FusionComputer::addExtractor)) + .hatchItemFilterAnd(t2 -> filterByMTETier(t2.tier(), Integer.MAX_VALUE)) + .casingIndex(53) + .dot(3) + .buildAndChain(t.getCasing(), t.getCasingMeta()))) + .build(); + } + }; + public GT_Recipe mLastRecipe; + public long mEUStore; + + static { + Textures.BlockIcons.setCasingTextureForId( + 52, + TextureFactory.of( + TextureFactory.builder() + .addIcon(MACHINE_CASING_FUSION_GLASS_YELLOW) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(MACHINE_CASING_FUSION_GLASS_YELLOW_GLOW) + .extFacing() + .glow() + .build())); + } + + public GT_MetaTileEntity_FusionComputer(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + this.overclockDescriber = createOverclockDescriber(); + } + + public GT_MetaTileEntity_FusionComputer(String aName) { + super(aName); + this.overclockDescriber = createOverclockDescriber(); + } + + protected OverclockDescriber createOverclockDescriber() { + return new FusionOverclockDescriber((byte) tier(), capableStartupCanonical()); + } + + @Nonnull + @Override + public OverclockDescriber getOverclockDescriber() { + return overclockDescriber; + } + + public abstract int tier(); + + @Override + public abstract long maxEUStore(); + + /** + * Unlike {@link #maxEUStore()}, this provides theoretical limit of startup EU, without considering the amount of + * hatches nor the room for extra energy. Intended for simulation. + */ + public abstract long capableStartupCanonical(); + + @Override + public abstract MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity); + + @Override + public boolean allowCoverOnSide(ForgeDirection side, GT_ItemStack aStack) { + + return side != getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (mEUt > 0) { + mEUt = -mEUt; + } + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_FusionComputer> getStructureDefinition() { + return STRUCTURE_DEFINITION.get(getClass()); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addController("Fusion Reactor") + .addInfo("Some kind of fusion reactor, maybe") + .addSeparator() + .addInfo("Some kind of fusion reactor, maybe") + .addStructureInfo("Should probably be built similar to other fusions") + .addStructureInfo("See controller tooltip for details") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + if (checkPiece(STRUCTURE_PIECE_MAIN, 7, 1, 12) && mInputHatches.size() > 1 + && !mOutputHatches.isEmpty() + && !mEnergyHatches.isEmpty()) { + mWrench = true; + mScrewdriver = true; + mSoftHammer = true; + mHardHammer = true; + mSolderingTool = true; + mCrowbar = true; + return true; + } + return false; + } + + private boolean addEnergyInjector(IGregTechTileEntity aBaseMetaTileEntity, int aBaseCasingIndex) { + IMetaTileEntity aMetaTileEntity = aBaseMetaTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (!(aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Energy tHatch)) return false; + if (tHatch.mTier < tier()) return false; + tHatch.updateTexture(aBaseCasingIndex); + return mEnergyHatches.add(tHatch); + } + + private boolean addInjector(IGregTechTileEntity aBaseMetaTileEntity, int aBaseCasingIndex) { + IMetaTileEntity aMetaTileEntity = aBaseMetaTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (!(aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input tHatch)) return false; + if (tHatch.getTierForStructure() < tier()) return false; + tHatch.updateTexture(aBaseCasingIndex); + tHatch.mRecipeMap = getRecipeMap(); + return mInputHatches.add(tHatch); + } + + private boolean addExtractor(IGregTechTileEntity aBaseMetaTileEntity, int aBaseCasingIndex) { + if (aBaseMetaTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aBaseMetaTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (!(aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output tHatch)) return false; + if (tHatch.getTierForStructure() < tier()) return false; + tHatch.updateTexture(aBaseCasingIndex); + return mOutputHatches.add(tHatch); + } + + public abstract Block getCasing(); + + public abstract int getCasingMeta(); + + public abstract Block getFusionCoil(); + + public abstract int getFusionCoilMeta(); + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) return new ITexture[] { TextureFactory.builder() + .addIcon(MACHINE_CASING_FUSION_GLASS) + .extFacing() + .build(), getTextureOverlay() }; + if (aActive) return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(52) }; + return new ITexture[] { TextureFactory.builder() + .addIcon(MACHINE_CASING_FUSION_GLASS) + .extFacing() + .build() }; + } + + /** + * @return The list of textures overlay + */ + public abstract ITexture getTextureOverlay(); + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.fusionRecipes; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @NotNull + @Override + protected GT_ParallelHelper createParallelHelper(@NotNull GT_Recipe recipe) { + // When the fusion first loads and is still processing, it does the recipe check without consuming. + return super.createParallelHelper(recipe).setConsumption(!mRunningOnLoad); + } + + @NotNull + @Override + protected GT_OverclockCalculator createOverclockCalculator(@NotNull GT_Recipe recipe) { + return overclockDescriber.createCalculator(super.createOverclockCalculator(recipe), recipe); + } + + @NotNull + @Override + protected CheckRecipeResult validateRecipe(@NotNull GT_Recipe recipe) { + if (!mRunningOnLoad && recipe.mSpecialValue > maxEUStore()) { + return CheckRecipeResultRegistry.insufficientStartupPower(recipe.mSpecialValue); + } + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + @NotNull + @Override + public CheckRecipeResult process() { + CheckRecipeResult result = super.process(); + if (mRunningOnLoad) mRunningOnLoad = false; + turnCasingActive(result.wasSuccessful()); + if (result.wasSuccessful()) { + mLastRecipe = lastRecipe; + } else { + mLastRecipe = null; + } + return result; + } + }; + } + + @Override + protected void setProcessingLogicPower(ProcessingLogic logic) { + logic.setAvailableVoltage(GT_Values.V[tier()]); + logic.setAvailableAmperage(1); + logic.setAmperageOC(false); + } + + public boolean turnCasingActive(boolean status) { + if (this.mEnergyHatches != null) { + for (GT_MetaTileEntity_Hatch_Energy hatch : this.mEnergyHatches) { + hatch.updateTexture(status ? 52 : 53); + } + } + if (this.mOutputHatches != null) { + for (GT_MetaTileEntity_Hatch_Output hatch : this.mOutputHatches) { + hatch.updateTexture(status ? 52 : 53); + } + } + if (this.mInputHatches != null) { + for (GT_MetaTileEntity_Hatch_Input hatch : this.mInputHatches) { + hatch.updateTexture(status ? 52 : 53); + } + } + return true; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + if (mEfficiency < 0) mEfficiency = 0; + if (mRunningOnLoad && checkMachine(aBaseMetaTileEntity, mInventory[1])) { + this.mEUStore = aBaseMetaTileEntity.getStoredEU(); + checkRecipe(); + } + if (mUpdated) { + mUpdate = 50; + mUpdated = false; + } + if (--mUpdate == 0 || --mStartUpCheck == 0) { + checkStructure(true, aBaseMetaTileEntity); + } + if (mStartUpCheck < 0) { + if (mMachine) { + this.mEUStore = aBaseMetaTileEntity.getStoredEU(); + if (this.mEnergyHatches != null) { + for (GT_MetaTileEntity_Hatch_Energy tHatch : filterValidMTEs(mEnergyHatches)) { + long energyToMove = GT_Values.V[tier()] / 16; + if (aBaseMetaTileEntity.getStoredEU() + energyToMove < maxEUStore() + && tHatch.getBaseMetaTileEntity() + .decreaseStoredEnergyUnits(energyToMove, false)) { + aBaseMetaTileEntity.increaseStoredEnergyUnits(energyToMove, true); + } + } + } + if (this.mEUStore <= 0 && mMaxProgresstime > 0) { + stopMachine(ShutDownReasonRegistry.POWER_LOSS); + } + if (mMaxProgresstime > 0) { + this.getBaseMetaTileEntity() + .decreaseStoredEnergyUnits(-mEUt, true); + if (mMaxProgresstime > 0 && ++mProgresstime >= mMaxProgresstime) { + if (mOutputItems != null) + for (ItemStack tStack : mOutputItems) if (tStack != null) addOutput(tStack); + if (mOutputFluids != null) + for (FluidStack tStack : mOutputFluids) if (tStack != null) addOutput(tStack); + mEfficiency = Math + .max(0, Math.min(mEfficiency + mEfficiencyIncrease, getMaxEfficiency(mInventory[1]))); + mOutputItems = null; + mProgresstime = 0; + mMaxProgresstime = 0; + mEfficiencyIncrease = 0; + if (mOutputFluids != null && mOutputFluids.length > 0) { + try { + GT_Mod.achievements.issueAchivementHatchFluid( + aBaseMetaTileEntity.getWorld() + .getPlayerEntityByName(aBaseMetaTileEntity.getOwnerName()), + mOutputFluids[0]); + } catch (Exception ignored) {} + } + this.mEUStore = aBaseMetaTileEntity.getStoredEU(); + if (aBaseMetaTileEntity.isAllowedToWork()) checkRecipe(); + } + } else { + if (aTick % 100 == 0 || aBaseMetaTileEntity.hasWorkJustBeenEnabled() + || aBaseMetaTileEntity.hasInventoryBeenModified()) { + turnCasingActive(mMaxProgresstime > 0); + if (aBaseMetaTileEntity.isAllowedToWork()) { + this.mEUStore = aBaseMetaTileEntity.getStoredEU(); + if (checkRecipe()) { + if (this.mEUStore < this.mLastRecipe.mSpecialValue + this.mEUt) { + stopMachine(ShutDownReasonRegistry.POWER_LOSS); + } + aBaseMetaTileEntity + .decreaseStoredEnergyUnits(this.mLastRecipe.mSpecialValue + this.mEUt, true); + } + } + if (mMaxProgresstime <= 0) mEfficiency = Math.max(0, mEfficiency - 1000); + } + } + } else if (aBaseMetaTileEntity.isAllowedToWork()) { + this.mLastRecipe = null; + stopMachine(ShutDownReasonRegistry.STRUCTURE_INCOMPLETE); + } + } + aBaseMetaTileEntity + .setErrorDisplayID((aBaseMetaTileEntity.getErrorDisplayID() & ~127) | (mMachine ? 0 : 64)); + aBaseMetaTileEntity.setActive(mMaxProgresstime > 0); + } + } + + @Override + public boolean drainEnergyInput(long aEU) { + return false; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public void stopMachine(@NotNull ShutDownReason reason) { + super.stopMachine(reason); + turnCasingActive(false); + } + + @Override + public String[] getInfoData() { + String tier = tier() == 6 ? EnumChatFormatting.RED + "I" + EnumChatFormatting.RESET + : tier() == 7 ? EnumChatFormatting.YELLOW + "II" + EnumChatFormatting.RESET + : tier() == 8 ? EnumChatFormatting.GRAY + "III" + EnumChatFormatting.RESET : "IV"; + float plasmaOut = 0; + int powerRequired = 0; + if (this.mLastRecipe != null) { + powerRequired = this.mLastRecipe.mEUt; + if (this.mLastRecipe.getFluidOutput(0) != null) { + plasmaOut = (float) this.mLastRecipe.getFluidOutput(0).amount / (float) this.mLastRecipe.mDuration; + } + } + + return new String[] { EnumChatFormatting.BLUE + "Fusion Reactor MK " + EnumChatFormatting.RESET + tier, + StatCollector.translateToLocal("GT5U.fusion.req") + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(powerRequired) + + EnumChatFormatting.RESET + + "EU/t", + StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mEUStore) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxEUStore()) + + EnumChatFormatting.RESET + + " EU", + StatCollector.translateToLocal("GT5U.fusion.plasma") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(plasmaOut) + + EnumChatFormatting.RESET + + "L/t" }; + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 7, 1, 12); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 7, 1, 12, elementBudget, env, false, true); + } + + @Override + protected SoundResource getProcessStartSound() { + return SoundResource.GT_MACHINES_FUSION_LOOP; + } + + @Override + public boolean doesBindPlayerInventory() { + return false; + } + + @Override + public void addGregTechLogo(ModularWindow.Builder builder) { + builder.widget( + new DrawableWidget().setDrawable(getGUITextureSet().getGregTechLogo()) + .setSize(17, 17) + .setPos(155, 145)); + } + + @Override + public GUITextureSet getGUITextureSet() { + return new GUITextureSet().setMainBackground(GT_UITextures.BACKGROUND_FUSION_COMPUTER); + } + + @Override + public int getGUIWidth() { + return 176; + } + + @Override + public int getGUIHeight() { + return 166; + } + + protected static final NumberFormatMUI numberFormat = new NumberFormatMUI(); + protected long clientEU; + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + builder + .widget( + new TextWidget(GT_Utility.trans("138", "Incomplete Structure.")).setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> !mMachine) + .setPos(10, 8)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> mMachine, val -> mMachine = val)) + .widget( + new TextWidget("Hit with Soft Mallet to (re-)start the Machine if it doesn't start.") + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setTextAlignment(Alignment.Center) + .setEnabled( + widget -> getBaseMetaTileEntity().getErrorDisplayID() == 0 + && !getBaseMetaTileEntity().isActive()) + .setPos(-getGUIWidth() / 2, 170) + .setSize(getGUIWidth() * 2, 9)) + .widget( + new FakeSyncWidget.IntegerSyncer( + () -> getBaseMetaTileEntity().getErrorDisplayID(), + val -> getBaseMetaTileEntity().setErrorDisplayID(val))) + .widget( + new FakeSyncWidget.BooleanSyncer( + () -> getBaseMetaTileEntity().isActive(), + val -> getBaseMetaTileEntity().setActive(val))) + .widget( + new TextWidget("Running perfectly.").setDefaultColor(COLOR_TEXT_WHITE.get()) + .setTextAlignment(Alignment.Center) + .setEnabled( + widget -> getBaseMetaTileEntity().getErrorDisplayID() == 0 + && getBaseMetaTileEntity().isActive()) + .setPos(0, 170) + .setSize(getGUIWidth(), 9)) + .widget( + new FakeSyncWidget.IntegerSyncer( + () -> getBaseMetaTileEntity().getErrorDisplayID(), + val -> getBaseMetaTileEntity().setErrorDisplayID(val))) + .widget( + new ProgressBar() + .setProgress( + () -> (float) getBaseMetaTileEntity().getStoredEU() / getBaseMetaTileEntity().getEUCapacity()) + .setDirection(ProgressBar.Direction.RIGHT) + .setTexture(GT_UITextures.PROGRESSBAR_STORED_EU, 147) + .setPos(5, 156) + .setSize(147, 5)) + .widget(new TextWidget().setStringSupplier(() -> { + if (clientEU > 160_000_000L && clientEU < 160_010_000L) { + clientEU = 160_000_000L; + } + if (clientEU > 320_000_000L && clientEU < 320_010_000L) { + clientEU = 320_000_000L; + } + if (clientEU > 640_000_000L && clientEU < 640_010_000L) { + clientEU = 640_000_000L; + } + if (clientEU > 5_120_000_000L && clientEU < 5_120_080_000L) { + clientEU = 5_120_000_000L; + } + return numberFormat.format(clientEU) + " EU"; + }) + .setDefaultColor(COLOR_TEXT_RED.get()) + .setTextAlignment(Alignment.Center) + .setScale(0.5f) + .setPos(5, 157) + .setSize(147, 5)) + .widget(new FakeSyncWidget.LongSyncer(() -> getBaseMetaTileEntity().getStoredEU(), val -> clientEU = val)) + .widget( + new ButtonWidget().setNEITransferRect( + RecipeMaps.fusionRecipes.getFrontend() + .getUIProperties().neiTransferRectId) + .setBackground(GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_NEI) + .setPos(154, 4) + .setSize(18, 18)); + } + + @Override + public boolean supportsVoidProtection() { + return true; + } + + @Override + public Set<VoidingMode> getAllowedVoidingModes() { + return VoidingMode.FLUID_ONLY_MODES; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer1.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer1.java new file mode 100644 index 0000000000..e3a2432bf9 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer1.java @@ -0,0 +1,103 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FUSION1; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FUSION1_GLOW; + +import net.minecraft.block.Block; + +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_FusionComputer1 extends GT_MetaTileEntity_FusionComputer { + + private static final ITexture textureOverlay = TextureFactory.of( + TextureFactory.builder() + .addIcon(OVERLAY_FUSION1) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FUSION1_GLOW) + .extFacing() + .glow() + .build()); + + public GT_MetaTileEntity_FusionComputer1(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_FusionComputer1(String aName) { + super(aName); + } + + @Override + public int tier() { + return 6; + } + + @Override + public long maxEUStore() { + return 160003000L * (Math.min(16, this.mEnergyHatches.size())) / 16L; + } + + @Override + public long capableStartupCanonical() { + return 160_000_000; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_FusionComputer1(mName); + } + + @Override + public Block getCasing() { + return GregTech_API.sBlockCasings1; + } + + @Override + public int getCasingMeta() { + return 6; + } + + @Override + public Block getFusionCoil() { + return GregTech_API.sBlockCasings1; + } + + @Override + public int getFusionCoilMeta() { + return 15; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Fusion Reactor") + .addInfo("It's over 9000!!!") + .addInfo("Controller block for the Fusion Reactor Mk I") + .addInfo("2048EU/t and 10M EU capacity per Energy Hatch") + .addInfo("If the recipe has a startup cost greater than the") + .addInfo("number of energy hatches * cap, you can't do it") + .addSeparator() + .beginStructureBlock(15, 3, 15, false) + .addController("See diagram when placed") + .addCasingInfoRange("LuV Machine Casing", 79, 123, false) + .addStructureInfo("Cover the coils with casing") + .addOtherStructurePart("Superconducting Coil Block", "Center part of the ring") + .addEnergyHatch("1-16, Specified casings", 2) + .addInputHatch("2-16, Specified casings", 1) + .addOutputHatch("1-16, Specified casings", 3) + .addStructureInfo("ALL Hatches must be LuV or better") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture getTextureOverlay() { + return textureOverlay; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer2.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer2.java new file mode 100644 index 0000000000..0b1f10158b --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer2.java @@ -0,0 +1,103 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FUSION2; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FUSION2_GLOW; + +import net.minecraft.block.Block; + +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_FusionComputer2 extends GT_MetaTileEntity_FusionComputer { + + private static final ITexture textureOverlay = TextureFactory.of( + TextureFactory.builder() + .addIcon(OVERLAY_FUSION2) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FUSION2_GLOW) + .extFacing() + .glow() + .build()); + + public GT_MetaTileEntity_FusionComputer2(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_FusionComputer2(String aName) { + super(aName); + } + + @Override + public int tier() { + return 7; + } + + @Override + public long maxEUStore() { + return 320006000L * (Math.min(16, this.mEnergyHatches.size())) / 16L; + } + + @Override + public long capableStartupCanonical() { + return 320_000_000; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_FusionComputer2(mName); + } + + @Override + public Block getCasing() { + return GregTech_API.sBlockCasings4; + } + + @Override + public int getCasingMeta() { + return 6; + } + + @Override + public Block getFusionCoil() { + return GregTech_API.sBlockCasings4; + } + + @Override + public int getFusionCoilMeta() { + return 7; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Fusion Reactor") + .addInfo("It's over 9000!!!") + .addInfo("Controller block for the Fusion Reactor Mk II") + .addInfo("8192EU/t and 20M EU capacity per Energy Hatch") + .addInfo("If the recipe has a startup cost greater than the") + .addInfo("number of energy hatches * cap, you can't do it") + .addSeparator() + .beginStructureBlock(15, 3, 15, false) + .addController("See diagram when placed") + .addCasingInfoRange("Fusion Machine Casing", 79, 123, false) + .addStructureInfo("Cover the coils with casing") + .addOtherStructurePart("Fusion Coil Block", "Center part of the ring") + .addEnergyHatch("1-16, Specified casings", 2) + .addInputHatch("2-16, Specified casings", 1) + .addOutputHatch("1-16, Specified casings", 3) + .addStructureInfo("ALL Hatches must be ZPM or better") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture getTextureOverlay() { + return textureOverlay; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer3.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer3.java new file mode 100644 index 0000000000..64d92ccc99 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_FusionComputer3.java @@ -0,0 +1,103 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FUSION3; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FUSION3_GLOW; + +import net.minecraft.block.Block; + +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_FusionComputer3 extends GT_MetaTileEntity_FusionComputer { + + private static final ITexture textureOverlay = TextureFactory.of( + TextureFactory.builder() + .addIcon(OVERLAY_FUSION3) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FUSION3_GLOW) + .extFacing() + .glow() + .build()); + + public GT_MetaTileEntity_FusionComputer3(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_FusionComputer3(String aName) { + super(aName); + } + + @Override + public int tier() { + return 8; + } + + @Override + public long maxEUStore() { + return 640010000L * (Math.min(16, this.mEnergyHatches.size())) / 16L; + } + + @Override + public long capableStartupCanonical() { + return 640_000_000; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_FusionComputer3(mName); + } + + @Override + public Block getCasing() { + return GregTech_API.sBlockCasings4; + } + + @Override + public int getCasingMeta() { + return 8; + } + + @Override + public Block getFusionCoil() { + return GregTech_API.sBlockCasings4; + } + + @Override + public int getFusionCoilMeta() { + return 7; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Fusion Reactor") + .addInfo("A SUN DOWN ON EARTH") + .addInfo("Controller block for the Fusion Reactor Mk III") + .addInfo("32768EU/t and 40M EU capacity per Energy Hatch") + .addInfo("If the recipe has a startup cost greater than the") + .addInfo("number of energy hatches * cap, you can't do it") + .addSeparator() + .beginStructureBlock(15, 3, 15, false) + .addController("See diagram when placed") + .addCasingInfoRange("Fusion Machine Casing Mk II", 79, 123, false) + .addStructureInfo("Cover the coils with casing") + .addOtherStructurePart("Fusion Coil Block", "Center part of the ring") + .addEnergyHatch("1-16, Specified casings", 2) + .addInputHatch("2-16, Specified casings", 1) + .addOutputHatch("1-16, Specified casings", 3) + .addStructureInfo("ALL Hatches must be UV or better") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture getTextureOverlay() { + return textureOverlay; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_HeatExchanger.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_HeatExchanger.java new file mode 100644 index 0000000000..70e8079b5b --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_HeatExchanger.java @@ -0,0 +1,416 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_HEAT_EXCHANGER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_HEAT_EXCHANGER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_HEAT_EXCHANGER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_HEAT_EXCHANGER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.GT_Values; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_HeatExchanger extends + GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_HeatExchanger> implements ISurvivalConstructable { + + private int dryHeatCounter = 0; // Counts up to dryHeatMaximum to check for explosion conditions + private static final int dryHeatMaximum = 2000; // 2000 ticks = 100 seconds + private static final int CASING_INDEX = 50; + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final IStructureDefinition<GT_MetaTileEntity_HeatExchanger> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_HeatExchanger>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose( + new String[][] { { "ccc", "cCc", "ccc" }, { "ccc", "cPc", "ccc" }, { "ccc", "cPc", "ccc" }, + { "c~c", "cHc", "ccc" }, })) + .addElement('P', ofBlock(GregTech_API.sBlockCasings2, 14)) + .addElement( + 'C', + OutputHatch.withAdder(GT_MetaTileEntity_HeatExchanger::addColdFluidOutputToMachineList) + .withCount(t -> t.mOutputColdFluidHatch.isValid() ? 1 : 0) + .newAny(CASING_INDEX, 3)) + .addElement( + 'H', + InputHatch.withAdder(GT_MetaTileEntity_HeatExchanger::addHotFluidInputToMachineList) + .withCount(t -> t.mInputHotFluidHatch.isValid() ? 1 : 0) + .newAny(CASING_INDEX, 3)) + .addElement( + 'c', + buildHatchAdder(GT_MetaTileEntity_HeatExchanger.class) + .atLeast(InputBus, InputHatch, OutputBus, OutputHatch, Maintenance) + .casingIndex(CASING_INDEX) + .dot(1) + .buildAndChain( + onElementPass( + GT_MetaTileEntity_HeatExchanger::onCasingAdded, + ofBlock(GregTech_API.sBlockCasings4, (byte) 2)))) + .build(); + public static float penalty_per_config = 0.015f; // penalize 1.5% efficiency per circuitry level (1-25) + + private GT_MetaTileEntity_Hatch_Input mInputHotFluidHatch; + private GT_MetaTileEntity_Hatch_Output mOutputColdFluidHatch; + private boolean superheated = false; + private int superheated_threshold = 0; + /** + * How much more steam we can make without draining real water. Unit is (1L/GT_Values.STEAM_PER_WATER) + */ + private int steamBudget; + + private int mCasingAmount; + + public GT_MetaTileEntity_HeatExchanger(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_HeatExchanger(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Heat Exchanger") + .addInfo("Controller Block for the Large Heat Exchanger") + .addInfo("More complicated than a Fusion Reactor. Seriously") + .addInfo("Inputs are Hot Coolant or Lava") + .addInfo("Outputs Coolant or Pahoehoe Lava and SH Steam/Steam") + .addInfo("Read the wiki article to understand how it works") + .addInfo("Then go to the Discord to understand the wiki") + .addSeparator() + .beginStructureBlock(3, 4, 3, false) + .addController("Front bottom") + .addCasingInfoRange("Stable Titanium Machine Casing", 20, 32, false) + .addOtherStructurePart("Titanium Pipe Casing", "Center 2 blocks") + .addMaintenanceHatch("Any casing", 1) + .addInputHatch("Hot fluid, bottom center", 2) + .addInputHatch("Distilled water, any casing", 1) + .addOutputHatch("Cold fluid, top center", 3) + .addOutputHatch("Steam/SH Steam, any casing", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + superheated = aNBT.getBoolean("superheated"); + steamBudget = aNBT.getInteger("steamBudget"); + super.loadNBTData(aNBT); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + aNBT.setBoolean("superheated", superheated); + aNBT.setInteger("steamBudget", steamBudget); + super.saveNBTData(aNBT); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { casingTexturePages[0][CASING_INDEX], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_HEAT_EXCHANGER_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_HEAT_EXCHANGER_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { casingTexturePages[0][CASING_INDEX], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_HEAT_EXCHANGER) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_HEAT_EXCHANGER_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { casingTexturePages[0][CASING_INDEX] }; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + protected IAlignmentLimits getInitialAlignmentLimits() { + return (d, r, f) -> !r.isUpsideDown() && !f.isVerticallyFliped(); + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + if (mInputHotFluidHatch.getFluid() == null) return CheckRecipeResultRegistry.NO_RECIPE; + + int fluidAmountToConsume = mInputHotFluidHatch.getFluidAmount(); // how much fluid is in hatch + + superheated_threshold = 4000; // default: must have 4000L per second to generate superheated steam + float efficiency = 1f; // default: operate at 100% efficiency with no integrated circuitry + int shs_reduction_per_config = 150; // reduce threshold 150L/s per circuitry level (1-25) + float steam_output_multiplier = 20f; // default: multiply output by 4 * 10 (boosted x5) + float penalty = 0.0f; // penalty to apply to output based on circuitry level (1-25). + boolean do_lava = false; + boolean do_coolant = false; + boolean do_solarSalt = false; + + // Do we have an integrated circuit with a valid configuration? + if (mInventory[1] != null && mInventory[1].getUnlocalizedName() + .startsWith("gt.integrated_circuit")) { + int circuit_config = mInventory[1].getItemDamage(); + if (circuit_config >= 1 && circuit_config <= 25) { + // If so, apply the penalty and reduce the threshold. + penalty = (circuit_config - 1) * penalty_per_config; + superheated_threshold -= (shs_reduction_per_config * (circuit_config - 1)); + } + } + efficiency -= penalty; + + // If we're working with lava, adjust the threshold and multipliers accordingly. + if (GT_ModHandler.isLava(mInputHotFluidHatch.getFluid())) { + steam_output_multiplier /= 5f; // lava is not boosted + superheated_threshold /= 4f; // unchanged + do_lava = true; + } else if (mInputHotFluidHatch.getFluid() + .isFluidEqual(FluidRegistry.getFluidStack("ic2hotcoolant", 1))) { + steam_output_multiplier /= 2f; // was boosted x2 on top of x5 -> total x10 -> + // nerf with this code back to 5x + superheated_threshold /= 5f; // 10x smaller since the Hot Things production in + // reactor is the same. + do_coolant = true; + } else if (mInputHotFluidHatch.getFluid() + .isFluidEqual(FluidRegistry.getFluidStack("molten.solarsalthot", 1))) { + steam_output_multiplier *= 2.5f; // Solar Salt:Steam value is 5x higher than Hot + // Coolant's value + superheated_threshold /= 25f; // Given that, multiplier is 5x higher and + // threshold is 5x lower + do_solarSalt = true; + } else { + // If we're working with neither, fail out + superheated_threshold = 0; + return CheckRecipeResultRegistry.NO_RECIPE; + } + + superheated = fluidAmountToConsume >= superheated_threshold; // set the internal superheated flag if we have + // enough hot fluid. Used in the + // onRunningTick method. + fluidAmountToConsume = Math.min(fluidAmountToConsume, superheated_threshold * 2); // Don't consume too much hot + // fluid per second + mInputHotFluidHatch.drain(fluidAmountToConsume, true); + this.mMaxProgresstime = 20; + this.mEUt = (int) (fluidAmountToConsume * steam_output_multiplier * efficiency); + if (do_lava) { + mOutputColdFluidHatch.fill(FluidRegistry.getFluidStack("ic2pahoehoelava", fluidAmountToConsume), true); + } else if (do_coolant) { + mOutputColdFluidHatch.fill(FluidRegistry.getFluidStack("ic2coolant", fluidAmountToConsume), true); + } else { + mOutputColdFluidHatch.fill(FluidRegistry.getFluidStack("molten.solarsaltcold", fluidAmountToConsume), true); + } + this.mEfficiencyIncrease = 80; + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + private int useWater(int steam) { + steamBudget -= steam; + int usage = -Math.min(0, Math.floorDiv(steamBudget, GT_Values.STEAM_PER_WATER)); + // still subtract, because usage will be a negative number + steamBudget += usage * GT_Values.STEAM_PER_WATER; + return usage; + } + + @Override + public boolean onRunningTick(ItemStack aStack) { + if (this.mEUt > 0) { + int tGeneratedEU = (int) (this.mEUt * 2L * this.mEfficiency / 10000L); // APPROXIMATELY how much steam to + // generate. + if (tGeneratedEU > 0) { + + if (superheated) tGeneratedEU /= 2; // We produce half as much superheated steam if necessary + + int distilledConsumed = useWater(tGeneratedEU); // how much distilled water to consume + // tGeneratedEU = distilledConsumed * 160; // EXACTLY how much steam to generate, producing a perfect + // 1:160 ratio with distilled water consumption + + FluidStack distilledStack = GT_ModHandler.getDistilledWater(distilledConsumed); + startRecipeProcessing(); + if (depleteInput(distilledStack)) // Consume the distilled water + { + if (superheated) { + addOutput(FluidRegistry.getFluidStack("ic2superheatedsteam", tGeneratedEU)); // Generate + // superheated + // steam + } else { + addOutput(GT_ModHandler.getSteam(tGeneratedEU)); // Generate regular steam + } + dryHeatCounter = 0; + } else { + if (dryHeatCounter < dryHeatMaximum) { + dryHeatCounter += 1; + } else { + GT_Log.exp.println(this.mName + " was too hot and had no more Distilled Water!"); + explodeMultiblock(); // Generate crater + } + } + endRecipeProcessing(); + } + return true; + } + return true; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_HeatExchanger> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + private void onCasingAdded() { + mCasingAmount++; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + mOutputColdFluidHatch = null; + mInputHotFluidHatch = null; + mCasingAmount = 0; + return checkPiece(STRUCTURE_PIECE_MAIN, 1, 3, 0) && mCasingAmount >= 20 && mMaintenanceHatches.size() == 1; + } + + public boolean addColdFluidOutputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output) { + ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); + mOutputColdFluidHatch = (GT_MetaTileEntity_Hatch_Output) aMetaTileEntity; + return true; + } + return false; + } + + public boolean addHotFluidInputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) { + ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); + ((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity).mRecipeMap = getRecipeMap(); + mInputHotFluidHatch = (GT_MetaTileEntity_Hatch_Input) aMetaTileEntity; + return true; + } + return false; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_HeatExchanger(this.mName); + } + + @Override + public String[] getInfoData() { + return new String[] { + StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mProgresstime / 20) + + EnumChatFormatting.RESET + + " s / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mMaxProgresstime / 20) + + EnumChatFormatting.RESET + + " s", + StatCollector.translateToLocal("GT5U.multiblock.usage") + " " + + StatCollector.translateToLocal("GT5U.LHE.steam") + + ": " + + (superheated ? EnumChatFormatting.RED : EnumChatFormatting.YELLOW) + + GT_Utility.formatNumbers(superheated ? -2L * mEUt : -mEUt) + + EnumChatFormatting.RESET + + " EU/t", + StatCollector.translateToLocal("GT5U.multiblock.problems") + ": " + + EnumChatFormatting.RED + + (getIdealStatus() - getRepairStatus()) + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.multiblock.efficiency") + + ": " + + EnumChatFormatting.YELLOW + + mEfficiency / 100.0F + + EnumChatFormatting.RESET + + " %", + StatCollector.translateToLocal("GT5U.LHE.superheated") + ": " + + (superheated ? EnumChatFormatting.RED : EnumChatFormatting.BLUE) + + superheated + + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.LHE.superheated") + " " + + StatCollector.translateToLocal("GT5U.LHE.threshold") + + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(superheated_threshold) + + EnumChatFormatting.RESET }; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 1, 3, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 1, 3, 0, elementBudget, env, false, true); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ImplosionCompressor.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ImplosionCompressor.java new file mode 100644 index 0000000000..a1968b05d4 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ImplosionCompressor.java @@ -0,0 +1,163 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_IMPLOSION_COMPRESSOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_IMPLOSION_COMPRESSOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_IMPLOSION_COMPRESSOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_IMPLOSION_COMPRESSOR_GLOW; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizon.structurelib.structure.IStructureElement; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.Textures; +import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_CubicMultiBlockBase; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_ImplosionCompressor + extends GT_MetaTileEntity_CubicMultiBlockBase<GT_MetaTileEntity_ImplosionCompressor> { + + public GT_MetaTileEntity_ImplosionCompressor(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_ImplosionCompressor(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_ImplosionCompressor(this.mName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Implosion Compressor") + .addInfo("Explosions are fun") + .addInfo("Controller block for the Implosion Compressor") + .addPollutionAmount(getPollutionPerSecond(null)) + .addSeparator() + .beginStructureBlock(3, 3, 3, true) + .addController("Front center") + .addCasingInfoRange("Solid Steel Machine Casing", 16, 24, false) + .addStructureInfo("Casings can be replaced with Explosion Warning Signs") + .addEnergyHatch("Any casing", 1) + .addMaintenanceHatch("Any casing", 1) + .addMufflerHatch("Any casing", 1) + .addInputBus("Any casing", 1) + .addOutputBus("Any casing", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public boolean addToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + return super.addToMachineList(aTileEntity, aBaseCasingIndex) + || addMufflerToMachineList(aTileEntity, aBaseCasingIndex); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { BlockIcons.casingTexturePages[0][16], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_IMPLOSION_COMPRESSOR_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_IMPLOSION_COMPRESSOR_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { BlockIcons.casingTexturePages[0][16], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_IMPLOSION_COMPRESSOR) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_IMPLOSION_COMPRESSOR_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { Textures.BlockIcons.casingTexturePages[0][16] }; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.implosionRecipes; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic(); + } + + @Override + protected int getTimeBetweenProcessSounds() { + return 10; + } + + @Override + protected SoundResource getProcessStartSound() { + return SoundResource.RANDOM_EXPLODE; + } + + @Override + protected IStructureElement<GT_MetaTileEntity_CubicMultiBlockBase<?>> getCasingElement() { + return ofChain(ofBlock(GregTech_API.sBlockCasings2, 0), ofBlock(GregTech_API.sBlockCasings3, 4)); + } + + @Override + protected int getHatchTextureIndex() { + return 16; + } + + @Override + protected int getRequiredCasingCount() { + return 16; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + return GT_Mod.gregtechproxy.mPollutionImplosionCompressorPerSecond; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public boolean supportsVoidProtection() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_IntegratedOreFactory.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_IntegratedOreFactory.java new file mode 100644 index 0000000000..27998e97e1 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_IntegratedOreFactory.java @@ -0,0 +1,785 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.Muffler; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_ARRAY; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_ARRAY_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_ARRAY_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_ARRAY_GLOW; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.ofFrame; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.oredict.OreDictionary; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.Materials; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.multitileentity.multiblock.casing.Glasses; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaTileEntity_IntegratedOreFactory extends + GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_IntegratedOreFactory> implements ISurvivalConstructable { + + private static final int CASING_INDEX1 = 183; + private static final int CASING_INDEX2 = 49; + private static final int MAX_PARA = 1024; + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final IStructureDefinition<GT_MetaTileEntity_IntegratedOreFactory> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_IntegratedOreFactory>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose( + new String[][] { + { " ", " ", " WWW ", " WWW ", " ", " " }, + { " ", " sss ", " sppps", " sppps", " sss ", " " }, + { " ", " sss ", " s s", " s s", " sss ", " " }, + { " ", " sss ", " sppps", " sppps", " sss ", " " }, + { " ", " sss ", " s s", " s s", " sss ", " " }, + { " ", " sss ", " sppps", " sppps", " sss ", " " }, + { "iiiiii ", "iIIIIiisssi", "iIIIIis s", "iIIIIis s", "iIIIIiisssi", "iiiiii " }, + { "iggggi ", "gt t isssi", "g xx sppps", "g xx sppps", "gt t isssi", "iggggi " }, + { "iggggi ", "gt t isssi", "g xx s s", "g xx s s", "gt t isssi", "iggggi " }, + { "iggggi ", "gt t is~si", "g xx spppO", "g xx spppO", "gt t isssi", "iggggi " }, + { "iggggi ", "gt t isssi", "g xx s O", "g xx s O", "gt t isssi", "iggggi " }, + { "EEEEEE ", "EEEEEEEEEEE", "EEEEEEEEEEE", "EEEEEEEEEEE", "EEEEEEEEEEE", "EEEEEE " } })) + .addElement('i', ofBlock(GregTech_API.sBlockCasings8, 7)) + .addElement('s', ofBlock(GregTech_API.sBlockCasings4, 1)) + .addElement('g', Glasses.chainAllGlasses()) + .addElement('x', ofBlock(GregTech_API.sBlockCasings2, 3)) + .addElement('p', ofBlock(GregTech_API.sBlockCasings2, 15)) + .addElement('t', ofFrame(Materials.TungstenSteel)) + .addElement( + 'E', + buildHatchAdder(GT_MetaTileEntity_IntegratedOreFactory.class).atLeast(Energy, Maintenance) + .casingIndex(CASING_INDEX1) + .dot(1) + .buildAndChain(GregTech_API.sBlockCasings8, 7)) + .addElement( + 'I', + buildHatchAdder(GT_MetaTileEntity_IntegratedOreFactory.class).atLeast(InputBus) + .casingIndex(CASING_INDEX1) + .dot(2) + .buildAndChain(GregTech_API.sBlockCasings8, 7)) + .addElement( + 'W', + buildHatchAdder(GT_MetaTileEntity_IntegratedOreFactory.class).atLeast(InputHatch, Muffler) + .casingIndex(CASING_INDEX2) + .dot(3) + .buildAndChain(GregTech_API.sBlockCasings4, 1)) + .addElement( + 'O', + buildHatchAdder(GT_MetaTileEntity_IntegratedOreFactory.class).atLeast(OutputBus, OutputHatch) + .casingIndex(CASING_INDEX2) + .dot(4) + .buildAndChain(GregTech_API.sBlockCasings4, 1)) + .build(); + + private static final HashSet<Integer> isCrushedOre = new HashSet<>(); + private static final HashSet<Integer> isCrushedPureOre = new HashSet<>(); + private static final HashSet<Integer> isPureDust = new HashSet<>(); + private static final HashSet<Integer> isImpureDust = new HashSet<>(); + private static final HashSet<Integer> isThermal = new HashSet<>(); + private static final HashSet<Integer> isOre = new HashSet<>(); + private static boolean isInit = false; + private ItemStack[] sMidProduct; + private int sMode = 0; + private boolean sVoidStone = false; + private int currentParallelism = 0; + + private static void initHash() { + for (String name : OreDictionary.getOreNames()) { + if (name == null || name.isEmpty()) continue; + if (name.startsWith("crushedPurified")) { + for (ItemStack stack : OreDictionary.getOres(name)) { + isCrushedPureOre.add(GT_Utility.stackToInt(stack)); + } + } else if (name.startsWith("crushedCentrifuged")) { + for (ItemStack stack : OreDictionary.getOres(name)) { + isThermal.add(GT_Utility.stackToInt(stack)); + } + } else if (name.startsWith("crushed")) { + for (ItemStack stack : OreDictionary.getOres(name)) { + isCrushedOre.add(GT_Utility.stackToInt(stack)); + } + } else if (name.startsWith("dustImpure")) { + for (ItemStack stack : OreDictionary.getOres(name)) { + isImpureDust.add(GT_Utility.stackToInt(stack)); + } + } else if (name.startsWith("dustPure")) { + for (ItemStack stack : OreDictionary.getOres(name)) { + isPureDust.add(GT_Utility.stackToInt(stack)); + } + } else if (name.startsWith("ore")) { + for (ItemStack stack : OreDictionary.getOres(name)) { + isOre.add(GT_Utility.stackToInt(stack)); + } + } else if (name.startsWith("rawOre")) { + for (ItemStack stack : OreDictionary.getOres(name)) { + isOre.add(GT_Utility.stackToInt(stack)); + } + } + } + } + + public GT_MetaTileEntity_IntegratedOreFactory(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_IntegratedOreFactory(String aName) { + super(aName); + } + + public boolean addFluidInputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) { + ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); + ((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity).mRecipeMap = getRecipeMap(); + return mInputHatches.add((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity); + } else if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Muffler) { + ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); + return mMufflerHatches.add((GT_MetaTileEntity_Hatch_Muffler) aMetaTileEntity); + } + return false; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_IntegratedOreFactory> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Ore Processor") + .addInfo("Controller Block for the Integrated Ore Factory") + .addInfo("It is OP. I mean ore processor.") + .addInfo("Do all ore processing in one step.") + .addInfo("Can process up to 1024 ores at a time.") + .addInfo("Every ore costs 30EU/t, 2L lubricant, 200L distilled water.") + .addInfo("Processing time is dependent on mode.") + .addInfo("Use a screwdriver to switch mode.") + .addInfo("Sneak click with screwdriver to void the stone dust.") + .addSeparator() + .beginStructureBlock(6, 12, 11, false) + .addController("The third layer") + .addStructureInfo("128 Advanced Iridium Plated Machine Casing") + .addStructureInfo("105 Clean Stainless Steel Machine Casing") + .addStructureInfo("48 Reinforced Glass") + .addStructureInfo("30 Tungstensteel Pipe Casing") + .addStructureInfo("16 Tungstensteel Frame Box") + .addStructureInfo("16 Steel Gear Box Casing") + .addEnergyHatch("Any bottom Casing", 1) + .addMaintenanceHatch("Any bottom Casing", 1) + .addInputBus("Input ore/crushed ore", 2) + .addInputHatch("Input lubricant/distilled water/washing chemicals", 3) + .addMufflerHatch("Output Pollution", 3) + .addOutputBus("Output products", 4) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + protected IAlignmentLimits getInitialAlignmentLimits() { + return (d, r, f) -> !r.isUpsideDown() && !f.isVerticallyFliped(); + } + + @Override + public void construct(ItemStack itemStack, boolean b) { + buildPiece(STRUCTURE_PIECE_MAIN, itemStack, b, 8, 9, 1); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 8, 9, 1, elementBudget, env, false, true); + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + private static int getTime(int mode) { + return switch (mode) { + case 0 -> 30 * 20; + case 1 -> 15 * 20; + case 2 -> 10 * 20; + case 3 -> 20 * 20; + case 4 -> 17 * 20; + default -> + // go to hell + 1000000000; + }; + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + if (!isInit) { + initHash(); + isInit = true; + } + + int tCharged = MAX_PARA; + List<ItemStack> tInput = getStoredInputs(); + List<FluidStack> tInputFluid = getStoredFluids(); + + int tLube = 0; + int tWater = 0; + + for (FluidStack fluid : tInputFluid) { + if (fluid != null && fluid.equals(GT_ModHandler.getDistilledWater(1L))) { + tWater += fluid.amount; + } else if (fluid != null && fluid.equals(Materials.Lubricant.getFluid(1L))) { + tLube += fluid.amount; + } + } + + tCharged = Math.min(tCharged, tLube / 2); + tCharged = Math.min(tCharged, tWater / 200); + + List<ItemStack> tOres = new ArrayList<>(); + int tRealUsed = 0; + + for (ItemStack ore : tInput) { + if (tCharged <= 0) break; + int tID = GT_Utility.stackToInt(ore); + if (tID == 0) continue; + if (isPureDust.contains(tID) || isImpureDust.contains(tID) + || isCrushedPureOre.contains(tID) + || isThermal.contains(tID) + || isCrushedOre.contains(tID) + || isOre.contains(tID)) { + if (ore.stackSize <= tCharged) { + tRealUsed += ore.stackSize; + tOres.add(GT_Utility.copy(ore)); + tCharged -= ore.stackSize; + ore.stackSize = 0; + } else { + tRealUsed = tCharged; + tOres.add(GT_Utility.copyAmountUnsafe(tCharged, ore)); + ore.stackSize -= tCharged; + tCharged = 0; + break; + } + } + } + + // for scanner + setCurrentParallelism(tRealUsed); + + if (tRealUsed == 0) { + return CheckRecipeResultRegistry.NO_RECIPE; + } + + depleteInput(GT_ModHandler.getDistilledWater(tRealUsed * 200L)); + depleteInput(Materials.Lubricant.getFluid(tRealUsed * 2L)); + + sMidProduct = tOres.toArray(new ItemStack[0]); + + switch (sMode) { + case 0 -> { + doMac(isOre); + doWash(isCrushedOre); + doThermal(isCrushedPureOre, isCrushedOre); + doMac(isThermal, isOre, isCrushedOre, isCrushedPureOre); + } + case 1 -> { + doMac(isOre); + doWash(isCrushedOre); + doMac(isOre, isCrushedOre, isCrushedPureOre); + doCentrifuge(isImpureDust, isPureDust); + } + case 2 -> { + doMac(isOre); + doMac(isThermal, isOre, isCrushedOre, isCrushedPureOre); + doCentrifuge(isImpureDust, isPureDust); + } + case 3 -> { + doMac(isOre); + doWash(isCrushedOre); + doSift(isCrushedPureOre); + } + case 4 -> { + doMac(isOre); + doChemWash(isCrushedOre, isCrushedPureOre); + doMac(isCrushedOre, isCrushedPureOre); + doCentrifuge(isImpureDust, isPureDust); + } + default -> { + return CheckRecipeResultRegistry.NO_RECIPE; + } + } + + this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); + this.mEfficiencyIncrease = 10000; + this.mOutputItems = sMidProduct; + calculateOverclockedNessMultiInternal(30L * tRealUsed, getTime(sMode), 1, getMaxInputVoltage(), false); + if (this.mEUt > 0) { + this.mEUt = -this.mEUt; + } + this.updateSlots(); + + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + @SafeVarargs + private boolean checkTypes(int aID, HashSet<Integer>... aTables) { + for (HashSet<Integer> set : aTables) { + if (set.contains(aID)) { + return true; + } + } + return false; + } + + @Override + public final void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (aPlayer.isSneaking()) { + sVoidStone = !sVoidStone; + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor.void", sVoidStone)); + return; + } + sMode = (sMode + 1) % 5; + List<String> des = getDisplayMode(sMode); + GT_Utility.sendChatToPlayer(aPlayer, String.join("", des)); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + sMode = aNBT.getInteger("ssMode"); + sVoidStone = aNBT.getBoolean("ssStone"); + currentParallelism = aNBT.getInteger("currentParallelism"); + super.loadNBTData(aNBT); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + aNBT.setInteger("ssMode", sMode); + aNBT.setBoolean("ssStone", sVoidStone); + aNBT.setInteger("currentParallelism", currentParallelism); + super.saveNBTData(aNBT); + } + + @SafeVarargs + private void doMac(HashSet<Integer>... aTables) { + List<ItemStack> tProduct = new ArrayList<>(); + if (sMidProduct != null) { + for (ItemStack aStack : sMidProduct) { + int tID = GT_Utility.stackToInt(aStack); + if (checkTypes(tID, aTables)) { + GT_Recipe tRecipe = RecipeMaps.maceratorRecipes + .findRecipe(getBaseMetaTileEntity(), false, GT_Values.V[15], null, aStack); + if (tRecipe != null) { + tProduct.addAll(getOutputStack(tRecipe, aStack.stackSize)); + } else { + tProduct.add(aStack); + } + } else { + tProduct.add(aStack); + } + } + } + doCompress(tProduct); + } + + @SafeVarargs + private void doWash(HashSet<Integer>... aTables) { + List<ItemStack> tProduct = new ArrayList<>(); + if (sMidProduct != null) { + for (ItemStack aStack : sMidProduct) { + int tID = GT_Utility.stackToInt(aStack); + if (checkTypes(tID, aTables)) { + GT_Recipe tRecipe = RecipeMaps.oreWasherRecipes.findRecipe( + getBaseMetaTileEntity(), + false, + GT_Values.V[15], + new FluidStack[] { GT_ModHandler.getDistilledWater(Integer.MAX_VALUE) }, + aStack); + if (tRecipe != null) { + tProduct.addAll(getOutputStack(tRecipe, aStack.stackSize)); + } else { + tProduct.add(aStack); + } + } else { + tProduct.add(aStack); + } + } + } + doCompress(tProduct); + } + + @SafeVarargs + private void doThermal(HashSet<Integer>... aTables) { + List<ItemStack> tProduct = new ArrayList<>(); + if (sMidProduct != null) { + for (ItemStack aStack : sMidProduct) { + int tID = GT_Utility.stackToInt(aStack); + if (checkTypes(tID, aTables)) { + GT_Recipe tRecipe = RecipeMaps.thermalCentrifugeRecipes + .findRecipe(getBaseMetaTileEntity(), false, GT_Values.V[15], null, aStack); + if (tRecipe != null) { + tProduct.addAll(getOutputStack(tRecipe, aStack.stackSize)); + } else { + tProduct.add(aStack); + } + } else { + tProduct.add(aStack); + } + } + } + doCompress(tProduct); + } + + @SafeVarargs + private void doCentrifuge(HashSet<Integer>... aTables) { + List<ItemStack> tProduct = new ArrayList<>(); + if (sMidProduct != null) { + for (ItemStack aStack : sMidProduct) { + int tID = GT_Utility.stackToInt(aStack); + if (checkTypes(tID, aTables)) { + GT_Recipe tRecipe = RecipeMaps.centrifugeRecipes + .findRecipe(getBaseMetaTileEntity(), false, GT_Values.V[15], null, aStack); + if (tRecipe != null) { + tProduct.addAll(getOutputStack(tRecipe, aStack.stackSize)); + } else { + tProduct.add(aStack); + } + } else { + tProduct.add(aStack); + } + } + } + doCompress(tProduct); + } + + @SafeVarargs + private void doSift(HashSet<Integer>... aTables) { + List<ItemStack> tProduct = new ArrayList<>(); + if (sMidProduct != null) { + for (ItemStack aStack : sMidProduct) { + int tID = GT_Utility.stackToInt(aStack); + if (checkTypes(tID, aTables)) { + GT_Recipe tRecipe = RecipeMaps.sifterRecipes + .findRecipe(getBaseMetaTileEntity(), false, GT_Values.V[15], null, aStack); + if (tRecipe != null) { + tProduct.addAll(getOutputStack(tRecipe, aStack.stackSize)); + } else { + tProduct.add(aStack); + } + } else { + tProduct.add(aStack); + } + } + } + doCompress(tProduct); + } + + @SafeVarargs + private void doChemWash(HashSet<Integer>... aTables) { + List<ItemStack> tProduct = new ArrayList<>(); + if (sMidProduct != null) { + for (ItemStack aStack : sMidProduct) { + int tID = GT_Utility.stackToInt(aStack); + if (checkTypes(tID, aTables)) { + GT_Recipe tRecipe = RecipeMaps.chemicalBathRecipes.findRecipe( + getBaseMetaTileEntity(), + false, + GT_Values.V[15], + getStoredFluids().toArray(new FluidStack[0]), + aStack); + if (tRecipe != null && tRecipe.getRepresentativeFluidInput(0) != null) { + FluidStack tInputFluid = tRecipe.getRepresentativeFluidInput(0) + .copy(); + int tStored = getFluidAmount(tInputFluid); + int tWashed = Math.min(tStored / tInputFluid.amount, aStack.stackSize); + depleteInput(new FluidStack(tInputFluid.getFluid(), tWashed * tInputFluid.amount)); + tProduct.addAll(getOutputStack(tRecipe, tWashed)); + if (tWashed < aStack.stackSize) { + tProduct.add(GT_Utility.copyAmountUnsafe(aStack.stackSize - tWashed, aStack)); + } + } else { + tProduct.add(aStack); + } + } else { + tProduct.add(aStack); + } + } + } + doCompress(tProduct); + } + + private int getFluidAmount(FluidStack aFluid) { + int tAmt = 0; + if (aFluid == null) return 0; + for (FluidStack fluid : getStoredFluids()) { + if (aFluid.isFluidEqual(fluid)) { + tAmt += fluid.amount; + } + } + return tAmt; + } + + private List<ItemStack> getOutputStack(GT_Recipe aRecipe, int aTime) { + List<ItemStack> tOutput = new ArrayList<>(); + for (int i = 0; i < aRecipe.mOutputs.length; i++) { + if (aRecipe.getOutput(i) == null) { + continue; + } + int tChance = aRecipe.getOutputChance(i); + if (tChance == 10000) { + tOutput.add(GT_Utility.copyAmountUnsafe(aTime * aRecipe.getOutput(i).stackSize, aRecipe.getOutput(i))); + } else { + // Use Normal Distribution + double u = aTime * (tChance / 10000D); + double e = aTime * (tChance / 10000D) * (1 - (tChance / 10000D)); + Random random = new Random(); + int tAmount = (int) Math.ceil(Math.sqrt(e) * random.nextGaussian() + u); + tOutput + .add(GT_Utility.copyAmountUnsafe(tAmount * aRecipe.getOutput(i).stackSize, aRecipe.getOutput(i))); + } + } + return tOutput.stream() + .filter(i -> (i != null && i.stackSize > 0)) + .collect(Collectors.toList()); + } + + private void doCompress(List<ItemStack> aList) { + HashMap<Integer, Integer> rProduct = new HashMap<>(); + for (ItemStack stack : aList) { + int tID = GT_Utility.stackToInt(stack); + if (sVoidStone) { + if (GT_Utility.areStacksEqual(Materials.Stone.getDust(1), stack)) { + continue; + } + } + if (tID != 0) { + if (rProduct.containsKey(tID)) { + rProduct.put(tID, rProduct.get(tID) + stack.stackSize); + } else { + rProduct.put(tID, stack.stackSize); + } + } + } + sMidProduct = new ItemStack[rProduct.size()]; + int cnt = 0; + for (Integer id : rProduct.keySet()) { + ItemStack stack = GT_Utility.intToStack(id); + sMidProduct[cnt] = GT_Utility.copyAmountUnsafe(rProduct.get(id), stack); + cnt++; + } + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + return checkPiece(STRUCTURE_PIECE_MAIN, 8, 9, 1) && mMaintenanceHatches.size() <= 1 + && !mMufflerHatches.isEmpty(); + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + return 200; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_IntegratedOreFactory(mName); + } + + private void setCurrentParallelism(int parallelism) { + this.currentParallelism = parallelism; + } + + private int getCurrentParallelism() { + return this.currentParallelism; + } + + @Override + public String[] getInfoData() { + List<String> informationData = new ArrayList<>(Arrays.asList(super.getInfoData())); + String parallelism = StatCollector.translateToLocal("GT5U.multiblock.parallelism") + ": " + + EnumChatFormatting.BLUE + + getCurrentParallelism() + + EnumChatFormatting.RESET; + informationData.add(parallelism); + informationData.add(StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor.void", sVoidStone)); + informationData.addAll(getDisplayMode(sMode)); + return informationData.toArray(new String[0]); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(CASING_INDEX2), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PROCESSING_ARRAY_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PROCESSING_ARRAY_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(CASING_INDEX2), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PROCESSING_ARRAY) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PROCESSING_ARRAY_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(CASING_INDEX2) }; + } + + private static List<String> getDisplayMode(int mode) { + final EnumChatFormatting AQUA = EnumChatFormatting.AQUA; + final String CRUSH = StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor.Macerate"); + final String WASH = StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor.Ore_Washer") + .replace(" ", " " + AQUA); + final String THERMAL = StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor.Thermal_Centrifuge") + .replace(" ", " " + AQUA); + final String CENTRIFUGE = StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor.Centrifuge"); + final String SIFTER = StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor.Sifter"); + final String CHEM_WASH = StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor.Chemical_Bathing") + .replace(" ", " " + AQUA); + final String ARROW = " " + AQUA + "-> "; + + List<String> des = new ArrayList<>(); + des.add(StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor1") + " "); + + switch (mode) { + case 0 -> { + des.add(AQUA + CRUSH + ARROW); + des.add(AQUA + WASH + ARROW); + des.add(AQUA + THERMAL + ARROW); + des.add(AQUA + CRUSH + ' '); + } + case 1 -> { + des.add(AQUA + CRUSH + ARROW); + des.add(AQUA + WASH + ARROW); + des.add(AQUA + CRUSH + ARROW); + des.add(AQUA + CENTRIFUGE + ' '); + } + case 2 -> { + des.add(AQUA + CRUSH + ARROW); + des.add(AQUA + CRUSH + ARROW); + des.add(AQUA + CENTRIFUGE + ' '); + } + case 3 -> { + des.add(AQUA + CRUSH + ARROW); + des.add(AQUA + WASH + ARROW); + des.add(AQUA + SIFTER + ' '); + } + case 4 -> { + des.add(AQUA + CRUSH + ARROW); + des.add(AQUA + CHEM_WASH + ARROW); + des.add(AQUA + CRUSH + ARROW); + des.add(AQUA + CENTRIFUGE + ' '); + } + default -> des.add(StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor.WRONG_MODE")); + } + + des.add(StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor2", getTime(mode) / 20)); + + return des; + + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + super.getWailaBody(itemStack, currenttip, accessor, config); + NBTTagCompound tag = accessor.getNBTData(); + + currenttip.add( + StatCollector.translateToLocal("GT5U.multiblock.parallelism") + ": " + + EnumChatFormatting.BLUE + + tag.getInteger("currentParallelism") + + EnumChatFormatting.RESET); + currenttip.addAll(getDisplayMode(tag.getInteger("ssMode"))); + currenttip + .add(StatCollector.translateToLocalFormatted("GT5U.machines.oreprocessor.void", tag.getBoolean("ssStone"))); + + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + super.getWailaNBTData(player, tile, tag, world, x, y, z); + tag.setInteger("ssMode", sMode); + tag.setBoolean("ssStone", sVoidStone); + tag.setInteger("currentParallelism", currentParallelism); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler.java new file mode 100644 index 0000000000..ae740447c8 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler.java @@ -0,0 +1,504 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.Muffler; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.GT_Values.STEAM_PER_WATER; +import static gregtech.api.enums.ItemList.Circuit_Integrated; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_LARGE_BOILER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_LARGE_BOILER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_LARGE_BOILER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_LARGE_BOILER_GLOW; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_Utility.formatNumbers; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.GT_Mod; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.Textures; +import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.maps.LargeBoilerFuelBackend; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; + +public abstract class GT_MetaTileEntity_LargeBoiler + extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_LargeBoiler> implements ISurvivalConstructable { + + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final ClassValue<IStructureDefinition<GT_MetaTileEntity_LargeBoiler>> STRUCTURE_DEFINITION = new ClassValue<>() { + + @Override + protected IStructureDefinition<GT_MetaTileEntity_LargeBoiler> computeValue(Class<?> type) { + return StructureDefinition.<GT_MetaTileEntity_LargeBoiler>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose( + new String[][] { { "ccc", "ccc", "ccc" }, { "ccc", "cPc", "ccc" }, { "ccc", "cPc", "ccc" }, + { "ccc", "cPc", "ccc" }, { "f~f", "fff", "fff" }, })) + .addElement('P', lazy(t -> ofBlock(t.getPipeBlock(), t.getPipeMeta()))) + .addElement( + 'c', + lazy( + t -> buildHatchAdder(GT_MetaTileEntity_LargeBoiler.class).atLeast(OutputHatch) + .casingIndex(t.getCasingTextureIndex()) + .dot(2) + .buildAndChain( + onElementPass( + GT_MetaTileEntity_LargeBoiler::onCasingAdded, + ofBlock(t.getCasingBlock(), t.getCasingMeta()))))) + .addElement( + 'f', + lazy( + t -> buildHatchAdder(GT_MetaTileEntity_LargeBoiler.class) + .atLeast(Maintenance, InputHatch, InputBus, Muffler) + .casingIndex(t.getFireboxTextureIndex()) + .dot(1) + .buildAndChain( + onElementPass( + GT_MetaTileEntity_LargeBoiler::onFireboxAdded, + ofBlock(t.getFireboxBlock(), t.getFireboxMeta()))))) + .build(); + } + }; + private boolean firstRun = true; + private int mSuperEfficencyIncrease = 0; + private int integratedCircuitConfig = 0; // Steam output is reduced by 1000L per config + private int excessWater = 0; // Eliminate rounding errors for water + private int excessFuel = 0; // Eliminate rounding errors for fuels that burn half items + private int excessProjectedEU = 0; // Eliminate rounding errors from throttling the boiler + private int mCasingAmount; + private int mFireboxAmount; + protected int pollutionPerSecond = 1; // placeholder for the child classes + + public GT_MetaTileEntity_LargeBoiler(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_LargeBoiler(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + + tt.addMachineType("Boiler") + .addInfo("Controller block for the Large " + getCasingMaterial() + " Boiler"); + // Tooltip differs between the boilers that output Superheated Steam (Titanium and Tungstensteel) and the ones + // that do not (Bronze and Steel) + if (isSuperheated()) { + tt.addInfo( + "Produces " + formatNumbers((getEUt() * 40) * ((runtimeBoost(20) / (20f)) / superToNormalSteam)) + + "L of Superheated Steam with 1 Coal at " + + formatNumbers((getEUt() * 40L) / superToNormalSteam) + + "L/s") // ? + .addInfo("A programmed circuit in the main block throttles the boiler (-1000L/s per config)") + .addInfo("Only some solid fuels are allowed (check the NEI Large Boiler tab for details)") + .addInfo("If there are any disallowed fuels in the input bus, the boiler won't run!"); + } else { + tt.addInfo( + "Produces " + formatNumbers((getEUt() * 40) * (runtimeBoost(20) / 20f)) + + "L of Steam with 1 Coal at " + + formatNumbers(getEUt() * 40L) + + "L/s") // ? + .addInfo("A programmed circuit in the main block throttles the boiler (-1000L/s per config)") + .addInfo("Solid Fuels with a burn value that is too high or too low will not work"); + } + tt.addInfo( + String.format( + "Diesel fuels have 1/4 efficiency - Takes %s seconds to heat up", + formatNumbers(500.0 / getEfficiencyIncrease()))) // ? check semifluid again + .addPollutionAmount(getPollutionPerSecond(null)) + .addSeparator() + .beginStructureBlock(3, 5, 3, false) + .addController("Front bottom") + .addCasingInfoRange(getCasingMaterial() + " " + getCasingBlockType() + " Casing", 24, 31, false) // ? + .addOtherStructurePart(getCasingMaterial() + " Fire Boxes", "Bottom layer, 3 minimum") + .addOtherStructurePart(getCasingMaterial() + " Pipe Casing Blocks", "Inner 3 blocks") + .addMaintenanceHatch("Any firebox", 1) + .addMufflerHatch("Any firebox", 1) + .addInputBus("Solid fuel, Any firebox", 1) + .addInputHatch("Liquid fuel, Any firebox", 1) + .addStructureInfo("You can use either, or both") + .addInputHatch("Water, Any firebox", 1) + .addOutputHatch("Steam, any casing", 2) + .toolTipFinisher("Gregtech"); + + return tt; + } + + public abstract String getCasingMaterial(); + + public abstract Block getCasingBlock(); + + public abstract String getCasingBlockType(); + + public abstract byte getCasingMeta(); + + public abstract byte getCasingTextureIndex(); + + public abstract Block getPipeBlock(); + + public abstract byte getPipeMeta(); + + public abstract Block getFireboxBlock(); + + public abstract byte getFireboxMeta(); + + public abstract byte getFireboxTextureIndex(); + + public abstract int getEUt(); + + public abstract int getEfficiencyIncrease(); + + public int getIntegratedCircuitConfig() { + return integratedCircuitConfig; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + // allows for 0 pollution if circuit throttle is too high + return Math.max( + 0, + (int) (pollutionPerSecond + * (1 - GT_Mod.gregtechproxy.mPollutionReleasedByThrottle * getIntegratedCircuitConfig()))); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { BlockIcons.getCasingTextureForId(getCasingTextureIndex()), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_LARGE_BOILER_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_LARGE_BOILER_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { BlockIcons.getCasingTextureForId(getCasingTextureIndex()), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_LARGE_BOILER) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_LARGE_BOILER_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(getCasingTextureIndex()) }; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + boolean isFuelValid() { + if (!isSuperheated()) return true; + for (ItemStack input : getStoredInputs()) { + if (!LargeBoilerFuelBackend.isAllowedSolidFuel(input) + && !Circuit_Integrated.isStackEqual(input, true, true)) { + // if any item is not in ALLOWED_SOLID_FUELS, operation cannot be allowed because it might still be + // consumed + this.mMaxProgresstime = 0; + this.mEUt = 0; + return false; + } + } + return true; + } + + @Override + public RecipeMap<?> getRecipeMap() { + // Only for visual + return RecipeMaps.largeBoilerFakeFuels; + } + + @Override + protected boolean filtersFluid() { + return false; + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + if (!isFuelValid()) return CheckRecipeResultRegistry.NO_FUEL_FOUND; + // Do we have an integrated circuit with a valid configuration? + if (Circuit_Integrated.isStackEqual(mInventory[1], true, true)) { + int circuit_config = mInventory[1].getItemDamage(); + if (circuit_config >= 1 && circuit_config <= 25) { + // If so, overwrite the current config + this.integratedCircuitConfig = circuit_config; + } + } else { + // If not, set the config to zero + this.integratedCircuitConfig = 0; + } + + this.mSuperEfficencyIncrease = 0; + if (!isSuperheated()) { + for (GT_Recipe tRecipe : RecipeMaps.dieselFuels.getAllRecipes()) { + FluidStack tFluid = GT_Utility.getFluidForFilledItem(tRecipe.getRepresentativeInput(0), true); + if (tFluid != null && tRecipe.mSpecialValue > 1) { + tFluid.amount = 1000; + if (depleteInput(tFluid)) { + this.mMaxProgresstime = adjustBurnTimeForConfig(runtimeBoost(tRecipe.mSpecialValue / 2)); + this.mEUt = adjustEUtForConfig(getEUt()); + this.mEfficiencyIncrease = this.mMaxProgresstime * getEfficiencyIncrease() * 4; + return CheckRecipeResultRegistry.SUCCESSFUL; + } + } + } + for (GT_Recipe tRecipe : RecipeMaps.denseLiquidFuels.getAllRecipes()) { + FluidStack tFluid = GT_Utility.getFluidForFilledItem(tRecipe.getRepresentativeInput(0), true); + if (tFluid != null) { + tFluid.amount = 1000; + if (depleteInput(tFluid)) { + this.mMaxProgresstime = adjustBurnTimeForConfig( + Math.max(1, runtimeBoost(tRecipe.mSpecialValue * 2))); + this.mEUt = adjustEUtForConfig(getEUt()); + this.mEfficiencyIncrease = this.mMaxProgresstime * getEfficiencyIncrease(); + return CheckRecipeResultRegistry.SUCCESSFUL; + } + } + } + } + + ArrayList<ItemStack> tInputList = getStoredInputs(); + if (!tInputList.isEmpty()) { + if (isSuperheated()) { + for (ItemStack tInput : tInputList) { + if (tInput != GT_OreDictUnificator.get(OrePrefixes.bucket, Materials.Lava, 1)) { + if (GT_Utility.getFluidForFilledItem(tInput, true) == null + && (this.mMaxProgresstime = GT_ModHandler.getFuelValue(tInput) / 80) > 0) { + this.excessFuel += GT_ModHandler.getFuelValue(tInput) % 80; + this.mMaxProgresstime += this.excessFuel / 80; + this.excessFuel %= 80; + this.mMaxProgresstime = adjustBurnTimeForConfig(runtimeBoost(this.mMaxProgresstime)); + this.mEUt = adjustEUtForConfig(getEUt()); + this.mEfficiencyIncrease = this.mMaxProgresstime * getEfficiencyIncrease(); + this.mOutputItems = new ItemStack[] { GT_Utility.getContainerItem(tInput, true) }; + tInput.stackSize -= 1; + updateSlots(); + if (this.mEfficiencyIncrease > 5000) { + this.mEfficiencyIncrease = 0; + this.mSuperEfficencyIncrease = 20; + } + return CheckRecipeResultRegistry.SUCCESSFUL; + } + } + } + } else { + for (ItemStack tInput : tInputList) { + if (tInput != GT_OreDictUnificator.get(OrePrefixes.bucket, Materials.Lava, 1)) { + // Solid fuels with burn values below getEUt are ignored (mostly items like sticks), and also + // those with very high fuel values that would cause an overflow error. + if (GT_Utility.getFluidForFilledItem(tInput, true) == null + && (this.mMaxProgresstime = GT_ModHandler.getFuelValue(tInput) / 80) > 0 + && (GT_ModHandler.getFuelValue(tInput) * 2 / this.getEUt()) > 1 + && GT_ModHandler.getFuelValue(tInput) < 100000000) { + this.excessFuel += GT_ModHandler.getFuelValue(tInput) % 80; + this.mMaxProgresstime += this.excessFuel / 80; + this.excessFuel %= 80; + this.mMaxProgresstime = adjustBurnTimeForConfig(runtimeBoost(this.mMaxProgresstime)); + this.mEUt = adjustEUtForConfig(getEUt()); + this.mEfficiencyIncrease = this.mMaxProgresstime * getEfficiencyIncrease(); + this.mOutputItems = new ItemStack[] { GT_Utility.getContainerItem(tInput, true) }; + tInput.stackSize -= 1; + updateSlots(); + if (this.mEfficiencyIncrease > 5000) { + this.mEfficiencyIncrease = 0; + this.mSuperEfficencyIncrease = 20; + } + return CheckRecipeResultRegistry.SUCCESSFUL; + } + } + } + } + } + this.mMaxProgresstime = 0; + this.mEUt = 0; + return CheckRecipeResultRegistry.NO_FUEL_FOUND; + } + + abstract int runtimeBoost(int mTime); + + abstract boolean isSuperheated(); + + private final int superToNormalSteam = 3; + + @Override + public boolean onRunningTick(ItemStack aStack) { + if (this.mEUt > 0) { + if (this.mSuperEfficencyIncrease > 0) mEfficiency = Math.max( + 0, + Math.min( + mEfficiency + mSuperEfficencyIncrease, + getMaxEfficiency(mInventory[1]) - ((getIdealStatus() - getRepairStatus()) * 1000))); + int tGeneratedEU = (int) (this.mEUt * 2L * this.mEfficiency / 10000L); + if (tGeneratedEU > 0) { + long amount = (tGeneratedEU + STEAM_PER_WATER) / STEAM_PER_WATER; + excessWater += amount * STEAM_PER_WATER - tGeneratedEU; + amount -= excessWater / STEAM_PER_WATER; + excessWater %= STEAM_PER_WATER; + startRecipeProcessing(); + if (isSuperheated()) { + // Consumes only one third of the water if producing Superheated Steam, to maintain water in the + // chain. + if (depleteInput(Materials.Water.getFluid(amount / superToNormalSteam)) + || depleteInput(GT_ModHandler.getDistilledWater(amount / superToNormalSteam))) { + // Outputs Superheated Steam instead of Steam, at one third of the amount (equivalent in power + // output to the normal Steam amount). + addOutput( + FluidRegistry.getFluidStack("ic2superheatedsteam", tGeneratedEU / superToNormalSteam)); + } else { + GT_Log.exp.println("Boiler " + this.mName + " had no Water!"); + explodeMultiblock(); + } + } else { + if (depleteInput(Materials.Water.getFluid(amount)) + || depleteInput(GT_ModHandler.getDistilledWater(amount))) { + addOutput(GT_ModHandler.getSteam(tGeneratedEU)); + } else { + GT_Log.exp.println("Boiler " + this.mName + " had no Water!"); + explodeMultiblock(); + } + } + endRecipeProcessing(); + } + return true; + } + return true; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setInteger("excessFuel", excessFuel); + aNBT.setInteger("excessWater", excessWater); + aNBT.setInteger("excessProjectedEU", excessProjectedEU); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + excessFuel = aNBT.getInteger("excessFuel"); + excessWater = aNBT.getInteger("excessWater"); + excessProjectedEU = aNBT.getInteger("excessProjectedEU"); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (mProgresstime > 0 && firstRun) { + firstRun = false; + GT_Mod.achievements.issueAchievement( + aBaseMetaTileEntity.getWorld() + .getPlayerEntityByName(aBaseMetaTileEntity.getOwnerName()), + "extremepressure"); + } + super.onPostTick(aBaseMetaTileEntity, aTick); + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_LargeBoiler> getStructureDefinition() { + return STRUCTURE_DEFINITION.get(getClass()); + } + + private void onCasingAdded() { + mCasingAmount++; + } + + private void onFireboxAdded() { + mFireboxAmount++; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + mCasingAmount = 0; + mFireboxAmount = 0; + return checkPiece(STRUCTURE_PIECE_MAIN, 1, 4, 0) && mCasingAmount >= 24 + && mFireboxAmount >= 3 + && mMaintenanceHatches.size() == 1 + && !mMufflerHatches.isEmpty(); + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + private int adjustEUtForConfig(int rawEUt) { + int adjustedSteamOutput = rawEUt - (isSuperheated() ? 75 : 25) * integratedCircuitConfig; + return Math.max(adjustedSteamOutput, 25); + } + + private int adjustBurnTimeForConfig(int rawBurnTime) { + if (mEfficiency < getMaxEfficiency(mInventory[1]) - ((getIdealStatus() - getRepairStatus()) * 1000)) { + return rawBurnTime; + } + int adjustedEUt = Math.max(25, getEUt() - (isSuperheated() ? 75 : 25) * integratedCircuitConfig); + int adjustedBurnTime = rawBurnTime * getEUt() / adjustedEUt; + this.excessProjectedEU += getEUt() * rawBurnTime - adjustedEUt * adjustedBurnTime; + adjustedBurnTime += this.excessProjectedEU / adjustedEUt; + this.excessProjectedEU %= adjustedEUt; + return adjustedBurnTime; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 1, 4, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 1, 4, 0, elementBudget, env, false, true); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_Bronze.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_Bronze.java new file mode 100644 index 0000000000..2effcf7966 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_Bronze.java @@ -0,0 +1,96 @@ +package gregtech.common.tileentities.machines.multi; + +import net.minecraft.block.Block; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +public class GT_MetaTileEntity_LargeBoiler_Bronze extends GT_MetaTileEntity_LargeBoiler { + + public GT_MetaTileEntity_LargeBoiler_Bronze(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + pollutionPerSecond = GT_Mod.gregtechproxy.mPollutionLargeBronzeBoilerPerSecond; + } + + public GT_MetaTileEntity_LargeBoiler_Bronze(String aName) { + super(aName); + pollutionPerSecond = GT_Mod.gregtechproxy.mPollutionLargeBronzeBoilerPerSecond; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LargeBoiler_Bronze(this.mName); + } + + @Override + public String getCasingMaterial() { + return "Bronze"; + } + + @Override + public String getCasingBlockType() { + return "Plated Bricks"; + } + + @Override + public Block getCasingBlock() { + return GregTech_API.sBlockCasings1; + } + + @Override + public byte getCasingMeta() { + return 10; + } + + @Override + public byte getCasingTextureIndex() { + return 10; + } + + @Override + public Block getPipeBlock() { + return GregTech_API.sBlockCasings2; + } + + @Override + public byte getPipeMeta() { + return 12; + } + + @Override + public Block getFireboxBlock() { + return GregTech_API.sBlockCasings3; + } + + @Override + public byte getFireboxMeta() { + return 13; + } + + @Override + public byte getFireboxTextureIndex() { + return 45; + } + + @Override + public int getEUt() { + return 400; + } + + @Override + public int getEfficiencyIncrease() { + return 16; + } + + @Override + int runtimeBoost(int mTime) { + return mTime * 2; + } + + @Override + boolean isSuperheated() { + return false; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_Steel.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_Steel.java new file mode 100644 index 0000000000..c7bd766945 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_Steel.java @@ -0,0 +1,96 @@ +package gregtech.common.tileentities.machines.multi; + +import net.minecraft.block.Block; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +public class GT_MetaTileEntity_LargeBoiler_Steel extends GT_MetaTileEntity_LargeBoiler { + + public GT_MetaTileEntity_LargeBoiler_Steel(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + pollutionPerSecond = GT_Mod.gregtechproxy.mPollutionLargeSteelBoilerPerSecond; + } + + public GT_MetaTileEntity_LargeBoiler_Steel(String aName) { + super(aName); + pollutionPerSecond = GT_Mod.gregtechproxy.mPollutionLargeSteelBoilerPerSecond; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LargeBoiler_Steel(this.mName); + } + + @Override + public String getCasingMaterial() { + return "Steel"; + } + + @Override + public String getCasingBlockType() { + return "Machine Casings"; + } + + @Override + public Block getCasingBlock() { + return GregTech_API.sBlockCasings2; + } + + @Override + public byte getCasingMeta() { + return 0; + } + + @Override + public byte getCasingTextureIndex() { + return 16; + } + + @Override + public Block getPipeBlock() { + return GregTech_API.sBlockCasings2; + } + + @Override + public byte getPipeMeta() { + return 13; + } + + @Override + public Block getFireboxBlock() { + return GregTech_API.sBlockCasings3; + } + + @Override + public byte getFireboxMeta() { + return 14; + } + + @Override + public byte getFireboxTextureIndex() { + return 46; + } + + @Override + public int getEUt() { + return 1000; + } + + @Override + public int getEfficiencyIncrease() { + return 12; + } + + @Override + int runtimeBoost(int mTime) { + return mTime; + } + + @Override + boolean isSuperheated() { + return false; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_Titanium.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_Titanium.java new file mode 100644 index 0000000000..61f2756622 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_Titanium.java @@ -0,0 +1,96 @@ +package gregtech.common.tileentities.machines.multi; + +import net.minecraft.block.Block; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +public class GT_MetaTileEntity_LargeBoiler_Titanium extends GT_MetaTileEntity_LargeBoiler { + + public GT_MetaTileEntity_LargeBoiler_Titanium(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + pollutionPerSecond = GT_Mod.gregtechproxy.mPollutionLargeTitaniumBoilerPerSecond; + } + + public GT_MetaTileEntity_LargeBoiler_Titanium(String aName) { + super(aName); + pollutionPerSecond = GT_Mod.gregtechproxy.mPollutionLargeTitaniumBoilerPerSecond; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LargeBoiler_Titanium(this.mName); + } + + @Override + public String getCasingMaterial() { + return "Titanium"; + } + + @Override + public String getCasingBlockType() { + return "Machine Casings"; + } + + @Override + public Block getCasingBlock() { + return GregTech_API.sBlockCasings4; + } + + @Override + public byte getCasingMeta() { + return 2; + } + + @Override + public byte getCasingTextureIndex() { + return 50; + } + + @Override + public Block getPipeBlock() { + return GregTech_API.sBlockCasings2; + } + + @Override + public byte getPipeMeta() { + return 14; + } + + @Override + public Block getFireboxBlock() { + return GregTech_API.sBlockCasings4; + } + + @Override + public byte getFireboxMeta() { + return 3; + } + + @Override + public byte getFireboxTextureIndex() { + return 51; + } + + @Override + public int getEUt() { + return 4000; + } + + @Override + public int getEfficiencyIncrease() { + return 8; + } + + @Override + int runtimeBoost(int mTime) { + return mTime * 130 / 400; + } + + @Override + boolean isSuperheated() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_TungstenSteel.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_TungstenSteel.java new file mode 100644 index 0000000000..f00ea287b2 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeBoiler_TungstenSteel.java @@ -0,0 +1,96 @@ +package gregtech.common.tileentities.machines.multi; + +import net.minecraft.block.Block; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +public class GT_MetaTileEntity_LargeBoiler_TungstenSteel extends GT_MetaTileEntity_LargeBoiler { + + public GT_MetaTileEntity_LargeBoiler_TungstenSteel(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + pollutionPerSecond = GT_Mod.gregtechproxy.mPollutionLargeTungstenSteelBoilerPerSecond; + } + + public GT_MetaTileEntity_LargeBoiler_TungstenSteel(String aName) { + super(aName); + pollutionPerSecond = GT_Mod.gregtechproxy.mPollutionLargeTungstenSteelBoilerPerSecond; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LargeBoiler_TungstenSteel(this.mName); + } + + @Override + public String getCasingMaterial() { + return "TungstenSteel"; + } + + @Override + public String getCasingBlockType() { + return "Machine Casings"; + } + + @Override + public Block getCasingBlock() { + return GregTech_API.sBlockCasings4; + } + + @Override + public byte getCasingMeta() { + return 0; + } + + @Override + public byte getCasingTextureIndex() { + return 48; + } + + @Override + public Block getPipeBlock() { + return GregTech_API.sBlockCasings2; + } + + @Override + public byte getPipeMeta() { + return 15; + } + + @Override + public Block getFireboxBlock() { + return GregTech_API.sBlockCasings3; + } + + @Override + public byte getFireboxMeta() { + return 15; + } + + @Override + public byte getFireboxTextureIndex() { + return 47; + } + + @Override + public int getEUt() { + return 16000; + } + + @Override + public int getEfficiencyIncrease() { + return 4; + } + + @Override + int runtimeBoost(int mTime) { + return mTime * 120 / 750; + } + + @Override + boolean isSuperheated() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeChemicalReactor.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeChemicalReactor.java new file mode 100644 index 0000000000..8e4b5ec650 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeChemicalReactor.java @@ -0,0 +1,298 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; + +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IChatComponent; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizon.structurelib.StructureLibAPI; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.AutoPlaceEnvironment; +import com.gtnewhorizon.structurelib.structure.IItemSource; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.IStructureElement; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizon.structurelib.structure.StructureUtility; +import com.gtnewhorizon.structurelib.util.ItemStackPredicate; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.HeatingCoilLevel; +import gregtech.api.interfaces.IHeatingCoil; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_LargeChemicalReactor extends + GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_LargeChemicalReactor> implements ISurvivalConstructable { + + private static final int CASING_INDEX = 176; + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final IStructureDefinition<GT_MetaTileEntity_LargeChemicalReactor> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_LargeChemicalReactor>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose(new String[][] { { "ccc", "cxc", "ccc" }, { "c~c", "xPx", "cxc" }, { "ccc", "cxc", "ccc" }, })) + .addElement('P', ofBlock(GregTech_API.sBlockCasings8, 1)) + .addElement( + 'c', + buildHatchAdder(GT_MetaTileEntity_LargeChemicalReactor.class) + .atLeast(InputHatch, OutputHatch, InputBus, OutputBus, Maintenance, Energy) + .casingIndex(CASING_INDEX) + .dot(1) + .buildAndChain( + onElementPass( + GT_MetaTileEntity_LargeChemicalReactor::onCasingAdded, + ofBlock(GregTech_API.sBlockCasings8, 0)))) + .addElement( + 'x', + buildHatchAdder(GT_MetaTileEntity_LargeChemicalReactor.class) + .atLeast(InputHatch, OutputHatch, InputBus, OutputBus, Maintenance, Energy) + .casingIndex(CASING_INDEX) + .dot(1) + .buildAndChain( + CoilStructureElement.INSTANCE, + onElementPass( + GT_MetaTileEntity_LargeChemicalReactor::onCasingAdded, + ofBlock(GregTech_API.sBlockCasings8, 0)))) + .build(); + + private int mCasingAmount; + private int mCoilAmount; + + public GT_MetaTileEntity_LargeChemicalReactor(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_LargeChemicalReactor(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LargeChemicalReactor(this.mName); + } + + @Override + public GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Chemical Reactor") + .addInfo("Controller block for the Large Chemical Reactor") + .addInfo("Does not lose efficiency when overclocked") + .addInfo("Accepts fluids instead of fluid cells") + .addSeparator() + .beginStructureBlock(3, 3, 3, false) + .addController("Front center") + .addCasingInfoRange("Chemically Inert Machine Casing", 8, 22, false) + .addOtherStructurePart("PTFE Pipe Machine Casing", "Center") + .addOtherStructurePart("Heating Coil", "Adjacent to the PTFE Pipe Machine Casing", 1) + .addEnergyHatch("Any casing", 1, 2) + .addMaintenanceHatch("Any casing", 1, 2) + .addInputBus("Any casing", 1, 2) + .addInputHatch("Any casing", 1, 2) + .addOutputBus("Any casing", 1, 2) + .addOutputHatch("Any casing", 1, 2) + .addStructureInfo("You can have multiple hatches/busses") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { casingTexturePages[1][48], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { casingTexturePages[1][48], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { casingTexturePages[1][48] }; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public boolean supportsSingleRecipeLocking() { + return true; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.multiblockChemicalReactorRecipes; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic().enablePerfectOverclock(); + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_LargeChemicalReactor> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + private void onCasingAdded() { + mCasingAmount++; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + mCasingAmount = 0; + mCoilAmount = 0; + return checkPiece(STRUCTURE_PIECE_MAIN, 1, 1, 0) && mCasingAmount >= 8 + && mCoilAmount == 1 + && !mEnergyHatches.isEmpty() + && mMaintenanceHatches.size() == 1; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + mCoilAmount = 0; + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 1, 1, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + mCoilAmount = 0; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 1, 1, 0, elementBudget, env, false, true); + } + + @Override + public boolean supportsVoidProtection() { + return true; + } + + private enum CoilStructureElement implements IStructureElement<GT_MetaTileEntity_LargeChemicalReactor> { + + INSTANCE; + + @Override + public boolean check(GT_MetaTileEntity_LargeChemicalReactor t, World world, int x, int y, int z) { + Block block = world.getBlock(x, y, z); + if (block instanceof IHeatingCoil + && ((IHeatingCoil) block).getCoilHeat(world.getBlockMetadata(x, y, z)) != HeatingCoilLevel.None) { + return t.mCoilAmount++ == 0; + } else { + return false; + } + } + + @Override + public boolean spawnHint(GT_MetaTileEntity_LargeChemicalReactor t, World world, int x, int y, int z, + ItemStack trigger) { + StructureLibAPI.hintParticle(world, x, y, z, GregTech_API.sBlockCasings5, 0); + return true; + } + + @Override + public boolean placeBlock(GT_MetaTileEntity_LargeChemicalReactor t, World world, int x, int y, int z, + ItemStack trigger) { + if (t.mCoilAmount > 0) return false; + boolean b = world.setBlock(x, y, z, GregTech_API.sBlockCasings5, 0, 3); + if (b) t.mCoilAmount++; + return b; + } + + @Override + public PlaceResult survivalPlaceBlock(GT_MetaTileEntity_LargeChemicalReactor t, World world, int x, int y, + int z, ItemStack trigger, IItemSource s, EntityPlayerMP actor, Consumer<IChatComponent> chatter) { + return survivalPlaceBlock(t, world, x, y, z, trigger, AutoPlaceEnvironment.fromLegacy(s, actor, chatter)); + } + + @Override + public BlocksToPlace getBlocksToPlace( + GT_MetaTileEntity_LargeChemicalReactor gt_metaTileEntity_largeChemicalReactor, World world, int x, int y, + int z, ItemStack trigger, AutoPlaceEnvironment env) { + return BlocksToPlace.create( + IntStream.range(0, 8) + .mapToObj(i -> new ItemStack(GregTech_API.sBlockCasings5, 1, i)) + .collect(Collectors.toList())); + } + + @Override + public PlaceResult survivalPlaceBlock(GT_MetaTileEntity_LargeChemicalReactor t, World world, int x, int y, + int z, ItemStack trigger, AutoPlaceEnvironment env) { + if (t.mCoilAmount > 0) return PlaceResult.SKIP; + if (check(t, world, x, y, z)) return PlaceResult.SKIP; + if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, env.getActor())) return PlaceResult.REJECT; + ItemStack result = env.getSource() + .takeOne(ItemStackPredicate.from(GregTech_API.sBlockCasings5), true); + if (result == null) return PlaceResult.REJECT; + PlaceResult ret = StructureUtility.survivalPlaceBlock( + result, + ItemStackPredicate.NBTMode.EXACT, + null, + true, + world, + x, + y, + z, + env.getSource(), + env.getActor(), + env.getChatter()); + if (ret == PlaceResult.ACCEPT) t.mCoilAmount++; + return ret; + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine.java new file mode 100644 index 0000000000..54ad5939f8 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine.java @@ -0,0 +1,492 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Dynamo; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.Muffler; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.Textures.BlockIcons.TURBINE_NEW; +import static gregtech.api.enums.Textures.BlockIcons.TURBINE_NEW_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.TURBINE_NEW_EMPTY; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; +import com.gtnewhorizon.structurelib.alignment.enumerable.Flip; +import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.api.enums.Dyes; +import gregtech.api.interfaces.IIconContainer; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.items.GT_MetaGenerated_Tool; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.LightingHelper; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; +import gregtech.common.items.GT_MetaGenerated_Tool_01; +import gregtech.common.render.GT_RenderUtil; + +public abstract class GT_MetaTileEntity_LargeTurbine + extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_LargeTurbine> implements ISurvivalConstructable { + + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final ClassValue<IStructureDefinition<GT_MetaTileEntity_LargeTurbine>> STRUCTURE_DEFINITION = new ClassValue<>() { + + @Override + protected IStructureDefinition<GT_MetaTileEntity_LargeTurbine> computeValue(Class<?> type) { + return StructureDefinition.<GT_MetaTileEntity_LargeTurbine>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose( + new String[][] { { " ", " ", " ", " ", " ", }, + { " --- ", " ccc ", " hhh ", " hhh ", " hhh ", }, + { " --- ", " c~c ", " h-h ", " h-h ", " hdh ", }, + { " --- ", " ccc ", " hhh ", " hhh ", " hhh ", }, + { " ", " ", " ", " ", " ", }, })) + .addElement('c', lazy(t -> ofBlock(t.getCasingBlock(), t.getCasingMeta()))) + .addElement('d', lazy(t -> Dynamo.newAny(t.getCasingTextureIndex(), 1))) + .addElement( + 'h', + lazy( + t -> buildHatchAdder(GT_MetaTileEntity_LargeTurbine.class) + .atLeast(Maintenance, InputHatch, OutputHatch, OutputBus, InputBus, Muffler) + .casingIndex(t.getCasingTextureIndex()) + .dot(2) + .buildAndChain(t.getCasingBlock(), t.getCasingMeta()))) + .build(); + } + }; + + protected int baseEff = 0; + protected int optFlow = 0; + protected double realOptFlow = 0; + protected int storedFluid = 0; + protected int counter = 0; + protected boolean looseFit = false; + protected int overflowMultiplier = 0; + protected final float[] flowMultipliers = new float[] { 1, 1, 1 }; + + // client side stuff + protected boolean mHasTurbine; + // mMachine got overwritten by StructureLib extended facing query response + // so we use a separate field for this + protected boolean mFormed; + + public GT_MetaTileEntity_LargeTurbine(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_LargeTurbine(String aName) { + super(aName); + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return getMaxEfficiency(aStack) > 0; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_LargeTurbine> getStructureDefinition() { + return STRUCTURE_DEFINITION.get(getClass()); + } + + @Override + protected IAlignmentLimits getInitialAlignmentLimits() { + return (d, r, f) -> r.isNotRotated() && f.isNotFlipped(); + } + + @Override + protected ExtendedFacing getCorrectedAlignment(ExtendedFacing aOldFacing) { + return aOldFacing.with(Flip.NONE) + .with(Rotation.NORMAL); + } + + @Override + public boolean isFlipChangeAllowed() { + return false; + } + + @Override + public boolean isRotationChangeAllowed() { + return false; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + return checkPiece(STRUCTURE_PIECE_MAIN, 2, 2, 1) && mMaintenanceHatches.size() == 1 + && mMufflerHatches.isEmpty() == (getPollutionPerTick(null) == 0); + } + + public abstract Block getCasingBlock(); + + public abstract byte getCasingMeta(); + + public abstract int getCasingTextureIndex(); + + public boolean isNewStyleRendering() { + return false; + } + + public IIconContainer[] getTurbineTextureActive() { + return TURBINE_NEW_ACTIVE; + } + + public IIconContainer[] getTurbineTextureFull() { + return TURBINE_NEW; + } + + public IIconContainer[] getTurbineTextureEmpty() { + return TURBINE_NEW_EMPTY; + } + + @Override + public boolean renderInWorld(IBlockAccess aWorld, int aX, int aY, int aZ, Block aBlock, RenderBlocks aRenderer) { + if (!isNewStyleRendering() || !mFormed) return false; + int[] tABCCoord = new int[] { -1, -1, 0 }; + int[] tXYZOffset = new int[3]; + final ForgeDirection tFacing = getBaseMetaTileEntity().getFrontFacing(); + final ExtendedFacing tExtendedFacing = getExtendedFacing(); + final ForgeDirection tDirection = tExtendedFacing.getDirection(); + final LightingHelper tLighting = new LightingHelper(aRenderer); + + // for some reason +x and -z need this field set to true, but not any other sides + if (tFacing == ForgeDirection.NORTH || tFacing == ForgeDirection.EAST) aRenderer.field_152631_f = true; + final Block tBlock = getCasingBlock(); + + IIconContainer[] tTextures; + if (getBaseMetaTileEntity().isActive()) tTextures = getTurbineTextureActive(); + else if (hasTurbine()) tTextures = getTurbineTextureFull(); + else tTextures = getTurbineTextureEmpty(); + + assert tTextures != null && tTextures.length == tABCCoord.length; + + for (int i = 0; i < 9; i++) { + if (i != 4) { // do not draw ourselves again. + tExtendedFacing.getWorldOffset(tABCCoord, tXYZOffset); + // since structure check passed, we can assume it is turbine casing + int tX = tXYZOffset[0] + aX; + int tY = tXYZOffset[1] + aY; + int tZ = tXYZOffset[2] + aZ; + // we skip the occlusion test, as we always require a working turbine to have a block of air before it + // so the front face cannot be occluded whatsoever in the most cases. + Tessellator.instance.setBrightness( + tBlock.getMixedBrightnessForBlock( + aWorld, + aX + tDirection.offsetX, + tY + tDirection.offsetY, + aZ + tDirection.offsetZ)); + tLighting.setupLighting(tBlock, tX, tY, tZ, tFacing) + .setupColor(tFacing, Dyes._NULL.mRGBa); + GT_RenderUtil.renderBlockIcon( + aRenderer, + tBlock, + tX + tDirection.offsetX * 0.01, + tY + tDirection.offsetY * 0.01, + tZ + tDirection.offsetZ * 0.01, + tTextures[i].getIcon(), + tFacing); + } + if (++tABCCoord[0] == 2) { + tABCCoord[0] = -1; + tABCCoord[1]++; + } + } + + aRenderer.field_152631_f = false; + return false; + } + + @Override + public void onValueUpdate(byte aValue) { + mHasTurbine = (aValue & 0x1) != 0; + mFormed = (aValue & 0x2) != 0; + super.onValueUpdate(aValue); + } + + @Override + public byte getUpdateData() { + return (byte) ((hasTurbine() ? 1 : 0) | (mMachine ? 2 : 0)); + } + + @Override + public boolean addToMachineList(IGregTechTileEntity tTileEntity, int aBaseCasingIndex) { + return addMaintenanceToMachineList(tTileEntity, getCasingTextureIndex()) + || addInputToMachineList(tTileEntity, getCasingTextureIndex()) + || addOutputToMachineList(tTileEntity, getCasingTextureIndex()) + || addMufflerToMachineList(tTileEntity, getCasingTextureIndex()); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + ItemStack controllerSlot = getControllerSlot(); + if ((counter & 7) == 0 + && (controllerSlot == null || !(controllerSlot.getItem() instanceof GT_MetaGenerated_Tool) + || controllerSlot.getItemDamage() < 170 + || controllerSlot.getItemDamage() > 179)) { + stopMachine(ShutDownReasonRegistry.NO_TURBINE); + return CheckRecipeResultRegistry.NO_TURBINE_FOUND; + } + ArrayList<FluidStack> tFluids = getStoredFluids(); + if (!tFluids.isEmpty()) { + + if (baseEff == 0 || optFlow == 0 + || counter >= 512 + || this.getBaseMetaTileEntity() + .hasWorkJustBeenEnabled() + || this.getBaseMetaTileEntity() + .hasInventoryBeenModified()) { + counter = 0; + baseEff = GT_Utility.safeInt( + (long) ((5F + + ((GT_MetaGenerated_Tool) controllerSlot.getItem()).getToolCombatDamage(controllerSlot)) + * 1000F)); + optFlow = GT_Utility.safeInt( + (long) Math.max( + Float.MIN_NORMAL, + ((GT_MetaGenerated_Tool) controllerSlot.getItem()).getToolStats(controllerSlot) + .getSpeedMultiplier() * GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mToolSpeed + * 50)); + + overflowMultiplier = getOverflowMultiplier(controllerSlot); + + flowMultipliers[0] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mSteamMultiplier; + flowMultipliers[1] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mGasMultiplier; + flowMultipliers[2] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mPlasmaMultiplier; + + if (optFlow <= 0 || baseEff <= 0) { + stopMachine(ShutDownReasonRegistry.NONE); // in case the turbine got removed + return CheckRecipeResultRegistry.NO_FUEL_FOUND; + } + } else { + counter++; + } + } + + int newPower = fluidIntoPower(tFluids, optFlow, baseEff, overflowMultiplier, flowMultipliers); // How much the + // turbine should + // be producing + // with this flow + int difference = newPower - this.mEUt; // difference between current output and new output + + // Magic numbers: can always change by at least 10 eu/t, but otherwise by at most 1 percent of the difference in + // power level (per tick) + // This is how much the turbine can actually change during this tick + int maxChangeAllowed = Math.max(10, GT_Utility.safeInt((long) Math.abs(difference) / 100)); + + if (Math.abs(difference) > maxChangeAllowed) { // If this difference is too big, use the maximum allowed change + int change = maxChangeAllowed * (difference > 0 ? 1 : -1); // Make the change positive or negative. + this.mEUt += change; // Apply the change + } else this.mEUt = newPower; + + if (this.mEUt <= 0) { + // stopMachine(); + this.mEUt = 0; + this.mEfficiency = 0; + return CheckRecipeResultRegistry.NO_FUEL_FOUND; + } else { + this.mMaxProgresstime = 1; + this.mEfficiencyIncrease = 10; + // Overvoltage is handled inside the MultiBlockBase when pushing out to dynamos. no need to do it here. + return CheckRecipeResultRegistry.GENERATING; + } + } + + abstract int fluidIntoPower(ArrayList<FluidStack> aFluids, int aOptFlow, int aBaseEff, int overflowMultiplier, + float[] flowMultipliers); + + abstract float getOverflowEfficiency(int totalFlow, int actualOptimalFlow, int overflowMultiplier); + + // Gets the maximum output that the turbine currently can handle. Going above this will cause the turbine to explode + public long getMaximumOutput() { + long aTotal = 0; + for (GT_MetaTileEntity_Hatch_Dynamo aDynamo : filterValidMTEs(mDynamoHatches)) { + long aVoltage = aDynamo.maxEUOutput(); + aTotal = aDynamo.maxAmperesOut() * aVoltage; + } + return aTotal; + } + + public int getOverflowMultiplier(ItemStack aStack) { + int aOverflowMultiplier = 0; + int toolQualityLevel = GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).mToolQuality; + if (toolQualityLevel >= 6) { + aOverflowMultiplier = 3; + } else if (toolQualityLevel >= 3) { + aOverflowMultiplier = 2; + } else { + aOverflowMultiplier = 1; + } + return aOverflowMultiplier; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 1; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + if (GT_Utility.isStackInvalid(aStack)) { + return 0; + } + if (aStack.getItem() instanceof GT_MetaGenerated_Tool_01) { + return 10000; + } + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return true; + } + + @Override + public String[] getInfoData() { + int mPollutionReduction = 0; + for (GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) { + mPollutionReduction = Math.max(tHatch.calculatePollutionReduction(100), mPollutionReduction); + } + + String tRunning = mMaxProgresstime > 0 + ? EnumChatFormatting.GREEN + StatCollector.translateToLocal("GT5U.turbine.running.true") + + EnumChatFormatting.RESET + : EnumChatFormatting.RED + StatCollector.translateToLocal("GT5U.turbine.running.false") + + EnumChatFormatting.RESET; + String tMaintainance = getIdealStatus() == getRepairStatus() + ? EnumChatFormatting.GREEN + StatCollector.translateToLocal("GT5U.turbine.maintenance.false") + + EnumChatFormatting.RESET + : EnumChatFormatting.RED + StatCollector.translateToLocal("GT5U.turbine.maintenance.true") + + EnumChatFormatting.RESET; + int tDura = 0; + + if (mInventory[1] != null && mInventory[1].getItem() instanceof GT_MetaGenerated_Tool_01) { + tDura = GT_Utility.safeInt( + (long) (100.0f / GT_MetaGenerated_Tool.getToolMaxDamage(mInventory[1]) + * (GT_MetaGenerated_Tool.getToolDamage(mInventory[1])) + 1)); + } + + long storedEnergy = 0; + long maxEnergy = 0; + for (GT_MetaTileEntity_Hatch_Dynamo tHatch : filterValidMTEs(mDynamoHatches)) { + storedEnergy += tHatch.getBaseMetaTileEntity() + .getStoredEU(); + maxEnergy += tHatch.getBaseMetaTileEntity() + .getEUCapacity(); + } + String[] ret = new String[] { + // 8 Lines available for information panels + tRunning + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(((long) mEUt * mEfficiency) / 10000) + + EnumChatFormatting.RESET + + " EU/t", /* 1 */ + tMaintainance, /* 2 */ + StatCollector.translateToLocal("GT5U.turbine.efficiency") + ": " + + EnumChatFormatting.YELLOW + + (mEfficiency / 100F) + + EnumChatFormatting.RESET + + "%", /* 2 */ + StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(storedEnergy) + + EnumChatFormatting.RESET + + " EU / " + + /* 3 */ EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxEnergy) + + EnumChatFormatting.RESET + + " EU", + StatCollector.translateToLocal("GT5U.turbine.flow") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(GT_Utility.safeInt((long) realOptFlow)) + + EnumChatFormatting.RESET + + " L/t" + + /* 4 */ EnumChatFormatting.YELLOW + + " (" + + (looseFit ? StatCollector.translateToLocal("GT5U.turbine.loose") + : StatCollector.translateToLocal("GT5U.turbine.tight")) + + ")", /* 5 */ + StatCollector.translateToLocal("GT5U.turbine.fuel") + ": " + + EnumChatFormatting.GOLD + + GT_Utility.formatNumbers(storedFluid) + + EnumChatFormatting.RESET + + "L", /* 6 */ + StatCollector.translateToLocal( + "GT5U.turbine.dmg") + ": " + EnumChatFormatting.RED + tDura + EnumChatFormatting.RESET + "%", /* 7 */ + StatCollector.translateToLocal("GT5U.multiblock.pollution") + ": " + + EnumChatFormatting.GREEN + + mPollutionReduction + + EnumChatFormatting.RESET + + " %" /* 8 */ + }; + if (!this.getClass() + .getName() + .contains("Steam")) + ret[4] = StatCollector.translateToLocal("GT5U.turbine.flow") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.safeInt((long) realOptFlow) + + EnumChatFormatting.RESET + + " L/t"; + return ret; + } + + public boolean hasTurbine() { + return getBaseMetaTileEntity() != null && getBaseMetaTileEntity().isClientSide() ? mHasTurbine + : this.getMaxEfficiency(mInventory[1]) > 0; + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 2, 2, 1); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 2, 2, 1, elementBudget, env, false, true); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Gas.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Gas.java new file mode 100644 index 0000000000..e84c695d68 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Gas.java @@ -0,0 +1,222 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW5; +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW_ACTIVE5; +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW_EMPTY5; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASINGS; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_LargeTurbine_Gas extends GT_MetaTileEntity_LargeTurbine { + + public GT_MetaTileEntity_LargeTurbine_Gas(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_LargeTurbine_Gas(String aName) { + super(aName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + return new ITexture[] { MACHINE_CASINGS[1][colorIndex + 1], + aFacing == side ? (aActive ? TextureFactory.builder() + .addIcon(LARGETURBINE_NEW_ACTIVE5) + .build() + : hasTurbine() ? TextureFactory.builder() + .addIcon(LARGETURBINE_NEW5) + .build() + : TextureFactory.builder() + .addIcon(LARGETURBINE_NEW_EMPTY5) + .build()) + : casingTexturePages[0][58] }; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Gas Turbine") + .addInfo("Controller block for the Large Gas Turbine") + .addInfo("Needs a Turbine, place inside controller") + .addInfo("Warning: Will be capped at 8192 EU/t in a future update") + .addInfo("See the Advanced Large Gas Turbine as the next, uncapped, option") + // .addInfo("The excess fuel that gets consumed will be voided!") + .addPollutionAmount(getPollutionPerSecond(null)) + .addSeparator() + .beginStructureBlock(3, 3, 4, true) + .addController("Front center") + .addCasingInfoRange("Stainless Steel Turbine Casing", 8, 30, false) + .addDynamoHatch("Back center", 1) + .addMaintenanceHatch("Side centered", 2) + .addMufflerHatch("Side centered", 2) + .addInputHatch("Gas Fuel, Side centered", 2) + .addOtherStructurePart("Air", "3x3 area in front of controller") + .toolTipFinisher("Gregtech"); + return tt; + } + + public int getFuelValue(FluidStack aLiquid) { + if (aLiquid == null) return 0; + GT_Recipe tFuel = RecipeMaps.gasTurbineFuels.getBackend() + .findFuel(aLiquid); + if (tFuel != null) return tFuel.mSpecialValue; + return 0; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LargeTurbine_Gas(mName); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.gasTurbineFuels; + } + + @Override + public int getRecipeCatalystPriority() { + return -1; + } + + @Override + protected boolean filtersFluid() { + return false; + } + + @Override + public Block getCasingBlock() { + return GregTech_API.sBlockCasings4; + } + + @Override + public byte getCasingMeta() { + return 10; + } + + @Override + public int getCasingTextureIndex() { + return 58; + } + + @Override + public boolean isNewStyleRendering() { + return true; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + return GT_Mod.gregtechproxy.mPollutionLargeGasTurbinePerSecond; + } + + @Override + int fluidIntoPower(ArrayList<FluidStack> aFluids, int aOptFlow, int aBaseEff, int overflowMultiplier, + float[] flowMultipliers) { + if (aFluids.size() >= 1) { + int tEU = 0; + int actualOptimalFlow = 0; + + FluidStack firstFuelType = new FluidStack(aFluids.get(0), 0); // Identify a SINGLE type of fluid to process. + // Doesn't matter which one. Ignore the rest! + int fuelValue = getFuelValue(firstFuelType); + + if (aOptFlow < fuelValue) { + // turbine too weak and/or fuel too powerful + // at least consume 1L + this.realOptFlow = 1; + // wastes the extra fuel and generate aOptFlow directly + depleteInput(new FluidStack(firstFuelType, 1)); + this.storedFluid += 1; + return GT_Utility.safeInt((long) aOptFlow * (long) aBaseEff / 10000L); + } + + actualOptimalFlow = GT_Utility.safeInt((long) (aOptFlow * flowMultipliers[1] / fuelValue)); + this.realOptFlow = actualOptimalFlow; + + // Allowed to use up to 450% optimal flow rate, depending on the value of overflowMultiplier. + // This value is chosen because the highest EU/t possible depends on the overflowMultiplier, and the formula + // used + // makes it so the flow rate for that max, per value of overflowMultiplier, is (percentage of optimal flow + // rate): + // - 150% if it is 1 + // - 300% if it is 2 + // - 450% if it is 3 + // Variable required outside of loop for multi-hatch scenarios. + int remainingFlow = GT_Utility.safeInt((long) (actualOptimalFlow * (1.5f * overflowMultiplier))); + int flow = 0; + int totalFlow = 0; + + storedFluid = 0; + for (FluidStack aFluid : aFluids) { + if (aFluid.isFluidEqual(firstFuelType)) { + flow = Math.min(aFluid.amount, remainingFlow); // try to use up to the max flow defined just above + depleteInput(new FluidStack(aFluid, flow)); // deplete that amount + this.storedFluid += aFluid.amount; + remainingFlow -= flow; // track amount we're allowed to continue depleting from hatches + totalFlow += flow; // track total input used + } + } + if (totalFlow <= 0) return 0; + tEU = GT_Utility.safeInt((long) totalFlow * fuelValue); + + if (totalFlow != actualOptimalFlow) { + float efficiency = getOverflowEfficiency(totalFlow, actualOptimalFlow, overflowMultiplier); + tEU *= efficiency; + } + tEU = GT_Utility.safeInt((long) tEU * (long) aBaseEff / 10000L); + + // EU/t output cap to properly tier the LGT against the Advanced LGT, will be implemented in a future dev + // update + /* + * if (tEU > 8192) { tEU = 8192; } + */ + + // If next output is above the maximum the dynamo can handle, set it to the maximum instead of exploding the + // turbine + // Raising the maximum allowed flow rate to account for the efficiency changes beyond the optimal flow + // When the max fuel consumption rate was increased, turbines could explode on world load + if (tEU > getMaximumOutput()) { + tEU = GT_Utility.safeInt(getMaximumOutput()); + } + return tEU; + } + return 0; + } + + @Override + float getOverflowEfficiency(int totalFlow, int actualOptimalFlow, int overflowMultiplier) { + // overflowMultiplier changes how quickly the turbine loses efficiency after flow goes beyond the optimal value + // At the default value of 1, any flow will generate less EU/t than optimal flow, regardless of the amount of + // fuel used + // The bigger this number is, the slower efficiency loss happens as flow moves beyond the optimal value + // Gases are the second most efficient in this regard, with plasma being the most efficient + float efficiency = 0; + + if (totalFlow > actualOptimalFlow) { + efficiency = 1.0f - Math.abs((totalFlow - actualOptimalFlow)) + / ((float) actualOptimalFlow * ((overflowMultiplier * 3) - 1)); + } else { + efficiency = 1.0f - Math.abs((totalFlow - actualOptimalFlow) / (float) actualOptimalFlow); + } + + return efficiency; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_GasAdvanced.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_GasAdvanced.java new file mode 100644 index 0000000000..4926655476 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_GasAdvanced.java @@ -0,0 +1,219 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW5; +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW_ACTIVE5; +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW_EMPTY5; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASINGS; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_LargeTurbine_GasAdvanced extends GT_MetaTileEntity_LargeTurbine { + + public GT_MetaTileEntity_LargeTurbine_GasAdvanced(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_LargeTurbine_GasAdvanced(String aName) { + super(aName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + return new ITexture[] { MACHINE_CASINGS[1][colorIndex + 1], + aFacing == side ? (aActive ? TextureFactory.builder() + .addIcon(LARGETURBINE_NEW_ACTIVE5) + .build() + : hasTurbine() ? TextureFactory.builder() + .addIcon(LARGETURBINE_NEW5) + .build() + : TextureFactory.builder() + .addIcon(LARGETURBINE_NEW_EMPTY5) + .build()) + : casingTexturePages[1][57] }; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Gas Turbine") + .addInfo("Warning: This is an experimental multiblock, subject to changes ") + .addInfo("Controller block for the Large Advanced Gas Turbine") + .addInfo("Needs a Turbine, place inside controller") + .addInfo("Only accepts gases above 800k EU/bucket") + .addInfo("Has no maximum EU/t output, only depends on the Dynamo Hatch") + .addPollutionAmount(getPollutionPerSecond(null)) + .addSeparator() + .beginStructureBlock(3, 3, 4, true) + .addController("Front center") + .addCasingInfoRange("Advanced Gas Turbine Casing", 8, 30, false) + .addDynamoHatch("Back center", 1) + .addMaintenanceHatch("Side centered", 2) + .addMufflerHatch("Side centered", 2) + .addInputHatch("Gas Fuel, Side centered", 2) + .toolTipFinisher("Gregtech"); + return tt; + } + + public int getFuelValue(FluidStack aLiquid) { + if (aLiquid == null) return 0; + GT_Recipe tFuel = RecipeMaps.gasTurbineFuels.getBackend() + .findFuel(aLiquid); + if (tFuel != null) return tFuel.mSpecialValue; + return 0; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LargeTurbine_GasAdvanced(mName); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.gasTurbineFuels; + } + + @Override + public int getRecipeCatalystPriority() { + return -2; + } + + @Override + protected boolean filtersFluid() { + return false; + } + + @Override + public Block getCasingBlock() { + return GregTech_API.sBlockCasings8; + } + + @Override + public byte getCasingMeta() { + return 9; + } + + @Override + public int getCasingTextureIndex() { + return 185; + } + + @Override + public boolean isNewStyleRendering() { + return true; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + return GT_Mod.gregtechproxy.mPollutionLargeGasTurbinePerSecond; + } + + @Override + int fluidIntoPower(ArrayList<FluidStack> aFluids, int aOptFlow, int aBaseEff, int overflowMultiplier, + float[] flowMultipliers) { + if (aFluids.size() >= 1) { + int tEU = 0; + int actualOptimalFlow = 0; + + FluidStack firstFuelType = new FluidStack(aFluids.get(0), 0); // Identify a SINGLE type of fluid to process. + // Doesn't matter which one. Ignore the rest! + int fuelValue = getFuelValue(firstFuelType); + + if (fuelValue < 100) { + return 0; + } + + if (aOptFlow < fuelValue) { + // turbine too weak and/or fuel too powerful + // at least consume 1L + this.realOptFlow = 1; + // wastes the extra fuel and generate aOptFlow directly + depleteInput(new FluidStack(firstFuelType, 1)); + this.storedFluid += 1; + return GT_Utility.safeInt((long) aOptFlow * (long) aBaseEff / 10000L); + } + + actualOptimalFlow = GT_Utility.safeInt((long) (aOptFlow * flowMultipliers[1] / fuelValue)); + this.realOptFlow = actualOptimalFlow; + + // Allowed to use up to 450% optimal flow rate, depending on the value of overflowMultiplier. + // This value is chosen because the highest EU/t possible depends on the overflowMultiplier, and the formula + // used + // makes it so the flow rate for that max, per value of overflowMultiplier, is (percentage of optimal flow + // rate): + // - 150% if it is 1 + // - 300% if it is 2 + // - 450% if it is 3 + // Variable required outside of loop for multi-hatch scenarios. + int remainingFlow = GT_Utility.safeInt((long) (actualOptimalFlow * (1.5f * overflowMultiplier))); + int flow = 0; + int totalFlow = 0; + + storedFluid = 0; + for (FluidStack aFluid : aFluids) { + if (aFluid.isFluidEqual(firstFuelType)) { + flow = Math.min(aFluid.amount, remainingFlow); // try to use up to the max flow defined just above + depleteInput(new FluidStack(aFluid, flow)); // deplete that amount + this.storedFluid += aFluid.amount; + remainingFlow -= flow; // track amount we're allowed to continue depleting from hatches + totalFlow += flow; // track total input used + } + } + if (totalFlow <= 0) return 0; + tEU = GT_Utility.safeInt((long) totalFlow * fuelValue); + + if (totalFlow != actualOptimalFlow) { + float efficiency = getOverflowEfficiency(totalFlow, actualOptimalFlow, overflowMultiplier); + tEU *= efficiency; + } + tEU = GT_Utility.safeInt((long) tEU * (long) aBaseEff / 10000L); + + // If next output is above the maximum the dynamo can handle, set it to the maximum instead of exploding the + // turbine + // Raising the maximum allowed flow rate to account for the efficiency changes beyond the optimal flow + // When the max fuel consumption rate was increased, turbines could explode on world load + if (tEU > getMaximumOutput()) { + tEU = GT_Utility.safeInt(getMaximumOutput()); + } + return tEU; + } + return 0; + } + + @Override + float getOverflowEfficiency(int totalFlow, int actualOptimalFlow, int overflowMultiplier) { + // overflowMultiplier changes how quickly the turbine loses efficiency after flow goes beyond the optimal value + // At the default value of 1, any flow will generate less EU/t than optimal flow, regardless of the amount of + // fuel used + // The bigger this number is, the slower efficiency loss happens as flow moves beyond the optimal value + // Gases are the second most efficient in this regard, with plasma being the most efficient + float efficiency = 0; + + if (totalFlow > actualOptimalFlow) { + efficiency = 1.0f - Math.abs((totalFlow - actualOptimalFlow)) + / ((float) actualOptimalFlow * ((overflowMultiplier * 3) - 1)); + } else { + efficiency = 1.0f - Math.abs((totalFlow - actualOptimalFlow) / (float) actualOptimalFlow); + } + + return efficiency; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_HPSteam.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_HPSteam.java new file mode 100644 index 0000000000..d61e75eac3 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_HPSteam.java @@ -0,0 +1,232 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW5; +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW_ACTIVE5; +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW_EMPTY5; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASINGS; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; +import static gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_LargeTurbine_Steam.calculateLooseFlow; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_LargeTurbine_HPSteam extends GT_MetaTileEntity_LargeTurbine { + + public boolean achievement = false; + private boolean looseFit = false; + + public GT_MetaTileEntity_LargeTurbine_HPSteam(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_LargeTurbine_HPSteam(String aName) { + super(aName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + return new ITexture[] { MACHINE_CASINGS[1][colorIndex + 1], + aFacing == side ? (aActive ? TextureFactory.builder() + .addIcon(LARGETURBINE_NEW_ACTIVE5) + .build() + : hasTurbine() ? TextureFactory.builder() + .addIcon(LARGETURBINE_NEW5) + .build() + : TextureFactory.builder() + .addIcon(LARGETURBINE_NEW_EMPTY5) + .build()) + : casingTexturePages[0][59] }; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Steam Turbine") + .addInfo("Controller block for the Large High Pressure Steam Turbine") + .addInfo("Needs a Turbine, place inside controller") + .addInfo("Outputs Steam as well as producing power") + .addInfo("Power output depends on turbine and fitting") + .addInfo("Use screwdriver to adjust fitting of turbine") + .addSeparator() + .beginStructureBlock(3, 3, 4, true) + .addController("Front center") + .addCasingInfoRange("Titanium Turbine Casing", 8, 31, false) + .addDynamoHatch("Back center", 1) + .addMaintenanceHatch("Side centered", 2) + .addInputHatch("Superheated Steam, Side centered", 2) + .addOutputHatch("Steam, Side centered", 2) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LargeTurbine_HPSteam(mName); + } + + @Override + public Block getCasingBlock() { + return GregTech_API.sBlockCasings4; + } + + @Override + public byte getCasingMeta() { + return 11; + } + + @Override + public int getCasingTextureIndex() { + return 59; + } + + @Override + public boolean isNewStyleRendering() { + return true; + } + + @Override + int fluidIntoPower(ArrayList<FluidStack> aFluids, int aOptFlow, int aBaseEff, int overflowEfficiency, + float[] flowMultipliers) { + if (looseFit) { + float[] calculatedFlow = calculateLooseFlow(aOptFlow, aBaseEff); + aOptFlow = GT_Utility.safeInt((long) calculatedFlow[0]); + aBaseEff = GT_Utility.safeInt((long) calculatedFlow[1]); + } + int tEU = 0; + int totalFlow = 0; // Byproducts are based on actual flow + int flow = 0; + + // Allowed to use up to 300% optimal flow rate, depending on the value of overflowMultiplier. + // This value is chosen because the highest EU/t possible depends on the overflowMultiplier, and the formula + // used + // makes it so the flow rate for that max, per value of overflowMultiplier, is (percentage of optimal flow + // rate): + // - 200% if it is 1 + // - 250% if it is 2 + // - 300% if it is 3 + // Variable required outside of loop for multi-hatch scenarios. + this.realOptFlow = aOptFlow * flowMultipliers[0]; + int remainingFlow = GT_Utility.safeInt((long) (realOptFlow * (0.5f * overflowMultiplier + 1.5))); + + storedFluid = 0; + for (int i = 0; i < aFluids.size() && remainingFlow > 0; i++) { + final FluidStack aFluidStack = aFluids.get(i); + if (GT_ModHandler.isSuperHeatedSteam(aFluidStack)) { + flow = Math.min(aFluidStack.amount, remainingFlow); // try to use up to the max flow defined just above + depleteInput(new FluidStack(aFluidStack, flow)); // deplete that amount + this.storedFluid += aFluidStack.amount; + remainingFlow -= flow; // track amount we're allowed to continue depleting from hatches + totalFlow += flow; // track total input used + if (!achievement) { + try { + GT_Mod.achievements.issueAchievement( + this.getBaseMetaTileEntity() + .getWorld() + .getPlayerEntityByName( + this.getBaseMetaTileEntity() + .getOwnerName()), + "efficientsteam"); + } catch (Exception ignored) {} + achievement = true; + } + } else if (GT_ModHandler.isAnySteam(aFluidStack)) { + depleteInput(new FluidStack(aFluidStack, aFluidStack.amount)); + } + } + if (totalFlow <= 0) return 0; + tEU = totalFlow; + addOutput(GT_ModHandler.getSteam(totalFlow)); + if (totalFlow == (GT_Utility.safeInt((long) realOptFlow))) { + tEU = GT_Utility.safeInt((long) tEU * (long) aBaseEff / 10000L); + } else { + float efficiency = getOverflowEfficiency( + totalFlow, + (GT_Utility.safeInt((long) realOptFlow)), + overflowMultiplier); + tEU *= efficiency; + tEU = Math.max(1, GT_Utility.safeInt((long) tEU * (long) aBaseEff / 10000L)); + } + + // If next output is above the maximum the dynamo can handle, set it to the maximum instead of exploding the + // turbine + // Raising the maximum allowed flow rate to account for the efficiency changes beyond the optimal flow rate can + // explode turbines on world load + if (tEU > getMaximumOutput()) { + tEU = GT_Utility.safeInt(getMaximumOutput()); + } + + return tEU; + } + + @Override + float getOverflowEfficiency(int totalFlow, int actualOptimalFlow, int overflowMultiplier) { + // overflowMultiplier changes how quickly the turbine loses efficiency after flow goes beyond the optimal value + // At the default value of 1, any flow will generate less EU/t than optimal flow, regardless of the amount of + // fuel used + // The bigger this number is, the slower efficiency loss happens as flow moves beyond the optimal value + // Superheated steam is the second least efficient out of all turbine fuels in this regard, with steam being the + // least efficient + float efficiency = 0; + + if (totalFlow > actualOptimalFlow) { + efficiency = 1.0f + - Math.abs((totalFlow - actualOptimalFlow)) / ((float) actualOptimalFlow * (overflowMultiplier + 2)); + } else { + efficiency = 1.0f - Math.abs((totalFlow - actualOptimalFlow) / (float) actualOptimalFlow); + } + + return efficiency; + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (side == getBaseMetaTileEntity().getFrontFacing()) { + looseFit ^= true; + GT_Utility.sendChatToPlayer( + aPlayer, + looseFit ? GT_Utility.trans("500", "Fitting: Loose - More Flow") + : GT_Utility.trans("501", "Fitting: Tight - More Efficiency")); + } + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return (looseFit && XSTR_INSTANCE.nextInt(4) == 0) ? 0 : 1; + } + + @Override + public String[] getInfoData() { + super.looseFit = looseFit; + return super.getInfoData(); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setBoolean("turbineFitting", looseFit); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + looseFit = aNBT.getBoolean("turbineFitting"); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Plasma.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Plasma.java new file mode 100644 index 0000000000..2ecc79cd3b --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Plasma.java @@ -0,0 +1,391 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW5; +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW_ACTIVE5; +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW_EMPTY5; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASINGS; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.items.GT_MetaGenerated_Tool; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; +import gregtech.common.items.GT_MetaGenerated_Tool_01; + +public class GT_MetaTileEntity_LargeTurbine_Plasma extends GT_MetaTileEntity_LargeTurbine { + + public GT_MetaTileEntity_LargeTurbine_Plasma(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_LargeTurbine_Plasma(String aName) { + super(aName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + return new ITexture[] { MACHINE_CASINGS[1][colorIndex + 1], + aFacing == side ? (aActive ? TextureFactory.builder() + .addIcon(LARGETURBINE_NEW_ACTIVE5) + .build() + : hasTurbine() ? TextureFactory.builder() + .addIcon(LARGETURBINE_NEW5) + .build() + : TextureFactory.builder() + .addIcon(LARGETURBINE_NEW_EMPTY5) + .build()) + : casingTexturePages[0][60] }; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Plasma Turbine") + .addInfo("Controller block for the Large Plasma Generator") + .addInfo("Needs a Turbine, place inside controller") + .addInfo("Use your Fusion Reactor to produce the Plasma") + .addSeparator() + .beginStructureBlock(3, 3, 4, true) + .addController("Front center") + .addCasingInfoRange("Tungstensteel Turbine Casing", 8, 31, false) + .addDynamoHatch("Back center", 1) + .addMaintenanceHatch("Side centered", 2) + .addInputHatch("Plasma Fluid, Side centered", 2) + .addOutputHatch("Molten Fluid, optional, Side centered", 2) + .toolTipFinisher("Gregtech"); + return tt; + } + + public int getFuelValue(FluidStack aLiquid) { + if (aLiquid == null) return 0; + GT_Recipe tFuel = RecipeMaps.plasmaFuels.getBackend() + .findFuel(aLiquid); + if (tFuel != null) return tFuel.mSpecialValue; + return 0; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LargeTurbine_Plasma(mName); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.plasmaFuels; + } + + @Override + public int getRecipeCatalystPriority() { + return -1; + } + + @Override + protected boolean filtersFluid() { + return false; + } + + @Override + public Block getCasingBlock() { + return GregTech_API.sBlockCasings4; + } + + @Override + public byte getCasingMeta() { + return 12; + } + + @Override + public int getCasingTextureIndex() { + return 60; + } + + @Override + public boolean isNewStyleRendering() { + return true; + } + + @Override + int fluidIntoPower(ArrayList<FluidStack> aFluids, int aOptFlow, int aBaseEff, int overflowMultiplier, + float[] flowMultipliers) { + if (aFluids.size() >= 1) { + aOptFlow *= 800; // CHANGED THINGS HERE, check recipe runs once per 20 ticks + int tEU = 0; + + int actualOptimalFlow = 0; + + FluidStack firstFuelType = new FluidStack(aFluids.get(0), 0); // Identify a SINGLE type of fluid to process. + // Doesn't matter which one. Ignore the rest! + int fuelValue = getFuelValue(firstFuelType); + actualOptimalFlow = GT_Utility + .safeInt((long) Math.ceil((double) aOptFlow * flowMultipliers[2] / (double) fuelValue)); + this.realOptFlow = actualOptimalFlow; // For scanner info + + // Allowed to use up to 550% optimal flow rate, depending on the value of overflowMultiplier. + // This value is chosen because the highest EU/t possible depends on the overflowMultiplier, and the formula + // used + // makes it so the flow rate for that max, per value of overflowMultiplier, is (percentage of optimal flow + // rate): + // - 250% if it is 1 + // - 400% if it is 2 + // - 550% if it is 3 + // Variable required outside of loop for multi-hatch scenarios. + int remainingFlow = GT_Utility.safeInt((long) (actualOptimalFlow * (1.5f * overflowMultiplier + 1))); + int flow = 0; + int totalFlow = 0; + + storedFluid = 0; + for (FluidStack aFluid : aFluids) { + if (aFluid.isFluidEqual(firstFuelType)) { + flow = Math.min(aFluid.amount, remainingFlow); // try to use up to the max flow defined just above + depleteInput(new FluidStack(aFluid, flow)); // deplete that amount + this.storedFluid += aFluid.amount; + remainingFlow -= flow; // track amount we're allowed to continue depleting from hatches + totalFlow += flow; // track total input used + } + } + String fn = FluidRegistry.getFluidName(firstFuelType); + String[] nameSegments = fn.split("\\.", 2); + if (nameSegments.length == 2) { + String outputName = nameSegments[1]; + FluidStack output = FluidRegistry.getFluidStack(outputName, totalFlow); + if (output == null) { + output = FluidRegistry.getFluidStack("molten." + outputName, totalFlow); + } + if (output != null) { + addOutput(output); + } + } + if (totalFlow <= 0) return 0; + tEU = GT_Utility.safeInt((long) ((fuelValue / 20D) * (double) totalFlow)); + + // GT_FML_LOGGER.info(totalFlow+" : "+fuelValue+" : "+aOptFlow+" : "+actualOptimalFlow+" : "+tEU); + + if (totalFlow != actualOptimalFlow) { + float efficiency = getOverflowEfficiency(totalFlow, actualOptimalFlow, overflowMultiplier); + tEU = (int) (tEU * efficiency); + } + tEU = GT_Utility.safeInt((long) (aBaseEff / 10000D * tEU)); + + // If next output is above the maximum the dynamo can handle, set it to the maximum instead of exploding the + // turbine + // Raising the maximum allowed flow rate to account for the efficiency changes beyond the optimal flow rate + // can explode turbines on world load + if (tEU > getMaximumOutput()) { + tEU = GT_Utility.safeInt(getMaximumOutput()); + } + + return tEU; + } + return 0; + } + + @Override + float getOverflowEfficiency(int totalFlow, int actualOptimalFlow, int overflowMultiplier) { + // overflowMultiplier changes how quickly the turbine loses efficiency after flow goes beyond the optimal value + // At the default value of 1, any flow will generate less EU/t than optimal flow, regardless of the amount of + // fuel used + // The bigger this number is, the slower efficiency loss happens as flow moves beyond the optimal value + // Plasmas are the most efficient out of all turbine fuels in this regard + float efficiency = 0; + + if (totalFlow > actualOptimalFlow) { + efficiency = 1.0f - Math.abs((totalFlow - actualOptimalFlow)) + / ((float) actualOptimalFlow * ((overflowMultiplier * 3) + 1)); + } else { + efficiency = 1.0f - Math.abs((totalFlow - actualOptimalFlow) / (float) actualOptimalFlow); + } + + return efficiency; + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + ItemStack controllerSlot = getControllerSlot(); + if ((counter & 7) == 0 + && (controllerSlot == null || !(controllerSlot.getItem() instanceof GT_MetaGenerated_Tool) + || controllerSlot.getItemDamage() < 170 + || controllerSlot.getItemDamage() > 179)) { + stopMachine(ShutDownReasonRegistry.NO_TURBINE); + return CheckRecipeResultRegistry.NO_TURBINE_FOUND; + } + ArrayList<FluidStack> tFluids = getStoredFluids(); + if (!tFluids.isEmpty()) { + if (baseEff == 0 || optFlow == 0 + || counter >= 512 + || this.getBaseMetaTileEntity() + .hasWorkJustBeenEnabled() + || this.getBaseMetaTileEntity() + .hasInventoryBeenModified()) { + counter = 0; + baseEff = GT_Utility.safeInt( + (long) ((5F + + ((GT_MetaGenerated_Tool) controllerSlot.getItem()).getToolCombatDamage(controllerSlot)) + * 1000F)); + optFlow = GT_Utility.safeInt( + (long) Math.max( + Float.MIN_NORMAL, + ((GT_MetaGenerated_Tool) controllerSlot.getItem()).getToolStats(controllerSlot) + .getSpeedMultiplier() * GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mToolSpeed + * 50)); + overflowMultiplier = getOverflowMultiplier(controllerSlot); + + flowMultipliers[0] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mSteamMultiplier; + flowMultipliers[1] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mGasMultiplier; + flowMultipliers[2] = GT_MetaGenerated_Tool.getPrimaryMaterial(controllerSlot).mPlasmaMultiplier; + + if (optFlow <= 0 || baseEff <= 0) { + stopMachine(ShutDownReasonRegistry.NONE); // in case the turbine got removed + return CheckRecipeResultRegistry.NO_FUEL_FOUND; + } + } else { + counter++; + } + } + + int newPower = fluidIntoPower(tFluids, optFlow, baseEff, overflowMultiplier, flowMultipliers); // How much the + // turbine should + // be producing + // with this flow + + int difference = newPower - this.mEUt; // difference between current output and new output + + // Magic numbers: can always change by at least 10 eu/t, but otherwise by at most 1 percent of the difference in + // power level (per tick) + // This is how much the turbine can actually change during this tick + int maxChangeAllowed = Math.max(200, GT_Utility.safeInt((long) Math.abs(difference) / 5)); + + if (Math.abs(difference) > maxChangeAllowed) { // If this difference is too big, use the maximum allowed change + int change = maxChangeAllowed * (difference > 0 ? 1 : -1); // Make the change positive or negative. + this.mEUt += change; // Apply the change + } else this.mEUt = newPower; + + if (this.mEUt <= 0) { + // stopMachine(); + this.mEUt = 0; + this.mEfficiency = 0; + return CheckRecipeResultRegistry.NO_FUEL_FOUND; + } else { + this.mMaxProgresstime = 20; + this.mEfficiencyIncrease = 200; + // Overvoltage is handled inside the MultiBlockBase when pushing out to dynamos. no need to do it here. + + return CheckRecipeResultRegistry.GENERATING; + } + } + + @Override + public String[] getInfoData() { + int mPollutionReduction = 0; + for (GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) { + mPollutionReduction = Math.max(tHatch.calculatePollutionReduction(100), mPollutionReduction); + } + + String tRunning = mMaxProgresstime > 0 + ? EnumChatFormatting.GREEN + StatCollector.translateToLocal("GT5U.turbine.running.true") + + EnumChatFormatting.RESET + : EnumChatFormatting.RED + StatCollector.translateToLocal("GT5U.turbine.running.false") + + EnumChatFormatting.RESET; + String tMaintainance = getIdealStatus() == getRepairStatus() + ? EnumChatFormatting.GREEN + StatCollector.translateToLocal("GT5U.turbine.maintenance.false") + + EnumChatFormatting.RESET + : EnumChatFormatting.RED + StatCollector.translateToLocal("GT5U.turbine.maintenance.true") + + EnumChatFormatting.RESET; + int tDura = 0; + + if (mInventory[1] != null && mInventory[1].getItem() instanceof GT_MetaGenerated_Tool_01) { + tDura = GT_Utility.safeInt( + (long) (100.0f / GT_MetaGenerated_Tool.getToolMaxDamage(mInventory[1]) + * (GT_MetaGenerated_Tool.getToolDamage(mInventory[1])) + 1)); + } + + long storedEnergy = 0; + long maxEnergy = 0; + for (GT_MetaTileEntity_Hatch_Dynamo tHatch : filterValidMTEs(mDynamoHatches)) { + storedEnergy += tHatch.getBaseMetaTileEntity() + .getStoredEU(); + maxEnergy += tHatch.getBaseMetaTileEntity() + .getEUCapacity(); + } + String[] ret = new String[] { + // 8 Lines available for information panels + tRunning + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(((long) mEUt * mEfficiency) / 10000) + + EnumChatFormatting.RESET + + " EU/t", /* 1 */ + tMaintainance, /* 2 */ + StatCollector.translateToLocal("GT5U.turbine.efficiency") + ": " + + EnumChatFormatting.YELLOW + + (mEfficiency / 100F) + + EnumChatFormatting.RESET + + "%", /* 2 */ + StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(storedEnergy) + + EnumChatFormatting.RESET + + " EU / " + + /* 3 */ EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxEnergy) + + EnumChatFormatting.RESET + + " EU", + StatCollector.translateToLocal("GT5U.turbine.flow") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(GT_Utility.safeInt((long) realOptFlow)) + + EnumChatFormatting.RESET + + " L/s" + + /* 4 */ EnumChatFormatting.YELLOW + + " (" + + (looseFit ? StatCollector.translateToLocal("GT5U.turbine.loose") + : StatCollector.translateToLocal("GT5U.turbine.tight")) + + ")", /* 5 */ + StatCollector.translateToLocal("GT5U.turbine.fuel") + ": " + + EnumChatFormatting.GOLD + + GT_Utility.formatNumbers(storedFluid) + + EnumChatFormatting.RESET + + "L", /* 6 */ + StatCollector.translateToLocal( + "GT5U.turbine.dmg") + ": " + EnumChatFormatting.RED + tDura + EnumChatFormatting.RESET + "%", /* 7 */ + StatCollector.translateToLocal("GT5U.multiblock.pollution") + ": " + + EnumChatFormatting.GREEN + + mPollutionReduction + + EnumChatFormatting.RESET + + " %" /* 8 */ + }; + if (!this.getClass() + .getName() + .contains("Steam")) + ret[4] = StatCollector.translateToLocal("GT5U.turbine.flow") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.safeInt((long) realOptFlow) + + EnumChatFormatting.RESET + + " L/s"; + return ret; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Steam.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Steam.java new file mode 100644 index 0000000000..849d0af462 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_LargeTurbine_Steam.java @@ -0,0 +1,273 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.GT_Values.STEAM_PER_WATER; +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW5; +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW_ACTIVE5; +import static gregtech.api.enums.Textures.BlockIcons.LARGETURBINE_NEW_EMPTY5; +import static gregtech.api.enums.Textures.BlockIcons.MACHINE_CASINGS; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; + +import java.util.ArrayList; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_LargeTurbine_Steam extends GT_MetaTileEntity_LargeTurbine { + + private int excessWater; + private boolean achievement = false; + private boolean looseFit = false; + + public GT_MetaTileEntity_LargeTurbine_Steam(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_LargeTurbine_Steam(String aName) { + super(aName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + return new ITexture[] { MACHINE_CASINGS[1][colorIndex + 1], + aFacing == side ? (aActive ? TextureFactory.builder() + .addIcon(LARGETURBINE_NEW_ACTIVE5) + .build() + : hasTurbine() ? TextureFactory.builder() + .addIcon(LARGETURBINE_NEW5) + .build() + : TextureFactory.builder() + .addIcon(LARGETURBINE_NEW_EMPTY5) + .build()) + : casingTexturePages[0][57] }; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Steam Turbine") + .addInfo("Controller block for the Large Steam Turbine") + .addInfo("Needs a Turbine, place inside controller") + .addInfo("Outputs Distilled Water as well as producing power") + .addInfo("Power output depends on turbine and fitting") + .addInfo("Use screwdriver to adjust fitting of turbine") + .addSeparator() + .beginStructureBlock(3, 3, 4, true) + .addController("Front center") + .addCasingInfoRange("Turbine Casing", 8, 31, false) + .addDynamoHatch("Back center", 1) + .addMaintenanceHatch("Side centered", 2) + .addInputHatch("Steam, Side centered", 2) + .addOutputHatch("Distilled Water, Side centered", 2) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_LargeTurbine_Steam(mName); + } + + @Override + public Block getCasingBlock() { + return GregTech_API.sBlockCasings4; + } + + @Override + public byte getCasingMeta() { + return 9; + } + + @Override + public int getCasingTextureIndex() { + return 16; + } + + @Override + public boolean isNewStyleRendering() { + return true; + } + + private int condenseSteam(int steam) { + excessWater += steam; + int water = excessWater / STEAM_PER_WATER; + excessWater %= STEAM_PER_WATER; + return water; + } + + @Override + int fluidIntoPower(ArrayList<FluidStack> aFluids, int aOptFlow, int aBaseEff, int overflowEfficiency, + float[] flowMultipliers) { + if (looseFit) { + float[] calculatedFlow = calculateLooseFlow(aOptFlow, aBaseEff); + aOptFlow = GT_Utility.safeInt((long) calculatedFlow[0]); + aBaseEff = GT_Utility.safeInt((long) calculatedFlow[1]); + } + int tEU = 0; + int totalFlow = 0; // Byproducts are based on actual flow + int flow = 0; + + // Allowed to use up to 250% optimal flow rate, depending on the value of overflowMultiplier. + // This value is chosen because the highest EU/t possible depends on the overflowMultiplier, and the formula + // used + // makes it so the flow rate for that max, per value of overflowMultiplier, is (percentage of optimal flow + // rate): + // - 150% if it is 1 + // - 200% if it is 2 + // - 250% if it is 3 + // Variable required outside of loop for multi-hatch scenarios. + this.realOptFlow = aOptFlow * flowMultipliers[0]; + int remainingFlow = GT_Utility.safeInt((long) (realOptFlow * (0.5f * overflowMultiplier + 1))); + + storedFluid = 0; + for (int i = 0; i < aFluids.size() && remainingFlow > 0; i++) { // loop through each hatch; extract inputs and + // track totals. + final FluidStack aFluidStack = aFluids.get(i); + if (GT_ModHandler.isAnySteam(aFluidStack)) { + flow = Math.min(aFluidStack.amount, remainingFlow); // try to use up to the max flow defined just above + depleteInput(new FluidStack(aFluidStack, flow)); // deplete that amount + this.storedFluid += aFluidStack.amount; + remainingFlow -= flow; // track amount we're allowed to continue depleting from hatches + totalFlow += flow; // track total input used + if (!achievement) { + GT_Mod.achievements.issueAchievement( + this.getBaseMetaTileEntity() + .getWorld() + .getPlayerEntityByName( + this.getBaseMetaTileEntity() + .getOwnerName()), + "muchsteam"); + achievement = true; + } + } else if (GT_ModHandler.isSuperHeatedSteam(aFluidStack)) { + depleteInput(new FluidStack(aFluidStack, aFluidStack.amount)); + } + } + if (totalFlow <= 0) return 0; + tEU = totalFlow; + int waterToOutput = condenseSteam(totalFlow); + addOutput(GT_ModHandler.getDistilledWater(waterToOutput)); + if (totalFlow == (GT_Utility.safeInt((long) realOptFlow))) { + tEU = GT_Utility.safeInt((long) tEU * (long) aBaseEff / 20000L); + } else { + float efficiency = getOverflowEfficiency( + totalFlow, + (GT_Utility.safeInt((long) realOptFlow)), + overflowMultiplier); + tEU *= efficiency; + tEU = Math.max(1, GT_Utility.safeInt((long) tEU * (long) aBaseEff / 20000L)); + } + + // If next output is above the maximum the dynamo can handle, set it to the maximum instead of exploding the + // turbine + // Raising the maximum allowed flow rate to account for the efficiency changes beyond the optimal flow rate can + // explode turbines on world load + if (tEU > getMaximumOutput()) { + tEU = GT_Utility.safeInt(getMaximumOutput()); + } + + return tEU; + } + + @Override + float getOverflowEfficiency(int totalFlow, int actualOptimalFlow, int overflowMultiplier) { + // overflowMultiplier changes how quickly the turbine loses efficiency after flow goes beyond the optimal value + // At the default value of 1, any flow will generate less EU/t than optimal flow, regardless of the amount of + // fuel used + // The bigger this number is, the slower efficiency loss happens as flow moves beyond the optimal value + // Steam is the least efficient out of all turbine fuels in this regard + float efficiency = 0; + + if (totalFlow > actualOptimalFlow) { + efficiency = 1.0f + - Math.abs((totalFlow - actualOptimalFlow)) / ((float) actualOptimalFlow * (overflowMultiplier + 1)); + } else { + efficiency = 1.0f - Math.abs((totalFlow - actualOptimalFlow) / (float) actualOptimalFlow); + } + + return efficiency; + } + + public static float[] calculateLooseFlow(float aOptFlow, float aBaseEff) { + aOptFlow *= 4f; + if (aBaseEff >= 26000f) { + aOptFlow = aOptFlow * (float) Math.pow(1.1f, ((aBaseEff - 8000f) / 10000f) * 20f); + aBaseEff = aBaseEff * 0.6f; + } else if (aBaseEff > 22000f) { + aOptFlow = aOptFlow * (float) Math.pow(1.1f, ((aBaseEff - 7000f) / 10000f) * 20f); + aBaseEff = aBaseEff * 0.65f; + } else if (aBaseEff > 18000f) { + aOptFlow = aOptFlow * (float) Math.pow(1.1f, ((aBaseEff - 6000f) / 10000f) * 20f); + aBaseEff = aBaseEff * 0.70f; + } else if (aBaseEff > 14000f) { + aOptFlow = aOptFlow * (float) Math.pow(1.1f, ((aBaseEff - 5000f) / 10000f) * 20f); + aBaseEff = aBaseEff * 0.75f; + } else if (aBaseEff > 10000f) { + aOptFlow = aOptFlow * (float) Math.pow(1.1f, ((aBaseEff - 4000f) / 10000f) * 20f); + aBaseEff = aBaseEff * 0.8f; + } else if (aBaseEff > 6000f) { + aOptFlow = aOptFlow * (float) Math.pow(1.1f, ((aBaseEff - 3000f) / 10000f) * 20f); + aBaseEff = aBaseEff * 0.85f; + } else { + aBaseEff = aBaseEff * 0.9f; + } + + if (aBaseEff % 100 != 0) { + aBaseEff -= aBaseEff % 100; + } + + float[] looseFlow = new float[2]; + looseFlow[0] = aOptFlow; + looseFlow[1] = aBaseEff; + return looseFlow; + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (side == getBaseMetaTileEntity().getFrontFacing()) { + looseFit ^= true; + GT_Utility.sendChatToPlayer( + aPlayer, + looseFit ? GT_Utility.trans("500", "Fitting: Loose - More Flow") + : GT_Utility.trans("501", "Fitting: Tight - More Efficiency")); + } + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return (looseFit && XSTR_INSTANCE.nextInt(4) == 0) ? 0 : 1; + } + + @Override + public String[] getInfoData() { + super.looseFit = looseFit; + return super.getInfoData(); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setBoolean("turbineFitting", looseFit); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + looseFit = aNBT.getBoolean("turbineFitting"); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_MultiFurnace.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_MultiFurnace.java new file mode 100644 index 0000000000..4f24b769d0 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_MultiFurnace.java @@ -0,0 +1,335 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.Muffler; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_MULTI_SMELTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_MULTI_SMELTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_MULTI_SMELTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_MULTI_SMELTER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.ArrayList; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.HeatingCoilLevel; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_StructureUtility; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_MultiFurnace + extends GT_MetaTileEntity_AbstractMultiFurnace<GT_MetaTileEntity_MultiFurnace> implements ISurvivalConstructable { + + private int mLevel = 0; + private int mCostDiscount = 1; + + private static final int CASING_INDEX = 11; + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final IStructureDefinition<GT_MetaTileEntity_MultiFurnace> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_MultiFurnace>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose(new String[][] { { "ccc", "cmc", "ccc" }, { "CCC", "C-C", "CCC" }, { "b~b", "bbb", "bbb" } })) + .addElement('c', ofBlock(GregTech_API.sBlockCasings1, CASING_INDEX)) + .addElement('m', Muffler.newAny(CASING_INDEX, 2)) + .addElement( + 'C', + GT_StructureUtility + .ofCoil(GT_MetaTileEntity_MultiFurnace::setCoilLevel, GT_MetaTileEntity_MultiFurnace::getCoilLevel)) + .addElement( + 'b', + ofChain( + GT_StructureUtility.<GT_MetaTileEntity_MultiFurnace>buildHatchAdder() + .atLeast(Maintenance, InputBus, OutputBus, Energy) + .casingIndex(CASING_INDEX) + .dot(1) + .build(), + ofBlock(GregTech_API.sBlockCasings1, CASING_INDEX))) + .build(); + + public GT_MetaTileEntity_MultiFurnace(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_MultiFurnace(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_MultiFurnace(this.mName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Furnace") + .addInfo("Controller Block for the Multi Smelter") + .addInfo("Smelts up to 8-8192 items at once") + .addInfo("Items smelted increases with coil tier") + .addPollutionAmount(getPollutionPerSecond(null)) + .addSeparator() + .beginStructureBlock(3, 3, 3, true) + .addController("Front bottom") + .addCasingInfoRange("Heat Proof Machine Casing", 8, 14, false) + .addOtherStructurePart("Heating Coils", "Middle layer") + .addEnergyHatch("Any bottom casing", 1) + .addMaintenanceHatch("Any bottom casing", 1) + .addMufflerHatch("Top Middle", 2) + .addInputBus("Any bottom casing", 1) + .addOutputBus("Any bottom casing", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + if (sideDirection != facingDirection) return new ITexture[] { casingTexturePages[0][CASING_INDEX] }; + if (active) return new ITexture[] { casingTexturePages[0][CASING_INDEX], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_MULTI_SMELTER_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_MULTI_SMELTER_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { casingTexturePages[0][CASING_INDEX], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_MULTI_SMELTER) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_MULTI_SMELTER_GLOW) + .extFacing() + .glow() + .build() }; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.furnaceRecipes; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + return GT_Mod.gregtechproxy.mPollutionMultiSmelterPerSecond; + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + ArrayList<ItemStack> tInputList = getAllStoredInputs(); + if (tInputList.isEmpty()) return CheckRecipeResultRegistry.NO_RECIPE; + + int mVolatage = GT_Utility.safeInt(getMaxInputVoltage()); + int tMaxParallel = this.mLevel; + int tCurrentParallel = 0; + ArrayList<ItemStack> smeltedOutputs = new ArrayList<>(); + ArrayList<Integer> outputStackSizes = new ArrayList<>(); + for (ItemStack item : tInputList) { + ItemStack smeltedOutput = GT_ModHandler.getSmeltingOutput(item, false, null); + if (smeltedOutput != null) { + smeltedOutputs.add(smeltedOutput); + if (item.stackSize <= (tMaxParallel - tCurrentParallel)) { + tCurrentParallel += item.stackSize; + outputStackSizes.add(smeltedOutput.stackSize * item.stackSize); + item.stackSize = 0; + } else { + int remainingStackSize = tCurrentParallel + item.stackSize - tMaxParallel; + outputStackSizes.add(smeltedOutput.stackSize * (item.stackSize - remainingStackSize)); + item.stackSize = remainingStackSize; + break; + } + } + if (tCurrentParallel == tMaxParallel) { + break; + } + } + this.mOutputItems = new ItemStack[smeltedOutputs.size()]; + for (int i = 0; i < this.mOutputItems.length; i++) { + ItemStack tNewStack = smeltedOutputs.get(i); + tNewStack.stackSize = outputStackSizes.get(i); + this.mOutputItems[i] = tNewStack; + } + + if (this.mOutputItems.length > 0) { + this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); + this.mEfficiencyIncrease = 10000; + calculateOverclockedNessMultiInternal(4, 512, 1, mVolatage, false); + // In case recipe is too OP for that machine + if (mMaxProgresstime == Integer.MAX_VALUE - 1 && mEUt == Integer.MAX_VALUE - 1) + return CheckRecipeResultRegistry.NO_RECIPE; + + this.mEUt = GT_Utility.safeInt(((long) mEUt) * (this.mLevel / 8) / (long) this.mCostDiscount, 1); + if (mEUt == Integer.MAX_VALUE - 1) return CheckRecipeResultRegistry.NO_RECIPE; + + if (this.mEUt > 0) this.mEUt = (-this.mEUt); + } + updateSlots(); + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_MultiFurnace> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + this.mLevel = 0; + this.mCostDiscount = 1; + + replaceDeprecatedCoils(aBaseMetaTileEntity); + + setCoilLevel(HeatingCoilLevel.None); + + if (!checkPiece(STRUCTURE_PIECE_MAIN, 1, 2, 0)) return false; + + if (getCoilLevel() == HeatingCoilLevel.None) return false; + + if (mMaintenanceHatches.size() != 1) return false; + + if (getCoilLevel().getHeat() < 9000) { + this.mLevel = 8 * getCoilLevel().getLevel(); + } else { + this.mLevel = 1 << (getCoilLevel().getTier()); + } + this.mCostDiscount = getCoilLevel().getCostDiscount(); + return true; + } + + private void replaceDeprecatedCoils(IGregTechTileEntity aBaseMetaTileEntity) { + final int xDir = aBaseMetaTileEntity.getBackFacing().offsetX; + final int zDir = aBaseMetaTileEntity.getBackFacing().offsetZ; + final int tX = aBaseMetaTileEntity.getXCoord() + xDir; + final int tY = aBaseMetaTileEntity.getYCoord(); + final int tZ = aBaseMetaTileEntity.getZCoord() + zDir; + int tUsedMeta; + for (int xPos = tX - 1; xPos <= tX + 1; xPos++) for (int zPos = tZ - 1; zPos <= tZ + 1; zPos++) { + if ((xPos == tX) && (zPos == tZ)) continue; + tUsedMeta = aBaseMetaTileEntity.getMetaID(xPos, tY + 1, zPos); + if (tUsedMeta >= 12 && tUsedMeta <= 14 + && aBaseMetaTileEntity.getBlock(xPos, tY + 1, zPos) == GregTech_API.sBlockCasings1) + aBaseMetaTileEntity.getWorld() + .setBlock(xPos, tY + 1, zPos, GregTech_API.sBlockCasings5, tUsedMeta - 12, 3); + } + } + + @Override + public String[] getInfoData() { + int mPollutionReduction = 0; + for (final GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) + mPollutionReduction = Math.max(tHatch.calculatePollutionReduction(100), mPollutionReduction); + + long storedEnergy = 0; + long maxEnergy = 0; + for (final GT_MetaTileEntity_Hatch_Energy tHatch : filterValidMTEs(mEnergyHatches)) { + storedEnergy += tHatch.getBaseMetaTileEntity() + .getStoredEU(); + maxEnergy += tHatch.getBaseMetaTileEntity() + .getEUCapacity(); + } + + return new String[] { + StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mProgresstime / 20) + + EnumChatFormatting.RESET + + " s / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mMaxProgresstime / 20) + + EnumChatFormatting.RESET + + " s", + StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(storedEnergy) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxEnergy) + + EnumChatFormatting.RESET + + " EU", + StatCollector.translateToLocal("GT5U.multiblock.usage") + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(-mEUt) + + EnumChatFormatting.RESET + + " EU/t", + StatCollector.translateToLocal("GT5U.multiblock.mei") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(getMaxInputVoltage()) + + EnumChatFormatting.RESET + + " EU/t(*2A) " + + StatCollector.translateToLocal("GT5U.machines.tier") + + ": " + + EnumChatFormatting.YELLOW + + VN[GT_Utility.getTier(getMaxInputVoltage())] + + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.multiblock.problems") + ": " + + EnumChatFormatting.RED + + (getIdealStatus() - getRepairStatus()) + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.multiblock.efficiency") + + ": " + + EnumChatFormatting.YELLOW + + mEfficiency / 100.0F + + EnumChatFormatting.RESET + + " %", + StatCollector.translateToLocal("GT5U.MS.multismelting") + ": " + + EnumChatFormatting.GREEN + + mLevel + + EnumChatFormatting.RESET + + " Discount: (EU/t) / " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mCostDiscount) + + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.multiblock.pollution") + ": " + + EnumChatFormatting.GREEN + + mPollutionReduction + + EnumChatFormatting.RESET + + " %" }; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 1, 2, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 1, 2, 0, elementBudget, env, false, true); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_NanoForge.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_NanoForge.java new file mode 100644 index 0000000000..4b0dc16943 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_NanoForge.java @@ -0,0 +1,467 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.ExoticEnergy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_Values.AuthorBlueWeabo; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE_GLOW; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.ofFrame; + +import javax.annotation.Nonnull; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.Materials; +import gregtech.api.enums.MaterialsUEVplus; +import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.common.blocks.GT_Block_Casings8; + +public class GT_MetaTileEntity_NanoForge extends + GT_MetaTileEntity_ExtendedPowerMultiBlockBase<GT_MetaTileEntity_NanoForge> implements ISurvivalConstructable { + + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final String STRUCTURE_PIECE_TIER2 = "tier2"; + private static final String STRUCTURE_PIECE_TIER3 = "tier3"; + private static final IStructureDefinition<GT_MetaTileEntity_NanoForge> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_NanoForge>builder() + // spotless:off + .addShape(STRUCTURE_PIECE_MAIN, transpose(new String[][] { + {" "," "," F "," C "," C "," C "," C "," F "," "," "}, + {" "," "," F "," C "," C "," C "," C "," F "," "," "}, + {" "," "," F "," C "," C "," C "," C "," F "," "," "}, + {" "," "," F "," C "," C "," C "," C "," F "," "," "}, + {" "," "," F "," C "," C "," C "," C "," F "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," FCF "," FC CF "," C C "," C C "," C C "," C C "," FC CF "," FCF "," "}, + {" "," FCF "," FC CF "," C C "," C C "," C C "," C C "," FC CF "," FCF "," "}, + {" "," FCF "," FC CF "," C C "," C C "," C C "," C C "," FC CF "," FCF "," "}, + {" "," FCF "," FC CF "," C C "," C C "," C C "," C C "," FC CF "," FCF "," "}, + {" C "," FCF "," CC CC "," C C "," C C "," C C "," C C "," CC CC "," FCF "," C "}, + {" C "," FCF "," CC CC "," C C "," C C "," C C "," C C "," CC CC "," FCF "," C "}, + {" C "," FCF "," CC CC "," C C "," C C "," C C "," C C "," CC CC "," FCF "," C "}, + {" C "," FCF "," CC CC "," CC CC "," CC CC "," CC CC "," CC CC "," CC CC "," FCF "," C "}, + {" C "," FCF "," CC CC "," CC CC "," CC CC "," CC CC "," CC CC "," CC CC "," FCF "," C "}, + {" C "," FCF "," CC CC "," C C "," C C "," C C "," C C "," CC CC "," FCF "," C "}, + {" C "," FCF "," CC CC "," C C "," C C "," C C "," C C "," CC CC "," FCF "," C "}, + {" C "," FCF "," CC CC "," C C "," C C "," C C "," C C "," CC CC "," FCF "," C "}, + {" "," FCF "," FC CF "," C C "," C C "," C C "," C C "," FC CF "," FCF "," "}, + {" "," FCF "," FC CF "," C C "," C C "," C C "," C C "," FC CF "," FCF "," "}, + {" "," FCF "," FC CF "," C C "," C C "," C C "," C C "," FC CF "," FCF "," "}, + {" "," FCF "," FC CF "," C C "," C C "," C C "," C C "," FC CF "," FCF "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," "," FCF "," C C "," C C "," C C "," C C "," FCF "," "," "}, + {" "," BB~BB "," BBBBBBB ","BBBBBBBBB","BBBBBBBBB","BBBBBBBBB","BBBBBBBBB"," BBBBBBB "," BBBBB "," "} + })) + .addShape(STRUCTURE_PIECE_TIER2, transpose(new String[][] { + {" ", " ", " CC ", " CCCC ", " CCCC ", " CC ", " ", " "}, + {" ", " ", " AA ", " ACCA ", " ACCA ", " AA ", " ", " "}, + {" ", " ", " CC ", " CCCC ", " CCCC ", " CC ", " ", " "}, + {" ", " ", " ", " CC ", " CC ", " ", " ", " "}, + {" ", " ", " ", " CC ", " CC ", " ", " ", " "}, + {" ", " ", " ", " CC ", " CC ", " ", " ", " "}, + {" ", " ", " ", " CC ", " CC ", " ", " ", " "}, + {" ", " ", " CC ", " CCCC ", " CCCC ", " CC ", " ", " "}, + {" ", " ", " AA ", " ACCA ", " ACCA ", " AA ", " ", " "}, + {" ", " ", " CC ", " CCCC ", " CCCC ", " CC ", " ", " "}, + {" ", " ", " ", " CC ", " CC ", " ", " ", " "}, + {" ", " ", " ", " CC ", " CC ", " ", " ", " "}, + {" ", " ", " ", " CC ", " CC ", " ", " ", " "}, + {" ", " ", " ", " CC ", " CC ", " ", " ", " "}, + {" CCCCCC ", "CCCCCCCC", "CCCCCCCC", "CCCCCCCC", "CCCCCCCC", "CCCCCCCC", "CCCCCCCC", " CCCCCC "} + })) + .addShape(STRUCTURE_PIECE_TIER3, transpose(new String[][] { + {" ", " ", " CC ", " CCCC ", " CCCC ", " CC ", " ", " "}, + {" ", " ", " FFAA ", " ACCA ", " ACCA ", " AAFF ", " ", " "}, + {" ", " ", "F CC ", "F CCCC ", " CCCC F", " CC F", " ", " "}, + {" ", " ", " F", " CC F", "F CC ", "F ", " ", " "}, + {" ", " F ", " ", " CC ", " CC ", " ", " F ", " "}, + {" FF ", " ", " ", " CC ", " CC ", " ", " ", " FF "}, + {" FF ", " ", " ", " CC ", " CC ", " ", " ", " FF "}, + {" ", " F ", " ", " CC ", " CC ", " ", " F ", " "}, + {" ", " ", "F ", "F CC ", " CC F", " F", " ", " "}, + {" ", " ", " CC F", " CCCC F", "F CCCC ", "F CC ", " ", " "}, + {" ", " F ", " CC ", " CCCC ", " CCCC ", " CC ", " F ", " "}, + {" FF ", " ", " CC ", " CCCC ", " CCCC ", " CC ", " ", " FF "}, + {" FF ", " ", " CC ", " CCCC ", " CCCC ", " CC ", " ", " FF "}, + {" ", " F ", " ", " CC ", " CC ", " ", " F ", " "}, + {" ", " ", "F ", "F CC ", " CC F", " F", " ", " "}, + {" ", " ", " F", " CC F", "F CC ", "F ", " ", " "}, + {" ", " F ", " ", " CC ", " CC ", " ", " F ", " "}, + {" FF ", " ", " ", " CC ", " CC ", " ", " ", " FF "}, + {" FF ", " ", " ", " CC ", " CC ", " ", " ", " FF "}, + {" ", " F ", " ", " CC ", " CC ", " ", " F ", " "}, + {" ", " ", "F CC ", "F CCCC ", " CCCC F", " CC F", " ", " "}, + {" ", " ", " AA F", " ACCA F", "F ACCA ", "F AA ", " ", " "}, + {" ", " F ", " CC ", " CCCC ", " CCCC ", " CC ", " F ", " "}, + {" FF ", " ", " ", " CC ", " CC ", " ", " ", " FF "}, + {" FF ", " ", " ", " CC ", " CC ", " ", " ", " FF "}, + {" ", " F ", " ", " CC ", " CC ", " ", " F ", " "}, + {" CCCCCC ", "CCCCCCCC", "CCCCCCCC", "CCCCCCCC", "CCCCCCCC", "CCCCCCCC", "CCCCCCCC", " CCCCCC "} + })) + //spotless:on + .addElement('F', ofFrame(Materials.StellarAlloy)) + .addElement('C', ofBlock(GregTech_API.sBlockCasings8, 10)) + .addElement('A', ofBlock(GregTech_API.sBlockCasings2, 5)) + .addElement( + 'B', + buildHatchAdder(GT_MetaTileEntity_NanoForge.class) + .atLeast(InputHatch, OutputBus, InputBus, Maintenance, Energy.or(ExoticEnergy)) + .dot(1) + .casingIndex(((GT_Block_Casings8) GregTech_API.sBlockCasings8).getTextureIndex(10)) + .buildAndChain(GregTech_API.sBlockCasings8, 10)) + .build(); + private byte mSpecialTier = 0; + + public GT_MetaTileEntity_NanoForge(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_NanoForge(String aName) { + super(aName); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.nanoForgeRecipes; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 4, 37, 1); + if (stackSize.stackSize > 1) { + buildPiece(STRUCTURE_PIECE_TIER2, stackSize, hintsOnly, -7, 14, 4); + } + if (stackSize.stackSize > 2) { + buildPiece(STRUCTURE_PIECE_TIER3, stackSize, hintsOnly, 14, 26, 4); + } + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_NanoForge(this.mName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + if (sideDirection == facingDirection) { + if (active) return new ITexture[] { + BlockIcons.getCasingTextureForId(GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings8, 10)), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { + BlockIcons.getCasingTextureForId(GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings8, 10)), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { + BlockIcons.getCasingTextureForId(GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings8, 10)) }; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_NanoForge> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @Override + protected @Nonnull CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + return recipe.mSpecialValue <= mSpecialTier ? CheckRecipeResultRegistry.SUCCESSFUL + : CheckRecipeResultRegistry.NO_RECIPE; + } + + @Nonnull + @Override + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) { + return super.createOverclockCalculator(recipe) + .setDurationDecreasePerOC(mSpecialTier > recipe.mSpecialValue ? 2 : 1); + } + }; + } + + @Override + protected void setProcessingLogicPower(ProcessingLogic logic) { + logic.setAvailableVoltage(getMaxInputEu()); + logic.setAvailableAmperage(1); + logic.setAmperageOC(false); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isServerSide()) { + // TODO: Look for proper fix + // Updates every 10 sec + if (mUpdate <= -150) mUpdate = 50; + } + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + mSpecialTier = 0; + if (checkPiece(STRUCTURE_PIECE_MAIN, 4, 37, 1) && aStack != null) { + if (aStack.isItemEqual(Materials.Carbon.getNanite(1))) { + mSpecialTier = 1; + } + + if (aStack.isItemEqual(Materials.Neutronium.getNanite(1)) && checkPiece(STRUCTURE_PIECE_TIER2, -7, 14, 4)) { + mSpecialTier = 2; + } + + if (aStack.isItemEqual(MaterialsUEVplus.TranscendentMetal.getNanite(1)) + && checkPiece(STRUCTURE_PIECE_TIER2, -7, 14, 4) + && checkPiece(STRUCTURE_PIECE_TIER3, 14, 26, 4)) { + mSpecialTier = 3; + } + } + + if (mMaintenanceHatches.size() != 1) { + return false; + } + + if (!checkExoticAndNormalEnergyHatches()) { + return false; + } + + return mSpecialTier > 0; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + int built = survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 4, 37, 1, elementBudget, env, false, true); + if (built >= 0) return built; + if (stackSize.stackSize > 1) { + built += survivialBuildPiece(STRUCTURE_PIECE_TIER2, stackSize, -7, 14, 4, elementBudget, env, false, true); + } + if (stackSize.stackSize > 2) { + built += survivialBuildPiece(STRUCTURE_PIECE_TIER3, stackSize, 14, 26, 4, elementBudget, env, false, true); + } + return built; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setByte("mSpecialTier", mSpecialTier); + } + + @Override + public void loadNBTData(final NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (aNBT.hasKey("mSeparate")) { + // backward compatibility + inputSeparation = aNBT.getBoolean("mSeparate"); + } + mSpecialTier = aNBT.getByte("mSpecialTier"); + } + + @Override + protected void drawTexts(DynamicPositionedColumn screenElements, SlotWidget inventorySlot) { + super.drawTexts(screenElements, inventorySlot); + screenElements + .widget( + new TextWidget(StatCollector.translateToLocal("GT5U.gui.button.tier") + " " + mSpecialTier) + .setDefaultColor(COLOR_TEXT_WHITE.get()) + .setEnabled(widget -> getBaseMetaTileEntity().getErrorDisplayID() == 0)) + .widget( + new FakeSyncWidget.IntegerSyncer( + () -> (int) mSpecialTier, + val -> mSpecialTier = (byte) (val % Byte.MAX_VALUE))); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Nanite Fabricator") + .addInfo("Controller block for the Nano Forge") + .addInfo("Requires insane amounts of power to create nanites. Each tier") + .addInfo("the multi gains a new building next to it. The nanite in the") + .addInfo("controller slot controls the tier.") + .addInfo("--------------------------------------------") + .addInfo("Requires a Carbon Nanite to use tier " + EnumChatFormatting.DARK_PURPLE + 1) + .addInfo("Requires a Neutronium Nanite to use tier " + EnumChatFormatting.DARK_PURPLE + 2) + .addInfo("Requires a Transcendent Metal Nanite to use tier " + EnumChatFormatting.DARK_PURPLE + 3) + .addInfo("--------------------------------------------") + .addInfo("If a recipe's tier is lower than the tier of the Nano Forge") + .addInfo("it gains " + EnumChatFormatting.RED + "perfect overclock" + EnumChatFormatting.GRAY + ".") + .addInfo(AuthorBlueWeabo) + .addSeparator() + .beginStructureBlock(30, 38, 13, false) + .addStructureInfo("Nano Forge Structure is too complex! See schematic for details.") + .addStructureInfo("--------------------------------------------") + .addStructureInfo("Tier " + EnumChatFormatting.DARK_PURPLE + 1 + EnumChatFormatting.GRAY) + .addStructureInfo( + EnumChatFormatting.GOLD + "527" + EnumChatFormatting.GRAY + " Radiant Naquadah Alloy Casing") + .addStructureInfo(EnumChatFormatting.GOLD + "171" + EnumChatFormatting.GRAY + " Stellar Alloy Frame Box") + .addStructureInfo("--------------------------------------------") + .addStructureInfo("Tier " + EnumChatFormatting.DARK_PURPLE + 2 + EnumChatFormatting.GRAY) + .addStructureInfo( + EnumChatFormatting.GOLD + "148" + EnumChatFormatting.GRAY + " Radiant Naquadah Alloy Casing") + .addStructureInfo(EnumChatFormatting.GOLD + "16" + EnumChatFormatting.GRAY + " Assembling Line Casing") + .addStructureInfo("--------------------------------------------") + .addStructureInfo("Tier " + EnumChatFormatting.DARK_PURPLE + 3 + EnumChatFormatting.GRAY) + .addStructureInfo( + EnumChatFormatting.GOLD + "228" + EnumChatFormatting.GRAY + " Radiant Naquadah Alloy Casing") + .addStructureInfo(EnumChatFormatting.GOLD + "84" + EnumChatFormatting.GRAY + " Stellar Alloy Frame Box") + .addStructureInfo(EnumChatFormatting.GOLD + "16" + EnumChatFormatting.GRAY + " Assembling Line Casing") + .addStructureInfo("--------------------------------------------") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + + "1" + + EnumChatFormatting.GRAY + + "-" + + EnumChatFormatting.GOLD + + "2" + + EnumChatFormatting.GRAY + + " energy hatches or " + + EnumChatFormatting.GOLD + + "1" + + EnumChatFormatting.GRAY + + " TT energy hatch.") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + "1" + EnumChatFormatting.GRAY + " maintenance hatch.") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + + 1 + + EnumChatFormatting.GRAY + + "+" + + EnumChatFormatting.GRAY + + " input hatches.") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + + 0 + + EnumChatFormatting.GRAY + + "+" + + EnumChatFormatting.GRAY + + " output hatches.") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + + 1 + + EnumChatFormatting.GRAY + + "+" + + EnumChatFormatting.GRAY + + " input busses.") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + + 1 + + EnumChatFormatting.GRAY + + "+" + + EnumChatFormatting.GRAY + + " output busses.") + .addStructureInfo("--------------------------------------------") + .toolTipFinisher("GregTech"); + return tt; + } + + @Override + public final void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + inputSeparation = !inputSeparation; + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("GT5U.machines.separatebus") + " " + inputSeparation); + } + + @Override + public boolean supportsVoidProtection() { + return true; + } + + @Override + public boolean supportsInputSeparation() { + return true; + } + + @Override + public boolean supportsBatchMode() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilCracker.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilCracker.java new file mode 100644 index 0000000000..9ca671aa49 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilCracker.java @@ -0,0 +1,423 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_CRACKER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.ofCoil; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nonnull; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.GT_HatchElement; +import gregtech.api.enums.HeatingCoilLevel; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_MultiInput; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.maps.OilCrackerBackend; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Input_ME; +import gregtech.common.tileentities.machines.IRecipeProcessingAwareHatch; + +public class GT_MetaTileEntity_OilCracker extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_OilCracker> + implements ISurvivalConstructable { + + private static final byte CASING_INDEX = 49; + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final IStructureDefinition<GT_MetaTileEntity_OilCracker> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_OilCracker>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose( + new String[][] { { "lcmcr", "lcmcr", "lcmcr" }, { "lc~cr", "l---r", "lcmcr" }, + { "lcmcr", "lcmcr", "lcmcr" }, })) + .addElement('c', ofCoil(GT_MetaTileEntity_OilCracker::setCoilLevel, GT_MetaTileEntity_OilCracker::getCoilLevel)) + .addElement( + 'l', + buildHatchAdder(GT_MetaTileEntity_OilCracker.class) + .atLeast( + GT_HatchElement.InputHatch.withAdder(GT_MetaTileEntity_OilCracker::addLeftHatchToMachineList), + GT_HatchElement.Energy, + GT_HatchElement.Maintenance) + .dot(2) + .casingIndex(CASING_INDEX) + .buildAndChain( + onElementPass( + GT_MetaTileEntity_OilCracker::onCasingAdded, + ofBlock(GregTech_API.sBlockCasings4, 1)))) + .addElement( + 'r', + buildHatchAdder(GT_MetaTileEntity_OilCracker.class) + .atLeast( + GT_HatchElement.OutputHatch.withAdder(GT_MetaTileEntity_OilCracker::addRightHatchToMachineList), + GT_HatchElement.Energy, + GT_HatchElement.Maintenance) + .dot(3) + .casingIndex(CASING_INDEX) + .buildAndChain( + onElementPass( + GT_MetaTileEntity_OilCracker::onCasingAdded, + ofBlock(GregTech_API.sBlockCasings4, 1)))) + .addElement( + 'm', + buildHatchAdder(GT_MetaTileEntity_OilCracker.class) + .atLeast( + GT_HatchElement.InputHatch.withAdder(GT_MetaTileEntity_OilCracker::addMiddleInputToMachineList) + .withCount(t -> t.mMiddleInputHatches.size()), + GT_HatchElement.InputBus, + GT_HatchElement.Energy, + GT_HatchElement.Maintenance) + .dot(1) + .casingIndex(CASING_INDEX) + .buildAndChain( + onElementPass( + GT_MetaTileEntity_OilCracker::onCasingAdded, + ofBlock(GregTech_API.sBlockCasings4, 1)))) + .build(); + private HeatingCoilLevel heatLevel; + protected final List<GT_MetaTileEntity_Hatch_Input> mMiddleInputHatches = new ArrayList<>(); + // 0 -> left, 1 -> right, any other -> not found + protected int mInputOnSide; + protected int mOutputOnSide; + protected int mCasingAmount; + + public GT_MetaTileEntity_OilCracker(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_OilCracker(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Cracker") + .addInfo("Controller block for the Oil Cracking Unit") + .addInfo("Thermally cracks heavy hydrocarbons into lighter fractions") + .addInfo("More efficient than the Chemical Reactor") + .addInfo("Gives different benefits whether it hydro or steam-cracks:") + .addInfo("Hydro - Consumes 20% less Hydrogen and outputs 25% more cracked fluid") + .addInfo("Steam - Outputs 50% more cracked fluid") + .addInfo("(Values compared to cracking in the Chemical Reactor)") + .addInfo("Place the appropriate circuit in the controller or an input bus") + .addSeparator() + .beginStructureBlock(5, 3, 3, true) + .addController("Front center") + .addCasingInfoRange("Clean Stainless Steel Machine Casing", 18, 21, false) + .addOtherStructurePart("2 Rings of 8 Coils", "Each side of the controller") + .addInfo("Gets 10% EU/t reduction per coil tier, up to a maximum of 50%") + .addEnergyHatch("Any casing", 1, 2, 3) + .addMaintenanceHatch("Any casing", 1, 2, 3) + .addInputHatch("For cracking fluid (Steam/Hydrogen/etc.) ONLY, Any middle ring casing", 1) + .addInputHatch("Any left/right side casing", 2, 3) + .addOutputHatch("Any right/left side casing", 2, 3) + .addStructureInfo("Input/Output Hatches must be on opposite sides!") + .addInputBus("Any middle ring casing, optional for programmed circuit automation") + .addStructureHint("GT5U.cracker.io_side") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + if (sideDirection == facingDirection) { + if (active) return new ITexture[] { casingTexturePages[0][CASING_INDEX], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_OIL_CRACKER_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { casingTexturePages[0][CASING_INDEX], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_OIL_CRACKER) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_OIL_CRACKER_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { casingTexturePages[0][CASING_INDEX] }; + } + + @Override + public RecipeMap<OilCrackerBackend> getRecipeMap() { + return RecipeMaps.crackingRecipes; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @Nonnull + @Override + public CheckRecipeResult process() { + setEuModifier(1.0F - Math.min(0.1F * (heatLevel.getTier() + 1), 0.5F)); + return super.process(); + } + }; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_OilCracker> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + public HeatingCoilLevel getCoilLevel() { + return heatLevel; + } + + public void setCoilLevel(HeatingCoilLevel aCoilLevel) { + heatLevel = aCoilLevel; + } + + private boolean addMiddleInputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input tHatch) { + tHatch.updateTexture(aBaseCasingIndex); + tHatch.mRecipeMap = getRecipeMap(); + return mMiddleInputHatches.add(tHatch); + } + return false; + } + + private boolean addLeftHatchToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input tHatch) { + if (mInputOnSide == 1) return false; + mInputOnSide = 0; + mOutputOnSide = 1; + tHatch.updateTexture(aBaseCasingIndex); + tHatch.mRecipeMap = getRecipeMap(); + return mInputHatches.add(tHatch); + } + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output tHatch) { + if (mOutputOnSide == 1) return false; + mInputOnSide = 1; + mOutputOnSide = 0; + tHatch.updateTexture(aBaseCasingIndex); + return mOutputHatches.add(tHatch); + } + return false; + } + + private boolean addRightHatchToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input tHatch) { + if (mInputOnSide == 0) return false; + mInputOnSide = 1; + mOutputOnSide = 0; + tHatch.updateTexture(aBaseCasingIndex); + tHatch.mRecipeMap = getRecipeMap(); + return mInputHatches.add(tHatch); + } + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output tHatch) { + if (mOutputOnSide == 0) return false; + mInputOnSide = 0; + mOutputOnSide = 1; + tHatch.updateTexture(aBaseCasingIndex); + return mOutputHatches.add(tHatch); + } + return false; + } + + private void onCasingAdded() { + mCasingAmount++; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + setCoilLevel(HeatingCoilLevel.None); + mCasingAmount = 0; + mMiddleInputHatches.clear(); + mInputOnSide = -1; + mOutputOnSide = -1; + replaceDeprecatedCoils(aBaseMetaTileEntity); + return checkPiece(STRUCTURE_PIECE_MAIN, 2, 1, 0) && mInputOnSide != -1 + && mOutputOnSide != -1 + && mCasingAmount >= 18 + && mMaintenanceHatches.size() == 1 + && !mMiddleInputHatches.isEmpty(); + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_OilCracker(this.mName); + } + + private void replaceDeprecatedCoils(IGregTechTileEntity aBaseMetaTileEntity) { + final int xDir = aBaseMetaTileEntity.getBackFacing().offsetX; + final int zDir = aBaseMetaTileEntity.getBackFacing().offsetZ; + final int tX = aBaseMetaTileEntity.getXCoord() + xDir; + final int tY = aBaseMetaTileEntity.getYCoord(); + final int tZ = aBaseMetaTileEntity.getZCoord() + zDir; + for (int xPos = tX - 1; xPos <= tX + 1; xPos += (xDir != 0 ? 1 : 2)) + for (int yPos = tY - 1; yPos <= tY + 1; yPos++) + for (int zPos = tZ - 1; zPos <= tZ + 1; zPos += (xDir != 0 ? 2 : 1)) { + if ((yPos == tY) && (xPos == tX || zPos == tZ)) continue; + final byte tUsedMeta = aBaseMetaTileEntity.getMetaID(xPos, yPos, zPos); + if (tUsedMeta < 12) continue; + if (tUsedMeta > 14) continue; + if (aBaseMetaTileEntity.getBlock(xPos, yPos, zPos) != GregTech_API.sBlockCasings1) continue; + + aBaseMetaTileEntity.getWorld() + .setBlock(xPos, yPos, zPos, GregTech_API.sBlockCasings5, tUsedMeta - 12, 3); + } + } + + @Override + public ArrayList<FluidStack> getStoredFluids() { + final ArrayList<FluidStack> rList = new ArrayList<>(); + Map<Fluid, FluidStack> inputsFromME = new HashMap<>(); + for (final GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) { + tHatch.mRecipeMap = getRecipeMap(); + if (tHatch instanceof GT_MetaTileEntity_Hatch_Input_ME meHatch) { + for (FluidStack tFluid : meHatch.getStoredFluids()) { + if (tFluid != null && !getRecipeMap().getBackend() + .isValidCatalystFluid(tFluid)) { + inputsFromME.put(tFluid.getFluid(), tFluid); + } + } + } else if (tHatch instanceof GT_MetaTileEntity_Hatch_MultiInput) { + for (final FluidStack tFluid : ((GT_MetaTileEntity_Hatch_MultiInput) tHatch).getStoredFluid()) { + if (tFluid != null && !getRecipeMap().getBackend() + .isValidCatalystFluid(tFluid)) { + rList.add(tFluid); + } + } + } else { + if (tHatch.getFillableStack() != null) { + if (!getRecipeMap().getBackend() + .isValidCatalystFluid(tHatch.getFillableStack())) rList.add(tHatch.getFillableStack()); + } + } + } + for (final GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mMiddleInputHatches)) { + tHatch.mRecipeMap = getRecipeMap(); + if (tHatch instanceof GT_MetaTileEntity_Hatch_Input_ME meHatch) { + for (FluidStack tFluid : meHatch.getStoredFluids()) { + if (tFluid != null && getRecipeMap().getBackend() + .isValidCatalystFluid(tFluid)) { + inputsFromME.put(tFluid.getFluid(), tFluid); + } + } + } else if (tHatch instanceof GT_MetaTileEntity_Hatch_MultiInput) { + for (final FluidStack tFluid : ((GT_MetaTileEntity_Hatch_MultiInput) tHatch).getStoredFluid()) { + if (tFluid != null && getRecipeMap().getBackend() + .isValidCatalystFluid(tFluid)) { + rList.add(tFluid); + } + } + } else { + if (tHatch.getFillableStack() != null) { + final FluidStack tStack = tHatch.getFillableStack(); + if (getRecipeMap().getBackend() + .isValidCatalystFluid(tStack)) { + rList.add(tStack); + } + } + } + } + if (!inputsFromME.isEmpty()) { + rList.addAll(inputsFromME.values()); + } + return rList; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 2, 1, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 2, 1, 0, elementBudget, env, false, true); + } + + @Override + public boolean supportsVoidProtection() { + return true; + } + + @Override + protected void startRecipeProcessing() { + for (GT_MetaTileEntity_Hatch_Input hatch : filterValidMTEs(mMiddleInputHatches)) { + if (hatch instanceof IRecipeProcessingAwareHatch aware) { + aware.startRecipeProcessing(); + } + } + super.startRecipeProcessing(); + } + + @Override + protected void endRecipeProcessing() { + super.endRecipeProcessing(); + for (GT_MetaTileEntity_Hatch_Input hatch : filterValidMTEs(mMiddleInputHatches)) { + if (hatch instanceof IRecipeProcessingAwareHatch aware) { + setResultIfFailure(aware.endRecipeProcessing(this)); + } + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill1.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill1.java new file mode 100644 index 0000000000..1e37dcbac9 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill1.java @@ -0,0 +1,53 @@ +package gregtech.common.tileentities.machines.multi; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_OilDrill1 extends GT_MetaTileEntity_OilDrillBase { + + public GT_MetaTileEntity_OilDrill1(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_OilDrill1(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + return createTooltip("I"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_OilDrill1(mName); + } + + @Override + protected ItemList getCasingBlockItem() { + return ItemList.Casing_SolidSteel; + } + + @Override + protected Materials getFrameMaterial() { + return Materials.Steel; + } + + @Override + protected int getCasingTextureIndex() { + return 16; + } + + @Override + protected int getRangeInChunks() { + return 1; + } + + @Override + protected int getMinTier() { + return 2; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill2.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill2.java new file mode 100644 index 0000000000..10a64a6b1d --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill2.java @@ -0,0 +1,55 @@ +package gregtech.common.tileentities.machines.multi; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_OilDrill2 extends GT_MetaTileEntity_OilDrillBase { + + public GT_MetaTileEntity_OilDrill2(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_OilDrill2(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + return createTooltip("II"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_OilDrill2(mName); + } + + @Override + protected ItemList getCasingBlockItem() { + return ItemList.Casing_CleanStainlessSteel; + } + + @Override + protected Materials getFrameMaterial() { + return Materials.StainlessSteel; + } + + @Override + protected int getCasingTextureIndex() { + return GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings4, 1); + } + + @Override + protected int getRangeInChunks() { + return 2; + } + + @Override + protected int getMinTier() { + return 3; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill3.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill3.java new file mode 100644 index 0000000000..bcbe42d794 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill3.java @@ -0,0 +1,55 @@ +package gregtech.common.tileentities.machines.multi; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_OilDrill3 extends GT_MetaTileEntity_OilDrillBase { + + public GT_MetaTileEntity_OilDrill3(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_OilDrill3(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + return createTooltip("III"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_OilDrill3(mName); + } + + @Override + protected ItemList getCasingBlockItem() { + return ItemList.Casing_StableTitanium; + } + + @Override + protected Materials getFrameMaterial() { + return Materials.Titanium; + } + + @Override + protected int getCasingTextureIndex() { + return GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings4, 2); + } + + @Override + protected int getRangeInChunks() { + return 4; + } + + @Override + protected int getMinTier() { + return 4; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill4.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill4.java new file mode 100644 index 0000000000..802e9f1c5c --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrill4.java @@ -0,0 +1,55 @@ +package gregtech.common.tileentities.machines.multi; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_OilDrill4 extends GT_MetaTileEntity_OilDrillBase { + + public GT_MetaTileEntity_OilDrill4(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_OilDrill4(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + return createTooltip("IV"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_OilDrill4(mName); + } + + @Override + protected ItemList getCasingBlockItem() { + return ItemList.Casing_RobustTungstenSteel; + } + + @Override + protected Materials getFrameMaterial() { + return Materials.TungstenSteel; + } + + @Override + protected int getCasingTextureIndex() { + return GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings4, 0); + } + + @Override + protected int getRangeInChunks() { + return 8; + } + + @Override + protected int getMinTier() { + return 5; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillBase.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillBase.java new file mode 100644 index 0000000000..075b4e19a1 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillBase.java @@ -0,0 +1,489 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.GT_Values.debugDriller; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_DRILL; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_DRILL_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_DRILL_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_OIL_DRILL_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.getCasingTextureForId; +import static gregtech.common.GT_UndergroundOil.undergroundOil; +import static gregtech.common.GT_UndergroundOil.undergroundOilReadInformation; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Nonnegative; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.modularui.api.NumberFormatMUI; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetricsExporter; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.objects.GT_ChunkManager; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.ValidationResult; +import gregtech.api.util.ValidationType; + +public abstract class GT_MetaTileEntity_OilDrillBase extends GT_MetaTileEntity_DrillerBase implements IMetricsExporter { + + private final ArrayList<Chunk> mOilFieldChunks = new ArrayList<>(); + private int mOilId = 0; + private int mOilFlow = 0; + + private int chunkRangeConfig = getRangeInChunks(); + + public GT_MetaTileEntity_OilDrillBase(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_OilDrillBase(String aName) { + super(aName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { getCasingTextureForId(casingTextureIndex), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_OIL_DRILL_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_OIL_DRILL_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { getCasingTextureForId(casingTextureIndex), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_OIL_DRILL) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_OIL_DRILL_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { getCasingTextureForId(casingTextureIndex) }; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setInteger("mOilId", mOilId); + aNBT.setInteger("chunkRangeConfig", chunkRangeConfig); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + mOilId = aNBT.getInteger("mOilId"); + if (aNBT.hasKey("chunkRangeConfig")) chunkRangeConfig = aNBT.getInteger("chunkRangeConfig"); + } + + protected GT_Multiblock_Tooltip_Builder createTooltip(String tierSuffix) { + String casings = getCasingBlockItem().get(0) + .getDisplayName(); + + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Pump") + .addInfo("Controller Block for the Oil/Gas/Fluid Drilling Rig " + (tierSuffix != null ? tierSuffix : "")) + .addInfo("Works on " + getRangeInChunks() + "x" + getRangeInChunks() + " chunks") + .addInfo("Use a Screwdriver to configure range") + .addInfo("Use Programmed Circuits to ignore near exhausted oil field") + .addInfo("If total circuit # is greater than output amount it will halt. If it worked right.") // doesn't + // work + .addSeparator() + .beginStructureBlock(3, 7, 3, false) + .addController("Front bottom") + .addOtherStructurePart(casings, "form the 3x1x3 Base") + .addOtherStructurePart(casings, "1x3x1 pillar above the center of the base (2 minimum total)") + .addOtherStructurePart(getFrameMaterial().mName + " Frame Boxes", "Each pillar's side and 1x3x1 on top") + .addEnergyHatch("1x " + VN[getMinTier()] + "+, Any base casing", 1) + .addMaintenanceHatch("Any base casing", 1) + .addInputBus("Mining Pipes or Circuits, optional, any base casing", 1) + .addOutputHatch("Any base casing", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + protected abstract int getRangeInChunks(); + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + super.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ); + int oldChunkRange = chunkRangeConfig; + if (aPlayer.isSneaking()) { + if (chunkRangeConfig > 0) { + chunkRangeConfig--; + } + if (chunkRangeConfig == 0) chunkRangeConfig = getRangeInChunks(); + } else { + if (chunkRangeConfig <= getRangeInChunks()) { + chunkRangeConfig++; + } + if (chunkRangeConfig > getRangeInChunks()) chunkRangeConfig = 1; + } + if (oldChunkRange != chunkRangeConfig) mOilFieldChunks.clear(); + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("GT5U.machines.workareaset") + " " + + chunkRangeConfig + + "x" + + chunkRangeConfig + + StatCollector.translateToLocal("GT5U.machines.chunks")); // TODO Add translation support + } + + @Override + protected boolean checkHatches() { + return !mMaintenanceHatches.isEmpty() && !mOutputHatches.isEmpty() && mEnergyHatches.size() == 1; + } + + @Override + protected List<IHatchElement<? super GT_MetaTileEntity_DrillerBase>> getAllowedHatches() { + return ImmutableList.of(InputBus, OutputHatch, Maintenance, Energy); + } + + @Override + protected void setElectricityStats() { + this.mEfficiency = getCurrentEfficiency(null); + this.mEfficiencyIncrease = 10000; + int tier = Math.max(0, GT_Utility.getTier(getMaxInputVoltage())); + this.mEUt = -7 << (tier << 1); // (1/4) A of current tier when at bottom (7/8) A of current tier while mining + this.mMaxProgresstime = Math.max( + 1, + (workState == STATE_AT_BOTTOM ? (64 * (chunkRangeConfig * chunkRangeConfig)) >> (getMinTier() - 1) : 120) + >> tier); + } + + protected float computeSpeed() { + return .5F + (GT_Utility.getTier(getMaxInputVoltage()) - getMinTier()) * .25F; + } + + @Override + protected boolean workingAtBottom(ItemStack aStack, int xDrill, int yDrill, int zDrill, int xPipe, int zPipe, + int yHead, int oldYHead) { + switch (tryLowerPipeState(true)) { + case 0 -> { + workState = STATE_DOWNWARD; + setElectricityStats(); + return true; + } + case 3 -> { + workState = STATE_UPWARD; + return true; + } + } + + if (reachingVoidOrBedrock() && tryFillChunkList()) { + if (mWorkChunkNeedsReload) { + mCurrentChunk = new ChunkCoordIntPair(xDrill >> 4, zDrill >> 4); + GT_ChunkManager.requestChunkLoad((TileEntity) getBaseMetaTileEntity(), null); + mWorkChunkNeedsReload = false; + } + float speed = computeSpeed(); + ValidationResult<FluidStack> pumpResult = tryPumpOil(speed); + if (pumpResult.getType() != ValidationType.VALID) { + mEUt = 0; + mMaxProgresstime = 0; + setRuntimeFailureReason(CheckRecipeResultRegistry.FLUID_OUTPUT_FULL); + return false; + } + FluidStack tFluid = pumpResult.getResult(); + if (tFluid != null && tFluid.amount > getTotalConfigValue()) { + this.mOutputFluids = new FluidStack[] { tFluid }; + return true; + } + } + GT_ChunkManager.releaseTicket((TileEntity) getBaseMetaTileEntity()); + workState = STATE_UPWARD; + setShutdownReason(StatCollector.translateToLocal("GT5U.gui.text.drill_exhausted")); + return true; + } + + private boolean tryFillChunkList() { + FluidStack tFluid, tOil; + if (mOilId <= 0) { + tFluid = undergroundOilReadInformation(getBaseMetaTileEntity()); + if (tFluid == null) return false; + mOilId = tFluid.getFluidID(); + } + if (debugDriller) { + GT_Log.out.println(" Driller on fluid = " + mOilId); + } + + tOil = new FluidStack(FluidRegistry.getFluid(mOilId), 0); + + if (mOilFieldChunks.isEmpty()) { + Chunk tChunk = getBaseMetaTileEntity().getWorld() + .getChunkFromBlockCoords(getBaseMetaTileEntity().getXCoord(), getBaseMetaTileEntity().getZCoord()); + int range = chunkRangeConfig; + int xChunk = Math.floorDiv(tChunk.xPosition, range) * range; // Java was written by idiots. For negative + // values, / returns rounded towards zero. + // Fucking morons. + int zChunk = Math.floorDiv(tChunk.zPosition, range) * range; + if (debugDriller) { + GT_Log.out.println( + "tChunk.xPosition = " + tChunk.xPosition + + " tChunk.zPosition = " + + tChunk.zPosition + + " xChunk = " + + xChunk + + " zChunk = " + + zChunk); + } + for (int i = 0; i < range; i++) { + for (int j = 0; j < range; j++) { + if (debugDriller) { + GT_Log.out.println(" getChunkX = " + (xChunk + i) + " getChunkZ = " + (zChunk + j)); + } + tChunk = getBaseMetaTileEntity().getWorld() + .getChunkFromChunkCoords(xChunk + i, zChunk + j); + tFluid = undergroundOilReadInformation(tChunk); + if (debugDriller) { + GT_Log.out.println( + " Fluid in chunk = " + tFluid.getFluid() + .getID()); + } + if (tOil.isFluidEqual(tFluid) && tFluid.amount > 0) { + mOilFieldChunks.add(tChunk); + if (debugDriller) { + GT_Log.out.println(" Matching fluid, quantity = " + tFluid.amount); + } + } + } + } + } + if (debugDriller) { + GT_Log.out.println("mOilFieldChunks.size = " + mOilFieldChunks.size()); + } + return !mOilFieldChunks.isEmpty(); + } + + /** + * Tries to pump oil, accounting for output space if void protection is enabled. + * <p> + * If pumped fluid will not fit in output hatches, it returns a result with INVALID. + * <p> + * If vein is depleted, it returns a result with VALID and null fluid. + */ + protected ValidationResult<FluidStack> tryPumpOil(float speed) { + if (mOilId <= 0) return null; + if (debugDriller) { + GT_Log.out.println(" pump speed = " + speed); + } + + // Even though it works fine without this check, + // it can save tiny amount of CPU time when void protection is disabled + if (protectsExcessFluid()) { + FluidStack simulatedOil = pumpOil(speed, true); + if (!canOutputAll(new FluidStack[] { simulatedOil })) { + return ValidationResult.of(ValidationType.INVALID, null); + } + } + + FluidStack pumpedOil = pumpOil(speed, false); + mOilFlow = pumpedOil.amount; + return ValidationResult.of(ValidationType.VALID, pumpedOil.amount == 0 ? null : pumpedOil); + } + + /** + * @param speed Speed to pump oil + * @param simulate If true, it actually does not consume vein + * @return Fluid pumped + */ + protected FluidStack pumpOil(@Nonnegative float speed, boolean simulate) { + if (speed < 0) { + throw new IllegalArgumentException("Don't pass negative speed"); + } + + ArrayList<Chunk> emptyChunks = new ArrayList<>(); + FluidStack returnOil = new FluidStack(FluidRegistry.getFluid(mOilId), 0); + + for (Chunk tChunk : mOilFieldChunks) { + FluidStack pumped = undergroundOil(tChunk, simulate ? -speed : speed); + if (debugDriller) { + GT_Log.out.println( + " chunkX = " + tChunk.getChunkCoordIntPair().chunkXPos + + " chunkZ = " + + tChunk.getChunkCoordIntPair().chunkZPos); + if (pumped != null) { + GT_Log.out.println(" Fluid pumped = " + pumped.amount); + } else { + GT_Log.out.println(" No fluid pumped "); + } + } + if (pumped == null || pumped.amount < 1) { + emptyChunks.add(tChunk); + continue; + } + if (returnOil.isFluidEqual(pumped)) { + returnOil.amount += pumped.amount; + } + } + for (Chunk tChunk : emptyChunks) { + mOilFieldChunks.remove(tChunk); + } + return returnOil; + } + + @Override + protected SoundResource getProcessStartSound() { + return SoundResource.IC2_MACHINES_PUMP_OP; + } + + @Override + public String[] getInfoData() { + List<String> l = new ArrayList<>( + Arrays.asList( + EnumChatFormatting.BLUE + StatCollector.translateToLocal("GT5U.machines.oilfluidpump") + + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.machines.workarea") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(chunkRangeConfig) + + " x " + + GT_Utility.formatNumbers(chunkRangeConfig) + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.machines.chunks"), + "Drilling fluid: " + EnumChatFormatting.GREEN + getFluidName() + EnumChatFormatting.RESET, + "Drilling flow: " + EnumChatFormatting.GREEN + + getFlowRatePerTick() + + EnumChatFormatting.RESET + + " L/t")); + l.addAll(Arrays.asList(super.getInfoData())); + return l.toArray(new String[0]); + } + + @Override + public @NotNull List<String> reportMetrics() { + final boolean machineIsActive = getBaseMetaTileEntity().isActive(); + final String failureReason = getFailureReason() + .map(reason -> StatCollector.translateToLocalFormatted("GT5U.gui.text.drill_offline_reason", reason)) + .orElseGet(() -> StatCollector.translateToLocalFormatted("GT5U.gui.text.drill_offline_generic")); + + if (workState == STATE_AT_BOTTOM) { + final ImmutableList.Builder<String> builder = ImmutableList.builder(); + builder.add(StatCollector.translateToLocalFormatted("GT5U.gui.text.pump_fluid_type", getFluidName())); + + if (machineIsActive) { + builder.add( + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.pump_rate.1", + EnumChatFormatting.AQUA + numberFormat.format(getFlowRatePerTick())) + + StatCollector.translateToLocal("GT5U.gui.text.pump_rate.2"), + mOilFlow + StatCollector.translateToLocal("GT5U.gui.text.pump_recovery.2")); + } else { + builder.add(failureReason); + } + + return builder.build(); + } + + if (machineIsActive) { + return switch (workState) { + case STATE_DOWNWARD -> ImmutableList.of(StatCollector.translateToLocal("GT5U.gui.text.deploying_pipe")); + case STATE_UPWARD, STATE_ABORT -> ImmutableList + .of(StatCollector.translateToLocal("GT5U.gui.text.retracting_pipe")); + default -> ImmutableList.of(); + }; + } + + return ImmutableList.of(failureReason); + } + + protected int getFlowRatePerTick() { + return this.mMaxProgresstime > 0 ? (mOilFlow / this.mMaxProgresstime) : 0; + } + + @NotNull + private String getFluidName() { + if (mOilId > 0) { + final Fluid fluid = FluidRegistry.getFluid(mOilId); + return fluid.getLocalizedName(new FluidStack(fluid, 0)); + } + return "None"; + } + + private @NotNull String clientFluidType = ""; + private int clientFlowPerTick = 0; + private int clientFlowPerOperation = 0; + + protected static final NumberFormatMUI numberFormat = new NumberFormatMUI(); + + @Override + protected void drawTexts(DynamicPositionedColumn screenElements, SlotWidget inventorySlot) { + super.drawTexts(screenElements, inventorySlot); + screenElements + .widget( + new TextWidget() + .setStringSupplier( + () -> EnumChatFormatting.GRAY + + StatCollector.translateToLocalFormatted("GT5U.gui.text.pump_fluid_type", clientFluidType)) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled(widget -> getBaseMetaTileEntity().isActive() && workState == STATE_AT_BOTTOM)) + .widget( + new TextWidget() + .setStringSupplier( + () -> EnumChatFormatting.GRAY + + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.pump_rate.1", + EnumChatFormatting.AQUA + numberFormat.format(clientFlowPerTick)) + + EnumChatFormatting.GRAY + + StatCollector.translateToLocal("GT5U.gui.text.pump_rate.2")) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled(widget -> getBaseMetaTileEntity().isActive() && workState == STATE_AT_BOTTOM)) + .widget( + new TextWidget() + .setStringSupplier( + () -> EnumChatFormatting.GRAY + + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.pump_recovery.1", + EnumChatFormatting.AQUA + numberFormat.format(clientFlowPerOperation)) + + EnumChatFormatting.GRAY + + StatCollector.translateToLocal("GT5U.gui.text.pump_recovery.2")) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled(widget -> getBaseMetaTileEntity().isActive() && workState == STATE_AT_BOTTOM)) + .widget(new FakeSyncWidget.IntegerSyncer(() -> workState, newInt -> workState = newInt)) + .widget(new FakeSyncWidget.StringSyncer(this::getFluidName, newString -> clientFluidType = newString)) + .widget(new FakeSyncWidget.IntegerSyncer(this::getFlowRatePerTick, newInt -> clientFlowPerTick = newInt)) + .widget(new FakeSyncWidget.IntegerSyncer(() -> mOilFlow, newInt -> clientFlowPerOperation = newInt)); + } + + @Override + public boolean supportsVoidProtection() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillInfinite.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillInfinite.java new file mode 100644 index 0000000000..056577e8e8 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OilDrillInfinite.java @@ -0,0 +1,87 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.GT_Values.VN; + +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_OilDrillInfinite extends GT_MetaTileEntity_OilDrillBase { + + public GT_MetaTileEntity_OilDrillInfinite(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_OilDrillInfinite(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + String casings = getCasingBlockItem().get(0) + .getDisplayName(); + + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Pump") + .addInfo("Controller Block for the Infinite Oil/Gas/Fluid Drilling Rig ") + .addInfo("Works on " + getRangeInChunks() + "x" + getRangeInChunks() + " chunks") + .addSeparator() + .beginStructureBlock(3, 7, 3, false) + .addController("Front bottom") + .addOtherStructurePart(casings, "form the 3x1x3 Base") + .addOtherStructurePart(casings, "1x3x1 pillar above the center of the base (2 minimum total)") + .addOtherStructurePart(getFrameMaterial().mName + " Frame Boxes", "Each pillar's side and 1x3x1 on top") + .addEnergyHatch("1x " + VN[getMinTier()] + "+, Any base casing", 1) + .addMaintenanceHatch("Any base casing", 1) + .addInputBus("Mining Pipes or Circuits, optional, any base casing", 1) + .addOutputHatch("Any base casing", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_OilDrillInfinite(mName); + } + + @Override + protected FluidStack pumpOil(float speed, boolean simulate) { + // always simulate to not deplete vein + return super.pumpOil(speed, true); + } + + @Override + protected ItemList getCasingBlockItem() { + return ItemList.Casing_MiningNeutronium; + } + + @Override + protected Materials getFrameMaterial() { + return Materials.Neutronium; + } + + @Override + protected int getCasingTextureIndex() { + return 178; + } + + @Override + protected int getRangeInChunks() { + return 8; + } + + @Override + protected float computeSpeed() { + return .5F + (GT_Utility.getTier(getMaxInputVoltage()) - getMinTier() + 5) * .25F; + } + + @Override + protected int getMinTier() { + return 9; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant1.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant1.java new file mode 100644 index 0000000000..50edf8928a --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant1.java @@ -0,0 +1,60 @@ +package gregtech.common.tileentities.machines.multi; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_OreDrillingPlant1 extends GT_MetaTileEntity_OreDrillingPlantBase { + + public GT_MetaTileEntity_OreDrillingPlant1(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + mTier = 1; + } + + public GT_MetaTileEntity_OreDrillingPlant1(String aName) { + super(aName); + mTier = 1; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + return createTooltip("I"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_OreDrillingPlant1(mName); + } + + @Override + protected ItemList getCasingBlockItem() { + return ItemList.Casing_SolidSteel; + } + + @Override + protected Materials getFrameMaterial() { + return Materials.Steel; + } + + @Override + protected int getCasingTextureIndex() { + return 16; + } + + @Override + protected int getRadiusInChunks() { + return 3; + } + + @Override + protected int getMinTier() { + return 2; + } + + @Override + protected int getBaseProgressTime() { + return 960; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant2.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant2.java new file mode 100644 index 0000000000..6a80c96d26 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant2.java @@ -0,0 +1,60 @@ +package gregtech.common.tileentities.machines.multi; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_OreDrillingPlant2 extends GT_MetaTileEntity_OreDrillingPlantBase { + + public GT_MetaTileEntity_OreDrillingPlant2(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + mTier = 2; + } + + public GT_MetaTileEntity_OreDrillingPlant2(String aName) { + super(aName); + mTier = 2; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + return createTooltip("II"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_OreDrillingPlant2(mName); + } + + @Override + protected ItemList getCasingBlockItem() { + return ItemList.Casing_StableTitanium; + } + + @Override + protected Materials getFrameMaterial() { + return Materials.Titanium; + } + + @Override + protected int getCasingTextureIndex() { + return 50; + } + + @Override + protected int getRadiusInChunks() { + return 4; + } + + @Override + protected int getMinTier() { + return 3; + } + + @Override + protected int getBaseProgressTime() { + return 800; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant3.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant3.java new file mode 100644 index 0000000000..2bb25b2254 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant3.java @@ -0,0 +1,60 @@ +package gregtech.common.tileentities.machines.multi; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_OreDrillingPlant3 extends GT_MetaTileEntity_OreDrillingPlantBase { + + public GT_MetaTileEntity_OreDrillingPlant3(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + mTier = 3; + } + + public GT_MetaTileEntity_OreDrillingPlant3(String aName) { + super(aName); + mTier = 3; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + return createTooltip("III"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_OreDrillingPlant3(mName); + } + + @Override + protected ItemList getCasingBlockItem() { + return ItemList.Casing_RobustTungstenSteel; + } + + @Override + protected Materials getFrameMaterial() { + return Materials.TungstenSteel; + } + + @Override + protected int getCasingTextureIndex() { + return 48; + } + + @Override + protected int getRadiusInChunks() { + return 6; + } + + @Override + protected int getMinTier() { + return 4; + } + + @Override + protected int getBaseProgressTime() { + return 640; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant4.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant4.java new file mode 100644 index 0000000000..7ba26b9500 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlant4.java @@ -0,0 +1,60 @@ +package gregtech.common.tileentities.machines.multi; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_OreDrillingPlant4 extends GT_MetaTileEntity_OreDrillingPlantBase { + + public GT_MetaTileEntity_OreDrillingPlant4(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + mTier = 4; + } + + public GT_MetaTileEntity_OreDrillingPlant4(String aName) { + super(aName); + mTier = 4; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + return createTooltip("IV"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_OreDrillingPlant4(mName); + } + + @Override + protected ItemList getCasingBlockItem() { + return ItemList.Casing_MiningOsmiridium; + } + + @Override + protected Materials getFrameMaterial() { + return Materials.Osmiridium; + } + + @Override + protected int getCasingTextureIndex() { + return 62; + } + + @Override + protected int getRadiusInChunks() { + return 9; + } + + @Override + protected int getMinTier() { + return 5; + } + + @Override + protected int getBaseProgressTime() { + return 480; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlantBase.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlantBase.java new file mode 100644 index 0000000000..9c15d2b6eb --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_OreDrillingPlantBase.java @@ -0,0 +1,745 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_Values.TIER_COLORS; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.ChunkPosition; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.modularui.api.NumberFormatMUI; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.SoundResource; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.gui.widgets.GT_LockedWhileActiveButton; +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.metatileentity.IMetricsExporter; +import gregtech.api.objects.GT_ChunkManager; +import gregtech.api.objects.ItemData; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.common.blocks.GT_Block_Ores_Abstract; +import gregtech.common.blocks.GT_TileEntity_Ores; + +public abstract class GT_MetaTileEntity_OreDrillingPlantBase extends GT_MetaTileEntity_DrillerBase + implements IMetricsExporter { + + private final List<ChunkPosition> oreBlockPositions = new ArrayList<>(); + protected int mTier = 1; + private int chunkRadiusConfig = getRadiusInChunks(); + private boolean replaceWithCobblestone = true; + + /** Used to drive the remaining ores count in the UI. */ + private int clientOreListSize = 0; + + /** Used to drive the current chunk number in the UI. */ + private int clientCurrentChunk = 0; + + /** Used to drive the total chunk count in the UI. */ + private int clientTotalChunks = 0; + + /** Used to drive the drill's y-level in the UI. */ + private int clientYHead = 0; + + GT_MetaTileEntity_OreDrillingPlantBase(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + GT_MetaTileEntity_OreDrillingPlantBase(String aName) { + super(aName); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setInteger("chunkRadiusConfig", chunkRadiusConfig); + aNBT.setBoolean("replaceWithCobblestone", replaceWithCobblestone); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (aNBT.hasKey("chunkRadiusConfig")) { + chunkRadiusConfig = aNBT.getInteger("chunkRadiusConfig"); + } + if (aNBT.hasKey("replaceWithCobblestone")) { + replaceWithCobblestone = aNBT.getBoolean("replaceWithCobblestone"); + } + } + + private void adjustChunkRadius(boolean increase) { + if (increase) { + if (chunkRadiusConfig <= getRadiusInChunks()) { + chunkRadiusConfig++; + } + if (chunkRadiusConfig > getRadiusInChunks()) chunkRadiusConfig = 1; + } else { + if (chunkRadiusConfig > 0) { + chunkRadiusConfig--; + } + if (chunkRadiusConfig == 0) chunkRadiusConfig = getRadiusInChunks(); + } + + if (mCurrentChunk != null && mChunkLoadingEnabled) { + GT_ChunkManager.releaseChunk((TileEntity) getBaseMetaTileEntity(), mCurrentChunk); + } + + oreBlockPositions.clear(); + createInitialWorkingChunk(); + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + super.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ); + + if (getBaseMetaTileEntity().isActive()) { + GT_Utility.sendChatToPlayer(aPlayer, StatCollector.translateToLocal("GT5U.machines.workarea_fail")); + } else { + adjustChunkRadius(!aPlayer.isSneaking()); + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("GT5U.machines.workareaset") + " " + + GT_Utility.formatNumbers((long) chunkRadiusConfig << 4) + + " " + + StatCollector.translateToLocal("GT5U.machines.radius")); + } + } + + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ) { + replaceWithCobblestone = !replaceWithCobblestone; + GT_Utility.sendChatToPlayer(aPlayer, "Replace with cobblestone " + replaceWithCobblestone); + return true; + } + + @Override + protected boolean workingDownward(ItemStack aStack, int xDrill, int yDrill, int zDrill, int xPipe, int zPipe, + int yHead, int oldYHead) { + if (yHead != oldYHead) oreBlockPositions.clear(); + + if (mWorkChunkNeedsReload && mChunkLoadingEnabled) { // ask to load machine itself + GT_ChunkManager.requestChunkLoad((TileEntity) getBaseMetaTileEntity(), null); + mWorkChunkNeedsReload = false; + } + fillMineListIfEmpty(xDrill, yDrill, zDrill, xPipe, zPipe, yHead); + if (oreBlockPositions.isEmpty()) { + switch (tryLowerPipeState()) { + case 2 -> { + mMaxProgresstime = 0; + setRuntimeFailureReason(CheckRecipeResultRegistry.MISSING_MINING_PIPE); + return false; + } + case 3 -> { + workState = STATE_UPWARD; + return true; + } + case 1 -> { + workState = STATE_AT_BOTTOM; + return true; + } + } + // new layer - fill again + fillMineListIfEmpty(xDrill, yDrill, zDrill, xPipe, zPipe, yHead); + } + return tryProcessOreList(); + } + + private boolean tryProcessOreList() { + // Even though it works fine without this check, + // it can save tiny amount of CPU time when void protection is disabled + if (protectsExcessItem()) { + boolean simulateResult = processOreList(true); + if (!simulateResult) { + mEUt = 0; + mMaxProgresstime = 0; + return false; + } + } + + boolean result = processOreList(false); + if (!result) { + mEUt = 0; + mMaxProgresstime = 0; + return false; + } + return true; + } + + private boolean processOreList(boolean simulate) { + ChunkPosition oreBlockPos = null; + List<ChunkPosition> oreBlockPositions = simulate ? copyOreBlockPositions(this.oreBlockPositions) + : this.oreBlockPositions; + int x = 0, y = 0, z = 0; + Block oreBlock = null; + int oreBlockMetadata = 0; + + while ((oreBlock == null || !GT_Utility.isOre(oreBlock, oreBlockMetadata)) && !oreBlockPositions.isEmpty()) { + oreBlockPos = oreBlockPositions.remove(0); + x = oreBlockPos.chunkPosX; + y = oreBlockPos.chunkPosY; + z = oreBlockPos.chunkPosZ; + if (GT_Utility.eraseBlockByFakePlayer(getFakePlayer(getBaseMetaTileEntity()), x, y, z, true)) + oreBlock = getBaseMetaTileEntity().getBlock(x, y, z); + oreBlockMetadata = getBaseMetaTileEntity().getWorld() + .getBlockMetadata(x, y, z); + } + + if (!tryConsumeDrillingFluid(simulate)) { + oreBlockPositions.add(0, oreBlockPos); + setRuntimeFailureReason(CheckRecipeResultRegistry.NO_DRILLING_FLUID); + return false; + } + if (oreBlock != null && GT_Utility.isOre(oreBlock, oreBlockMetadata)) { + short metaData = 0; + TileEntity tTileEntity = getBaseMetaTileEntity().getTileEntity(x, y, z); + if (tTileEntity instanceof GT_TileEntity_Ores) { + metaData = ((GT_TileEntity_Ores) tTileEntity).mMetaData; + } + + Collection<ItemStack> oreBlockDrops = getBlockDrops(oreBlock, x, y, z); + ItemStack cobble = GT_Utility.getCobbleForOre(oreBlock, metaData); + if (!simulate) { + if (replaceWithCobblestone) { + getBaseMetaTileEntity().getWorld() + .setBlock(x, y, z, Block.getBlockFromItem(cobble.getItem()), cobble.getItemDamage(), 3); + } else { + getBaseMetaTileEntity().getWorld() + .setBlockToAir(oreBlockPos.chunkPosX, oreBlockPos.chunkPosY, oreBlockPos.chunkPosZ); + } + } + ItemStack[] toOutput = getOutputByDrops(oreBlockDrops); + if (simulate && !canOutputAll(toOutput)) { + setRuntimeFailureReason(CheckRecipeResultRegistry.ITEM_OUTPUT_FULL); + return false; + } + mOutputItems = toOutput; + } + return true; + } + + private static List<ChunkPosition> copyOreBlockPositions(List<ChunkPosition> oreBlockPositions) { + List<ChunkPosition> ret = new ArrayList<>(); + for (ChunkPosition chunkPosition : oreBlockPositions) { + ret.add(new ChunkPosition(chunkPosition.chunkPosX, chunkPosition.chunkPosY, chunkPosition.chunkPosZ)); + } + return ret; + } + + @Override + protected boolean workingAtBottom(ItemStack aStack, int xDrill, int yDrill, int zDrill, int xPipe, int zPipe, + int yHead, int oldYHead) { + if (!mChunkLoadingEnabled) + return super.workingAtBottom(aStack, xDrill, yDrill, zDrill, xPipe, zPipe, yHead, oldYHead); + + if (mCurrentChunk == null) { + createInitialWorkingChunk(); + return true; + } + + if (mWorkChunkNeedsReload) { + GT_ChunkManager.requestChunkLoad((TileEntity) getBaseMetaTileEntity(), mCurrentChunk); + mWorkChunkNeedsReload = false; + return true; + } + if (oreBlockPositions.isEmpty()) { + fillChunkMineList(yHead, yDrill); + if (oreBlockPositions.isEmpty()) { + GT_ChunkManager.releaseChunk((TileEntity) getBaseMetaTileEntity(), mCurrentChunk); + if (!moveToNextChunk(xDrill >> 4, zDrill >> 4)) workState = STATE_UPWARD; + return true; + } + } + return tryProcessOreList(); + } + + private void createInitialWorkingChunk() { + mCurrentChunk = getTopLeftChunkCoords(); + if (mChunkLoadingEnabled) { + GT_ChunkManager.requestChunkLoad((TileEntity) getBaseMetaTileEntity(), mCurrentChunk); + mWorkChunkNeedsReload = false; + } + } + + @NotNull + private ChunkCoordIntPair getTopLeftChunkCoords() { + return getCornerCoords(-1, -1); + } + + @NotNull + private ChunkCoordIntPair getBottomRightChunkCoords() { + return getCornerCoords(1, 1); + } + + @NotNull + private ChunkCoordIntPair getCornerCoords(int xMultiplier, int zMultiplier) { + final ChunkCoordIntPair drillPos = getDrillCoords(); + // use corner closest to the drill as mining area center + return new ChunkCoordIntPair( + drillPos.chunkXPos + xMultiplier * chunkRadiusConfig + + ((getXDrill() - (drillPos.chunkXPos << 4)) < 8 ? 0 : 1), + drillPos.chunkZPos + zMultiplier * chunkRadiusConfig + + ((getZDrill() - (drillPos.chunkZPos << 4)) < 8 ? 0 : 1)); + } + + @NotNull + private ChunkCoordIntPair getDrillCoords() { + return new ChunkCoordIntPair(getXDrill() >> 4, getZDrill() >> 4); + } + + private int getTotalChunkCount() { + final ChunkCoordIntPair topLeft = getTopLeftChunkCoords(); + final ChunkCoordIntPair bottomRight = getBottomRightChunkCoords(); + return (bottomRight.chunkXPos - topLeft.chunkXPos) * (bottomRight.chunkZPos - topLeft.chunkZPos); + } + + /** + * Returns a number corresponding to which chunk the drill is operating on. Only really useful for driving outputs + * in the controller UI. + * + * @return 0 if the miner is not in operation, positive integer corresponding to the chunk currently being drilled + */ + @SuppressWarnings("ExtractMethodRecommender") + private int getChunkNumber() { + if (mCurrentChunk == null) { + return 0; + } + + final ChunkCoordIntPair topLeft = getTopLeftChunkCoords(); + final ChunkCoordIntPair drillPos = getDrillCoords(); + + if (workState == STATE_DOWNWARD) { + return 1; + } else if (workState == STATE_UPWARD) { + // Technically, the miner isn't mining anything now; it's retracting the pipes in preparation to end + // operation. + return 0; + } + + int chunkNumber = (chunkRadiusConfig * 2) * (mCurrentChunk.chunkZPos - topLeft.chunkZPos) + + mCurrentChunk.chunkXPos + - topLeft.chunkXPos + + 1; + + // Drills mine the chunk they're in first, so if we're not there yet, bump the number to indicate that it + // was already mined. + if (mCurrentChunk.chunkZPos < drillPos.chunkZPos + || (mCurrentChunk.chunkZPos == drillPos.chunkZPos && mCurrentChunk.chunkXPos < drillPos.chunkXPos)) { + chunkNumber += 1; + } + return chunkNumber; + } + + @Override + protected boolean workingUpward(ItemStack aStack, int xDrill, int yDrill, int zDrill, int xPipe, int zPipe, + int yHead, int oldYHead) { + boolean result; + if (!mChunkLoadingEnabled || oreBlockPositions.isEmpty()) { + result = super.workingUpward(aStack, xDrill, yDrill, zDrill, xPipe, zPipe, yHead, oldYHead); + } else { + result = tryProcessOreList(); + if (oreBlockPositions.isEmpty()) GT_ChunkManager.releaseTicket((TileEntity) getBaseMetaTileEntity()); + } + + if (!result) { + setShutdownReason(StatCollector.translateToLocal("GT5U.gui.text.drill_exhausted")); + } + + return result; + } + + @Override + protected void onAbort() { + oreBlockPositions.clear(); + if (mCurrentChunk != null) { + GT_ChunkManager.releaseChunk((TileEntity) getBaseMetaTileEntity(), mCurrentChunk); + } + mCurrentChunk = null; + } + + private boolean moveToNextChunk(int centerX, int centerZ) { + if (mCurrentChunk == null) return false; + // use corner closest to the drill as mining area center + final int left = centerX - chunkRadiusConfig + ((getXDrill() - (centerX << 4)) < 8 ? 0 : 1); + final int right = left + chunkRadiusConfig * 2; + final int bottom = centerZ + chunkRadiusConfig + ((getZDrill() - (centerZ << 4)) < 8 ? 0 : 1); + + int nextChunkX = mCurrentChunk.chunkXPos + 1; + int nextChunkZ = mCurrentChunk.chunkZPos; + + // step to the next chunk + if (nextChunkX >= right) { + nextChunkX = left; + ++nextChunkZ; + } + // skip center chunk - dug in workingDownward() + if (nextChunkX == centerX && nextChunkZ == centerZ) { + ++nextChunkX; + + if (nextChunkX >= right) { + nextChunkX = left; + ++nextChunkZ; + } + } + + if (nextChunkZ >= bottom) { + mCurrentChunk = null; + return false; + } + mCurrentChunk = new ChunkCoordIntPair(nextChunkX, nextChunkZ); + GT_ChunkManager + .requestChunkLoad((TileEntity) getBaseMetaTileEntity(), new ChunkCoordIntPair(nextChunkX, nextChunkZ)); + return true; + } + + @Override + protected boolean checkHatches() { + return !mMaintenanceHatches.isEmpty() && !mInputHatches.isEmpty() + && !mOutputBusses.isEmpty() + && !mEnergyHatches.isEmpty(); + } + + @Override + protected List<IHatchElement<? super GT_MetaTileEntity_DrillerBase>> getAllowedHatches() { + return ImmutableList.of(InputHatch, InputBus, OutputBus, Maintenance, Energy); + } + + @Override + protected void setElectricityStats() { + this.mEfficiency = getCurrentEfficiency(null); + this.mEfficiencyIncrease = 10000; + int tier = Math.max(1, GT_Utility.getTier(getMaxInputVoltage())); + this.mEUt = -3 * (1 << (tier << 1)); + this.mMaxProgresstime = calculateMaxProgressTime(tier); + } + + private int calculateMaxProgressTime(int tier) { + return Math.max( + 1, + ((workState == STATE_DOWNWARD || workState == STATE_AT_BOTTOM) ? getBaseProgressTime() : 80) / (1 << tier)); + } + + private ItemStack[] getOutputByDrops(Collection<ItemStack> oreBlockDrops) { + long voltage = getMaxInputVoltage(); + Collection<ItemStack> outputItems = new HashSet<>(); + oreBlockDrops.forEach(currentItem -> { + if (!doUseMaceratorRecipe(currentItem)) { + outputItems.add(multiplyStackSize(currentItem)); + return; + } + GT_Recipe tRecipe = RecipeMaps.maceratorRecipes + .findRecipe(getBaseMetaTileEntity(), false, voltage, null, currentItem); + if (tRecipe == null) { + outputItems.add(currentItem); + return; + } + for (int i = 0; i < tRecipe.mOutputs.length; i++) { + ItemStack recipeOutput = tRecipe.mOutputs[i].copy(); + if (getBaseMetaTileEntity().getRandomNumber(10000) < tRecipe.getOutputChance(i)) + multiplyStackSize(recipeOutput); + outputItems.add(recipeOutput); + } + }); + return outputItems.toArray(new ItemStack[0]); + } + + private boolean doUseMaceratorRecipe(ItemStack currentItem) { + ItemData itemData = GT_OreDictUnificator.getItemData(currentItem); + return itemData == null || itemData.mPrefix != OrePrefixes.crushed && itemData.mPrefix != OrePrefixes.dustImpure + && itemData.mPrefix != OrePrefixes.dust + && itemData.mPrefix != OrePrefixes.gem + && itemData.mPrefix != OrePrefixes.gemChipped + && itemData.mPrefix != OrePrefixes.gemExquisite + && itemData.mPrefix != OrePrefixes.gemFlawed + && itemData.mPrefix != OrePrefixes.gemFlawless + && itemData.mMaterial.mMaterial != Materials.Oilsands; + } + + private ItemStack multiplyStackSize(ItemStack itemStack) { + itemStack.stackSize *= getBaseMetaTileEntity().getRandomNumber(4) + 1; + return itemStack; + } + + private Collection<ItemStack> getBlockDrops(final Block oreBlock, int posX, int posY, int posZ) { + final int blockMeta = getBaseMetaTileEntity().getMetaID(posX, posY, posZ); + if (oreBlock.canSilkHarvest(getBaseMetaTileEntity().getWorld(), null, posX, posY, posZ, blockMeta)) { + return Collections.singleton(new ItemStack(oreBlock, 1, blockMeta)); + } + if (oreBlock instanceof GT_Block_Ores_Abstract) { + TileEntity tTileEntity = getBaseMetaTileEntity().getTileEntity(posX, posY, posZ); + if (tTileEntity instanceof GT_TileEntity_Ores && ((GT_TileEntity_Ores) tTileEntity).mMetaData >= 16000) { + // GT_Log.out.println("Running Small Ore"); + return oreBlock.getDrops(getBaseMetaTileEntity().getWorld(), posX, posY, posZ, blockMeta, mTier + 3); + } + } + // GT_Log.out.println("Running Normal Ore"); + return oreBlock.getDrops(getBaseMetaTileEntity().getWorld(), posX, posY, posZ, blockMeta, 0); + } + + private boolean tryConsumeDrillingFluid(boolean simulate) { + return depleteInput(new FluidStack(ItemList.sDrillingFluid, 2000), simulate); + } + + private void fillChunkMineList(int yHead, int yDrill) { + if (mCurrentChunk == null || !oreBlockPositions.isEmpty()) return; + final int minX = mCurrentChunk.chunkXPos << 4; + final int maxX = minX + 16; + final int minZ = mCurrentChunk.chunkZPos << 4; + final int maxZ = minZ + 16; + for (int x = minX; x < maxX; ++x) + for (int z = minZ; z < maxZ; ++z) for (int y = yHead; y < yDrill; ++y) tryAddOreBlockToMineList(x, y, z); + } + + private void fillMineListIfEmpty(int xDrill, int yDrill, int zDrill, int xPipe, int zPipe, int yHead) { + if (!oreBlockPositions.isEmpty()) return; + + tryAddOreBlockToMineList(xPipe, yHead - 1, zPipe); + if (yHead == yDrill) return; // skip controller block layer + + if (mChunkLoadingEnabled) { + int startX = (xDrill >> 4) << 4; + int startZ = (zDrill >> 4) << 4; + for (int x = startX; x < (startX + 16); ++x) + for (int z = startZ; z < (startZ + 16); ++z) tryAddOreBlockToMineList(x, yHead, z); + } else { + int radius = chunkRadiusConfig << 4; + for (int xOff = -radius; xOff <= radius; xOff++) for (int zOff = -radius; zOff <= radius; zOff++) + tryAddOreBlockToMineList(xDrill + xOff, yHead, zDrill + zOff); + } + } + + private void tryAddOreBlockToMineList(int x, int y, int z) { + Block block = getBaseMetaTileEntity().getBlock(x, y, z); + int blockMeta = getBaseMetaTileEntity().getMetaID(x, y, z); + ChunkPosition blockPos = new ChunkPosition(x, y, z); + if (!oreBlockPositions.contains(blockPos)) { + if (block instanceof GT_Block_Ores_Abstract) { + TileEntity tTileEntity = getBaseMetaTileEntity().getTileEntity(x, y, z); + if (tTileEntity instanceof GT_TileEntity_Ores && ((GT_TileEntity_Ores) tTileEntity).mNatural) + oreBlockPositions.add(blockPos); + } else if (GT_Utility.isOre(block, blockMeta)) oreBlockPositions.add(blockPos); + } + } + + protected abstract int getRadiusInChunks(); + + protected abstract int getBaseProgressTime(); + + protected GT_Multiblock_Tooltip_Builder createTooltip(String tierSuffix) { + String casings = getCasingBlockItem().get(0) + .getDisplayName(); + + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + final int baseCycleTime = calculateMaxProgressTime(getMinTier()); + tt.addMachineType("Miner") + .addInfo("Controller Block for the Ore Drilling Plant " + (tierSuffix != null ? tierSuffix : "")) + .addInfo("Use a Screwdriver to configure block radius") + .addInfo("Maximum radius is " + GT_Utility.formatNumbers((long) getRadiusInChunks() << 4) + " blocks") + .addInfo("Use Soldering iron to turn off chunk mode") + .addInfo("Use Wire Cutter to toggle replacing mined blocks with cobblestone") + .addInfo("In chunk mode, working area center is the chunk corner nearest to the drill") + .addInfo("Gives ~3x as much crushed ore vs normal processing") + .addInfo("Fortune bonus of " + GT_Utility.formatNumbers(mTier + 3) + ". Only works on small ores") + .addInfo("Minimum energy hatch tier: " + TIER_COLORS[getMinTier()] + VN[getMinTier()]) + .addInfo( + "Base cycle time: " + (baseCycleTime < 20 ? GT_Utility.formatNumbers(baseCycleTime) + " ticks" + : GT_Utility.formatNumbers(baseCycleTime / 20) + " seconds")) + .addSeparator() + .beginStructureBlock(3, 7, 3, false) + .addController("Front bottom") + .addOtherStructurePart(casings, "form the 3x1x3 Base") + .addOtherStructurePart(casings, "1x3x1 pillar above the center of the base (2 minimum total)") + .addOtherStructurePart(getFrameMaterial().mName + " Frame Boxes", "Each pillar's side and 1x3x1 on top") + .addEnergyHatch(VN[getMinTier()] + "+, Any base casing", 1) + .addMaintenanceHatch("Any base casing", 1) + .addInputBus("Mining Pipes, optional, any base casing", 1) + .addInputHatch("Drilling Fluid, any base casing", 1) + .addOutputBus("Any base casing", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + protected static final NumberFormatMUI numberFormat = new NumberFormatMUI(); + + @Override + protected void drawTexts(DynamicPositionedColumn screenElements, SlotWidget inventorySlot) { + super.drawTexts(screenElements, inventorySlot); + screenElements + .widget( + new TextWidget() + .setStringSupplier( + () -> EnumChatFormatting.GRAY + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.drill_ores_left_chunk", + numberFormat.format(clientOreListSize))) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled( + widget -> getBaseMetaTileEntity().isActive() && clientOreListSize > 0 + && workState == STATE_AT_BOTTOM)) + .widget( + new TextWidget() + .setStringSupplier( + () -> EnumChatFormatting.GRAY + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.drill_ores_left_layer", + numberFormat.format(clientYHead), + numberFormat.format(clientOreListSize))) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled( + widget -> getBaseMetaTileEntity().isActive() && clientYHead > 0 && workState == STATE_DOWNWARD)) + .widget( + new TextWidget() + .setStringSupplier( + () -> EnumChatFormatting.GRAY + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.drill_chunks_left", + numberFormat.format(clientCurrentChunk), + numberFormat.format(clientTotalChunks))) + .setTextAlignment(Alignment.CenterLeft) + .setEnabled( + widget -> getBaseMetaTileEntity().isActive() && clientCurrentChunk > 0 + && workState == STATE_AT_BOTTOM)) + .widget(new FakeSyncWidget.IntegerSyncer(oreBlockPositions::size, (newInt) -> clientOreListSize = newInt)) + .widget(new FakeSyncWidget.IntegerSyncer(this::getTotalChunkCount, (newInt) -> clientTotalChunks = newInt)) + .widget(new FakeSyncWidget.IntegerSyncer(this::getChunkNumber, (newInt) -> clientCurrentChunk = newInt)) + .widget(new FakeSyncWidget.IntegerSyncer(() -> workState, (newInt) -> workState = newInt)) + .widget(new FakeSyncWidget.IntegerSyncer(this::getYHead, (newInt) -> clientYHead = newInt)); + } + + @Override + protected List<ButtonWidget> getAdditionalButtons(ModularWindow.Builder builder, UIBuildContext buildContext) { + return ImmutableList.of( + (ButtonWidget) new GT_LockedWhileActiveButton(this.getBaseMetaTileEntity(), builder) + .setOnClick((clickData, widget) -> adjustChunkRadius(clickData.mouseButton == 0)) + .setPlayClickSound(true) + .setBackground(GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_WORK_AREA) + .attachSyncer( + new FakeSyncWidget.IntegerSyncer(() -> chunkRadiusConfig, (val) -> chunkRadiusConfig = val), + builder, + (widget, val) -> widget.notifyTooltipChange()) + .dynamicTooltip( + () -> ImmutableList.of( + StatCollector.translateToLocalFormatted( + "GT5U.gui.button.ore_drill_radius_1", + GT_Utility.formatNumbers((long) chunkRadiusConfig << 4)), + StatCollector.translateToLocal("GT5U.gui.button.ore_drill_radius_2"))) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setSize(16, 16), + (ButtonWidget) new GT_LockedWhileActiveButton(this.getBaseMetaTileEntity(), builder) + .setOnClick((clickData, widget) -> replaceWithCobblestone = !replaceWithCobblestone) + .setPlayClickSound(true) + .setBackground(() -> { + if (replaceWithCobblestone) { + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD_PRESSED, + GT_UITextures.OVERLAY_BUTTON_REPLACE_COBBLE_ON }; + } + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD, + GT_UITextures.OVERLAY_BUTTON_REPLACE_COBBLE_OFF }; + }) + .attachSyncer( + new FakeSyncWidget.BooleanSyncer( + () -> replaceWithCobblestone, + (val) -> replaceWithCobblestone = val), + builder, + (widget, val) -> widget.notifyTooltipChange()) + .dynamicTooltip( + () -> ImmutableList.of( + StatCollector.translateToLocal( + replaceWithCobblestone ? "GT5U.gui.button.ore_drill_cobblestone_on" + : "GT5U.gui.button.ore_drill_cobblestone_off"))) + .setTooltipShowUpDelay(TOOLTIP_DELAY) + .setSize(16, 16)); + } + + @Override + protected SoundResource getProcessStartSound() { + return SoundResource.IC2_MACHINES_MINER_OP; + } + + @Override + public String[] getInfoData() { + final String diameter = GT_Utility.formatNumbers(chunkRadiusConfig * 2L); + return new String[] { + EnumChatFormatting.BLUE + StatCollector.translateToLocal("GT5U.machines.minermulti") + + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.machines.workarea") + ": " + + EnumChatFormatting.GREEN + + diameter + + "x" + + diameter + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.machines.chunks") }; + } + + @Override + public @NotNull List<String> reportMetrics() { + if (getBaseMetaTileEntity().isActive()) { + return switch (workState) { + case STATE_AT_BOTTOM -> ImmutableList.of( + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.drill_ores_left_chunk", + GT_Utility.formatNumbers(oreBlockPositions.size())), + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.drill_chunks_left", + GT_Utility.formatNumbers(getChunkNumber()), + GT_Utility.formatNumbers(getTotalChunkCount()))); + case STATE_DOWNWARD -> ImmutableList.of( + StatCollector.translateToLocalFormatted( + "GT5U.gui.text.drill_ores_left_layer", + getYHead(), + GT_Utility.formatNumbers(oreBlockPositions.size()))); + case STATE_UPWARD, STATE_ABORT -> ImmutableList + .of(StatCollector.translateToLocal("GT5U.gui.text.retracting_pipe")); + + default -> ImmutableList.of(); + }; + } + + return ImmutableList.of( + getFailureReason() + .map(reason -> StatCollector.translateToLocalFormatted("GT5U.gui.text.drill_offline_reason", reason)) + .orElseGet(() -> StatCollector.translateToLocalFormatted("GT5U.gui.text.drill_offline_generic"))); + } + + @Override + public boolean supportsVoidProtection() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java new file mode 100644 index 0000000000..3616baf742 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PCBFactory.java @@ -0,0 +1,1276 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.ExoticEnergy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_Values.AuthorBlueWeabo; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_ASSEMBLY_LINE_GLOW; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.ofFrame; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nonnull; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; +import com.gtnewhorizon.structurelib.alignment.enumerable.Flip; +import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.drawable.Text; +import com.gtnewhorizons.modularui.api.drawable.UITexture; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Color; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.CycleButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedRow; +import com.gtnewhorizons.modularui.common.widget.MultiChildWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; +import com.gtnewhorizons.modularui.common.widget.textfield.NumericWidget; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.GregTechTileClientEvents; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.multitileentity.multiblock.casing.Glasses; +import gregtech.api.objects.ItemData; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; +import gregtech.api.recipe.metadata.PCBFactoryTierKey; +import gregtech.api.recipe.metadata.PCBFactoryUpgrade; +import gregtech.api.recipe.metadata.PCBFactoryUpgradeKey; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_ParallelHelper; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; +import gregtech.common.blocks.GT_Block_Casings8; + +@SuppressWarnings("SpellCheckingInspection") +public class GT_MetaTileEntity_PCBFactory extends + GT_MetaTileEntity_ExtendedPowerMultiBlockBase<GT_MetaTileEntity_PCBFactory> implements ISurvivalConstructable { + + private static final String tier1 = "tier1"; + private static final String tier2 = "tier2"; + private static final String tier3 = "tier3"; + private static final String bioUpgrade = "bioUpgrade"; + private static final String ocTier1Upgrade = "ocTier1Upgrade"; + private static final String ocTier2Upgrade = "ocTier2Upgrade"; + private float mRoughnessMultiplier = 1; + private int mTier = 1, mSetTier = 1, mUpgradesInstalled = 0, mCurrentParallel = 0, mMaxParallel = 0; + private boolean mBioUpgrade = false, mBioRotate = false, mOCTier1 = false, mOCTier2 = false; + private final int[] mBioOffsets = new int[] { -5, -1 }; + private final int[] mOCTier1Offsets = new int[] { 2, -11 }; + private final int[] mOCTier2Offsets = new int[] { 2, -11 }; + private GT_MetaTileEntity_Hatch_Input mCoolantInputHatch; + private static final int mBioRotateBitMap = 0b1000000; + private static final int mOCTier2BitMap = 0b100000; + private static final int mOCTier1BitMap = 0b10000; + private static final int mBioBitMap = 0b1000; + private static final int mTier3BitMap = 0b100; + private static final int mTier2BitMap = 0b10; + private static final int mTier1BitMap = 0b1; + private static final int COOLANT_CONSUMED_PER_SEC = 10; + private static final IStructureDefinition<GT_MetaTileEntity_PCBFactory> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_PCBFactory>builder() + .addShape( + tier1, + transpose( + new String[][] { + // spotless:off + {" ","E E","E E","EEEEEEE","E E","E E"," "}, + {"EEEEEEE","CAAAAAC","CAAAAAC","CCCCCCC","CCCCCCC","CCCCCCC","E E"}, + {"EAAAAAE","C-----C","C-----C","C-----C","C-----C","C-----C","ECCCCCE"}, + {"EAAAAAE","C-----C","B-----B","B-----B","B-----B","C-----C","ECCCCCE"}, + {"EAAAAAE","C-----C","B-FFF-B","B-FFF-B","B-FFF-B","C-----C","EPPPPPE"}, + {"ECC~CCE","CDDDDDC","CDDDDDC","CDDDDDC","CDDDDDC","CDDDDDC","EPPPPPE"} + //spotless:on + })) + .addShape( + tier2, + transpose( + new String[][] { + // spotless:off + {" "," "," ","HGGH","HGGH","HGGH","HGGH","HGGH"," "," "," "}, + {" "," ","HGGH","GGGG","GGGG","GGGG","GGGG","GGGG","HGGH"," "," "}, + {" ","HGGH","GGGG","G G","G G","G G","G G","G G","GGGG","HGGH"," "}, + {" ","HGGH","G G","G G","G G","G G","G G","G G","G G","HGGH"," "}, + {"HGGH","G G","G G","G G","G G","G G","G G","G G","G G","G G","HGGH"}, + {"HGGH","G G","G G","G G","G G","G G","G G","G G","G G","G G","HGGH"}, + {"HGGH","GGGG","GGGG","GGGG","GGGG","GGGG","GGGG","GGGG","GGGG","GGGG","HGGH"} + //spotless:on + })) + .addShape( + tier3, + transpose( + new String[][] { + // spotless:off + {" "," "," "," "," I "," I "," "," "," "," "}, + {" "," "," "," I "," I "," I "," I "," "," "," "}, + {" "," "," KKK "," KIK "," K K "," K K "," I "," "," "," "}, + {" "," "," KKK "," K K "," K K "," K K "," I "," "," "," "}, + {" "," III "," I I "," I I "," I I "," K K "," I "," "," "," "}, + {" "," III "," I I "," I I "," I I "," K K "," I "," "," "," "}, + {" "," III "," I I "," I I "," I I "," K K "," KIK "," "," "," "}, + {" "," I I "," I K I "," I I "," I I "," K K "," KIK "," "," "," "}, + {" "," I I "," I K I "," I I "," I I "," K K "," K K "," KKK "," "," "}, + {" "," I I "," I K I "," I I "," I I "," K K "," K K "," KKK "," "," "}, + {" "," III "," I I "," I I "," I I "," I I "," I I "," I I "," III "," "}, + {" "," III "," I I "," K K "," K K "," K K "," K K "," I I "," III "," "}, + {" "," III "," I I "," I I "," I I "," I I "," I I "," I I "," III "," "}, + {" "," "," KKK "," K K "," K K "," I I "," I I "," I I "," III "," "}, + {" "," "," KKK "," K K "," K K "," I I "," I I "," I I "," III "," "}, + {" "," "," KKK "," K K "," K K "," I I "," I I "," I I "," III "," "}, + {" "," III "," I I "," I I "," I I "," I I "," I I "," I I "," III "," "}, + {" "," III "," I I "," I I "," I I "," I I "," I I "," I I "," III "," "}, + {" "," III "," I I "," I I "," I I "," I I "," I I "," I I "," III "," "}, + {" "," III "," I I "," I I "," I I "," I I "," I I "," I I "," III "," "}, + {" "," III "," I I "," I I "," I I "," I I "," I I "," I I "," III "," "}, + {" II~II ","IIJJJII","IJJJJJI","IJJJJJI","IJJJJJI","IJJJJJI","IJJJJJI","IJJJJJI","IIJJJII"," IIIII "} + //spotless:on + })) + .addShape( + bioUpgrade, + transpose( + new String[][] { + // spotless:off + {" "," "," LLLLLL "," "," "}, + {" "," "," L L "," "," "}, + {"E E E E"," LLL LLL "," LLL LLL "," LLL LLL ","E E E E"}, + {"EAAAE EAAAE","A A A A","A A A A","A A A A","EAAAE EAAAE"}, + {"EAAAE EAAAE","A A A A","A A A A","A A A A","EAAAE EAAAE"}, + {"EAAAE EAAAE","A A A A","A A A A","A A A A","EAAAE EAAAE"}, + {"ELLLE ELLLE","LLLLL LLLLL","LLLLL LLLLL","LLLLL LLLLL","ELLLE ELLLE"} + //spotless:on + })) + .addShape( + ocTier1Upgrade, + transpose( + new String[][] { + // spotless:off + {"EKKKE","K K","K K","K K","EKKKE"}, + {"E E"," KKK "," K K "," KKK ","E E"}, + {"E E"," NNN "," N N "," NNN ","E E"}, + {"E E"," KKK "," K K "," KKK ","E E"}, + {"E E"," KKK "," K K "," KKK ","E E"}, + {"EOOOE","OKKKO","OK KO","OKKKO","EOOOE"}, + {"E E"," KKK "," K K "," KKK ","E E"}, + {"E E"," KKK "," K K "," KKK ","E E"}, + {"ENNNE","NKKKN","NK KN","NKKKN","ENNNE"}, + {"EGGGE","GGGGG","GGMGG","GGGGG","EGGGE"} + //spotless:on + })) + .addShape( + ocTier2Upgrade, + transpose( + new String[][] { + // spotless:off + {"RGGGR","G G","G G","G G","RGGGR"}, + {"R R"," GGG "," GTG "," GGG ","R R"}, + {"R R"," NNN "," NTN "," NNN ","R R"}, + {"R R"," QQQ "," QTQ "," QQQ ","R R"}, + {"R R"," QQQ "," QTQ "," QQQ ","R R"}, + {"R R"," QQQ "," QTQ "," QQQ ","R R"}, + {"R R"," QQQ "," QTQ "," QQQ ","R R"}, + {"R R"," QQQ "," QTQ "," QQQ ","R R"}, + {"RNNNR","NQQQN","NQTQN","NQQQN","RNNNR"}, + {"RGGGR","GGGGG","GGSGG","GGGGG","RGGGR"} + //spotless:on + })) + .addElement('E', ofFrame(Materials.DamascusSteel)) + .addElement('C', ofBlock(GregTech_API.sBlockCasings8, 11)) + .addElement('D', ofBlock(GregTech_API.sBlockReinforced, 2)) + .addElement('A', Glasses.chainAllGlasses()) + .addElement('B', ofBlock(GregTech_API.sBlockCasings3, 10)) + .addElement('F', ofFrame(Materials.VibrantAlloy)) + .addElement( + 'P', + buildHatchAdder(GT_MetaTileEntity_PCBFactory.class) + .atLeast(InputHatch, OutputBus, InputBus, Maintenance, Energy.or(ExoticEnergy)) + .dot(1) + .casingIndex(((GT_Block_Casings8) GregTech_API.sBlockCasings8).getTextureIndex(11)) + .buildAndChain(GregTech_API.sBlockCasings8, 11)) + .addElement('H', ofFrame(Materials.Duranium)) + .addElement('G', ofBlock(GregTech_API.sBlockCasings8, 12)) + .addElement('I', ofBlock(GregTech_API.sBlockCasings8, 13)) + .addElement('K', ofBlock(GregTech_API.sBlockCasings8, 10)) + .addElement( + 'J', + buildHatchAdder(GT_MetaTileEntity_PCBFactory.class) + .atLeast(InputHatch, OutputBus, InputBus, Maintenance, Energy.or(ExoticEnergy)) + .dot(1) + .casingIndex(((GT_Block_Casings8) GregTech_API.sBlockCasings8).getTextureIndex(13)) + .buildAndChain(GregTech_API.sBlockCasings8, 13)) + .addElement('L', ofBlock(GregTech_API.sBlockCasings4, 1)) + .addElement( + 'M', + buildHatchAdder(GT_MetaTileEntity_PCBFactory.class).hatchClass(GT_MetaTileEntity_Hatch_Input.class) + .adder(GT_MetaTileEntity_PCBFactory::addCoolantInputToMachineList) + .casingIndex(GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings8, 12)) + .dot(2) + .buildAndChain(GregTech_API.sBlockCasings8, 12)) + .addElement('N', ofBlock(GregTech_API.sBlockCasings2, 15)) + .addElement('O', ofBlock(GregTech_API.sBlockCasings8, 4)) + .addElement( + 'S', + buildHatchAdder(GT_MetaTileEntity_PCBFactory.class).hatchClass(GT_MetaTileEntity_Hatch_Input.class) + .adder(GT_MetaTileEntity_PCBFactory::addCoolantInputToMachineList) + .casingIndex(GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings8, 12)) + .dot(2) + .buildAndChain(GregTech_API.sBlockCasings8, 12)) + .addElement('R', ofFrame(Materials.Americium)) + .addElement('Q', ofBlock(GregTech_API.sBlockCasings8, 14)) + .addElement('T', ofBlock(GregTech_API.sBlockCasings1, 15)) + .build(); + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + if (mSetTier < 3) { + buildPiece(tier1, stackSize, hintsOnly, 3, 5, 0); + if (mSetTier == 2) { + buildPiece(tier2, stackSize, hintsOnly, 7, 6, 2); + } + } else { + buildPiece(tier3, stackSize, hintsOnly, 3, 21, 0); + } + + if (mBioUpgrade) { + if (mBioRotate) { + final IGregTechTileEntity tTile = getBaseMetaTileEntity(); + getStructureDefinition().buildOrHints( + this, + stackSize, + bioUpgrade, + tTile.getWorld(), + transformFacing(getExtendedFacing()), + tTile.getXCoord(), + tTile.getYCoord(), + tTile.getZCoord(), + mBioOffsets[1], + 6, + mBioOffsets[0], + hintsOnly); + } else { + buildPiece(bioUpgrade, stackSize, hintsOnly, mBioOffsets[0], 6, mBioOffsets[1]); + } + } + + if (mOCTier1 && !mOCTier2) { + buildPiece(ocTier1Upgrade, stackSize, hintsOnly, mOCTier1Offsets[0], 9, mOCTier1Offsets[1]); + } + + if (!mOCTier1 && mOCTier2) { + buildPiece(ocTier2Upgrade, stackSize, hintsOnly, mOCTier2Offsets[0], 9, mOCTier2Offsets[1]); + } + } + + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + int built = 0; + if (mSetTier < 3) { + built += survivialBuildPiece(tier1, stackSize, 3, 5, 0, elementBudget, env, false, true); + if (mSetTier == 2) { + built += survivialBuildPiece(tier2, stackSize, 7, 6, 2, elementBudget, env, false, true); + } + } else { + built += survivialBuildPiece(tier3, stackSize, 3, 21, 0, elementBudget, env, false, true); + } + + if (mBioUpgrade) { + if (mBioRotate) { + final IGregTechTileEntity tTile = getBaseMetaTileEntity(); + getStructureDefinition().survivalBuild( + this, + stackSize, + bioUpgrade, + tTile.getWorld(), + transformFacing(getExtendedFacing()), + tTile.getXCoord(), + tTile.getYCoord(), + tTile.getZCoord(), + mBioOffsets[1], + 6, + mBioOffsets[0], + elementBudget, + env, + false); + } else { + built += survivialBuildPiece( + bioUpgrade, + stackSize, + mBioOffsets[0], + 6, + mBioOffsets[1], + elementBudget, + env, + false, + true); + } + } + + if (mOCTier1 && !mOCTier2) { + built += survivialBuildPiece( + ocTier1Upgrade, + stackSize, + mOCTier1Offsets[0], + 9, + mOCTier1Offsets[1], + elementBudget, + env, + false, + true); + } + if (!mOCTier1 && mOCTier2) { + built += survivialBuildPiece( + ocTier2Upgrade, + stackSize, + mOCTier2Offsets[0], + 9, + mOCTier2Offsets[1], + elementBudget, + env, + false, + true); + } + + return built; + } + + public GT_MetaTileEntity_PCBFactory(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_PCBFactory(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_PCBFactory(this.mName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + if (sideDirection == facingDirection) { + if (active) + return new ITexture[] { + BlockIcons.getCasingTextureForId( + getTier() < 3 ? GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings8, 11) + : GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings8, 13)), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { + BlockIcons.getCasingTextureForId( + getTier() < 3 ? GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings8, 11) + : GT_Utility.getCasingTextureIndex(GregTech_API.sBlockCasings8, 13)), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ASSEMBLY_LINE_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { BlockIcons.getCasingTextureForId( + mSetTier < 3 ? ((GT_Block_Casings8) GregTech_API.sBlockCasings8).getTextureIndex(11) + : ((GT_Block_Casings8) GregTech_API.sBlockCasings8).getTextureIndex(13)) }; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_PCBFactory> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + mTier = 0; + mUpgradesInstalled = 0; + mCoolantInputHatch = null; + if (mSetTier < 3) { + if (!checkPiece(tier1, 3, 5, 0)) { + return false; + } + if (mSetTier == 2) { + if (!checkPiece(tier2, 7, 6, 2)) { + return false; + } + mTier = 2; + } else { + mTier = 1; + } + } else { + if (!checkPiece(tier3, 3, 21, 0)) { + return false; + } + mTier = 3; + } + + if (mBioUpgrade) { + if (mBioRotate) { + final IGregTechTileEntity tTile = getBaseMetaTileEntity(); + if (!getStructureDefinition().check( + this, + bioUpgrade, + tTile.getWorld(), + transformFacing(getExtendedFacing()), + tTile.getXCoord(), + tTile.getYCoord(), + tTile.getZCoord(), + mBioOffsets[1], + 6, + mBioOffsets[0], + !mMachine)) { + return false; + } + } else { + if (!checkPiece(bioUpgrade, mBioOffsets[0], 6, mBioOffsets[1])) { + return false; + } + } + mUpgradesInstalled++; + } + + if (mOCTier1 && !mOCTier2) { + if (!checkPiece(ocTier1Upgrade, mOCTier1Offsets[0], 9, mOCTier1Offsets[1])) { + return false; + } + if (mCoolantInputHatch == null) { + return false; + } + mUpgradesInstalled++; + } + + if (mOCTier2 && !mOCTier1) { + if (!checkPiece(ocTier2Upgrade, mOCTier2Offsets[0], 9, mOCTier2Offsets[1])) { + return false; + } + if (mCoolantInputHatch == null) { + return false; + } + mUpgradesInstalled++; + } + + getBaseMetaTileEntity().sendBlockEvent(GregTechTileClientEvents.CHANGE_CUSTOM_DATA, getUpdateData()); + + if (mMaintenanceHatches.size() != 1) { + return false; + } + + if (!checkExoticAndNormalEnergyHatches()) { + return false; + } + + return mTier > 0; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.pcbFactoryRecipes; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @NotNull + @Override + protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + // Here we check the dynamic parallels, which depend on the recipe + int numberOfNanites = 0; + ItemStack aNanite = recipe.getRepresentativeInput(1); + ItemData naniteData = GT_OreDictUnificator.getAssociation(aNanite); + if (naniteData != null && naniteData.mPrefix != null && naniteData.mPrefix.equals(OrePrefixes.nanite)) { + for (ItemStack aItem : inputItems) { + if (aItem != null && aItem.isItemEqual(aNanite)) { + numberOfNanites += aItem.stackSize; + } + } + } + maxParallel = (int) Math.max(Math.ceil(Math.log(numberOfNanites) / Math.log(2) + 0.00001), 1); + mMaxParallel = maxParallel; + + PCBFactoryUpgrade requiredUpgrade = recipe.getMetadata(PCBFactoryUpgradeKey.INSTANCE); + if (requiredUpgrade == PCBFactoryUpgrade.BIO && !mBioUpgrade) + return SimpleCheckRecipeResult.ofFailure("bio_upgrade_missing"); + + int requiredPCBTier = recipe.getMetadataOrDefault(PCBFactoryTierKey.INSTANCE, 1); + if (requiredPCBTier > mTier) return CheckRecipeResultRegistry.insufficientMachineTier(requiredPCBTier); + + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + @Nonnull + @Override + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) { + return super.createOverclockCalculator(recipe).setNoOverclock(isNoOC()) + .setEUtDiscount((float) Math.sqrt(mUpgradesInstalled == 0 ? 1 : mUpgradesInstalled)) + .setSpeedBoost(getDurationMultiplierFromRoughness()) + .setDurationDecreasePerOC(mOCTier2 ? 2 : 1); + } + + @Nonnull + @Override + protected GT_ParallelHelper createParallelHelper(@Nonnull GT_Recipe recipe) { + return super.createParallelHelper(recipe) + .setEUtModifier((float) Math.sqrt(mUpgradesInstalled == 0 ? 1 : mUpgradesInstalled)) + .setChanceMultiplier(mRoughnessMultiplier); + } + }; + } + + private boolean isNoOC() { + return !mOCTier1 && !mOCTier2; + } + + private float getDurationMultiplierFromRoughness() { + return (float) Math.pow(mRoughnessMultiplier, 2); + } + + private int ticker = 0; + + @Override + public boolean onRunningTick(ItemStack aStack) { + if (!super.onRunningTick(aStack)) { + return false; + } + + if (ticker % 20 == 0) { + if (!isNoOC()) { + FluidStack tFluid = mOCTier1 ? GT_ModHandler.getDistilledWater(COOLANT_CONSUMED_PER_SEC) + : Materials.SuperCoolant.getFluid(COOLANT_CONSUMED_PER_SEC); + if (!drain(mCoolantInputHatch, tFluid, true)) { + stopMachine(ShutDownReasonRegistry.outOfFluid(tFluid)); + return false; + } + } + ticker = 0; + } + + ticker++; + + return true; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isServerSide()) { + // TODO: Look for proper fix + // Updates every 10 sec + if (mUpdate <= -150) mUpdate = 50; + } + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return (int) (10000f * mRoughnessMultiplier); + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + private int getTier() { + return mSetTier; + } + + @Override + public void receiveClientEvent(byte aEventID, byte aValue) { + if (aEventID == 1) { + if ((aValue & mTier1BitMap) == mTier1BitMap) { + mSetTier = 1; + } + + if ((aValue & mTier2BitMap) == mTier2BitMap) { + mSetTier = 2; + } + + if ((aValue & mTier3BitMap) == mTier3BitMap) { + mSetTier = 3; + } + + if ((aValue & mBioBitMap) == mBioBitMap) { + mBioUpgrade = true; + } + + if ((aValue & mBioRotateBitMap) == mBioRotateBitMap) { + mBioRotate = true; + } + + if ((aValue & mOCTier1BitMap) == mOCTier1BitMap) { + mOCTier1 = true; + } + + if ((aValue & mOCTier2BitMap) == mOCTier2BitMap) { + mOCTier2 = true; + } + } + } + + private ExtendedFacing transformFacing(ExtendedFacing facing) { + ForgeDirection curDirection = facing.getDirection(); + Rotation curRotation = facing.getRotation(); + Flip curFlip = facing.getFlip(); + ForgeDirection newDirection = curDirection; + Rotation newRotation = curRotation; + Flip newFlip = curFlip; + + if (curDirection == ForgeDirection.UP || curDirection == ForgeDirection.DOWN) { + switch (curRotation) { + case CLOCKWISE, COUNTER_CLOCKWISE -> { + newFlip = curFlip == Flip.NONE ? Flip.HORIZONTAL : Flip.NONE; + newDirection = curDirection == ForgeDirection.UP ? ForgeDirection.NORTH : ForgeDirection.SOUTH; + } + case NORMAL -> { + newRotation = curDirection == ForgeDirection.UP ? Rotation.CLOCKWISE : Rotation.COUNTER_CLOCKWISE; + newDirection = curDirection == ForgeDirection.UP ? ForgeDirection.EAST : ForgeDirection.WEST; + newFlip = Flip.NONE; + } + case UPSIDE_DOWN -> { + newRotation = curDirection == ForgeDirection.UP ? Rotation.COUNTER_CLOCKWISE : Rotation.CLOCKWISE; + newDirection = curDirection == ForgeDirection.UP ? ForgeDirection.EAST : ForgeDirection.WEST; + newFlip = Flip.NONE; + } + } + } else if (curRotation == Rotation.CLOCKWISE || curRotation == Rotation.COUNTER_CLOCKWISE) { + newFlip = curRotation == Rotation.CLOCKWISE ? curFlip == Flip.NONE ? Flip.NONE : Flip.HORIZONTAL + : curFlip != Flip.NONE ? Flip.NONE : Flip.HORIZONTAL; + newDirection = curRotation == Rotation.CLOCKWISE ? ForgeDirection.UP : ForgeDirection.DOWN; + } else { + newDirection = switch (curDirection) { + case EAST -> ForgeDirection.SOUTH; + case NORTH -> ForgeDirection.EAST; + case WEST -> ForgeDirection.NORTH; + case SOUTH -> ForgeDirection.WEST; + default -> curDirection; + }; + } + + if (curRotation == Rotation.UPSIDE_DOWN) { + if (curDirection != ForgeDirection.UP && curDirection != ForgeDirection.DOWN) { + newFlip = curFlip == Flip.NONE ? Flip.HORIZONTAL : Flip.NONE; + } + } + + return ExtendedFacing.of(newDirection, newRotation, newFlip); + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + public boolean addCoolantInputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) { + ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); + ((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity).mRecipeMap = null; + mCoolantInputHatch = (GT_MetaTileEntity_Hatch_Input) aMetaTileEntity; + return true; + } + return false; + } + + @Override + protected long getActualEnergyUsage() { + return (-this.lEUt * 10000) / Math.min(Math.max(1000, mEfficiency), 10000); + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + inputSeparation = !inputSeparation; + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("GT5U.machines.separatebus") + " " + inputSeparation); + } + + @Override + public String[] getInfoData() { + int mPollutionReduction = 0; + for (GT_MetaTileEntity_Hatch_Muffler tHatch : filterValidMTEs(mMufflerHatches)) { + mPollutionReduction = Math.max(tHatch.calculatePollutionReduction(100), mPollutionReduction); + } + + long storedEnergy = 0; + long maxEnergy = 0; + for (GT_MetaTileEntity_Hatch tHatch : getExoticAndNormalEnergyHatchList()) { + storedEnergy += tHatch.getBaseMetaTileEntity() + .getStoredEU(); + maxEnergy += tHatch.getBaseMetaTileEntity() + .getEUCapacity(); + } + long voltage = getAverageInputVoltage(); + long amps = getMaxInputAmps(); + + return new String[] { + /* 1 */ StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mProgresstime / 20) + + EnumChatFormatting.RESET + + " s / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mMaxProgresstime / 20) + + EnumChatFormatting.RESET + + " s", + /* 2 */ StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(storedEnergy) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxEnergy) + + EnumChatFormatting.RESET + + " EU", + /* 3 */ StatCollector.translateToLocal("GT5U.multiblock.usage") + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(getActualEnergyUsage()) + + EnumChatFormatting.RESET + + " EU/t", + /* 4 */ StatCollector.translateToLocal("GT5U.multiblock.mei") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(voltage) + + EnumChatFormatting.RESET + + " EU/t(*" + + amps + + " A)" + + StatCollector.translateToLocal("GT5U.machines.tier") + + ": " + + EnumChatFormatting.YELLOW + + VN[GT_Utility.getTier(voltage)] + + EnumChatFormatting.RESET, + /* 5 */ StatCollector.translateToLocal("GT5U.multiblock.problems") + ": " + + EnumChatFormatting.RED + + (getIdealStatus() - getRepairStatus()) + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.multiblock.efficiency") + + ": " + + EnumChatFormatting.YELLOW + + mEfficiency / 100.0F + + EnumChatFormatting.RESET + + " %", + /* 6 */ StatCollector.translateToLocal("GT5U.multiblock.pollution") + ": " + + EnumChatFormatting.GREEN + + mPollutionReduction + + EnumChatFormatting.RESET + + " %", + /* 7 */ StatCollector.translateToLocal("GT5U.multiblock.parallelism") + ": " + + EnumChatFormatting.GREEN + + mMaxParallel, + /* 8 */ StatCollector.translateToLocal("GT5U.multiblock.curparallelism") + ": " + + EnumChatFormatting.GREEN + + mCurrentParallel }; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Circuit Board Fabricator") + .addInfo("Controller for the PCB Factory") + .addInfo( + EnumChatFormatting.GOLD.toString() + EnumChatFormatting.BOLD + + "IMPORTANT!" + + " Check the configuration menu before building.") + .addInfo("Tier of the machine determines the available recipes.") + .addInfo("Machine tier (1-3) is set in the controller GUI.") + .addInfo("The configuration menu can be used to add upgrades.") + .addInfo("Each tier and upgrade requires additional structures.") + .addInfo("Power consumption is multiplied by Sqrt(structures).") + .addInfo("Tier 2 and 3 allow parallel by using extra nanites.") + .addInfo("Every doubling of nanites adds one parallel.") + .addInfo("1x->1, 2x->2, 4x->3, 8x->4 with no limit.") + .addInfo("Recipes require a cooling upgrade to be overclocked.") + .addInfo("Liquid Cooling uses 10 L/s of distilled water and enables default overclocks.") + .addInfo("Thermosink uses 10 L/s of Super Coolant and enables perfect overclocks.") + .addInfo("Trace size can be changed to modify the material usage and machine speed.") + .addInfo(AuthorBlueWeabo) + .beginStructureBlock(30, 38, 13, false) + .addSeparator() + .addMaintenanceHatch(EnumChatFormatting.GOLD + "1", 1) + .addEnergyHatch( + EnumChatFormatting.GOLD + "1" + + EnumChatFormatting.GRAY + + "-" + + EnumChatFormatting.GOLD + + "2" + + EnumChatFormatting.GRAY + + " or " + + EnumChatFormatting.GOLD + + "1" + + EnumChatFormatting.GRAY + + " TT energy hatch.", + 1) + .addInputBus(EnumChatFormatting.GOLD + "0" + EnumChatFormatting.GRAY + "+", 1) + .addOutputBus(EnumChatFormatting.GOLD + "0" + EnumChatFormatting.GRAY + "+", 1) + .addInputHatch(EnumChatFormatting.GOLD + "0" + EnumChatFormatting.GRAY + "+", 1) + .addStructureInfo( + "Coolant Hatch (Input Hatch): " + EnumChatFormatting.GOLD + + "1" + + EnumChatFormatting.GRAY + + " Center of the Liquid Cooling/Thermosink") + .addStructureInfo( + EnumChatFormatting.BLUE + "Base Multi (Tier " + + EnumChatFormatting.DARK_PURPLE + + 1 + + EnumChatFormatting.BLUE + + "):") + .addStructureInfo(EnumChatFormatting.GOLD + "40" + EnumChatFormatting.GRAY + " Damascus Steel Frame Box") + .addStructureInfo(EnumChatFormatting.GOLD + "9" + EnumChatFormatting.GRAY + " Vibrant Alloy Frame Box") + .addStructureInfo(EnumChatFormatting.GOLD + "25" + EnumChatFormatting.GRAY + " Reinforced Glass") + .addStructureInfo( + EnumChatFormatting.GOLD + "77" + EnumChatFormatting.GRAY + " Basic Photolithography Framework Casing") + .addStructureInfo(EnumChatFormatting.GOLD + "12" + EnumChatFormatting.GRAY + " Grate Machine Casing") + .addStructureInfo(EnumChatFormatting.GOLD + "25" + EnumChatFormatting.GRAY + " Plascrete Block") + .addStructureInfo( + EnumChatFormatting.BLUE + "Tier " + + EnumChatFormatting.DARK_PURPLE + + 2 + + EnumChatFormatting.BLUE + + " (Adds to Tier " + + EnumChatFormatting.DARK_PURPLE + + 1 + + EnumChatFormatting.BLUE + + "):") + .addStructureInfo(EnumChatFormatting.GOLD + "34" + EnumChatFormatting.GRAY + " Duranium Frame Box") + .addStructureInfo( + EnumChatFormatting.GOLD + "158" + + EnumChatFormatting.GRAY + + " Reinforced Photolithography Framework Casing") + .addStructureInfo( + EnumChatFormatting.BLUE + "Tier " + EnumChatFormatting.DARK_PURPLE + 3 + EnumChatFormatting.BLUE + ":") + .addStructureInfo( + EnumChatFormatting.GOLD + "292" + + EnumChatFormatting.GRAY + + " Radiation Proof Photolithography Framework Casing") + .addStructureInfo( + EnumChatFormatting.GOLD + "76" + EnumChatFormatting.GRAY + " Radiant Naquadah Alloy Casing") + .addStructureInfo(EnumChatFormatting.BLUE + "Biochamber Upgrade") + .addStructureInfo( + EnumChatFormatting.GOLD + "68" + EnumChatFormatting.GRAY + " Clean Stainless Steel Machine Casing") + .addStructureInfo(EnumChatFormatting.GOLD + "40" + EnumChatFormatting.GRAY + " Damascus Steel Frame Box") + .addStructureInfo(EnumChatFormatting.GOLD + "72" + EnumChatFormatting.GRAY + " Reinforced Glass") + .addStructureInfo( + EnumChatFormatting.BLUE + "Liquid Cooling Tower (Tier " + + EnumChatFormatting.DARK_PURPLE + + 1 + + EnumChatFormatting.BLUE + + "):") + .addStructureInfo(EnumChatFormatting.GOLD + "40" + EnumChatFormatting.GRAY + " Damascus Steel Frame Box") + .addStructureInfo( + EnumChatFormatting.GOLD + "68" + EnumChatFormatting.GRAY + " Radiant Naquadah Alloy Casing") + .addStructureInfo( + EnumChatFormatting.GOLD + "12" + EnumChatFormatting.GRAY + " Extreme Engine Intake Casing") + .addStructureInfo(EnumChatFormatting.GOLD + "20" + EnumChatFormatting.GRAY + " Tungstensteel Pipe Casing") + .addStructureInfo( + EnumChatFormatting.GOLD + "21" + + EnumChatFormatting.GRAY + + " Reinforced Photolithography Framework Casing") + .addStructureInfo( + EnumChatFormatting.BLUE + "Thermosink Radiator(Tier " + + EnumChatFormatting.DARK_PURPLE + + 2 + + EnumChatFormatting.BLUE + + "):") + .addStructureInfo(EnumChatFormatting.GOLD + "40" + EnumChatFormatting.GRAY + " Americium Frame Box") + .addStructureInfo( + EnumChatFormatting.GOLD + "41" + + EnumChatFormatting.GRAY + + " Reinforced Photolithography Framework Casing") + .addStructureInfo(EnumChatFormatting.GOLD + "8" + EnumChatFormatting.GRAY + " Superconducting Coil Block") + .addStructureInfo(EnumChatFormatting.GOLD + "20" + EnumChatFormatting.GRAY + " Tungstensteel Pipe Casing") + .addStructureInfo(EnumChatFormatting.GOLD + "48" + EnumChatFormatting.GRAY + " Infinity Cooled Casing") + .toolTipFinisher("GregTech"); + return tt; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setBoolean("mBioUpgrade", mBioUpgrade); + aNBT.setBoolean("mBioRotate", mBioRotate); + aNBT.setInteger("mBioOffsetX", mBioOffsets[0]); + aNBT.setInteger("mBioOffsetZ", mBioOffsets[1]); + aNBT.setBoolean("mOCTier1Upgrade", mOCTier1); + aNBT.setInteger("mOCTier1OffsetX", mOCTier1Offsets[0]); + aNBT.setInteger("mOCTier1OffsetZ", mOCTier1Offsets[1]); + aNBT.setBoolean("mOCTier2Upgrade", mOCTier2); + aNBT.setInteger("mOCTier2OffsetX", mOCTier2Offsets[0]); + aNBT.setInteger("mOCTier2OffsetZ", mOCTier2Offsets[1]); + aNBT.setFloat("mRoughnessMultiplier", mRoughnessMultiplier); + aNBT.setInteger("mSetTier", mSetTier); + } + + @Override + public void loadNBTData(final NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (aNBT.hasKey("mSeparate")) { + // backward compatibility + inputSeparation = aNBT.getBoolean("mSeparate"); + } + mBioUpgrade = aNBT.getBoolean("mBioUpgrade"); + mBioRotate = aNBT.getBoolean("mBioRotate"); + mBioOffsets[0] = aNBT.getInteger("mBioOffsetX"); + mBioOffsets[1] = aNBT.getInteger("mBioOffsetZ"); + mOCTier1 = aNBT.getBoolean("mOCTier1Upgrade"); + mOCTier1Offsets[0] = aNBT.getInteger("mOCTier1OffsetX"); + mOCTier1Offsets[1] = aNBT.getInteger("mOCTier1OffsetZ"); + mOCTier2 = aNBT.getBoolean("mOCTier2Upgrade"); + mOCTier2Offsets[0] = aNBT.getInteger("mOCTier2OffsetX"); + mOCTier2Offsets[1] = aNBT.getInteger("mOCTier2OffsetZ"); + mRoughnessMultiplier = aNBT.getFloat("mRoughnessMultiplier"); + mSetTier = aNBT.getInteger("mSetTier"); + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + protected SoundResource getProcessStartSound() { + return SoundResource.IC2_MACHINES_MAGNETIZER_LOOP; + } + + @Override + public boolean useModularUI() { + return true; + } + + @Override + public byte getUpdateData() { + byte data = 0; + if (mSetTier == 1) { + data += mTier1BitMap; + } else if (mSetTier == 2) { + data += mTier2BitMap; + } else { + data += mTier3BitMap; + } + + if (mBioUpgrade) { + data += mBioBitMap; + } + + if (mBioRotate) { + data += mBioRotateBitMap; + } + + if (mOCTier1) { + data += mOCTier1BitMap; + } + + if (mOCTier2) { + data += mOCTier2BitMap; + } + + return data; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + super.addUIWidgets(builder, buildContext); + buildContext.addSyncedWindow(10, this::createConfigurationWindow); + builder.widget( + new ButtonWidget().setOnClick( + (clickData, widget) -> { + if (!widget.isClient()) widget.getContext() + .openSyncedWindow(10); + }) + .setSize(16, 16) + .setBackground(() -> { + List<UITexture> ret = new ArrayList<>(); + ret.add(GT_UITextures.BUTTON_STANDARD); + ret.add(GT_UITextures.OVERLAY_BUTTON_CYCLIC); + return ret.toArray(new IDrawable[0]); + }) + .addTooltip("Configuration Menu") + .setPos(174, 130)) + .widget( + new TextWidget(new Text("Tier")).setTextAlignment(Alignment.Center) + .setScale(0.91f) + .setSize(20, 16) + .setPos(173, 98)) + .widget( + new NumericWidget().setGetter(() -> mSetTier) + .setSetter(val -> mSetTier = (int) val) + .setBounds(1, 3) + .setTextColor(Color.WHITE.normal) + .setTextAlignment(Alignment.Center) + .addTooltip("PCB Factory Tier") + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD) + .setSize(18, 18) + .setPos(173, 110)); + } + + protected ModularWindow createConfigurationWindow(final EntityPlayer player) { + ModularWindow.Builder builder = ModularWindow.builder(200, 160); + builder.setBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); + builder.setGuiTint(getGUIColorization()); + builder.widget( + new DrawableWidget().setDrawable(GT_UITextures.OVERLAY_BUTTON_CYCLIC) + .setPos(5, 5) + .setSize(16, 16)) + .widget(new TextWidget("Configuration Menu").setPos(25, 9)) + .widget( + ButtonWidget.closeWindowButton(true) + .setPos(185, 3)) + .widget( + new DynamicPositionedColumn().setSynced(false) + .widget( + new MultiChildWidget().addChild(new CycleButtonWidget().setToggle(() -> mBioUpgrade, val -> { + mBioUpgrade = val; + if (!mBioUpgrade) { + GT_Utility + .sendChatToPlayer(player, GT_Utility.trans("339.1", "Biochamber Upgrade Disabled")); + } else { + GT_Utility + .sendChatToPlayer(player, GT_Utility.trans("339", "Biochamber Upgrade Enabled")); + } + }) + .setVariableBackground(GT_UITextures.BUTTON_STANDARD_TOGGLE) + .setSize(90, 18) + .addTooltip( + "Enables nanites to construct organic circuitry. Required for Bioware and Wetware boards.")) + .addChild( + new DrawableWidget().setDrawable(GT_UITextures.OVERLAY_BUTTON_CYCLIC) + .setSize(18, 18)) + .addChild( + new TextWidget("Biochamber").setTextAlignment(Alignment.Center) + .setPos(23, 5)) + .setEnabled(widget -> !getBaseMetaTileEntity().isActive())) + .widget(new MultiChildWidget().addChild(new CycleButtonWidget().setToggle(() -> mBioRotate, val -> { + mBioRotate = val; + if (!mBioRotate) { + GT_Utility + .sendChatToPlayer(player, GT_Utility.trans("340.1", "Rotated biochamber disabled")); + } else { + GT_Utility.sendChatToPlayer(player, GT_Utility.trans("340", "Rotated biochamber enabled")); + } + }) + .setVariableBackground(GT_UITextures.BUTTON_STANDARD_TOGGLE) + .setSize(90, 18) + .addTooltip("Rotates the biochamber by 90 degrees.")) + .addChild( + new DrawableWidget().setDrawable(GT_UITextures.OVERLAY_BUTTON_CYCLIC) + .setSize(18, 18)) + .addChild( + new TextWidget("Bio Rotation").setTextAlignment(Alignment.Center) + .setPos(23, 5)) + .setEnabled(widget -> !getBaseMetaTileEntity().isActive())) + .widget(new MultiChildWidget().addChild(new CycleButtonWidget().setToggle(() -> mOCTier1, val -> { + mOCTier1 = val; + mOCTier2 = false; + if (!mOCTier1) { + GT_Utility.sendChatToPlayer(player, GT_Utility.trans("341.1", "Tier 1 cooling disabled")); + } else { + GT_Utility.sendChatToPlayer(player, GT_Utility.trans("341", "Tier 1 cooling enabled")); + } + }) + .setVariableBackground(GT_UITextures.BUTTON_STANDARD_TOGGLE) + .setSize(90, 18) + .addTooltip( + "Allows for overclocking. Requires 10 L/s of distilled water. Cooling upgrades are mutually exclusive.")) + .addChild( + new DrawableWidget().setDrawable(GT_UITextures.OVERLAY_BUTTON_CYCLIC) + .setSize(18, 18)) + .addChild( + new TextWidget("Liquid Cooling").setTextAlignment(Alignment.Center) + .setPos(20, 5)) + .setEnabled(widget -> !getBaseMetaTileEntity().isActive())) + .widget(new MultiChildWidget().addChild(new CycleButtonWidget().setToggle(() -> mOCTier2, val -> { + mOCTier2 = val; + mOCTier1 = false; + if (!mOCTier2) { + GT_Utility.sendChatToPlayer(player, GT_Utility.trans("342.1", "Tier 2 cooling disabled")); + } else { + GT_Utility.sendChatToPlayer(player, GT_Utility.trans("342", "Tier 2 cooling enabled")); + } + }) + .setVariableBackground(GT_UITextures.BUTTON_STANDARD_TOGGLE) + .setSize(90, 18) + .addTooltip( + "Enables perfect overclocking by allowing nanites to work with extreme speed and efficiency. Uses 10 L/s of Super Coolant.")) + .addChild( + new DrawableWidget().setDrawable(GT_UITextures.OVERLAY_BUTTON_CYCLIC) + .setSize(18, 18)) + .addChild( + new TextWidget("Thermosink").setTextAlignment(Alignment.Center) + .setPos(20, 5)) + .setEnabled(widget -> !getBaseMetaTileEntity().isActive())) + .widget( + new TextWidget(new Text("Trace Size")).setSize(90, 18) + .setEnabled(widget -> !getBaseMetaTileEntity().isActive()) + .setPos(0, 4)) + .widget( + new NumericWidget().setGetter(() -> (int) ((1f / mRoughnessMultiplier) * 100f)) + .setSetter(val -> mRoughnessMultiplier = 100f / (int) val) + .setBounds(50, 200) + .setTextColor(Color.WHITE.normal) + .setTextAlignment(Alignment.Center) + .addTooltip( + "Set the trace size. Smaller traces allow material savings but take longer to fabricate. Larger traces waste material but are fast. 50-200 μm.") + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD) + .setSize(90, 16)) + .widget( + new DrawableWidget().setDrawable(GT_UITextures.OVERLAY_BUTTON_CROSS) + .setSize(18, 18) + .addTooltip(new Text("Can't change configuration when running !").color(Color.RED.dark(3))) + .setEnabled(widget -> getBaseMetaTileEntity().isActive())) + .setPos(10, 25)) + .widget( + new DynamicPositionedColumn().setSynced(false) + .widget( + new TextWidget(new Text("Bio Upgrade Offsets")).setSize(72, 18) + .setEnabled(widget -> !getBaseMetaTileEntity().isActive())) + .widget( + new DynamicPositionedRow().setSynced(false) + .widget( + new NumericWidget().setGetter(() -> mBioOffsets[0]) + .setSetter(val -> mBioOffsets[0] = (int) val) + .setBounds(-16, 16) + .setTextColor(Color.WHITE.normal) + .setTextAlignment(Alignment.Center) + .addTooltip("X Offset") + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD) + .setSize(36, 18)) + .widget( + new NumericWidget().setGetter(() -> mBioOffsets[1]) + .setSetter(val -> mBioOffsets[1] = (int) val) + .setBounds(-16, 16) + .setTextColor(Color.WHITE.normal) + .setTextAlignment(Alignment.Center) + .addTooltip("Z Offset") + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD) + .setSize(36, 18)) + .setEnabled(widget -> !getBaseMetaTileEntity().isActive())) + .widget( + new TextWidget(new Text("Cooler Tier 1 Offsets")).setSize(72, 18) + .setEnabled(widget -> !getBaseMetaTileEntity().isActive())) + .widget( + new DynamicPositionedRow().setSynced(false) + .widget( + new NumericWidget().setGetter(() -> mOCTier1Offsets[0]) + .setSetter(val -> mOCTier1Offsets[0] = (int) val) + .setBounds(-16, 16) + .setTextColor(Color.WHITE.normal) + .setTextAlignment(Alignment.Center) + .addTooltip("X Offset") + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD) + .setSize(36, 18)) + .widget( + new NumericWidget().setGetter(() -> mOCTier1Offsets[1]) + .setSetter(val -> mOCTier1Offsets[1] = (int) val) + .setBounds(-16, 16) + .setTextColor(Color.WHITE.normal) + .setTextAlignment(Alignment.Center) + .addTooltip("Z Offset") + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD) + .setSize(36, 18)) + .setEnabled(widget -> !getBaseMetaTileEntity().isActive())) + .widget( + new TextWidget(new Text("Cooler Tier 2 Offsets")).setSize(72, 18) + .setEnabled(widget -> !getBaseMetaTileEntity().isActive())) + .widget( + new DynamicPositionedRow().setSynced(false) + .widget( + new NumericWidget().setGetter(() -> mOCTier2Offsets[0]) + .setSetter(val -> mOCTier2Offsets[0] = (int) val) + .setBounds(-16, 16) + .setTextColor(Color.WHITE.normal) + .setTextAlignment(Alignment.Center) + .addTooltip("X Offset") + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD) + .setSize(36, 18)) + .widget( + new NumericWidget().setGetter(() -> mOCTier2Offsets[1]) + .setSetter(val -> mOCTier2Offsets[1] = (int) val) + .setBounds(-16, 16) + .setTextColor(Color.WHITE.normal) + .setTextAlignment(Alignment.Center) + .addTooltip("Z Offset") + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD) + .setSize(36, 18)) + .setEnabled(widget -> !getBaseMetaTileEntity().isActive())) + .setPos(110, 25)); + return builder.build(); + } + + @Override + public boolean supportsVoidProtection() { + return true; + } + + @Override + public boolean supportsInputSeparation() { + return true; + } + + @Override + public boolean supportsSingleRecipeLocking() { + return true; + } + + @Override + public boolean supportsBatchMode() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PlasmaForge.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PlasmaForge.java new file mode 100644 index 0000000000..1eef27c8f1 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PlasmaForge.java @@ -0,0 +1,986 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.ExoticEnergy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.GT_Values.AuthorColen; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_DTPF_OFF; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_DTPF_ON; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FUSION1_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.ofCoil; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import javax.annotation.Nonnull; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.GregTech_API; +import gregtech.api.enums.HeatingCoilLevel; +import gregtech.api.enums.MaterialsUEVplus; +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy; +import gregtech.api.objects.GT_ChunkManager; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_ParallelHelper; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_PlasmaForge extends + GT_MetaTileEntity_ExtendedPowerMultiBlockBase<GT_MetaTileEntity_PlasmaForge> implements ISurvivalConstructable { + + // 3600 seconds in an hour, 8 hours, 20 ticks in a second. + private static final double max_efficiency_time_in_ticks = 3600d * 8d * 20d; + // Multiplier for the efficiency decay rate + private static final double efficiency_decay_rate = 100; + private static final double maximum_discount = 0.5d; + + // Valid fuels which the discount will get applied to. + private static final FluidStack[] valid_fuels = { MaterialsUEVplus.ExcitedDTEC.getFluid(1L), + MaterialsUEVplus.ExcitedDTRC.getFluid(1L), MaterialsUEVplus.ExcitedDTPC.getFluid(1L), + MaterialsUEVplus.ExcitedDTCC.getFluid(1L), MaterialsUEVplus.ExcitedDTSC.getFluid(1L) }; + + private static final int min_input_hatch = 0; + private static final int max_input_hatch = 7; + private static final int min_output_hatch = 0; + private static final int max_output_hatch = 2; + private static final int min_input_bus = 0; + private static final int max_input_bus = 6; + private static final int min_output_bus = 0; + private static final int max_output_bus = 1; + + // Current discount rate. 1 = 0%, 0 = 100%. + private double discount = 1; + private int mHeatingCapacity = 0; + private long running_time = 0; + private HeatingCoilLevel mCoilLevel; + + @SuppressWarnings("SpellCheckingInspection") + private static final String[][] structure_string = new String[][] { { " ", + " N N N N ", " N N N N ", " N N N N ", + " ", " ", " ", + " N N N N ", " N N N N ", " NNN NNN N N NNN NNN ", + " ", " ", " ", + " NNN NNN NNN NNN ", " ", " ", + " ", " ", " ", + " NNN NNN NNN NNN ", " ", " ", + " ", " NNN NNN NNN NNN " }, + { " N N N N ", " bCCCb bCCCb ", " bCCCb bCCCb ", + " bCCCb bCCCb ", " N N N N ", + " ", " N N N N ", + " bCCCb bCCCb ", " bCCCb bCCCb ", + "NbbbN NbbNCCCb bCCCNbbN NbbbN", " CCC CCC N N CCC CCC ", + " CCC CCC CCC CCC ", " CCC CCC CCC CCC ", + "NbbbN NbbbN NbbbN NbbbN", " N N N N ", + " N N N N ", " ", + " N N N N ", " N N N N ", + "NbbbN NbbbN NbbbN NbbbN", " CCC CCC CCC CCC ", + " CCC CCC CCC CCC ", " CCC CCC CCC CCC ", + "NbbbN NbbbN N N NbbbN NbbbN", }, + { " N N N N ", " bCCCb bCCCb ", " NNNbbbbbNNsNNbbbbbNNN ", + " ss bCCCb bCCCb ss ", " s N N N N s ", + " s s ", " N N N N N N ", + " N bCCCb bCCCb N ", " N sbbbbbNNsNNbbbbbs N ", + "NbbbN NbbNCCCb bCCCNbbN NbbbN", " CbC CbC N N CbC CbC ", + " CbC CbC CbC CbC ", " CbC CbC CbC CbC ", + "NbbbN NbbbN NbbbN NbbbN", " NNN NNN NNN NNN ", + " NNN NNN NNN NNN ", " s s s s ", + " NNN NNN NNN NNN ", " NNN NNN NNN NNN ", + "NbbbN NbbbN NbbbN NbbbN", " CbC CbC CbC CbC ", + " CbC CbC CbC CbC ", " CbC CbC CbC CbC ", + "NbbbN NbbbNNNNNsNsNNNNNbbbN NbbbN", }, + { " N N N N ", " bCCCb bCCCb ", " ss bCCCb bCCCb ss ", + " bCCCb bCCCb ", " s NCCCN NCCCN s ", + " s NCCCN NCCCN s ", " NCCCN NCCCN ", + " bCCCb bCCCb ", " bCCCb bCCCb ", + "NbbbNNNbbNCCCb bCCCNbbNNNbbbN", " CCCCCCCCC N N CCCCCCCCC ", + " CCCCCCCCC CCCCCCCCC ", " CCCCCCCCC CCCCCCCCC ", + "NbbbNNNbbbN NbbbNNNbbbN", " N N N N ", + " N N N N ", " ", + " N N N N ", " N N N N ", + "NbbbNNNbbbN NbbbNNNbbbN", " CCCCCCCCC CCCCCCCCC ", + " CCCCCCCCC CCCCCCCCC ", " CCCCCCCCC CCCCCCCCC ", + "NbbbNNNbbbN NbN NbbbNNNbbbN", }, + { " ", " N N N N ", " s N N N N s ", + " s NCCCN NCCCN s ", " ", + " ", " ", + " NCCCN NCCCN ", " N N N N ", + " NNN NN N N NN NNN ", " C C C C ", + " C C C C ", " C C C C ", + " NNN NNN NNN NNN ", " ", + " ", " ", + " ", " ", + " NNN NNN NNN NNN ", " C C C C ", + " C C C C ", " C C C C ", + " NNN NNN NbN NNN NNN ", }, + { " ", " ", " s s ", + " s NCCCN NCCCN s ", " ", + " ", " ", + " NCCCN NCCCN ", " ", + " N N N N ", " C C C C ", + " C C C C ", " C C C C ", + " N N N N ", " ", + " ", " ", + " ", " ", + " N N N N ", " C C C C ", + " C C C C ", " C C C C ", + " N N NbN N N ", }, + { " ", " N N N N ", " N N N N N N ", + " NCCCN NCCCN ", " ", + " ", " ", + " NCCCN NCCCN ", " N N N N ", + " NNN NN N N NN NNN ", " C C C C ", + " C C C C ", " C C C C ", + " NNN NNN NNN NNN ", " ", + " ", " ", + " ", " ", + " NNN NNN NNN NNN ", " C C C C ", + " C C C C ", " C C C C ", + " NNN NNN NbN NNN NNN ", }, + { " N N N N ", " bCCCb bCCCb ", " N bCCCb bCCCb N ", + " bCCCb bCCCb ", " NCCCN NCCCN ", + " NCCCN NCCCN ", " NCCCN NCCCN ", + " bCCCb bCCCb ", " bCCCb bCCCb ", + "NbbbNNNbbNCCCb bCCCNbbNNNbbbN", " CCCCCCCCC N N CCCCCCCCC ", + " CCCCCCCCC CCCCCCCCC ", " CCCCCCCCC CCCCCCCCC ", + "NbbbNNNbbbN NbbbNNNbbbN", " N N N N ", + " N N N N ", " ", + " N N N N ", " N N N N ", + "NbbbNNNbbbN NbbbNNNbbbN", " CCCCCCCCC CCCCCCCCC ", + " CCCCCCCCC CCCCCCCCC ", " CCCCCCCCC CCCCCCCCC ", + "NbbbNNNbbbN NbN NbbbNNNbbbN", }, + { " N N N N ", " bCCCb bCCCb ", " N sbbbbbNNsNNbbbbbs N ", + " bCCCb bCCCb ", " N N N N ", + " ", " N N N N ", + " bCCCb bCCCb ", " s sbbbbbNNsNNbbbbbs s ", + "NbbbN NbbNCCCb bCCCNbbN NbbbN", " CbC CbC N N CbC CbC ", + " CbC CbC CbC CbC ", " CbC CbC CbC CbC ", + "NbbbN NbbbN NbbbN NbbbN", " NNN NNN NNN NNN ", + " NNN NNN NNN NNN ", " s s s s ", + " NNN NNN NNN NNN ", " NNN NNN NNN NNN ", + "NbbbN NbbbN NbbbN NbbbN", " CbC CbC CbC CbC ", + " CbC CbC CbC CbC ", " CbC CbC CbC CbC ", + "NbbbN NbbbNNNNNsNsNNNNNbbbN NbbbN", }, + { " NNN NNN N N NNN NNN ", "NbbbN NbbNCCCb bCCCNbbN NbbbN", "NbbbN NbbNCCCb bCCCNbbN NbbbN", + "NbbbNNNbbNCCCb bCCCNbbNNNbbbN", " NNN NNN N N NNN NNN ", + " N N N N ", " NNN NNN N N NNN NNN ", + "NbbbNNNbbNCCCb bCCCNbbNNNbbbN", "NbbbN NbbNCCCb bCCCNbbN NbbbN", + "NNNN NNNCCCb bCCCNNN NNNN", " CCC CCC N N CCC CCC ", + " CCC CCC CCC CCC ", " CCC CCC CCC CCC ", + "NbbbN NbbbN NbbbN NbbbN", " N N N N ", + " N N N N ", " ", + " N N N N ", " N N N N ", + "NbbbN NbbbN NbbbN NbbbN", " CCC CCC CCC CCC ", + " CCC CCC CCC CCC ", " CCC CCC CCC CCC ", + "NbbbN NbbbN NbN NbbbN NbbbN", }, + { " ", " CCC CCC N N CCC CCC ", " CbC CbC N N CbC CbC ", + " CCCCCCCCC N N CCCCCCCCC ", " C C C C ", + " C C C C ", " C C C C ", + " CCCCCCCCC N N CCCCCCCCC ", " CbC CbC N N CbC CbC ", + " CCC CCC N N CCC CCC ", " ", + " ", " ", + " NNN NNN NNN NNN ", " ", + " ", " ", + " ", " ", + " NNN NNN NNN NNN ", " ", + " ", " ", + " NNN NNN NbN NNN NNN ", }, + { " ", " CCC CCC CCC CCC ", " CbC CbC CbC CbC ", + " CCCCCCCCC CCCCCCCCC ", " C C C C ", + " C C C C ", " C C C C ", + " CCCCCCCCC CCCCCCCCC ", " CbC CbC CbC CbC ", + " CCC CCC CCC CCC ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " N N NbN N N ", }, + { " ", " CCC CCC CCC CCC ", " CbC CbC CbC CbC ", + " CCCCCCCCC CCCCCCCCC ", " C C C C ", + " C C C C ", " C C C C ", + " CCCCCCCCC CCCCCCCCC ", " CbC CbC CbC CbC ", + " CCC CCC CCC CCC ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " N N NbN N N ", }, + { " NNN NNN NNN NNN ", "NbbbN NbbbN NbbbN NbbbN", "NbbbN NbbbN NbbbN NbbbN", + "NbbbNNNbbbN NbbbNNNbbbN", " NNN NNN NNN NNN ", + " N N N N ", " NNN NNN NNN NNN ", + "NbbbNNNbbbN NbbbNNNbbbN", "NbbbN NbbbN NbbbN NbbbN", + "NbbbN NbbbN NbbbN NbbbN", " NNN NNN NNN NNN ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " N N NsNsN N N ", }, + { " ", " ", " N N N N ", + " ", " ", + " ", " ", + " ", " N N N N ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " N N NbbbbbN N N ", }, + { " ", " ", " N N N N ", + " ", " ", + " ", " ", + " ", " N N N N ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " N ", + " NsNNNNNsNNNNsbbbbbsNNNNsNNNNNsN ", }, + { " ", " ", " s s s s ", + " ", " ", + " ", " ", + " ", " s s s s ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ~ ", " NNN ", + " NbbbbbNbbbbNbbbbbNbbbbNbbbbbN ", }, + { " ", " ", " N N N N ", + " ", " ", + " ", " ", + " ", " N N N N ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " N ", + " NsNNNNNsNNNNsbbbbbsNNNNsNNNNNsN ", }, + { " ", " ", " N N N N ", + " ", " ", + " ", " ", + " ", " N N N N ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " N N NbbbbbN N N ", }, + { " NNN NNN NNN NNN ", "NbbbN NbbbN NbbbN NbbbN", "NbbbN NbbbN NbbbN NbbbN", + "NbbbNNNbbbN NbbbNNNbbbN", " NNN NNN NNN NNN ", + " N N N N ", " NNN NNN NNN NNN ", + "NbbbNNNbbbN NbbbNNNbbbN", "NbbbN NbbbN NbbbN NbbbN", + "NbbbN NbbbN NbbbN NbbbN", " NNN NNN NNN NNN ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " N N NsNsN N N ", }, + { " ", " CCC CCC CCC CCC ", " CbC CbC CbC CbC ", + " CCCCCCCCC CCCCCCCCC ", " C C C C ", + " C C C C ", " C C C C ", + " CCCCCCCCC CCCCCCCCC ", " CbC CbC CbC CbC ", + " CCC CCC CCC CCC ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " N N NbN N N ", }, + { " ", " CCC CCC CCC CCC ", " CbC CbC CbC CbC ", + " CCCCCCCCC CCCCCCCCC ", " C C C C ", + " C C C C ", " C C C C ", + " CCCCCCCCC CCCCCCCCC ", " CbC CbC CbC CbC ", + " CCC CCC CCC CCC ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " ", " ", + " N N NbN N N ", }, + { " ", " CCC CCC N N CCC CCC ", " CbC CbC N N CbC CbC ", + " CCCCCCCCC N N CCCCCCCCC ", " C C C C ", + " C C C C ", " C C C C ", + " CCCCCCCCC N N CCCCCCCCC ", " CbC CbC N N CbC CbC ", + " CCC CCC N N CCC CCC ", " ", + " ", " ", + " NNN NNN NNN NNN ", " ", + " ", " ", + " ", " ", + " NNN NNN NNN NNN ", " ", + " ", " ", + " NNN NNN NbN NNN NNN ", }, + { " NNN NNN N N NNN NNN ", "NbbbN NbbNCCCb bCCCNbbN NbbbN", "NbbbN NbbNCCCb bCCCNbbN NbbbN", + "NbbbNNNbbNCCCb bCCCNbbNNNbbbN", " NNN NNN N N NNN NNN ", + " N N N N ", " NNN NNN N N NNN NNN ", + "NbbbNNNbbNCCCb bCCCNbbNNNbbbN", "NbbbN NbbNCCCb bCCCNbbN NbbbN", + "NNNN NNNCCCb bCCCNNN NNNN", " CCC CCC N N CCC CCC ", + " CCC CCC CCC CCC ", " CCC CCC CCC CCC ", + "NbbbN NbbbN NbbbN NbbbN", " N N N N ", + " N N N N ", " ", + " N N N N ", " N N N N ", + "NbbbN NbbbN NbbbN NbbbN", " CCC CCC CCC CCC ", + " CCC CCC CCC CCC ", " CCC CCC CCC CCC ", + "NbbbN NbbbN NbN NbbbN NbbbN", }, + { " N N N N ", " bCCCb bCCCb ", " N sbbbbbNNsNNbbbbbs N ", + " bCCCb bCCCb ", " N N N N ", + " ", " N N N N ", + " bCCCb bCCCb ", " s sbbbbbNNsNNbbbbbs s ", + "NbbbN NbbNCCCb bCCCNbbN NbbbN", " CbC CbC N N CbC CbC ", + " CbC CbC CbC CbC ", " CbC CbC CbC CbC ", + "NbbbN NbbbN NbbbN NbbbN", " NNN NNN NNN NNN ", + " NNN NNN NNN NNN ", " s s s s ", + " NNN NNN NNN NNN ", " NNN NNN NNN NNN ", + "NbbbN NbbbN NbbbN NbbbN", " CbC CbC CbC CbC ", + " CbC CbC CbC CbC ", " CbC CbC CbC CbC ", + "NbbbN NbbbNNNNNsNsNNNNNbbbN NbbbN", }, + { " N N N N ", " bCCCb bCCCb ", " N bCCCb bCCCb N ", + " bCCCb bCCCb ", " NCCCN NCCCN ", + " NCCCN NCCCN ", " NCCCN NCCCN ", + " bCCCb bCCCb ", " bCCCb bCCCb ", + "NbbbNNNbbNCCCb bCCCNbbNNNbbbN", " CCCCCCCCC N N CCCCCCCCC ", + " CCCCCCCCC CCCCCCCCC ", " CCCCCCCCC CCCCCCCCC ", + "NbbbNNNbbbN NbbbNNNbbbN", " N N N N ", + " N N N N ", " ", + " N N N N ", " N N N N ", + "NbbbNNNbbbN NbbbNNNbbbN", " CCCCCCCCC CCCCCCCCC ", + " CCCCCCCCC CCCCCCCCC ", " CCCCCCCCC CCCCCCCCC ", + "NbbbNNNbbbN NbN NbbbNNNbbbN", }, + { " ", " N N N N ", " N N N N N N ", + " NCCCN NCCCN ", " ", + " ", " ", + " NCCCN NCCCN ", " N N N N ", + " NNN NN N N NN NNN ", " C C C C ", + " C C C C ", " C C C C ", + " NNN NNN NNN NNN ", " ", + " ", " ", + " ", " ", + " NNN NNN NNN NNN ", " C C C C ", + " C C C C ", " C C C C ", + " NNN NNN NbN NNN NNN ", }, + { " ", " ", " s s ", + " s NCCCN NCCCN s ", " ", + " ", " ", + " NCCCN NCCCN ", " ", + " N N N N ", " C C C C ", + " C C C C ", " C C C C ", + " N N N N ", " ", + " ", " ", + " ", " ", + " N N N N ", " C C C C ", + " C C C C ", " C C C C ", + " N N NbN N N ", }, + { " ", " N N N N ", " s N N N N s ", + " s NCCCN NCCCN s ", " ", + " ", " ", + " NCCCN NCCCN ", " N N N N ", + " NNN NN N N NN NNN ", " C C C C ", + " C C C C ", " C C C C ", + " NNN NNN NNN NNN ", " ", + " ", " ", + " ", " ", + " NNN NNN NNN NNN ", " C C C C ", + " C C C C ", " C C C C ", + " NNN NNN NbN NNN NNN ", }, + { " N N N N ", " bCCCb bCCCb ", " ss bCCCb bCCCb ss ", + " bCCCb bCCCb ", " s NCCCN NCCCN s ", + " s NCCCN NCCCN s ", " NCCCN NCCCN ", + " bCCCb bCCCb ", " bCCCb bCCCb ", + "NbbbNNNbbNCCCb bCCCNbbNNNbbbN", " CCCCCCCCC N N CCCCCCCCC ", + " CCCCCCCCC CCCCCCCCC ", " CCCCCCCCC CCCCCCCCC ", + "NbbbNNNbbbN NbbbNNNbbbN", " N N N N ", + " N N N N ", " ", + " N N N N ", " N N N N ", + "NbbbNNNbbbN NbbbNNNbbbN", " CCCCCCCCC CCCCCCCCC ", + " CCCCCCCCC CCCCCCCCC ", " CCCCCCCCC CCCCCCCCC ", + "NbbbNNNbbbN NbN NbbbNNNbbbN", }, + { " N N N N ", " bCCCb bCCCb ", " NNNbbbbbNNsNNbbbbbNNN ", + " ss bCCCb bCCCb ss ", " s N N N N s ", + " s s ", " N N N N N N ", + " N bCCCb bCCCb N ", " N sbbbbbNNsNNbbbbbs N ", + "NbbbN NbbNCCCb bCCCNbbN NbbbN", " CbC CbC N N CbC CbC ", + " CbC CbC CbC CbC ", " CbC CbC CbC CbC ", + "NbbbN NbbbN NbbbN NbbbN", " NNN NNN NNN NNN ", + " NNN NNN NNN NNN ", " s s s s ", + " NNN NNN NNN NNN ", " NNN NNN NNN NNN ", + "NbbbN NbbbN NbbbN NbbbN", " CbC CbC CbC CbC ", + " CbC CbC CbC CbC ", " CbC CbC CbC CbC ", + "NbbbN NbbbNNNNNsNsNNNNNbbbN NbbbN", }, + { " N N N N ", " bCCCb bCCCb ", " bCCCb bCCCb ", + " bCCCb bCCCb ", " N N N N ", + " ", " N N N N ", + " bCCCb bCCCb ", " bCCCb bCCCb ", + "NbbbN NbbNCCCb bCCCNbbN NbbbN", " CCC CCC N N CCC CCC ", + " CCC CCC CCC CCC ", " CCC CCC CCC CCC ", + "NbbbN NbbbN NbbbN NbbbN", " N N N N ", + " N N N N ", " ", + " N N N N ", " N N N N ", + "NbbbN NbbbN NbbbN NbbbN", " CCC CCC CCC CCC ", + " CCC CCC CCC CCC ", " CCC CCC CCC CCC ", + "NbbbN NbbbN N N NbbbN NbbbN", }, + { " ", " N N N N ", " N N N N ", + " N N N N ", " ", + " ", " ", + " N N N N ", " N N N N ", + " NNN NNN N N NNN NNN ", " ", + " ", " ", + " NNN NNN NNN NNN ", " ", + " ", " ", + " ", " ", + " NNN NNN NNN NNN ", " ", + " ", " ", + " NNN NNN NNN NNN ", } }; + + protected static final int DIM_TRANS_CASING = 12; + protected static final int DIM_INJECTION_CASING = 13; + protected static final int DIM_BRIDGE_CASING = 14; + + private boolean isMultiChunkloaded = true; + + protected static final String STRUCTURE_PIECE_MAIN = "main"; + private static final IStructureDefinition<GT_MetaTileEntity_PlasmaForge> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_PlasmaForge>builder() + .addShape(STRUCTURE_PIECE_MAIN, structure_string) + .addElement( + 'C', + ofCoil(GT_MetaTileEntity_PlasmaForge::setCoilLevel, GT_MetaTileEntity_PlasmaForge::getCoilLevel)) + .addElement( + 'b', + buildHatchAdder(GT_MetaTileEntity_PlasmaForge.class) + .atLeast(InputHatch, OutputHatch, InputBus, OutputBus, Energy, ExoticEnergy, Maintenance) + .casingIndex(DIM_INJECTION_CASING) + .dot(3) + .buildAndChain(GregTech_API.sBlockCasings1, DIM_INJECTION_CASING)) + .addElement('N', ofBlock(GregTech_API.sBlockCasings1, DIM_TRANS_CASING)) + .addElement('s', ofBlock(GregTech_API.sBlockCasings1, DIM_BRIDGE_CASING)) + .build(); + + public GT_MetaTileEntity_PlasmaForge(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_PlasmaForge(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_PlasmaForge(mName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addInfo("Transcending Dimensional Boundaries.") + .addInfo( + "Takes " + EnumChatFormatting.RED + + GT_Utility.formatNumbers(max_efficiency_time_in_ticks / (3600 * 20)) + + EnumChatFormatting.GRAY + + " hours of continuous run time to fully breach dimensional") + .addInfo("boundaries and achieve maximum efficiency. This reduces fuel") + .addInfo( + "consumption by up to " + EnumChatFormatting.RED + + GT_Utility.formatNumbers(100 * maximum_discount) + + "%" + + EnumChatFormatting.GRAY + + ". Supports overclocking beyond MAX voltage.") + .addInfo( + "When no recipe is running, fuel discount decays x" + EnumChatFormatting.RED + + GT_Utility.formatNumbers(efficiency_decay_rate) + + EnumChatFormatting.GRAY + + " as fast as it builds up.") + .addInfo(AuthorColen) + .addSeparator() + .beginStructureBlock(33, 24, 33, false) + .addStructureInfo("DTPF Structure is too complex! See schematic for details.") + .addStructureInfo(EnumChatFormatting.GOLD + "2,112" + EnumChatFormatting.GRAY + " Heating coils required.") + .addStructureInfo( + EnumChatFormatting.GOLD + "120" + EnumChatFormatting.GRAY + " Dimensional bridge blocks required.") + .addStructureInfo( + EnumChatFormatting.GOLD + "1,270" + + EnumChatFormatting.GRAY + + " Dimensional injection casings required.") + .addStructureInfo( + EnumChatFormatting.GOLD + "2,121" + + EnumChatFormatting.GRAY + + " Dimensionally transcendent casings required.") + .addStructureInfo("--------------------------------------------") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + + "1" + + EnumChatFormatting.GRAY + + "-" + + EnumChatFormatting.GOLD + + "2" + + EnumChatFormatting.GRAY + + " energy hatches or " + + EnumChatFormatting.GOLD + + "1" + + EnumChatFormatting.GRAY + + " TT energy hatch.") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + "1" + EnumChatFormatting.GRAY + " maintenance hatch.") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + + min_input_hatch + + EnumChatFormatting.GRAY + + "-" + + EnumChatFormatting.GOLD + + max_input_hatch + + EnumChatFormatting.GRAY + + " input hatches.") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + + min_output_hatch + + EnumChatFormatting.GRAY + + "-" + + EnumChatFormatting.GOLD + + max_output_hatch + + EnumChatFormatting.GRAY + + " output hatches.") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + + min_input_bus + + EnumChatFormatting.GRAY + + "-" + + EnumChatFormatting.GOLD + + max_input_bus + + EnumChatFormatting.GRAY + + " input busses.") + .addStructureInfo( + "Requires " + EnumChatFormatting.GOLD + + min_output_bus + + EnumChatFormatting.GRAY + + "-" + + EnumChatFormatting.GOLD + + max_input_bus + + EnumChatFormatting.GRAY + + " output busses.") + .addStructureInfo("--------------------------------------------") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public boolean addToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + boolean exotic = addExoticEnergyInputToMachineList(aTileEntity, aBaseCasingIndex); + return super.addToMachineList(aTileEntity, aBaseCasingIndex) || exotic; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { casingTexturePages[0][DIM_BRIDGE_CASING], TextureFactory.builder() + .addIcon(OVERLAY_DTPF_ON) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FUSION1_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { casingTexturePages[0][DIM_BRIDGE_CASING], TextureFactory.builder() + .addIcon(OVERLAY_DTPF_OFF) + .extFacing() + .build() }; + } + return new ITexture[] { casingTexturePages[0][DIM_BRIDGE_CASING] }; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + return 0; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.plasmaForgeRecipes; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_PlasmaForge> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + CheckRecipeResult recipe_process = super.checkProcessing(); + if (recipe_process.wasSuccessful()) { + running_time = Math.min(running_time + mMaxProgresstime, (long) max_efficiency_time_in_ticks); + } + return recipe_process; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @Nonnull + @Override + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) { + return super.createOverclockCalculator(recipe).setRecipeHeat(recipe.mSpecialValue) + .setMachineHeat(mHeatingCapacity); + } + + @NotNull + @Override + protected GT_ParallelHelper createParallelHelper(@Nonnull GT_Recipe recipe) { + return super.createParallelHelper(recipeAfterDiscount(recipe)); + } + + @Override + protected @Nonnull CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + return recipe.mSpecialValue <= mHeatingCapacity ? CheckRecipeResultRegistry.SUCCESSFUL + : CheckRecipeResultRegistry.insufficientHeat(recipe.mSpecialValue); + } + }; + } + + @Nonnull + protected GT_Recipe recipeAfterDiscount(@Nonnull GT_Recipe recipe) { + GT_Recipe tRecipe = recipe.copy(); + outside: for (int i = 0; i < recipe.mFluidInputs.length; i++) { + for (FluidStack fuel : valid_fuels) { + if (tRecipe.mFluidInputs[i].isFluidEqual(fuel)) { + recalculateDiscount(); + tRecipe.mFluidInputs[i].amount = (int) Math.round(tRecipe.mFluidInputs[i].amount * discount); + break outside; + } + } + } + return tRecipe; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + + // Reset heating capacity. + mHeatingCapacity = 0; + + // Get heating capacity from coils in structure. + setCoilLevel(HeatingCoilLevel.None); + + // Check the main structure + if (!checkPiece(STRUCTURE_PIECE_MAIN, 16, 21, 16)) return false; + + if (getCoilLevel() == HeatingCoilLevel.None) return false; + + // Item input bus check. + if (mInputBusses.size() > max_input_bus) return false; + + // Item output bus check. + if (mOutputBusses.size() > max_output_bus) return false; + + // Fluid input hatch check. + if (mInputHatches.size() > max_input_hatch) return false; + + // Fluid output hatch check. + if (mOutputHatches.size() > max_output_hatch) return false; + + // If there is more than 1 TT energy hatch, the structure check will fail. + // If there is a TT hatch and a normal hatch, the structure check will fail. + if (mExoticEnergyHatches.size() > 0) { + if (mEnergyHatches.size() > 0) return false; + if (mExoticEnergyHatches.size() > 1) return false; + } + + // If there is 0 or more than 2 energy hatches structure check will fail. + if (mEnergyHatches.size() > 0) { + if (mEnergyHatches.size() > 2) return false; + + // Check will also fail if energy hatches are not of the same tier. + byte tier_of_hatch = mEnergyHatches.get(0).mTier; + for (GT_MetaTileEntity_Hatch_Energy energyHatch : mEnergyHatches) { + if (energyHatch.mTier != tier_of_hatch) { + return false; + } + } + } + + // If there are no energy hatches or TT energy hatches, structure will fail to form. + if ((mEnergyHatches.size() == 0) && (mExoticEnergyHatches.size() == 0)) return false; + + // One maintenance hatch only. Mandatory. + if (mMaintenanceHatches.size() != 1) return false; + + // Heat capacity of coils used on multi. No free heat from extra EU! + mHeatingCapacity = (int) getCoilLevel().getHeat(); + + // All structure checks passed, return true. + return true; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public void clearHatches() { + super.clearHatches(); + mExoticEnergyHatches.clear(); + } + + @Override + public boolean addOutput(FluidStack aLiquid) { + if (aLiquid == null) return false; + FluidStack tLiquid = aLiquid.copy(); + + return dumpFluid(mOutputHatches, tLiquid, true) || dumpFluid(mOutputHatches, tLiquid, false); + } + + @Override + public String[] getInfoData() { + + long storedEnergy = 0; + long maxEnergy = 0; + + for (GT_MetaTileEntity_Hatch tHatch : filterValidMTEs(mExoticEnergyHatches)) { + storedEnergy += tHatch.getBaseMetaTileEntity() + .getStoredEU(); + maxEnergy += tHatch.getBaseMetaTileEntity() + .getEUCapacity(); + } + long voltage = getAverageInputVoltage(); + long amps = getMaxInputAmps(); + + // Calculate discount to make sure it is shown properly even when machine is off but decaying + recalculateDiscount(); + + return new String[] { "------------ Critical Information ------------", + StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mProgresstime) + + EnumChatFormatting.RESET + + "t / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mMaxProgresstime) + + EnumChatFormatting.RESET + + "t", + StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(storedEnergy) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxEnergy) + + EnumChatFormatting.RESET + + " EU", + StatCollector.translateToLocal("GT5U.multiblock.usage") + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(getActualEnergyUsage()) + + EnumChatFormatting.RESET + + " EU/t", + StatCollector.translateToLocal("GT5U.multiblock.mei") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(voltage) + + EnumChatFormatting.RESET + + " EU/t(*" + + EnumChatFormatting.YELLOW + + amps + + EnumChatFormatting.RESET + + "A) " + + StatCollector.translateToLocal("GT5U.machines.tier") + + ": " + + EnumChatFormatting.YELLOW + + VN[GT_Utility.getTier(voltage)] + + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.EBF.heat") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mHeatingCapacity) + + EnumChatFormatting.RESET + + " K", + "Ticks run: " + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(running_time) + + EnumChatFormatting.RESET + + ", Fuel Discount: " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(100 * (1 - discount)) + + EnumChatFormatting.RESET + + "%", + "-----------------------------------------" }; + } + + private void recalculateDiscount() { + double time_percentage = running_time / max_efficiency_time_in_ticks; + time_percentage = Math.min(time_percentage, 1.0d); + // Multiplied by 0.5 because that is the maximum achievable discount + discount = 1 - time_percentage * 0.5; + discount = Math.max(maximum_discount, discount); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide() && !aBaseMetaTileEntity.isAllowedToWork()) { + // If machine has stopped, stop chunkloading. + GT_ChunkManager.releaseTicket((TileEntity) aBaseMetaTileEntity); + isMultiChunkloaded = false; + } else if (aBaseMetaTileEntity.isServerSide() && aBaseMetaTileEntity.isAllowedToWork() && !isMultiChunkloaded) { + // Load a 3x3 area centered on controller when machine is running. + GT_ChunkManager.releaseTicket((TileEntity) aBaseMetaTileEntity); + + int ControllerXCoordinate = ((TileEntity) aBaseMetaTileEntity).xCoord; + int ControllerZCoordinate = ((TileEntity) aBaseMetaTileEntity).zCoord; + + GT_ChunkManager.requestChunkLoad( + (TileEntity) aBaseMetaTileEntity, + new ChunkCoordIntPair(ControllerXCoordinate, ControllerZCoordinate)); + GT_ChunkManager.requestChunkLoad( + (TileEntity) aBaseMetaTileEntity, + new ChunkCoordIntPair(ControllerXCoordinate + 16, ControllerZCoordinate)); + GT_ChunkManager.requestChunkLoad( + (TileEntity) aBaseMetaTileEntity, + new ChunkCoordIntPair(ControllerXCoordinate - 16, ControllerZCoordinate)); + GT_ChunkManager.requestChunkLoad( + (TileEntity) aBaseMetaTileEntity, + new ChunkCoordIntPair(ControllerXCoordinate, ControllerZCoordinate + 16)); + GT_ChunkManager.requestChunkLoad( + (TileEntity) aBaseMetaTileEntity, + new ChunkCoordIntPair(ControllerXCoordinate, ControllerZCoordinate - 16)); + GT_ChunkManager.requestChunkLoad( + (TileEntity) aBaseMetaTileEntity, + new ChunkCoordIntPair(ControllerXCoordinate + 16, ControllerZCoordinate + 16)); + GT_ChunkManager.requestChunkLoad( + (TileEntity) aBaseMetaTileEntity, + new ChunkCoordIntPair(ControllerXCoordinate + 16, ControllerZCoordinate - 16)); + GT_ChunkManager.requestChunkLoad( + (TileEntity) aBaseMetaTileEntity, + new ChunkCoordIntPair(ControllerXCoordinate - 16, ControllerZCoordinate + 16)); + GT_ChunkManager.requestChunkLoad( + (TileEntity) aBaseMetaTileEntity, + new ChunkCoordIntPair(ControllerXCoordinate - 16, ControllerZCoordinate - 16)); + + isMultiChunkloaded = true; + } + + super.onPostTick(aBaseMetaTileEntity, aTick); + + if (aBaseMetaTileEntity.isServerSide()) { + if (mMaxProgresstime == 0) { + running_time = Math.max(0, running_time - (long) efficiency_decay_rate); + } + } + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, 16, 21, 16); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + int realBudget = elementBudget >= 200 ? elementBudget : Math.min(200, elementBudget * 5); + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 16, 21, 16, realBudget, env, false, true); + } + + @SideOnly(Side.CLIENT) + @Override + protected ResourceLocation getActivitySoundLoop() { + return SoundResource.GT_MACHINES_PLASMAFORGE_LOOP.resourceLocation; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + aNBT.setLong("eRunningTime", running_time); + aNBT.setDouble("eLongDiscountValue", discount); + super.saveNBTData(aNBT); + } + + @Override + public void loadNBTData(final NBTTagCompound aNBT) { + running_time = aNBT.getLong("eRunningTime"); + discount = aNBT.getDouble("eLongDiscountValue"); + super.loadNBTData(aNBT); + } + + public HeatingCoilLevel getCoilLevel() { + return mCoilLevel; + } + + public void setCoilLevel(HeatingCoilLevel aCoilLevel) { + mCoilLevel = aCoilLevel; + } + + @Override + public boolean supportsVoidProtection() { + return true; + } + + @Override + public boolean supportsBatchMode() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PrimitiveBlastFurnace.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PrimitiveBlastFurnace.java new file mode 100644 index 0000000000..e69d2c2921 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PrimitiveBlastFurnace.java @@ -0,0 +1,526 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.isAir; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlockAnyMeta; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizon.structurelib.StructureLibAPI; +import com.gtnewhorizon.structurelib.alignment.IAlignment; +import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; +import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ProgressBar; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.ParticleFX; +import gregtech.api.enums.SteamVariant; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.gui.modularui.GUITextureSet; +import gregtech.api.interfaces.modularui.IAddUIWidgets; +import gregtech.api.interfaces.modularui.IGetTitleColor; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.RecipeMapWorkable; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.objects.GT_ItemStack; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.WorldSpawnedEventBuilder; +import gregtech.api.util.WorldSpawnedEventBuilder.ParticleEventBuilder; +import gregtech.common.GT_Pollution; + +public abstract class GT_MetaTileEntity_PrimitiveBlastFurnace extends MetaTileEntity + implements IAlignment, ISurvivalConstructable, RecipeMapWorkable, IAddUIWidgets, IGetTitleColor { + + public static final int INPUT_SLOTS = 3, OUTPUT_SLOTS = 3; + private static final ClassValue<IStructureDefinition<GT_MetaTileEntity_PrimitiveBlastFurnace>> STRUCTURE_DEFINITION = new ClassValue<>() { + + @Override + protected IStructureDefinition<GT_MetaTileEntity_PrimitiveBlastFurnace> computeValue(Class<?> type) { + return IStructureDefinition.<GT_MetaTileEntity_PrimitiveBlastFurnace>builder() + .addShape( + "main", + transpose( + new String[][] { { "ccc", "c-c", "ccc" }, { "ccc", "clc", "ccc" }, { "c~c", "clc", "ccc" }, + { "ccc", "ccc", "ccc" }, })) + .addElement('c', lazy(t -> ofBlock(t.getCasingBlock(), t.getCasingMetaID()))) + .addElement( + 'l', + ofChain(isAir(), ofBlockAnyMeta(Blocks.lava, 1), ofBlockAnyMeta(Blocks.flowing_lava, 1))) + .build(); + } + }; + + public int mMaxProgresstime = 0; + private volatile boolean mUpdated; + public int mUpdate = 5; + public int mProgresstime = 0; + public boolean mMachine = false; + + public ItemStack[] mOutputItems = new ItemStack[OUTPUT_SLOTS]; + + public GT_MetaTileEntity_PrimitiveBlastFurnace(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, INPUT_SLOTS + OUTPUT_SLOTS); + } + + public GT_MetaTileEntity_PrimitiveBlastFurnace(String aName) { + super(aName, INPUT_SLOTS + OUTPUT_SLOTS); + } + + @Override + public boolean isTeleporterCompatible() { + return false; + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return (facing.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public int getProgresstime() { + return this.mProgresstime; + } + + @Override + public int maxProgresstime() { + return this.mMaxProgresstime; + } + + @Override + public int increaseProgress(int aProgress) { + this.mProgresstime += aProgress; + return this.mMaxProgresstime - this.mProgresstime; + } + + @Override + public boolean allowCoverOnSide(ForgeDirection side, GT_ItemStack aCoverID) { + return (GregTech_API.getCoverBehaviorNew(aCoverID.toStack()) + .isSimpleCover()) && (super.allowCoverOnSide(side, aCoverID)); + } + + @Override + public abstract MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity); + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + aNBT.setInteger("mProgresstime", this.mProgresstime); + aNBT.setInteger("mMaxProgresstime", this.mMaxProgresstime); + if (this.mOutputItems != null) { + for (int i = 0; i < mOutputItems.length; i++) { + if (this.mOutputItems[i] != null) { + NBTTagCompound tNBT = new NBTTagCompound(); + this.mOutputItems[i].writeToNBT(tNBT); + aNBT.setTag("mOutputItem" + i, tNBT); + } + } + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + this.mUpdate = 5; + this.mProgresstime = aNBT.getInteger("mProgresstime"); + this.mMaxProgresstime = aNBT.getInteger("mMaxProgresstime"); + this.mOutputItems = new ItemStack[OUTPUT_SLOTS]; + for (int i = 0; i < OUTPUT_SLOTS; i++) { + this.mOutputItems[i] = GT_Utility.loadItem(aNBT, "mOutputItem" + i); + } + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + + @Override + public ExtendedFacing getExtendedFacing() { + return ExtendedFacing.of(getBaseMetaTileEntity().getFrontFacing()); + } + + @Override + public void setExtendedFacing(ExtendedFacing alignment) { + getBaseMetaTileEntity().setFrontFacing(alignment.getDirection()); + } + + @Override + public IAlignmentLimits getAlignmentLimits() { + return (d, r, f) -> (d.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0 && r.isNotRotated() + && f.isNotFlipped(); + } + + private boolean checkMachine() { + return STRUCTURE_DEFINITION.get(this.getClass()) + .check( + this, + "main", + getBaseMetaTileEntity().getWorld(), + getExtendedFacing(), + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord(), + 1, + 2, + 0, + !mMachine); + } + + protected abstract Block getCasingBlock(); + + protected abstract int getCasingMetaID(); + + @Override + public void onMachineBlockUpdate() { + mUpdated = true; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTimer) { + final int lavaX = aBaseMetaTileEntity.getOffsetX(aBaseMetaTileEntity.getBackFacing(), 1); + final int lavaZ = aBaseMetaTileEntity.getOffsetZ(aBaseMetaTileEntity.getBackFacing(), 1); + if ((aBaseMetaTileEntity.isClientSide()) && (aBaseMetaTileEntity.isActive())) { + + new WorldSpawnedEventBuilder.ParticleEventBuilder().setMotion(0D, 0.3D, 0D) + .setIdentifier(ParticleFX.LARGE_SMOKE) + .setPosition( + lavaX + XSTR_INSTANCE.nextFloat(), + aBaseMetaTileEntity.getOffsetY(aBaseMetaTileEntity.getBackFacing(), 1), + lavaZ + XSTR_INSTANCE.nextFloat()) + .setWorld(getBaseMetaTileEntity().getWorld()) + .run(); + } + if (aBaseMetaTileEntity.isServerSide()) { + if (mUpdated) { + // duct tape fix for too many updates on an overloaded server, causing the structure check to not run + if (mUpdate < 0) mUpdate = 5; + mUpdated = false; + } + if (this.mUpdate-- == 0) { + this.mMachine = checkMachine(); + } + if (this.mMachine) { + if (this.mMaxProgresstime > 0) { + if (++this.mProgresstime >= this.mMaxProgresstime) { + addOutputProducts(); + this.mOutputItems = null; + this.mProgresstime = 0; + this.mMaxProgresstime = 0; + GT_Mod.achievements.issueAchievement( + aBaseMetaTileEntity.getWorld() + .getPlayerEntityByName(aBaseMetaTileEntity.getOwnerName()), + "steel"); + } + } else if (aBaseMetaTileEntity.isAllowedToWork()) { + checkRecipe(); + } + } + if (this.mMaxProgresstime > 0 && (aTimer % 20L == 0L)) { + GT_Pollution.addPollution( + this.getBaseMetaTileEntity(), + GT_Mod.gregtechproxy.mPollutionPrimitveBlastFurnacePerSecond); + } + + aBaseMetaTileEntity.setActive((this.mMaxProgresstime > 0) && (this.mMachine)); + final short lavaY = aBaseMetaTileEntity.getYCoord(); + if (aBaseMetaTileEntity.isActive()) { + if (aBaseMetaTileEntity.getAir(lavaX, lavaY, lavaZ)) { + aBaseMetaTileEntity.getWorld() + .setBlock(lavaX, lavaY, lavaZ, Blocks.lava, 1, 2); + this.mUpdate = 1; + } + if (aBaseMetaTileEntity.getAir(lavaX, lavaY + 1, lavaZ)) { + aBaseMetaTileEntity.getWorld() + .setBlock(lavaX, lavaY + 1, lavaZ, Blocks.lava, 1, 2); + this.mUpdate = 1; + } + } else { + Block lowerLava = aBaseMetaTileEntity.getBlock(lavaX, lavaY, lavaZ); + Block upperLava = aBaseMetaTileEntity.getBlock(lavaX, lavaY + 1, lavaZ); + if (lowerLava == Blocks.lava) { + aBaseMetaTileEntity.getWorld() + .setBlock(lavaX, lavaY, lavaZ, Blocks.air, 0, 2); + this.mUpdate = 1; + } + if (upperLava == Blocks.lava) { + aBaseMetaTileEntity.getWorld() + .setBlock(lavaX, lavaY + 1, lavaZ, Blocks.air, 0, 2); + this.mUpdate = 1; + } + } + } + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + if (aBaseMetaTileEntity.isClientSide()) + StructureLibAPI.queryAlignment((IAlignmentProvider) aBaseMetaTileEntity); + } + + /** + * Draws random flames and smoke particles in front of Primitive Blast Furnace when active + * + * @param aBaseMetaTileEntity The entity that will handle the {@link Block#randomDisplayTick} + */ + @SideOnly(Side.CLIENT) + @Override + public void onRandomDisplayTick(IGregTechTileEntity aBaseMetaTileEntity) { + if (aBaseMetaTileEntity.isActive()) { + + final ForgeDirection frontFacing = aBaseMetaTileEntity.getFrontFacing(); + + final double oX = aBaseMetaTileEntity.getOffsetX(frontFacing, 1) + 0.5D; + final double oY = aBaseMetaTileEntity.getOffsetY(frontFacing, 1); + final double oZ = aBaseMetaTileEntity.getOffsetZ(frontFacing, 1) + 0.5D; + final double offset = -0.48D; + final double horizontal = XSTR_INSTANCE.nextFloat() * 8D / 16D - 4D / 16D; + + final double x, y, z; + + y = oY + XSTR_INSTANCE.nextFloat() * 10D / 16D + 5D / 16D; + + if (frontFacing == ForgeDirection.WEST) { + x = oX - offset; + z = oZ + horizontal; + } else if (frontFacing == ForgeDirection.EAST) { + x = oX + offset; + z = oZ + horizontal; + } else if (frontFacing == ForgeDirection.NORTH) { + x = oX + horizontal; + z = oZ - offset; + } else // if (frontFacing == ForgeDirection.SOUTH.ordinal()) + { + x = oX + horizontal; + z = oZ + offset; + } + + ParticleEventBuilder particleEventBuilder = (new ParticleEventBuilder()).setMotion(0D, 0D, 0D) + .setPosition(x, y, z) + .setWorld(getBaseMetaTileEntity().getWorld()); + particleEventBuilder.setIdentifier(ParticleFX.SMOKE) + .run(); + particleEventBuilder.setIdentifier(ParticleFX.FLAME) + .run(); + } + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.primitiveBlastRecipes; + } + + private void addOutputProducts() { + if (this.mOutputItems == null) { + return; + } + int limit = Math.min(mOutputItems.length, OUTPUT_SLOTS); + for (int i = 0; i < limit; i++) { + int absi = INPUT_SLOTS + i; + if (this.mInventory[absi] == null) { + this.mInventory[absi] = GT_Utility.copyOrNull(this.mOutputItems[i]); + } else if (GT_Utility.areStacksEqual(this.mInventory[absi], this.mOutputItems[i])) { + this.mInventory[absi].stackSize = Math.min( + this.mInventory[absi].getMaxStackSize(), + this.mInventory[absi].stackSize + this.mOutputItems[i].stackSize); + } + } + } + + private boolean spaceForOutput(ItemStack outputStack, int relativeOutputSlot) { + int absoluteSlot = relativeOutputSlot + INPUT_SLOTS; + if (this.mInventory[absoluteSlot] == null || outputStack == null) { + return true; + } + return ((this.mInventory[absoluteSlot].stackSize + outputStack.stackSize + <= this.mInventory[absoluteSlot].getMaxStackSize()) + && (GT_Utility.areStacksEqual(this.mInventory[absoluteSlot], outputStack))); + } + + private boolean checkRecipe() { + if (!this.mMachine) { + return false; + } + ItemStack[] inputs = new ItemStack[INPUT_SLOTS]; + System.arraycopy(mInventory, 0, inputs, 0, INPUT_SLOTS); + GT_Recipe recipe = getRecipeMap().findRecipe(getBaseMetaTileEntity(), false, 0, null, inputs); + if (recipe == null) { + this.mOutputItems = null; + return false; + } + for (int i = 0; i < OUTPUT_SLOTS; i++) { + if (!spaceForOutput(recipe.getOutput(i), i)) { + this.mOutputItems = null; + return false; + } + } + + if (!recipe.isRecipeInputEqual(true, null, inputs)) { + this.mOutputItems = null; + return false; + } + for (int i = 0; i < INPUT_SLOTS; i++) { + if (mInventory[i] != null && mInventory[i].stackSize == 0) { + mInventory[i] = null; + } + } + + this.mMaxProgresstime = recipe.mDuration; + this.mOutputItems = recipe.mOutputs; + return true; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return aIndex > INPUT_SLOTS; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return !GT_Utility.areStacksEqual(aStack, this.mInventory[0]); + } + + @Override + public byte getTileEntityBaseType() { + return 0; + } + + public abstract String getName(); + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return STRUCTURE_DEFINITION.get(getClass()) + .survivalBuild( + this, + stackSize, + "main", + getBaseMetaTileEntity().getWorld(), + getExtendedFacing(), + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord(), + 1, + 2, + 0, + elementBudget, + env, + false); + } + + @Override + public IStructureDefinition<?> getStructureDefinition() { + return STRUCTURE_DEFINITION.get(getClass()); + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + STRUCTURE_DEFINITION.get(getClass()) + .buildOrHints( + this, + stackSize, + "main", + getBaseMetaTileEntity().getWorld(), + getExtendedFacing(), + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord(), + 1, + 2, + 0, + hintsOnly); + } + + @Override + public boolean useModularUI() { + return true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + builder + .widget( + new SlotWidget(inventoryHandler, 0) + .setBackground( + getGUITextureSet().getItemSlot(), + GT_UITextures.OVERLAY_SLOT_INGOT_STEAM.get(getSteamVariant())) + .setPos(33, 15)) + .widget( + new SlotWidget(inventoryHandler, 1) + .setBackground( + getGUITextureSet().getItemSlot(), + GT_UITextures.OVERLAY_SLOT_DUST_STEAM.get(getSteamVariant())) + .setPos(33, 33)) + .widget( + new SlotWidget(inventoryHandler, 2) + .setBackground( + getGUITextureSet().getItemSlot(), + GT_UITextures.OVERLAY_SLOT_FURNACE_STEAM.get(getSteamVariant())) + .setPos(33, 51)) + .widget( + new SlotWidget(inventoryHandler, 3).setAccess(true, false) + .setBackground( + getGUITextureSet().getItemSlot(), + GT_UITextures.OVERLAY_SLOT_INGOT_STEAM.get(getSteamVariant())) + .setPos(85, 24)) + .widget( + new SlotWidget(inventoryHandler, 4).setAccess(true, false) + .setBackground( + getGUITextureSet().getItemSlot(), + GT_UITextures.OVERLAY_SLOT_DUST_STEAM.get(getSteamVariant())) + .setPos(103, 24)) + .widget( + new SlotWidget(inventoryHandler, 5).setAccess(true, false) + .setBackground( + getGUITextureSet().getItemSlot(), + GT_UITextures.OVERLAY_SLOT_DUST_STEAM.get(getSteamVariant())) + .setPos(121, 24)) + .widget( + new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ARROW_2_STEAM.get(getSteamVariant()), 20) + .setProgress(() -> (float) mProgresstime / mMaxProgresstime) + .setNEITransferRect( + getRecipeMap().getFrontend() + .getUIProperties().neiTransferRectId) + .setPos(58, 24) + .setSize(20, 18)); + } + + @Override + public GUITextureSet getGUITextureSet() { + return GUITextureSet.STEAM.apply(getSteamVariant()); + } + + @Override + public int getTitleColor() { + return getSteamVariant() == SteamVariant.BRONZE ? COLOR_TITLE.get() : COLOR_TITLE_WHITE.get(); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java new file mode 100644 index 0000000000..5f818c075b --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_ProcessingArray.java @@ -0,0 +1,545 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.ExoticEnergy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.GT_Values.VN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_ARRAY; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_ARRAY_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_ARRAY_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PROCESSING_ARRAY_GLOW; +import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; +import static gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine.isValidForLowGravity; +import static gregtech.api.util.GT_Utility.filterValidMTEs; + +import java.util.List; + +import javax.annotation.Nonnull; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.Textures; +import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TieredMachineBlock; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ExoticEnergyInputHelper; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_ProcessingArray_Manager; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_StructureUtility; +import gregtech.api.util.GT_Utility; +import gregtech.common.blocks.GT_Item_Machines; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +@Deprecated +public class GT_MetaTileEntity_ProcessingArray extends + GT_MetaTileEntity_ExtendedPowerMultiBlockBase<GT_MetaTileEntity_ProcessingArray> implements ISurvivalConstructable { + + private static final String STRUCTURE_PIECE_MAIN = "main"; + private static final IStructureDefinition<GT_MetaTileEntity_ProcessingArray> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_ProcessingArray>builder() + .addShape( + STRUCTURE_PIECE_MAIN, + transpose(new String[][] { { "hhh", "hhh", "hhh" }, { "h~h", "h-h", "hhh" }, { "hhh", "hhh", "hhh" }, })) + .addElement( + 'h', + ofChain( + lazy( + t -> GT_StructureUtility.<GT_MetaTileEntity_ProcessingArray>buildHatchAdder() + .atLeastList(t.getAllowedHatches()) + .casingIndex(48) + .dot(1) + .build()), + onElementPass(t -> t.mCasingAmount++, ofBlock(GregTech_API.sBlockCasings4, 0)))) + .build(); + + private int mCasingAmount = 0; + + private RecipeMap<?> mLastRecipeMap; + private ItemStack lastControllerStack; + private int tTier = 0; + private int mMult = 0; + private boolean downtierUEV = true; + + public GT_MetaTileEntity_ProcessingArray(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_ProcessingArray(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_ProcessingArray(this.mName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Processing Array") + .addInfo("Runs supplied machines as if placed in the world") + .addInfo("Place up to 64 singleblock GT machines into the controller") + .addInfo("Note that you still need to supply power to them all") + .addInfo("Use a screwdriver to enable separate input busses") + .addInfo("Use a wire cutter to disable UEV+ downtiering") + .addInfo("Doesn't work on certain machines, deal with it") + .addInfo("Use it if you hate GT++, or want even more speed later on") + .addInfo( + EnumChatFormatting.GOLD + + "On the way to be slowly removed. Use it strictly if you have no alternative.") + .addSeparator() + .beginStructureBlock(3, 3, 3, true) + .addController("Front center") + .addCasingInfoRange("Robust Tungstensteel Machine Casing", 14, 24, false) + .addEnergyHatch("Any casing", 1) + .addMaintenanceHatch("Any casing", 1) + .addInputBus("Any casing", 1) + .addInputHatch("Any casing", 1) + .addOutputBus("Any casing", 1) + .addOutputHatch("Any casing", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public boolean addToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + return super.addToMachineList(aTileEntity, aBaseCasingIndex) + || addExoticEnergyInputToMachineList(aTileEntity, aBaseCasingIndex); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { BlockIcons.casingTexturePages[0][48], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PROCESSING_ARRAY_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PROCESSING_ARRAY_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { BlockIcons.casingTexturePages[0][48], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PROCESSING_ARRAY) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PROCESSING_ARRAY_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { Textures.BlockIcons.casingTexturePages[0][48] }; + } + + private RecipeMap<?> fetchRecipeMap() { + if (isCorrectMachinePart(getControllerSlot())) { + // Gets the recipe map for the given machine through its unlocalized name + return GT_ProcessingArray_Manager + .giveRecipeMap(GT_ProcessingArray_Manager.getMachineName(getControllerSlot())); + } + return null; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return mLastRecipeMap; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return aStack != null && aStack.getUnlocalizedName() + .startsWith("gt.blockmachines."); + } + + @Override + protected void sendStartMultiBlockSoundLoop() { + SoundResource sound = GT_ProcessingArray_Manager + .getSoundResource(GT_ProcessingArray_Manager.getMachineName(getControllerSlot())); + if (sound != null) { + sendLoopStart((byte) sound.id); + } + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + SoundResource sound = SoundResource.get(aIndex < 0 ? aIndex + 256 : 0); + if (sound != null) { + GT_Utility.doSoundAtClient(sound, getTimeBetweenProcessSounds(), 1.0F, aX, aY, aZ); + } + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + if (!GT_Utility.areStacksEqual(lastControllerStack, getControllerSlot())) { + // controller slot has changed + lastControllerStack = getControllerSlot(); + mLastRecipeMap = fetchRecipeMap(); + setTierAndMult(); + } + if (mLastRecipeMap == null) return SimpleCheckRecipeResult.ofFailure("no_machine"); + if (mLockedToSingleRecipe && mSingleRecipeCheck != null) { + if (mSingleRecipeCheck.getRecipeMap() != mLastRecipeMap) { + return SimpleCheckRecipeResult.ofFailure("machine_mismatch"); + } + } + + return super.checkProcessing(); + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @Nonnull + @Override + protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + if (GT_Mod.gregtechproxy.mLowGravProcessing && recipe.mSpecialValue == -100 + && !isValidForLowGravity(recipe, getBaseMetaTileEntity().getWorld().provider.dimensionId)) { + return SimpleCheckRecipeResult.ofFailure("high_gravity"); + } + if (recipe.mEUt > availableVoltage) return CheckRecipeResultRegistry.insufficientPower(recipe.mEUt); + return CheckRecipeResultRegistry.SUCCESSFUL; + } + }.setMaxParallelSupplier(this::getMaxParallel); + } + + @Override + protected boolean canUseControllerSlotForRecipe() { + return false; + } + + @Override + protected void setProcessingLogicPower(ProcessingLogic logic) { + logic.setAvailableVoltage(GT_Values.V[tTier] * (mLastRecipeMap != null ? mLastRecipeMap.getAmperage() : 1)); + logic.setAvailableAmperage(getMaxParallel()); + logic.setAmperageOC(false); + } + + private void setTierAndMult() { + IMetaTileEntity aMachine = GT_Item_Machines.getMetaTileEntity(getControllerSlot()); + if (aMachine instanceof GT_MetaTileEntity_TieredMachineBlock) { + tTier = ((GT_MetaTileEntity_TieredMachineBlock) aMachine).mTier; + } else { + tTier = 0; + } + mMult = 0; + if (downtierUEV && tTier > 9) { + tTier--; // Lowers down the tier by 1 to allow for bigger parallel + mMult = 2; // Multiplies Parallels by 4x, keeping the energy cost + } + } + + private int getMaxParallel() { + if (getControllerSlot() == null) { + return 0; + } + return getControllerSlot().stackSize << mMult; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (mMachine && aTick % 20 == 0) { + for (GT_MetaTileEntity_Hatch_InputBus tInputBus : mInputBusses) { + tInputBus.mRecipeMap = mLastRecipeMap; + } + for (GT_MetaTileEntity_Hatch_Input tInputHatch : mInputHatches) { + tInputHatch.mRecipeMap = mLastRecipeMap; + } + } + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_ProcessingArray> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public void construct(ItemStack aStack, boolean aHintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, aStack, aHintsOnly, 1, 1, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(STRUCTURE_PIECE_MAIN, stackSize, 1, 1, 0, elementBudget, env, false, true); + } + + private boolean checkHatches() { + return mMaintenanceHatches.size() == 1; + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setBoolean("downtierUEV", downtierUEV); + } + + @Override + public void loadNBTData(final NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + if (aNBT.hasKey("mSeparate")) { + // backward compatibility + inputSeparation = aNBT.getBoolean("mSeparate"); + } + if (aNBT.hasKey("mUseMultiparallelMode")) { + // backward compatibility + batchMode = aNBT.getBoolean("mUseMultiparallelMode"); + } + downtierUEV = aNBT.getBoolean("downtierUEV"); + } + + @Override + public final void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (aPlayer.isSneaking()) { + // Lock to single recipe + super.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ); + } else { + inputSeparation = !inputSeparation; + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("GT5U.machines.separatebus") + " " + inputSeparation); + } + } + + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ) { + if (aPlayer.isSneaking()) { + batchMode = !batchMode; + if (batchMode) { + GT_Utility.sendChatToPlayer(aPlayer, "Batch recipes"); + } else { + GT_Utility.sendChatToPlayer(aPlayer, "Don't batch recipes"); + } + } else { + downtierUEV = !downtierUEV; + GT_Utility.sendChatToPlayer(aPlayer, "Treat UEV+ machines as multiple UHV " + downtierUEV); + } + return true; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + private List<IHatchElement<? super GT_MetaTileEntity_ProcessingArray>> getAllowedHatches() { + return ImmutableList.of(InputHatch, OutputHatch, InputBus, OutputBus, Maintenance, Energy, ExoticEnergy); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + mExoticEnergyHatches.clear(); + mCasingAmount = 0; + return checkPiece(STRUCTURE_PIECE_MAIN, 1, 1, 0) && mCasingAmount >= 14 && checkHatches(); + } + + @Override + public String[] getInfoData() { + long storedEnergy = 0; + long maxEnergy = 0; + for (GT_MetaTileEntity_Hatch tHatch : filterValidMTEs(mExoticEnergyHatches)) { + storedEnergy += tHatch.getBaseMetaTileEntity() + .getStoredEU(); + maxEnergy += tHatch.getBaseMetaTileEntity() + .getEUCapacity(); + } + + return new String[] { + StatCollector.translateToLocal("GT5U.multiblock.Progress") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(mProgresstime / 20) + + EnumChatFormatting.RESET + + " s / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(mMaxProgresstime / 20) + + EnumChatFormatting.RESET + + " s", + StatCollector.translateToLocal("GT5U.multiblock.energy") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(storedEnergy) + + EnumChatFormatting.RESET + + " EU / " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers(maxEnergy) + + EnumChatFormatting.RESET + + " EU", + StatCollector.translateToLocal("GT5U.multiblock.usage") + ": " + + EnumChatFormatting.RED + + GT_Utility.formatNumbers(-lEUt) + + EnumChatFormatting.RESET + + " EU/t", + StatCollector.translateToLocal("GT5U.multiblock.mei") + ": " + + EnumChatFormatting.YELLOW + + GT_Utility.formatNumbers( + GT_ExoticEnergyInputHelper.getMaxInputVoltageMulti(getExoticAndNormalEnergyHatchList())) + + EnumChatFormatting.RESET + + " EU/t(*" + + GT_Utility + .formatNumbers(GT_ExoticEnergyInputHelper.getMaxInputAmpsMulti(getExoticAndNormalEnergyHatchList())) + + "A) " + + StatCollector.translateToLocal("GT5U.machines.tier") + + ": " + + EnumChatFormatting.YELLOW + + VN[GT_Utility + .getTier(GT_ExoticEnergyInputHelper.getMaxInputVoltageMulti(getExoticAndNormalEnergyHatchList()))] + + EnumChatFormatting.RESET, + StatCollector.translateToLocal("GT5U.multiblock.problems") + ": " + + EnumChatFormatting.RED + + (getIdealStatus() - getRepairStatus()) + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.multiblock.efficiency") + + ": " + + EnumChatFormatting.YELLOW + + mEfficiency / 100.0F + + EnumChatFormatting.RESET + + " %", + StatCollector.translateToLocal("GT5U.PA.machinetier") + ": " + + EnumChatFormatting.GREEN + + tTier + + EnumChatFormatting.RESET + + " " + + StatCollector.translateToLocal("GT5U.PA.discount") + + ": " + + EnumChatFormatting.GREEN + + 1 + + EnumChatFormatting.RESET + + " x", + StatCollector.translateToLocal("GT5U.PA.parallel") + ": " + + EnumChatFormatting.GREEN + + GT_Utility.formatNumbers(getMaxParallel()) + + EnumChatFormatting.RESET }; + } + + @Override + public boolean supportsInputSeparation() { + return true; + } + + @Override + public boolean supportsBatchMode() { + return true; + } + + @Override + public boolean supportsSingleRecipeLocking() { + return true; + } + + @Override + public boolean supportsVoidProtection() { + return true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + super.addUIWidgets(builder, buildContext); + + builder.widget(new ButtonWidget().setOnClick((clickData, widget) -> { + downtierUEV = !downtierUEV; + setTierAndMult(); + }) + .setPlayClickSound(true) + .setBackground(() -> { + if (downtierUEV) { + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD_PRESSED, + GT_UITextures.OVERLAY_BUTTON_DOWN_TIERING_ON }; + } else { + return new IDrawable[] { GT_UITextures.BUTTON_STANDARD, + GT_UITextures.OVERLAY_BUTTON_DOWN_TIERING_OFF }; + } + }) + .setPos(80, 91) + .setSize(16, 16) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.down_tier")) + .setTooltipShowUpDelay(TOOLTIP_DELAY)) + .widget(new FakeSyncWidget.BooleanSyncer(() -> downtierUEV, val -> downtierUEV = val)); + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + super.getWailaNBTData(player, tile, tag, world, x, y, z); + if (mLastRecipeMap != null && getControllerSlot() != null) { + tag.setString("type", getControllerSlot().getDisplayName()); + } + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + super.getWailaBody(itemStack, currentTip, accessor, config); + final NBTTagCompound tag = accessor.getNBTData(); + if (tag.hasKey("type")) { + currentTip.add("Machine: " + EnumChatFormatting.YELLOW + tag.getString("type")); + } else { + currentTip.add("Machine: " + EnumChatFormatting.YELLOW + "None"); + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PyrolyseOven.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PyrolyseOven.java new file mode 100644 index 0000000000..ff84a69b44 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_PyrolyseOven.java @@ -0,0 +1,263 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlockUnlocalizedName; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.Muffler; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.Mods.NewHorizonsCoreMod; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PYROLYSE_OVEN; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PYROLYSE_OVEN_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PYROLYSE_OVEN_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_PYROLYSE_OVEN_GLOW; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.ofCoil; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.IStructureElement; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.GT_Mod; +import gregtech.api.GregTech_API; +import gregtech.api.enums.HeatingCoilLevel; +import gregtech.api.enums.Textures; +import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_PyrolyseOven + extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_PyrolyseOven> implements ISurvivalConstructable { + + private HeatingCoilLevel coilHeat; + private static final int CASING_INDEX = 1090; + private static final IStructureDefinition<GT_MetaTileEntity_PyrolyseOven> STRUCTURE_DEFINITION = createStructureDefinition(); + + private static IStructureDefinition<GT_MetaTileEntity_PyrolyseOven> createStructureDefinition() { + IStructureElement<GT_MetaTileEntity_PyrolyseOven> tCasingElement = NewHorizonsCoreMod.isModLoaded() + ? ofBlockUnlocalizedName(NewHorizonsCoreMod.ID, "gt.blockcasingsNH", 2) + : ofBlock(GregTech_API.sBlockCasings1, 0); + + return StructureDefinition.<GT_MetaTileEntity_PyrolyseOven>builder() + .addShape( + "main", + transpose( + new String[][] { { "ccccc", "ctttc", "ctttc", "ctttc", "ccccc" }, + { "ccccc", "c---c", "c---c", "c---c", "ccccc" }, + { "ccccc", "c---c", "c---c", "c---c", "ccccc" }, + { "bb~bb", "bCCCb", "bCCCb", "bCCCb", "bbbbb" }, })) + .addElement('c', onElementPass(GT_MetaTileEntity_PyrolyseOven::onCasingAdded, tCasingElement)) + .addElement( + 'C', + ofCoil(GT_MetaTileEntity_PyrolyseOven::setCoilLevel, GT_MetaTileEntity_PyrolyseOven::getCoilLevel)) + .addElement( + 'b', + buildHatchAdder(GT_MetaTileEntity_PyrolyseOven.class) + .atLeast(OutputBus, OutputHatch, Energy, Maintenance) + .casingIndex(CASING_INDEX) + .dot(1) + .buildAndChain(onElementPass(GT_MetaTileEntity_PyrolyseOven::onCasingAdded, tCasingElement))) + .addElement( + 't', + buildHatchAdder(GT_MetaTileEntity_PyrolyseOven.class).atLeast(InputBus, InputHatch, Muffler) + .casingIndex(CASING_INDEX) + .dot(1) + .buildAndChain(onElementPass(GT_MetaTileEntity_PyrolyseOven::onCasingAdded, tCasingElement))) + .build(); + } + + private int mCasingAmount; + + public GT_MetaTileEntity_PyrolyseOven(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_PyrolyseOven(String aName) { + super(aName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Coke Oven") + .addInfo("Controller block for the Pyrolyse Oven") + .addInfo("Industrial Charcoal producer") + .addInfo("Processing speed scales linearly with Coil tier:") + .addInfo("CuNi: 50%, FeAlCr: 100%, Ni4Cr: 150%, TPV: 200%, etc.") + .addInfo("EU/t is not affected by Coil tier") + .addPollutionAmount(getPollutionPerSecond(null)) + .addSeparator() + .beginStructureBlock(5, 4, 5, true) + .addController("Front center") + .addCasingInfoRange("Pyrolyse Oven Casing", 60, 80, false) + .addOtherStructurePart("Heating Coils", "Center 3x1x3 of the bottom layer") + .addEnergyHatch("Any bottom layer casing", 1) + .addMaintenanceHatch("Any bottom layer casing", 1) + .addMufflerHatch("Center 3x1x3 area in top layer", 2) + .addInputBus("Center 3x1x3 area in top layer", 2) + .addInputHatch("Center 3x1x3 area in top layer", 2) + .addOutputBus("Any bottom layer casing", 1) + .addOutputHatch("Any bottom layer casing", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity baseMetaTileEntity, ForgeDirection sideDirection, + ForgeDirection facingDirection, int colorIndex, boolean active, boolean redstoneLevel) { + if (sideDirection == facingDirection) { + if (active) return new ITexture[] { BlockIcons.casingTexturePages[8][66], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PYROLYSE_OVEN_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PYROLYSE_OVEN_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { BlockIcons.casingTexturePages[8][66], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PYROLYSE_OVEN) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_PYROLYSE_OVEN_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { Textures.BlockIcons.casingTexturePages[8][66] }; + } + + @Override + public boolean supportsSingleRecipeLocking() { + return true; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.pyrolyseRecipes; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @NotNull + @Override + public CheckRecipeResult process() { + setSpeedBonus(2f / (1 + coilHeat.getTier())); + return super.process(); + } + }; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_PyrolyseOven> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + private void onCasingAdded() { + mCasingAmount++; + } + + public HeatingCoilLevel getCoilLevel() { + return coilHeat; + } + + private void setCoilLevel(HeatingCoilLevel aCoilLevel) { + coilHeat = aCoilLevel; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + coilHeat = HeatingCoilLevel.None; + mCasingAmount = 0; + replaceDeprecatedCoils(aBaseMetaTileEntity); + return checkPiece("main", 2, 3, 0) && mCasingAmount >= 60 + && mMaintenanceHatches.size() == 1 + && !mMufflerHatches.isEmpty(); + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getPollutionPerSecond(ItemStack aStack) { + return GT_Mod.gregtechproxy.mPollutionPyrolyseOvenPerSecond; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_PyrolyseOven(this.mName); + } + + private void replaceDeprecatedCoils(IGregTechTileEntity aBaseMetaTileEntity) { + final int xDir = aBaseMetaTileEntity.getBackFacing().offsetX; + final int zDir = aBaseMetaTileEntity.getBackFacing().offsetZ; + final int tX = aBaseMetaTileEntity.getXCoord() + xDir * 2; + final int tY = aBaseMetaTileEntity.getYCoord(); + final int tZ = aBaseMetaTileEntity.getZCoord() + zDir * 2; + for (int xPos = tX - 1; xPos <= tX + 1; xPos++) { + for (int zPos = tZ - 1; zPos <= tZ + 1; zPos++) { + if (aBaseMetaTileEntity.getBlock(xPos, tY, zPos) == GregTech_API.sBlockCasings1 + && aBaseMetaTileEntity.getMetaID(xPos, tY, zPos) == 13) { + aBaseMetaTileEntity.getWorld() + .setBlock(xPos, tY, zPos, GregTech_API.sBlockCasings5, 1, 3); + } + } + } + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece("main", stackSize, hintsOnly, 2, 3, 0); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece("main", stackSize, 2, 3, 0, elementBudget, env, false, true); + } + + @Override + public boolean supportsVoidProtection() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_TranscendentPlasmaMixer.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_TranscendentPlasmaMixer.java new file mode 100644 index 0000000000..7d038666d6 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_TranscendentPlasmaMixer.java @@ -0,0 +1,288 @@ +package gregtech.common.tileentities.machines.multi; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.GT_Values.AuthorColen; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_DTPF_OFF; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_DTPF_ON; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FUSION1_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.common.misc.WirelessNetworkManager.addEUToGlobalEnergyMap; +import static gregtech.common.misc.WirelessNetworkManager.getUserEU; +import static gregtech.common.misc.WirelessNetworkManager.processInitialSettings; +import static gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_PlasmaForge.DIM_BRIDGE_CASING; +import static gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_PlasmaForge.DIM_INJECTION_CASING; +import static gregtech.common.tileentities.machines.multi.GT_MetaTileEntity_PlasmaForge.DIM_TRANS_CASING; +import static java.lang.Math.max; +import static net.minecraft.util.EnumChatFormatting.GOLD; +import static net.minecraft.util.EnumChatFormatting.GRAY; + +import java.math.BigInteger; +import java.util.UUID; + +import javax.annotation.Nonnull; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.ForgeDirection; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Recipe; +import gregtech.common.items.GT_IntegratedCircuit_Item; + +public class GT_MetaTileEntity_TranscendentPlasmaMixer + extends GT_MetaTileEntity_EnhancedMultiBlockBase<GT_MetaTileEntity_TranscendentPlasmaMixer> + implements ISurvivalConstructable { + + private static final String[][] structure = new String[][] { + { " CAC ", " ABA ", " ABA ", " A~A ", " ABA ", " ABA ", " CAC " }, + { "CBBBC", "A A", "A A", "A A", "A A", "A A", "CBBBC" }, + { "ABBBA", "B B", "B B", "B B", "B B", "B B", "ABBBA" }, + { "CBBBC", "A A", "A A", "A A", "A A", "A A", "CBBBC" }, + { " CAC ", " ABA ", " ABA ", " ABA ", " ABA ", " ABA ", " CAC " } }; + + private static final String STRUCTURE_PIECE_MAIN = "MAIN"; + private static final IStructureDefinition<GT_MetaTileEntity_TranscendentPlasmaMixer> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_TranscendentPlasmaMixer>builder() + .addShape(STRUCTURE_PIECE_MAIN, structure) + .addElement( + 'B', + buildHatchAdder(GT_MetaTileEntity_TranscendentPlasmaMixer.class) + .atLeast(InputHatch, OutputHatch, InputBus, Maintenance) + .casingIndex(DIM_INJECTION_CASING) + .dot(1) + .buildAndChain(GregTech_API.sBlockCasings1, DIM_INJECTION_CASING)) + .addElement('A', ofBlock(GregTech_API.sBlockCasings1, DIM_TRANS_CASING)) + .addElement('C', ofBlock(GregTech_API.sBlockCasings1, DIM_BRIDGE_CASING)) + .build(); + + private UUID ownerUUID; + + public GT_MetaTileEntity_TranscendentPlasmaMixer(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_TranscendentPlasmaMixer(String aName) { + super(aName); + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_TranscendentPlasmaMixer> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Transcendent Mixer") + .addInfo("Assisting in all your DTPF needs.") + .addInfo("This multiblock will run in parallel according to the circuit provided to the") + .addInfo("controller slot. E.g. 3x Circuit #16 = 48x parallel. All inputs will scale,") + .addInfo("except time. All EU is deducted from wireless EU networks only.") + .addInfo(AuthorColen) + .addInfo("Controller slot and circuit slot are separate.") + .addSeparator() + .beginStructureBlock(5, 7, 5, false) + .addStructureInfo(GOLD + "1+ " + GRAY + "Input Hatch") + .addStructureInfo(GOLD + "1+ " + GRAY + "Output Hatch") + .addStructureInfo(GOLD + "1+ " + GRAY + "Input Bus") + .addStructureInfo(GOLD + "1 " + GRAY + "Maintenance Hatch") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_TranscendentPlasmaMixer(mName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { casingTexturePages[0][DIM_TRANS_CASING], TextureFactory.builder() + .addIcon(OVERLAY_DTPF_ON) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FUSION1_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { casingTexturePages[0][DIM_TRANS_CASING], TextureFactory.builder() + .addIcon(OVERLAY_DTPF_OFF) + .extFacing() + .build() }; + } + + return new ITexture[] { casingTexturePages[0][DIM_TRANS_CASING] }; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + int multiplier = 1; + long mWirelessEUt = 0; + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.transcendentPlasmaMixerRecipes; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @NotNull + @Override + protected CheckRecipeResult validateRecipe(@Nonnull GT_Recipe recipe) { + mWirelessEUt = 10L * (long) recipe.mEUt * (long) multiplier; + if (getUserEU(ownerUUID).compareTo(BigInteger.valueOf(mWirelessEUt * recipe.mDuration)) < 0) { + return CheckRecipeResultRegistry.insufficientPower(mWirelessEUt * recipe.mDuration); + } + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + @NotNull + @Override + protected CheckRecipeResult onRecipeStart(@Nonnull GT_Recipe recipe) { + mWirelessEUt = 10L * (long) recipe.mEUt * (long) multiplier; + // This will void the inputs if wireless energy has dropped + // below the required amount between validateRecipe and here. + if (!addEUToGlobalEnergyMap(ownerUUID, -mWirelessEUt * recipe.mDuration)) { + return CheckRecipeResultRegistry.insufficientPower(mWirelessEUt * recipe.mDuration); + } + // Energy consumed all at once from wireless net. + setCalculatedEut(0); + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + @Nonnull + @Override + protected GT_OverclockCalculator createOverclockCalculator(@Nonnull GT_Recipe recipe) { + return GT_OverclockCalculator.ofNoOverclock(recipe); + } + }.setMaxParallelSupplier(() -> { + ItemStack controllerStack = getControllerSlot(); + if (controllerStack != null && controllerStack.getItem() instanceof GT_IntegratedCircuit_Item) { + multiplier = controllerStack.stackSize * max(1, controllerStack.getItemDamage()); + } + return multiplier; + }); + } + + @Override + protected void setProcessingLogicPower(ProcessingLogic logic) { + // The voltage is only used for recipe finding + logic.setAvailableVoltage(Long.MAX_VALUE); + logic.setAvailableAmperage(1); + logic.setAmperageOC(false); + } + + @Override + protected long getActualEnergyUsage() { + return mWirelessEUt; + } + + private static final int HORIZONTAL_OFFSET = 2; + private static final int VERTICAL_OFFSET = 3; + private static final int DEPTH_OFFSET = 0; + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, stackSize, hintsOnly, HORIZONTAL_OFFSET, VERTICAL_OFFSET, DEPTH_OFFSET); + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + return survivialBuildPiece( + STRUCTURE_PIECE_MAIN, + stackSize, + HORIZONTAL_OFFSET, + VERTICAL_OFFSET, + DEPTH_OFFSET, + elementBudget, + env, + false, + true); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + + // Check the main structure + if (!checkPiece(STRUCTURE_PIECE_MAIN, HORIZONTAL_OFFSET, VERTICAL_OFFSET, DEPTH_OFFSET)) { + return false; + } + + return (mMaintenanceHatches.size() == 1); + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 0; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + + super.onPreTick(aBaseMetaTileEntity, aTick); + + if (aBaseMetaTileEntity.isServerSide() && (aTick == 1)) { + // Adds player to the wireless network if they do not already exist on it. + ownerUUID = processInitialSettings(aBaseMetaTileEntity); + } + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + aNBT.setInteger("eMultiplier", multiplier); + super.saveNBTData(aNBT); + } + + @Override + public void loadNBTData(final NBTTagCompound aNBT) { + multiplier = aNBT.getInteger("eMultiplier"); + super.loadNBTData(aNBT); + } + + @Override + public boolean supportsVoidProtection() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_VacuumFreezer.java b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_VacuumFreezer.java new file mode 100644 index 0000000000..499da54bc3 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/GT_MetaTileEntity_VacuumFreezer.java @@ -0,0 +1,163 @@ +package gregtech.common.tileentities.machines.multi; + +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_HatchElement.OutputHatch; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_VACUUM_FREEZER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_VACUUM_FREEZER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_VACUUM_FREEZER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_VACUUM_FREEZER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; + +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizon.structurelib.structure.IStructureElement; +import com.gtnewhorizon.structurelib.structure.StructureUtility; + +import gregtech.api.GregTech_API; +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_CubicMultiBlockBase; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; + +public class GT_MetaTileEntity_VacuumFreezer + extends GT_MetaTileEntity_CubicMultiBlockBase<GT_MetaTileEntity_VacuumFreezer> { + + public GT_MetaTileEntity_VacuumFreezer(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_VacuumFreezer(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_VacuumFreezer(this.mName); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Vacuum Freezer") + .addInfo("Controller Block for the Vacuum Freezer") + .addInfo("Cools hot ingots and cells") + .addSeparator() + .beginStructureBlock(3, 3, 3, true) + .addController("Front center") + .addCasingInfoRange("Frost Proof Machine Casing", 16, 24, false) + .addEnergyHatch("Any casing", 1) + .addMaintenanceHatch("Any casing", 1) + .addInputHatch("Any casing", 1) + .addOutputHatch("Any casing", 1) + .addInputBus("Any casing", 1) + .addOutputBus("Any casing", 1) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + ITexture[] rTexture; + if (side == aFacing) { + if (aActive) { + rTexture = new ITexture[] { casingTexturePages[0][17], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_VACUUM_FREEZER_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_VACUUM_FREEZER_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + } else { + rTexture = new ITexture[] { casingTexturePages[0][17], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_VACUUM_FREEZER) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_VACUUM_FREEZER_GLOW) + .extFacing() + .glow() + .build() }; + } + } else { + rTexture = new ITexture[] { casingTexturePages[0][17] }; + } + return rTexture; + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.vacuumFreezerRecipes; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + protected ProcessingLogic createProcessingLogic() { + return new ProcessingLogic(); + } + + @Override + protected IStructureElement<GT_MetaTileEntity_CubicMultiBlockBase<?>> getCasingElement() { + return StructureUtility.ofBlock(GregTech_API.sBlockCasings2, 1); + } + + @Override + protected List<IHatchElement<? super GT_MetaTileEntity_CubicMultiBlockBase<?>>> getAllowedHatches() { + return ImmutableList.of(InputHatch, OutputHatch, InputBus, OutputBus, Maintenance, Energy); + } + + @Override + protected int getHatchTextureIndex() { + return 17; + } + + @Override + protected int getRequiredCasingCount() { + return 16; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public boolean supportsVoidProtection() { + return true; + } + + @Override + public boolean supportsBatchMode() { + return true; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/drone/DroneConnection.java b/src/main/java/gregtech/common/tileentities/machines/multi/drone/DroneConnection.java new file mode 100644 index 0000000000..92b1c65032 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/drone/DroneConnection.java @@ -0,0 +1,143 @@ +package gregtech.common.tileentities.machines.multi.drone; + +import static gregtech.GT_Mod.gregtechproxy; + +import java.util.Optional; + +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.world.World; +import net.minecraftforge.common.DimensionManager; + +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.util.GT_LanguageManager; +import gregtech.api.util.GT_Util; +import gregtech.api.util.GT_Utility; + +public class DroneConnection { + + String customName; + String unlocalizedName; + GT_MetaTileEntity_MultiBlockBase machine; + ItemStack machineItem; + ChunkCoordinates machineCoord; + GT_MetaTileEntity_DroneCentre centre; + ChunkCoordinates centreCoord; + World world; + + public DroneConnection(GT_MetaTileEntity_MultiBlockBase machine, GT_MetaTileEntity_DroneCentre centre) { + this.machine = machine; + this.machineItem = machine.getStackForm(1); + machineCoord = machine.getBaseMetaTileEntity() + .getCoords(); + this.centre = centre; + centreCoord = centre.getBaseMetaTileEntity() + .getCoords(); + this.world = centre.getBaseMetaTileEntity() + .getWorld(); + unlocalizedName = machine.mName; + customName = Optional.ofNullable(centre.tempNameList.remove(machineCoord.toString())) + .orElse(machine.getLocalName()); + } + + public DroneConnection(NBTTagCompound aNBT) { + NBTTagCompound machineTag = aNBT.getCompoundTag("machine"); + NBTTagCompound centreTag = aNBT.getCompoundTag("centre"); + if (!gregtechproxy.isClientSide()) { + this.world = DimensionManager.getWorld(aNBT.getInteger("worldID")); + } else { + this.world = Minecraft.getMinecraft().thePlayer.worldObj; + } + machineItem = ItemStack.loadItemStackFromNBT(aNBT.getCompoundTag("item")); + machineCoord = new ChunkCoordinates( + machineTag.getInteger("x"), + machineTag.getInteger("y"), + machineTag.getInteger("z")); + this.machine = getLoadedGT_BaseMachineAt(machineCoord, world, true); + centreCoord = new ChunkCoordinates( + centreTag.getInteger("x"), + centreTag.getInteger("y"), + centreTag.getInteger("z")); + this.centre = (GT_MetaTileEntity_DroneCentre) getLoadedGT_BaseMachineAt(centreCoord, world, true); + this.customName = aNBT.getString("name"); + this.unlocalizedName = aNBT.getString("unlocalizedName"); + } + + public GT_MetaTileEntity_MultiBlockBase getMachine() { + return machine; + } + + public boolean reCheckConnection() { + if (machine == null) this.machine = getLoadedGT_BaseMachineAt(machineCoord, world, true); + if (centre == null) + this.centre = (GT_MetaTileEntity_DroneCentre) getLoadedGT_BaseMachineAt(centreCoord, world, true); + if (machine != null && centre != null + && !centre.getConnectionList() + .contains(this)) + centre.getConnectionList() + .add(this); + return isValid(); + } + + public String getCustomName(boolean localized) { + if (localized) return GT_LanguageManager.getTranslation("gt.blockmachines." + unlocalizedName + ".name"); + return customName; + } + + public float getDistanceSquared() { + return centreCoord.getDistanceSquaredToChunkCoordinates(machineCoord); + } + + public void setCustomName(String name) { + customName = name; + } + + public boolean isMachineShutdown() { + return machine != null && machine.shouldDisplayShutDownReason() + && !machine.getBaseMetaTileEntity() + .isActive() + && GT_Utility.isStringValid( + machine.getBaseMetaTileEntity() + .getLastShutDownReason() + .getDisplayString()) + && machine.getBaseMetaTileEntity() + .wasShutdown(); + } + + public NBTTagCompound transConnectionToNBT() { + NBTTagCompound aNBT = new NBTTagCompound(); + aNBT.setTag("machine", transCoordsToNBT(machineCoord)); + aNBT.setTag("centre", transCoordsToNBT(centreCoord)); + aNBT.setTag("item", machineItem.writeToNBT(new NBTTagCompound())); + aNBT.setInteger( + "worldID", + centre.getBaseMetaTileEntity() + .getWorld().provider.dimensionId); + aNBT.setString("name", getCustomName(false)); + aNBT.setString("unlocalizedName", unlocalizedName); + return aNBT; + } + + public GT_MetaTileEntity_MultiBlockBase getLoadedGT_BaseMachineAt(ChunkCoordinates coords, World world, + boolean isLoaded) { + TileEntity te = GT_Util.getTileEntity(world, coords, isLoaded); + if (te == null) return null; + return (GT_MetaTileEntity_MultiBlockBase) ((IGregTechTileEntity) te).getMetaTileEntity(); + } + + private NBTTagCompound transCoordsToNBT(ChunkCoordinates coord) { + NBTTagCompound tag = new NBTTagCompound(); + tag.setInteger("x", coord.posX); + tag.setInteger("y", coord.posY); + tag.setInteger("z", coord.posZ); + return tag; + } + + public boolean isValid() { + return machine != null && machine.isValid() && centre != null && centre.isValid(); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_DroneCentre.java b/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_DroneCentre.java new file mode 100644 index 0000000000..2bb224cdb7 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_DroneCentre.java @@ -0,0 +1,912 @@ +package gregtech.common.tileentities.machines.multi.drone; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_Values.AuthorSilverMoon; +import static gregtech.api.multitileentity.multiblock.casing.Glasses.chainAllGlasses; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; + +import java.io.IOException; +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.stream.Collectors; + +import net.minecraft.client.Minecraft; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.HashMultimap; +import com.gtnewhorizon.structurelib.alignment.IAlignmentLimits; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizon.structurelib.util.Vec3Impl; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.drawable.UITexture; +import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Color; +import com.gtnewhorizons.modularui.api.math.MainAxisAlignment; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedRow; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.Scrollable; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; +import com.gtnewhorizons.modularui.common.widget.textfield.TextFieldWidget; + +import appeng.api.util.DimensionalCoord; +import appeng.api.util.WorldCoord; +import appeng.client.render.BlockPosHighlighter; +import gregtech.api.GregTech_API; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.Textures; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.IIconContainer; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.SimpleCheckRecipeResult; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Log; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.shutdown.ShutDownReason; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; +import gregtech.common.gui.modularui.widget.ShutDownReasonSyncer; +import gregtech.common.items.GT_TierDrone; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaTileEntity_DroneCentre extends + GT_MetaTileEntity_ExtendedPowerMultiBlockBase<GT_MetaTileEntity_DroneCentre> implements ISurvivalConstructable { + + private static final IIconContainer ACTIVE = new Textures.BlockIcons.CustomIcon("iconsets/DRONE_CENTRE_ACTIVE"); + private static final IIconContainer FACE = new Textures.BlockIcons.CustomIcon("iconsets/DRONE_CENTRE_FACE"); + private static final IIconContainer INACTIVE = new Textures.BlockIcons.CustomIcon("iconsets/DRONE_CENTRE_INACTIVE"); + private final int MACHINE_LIST_WINDOW_ID = 10; + private final int CUSTOM_NAME_WINDOW_ID = 11; + private static final int CASINGS_MIN = 85; + private int mCasingAmount = 0; + private Vec3Impl centreCoord; + private int droneLevel = 0; + private int buttonID; + private String searchFilter = ""; + private boolean useRender = true; + private boolean showLocalizedName = false; + private String sort = "distance"; + private List<DroneConnection> connectionList = new ArrayList<>(); + public HashMap<String, String> tempNameList = new HashMap<>(); + // Save centre by dimID + private static final HashMultimap<Integer, GT_MetaTileEntity_DroneCentre> droneMap = HashMultimap.create(); + // spotless off + private static final IStructureDefinition<GT_MetaTileEntity_DroneCentre> STRUCTURE_DEFINITION = StructureDefinition + .<GT_MetaTileEntity_DroneCentre>builder() + .addShape( + "main", + transpose( + new String[][] { { " ", " ", " ", " ", "CCCCC", "CCCCC", "CCCCC", "CCCCC", "CCCCC" }, + { "CC~CC", "C C", "C C", "C C", "CAAAC", "CCCCC", "CAAAC", "C C", "CCCCC" }, + { "CCCCC", "CBBBC", "CBDBC", "CBBBC", "CCCCC", "CCCCC", "CCCCC", "CCCCC", "CCCCC" }, + { "C C", " ", " ", " ", " ", " ", " ", " ", "C C" } })) + .addElement( + 'C', + buildHatchAdder(GT_MetaTileEntity_DroneCentre.class).atLeast(InputBus) + .casingIndex(59) + .dot(1) + .buildAndChain( + onElementPass( + GT_MetaTileEntity_DroneCentre::onCasingAdded, + ofBlock(GregTech_API.sBlockCasings4, 2)))) + .addElement('A', chainAllGlasses()) + .addElement('B', ofBlock(GregTech_API.sBlockCasings1, 11)) + .addElement('D', ofBlock(GregTech_API.sBlockCasings4, 0)) + .build(); + + // spotless on + public GT_MetaTileEntity_DroneCentre(String name) { + super(name); + } + + public GT_MetaTileEntity_DroneCentre(int ID, String Name, String NameRegional) { + super(ID, Name, NameRegional); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_DroneCentre(super.mName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (getBaseMetaTileEntity().isActive()) { + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(59), TextureFactory.builder() + .addIcon(ACTIVE) + .extFacing() + .build() }; + } else { + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(59), TextureFactory.builder() + .addIcon(INACTIVE) + .extFacing() + .build() }; + } + } else if (side == aFacing.getOpposite()) { + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(59), TextureFactory.builder() + .addIcon(FACE) + .extFacing() + .build() }; + } + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(59) }; + } + + @Override + public IStructureDefinition<GT_MetaTileEntity_DroneCentre> getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Drone Centre") + .addInfo("Drone Center Controller") + .addInfo(EnumChatFormatting.AQUA + "Drone #10032, cleared for takeoff!") + .addInfo("Monitors multiblock machines in range.") + .addInfo("Replace maintenance hatch on other multi with drone downlink module.") + .addInfo("Provides maintenance, power control, monitoring and etc.") + .addInfo("Range is determined by drone tier: T1-128, T2-512, T3-4096") + .addInfo("Place drones in input bus; only one needed to operate.") + .addInfo("Automatically upgrade based on the drone level in the input bus.") + .addInfo("There is a chance per second that the drone will crash.") + .addInfo("Chance is determined by drone tier: T1-1/28800, T2-1/172800, T3-0") + .addInfo("If machine is too far, remote control would not available") + .addInfo(AuthorSilverMoon) + .addSeparator() + .beginStructureBlock(5, 4, 9, false) + .addController("Front center") + .addCasingInfoRange("Stable Titanium Machine Casing", CASINGS_MIN, 91, false) + .addCasingInfoExactly("Heat Proof Machine Casing", 8, false) + .addCasingInfoExactly("Robust Tungstensteel Machine Casing", 1, false) + .addCasingInfoExactly("Any tiered glass", 6, false) + .addInputBus("Any Titanium Casing", 1) + .addStructureInfo("No maintenance hatch needed") + .addSeparator() + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece("main", stackSize, hintsOnly, 2, 1, 0); + } + + @Override + public int survivalConstruct(ItemStack stack, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece("main", stack, 2, 1, 0, elementBudget, env, false, true); + } + + @Override + protected IAlignmentLimits getInitialAlignmentLimits() { + // I don't think a drone can take off HORIZONTALLY! + return (d, r, f) -> (d.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0 && r.isNotRotated() + && !f.isVerticallyFliped(); + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + private void onCasingAdded() { + mCasingAmount++; + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + mCasingAmount = 0; + return checkPiece("main", 2, 1, 0) && mCasingAmount >= CASINGS_MIN; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public final void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + super.onScrewdriverRightClick(side, aPlayer, aX, aY, aZ); + useRender = !useRender; + aPlayer.addChatComponentMessage( + new ChatComponentTranslation( + "GT5U.machines.dronecentre." + (useRender ? "enableRender" : "disableRender"))); + if (useRender) { + createRenderBlock(); + } else { + destroyRenderBlock(); + } + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return true; + } + + @Override + public void stopMachine(@NotNull ShutDownReason reason) { + destroyRenderBlock(); + super.stopMachine(reason); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + fixAll(); + if (aTick % 20 == 0) { + if (switch (droneLevel) { + case 1 -> getBaseMetaTileEntity().getRandomNumber(28800); + case 2 -> getBaseMetaTileEntity().getRandomNumber(172800); + default -> 1; + } == 0) { + droneLevel = 0; + startRecipeProcessing(); + if (!tryConsumeDrone()) stopMachine(ShutDownReasonRegistry.outOfStuff("Any Drone", 1)); + endRecipeProcessing(); + } + } + // Clean invalid connections every 4 seconds + if (aTick % 80 == 0) connectionList.removeIf(v -> !v.isValid()); + } + if (mMaxProgresstime > 0 && mMaxProgresstime - mProgresstime == 1) destroyRenderBlock(); + super.onPostTick(aBaseMetaTileEntity, aTick); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + droneLevel = aNBT.getInteger("drone"); + useRender = aNBT.getBoolean("useRender"); + sort = aNBT.getString("sort"); + NBTTagCompound nameList = aNBT.getCompoundTag("conList"); + for (String s : nameList.func_150296_c()) { + tempNameList.put(s, nameList.getString(s)); + } + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setInteger("drone", droneLevel); + aNBT.setBoolean("useRender", useRender); + aNBT.setString("sort", sort); + NBTTagCompound conList = new NBTTagCompound(); + for (DroneConnection con : connectionList) { + if (!con.customName.equals(con.machine.getLocalName())) + conList.setString(con.machineCoord.toString(), con.customName); + } + aNBT.setTag("conList", conList); + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + super.getWailaNBTData(player, tile, tag, world, x, y, z); + tag.setInteger("connectionCount", connectionList.size()); + if (droneLevel != 0) tag.setInteger("droneLevel", droneLevel); + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + NBTTagCompound tag = accessor.getNBTData(); + currenttip.add( + EnumChatFormatting.AQUA + StatCollector.translateToLocal("GT5U.waila.drone_downlink.droneLevel") + + tag.getInteger("droneLevel")); + currenttip.add( + StatCollector.translateToLocal("GT5U.waila.drone_downlink.connectionCount") + + tag.getInteger("connectionCount")); + super.getWailaBody(itemStack, currenttip, accessor, config); + } + + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + if (droneLevel == 0) { + if (!tryConsumeDrone()) return SimpleCheckRecipeResult.ofFailure("drone_noDrone"); + } + if (droneLevel == 1 || droneLevel == 2) tryUpdateDrone(); + mMaxProgresstime = 200 * droneLevel; + createRenderBlock(); + return SimpleCheckRecipeResult.ofSuccess("drone_operating"); + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + if (aBaseMetaTileEntity.isServerSide()) { + if (droneMap.containsValue(this)) return; + centreCoord = new Vec3Impl( + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord()); + droneMap.put(getBaseMetaTileEntity().getWorld().provider.dimensionId, this); + } + } + + @Override + public void onBlockDestroyed() { + destroyRenderBlock(); + connectionList.clear(); + if (droneLevel != 0) spawnDroneItem(); + super.onBlockDestroyed(); + } + + private void spawnDroneItem() { + ItemStack insideDrone = new ItemStack(switch (droneLevel) { + case 1: + yield ItemList.TierdDrone0.getItem(); + case 2: + yield ItemList.TierdDrone1.getItem(); + case 3: + yield ItemList.TierdDrone2.getItem(); + default: + yield null; + }, 1); + final EntityItem tItemEntity = new EntityItem( + getBaseMetaTileEntity().getWorld(), + getBaseMetaTileEntity().getXCoord() + XSTR_INSTANCE.nextFloat() * 0.8F + 0.1F, + getBaseMetaTileEntity().getYCoord() + XSTR_INSTANCE.nextFloat() * 0.8F + 0.1F, + getBaseMetaTileEntity().getZCoord() + XSTR_INSTANCE.nextFloat() * 0.8F + 0.1F, + insideDrone); + tItemEntity.motionX = (XSTR_INSTANCE.nextGaussian() * 0.05D); + tItemEntity.motionY = (XSTR_INSTANCE.nextGaussian() * 0.25D); + tItemEntity.motionZ = (XSTR_INSTANCE.nextGaussian() * 0.05D); + getBaseMetaTileEntity().getWorld() + .spawnEntityInWorld(tItemEntity); + } + + @Override + public void onRemoval() { + droneMap.remove(getBaseMetaTileEntity().getWorld().provider.dimensionId, this); + } + + public List<DroneConnection> getConnectionList() { + return connectionList; + } + + public int getRange() { + return switch (droneLevel) { + case 1 -> 128; + case 2 -> 512; + case 3 -> 4096; + default -> 0; + }; + } + + public Vec3Impl getCoords() { + return centreCoord; + } + + private boolean tryConsumeDrone() { + List<ItemStack> inputs = getStoredInputs(); + if (inputs.isEmpty()) return false; + for (ItemStack item : inputs) { + if (item != null && item.getItem() instanceof GT_TierDrone drone) { + this.droneLevel = drone.getLevel(); + item.stackSize--; + updateSlots(); + return true; + } + } + return false; + } + + private void tryUpdateDrone() { + List<ItemStack> inputs = getStoredInputs(); + if (inputs.isEmpty()) return; + for (ItemStack item : inputs) { + if (item != null && item.getItem() instanceof GT_TierDrone drone) { + if (drone.getLevel() <= this.droneLevel) continue; + this.droneLevel = drone.getLevel(); + item.stackSize--; + updateSlots(); + return; + } + } + } + + private void createRenderBlock() { + if (!useRender) return; + int x = getBaseMetaTileEntity().getXCoord(); + int y = getBaseMetaTileEntity().getYCoord(); + int z = getBaseMetaTileEntity().getZCoord(); + + double xOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetX; + double zOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetZ; + double yOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetY; + + this.getBaseMetaTileEntity() + .getWorld() + .setBlock((int) (x + xOffset), (int) (y + yOffset), (int) (z + zOffset), Blocks.air); + this.getBaseMetaTileEntity() + .getWorld() + .setBlock((int) (x + xOffset), (int) (y + yOffset), (int) (z + zOffset), GregTech_API.sDroneRender); + } + + private void destroyRenderBlock() { + int x = getBaseMetaTileEntity().getXCoord(); + int y = getBaseMetaTileEntity().getYCoord(); + int z = getBaseMetaTileEntity().getZCoord(); + + double xOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetX; + double zOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetZ; + double yOffset = 2 * getExtendedFacing().getRelativeBackInWorld().offsetY; + + this.getBaseMetaTileEntity() + .getWorld() + .setBlock((int) (x + xOffset), (int) (y + yOffset), (int) (z + zOffset), Blocks.air); + } + + private void fixAll() { + this.mWrench = this.mScrewdriver = this.mSoftHammer = this.mHardHammer = this.mCrowbar = this.mSolderingTool = true; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + super.addUIWidgets(builder, buildContext); + buildContext.addSyncedWindow(MACHINE_LIST_WINDOW_ID, this::createMachineListWindow); + buildContext.addSyncedWindow(CUSTOM_NAME_WINDOW_ID, this::createCustomNameWindow); + builder.widget(// Machine List + new ButtonWidget().setOnClick( + (clickData, widget) -> { + if (!widget.isClient()) widget.getContext() + .openSyncedWindow(MACHINE_LIST_WINDOW_ID); + }) + .setSize(16, 16) + .setBackground(() -> { + List<UITexture> UI = new ArrayList<>(); + UI.add(GT_UITextures.BUTTON_STANDARD); + UI.add(GT_UITextures.OVERLAY_BUTTON_WHITELIST); + return UI.toArray(new IDrawable[0]); + }) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.drone_open_list")) + .setPos(94, 91) + .setEnabled(var -> getBaseMetaTileEntity().isActive())) + .widget(// Turn on ALL machines + new ButtonWidget().setOnClick((clickData, widget) -> { + if (!widget.isClient()) { + if (!getBaseMetaTileEntity().isActive()) { + widget.getContext() + .getPlayer() + .addChatComponentMessage( + new ChatComponentTranslation("GT5U.machines.dronecentre.shutdown")); + return; + } + for (DroneConnection mte : connectionList) { + mte.machine.getBaseMetaTileEntity() + .enableWorking(); + } + widget.getContext() + .getPlayer() + .addChatComponentMessage(new ChatComponentTranslation("GT5U.machines.dronecentre.turnon")); + widget.getContext() + .getPlayer() + .closeScreen(); + } + }) + .setSize(16, 16) + .setBackground(() -> { + List<UITexture> UI = new ArrayList<>(); + UI.add(GT_UITextures.BUTTON_STANDARD); + UI.add(GT_UITextures.OVERLAY_BUTTON_POWER_SWITCH_ON); + return UI.toArray(new IDrawable[0]); + }) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.drone_poweron_all")) + .setPos(146, 91) + .setEnabled(var -> getBaseMetaTileEntity().isActive())) + .widget(// Turn off ALL machines + new ButtonWidget().setOnClick((clickData, widget) -> { + if (!widget.isClient()) { + if (!getBaseMetaTileEntity().isActive()) { + widget.getContext() + .getPlayer() + .addChatComponentMessage( + new ChatComponentTranslation("GT5U.machines.dronecentre.shutdown")); + return; + } + for (DroneConnection mte : connectionList) { + mte.machine.getBaseMetaTileEntity() + .disableWorking(); + } + widget.getContext() + .getPlayer() + .addChatComponentMessage(new ChatComponentTranslation("GT5U.machines.dronecentre.turnoff")); + widget.getContext() + .getPlayer() + .closeScreen(); + } + }) + .setSize(16, 16) + .setBackground(() -> { + List<UITexture> UI = new ArrayList<>(); + UI.add(GT_UITextures.BUTTON_STANDARD); + UI.add(GT_UITextures.OVERLAY_BUTTON_POWER_SWITCH_OFF); + return UI.toArray(new IDrawable[0]); + }) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.drone_poweroff_all")) + .setPos(120, 91) + .setEnabled(var -> getBaseMetaTileEntity().isActive())) + .widget(new FakeSyncWidget.ListSyncer<>(() -> connectionList, var1 -> { + connectionList.clear(); + connectionList.addAll(var1); + }, (buffer, j) -> { + try { + buffer.writeNBTTagCompoundToBuffer(j.transConnectionToNBT()); + } catch (IOException e) { + GT_Log.err.println(e.getCause()); + } + }, buffer -> { + try { + return new DroneConnection(buffer.readNBTTagCompoundFromBuffer()); + } catch (IOException e) { + GT_Log.err.println(e.getCause()); + } + return null; + })); + } + + protected ModularWindow createMachineListWindow(final EntityPlayer player) { + int heightCoff = getBaseMetaTileEntity().isServerSide() ? 0 + : Minecraft.getMinecraft().currentScreen.height - 40; + ModularWindow.Builder builder = ModularWindow.builder(260, heightCoff); + builder.setBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); + builder.setGuiTint(getGUIColorization()); + builder.widget( + ButtonWidget.closeWindowButton(true) + .setPos(245, 3)); + builder.widget( + new TextWidget(EnumChatFormatting.BOLD + StatCollector.translateToLocal("GT5U.gui.text.drone_title")) + .setScale(2) + .setTextAlignment(Alignment.Center) + .setPos(0, 10) + .setSize(260, 8)); + // SearchBar + builder.widget(new TextFieldWidget() { + + @Override + public void onRemoveFocus() { + super.onRemoveFocus(); + syncToServer(2, buffer -> {}); + } + + // Refresh + @Override + public void readOnServer(int id, PacketBuffer buf) { + switch (id) { + case 1 -> super.readOnServer(id, buf); + case 2 -> { + getContext().closeWindow(MACHINE_LIST_WINDOW_ID); + getContext().openSyncedWindow(MACHINE_LIST_WINDOW_ID); + } + } + } + }.setGetter(() -> searchFilter) + .setSetter(var -> searchFilter = var) + .setTextAlignment(Alignment.CenterLeft) + .setTextColor(Color.WHITE.dark(1)) + .setFocusOnGuiOpen(false) + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD_LIGHT_GRAY.withOffset(-1, -1, 2, 2)) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.text.drone_search")) + .setPos(50, 30) + .setSize(200, 16)) + // Sort button + .widget(new ButtonWidget() { + + @Override + public ClickResult onClick(int buttonId, boolean doubleClick) { + ClickResult result = super.onClick(buttonId, doubleClick); + syncToServer(2, buffer -> {}); + return result; + } + + @Override + public void readOnServer(int id, PacketBuffer buf) { + switch (id) { + case 1 -> super.readOnServer(id, buf); + case 2 -> { + getContext().closeWindow(MACHINE_LIST_WINDOW_ID); + getContext().openSyncedWindow(MACHINE_LIST_WINDOW_ID); + } + } + } + }.setOnClick((clickData, widget) -> { + switch (sort) { + case "name" -> sort = "distance"; + case "distance" -> sort = "error"; + case "error" -> sort = "name"; + } + }) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.drone_" + sort)) + .setBackground( + () -> new IDrawable[] { GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_SORTING_MODE }) + .setPos(10, 30) + .setSize(16, 16)) + .widget(new FakeSyncWidget.StringSyncer(() -> sort, var1 -> sort = var1)) + // Localized Button + .widget(new ButtonWidget() { + + @Override + public ClickResult onClick(int buttonId, boolean doubleClick) { + ClickResult result = super.onClick(buttonId, doubleClick); + syncToServer(2, buffer -> {}); + return result; + } + + @Override + public void readOnServer(int id, PacketBuffer buf) { + switch (id) { + case 1 -> super.readOnServer(id, buf); + case 2 -> { + getContext().closeWindow(MACHINE_LIST_WINDOW_ID); + getContext().openSyncedWindow(MACHINE_LIST_WINDOW_ID); + } + } + } + }.setOnClick((clickData, widget) -> showLocalizedName = !showLocalizedName) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.drone_showLocalName")) + .setBackground( + () -> new IDrawable[] { + showLocalizedName ? GT_UITextures.BUTTON_STANDARD_PRESSED : GT_UITextures.BUTTON_STANDARD, + GT_UITextures.OVERLAY_BUTTON_CYCLIC }) + .setPos(30, 30) + .setSize(16, 16)); + // Sort first + switch (sort) { + case "name" -> connectionList = connectionList.stream() + .sorted( + (o1, o2) -> Collator.getInstance(Locale.UK) + .compare(o1.getCustomName(false), o2.getCustomName(false))) + .collect(Collectors.toList()); + case "distance" -> connectionList = connectionList.stream() + .sorted(Comparator.comparing(DroneConnection::getDistanceSquared)) + .collect(Collectors.toList()); + case "error" -> connectionList = connectionList.stream() + .sorted( + Comparator.comparing(DroneConnection::isMachineShutdown) + .reversed() + .thenComparing(DroneConnection::getDistanceSquared)) + .collect(Collectors.toList()); + } + + Scrollable MachineContainer = new Scrollable().setVerticalScroll(); + int posY = 0; + for (int i = 0; i < connectionList.size(); i++) { + DroneConnection connection = connectionList.get(i); + if (!connection.customName.toLowerCase() + .contains(searchFilter.toLowerCase())) continue; + ItemStackHandler drawitem = new ItemStackHandler(1); + drawitem.setStackInSlot(0, connection.machineItem); + DynamicPositionedRow row = new DynamicPositionedRow().setSynced(false); + GT_MetaTileEntity_MultiBlockBase coreMachine = connection.machine; + int finalI = i; + row.widget( + SlotWidget.phantom(drawitem, 0) + .disableInteraction() + .setPos(0, 0)) + .widget(new ButtonWidget().setOnClick((clickData, widget) -> { + buttonID = finalI; + if (!widget.isClient()) widget.getContext() + .openSyncedWindow(CUSTOM_NAME_WINDOW_ID); + }) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.drone_setname")) + .setBackground( + () -> new IDrawable[] { GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_PRINT }) + .setSize(16, 16)); + // Client can't handle unloaded machines + row.widget( + new ButtonWidget().setOnClick( + (clickData, widget) -> Optional.ofNullable(coreMachine) + .ifPresent(machine -> { + if (!getBaseMetaTileEntity().isActive()) { + player.addChatComponentMessage( + new ChatComponentTranslation("GT5U.machines.dronecentre.shutdown")); + return; + } + if (machine.isAllowedToWork()) { + machine.disableWorking(); + } else { + machine.enableWorking(); + } + })) + .setPlayClickSoundResource( + () -> Optional.ofNullable(coreMachine) + .filter(GT_MetaTileEntity_MultiBlockBase::isAllowedToWork) + .map(var -> SoundResource.GUI_BUTTON_UP.resourceLocation) + .orElse(SoundResource.GUI_BUTTON_DOWN.resourceLocation)) + .setBackground( + () -> Optional.ofNullable(coreMachine) + .map( + machine -> machine.isAllowedToWork() + ? new IDrawable[] { GT_UITextures.BUTTON_STANDARD_PRESSED, + GT_UITextures.OVERLAY_BUTTON_POWER_SWITCH_ON } + : new IDrawable[] { GT_UITextures.BUTTON_STANDARD, + GT_UITextures.OVERLAY_BUTTON_POWER_SWITCH_OFF }) + .orElse(new IDrawable[] { GT_UITextures.OVERLAY_BUTTON_CROSS })) + .attachSyncer( + new FakeSyncWidget.BooleanSyncer( + () -> Optional.ofNullable(coreMachine) + .map(GT_MetaTileEntity_MultiBlockBase::isAllowedToWork) + .orElse(false), + var -> Optional.ofNullable(coreMachine) + .ifPresent(machine -> { + if (var) machine.enableWorking(); + else machine.disableWorking(); + })), + builder) + .addTooltip( + coreMachine != null ? StatCollector.translateToLocal("GT5U.gui.button.power_switch") + : StatCollector.translateToLocal("GT5U.gui.button.drone_outofrange")) + .setSize(16, 16)) + .widget(new ButtonWidget().setOnClick((clickData, widget) -> { + if (widget.isClient()) { + highlightMachine(player, connection.machineCoord); + player.closeScreen(); + } + }) + .addTooltip(StatCollector.translateToLocal("GT5U.gui.button.drone_highlight")) + .setBackground( + new IDrawable[] { GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_INVERT_REDSTONE }) + .setSize(16, 16)); + // Show the reason why the machine shutdown + row.widget( + new DrawableWidget().dynamicTooltip( + () -> Collections.singletonList( + Optional.ofNullable(coreMachine) + .map( + machine -> machine.getBaseMetaTileEntity() + .getLastShutDownReason() + .getDisplayString()) + .orElse(""))) + .setBackground(GT_UITextures.PICTURE_STALLED_ELECTRICITY) + .setSize(16, 16) + .setEnabled( + var -> coreMachine != null && coreMachine.shouldDisplayShutDownReason() + && !coreMachine.getBaseMetaTileEntity() + .isActive() + && GT_Utility.isStringValid( + coreMachine.getBaseMetaTileEntity() + .getLastShutDownReason() + .getDisplayString()) + && coreMachine.getBaseMetaTileEntity() + .wasShutdown()) + .attachSyncer( + new ShutDownReasonSyncer( + () -> Optional.ofNullable(coreMachine) + .map( + var -> coreMachine.getBaseMetaTileEntity() + .getLastShutDownReason()) + .orElse(ShutDownReasonRegistry.NONE), + reason -> Optional.ofNullable(coreMachine) + .ifPresent( + machine -> coreMachine.getBaseMetaTileEntity() + .setShutDownReason(reason))), + builder) + .attachSyncer( + new FakeSyncWidget.BooleanSyncer( + () -> Optional.ofNullable(coreMachine) + .map( + var -> coreMachine.getBaseMetaTileEntity() + .wasShutdown()) + .orElse(false), + wasShutDown -> Optional.ofNullable(coreMachine) + .ifPresent( + machine -> coreMachine.getBaseMetaTileEntity() + .setShutdownStatus(wasShutDown))), + builder)); + row.widget( + new TextWidget( + connectionList.get(i) + .getCustomName(showLocalizedName)).setTextAlignment(Alignment.CenterLeft) + .setPos(0, 4)); + MachineContainer.widget( + row.setAlignment(MainAxisAlignment.SPACE_BETWEEN) + .setSpace(4) + .setPos(0, posY)); + posY += 20; + } + return builder.widget( + MachineContainer.setPos(10, 50) + .setSize(240, heightCoff - 60)) + .setDraggable(false) + .build(); + } + + protected ModularWindow createCustomNameWindow(final EntityPlayer player) { + ModularWindow.Builder builder = ModularWindow.builder(150, 40); + builder.setBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); + builder.setGuiTint(getGUIColorization()); + return builder.widget( + ButtonWidget.closeWindowButton(true) + .setPos(135, 3)) + .widget( + new TextWidget(StatCollector.translateToLocal("GT5U.gui.text.drone_custom_name")) + .setTextAlignment(Alignment.Center) + .setPos(0, 5) + .setSize(150, 8)) + .widget(new TextFieldWidget() { + + @Override + public void onDestroy() { + if (isClient()) return; + getContext().closeWindow(MACHINE_LIST_WINDOW_ID); + getContext().openSyncedWindow(MACHINE_LIST_WINDOW_ID); + } + }.setGetter( + () -> connectionList.get(buttonID) + .getCustomName(false)) + .setSetter( + var -> connectionList.get(buttonID) + .setCustomName(var)) + .setTextAlignment(Alignment.CenterLeft) + .setTextColor(Color.WHITE.dark(1)) + .setFocusOnGuiOpen(true) + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD_LIGHT_GRAY.withOffset(-1, -1, 2, 2)) + .setPos(10, 16) + .setSize(130, 16)) + .build(); + } + + // Just like HIGHLIGHT_INTERFACE (and exactly from it) + private void highlightMachine(EntityPlayer player, ChunkCoordinates machineCoord) { + DimensionalCoord blockPos = new DimensionalCoord( + machineCoord.posX, + machineCoord.posY, + machineCoord.posZ, + player.dimension); + WorldCoord blockPos2 = new WorldCoord((int) player.posX, (int) player.posY, (int) player.posZ); + BlockPosHighlighter.highlightBlock( + blockPos, + System.currentTimeMillis() + 500 * WorldCoord.getTaxicabDistance(blockPos, blockPos2)); + } + + public static HashMultimap<Integer, GT_MetaTileEntity_DroneCentre> getCentreMap() { + return droneMap; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_Hatch_DroneDownLink.java b/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_Hatch_DroneDownLink.java new file mode 100644 index 0000000000..959b6874ba --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/drone/GT_MetaTileEntity_Hatch_DroneDownLink.java @@ -0,0 +1,340 @@ +package gregtech.common.tileentities.machines.multi.drone; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.stream.Collectors; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizon.structurelib.util.Vec3Impl; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Color; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; +import com.gtnewhorizons.modularui.common.widget.textfield.TextFieldWidget; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Textures; +import gregtech.api.gui.modularui.GT_UIInfos; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.IIconContainer; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.interfaces.tileentity.IMachineBlockUpdateable; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Maintenance; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.render.TextureFactory; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +public class GT_MetaTileEntity_Hatch_DroneDownLink extends GT_MetaTileEntity_Hatch_Maintenance { + + private Vec3Impl downlinkCoord; + private DroneConnection connection; + // This has to be existed for doing random damage. + private GT_MetaTileEntity_MultiBlockBase machine; + private static final IIconContainer moduleActive = new Textures.BlockIcons.CustomIcon( + "iconsets/OVERLAY_DRONE_MODULE_ACTIVE"); + + public GT_MetaTileEntity_Hatch_DroneDownLink(int aID, String aName, String aNameRegional, int aTier) { + super(aID, aName, aNameRegional, aTier); + } + + public GT_MetaTileEntity_Hatch_DroneDownLink(String aName, int aTier, String[] aDescription, + ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures, false); + } + + @Override + public String[] getDescription() { + return new String[] { "Built-in powerful navigation beacon!" }; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister aBlockIconRegister) { + super.registerIcons(aBlockIconRegister); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(moduleActive) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, TextureFactory.of(moduleActive) }; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Hatch_DroneDownLink( + this.mName, + this.mTier, + this.mDescriptionArray, + this.mTextures); + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + downlinkCoord = new Vec3Impl( + getBaseMetaTileEntity().getXCoord(), + getBaseMetaTileEntity().getYCoord(), + getBaseMetaTileEntity().getZCoord()); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + if (hasConnection()) { + if (connection.centre.getBaseMetaTileEntity() + .isActive()) { + doNormalMaintain(); + } else { + // Centre offline? ...do nothing. + // doRandomIssue(); + } + } else { + // If the connection invalid, set it to null. + // Find connection every 10 second + if (aTick % 200 == 0) { + connection = null; + tryFindConnection(); + // Let's have some "surprise". Sorry, surprise party is over. + // if (this.machine != null && this.machine.isValid()) { + // doRandomIssue(); + } + } + } + } + + private void doNormalMaintain() { + this.mWrench = this.mScrewdriver = this.mSoftHammer = this.mHardHammer = this.mCrowbar = this.mSolderingTool = true; + connection.machine.mWrench = connection.machine.mScrewdriver = connection.machine.mSoftHammer = connection.machine.mHardHammer = connection.machine.mCrowbar = connection.machine.mSolderingTool = true; + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side, + float aX, float aY, float aZ) { + if (aBaseMetaTileEntity.isClientSide()) return true; + if (side == aBaseMetaTileEntity.getFrontFacing()) { + if (aPlayer instanceof FakePlayer) return false; + if (connection == null || !connection.isValid()) { + aPlayer.addChatComponentMessage(new ChatComponentTranslation("GT5U.machines.dronecentre.noconnection")); + return false; + } + GT_UIInfos.openGTTileEntityUI(aBaseMetaTileEntity, aPlayer); + return true; + } + return false; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public void onRemoval() { + if (hasConnection()) connection.machine = null; + } + + private boolean hasConnection() { + if (connection == null) return false; + if (connection.isValid()) return true; + return connection.reCheckConnection(); + } + + /** + * Find a drone connection. This will search for all DC in the same dimension, then find one in range. + */ + private void tryFindConnection() { + if (GT_MetaTileEntity_DroneCentre.getCentreMap() + .containsKey(getBaseMetaTileEntity().getWorld().provider.dimensionId)) { + List<GT_MetaTileEntity_DroneCentre> target = GT_MetaTileEntity_DroneCentre.getCentreMap() + .get(getBaseMetaTileEntity().getWorld().provider.dimensionId) + .stream() + .collect(Collectors.toList()); + for (GT_MetaTileEntity_DroneCentre centre : target) { + if (centre.getCoords() + .withinDistance(this.downlinkCoord, centre.getRange()) + && centre.getBaseMetaTileEntity() + .isActive()) { + GT_MetaTileEntity_MultiBlockBase machine = tryFindCoreGTMultiBlock(); + if (machine != null && machine.isValid()) { + this.machine = machine; + connection = new DroneConnection(machine, centre); + connection.centre.getConnectionList() + .add(connection); + return; + } + } + } + } + } + + private void doRandomIssue() { + switch (getBaseMetaTileEntity().getRandomNumber(6)) { + case 0 -> machine.mWrench = !machine.mWrench; + case 1 -> machine.mScrewdriver = !machine.mScrewdriver; + case 2 -> machine.mSoftHammer = !machine.mSoftHammer; + case 3 -> machine.mCrowbar = !machine.mCrowbar; + case 4 -> machine.mSolderingTool = !connection.machine.mSolderingTool; + case 5 -> machine.mHardHammer = !connection.machine.mHardHammer; + } + } + + // Find mainframe. Mainly from a method in GT_API——This will cause performance issue! Do not call it frequently. + private GT_MetaTileEntity_MultiBlockBase tryFindCoreGTMultiBlock() { + Queue<ChunkCoordinates> tQueue = new LinkedList<>(); + Set<ChunkCoordinates> visited = new HashSet<>(80); + tQueue.add( + this.getBaseMetaTileEntity() + .getCoords()); + World world = this.getBaseMetaTileEntity() + .getWorld(); + while (!tQueue.isEmpty()) { + final ChunkCoordinates aCoords = tQueue.poll(); + final TileEntity tTileEntity; + final boolean isMachineBlock; + tTileEntity = world.getTileEntity(aCoords.posX, aCoords.posY, aCoords.posZ); + Block block = world.getBlock(aCoords.posX, aCoords.posY, aCoords.posZ); + // Plascrete block isn't registered as machineBlock, therefore we have to check it manually so that drone + // can work with cleanroom. + // Todo: loading cleanroom's config for other blocks + isMachineBlock = GregTech_API + .isMachineBlock(block, world.getBlockMetadata(aCoords.posX, aCoords.posY, aCoords.posZ)) + || (block == GregTech_API.sBlockReinforced + && world.getBlockMetadata(aCoords.posX, aCoords.posY, aCoords.posZ) == 2); + // See if the block itself is MultiBlock, also the one we need. + if (tTileEntity instanceof IGregTechTileEntity te + && te.getMetaTileEntity() instanceof GT_MetaTileEntity_MultiBlockBase mte) + if (mte.mMaintenanceHatches.contains(this)) return mte; + + // Now see if we should add the nearby blocks to the queue: + // 1) If we've visited less than 5 blocks, then yes + // 2) If the tile says we should recursively update (pipes don't, machine blocks do) + // 3) If the block at the coordinates is marked as a machine block + if (visited.size() < 5 + || (tTileEntity instanceof IMachineBlockUpdateable + && ((IMachineBlockUpdateable) tTileEntity).isMachineBlockUpdateRecursive()) + || isMachineBlock) { + ChunkCoordinates tCoords; + + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX + 1, aCoords.posY, aCoords.posZ))) + tQueue.add(tCoords); + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX - 1, aCoords.posY, aCoords.posZ))) + tQueue.add(tCoords); + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY + 1, aCoords.posZ))) + tQueue.add(tCoords); + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY - 1, aCoords.posZ))) + tQueue.add(tCoords); + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY, aCoords.posZ + 1))) + tQueue.add(tCoords); + if (visited.add(tCoords = new ChunkCoordinates(aCoords.posX, aCoords.posY, aCoords.posZ - 1))) + tQueue.add(tCoords); + } + } + return null; + } + + @Override + public boolean doesBindPlayerInventory() { + return false; + } + + @Override + public int getGUIWidth() { + return 150; + } + + @Override + public int getGUIHeight() { + return 40; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + builder.setBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); + builder.setGuiTint(getGUIColorization()); + builder.widget( + ButtonWidget.closeWindowButton(true) + .setPos(135, 3)) + .widget( + new TextWidget(StatCollector.translateToLocal("GT5U.gui.text.drone_custom_name")) + .setTextAlignment(Alignment.Center) + .setPos(0, 5) + .setSize(150, 8)) + .widget( + new TextFieldWidget().setGetter(() -> connection == null ? "" : connection.getCustomName(false)) + .setSetter(var -> { if (connection != null) connection.setCustomName(var); }) + .setTextAlignment(Alignment.CenterLeft) + .setTextColor(Color.WHITE.dark(1)) + .setFocusOnGuiOpen(true) + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD_LIGHT_GRAY.withOffset(-1, -1, 2, 2)) + .setPos(10, 16) + .setSize(130, 16)) + .build(); + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + super.getWailaNBTData(player, tile, tag, world, x, y, z); + tag.setBoolean("connection", connection == null); + if (connection != null) { + tag.setInteger("x", connection.centreCoord.posX); + tag.setInteger("y", connection.centreCoord.posY); + tag.setInteger("z", connection.centreCoord.posZ); + tag.setString("name", connection.customName); + } + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + NBTTagCompound tag = accessor.getNBTData(); + if (tag.getBoolean("connection")) { + currenttip + .add(EnumChatFormatting.RED + StatCollector.translateToLocal("GT5U.waila.drone_downlink.noConnection")); + } else { + currenttip.add( + EnumChatFormatting.AQUA + StatCollector.translateToLocal("GT5U.waila.drone_downlink.connection") + + tag.getInteger("x") + + " " + + tag.getInteger("y") + + " " + + tag.getInteger("z")); + currenttip.add(EnumChatFormatting.YELLOW + tag.getString("name")); + } + super.getWailaBody(itemStack, currenttip, accessor, config); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/AdvChemicalProcessor.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/AdvChemicalProcessor.java new file mode 100644 index 0000000000..87e986f941 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/AdvChemicalProcessor.java @@ -0,0 +1,508 @@ +package gregtech.common.tileentities.machines.multiblock; + +import static com.google.common.primitives.Ints.saturatedCast; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ENERGY_IN; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.FLUID_IN; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.FLUID_OUT; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ITEM_IN; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ITEM_OUT; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.NOTHING; +import static gregtech.api.util.GT_StructureUtilityMuTE.MOTOR_CASINGS; +import static gregtech.api.util.GT_StructureUtilityMuTE.ofMuTECasings; + +import java.util.ArrayList; +import java.util.HashSet; + +import javax.annotation.Nonnull; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.IFluidTank; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizon.structurelib.util.Vec3Impl; +import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Color; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.api.widget.IWidgetBuilder; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.MultiChildWidget; +import com.gtnewhorizons.modularui.common.widget.SlotGroup; +import com.gtnewhorizons.modularui.common.widget.TextWidget; +import com.gtnewhorizons.modularui.common.widget.textfield.NumericWidget; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.HeatingCoilLevel; +import gregtech.api.enums.Materials; +import gregtech.api.fluid.FluidTankGT; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.multitileentity.enums.GT_MultiTileCasing; +import gregtech.api.multitileentity.multiblock.base.ComplexParallelController; +import gregtech.api.multitileentity.multiblock.casing.Glasses; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_StructureUtility; +import gregtech.api.util.GT_StructureUtilityMuTE; +import gregtech.common.tileentities.machines.multiblock.logic.AdvChemicalProcessorProcessingLogic; + +public class AdvChemicalProcessor + extends ComplexParallelController<AdvChemicalProcessor, AdvChemicalProcessorProcessingLogic> { + + private static IStructureDefinition<AdvChemicalProcessor> STRUCTURE_DEFINITION = null; + protected static final String STRUCTURE_PIECE_T1 = "T1"; + protected static final String STRUCTURE_PIECE_T2 = "T2"; + protected static final String STRUCTURE_PIECE_T3 = "T3"; + protected static final String STRUCTURE_PIECE_T4 = "T4"; + protected static final String STRUCTURE_PIECE_T5_6 = "T5_6"; + protected static final String STRUCTURE_PIECE_T7_8 = "T7_8"; + protected static final Vec3Impl STRUCTURE_OFFSET_T1 = new Vec3Impl(3, 1, 0); + protected static final Vec3Impl STRUCTURE_OFFSET_T2 = new Vec3Impl(1, 4, -3); + protected static final Vec3Impl STRUCTURE_OFFSET_T3 = new Vec3Impl(8, 0, 5); + protected static final Vec3Impl STRUCTURE_OFFSET_T4 = new Vec3Impl(-14, 0, 0); + protected static final Vec3Impl STRUCTURE_OFFSET_T5 = new Vec3Impl(14, 0, -6); + protected static final Vec3Impl STRUCTURE_OFFSET_T6 = new Vec3Impl(-16, 0, 0); + protected static final Vec3Impl STRUCTURE_OFFSET_T7 = new Vec3Impl(16, 0, 15); + protected static final Vec3Impl STRUCTURE_OFFSET_T8 = new Vec3Impl(-16, 0, 0); + protected static final int PROCESS_WINDOW_BASE_ID = 100; + protected static final int ITEM_WHITELIST_SLOTS = 8; + protected static final int FLUID_WHITELIST_SLOTS = 8; + protected static final int MAX_PROCESSES = 8; + protected HeatingCoilLevel coilTier; + protected final ArrayList<HashSet<String>> processWhitelists = new ArrayList<>(MAX_PROCESSES); + protected final ArrayList<ItemStackHandler> processWhitelistInventoryHandlers = new ArrayList<>(MAX_PROCESSES); + protected final ArrayList<ArrayList<IFluidTank>> processFluidWhiteLists = new ArrayList<>(MAX_PROCESSES); + protected boolean wasWhitelistOpened = false; + + public AdvChemicalProcessor() { + super(); + for (int i = 0; i < MAX_PROCESSES; i++) { + processWhitelists.add(null); + processWhitelistInventoryHandlers.add(new ItemStackHandler(ITEM_WHITELIST_SLOTS)); + ArrayList<IFluidTank> processFluidTanks = new ArrayList<>(FLUID_WHITELIST_SLOTS); + for (int j = 0; j < FLUID_WHITELIST_SLOTS; j++) { + processFluidTanks.add(new FluidTankGT()); + } + processFluidWhiteLists.add(processFluidTanks); + } + setMaxComplexParallels(1, false); + } + + @Override + public void readMultiTileNBT(NBTTagCompound nbt) { + super.readMultiTileNBT(nbt); + setMaxComplexParallels(nbt.getInteger("processors"), false); + final NBTTagCompound processWhiteLists = nbt.getCompoundTag("whiteLists"); + long capacity = 1000; + if (nbt.hasKey(GT_Values.NBT.TANK_CAPACITY)) { + capacity = saturatedCast(nbt.getLong(GT_Values.NBT.TANK_CAPACITY)); + } + for (int i = 0; i < MAX_PROCESSES; i++) { + + if (processWhiteLists == null) { + continue; + } + + final NBTTagCompound itemList = processWhiteLists.getCompoundTag("items" + i); + if (itemList != null) { + processWhitelistInventoryHandlers.get(i) + .deserializeNBT(itemList); + } + final NBTTagList fluidList = processWhiteLists.getTagList("fluids" + i, Constants.NBT.TAG_COMPOUND); + + if (fluidList == null) { + continue; + } + + for (int j = 0; j < fluidList.tagCount(); j++) { + final NBTTagCompound fluid = fluidList.getCompoundTagAt(j); + + if (fluid == null) { + continue; + } + + short index = fluid.getShort("s"); + FluidStack fluidStack = FluidStack.loadFluidStackFromNBT(fluid); + if (fluidStack != null) { + processFluidWhiteLists.get(i) + .get(index) + .fill(fluidStack, true); + } + } + } + } + + @Override + public void writeMultiTileNBT(NBTTagCompound nbt) { + super.writeMultiTileNBT(nbt); + nbt.setInteger("processors", maxComplexParallels); + final NBTTagCompound processWhiteLists = new NBTTagCompound(); + for (int i = 0; i < MAX_PROCESSES; i++) { + processWhiteLists.setTag( + "items" + i, + processWhitelistInventoryHandlers.get(i) + .serializeNBT()); + final NBTTagList fluidList = new NBTTagList(); + for (int j = 0; j < FLUID_WHITELIST_SLOTS; j++) { + final FluidStack fluidStack = processFluidWhiteLists.get(i) + .get(j) + .getFluid(); + if (fluidStack != null) { + final NBTTagCompound tag = new NBTTagCompound(); + tag.setByte("s", (byte) j); + fluidStack.writeToNBT(tag); + fluidList.appendTag(tag); + } + } + processWhiteLists.setTag("fluids" + i, fluidList); + } + nbt.setTag("whiteLists", processWhiteLists); + } + + @Override + public short getCasingRegistryID() { + return GT_MultiTileCasing.Chemical.getRegistryId(); + } + + @Override + public int getCasingMeta() { + return GT_MultiTileCasing.Chemical.getId(); + } + + @Override + public GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Chemical Reactor") + .addInfo("Controller block for the Advanced Chemical Processor") + .addInfo("Does not lose efficiency when overclocked") + .addInfo("Accepts fluids instead of fluid cells") + .addInfo("Can do multiple different recipes at once") + .addInfo("By using the whitelist filter a recipe can push its output") + .addInfo("to a different recipes input to chain them") + .addInfo("Disclaimer: Still WIP - Use at your own risk") + .addInfo(GT_Values.Authorminecraft7771) + .addSeparator() + .beginStructureBlock(5, 3, 3, false) + .addController("Front center") + .addCasingInfoExactly("PTFE Pipe Machine Casing", 8, false) + .addCasingInfoExactly("Heating Coils", 3, true) + .addCasingInfoExactly("EV+ Glass", 3, true) + .addCasingInfoExactly("Motor Casing", 3, true) + .addCasingInfoExactly("Chemical Casing", 27, false) + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public Vec3Impl getStartingStructureOffset() { + return STRUCTURE_OFFSET_T1; + } + + @Override + public boolean checkMachine() { + setCoilTier(HeatingCoilLevel.None); + buildState.startBuilding(getStartingStructureOffset()); + if (!checkPiece(STRUCTURE_PIECE_T1, buildState.getCurrentOffset())) return buildState.failBuilding(); + if (maxComplexParallels > 1) { + buildState.addOffset(STRUCTURE_OFFSET_T2); + if (!checkPiece(STRUCTURE_PIECE_T2, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + if (maxComplexParallels > 2) { + buildState.addOffset(STRUCTURE_OFFSET_T3); + if (!checkPiece(STRUCTURE_PIECE_T3, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + if (maxComplexParallels > 3) { + buildState.addOffset(STRUCTURE_OFFSET_T4); + if (!checkPiece(STRUCTURE_PIECE_T4, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + if (maxComplexParallels > 4) { + buildState.addOffset(STRUCTURE_OFFSET_T5); + if (!checkPiece(STRUCTURE_PIECE_T5_6, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + if (maxComplexParallels > 5) { + buildState.addOffset(STRUCTURE_OFFSET_T6); + if (!checkPiece(STRUCTURE_PIECE_T5_6, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + if (maxComplexParallels > 6) { + buildState.addOffset(STRUCTURE_OFFSET_T7); + if (!checkPiece(STRUCTURE_PIECE_T7_8, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + if (maxComplexParallels > 7) { + buildState.addOffset(STRUCTURE_OFFSET_T8); + if (!checkPiece(STRUCTURE_PIECE_T7_8, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + buildState.stopBuilding(); + return super.checkMachine(); + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + buildState.startBuilding(getStartingStructureOffset()); + buildPiece(STRUCTURE_PIECE_T1, trigger, hintsOnly, buildState.getCurrentOffset()); + if (maxComplexParallels > 1) { + buildState.addOffset(STRUCTURE_OFFSET_T2); + buildPiece(STRUCTURE_PIECE_T2, trigger, hintsOnly, buildState.getCurrentOffset()); + } + if (maxComplexParallels > 2) { + buildState.addOffset(STRUCTURE_OFFSET_T3); + buildPiece(STRUCTURE_PIECE_T3, trigger, hintsOnly, buildState.getCurrentOffset()); + } + if (maxComplexParallels > 3) { + buildState.addOffset(STRUCTURE_OFFSET_T4); + buildPiece(STRUCTURE_PIECE_T4, trigger, hintsOnly, buildState.getCurrentOffset()); + } + if (maxComplexParallels > 4) { + buildState.addOffset(STRUCTURE_OFFSET_T5); + buildPiece(STRUCTURE_PIECE_T5_6, trigger, hintsOnly, buildState.getCurrentOffset()); + } + if (maxComplexParallels > 5) { + buildState.addOffset(STRUCTURE_OFFSET_T6); + buildPiece(STRUCTURE_PIECE_T5_6, trigger, hintsOnly, buildState.getCurrentOffset()); + } + if (maxComplexParallels > 6) { + buildState.addOffset(STRUCTURE_OFFSET_T7); + buildPiece(STRUCTURE_PIECE_T7_8, trigger, hintsOnly, buildState.getCurrentOffset()); + } + if (maxComplexParallels > 7) { + buildState.addOffset(STRUCTURE_OFFSET_T8); + buildPiece(STRUCTURE_PIECE_T7_8, trigger, hintsOnly, buildState.getCurrentOffset()); + } + + buildState.stopBuilding(); + } + + @Override + public IStructureDefinition<AdvChemicalProcessor> getStructureDefinition() { + if (STRUCTURE_DEFINITION == null) { + STRUCTURE_DEFINITION = StructureDefinition.<AdvChemicalProcessor>builder() + .addShape( + STRUCTURE_PIECE_T1, + transpose( + new String[][] { { "CPCPC", "CCCCC", "CPCPC" }, { "CGC~C", "GWWWU", "CGCCC" }, + { "CPCPC", "CTTTC", "CPCPC" } })) + .addShape( + STRUCTURE_PIECE_T2, + new String[][] { { " ", " ", " ", " ", " ", " F F ", " B B " }, + { " ", " ", " ", " ", " ", " F F ", " B B " }, + { " ", " ", " ", " ", " ", " F F ", " BBB " }, + { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, + { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, + { " CBBBC ", " G W G ", " G W G ", " G W G ", " G W G ", " G W G ", "BCPCPCB" }, + { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, + { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, + { " ", " ", " ", " ", " ", " ", " BBB " } }) + .addShape( + STRUCTURE_PIECE_T3, + new String[][] { + { " ", " ", " ", " ", " ", " ", " BBB " }, + { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, + { " BBB ", " C C ", " C C ", " C C ", " C C ", " C CFFF", "BCPPPCBBB" }, + { " CBBBC ", " G W G ", " G W G ", " G W G ", " G W G ", " G W G ", "BCPCPCB " }, + { " BBB ", " C C ", " C C ", " C C ", " C C ", " C CFFF", "BCPPPCBBB" }, + { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, + { " ", " ", " ", " ", " ", " ", " BBB " } }) + .addShape( + STRUCTURE_PIECE_T4, + new String[][] { + { " ", " ", " ", " ", " ", " ", " BBB " }, + { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, + { " BBB ", " C C ", " C C ", " C C ", " C C ", "FFFC C ", "BBBCPPPCB" }, + { " CBBBC ", " G W G ", " G W G ", " G W G ", " G W G ", " G W G ", " BCPCPCB" }, + { " BBB ", " C C ", " C C ", " C C ", " C C ", "FFFC C ", "BBBCPPPCB" }, + { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, + { " ", " ", " ", " ", " ", " ", " BBB " } }) + .addShape( + STRUCTURE_PIECE_T5_6, + new String[][] { { " ", " ", " ", " ", " ", " F F ", " " }, + { " ", " ", " ", " ", " ", " F F ", " B B " }, + { " ", " ", " ", " ", " ", " F F ", " B B " }, + { " ", " ", " ", " ", " ", " F F ", " BBB " }, + { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, + { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, + { " CBBBC ", " G W G ", " G W G ", " G W G ", " G W G ", " G W G ", "BCPCPCB" }, + { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, + { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, + { " ", " ", " ", " ", " ", " ", " BBB " } }) + .addShape( + STRUCTURE_PIECE_T7_8, + new String[][] { { " ", " ", " ", " ", " ", " ", " BBB " }, + { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, + { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, + { " CBBBC ", " G W G ", " G W G ", " G W G ", " G W G ", " G W G ", "BCPCPCB" }, + { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, + { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, + { " ", " ", " ", " ", " ", " F F ", " BBB " }, + { " ", " ", " ", " ", " ", " F F ", " B B " }, + { " ", " ", " ", " ", " ", " F F ", " B B " }, + { " ", " ", " ", " ", " ", " F F ", " " } }) + .addElement( + 'C', + ofMuTECasings( + FLUID_IN | ITEM_IN | FLUID_OUT | ITEM_OUT | ENERGY_IN, + GT_MultiTileCasing.Chemical.getCasing())) + .addElement('P', ofBlock(GregTech_API.sBlockCasings8, 1)) + .addElement('T', ofMuTECasings(NOTHING, MOTOR_CASINGS)) + .addElement( + 'W', + GT_StructureUtility.ofCoil(AdvChemicalProcessor::setCoilTier, AdvChemicalProcessor::getCoilTier)) + .addElement('G', Glasses.chainAllGlasses()) + .addElement('B', ofBlock(GregTech_API.sBlockCasings4, 1)) + .addElement('F', GT_StructureUtility.ofFrame(Materials.Steel)) + .addElement( + 'U', + ofMuTECasings( + FLUID_IN | ITEM_IN | FLUID_OUT | ITEM_OUT | ENERGY_IN, + GT_MultiTileCasing.Chemical.getCasing(), + GT_StructureUtilityMuTE.INVENTORY_CASINGS)) + .build(); + } + return STRUCTURE_DEFINITION; + } + + @Override + protected void setMaxComplexParallels(int parallel, boolean stopMachine) { + super.setMaxComplexParallels(parallel, stopMachine); + onStructureChange(); + } + + protected MultiChildWidget createMainPage(IWidgetBuilder<?> builder) { + MultiChildWidget child = new MultiChildWidget(); + for (int i = 0; i < MAX_PROCESSES; i++) { + final int processIndex = i; + child.addChild( + new ButtonWidget().setPlayClickSound(true) + .setOnClick( + (clickData, widget) -> { + if (!widget.isClient()) widget.getContext() + .openSyncedWindow(PROCESS_WINDOW_BASE_ID + processIndex); + }) + .setBackground(GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_WHITELIST) + .setSize(18, 18) + .setEnabled((widget -> processIndex < maxComplexParallels)) + .setPos(20 * (i % 4) + 18, 18 + (i / 4) * 20)); + } + child.addChild( + new NumericWidget().setGetter(() -> maxComplexParallels) + .setSetter(parallel -> setMaxComplexParallels((int) parallel, true)) + .setBounds(1, MAX_PROCESSES) + .setTextColor(Color.WHITE.normal) + .setTextAlignment(Alignment.Center) + .addTooltip("Tier") + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD) + .setSize(18, 18) + .setPos(130, 85)); + return child; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + super.addUIWidgets(builder, buildContext); + for (int i = 0; i < MAX_PROCESSES; i++) { + final int processIndex = i; + buildContext.addSyncedWindow( + PROCESS_WINDOW_BASE_ID + i, + (player) -> createProcessConfigWindow(player, processIndex)); + } + buildContext.addCloseListener(() -> { + // Reset HashSet, we will let it re-generate on next item output + if (wasWhitelistOpened) { + for (int i = 0; i < MAX_PROCESSES; i++) { + processWhitelists.set(i, null); + } + wasWhitelistOpened = false; + } + }); + } + + protected ModularWindow createProcessConfigWindow(final EntityPlayer player, final int processIndex) { + wasWhitelistOpened = true; + ModularWindow.Builder builder = ModularWindow.builder(86, 100); + builder.widget( + new TextWidget("Process " + processIndex).setTextAlignment(Alignment.Center) + .setPos(13, 7)); + builder.setBackground(GT_UITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); + builder.widget( + SlotGroup.ofItemHandler(processWhitelistInventoryHandlers.get(processIndex), 4) + .startFromSlot(0) + .endAtSlot(ITEM_WHITELIST_SLOTS - 1) + .phantom(true) + .background(getGUITextureSet().getItemSlot()) + .build() + .setPos(7, 19)); + builder.widget( + SlotGroup.ofFluidTanks(processFluidWhiteLists.get(processIndex), 4) + .startFromSlot(0) + .endAtSlot(FLUID_WHITELIST_SLOTS - 1) + .phantom(true) + .build() + .setPos(7, 55)); + return builder.build(); + } + + @Override + public String getTileEntityName() { + return "gt.multitileentity.multiblock.advchemicalprocessor"; + } + + @Override + public String getLocalName() { + return "Advanced Chemical Processor"; + } + + public void setCoilTier(HeatingCoilLevel coilTier) { + this.coilTier = coilTier; + } + + public HeatingCoilLevel getCoilTier() { + return coilTier; + } + + @Override + protected boolean hasPerfectOverclock() { + return true; + } + + protected void generateWhitelist(int processIndex) { + HashSet<String> whitelist = new HashSet<>(); + for (ItemStack itemStack : processWhitelistInventoryHandlers.get(processIndex) + .getStacks()) { + if (itemStack != null) { + whitelist.add(getWhitelistString(itemStack)); + } + } + for (IFluidTank tank : processFluidWhiteLists.get(processIndex)) { + if (tank.getFluid() != null) { + whitelist.add(getWhitelistString(tank.getFluid())); + } + } + processWhitelists.set(processIndex, whitelist); + } + + protected String getWhitelistString(ItemStack itemStack) { + if (itemStack != null) { + return itemStack.getUnlocalizedName(); + } + return null; + } + + protected String getWhitelistString(FluidStack fluidStack) { + if (fluidStack != null) { + return fluidStack.getUnlocalizedName(); + } + return null; + } + + @Override + @Nonnull + protected AdvChemicalProcessorProcessingLogic createProcessingLogic() { + return new AdvChemicalProcessorProcessingLogic(); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/CokeOven.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/CokeOven.java new file mode 100644 index 0000000000..06fc7b42b1 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/CokeOven.java @@ -0,0 +1,153 @@ +package gregtech.common.tileentities.machines.multiblock; + +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ITEM_IN; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ITEM_OUT; +import static gregtech.api.util.GT_StructureUtilityMuTE.ofMuTECasings; + +import java.util.List; + +import javax.annotation.Nonnull; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizon.structurelib.util.Vec3Impl; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.common.internal.network.NetworkUtils; +import com.gtnewhorizons.modularui.common.widget.DrawableWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import gregtech.GT_Mod; +import gregtech.api.enums.GT_Values; +import gregtech.api.multitileentity.enums.GT_MultiTileCasing; +import gregtech.api.multitileentity.multiblock.base.Controller; +import gregtech.api.task.tasks.PollutionTask; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.common.tileentities.machines.multiblock.logic.CokeOvenProcessingLogic; + +public class CokeOven extends Controller<CokeOven, CokeOvenProcessingLogic> { + + private static IStructureDefinition<CokeOven> STRUCTURE_DEFINITION = null; + private static final Vec3Impl OFFSET = new Vec3Impl(1, 1, 0); + private static final String MAIN = "Main"; + private static final int POLLUTION_AMOUNT = 10; + + public CokeOven() { + super(); + setElectric(false); + new PollutionTask<>(this).setPollutionPerSecond(POLLUTION_AMOUNT); + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + buildState.startBuilding(getStartingStructureOffset()); + buildPiece(MAIN, trigger, hintsOnly, buildState.stopBuilding()); + } + + @Override + public boolean checkMachine() { + buildState.startBuilding(getStartingStructureOffset()); + return checkPiece(MAIN, buildState.stopBuilding()); + } + + @Override + public int survivalConstruct(ItemStack trigger, int elementBudget, ISurvivalBuildEnvironment env) { + buildState.startBuilding(getStartingStructureOffset()); + return survivalBuildPiece(MAIN, trigger, buildState.stopBuilding(), elementBudget, env, false); + } + + @Override + public short getCasingRegistryID() { + return 0; + } + + @Override + public int getCasingMeta() { + return GT_MultiTileCasing.CokeOven.getId(); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Coke Oven") + .addInfo("Used for charcoal") + .beginStructureBlock(3, 3, 3, true) + .addCasingInfoExactly("Coke Oven Bricks", 25, false) + .addPollutionAmount(POLLUTION_AMOUNT) + .toolTipFinisher(GT_Values.AuthorBlueWeabo); + return tt; + } + + @Override + public Vec3Impl getStartingStructureOffset() { + return OFFSET; + } + + @Override + public IStructureDefinition<CokeOven> getStructureDefinition() { + if (STRUCTURE_DEFINITION == null) { + STRUCTURE_DEFINITION = StructureDefinition.<CokeOven>builder() + .addShape( + MAIN, + new String[][] { { "AAA", "A~A", "AAA" }, { "AAA", "A-A", "AAA" }, { "AAA", "AAA", "AAA" } }) + .addElement('A', ofMuTECasings(ITEM_IN | ITEM_OUT, GT_MultiTileCasing.CokeOven.getCasing())) + .build(); + } + return STRUCTURE_DEFINITION; + } + + @Override + public boolean hasFluidInput() { + return false; + } + + @Override + protected void addTitleTextStyle(ModularWindow.Builder builder, String title) { + final int TAB_PADDING = 3; + final int TITLE_PADDING = 2; + int titleWidth = 0, titleHeight = 0; + if (NetworkUtils.isClient()) { + final FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + final List<String> titleLines = fontRenderer + .listFormattedStringToWidth(title, getGUIWidth() - (TAB_PADDING + TITLE_PADDING) * 2); + titleWidth = titleLines.size() > 1 ? getGUIWidth() - (TAB_PADDING + TITLE_PADDING) * 2 + : fontRenderer.getStringWidth(title); + titleHeight = titleLines.size() * fontRenderer.FONT_HEIGHT + (titleLines.size() - 1); + } + + final DrawableWidget tab = new DrawableWidget(); + final TextWidget text = new TextWidget(title).setDefaultColor(getTitleColor()) + .setTextAlignment(Alignment.CenterLeft) + .setMaxWidth(titleWidth); + if (GT_Mod.gregtechproxy.mTitleTabStyle == 1) { + tab.setDrawable(getGUITextureSet().getTitleTabAngular()) + .setPos(0, -(titleHeight + TAB_PADDING) + 1) + .setSize(getGUIWidth(), titleHeight + TAB_PADDING * 2); + text.setPos(TAB_PADDING + TITLE_PADDING, -titleHeight + TAB_PADDING); + } else { + tab.setDrawable(getGUITextureSet().getTitleTabDark()) + .setPos(0, -(titleHeight + TAB_PADDING * 2) + 1) + .setSize(titleWidth + (TAB_PADDING + TITLE_PADDING) * 2, titleHeight + TAB_PADDING * 2 - 1); + text.setPos(TAB_PADDING + TITLE_PADDING, -titleHeight); + } + builder.widget(tab) + .widget(text); + } + + @Override + public String getLocalName() { + return StatCollector.translateToLocal("gt.multiBlock.controller.cokeOven"); + } + + @Override + @Nonnull + protected CokeOvenProcessingLogic createProcessingLogic() { + return new CokeOvenProcessingLogic(); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/DistillationTower.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/DistillationTower.java new file mode 100644 index 0000000000..326bfcc9ee --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/DistillationTower.java @@ -0,0 +1,174 @@ +package gregtech.common.tileentities.machines.multiblock; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.*; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.*; +import static gregtech.api.util.GT_StructureUtilityMuTE.MOTOR_CASINGS; +import static gregtech.api.util.GT_StructureUtilityMuTE.ofMuTECasings; + +import javax.annotation.Nonnull; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizon.structurelib.util.Vec3Impl; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.HeatingCoilLevel; +import gregtech.api.enums.Materials; +import gregtech.api.multitileentity.enums.GT_MultiTileCasing; +import gregtech.api.multitileentity.multiblock.base.StackableController; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_StructureUtility; +import gregtech.common.tileentities.machines.multiblock.logic.DistillationTowerProcessingLogic; + +public class DistillationTower extends StackableController<DistillationTower, DistillationTowerProcessingLogic> { + + private static IStructureDefinition<DistillationTower> STRUCTURE_DEFINITION_MEGA = null; + private static final Vec3Impl STRUCTURE_OFFSET_MEGA = new Vec3Impl(8, 3, 0); + private static final Vec3Impl STRUCTURE_OFFSET_MEGA_START = new Vec3Impl(0, 3, 0); + private static final Vec3Impl STRUCTURE_OFFSET_MEGA_STOP = new Vec3Impl(0, 5, 0); + private static final Vec3Impl STRUCTURE_OFFSET_MEGA_STACK = new Vec3Impl(0, 3, 0); + private static final String STACKABLE_MIDDLE_1 = "STACKABLE_MIDDLE_1"; + private static final String STACKABLE_MIDDLE_2 = "STACKABLE_MIDDLE_2"; + private boolean isMega = true; + + @Override + public short getCasingRegistryID() { + return 0; + } + + @Override + public int getCasingMeta() { + return GT_MultiTileCasing.Distillation.getId(); + } + + @Override + public GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Distillation Tower") + .addInfo("Controller block for the Distillation Tower") + .addInfo("Can be specialised to be a mega structure") + .addInfo(GT_Values.Authorminecraft7771) + .addSeparator() + .beginStructureBlock(5, 3, 3, false) + .addController("Front center") + .toolTipFinisher("Gregtech"); + return tt; + } + + @Override + public Vec3Impl getStartingStructureOffset() { + return STRUCTURE_OFFSET_MEGA; + } + + @Override + public IStructureDefinition<DistillationTower> getStructureDefinition() { + if (STRUCTURE_DEFINITION_MEGA == null) { + STRUCTURE_DEFINITION_MEGA = StructureDefinition.<DistillationTower>builder() + .addShape( + STACKABLE_START, + transpose( + // spotless:off + new String[][]{ + {" "," "," "," "," "," ECCCCCE "," CCCCCCC "," C C "," EC CE "," CC CC "," CC CC ABA "," CC CC B B "," CC CC ABA "," CC CC "," EC CE "," C C "," CCCCCCC "," ECCCCCE "," "}, + {" "," EEE "," E "," E "," E "," E E E "," CCCCCCC "," C C "," EC CE "," C C "," C C ABA "," C C B B "," C C ABA "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + {" CCCCC "," CCCCC "," CCCCC "," "," "," E E "," CCCCCCC "," C C "," EC CE "," C C "," C C ABA "," C C B B "," C C ABA "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + {" CXC~C "," BDDDB "," CBCBC "," B B "," B B "," E B B E "," CCCCCCC "," C C "," EC CE "," C C "," C C AAA "," C C A A "," C C AAA "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + {" CCCCC "," CCCCC "," CCCCC "," "," CCCCCCCCCCC "," CAAAAAAAAAC ","CCCACCCCCCCACCC ","CAACAAAAAAACAAC ","CACAADDDDDAACAC ","CACADDDDDDDACACCCCC","CACADDAAADDACACCCCC","CACADDAAADDACACCCCC","CACADDAAADDACACCCCC","CACADDDDDDDACACCCCC","CACAADDDDDAACAC ","CAACAAAAAAACAAC ","CCCACCCCCCCACCC "," CAAAAAAAAAC "," CCCCCCCCCCC "} + })) + .addShape( + STACKABLE_STOP, + transpose( + new String[][]{ + {" "," "," "," "," "," "," "," "," "," "," CCC "," CCC "," CCC "," "," "," "," "," "," "}, + {" "," "," "," "," "," E E "," E E "," E E "," EEEEAAAAAEEEE "," AAAAAAA "," AA AA "," AA AA "," AA AA "," AAAAAAA "," EEEEAAAAAEEEE "," E E "," E E "," E E "," "}, + {" "," "," "," "," "," ECCCCCE "," CCCCCCCCC "," CCCCCCCCCCC "," ECCC CCCE "," CCC CCC "," CCC CCC "," CCC CCC "," CCC CCC "," CCC CCC "," ECCC CCCE "," CCCCCCCCCCC "," CCCCCCCCC "," ECCCCCE "," "}, + {" "," "," "," "," "," E E "," CCCCCCC "," C C "," EC CE "," C C "," C C "," C C "," C C "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + {" "," "," "," "," "," E E "," CCCCCCC "," C C "," EC CE "," C C "," C CAAAAA "," C CABBBA "," C CAAAAA "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + {" "," "," "," "," "," ECCCCCE "," CCCCCCC "," C C "," EC CE "," CC CC "," CC CABBBA "," CC C B "," CC CABBBA "," CC CC "," EC CE "," C C "," CCCCCCC "," ECCCCCE "," "}, + {" "," "," "," "," "," E E "," CCCCCCC "," C C "," EC CE "," C C "," C CAAABA "," C CAAA B "," C CAAABA "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + {" "," "," "," "," "," E E "," CCCCCCC "," C C "," EC CE "," C C "," C C ABA "," C C A B "," C C ABA "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + })) + .addShape( + STACKABLE_MIDDLE_1, + transpose( + new String[][]{ + {" "," "," "," "," "," E E "," CCCCCCC "," C C "," EC CE "," C C "," C C ABA "," C C B B "," C C ABA "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + {" "," "," "," "," "," E E "," CCCCCCC "," C C "," EC CE "," C C "," C C ABA "," C C B B "," C C ABA "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + {" "," "," "," "," "," E E "," CCCCCCC "," C C "," EC CE "," C C "," C C ABA "," C C B B "," C C ABA "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + })) + .addShape( + STACKABLE_MIDDLE_2, + transpose( + new String[][]{ + {" "," "," "," "," "," ECCCCCE "," CCCCCCC "," C C "," EC CE "," CC CC "," CC CC ABA "," CC CC B B "," CC CC ABA "," CC CC "," EC CE "," C C "," CCCCCCC "," ECCCCCE "," "}, + {" "," "," "," "," "," E E "," CCCCCCC "," C C "," EC CE "," C C "," C C ABA "," C C B B "," C C ABA "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + {" "," "," "," "," "," E E "," CCCCCCC "," C C "," EC CE "," C C "," C C ABA "," C C B B "," C C ABA "," C C "," EC CE "," C C "," CCCCCCC "," E E "," "}, + })) + // spotless:on + .addElement( + 'C', + ofMuTECasings( + FLUID_IN | ITEM_IN | FLUID_OUT | ITEM_OUT | ENERGY_IN, + GT_MultiTileCasing.Distillation.getCasing())) + .addElement('E', GT_StructureUtility.ofFrame(Materials.StainlessSteel)) + .addElement('A', ofBlock(GregTech_API.sBlockCasings2, 0)) + .addElement('B', ofBlock(GregTech_API.sBlockCasings2, 13)) + .addElement('X', ofMuTECasings(NOTHING, MOTOR_CASINGS)) + .addElement('D', GT_StructureUtility.ofCoil((tile, meta) -> {}, (tile) -> HeatingCoilLevel.None)) + .build(); + } + return STRUCTURE_DEFINITION_MEGA; + } + + @Override + public int getFluidOutputCount() { + return 12; + } + + @Override + public int getMinStacks() { + return 0; + } + + @Override + public int getMaxStacks() { + return 9; + } + + @Override + public Vec3Impl getStartingStackOffset() { + return STRUCTURE_OFFSET_MEGA_START; + } + + @Override + public Vec3Impl getPerStackOffset() { + return STRUCTURE_OFFSET_MEGA_STACK; + } + + @Override + public Vec3Impl getAfterLastStackOffset() { + return STRUCTURE_OFFSET_MEGA_STOP; + } + + @Override + public String getTileEntityName() { + return "gt.multitileentity.multiblock.distillationtower"; + } + + @Override + public String getLocalName() { + return "Distillation Tower"; + } + + @Override + protected String getStackableMiddle(int stackIndex) { + return stackIndex % 2 == 0 ? STACKABLE_MIDDLE_1 : STACKABLE_MIDDLE_2; + } + + @Override + @Nonnull + protected DistillationTowerProcessingLogic createProcessingLogic() { + return new DistillationTowerProcessingLogic(); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/LaserEngraver.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/LaserEngraver.java new file mode 100644 index 0000000000..d4a7283f3e --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/LaserEngraver.java @@ -0,0 +1,305 @@ +package gregtech.common.tileentities.machines.multiblock; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.*; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlockUnlocalizedName; +import static gregtech.api.enums.Mods.*; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.*; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ENERGY_IN; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.FLUID_OUT; +import static gregtech.api.util.GT_StructureUtilityMuTE.*; + +import java.util.UUID; + +import javax.annotation.Nonnull; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizon.structurelib.util.Vec3Impl; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Color; +import com.gtnewhorizons.modularui.api.widget.IWidgetBuilder; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.MultiChildWidget; +import com.gtnewhorizons.modularui.common.widget.textfield.NumericWidget; + +import gregtech.api.GregTech_API; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.Materials; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.multitileentity.enums.GT_MultiTileCasing; +import gregtech.api.multitileentity.multiblock.base.ComplexParallelController; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_StructureUtility; +import gregtech.common.tileentities.machines.multiblock.logic.LaserEngraverProcessingLogic; + +public class LaserEngraver extends ComplexParallelController<LaserEngraver, LaserEngraverProcessingLogic> { + + private static IStructureDefinition<LaserEngraver> STRUCTURE_DEFINITION = null; + protected static final String STRUCTURE_MAIN = "Main"; + protected static final String STRUCTURE_PIECE_T1 = "T1"; + protected static final String STRUCTURE_PIECE_T2 = "T2"; + protected static final String STRUCTURE_PIECE_T3 = "T3"; + protected static final String STRUCTURE_PIECE_T4 = "T4"; + protected static final String STRUCTURE_PIECE_T5 = "T5"; + protected static final String STRUCTURE_PIECE_T6 = "T6"; + protected static final int PROCESS_WINDOW_BASE_ID = 100; + protected static final Vec3Impl STRUCTURE_OFFSET_T1 = new Vec3Impl(3, 1, 0); + protected static final Vec3Impl STRUCTURE_OFFSET_T2 = new Vec3Impl(1, 3, 0); + protected static final Vec3Impl STRUCTURE_OFFSET_T3 = new Vec3Impl(-6, 0, -5); + protected static final Vec3Impl STRUCTURE_OFFSET_T4 = new Vec3Impl(18, 0, 0); + protected static final Vec3Impl STRUCTURE_OFFSET_T5 = new Vec3Impl(-18, 0, 9); + protected static final Vec3Impl STRUCTURE_OFFSET_T6 = new Vec3Impl(18, 0, 0); + protected static final int MAX_PROCESSES = 6; + protected RecipeMap<?> recipeMap; + private UUID LaserEngraver; + + @Override + public String getTileEntityName() { + return "gt.multitileentity.multiblock.laserengraver"; + } + + @Override + public Vec3Impl getStartingStructureOffset() { + return STRUCTURE_OFFSET_T1; + } + + @Override + public boolean checkMachine() { + buildState.startBuilding(getStartingStructureOffset()); + if (!checkPiece(STRUCTURE_PIECE_T1, buildState.getCurrentOffset())) return buildState.failBuilding(); + if (maxComplexParallels > 1) { + buildState.addOffset(STRUCTURE_OFFSET_T2); + if (!checkPiece(STRUCTURE_PIECE_T2, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + if (maxComplexParallels > 2) { + buildState.addOffset(STRUCTURE_OFFSET_T3); + if (!checkPiece(STRUCTURE_PIECE_T3, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + if (maxComplexParallels > 3) { + buildState.addOffset(STRUCTURE_OFFSET_T4); + if (!checkPiece(STRUCTURE_PIECE_T4, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + if (maxComplexParallels > 4) { + buildState.addOffset(STRUCTURE_OFFSET_T5); + if (!checkPiece(STRUCTURE_PIECE_T5, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + if (maxComplexParallels > 5) { + buildState.addOffset(STRUCTURE_OFFSET_T6); + if (!checkPiece(STRUCTURE_PIECE_T6, buildState.getCurrentOffset())) return buildState.failBuilding(); + } + buildState.stopBuilding(); + return super.checkMachine(); + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + buildState.startBuilding(getStartingStructureOffset()); + buildPiece(STRUCTURE_PIECE_T1, trigger, hintsOnly, buildState.getCurrentOffset()); + if (maxComplexParallels > 1) { + buildState.addOffset(STRUCTURE_OFFSET_T2); + buildPiece(STRUCTURE_PIECE_T2, trigger, hintsOnly, buildState.getCurrentOffset()); + } + if (maxComplexParallels > 2) { + buildState.addOffset(STRUCTURE_OFFSET_T3); + buildPiece(STRUCTURE_PIECE_T3, trigger, hintsOnly, buildState.getCurrentOffset()); + } + if (maxComplexParallels > 3) { + buildState.addOffset(STRUCTURE_OFFSET_T4); + buildPiece(STRUCTURE_PIECE_T4, trigger, hintsOnly, buildState.getCurrentOffset()); + } + if (maxComplexParallels > 4) { + buildState.addOffset(STRUCTURE_OFFSET_T5); + buildPiece(STRUCTURE_PIECE_T5, trigger, hintsOnly, buildState.getCurrentOffset()); + } + if (maxComplexParallels > 5) { + buildState.addOffset(STRUCTURE_OFFSET_T6); + buildPiece(STRUCTURE_PIECE_T6, trigger, hintsOnly, buildState.getCurrentOffset()); + } + buildState.stopBuilding(); + } + + @Override + public IStructureDefinition<LaserEngraver> getStructureDefinition() { + if (STRUCTURE_DEFINITION == null) { + STRUCTURE_DEFINITION = StructureDefinition.<LaserEngraver>builder() + .addShape( + STRUCTURE_PIECE_T1, + transpose( + // spotless:off + new String[][]{{"ACADA", "AAAAA", "AAAAA"}, {"GGA~A", "H I", "GGAAA"}, + {"AAAAA", "ABBBA", "AAAAA"}})) + .addShape( + STRUCTURE_PIECE_T2, + new String[][]{{" ", " ", " ", " ", " ", " "}, + {" K ", " K ", " K ", " ", " ", " "}, + {" K ", " ", " ", " ", " ", " "}, + {" K ", " ", " ", " ", " ", " "}, + {" K ", " ", " ", " ", " ", " "}, + {" K ", "FBF FBF", " G G ", " G G ", " G G ", "FBF FBF"}, + {" KKKKK ", "BIB BIB", "G G G G", "G G G G", "G G G G", "BHB BHB"}, + {" K K ", "FBF FBF", " G G ", " G G ", " G G ", "FBF FBF"}, + {" K K ", " ", " ", " ", " ", " "}, + {" K K ", "FBF FBF", " G G ", " G G ", " G G ", "FBF FBF"}, + {" KKKKK ", "BIB BIB", "G G G G", "G G G G", "G G G G", "BHB BHB"}, + {" ", "FBF FBF", " G G ", " G G ", " G G ", "FBF FBF",}}) + .addShape( + STRUCTURE_PIECE_T3, + new String[][]{ + {" ", " BBBBB FBF ", " BGGGB G ", " BGGGB G ", " BMLMB G ", " BBBBB FBF "}, + {" KKKKKKK ", " BBAAABB BIB ", " B B G G ", " B B G G ", " B B G G ", " BBBBBBB BHB "}, + {" K ", " BABBBAB FBF ", " G G G ", " G G G ", " M HHH M G ", " BBBBBBB FBF "}, + {"KKKKKK ", " BABIBAB ", " G G ", " G G ", " L HHH L ", " BBBBBBB "}, + {" K ", " BABBBAB FBF ", " G G G ", " G G G ", " M HHH M G ", " BBBBBBB FBF "}, + {" KKKKKKK ", " BBAAABB BIB ", " B B G G ", " B B G G ", " B B G G ", " BBBBBBB BHB "}, + {" ", " BBBBB FBF ", " BGGGB G ", " BGGGB G ", " BMLMB G ", " BBBBB FBF "}}) + .addShape( + STRUCTURE_PIECE_T4, + new String[][]{ + {" ", "FBF BBBBB ", " G BGGGB ", " G BGGGB ", " G BNLNB ", "FBF BBBBB "}, + {" KKKKKKK ", "BIB BBAAABB ", "G G B B ", "G G B B ", "G G B B ", "BHB BBBBBBB "}, + {" K ", "FBF BABBBAB ", " G G G ", " G G G ", " G N HHH N ", "FBF BBBBBBB "}, + {" KKKKKK", " BABIBAB ", " G G ", " G G ", " L HHH L ", " BBBBBBB "}, + {" K ", "FBF BABBBAB ", " G G G ", " G G G ", " G N HHH N ", "FBF BBBBBBB "}, + {" KKKKKKK ", "BIB BBAAABB ", "G G B B ", "G G B B ", "G G B B ", "BHB BBBBBBB "}, + {" ", "FBF BBBBB ", " G BGGGB ", " G BGGGB ", " G BNLNB ", "FBF BBBBB "}}) + .addShape( + STRUCTURE_PIECE_T5, + new String[][]{ + {" ", " BBBBB FBF ", " BGGGB G ", " BGGGB G ", " BOLOB G ", " BBBBB FBF "}, + {" KKKKKKK ", " BBAAABB BIB ", " B B G G ", " B B G G ", " B B G G ", " BBBBBBB BHB "}, + {" K ", " BABBBAB FBF ", " G G G ", " G G G ", " O HHH O G ", " BBBBBBB FBF "}, + {" K ", " BABIBAB ", " G G ", " G G ", " L HHH L ", " BBBBBBB "}, + {" K ", " BABBBAB FBF ", " G G G ", " G G G ", " O HHH O G ", " BBBBBBB FBF "}, + {" KKKKKKK ", " BBAAABB BIB ", " B B G G ", " B B G G ", " B B G G ", " BBBBBBB BHB "}, + {" K ", " BBBBB FBF ", " BGGGB G ", " BGGGB G ", " BOLOB G ", " BBBBB FBF "}, + {" K ", " ", " ", " ", " "}, + {" K ", " ", " ", " ", " "}, + {" K ", " ", " ", " ", " "}}) + .addShape( + STRUCTURE_PIECE_T6, + new String[][]{ + {" ", "FBF BBBBB ", " G BGGGB ", " G BGGGB ", " G BPLPB ", "FBF BBBBB "}, + {" KKKKKKK ", "BIB BBAAABB ", "G G B B ", "G G B B ", "G G B B ", "BHB BBBBBBB "}, + {" K ", "FBF BABBBAB ", " G G G ", " G G G ", " G P HHH P ", "FBF BBBBBBB "}, + {" K ", " BABIBAB ", " G G ", " G G ", " L HHH L ", " BBBBBBB "}, + {" K ", "FBF BABBBAB ", " G G G ", " G G G ", " G P HHH P ", "FBF BBBBBBB "}, + {" KKKKKKK ", "BIB BBAAABB ", "G G B B ", "G G B B ", "G G B B ", "BHB BBBBBBB "}, + {" K ", "FBF BBBBB ", " G BGGGB ", " G BGGGB ", " G BPLPB ", "FBF BBBBB "}, + {" K ", " ", " ", " ", " "}, + {" K ", " ", " ", " ", " "}, + {" K ", " ", " ", " ", " "}}) + // spotless:on + .addElement( + 'A', + ofMuTECasings( + FLUID_IN | ITEM_IN | FLUID_OUT | ITEM_OUT | ENERGY_IN, + GT_MultiTileCasing.LaserEngraver.getCasing())) + .addElement( + 'B', + ofMuTECasings( + FLUID_IN | ITEM_IN | FLUID_OUT | ITEM_OUT | ENERGY_IN, + GT_MultiTileCasing.BlackLaserEngraverCasing.getCasing())) + .addElement( + 'C', + ofMuTECasings(NOTHING, CLEANROOM_CASINGS, GT_MultiTileCasing.LaserEngraver.getCasing())) + .addElement('D', ofMuTECasings(NOTHING, WIRELESS_CASINGS, GT_MultiTileCasing.LaserEngraver.getCasing())) + .addElement('E', ofMuTECasings(NOTHING, MOTOR_CASINGS)) + .addElement('F', GT_StructureUtility.ofFrame(Materials.Naquadah) + + ) + .addElement('H', ofMuTECasings(NOTHING, GT_MultiTileCasing.Mirror.getCasing())) + + .addElement( + 'G', + ofChain( + ofBlockUnlocalizedName(IndustrialCraft2.ID, "blockAlloyGlass", 0, true), + ofBlockUnlocalizedName(BartWorks.ID, "BW_GlasBlocks", 0, true), + ofBlockUnlocalizedName(BartWorks.ID, "BW_GlasBlocks2", 0, true), + ofBlockUnlocalizedName(Thaumcraft.ID, "blockCosmeticOpaque", 2, false))) + .addElement('I', ofMuTECasings(NOTHING, EMITTER_CASINGS)) + .addElement('K', ofBlock(GregTech_API.sBlockCasings3, 11)) + .addElement('L', ofMuTECasings(NOTHING, ROBOT_ARM_CASINGS)) + .addElement('M', ofMuTECasings(NOTHING, GT_MultiTileCasing.LaserEngraverUpgrade1.getCasing())) + .addElement('N', ofMuTECasings(NOTHING, GT_MultiTileCasing.LaserEngraverUpgrade2.getCasing())) + .addElement('O', ofMuTECasings(NOTHING, GT_MultiTileCasing.LaserEngraverUpgrade3.getCasing())) + .addElement('P', ofMuTECasings(NOTHING, GT_MultiTileCasing.LaserEngraverUpgrade4.getCasing())) + .build(); + buildState.stopBuilding(); + } + return STRUCTURE_DEFINITION; + } + + protected MultiChildWidget createMainPage(IWidgetBuilder<?> builder) { + MultiChildWidget child = new MultiChildWidget(); + for (int i = 0; i < MAX_PROCESSES; i++) { + final int processIndex = i; + child.addChild( + new ButtonWidget().setPlayClickSound(true) + .setOnClick( + (clickData, widget) -> { + if (!widget.isClient()) widget.getContext() + .openSyncedWindow(PROCESS_WINDOW_BASE_ID + processIndex); + }) + .setBackground(GT_UITextures.BUTTON_STANDARD, GT_UITextures.OVERLAY_BUTTON_WHITELIST) + .setSize(18, 18) + .setEnabled((widget -> processIndex < maxComplexParallels)) + .setPos(20 * (i % 4) + 18, 18 + (i / 4) * 20)); + } + child.addChild( + new NumericWidget().setGetter(() -> maxComplexParallels) + .setSetter(parallel -> setMaxComplexParallels((int) parallel, true)) + .setBounds(1, MAX_PROCESSES) + .setTextColor(Color.WHITE.normal) + .setTextAlignment(Alignment.Center) + .addTooltip("Tier") + .setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD) + .setSize(18, 18) + .setPos(130, 85)); + return child; + } + + @Override + public short getCasingRegistryID() { + return 0; + } + + @Override + public void readMultiTileNBT(NBTTagCompound nbt) { + super.readMultiTileNBT(nbt); + setMaxComplexParallels(nbt.getInteger("processors"), false); + } + + @Override + public void writeMultiTileNBT(NBTTagCompound nbt) { + super.writeMultiTileNBT(nbt); + nbt.setInteger("processors", maxComplexParallels); + } + + @Override + public int getCasingMeta() { + return GT_MultiTileCasing.LaserEngraver.getId(); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Laser Engraver") + .addInfo("Used for Engraving") + .addSeparator() + .beginStructureBlock(3, 3, 5, true) + .addController("Front right center") + .toolTipFinisher(GT_Values.AuthorTheEpicGamer274); + return tt; + } + + @Override + @Nonnull + protected LaserEngraverProcessingLogic createProcessingLogic() { + return new LaserEngraverProcessingLogic(); + } + +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/LayeredCokeBattery.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/LayeredCokeBattery.java new file mode 100644 index 0000000000..3b00708e40 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/LayeredCokeBattery.java @@ -0,0 +1,295 @@ +package gregtech.common.tileentities.machines.multiblock; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.*; +import static gregtech.api.enums.Mods.*; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ENERGY_IN; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.FLUID_IN; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.FLUID_OUT; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ITEM_IN; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ITEM_OUT; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.NOTHING; +import static gregtech.api.util.GT_StructureUtilityMuTE.AMPERAGE_CASINGS; +import static gregtech.api.util.GT_StructureUtilityMuTE.HEATER_CASINGS; +import static gregtech.api.util.GT_StructureUtilityMuTE.INSULATOR_CASINGS; +import static gregtech.api.util.GT_StructureUtilityMuTE.MOTOR_CASINGS; +import static gregtech.api.util.GT_StructureUtilityMuTE.ofMuTECasings; + +import java.util.Arrays; +import java.util.Map; + +import javax.annotation.Nonnull; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizon.structurelib.util.Vec3Impl; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Materials; +import gregtech.api.enums.SoundResource; +import gregtech.api.multitileentity.enums.GT_MultiTileCasing; +import gregtech.api.multitileentity.multiblock.base.StackableModularController; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_StructureUtility; +import gregtech.api.util.GT_StructureUtilityMuTE.UpgradeCasings; +import gregtech.common.tileentities.machines.multiblock.logic.LayeredCokeBatteryProcessingLogic; + +public class LayeredCokeBattery + extends StackableModularController<LayeredCokeBattery, LayeredCokeBatteryProcessingLogic> { + + private static IStructureDefinition<LayeredCokeBattery> STRUCTURE_DEFINITION_MEGA = null; + protected static final String STRUCTURE_PIECE_BASE = "T1"; + private static final Vec3Impl STRUCTURE_OFFSET_BASE = new Vec3Impl(2, 2, 0); + private static final Vec3Impl STRUCTURE_OFFSET_MEGA_POSITION = new Vec3Impl(4, 7, -4); + private static final Vec3Impl STRUCTURE_OFFSET_MEGA_START = new Vec3Impl(0, 0, -3); + private static final Vec3Impl STRUCTURE_OFFSET_MEGA_STACK = new Vec3Impl(0, 0, -2); + private static final Vec3Impl STRUCTURE_OFFSET_MEGA_STOP = new Vec3Impl(0, 0, -1); + + @Override + public String getTileEntityName() { + return "gt.multitileentity.multiblock.layeredcokebattery"; + } + + @Override + public String getLocalName() { + return "Layered Coke Battery"; + } + + @Override + public Vec3Impl getStartingStructureOffset() { + return STRUCTURE_OFFSET_BASE; + } + + public UpgradeCasings getBaseMucType() { + return UpgradeCasings.Heater; + } + + public int getParallelFactor() { + return 2; + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + final int blueprintCount = (trigger.stackSize - 1) + getMinStacks(); + final int stackCount = Math.min(blueprintCount, getMaxStacks()); + + buildState.startBuilding(getStartingStructureOffset()); + buildPiece(STRUCTURE_PIECE_BASE, trigger, hintsOnly, buildState.getCurrentOffset()); + buildState.addOffset(getMegaPositionOffset()); + + if (stackCount >= 1) { + buildPiece(STACKABLE_START, trigger, hintsOnly, buildState.getCurrentOffset()); + buildState.addOffset(getStartingStackOffset()); + + for (int i = 0; i < stackCount; i++) { + buildPiece(STACKABLE_MIDDLE, trigger, hintsOnly, buildState.getCurrentOffset()); + buildState.addOffset(getPerStackOffset()); + } + if (hasTop()) { + buildPiece(STACKABLE_STOP, trigger, hintsOnly, buildState.getCurrentOffset()); + } + } + + buildState.stopBuilding(); + } + + @Override + public IStructureDefinition<LayeredCokeBattery> getStructureDefinition() { + if (STRUCTURE_DEFINITION_MEGA == null) { + STRUCTURE_DEFINITION_MEGA = StructureDefinition.<LayeredCokeBattery>builder() + .addShape( + STRUCTURE_PIECE_BASE, + transpose( + new String[][] { { " AAA ", "AAAAA", "AEEEP", "AAAAA" }, { " AAA ", "A A", "A A", "AAAAA" }, + { " A~A ", "A A", "A A", "AAAAA" }, { " AAA ", "A A", "A A", "AAAAA" }, + { " AAA ", "AAAAA", "AAAAA", "AAAAA" } })) + .addShape( + STACKABLE_STOP, + transpose( + new String[][] { { "AHFFFFAFFFFHA", "AAAAAAAAAAAAA" }, { " B B B B B B ", "AFAFAFAFAFAFA" }, + { "HB B B B B BH", "AFAFAFAFAFAFA" }, { " B B B B B B ", "AFAFAFAFAFAFA" }, + { " B B B B B B ", "AFAFAFAFAFAFA" }, { " B B B B B B ", "AFAFAFAFAFAFA" }, + { " B B B B B B ", "AFAFAFAFAFAFA" }, { " B B B B B B ", "AFAFAFAFAFAFA" }, + { " B B B B B B ", "AFAFAFAFAFAFA" }, { "HB B B B B BH", "AFAFAFAFAFAFA" }, + { " B B B B B B ", "AFAFAFAFAFAFA" }, { "AAAAAAAAAAAAA", "AAAAAAAAAAAAA" } })) + .addShape( + STACKABLE_MIDDLE, + transpose( + new String[][] { { "AHFFFFAFFFFHA", "AAAAAAAAAAAAA" }, { " B A B ", "AAAAAAAAAAAAA" }, + { "HB A BH", "AAAAAAAAAAAAA" }, { " B A B ", "AAAAAAAAAAAAA" }, + { " B A B ", "AAAAAAAAAAAAA" }, { " B A B ", "AAAAAAAAAAAAA" }, + { " B A B ", "AAAAAAAAAAAAA" }, { " B A B ", "AAAAAAAAAAAAA" }, + { " B A B ", "AAAAAAAAAAAAA" }, { "HB A BH", "AAAAAAAAAAAAA" }, + { " B A B ", "AAAAAAAAAAAAA" }, { "AAAAAAAAAAAAA", "AAAAAAAAAAAAA" } })) + .addShape( + STACKABLE_START, + transpose( + new String[][] { { "AAAAAAAAAAAAA", "AHFFFFAFFFFHA", "AAAAAAAAAAAAA" }, + { "AFAFAFAFAFAFA", " B B B B B B ", "AAAAAAAAAAAAA" }, + { "AFAFAFAFAFAFA", "HB B B B B BH", "AAAAAAAAAAAAA" }, + { "AFAFAFAFAFAFA", " B B B B B B ", "AAAAAAAAAAAAA" }, + { "AFAFAFAFAFAFA", " B B B B B B ", "AAAAAAAAAAAAA" }, + { "AFAFAFAFAFAFA", " B B B B B B ", "AAAAAAAAAAAAA" }, + { "AFAFAFAFAFAFA", " B B B B B B ", "AAAAAAAAAAAAA" }, + { "AFAFAFAFAFAFA", " B B B B B B ", "AAAAAAAAAAAAA" }, + { "AFAFAFAFAFAFA", " B B B B B B ", "AAAAAAAAAAAAA" }, + { "AFAFAFAFAFAFA", "HB B B B B BH", "AAAAAAAAAAAAA" }, + { "AFAFAFAFAFAFA", " B B B B B B ", "AAAAAAAAAAAAA" }, + { "AAAAAAAAAAAAA", "AAAAAAAAAAAAA", "AAAAAAAAAAAAA" } })) + .addElement( + 'A', + ofMuTECasings( + FLUID_IN | ITEM_IN | FLUID_OUT | ITEM_OUT | ENERGY_IN, + GT_MultiTileCasing.Chemical.getCasing())) + .addElement( + 'B', + ofMuTECasings( + FLUID_IN | ITEM_IN | FLUID_OUT | ITEM_OUT | ENERGY_IN, + GT_MultiTileCasing.Distillation.getCasing())) + .addElement('C', ofBlock(GregTech_API.sBlockCasings4, 1)) + .addElement('D', GT_StructureUtility.ofFrame(Materials.Steel)) + .addElement('E', ofMuTECasings(NOTHING, MOTOR_CASINGS)) + .addElement( + 'F', + ofChain( + ofBlockUnlocalizedName(IndustrialCraft2.ID, "blockAlloyGlass", 0, true), + ofBlockUnlocalizedName(BartWorks.ID, "BW_GlasBlocks", 0, true), + ofBlockUnlocalizedName(BartWorks.ID, "BW_GlasBlocks2", 0, true), + ofBlockUnlocalizedName(Thaumcraft.ID, "blockCosmeticOpaque", 2, false))) + .addElement('H', ofMuTECasings(NOTHING, HEATER_CASINGS, INSULATOR_CASINGS)) + .addElement('P', ofMuTECasings(NOTHING, AMPERAGE_CASINGS)) + .build(); + } + return STRUCTURE_DEFINITION_MEGA; + } + + public boolean checkMachine() { + stackCount = 0; + resetMucCount(); + + buildState.startBuilding(getStartingStructureOffset()); + if (!checkPiece(STRUCTURE_PIECE_BASE, buildState.getCurrentOffset())) return buildState.failBuilding(); + + buildState.addOffset(getMegaPositionOffset()); + if (!checkPiece(STACKABLE_START, buildState.getCurrentOffset())) { + return buildState.failBuilding(); + } + + buildState.addOffset(getStartingStackOffset()); + for (int i = 0; i < getMaxStacks(); i++) { + if (!checkPiece(getStackableMiddle(i), buildState.getCurrentOffset())) { + break; + } + + buildState.addOffset(getPerStackOffset()); + stackCount++; + } + if (stackCount < getMinStacks()) return buildState.failBuilding(); + + if (!checkPiece(getStackableStop(), buildState.stopBuilding())) { + return buildState.failBuilding(); + } + + calculateTier(); + if (!calculateMucMultipliers()) { + return false; + } + calculateParallels(); + updatePowerLogic(); + return tier > 0; + } + + protected boolean calculateMucMultipliers() { + Map<UpgradeCasings, int[]> mucMap = getMucMap(); + int[] heaterList = mucMap.get(UpgradeCasings.Heater); + int[] insulatorList = mucMap.get(UpgradeCasings.Insulator); + int totalHeaterCount = Arrays.stream(heaterList) + .sum(); + int totalInsulatorCount = Arrays.stream(insulatorList) + .sum(); + if (totalHeaterCount + totalInsulatorCount < stackCount || totalInsulatorCount > totalHeaterCount) { + return false; + } + if (totalInsulatorCount > 0) { + // To be improved later, when more MUCs are added + // durationMultiplier = 1.0 / totalHeaterCount; + euTickMultiplier = 1.0 / totalInsulatorCount; + } + return true; + } + + @Override + public short getCasingRegistryID() { + return 0; + } + + @Override + public int getCasingMeta() { + return GT_MultiTileCasing.Distillation.getId(); + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Coke Oven") + .addInfo("Controller for the Layered Coke Battery") + .addSeparator() + .beginVariableStructureBlock(7, 9, 2 + getMinStacks(), 2 + getMaxStacks(), 7, 9, true) + .addController("Bottom Front Center") + .addCasingInfoExactly("Test Casing", 60, false) + .addEnergyHatch("Any bottom layer casing") + .addInputHatch("Any non-optional external facing casing on the stacks") + .addInputBus("Any non-optional external facing casing on the stacks") + .addOutputHatch("Any non-optional external facing casing on the stacks") + .addOutputBus("Any non-optional external facing casing on the stacks") + .addStructureInfo( + String.format("Stackable middle stacks between %d-%d time(s).", getMinStacks(), getMaxStacks())) + .toolTipFinisher("Wildcard"); + return tt; + } + + @Override + public int getMinStacks() { + return 0; + } + + @Override + public int getMaxStacks() { + return 20; + } + + public Vec3Impl getMegaPositionOffset() { + return STRUCTURE_OFFSET_MEGA_POSITION; + } + + @Override + public Vec3Impl getStartingStackOffset() { + return STRUCTURE_OFFSET_MEGA_START; + } + + @Override + public Vec3Impl getPerStackOffset() { + return STRUCTURE_OFFSET_MEGA_STACK; + } + + @Override + public Vec3Impl getAfterLastStackOffset() { + return STRUCTURE_OFFSET_MEGA_STOP; + } + + @SideOnly(Side.CLIENT) + @Override + protected ResourceLocation getActivitySoundLoop() { + return SoundResource.IC2_MACHINES_MACERATOR_OP.resourceLocation; + } + + @Override + @Nonnull + protected LayeredCokeBatteryProcessingLogic createProcessingLogic() { + return new LayeredCokeBatteryProcessingLogic(); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/Macerator.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/Macerator.java new file mode 100644 index 0000000000..dfdacfe7f2 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/Macerator.java @@ -0,0 +1,132 @@ +package gregtech.common.tileentities.machines.multiblock; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ENERGY_IN; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.FLUID_IN; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.FLUID_OUT; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ITEM_IN; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ITEM_OUT; +import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.NOTHING; +import static gregtech.api.util.GT_StructureUtilityMuTE.*; + +import javax.annotation.Nonnull; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import com.gtnewhorizon.structurelib.util.Vec3Impl; + +import gregtech.api.multitileentity.enums.GT_MultiTileCasing; +import gregtech.api.multitileentity.multiblock.base.StackableController; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.common.tileentities.machines.multiblock.logic.MaceratorProcessingLogic; + +public class Macerator extends StackableController<Macerator, MaceratorProcessingLogic> { + + private static IStructureDefinition<Macerator> STRUCTURE_DEFINITION = null; + + public Macerator() { + super(); + } + + @Override + public String getTileEntityName() { + return "gt.multitileentity.multiblock.macerator"; + } + + @Override + public IStructureDefinition<Macerator> getStructureDefinition() { + if (STRUCTURE_DEFINITION == null) { + STRUCTURE_DEFINITION = StructureDefinition.<Macerator>builder() + .addShape( + STACKABLE_STOP, + transpose(new String[][] { { " CCC ", "CCCCC", "CCCCC", "CCCCC", " CCC " }, })) + .addShape( + STACKABLE_MIDDLE, + transpose(new String[][] { { " BBB ", " B---B ", "DC---CD", " B---B ", " BBB " }, })) + .addShape( + STACKABLE_START, + transpose(new String[][] { { " G~F ", "AAAAA", "AAAAA", "AAAAA", " AAA " }, })) + .addElement('A', ofMuTECasings(ENERGY_IN, GT_MultiTileCasing.Macerator.getCasing())) + .addElement( + 'B', + ofMuTECasings(FLUID_IN | ITEM_IN | FLUID_OUT | ITEM_OUT, GT_MultiTileCasing.Macerator.getCasing())) + .addElement('C', ofMuTECasings(NOTHING, GT_MultiTileCasing.Macerator.getCasing())) + .addElement('D', ofMuTECasings(NOTHING, GT_MultiTileCasing.Macerator.getCasing())) + .addElement('F', ofMuTECasings(NOTHING, MOTOR_CASINGS)) + .addElement('G', ofMuTECasings(NOTHING, INVENTORY_CASINGS)) + .build(); + } + return STRUCTURE_DEFINITION; + } + + @Override + public short getCasingRegistryID() { + return 0; + } + + @Override + public int getCasingMeta() { + return 18000; + } + + @Override + public boolean hasTop() { + return true; + } + + @Override + protected GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + tt.addMachineType("Macerator") + .addInfo("Controller for the Macerator") + .addSeparator() + .beginVariableStructureBlock(7, 9, 2 + getMinStacks(), 2 + getMaxStacks(), 7, 9, true) + .addController("Bottom Front Center") + .addCasingInfoExactly("Test Casing", 60, false) + .addEnergyHatch("Any bottom layer casing") + .addInputHatch("Any non-optional external facing casing on the stacks") + .addInputBus("Any non-optional external facing casing on the stacks") + .addOutputHatch("Any non-optional external facing casing on the stacks") + .addOutputBus("Any non-optional external facing casing on the stacks") + .addStructureInfo( + String.format("Stackable middle stacks between %d-%d time(s).", getMinStacks(), getMaxStacks())) + .toolTipFinisher("Wildcard"); + return tt; + } + + @Override + public int getMinStacks() { + return 1; + } + + @Override + public int getMaxStacks() { + return 10; + } + + @Override + public Vec3Impl getStartingStructureOffset() { + return new Vec3Impl(2, 0, 0); + } + + @Override + public Vec3Impl getStartingStackOffset() { + return new Vec3Impl(1, 1, 0); + } + + @Override + public Vec3Impl getPerStackOffset() { + return new Vec3Impl(0, 1, 0); + } + + @Override + public Vec3Impl getAfterLastStackOffset() { + return new Vec3Impl(-1, 0, 0); + } + + @Override + @Nonnull + protected MaceratorProcessingLogic createProcessingLogic() { + return new MaceratorProcessingLogic(); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/AdvChemicalProcessorProcessingLogic.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/AdvChemicalProcessorProcessingLogic.java new file mode 100644 index 0000000000..59879e30c7 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/AdvChemicalProcessorProcessingLogic.java @@ -0,0 +1,12 @@ +package gregtech.common.tileentities.machines.multiblock.logic; + +import gregtech.api.logic.ComplexParallelProcessingLogic; +import gregtech.api.recipe.RecipeMaps; + +public class AdvChemicalProcessorProcessingLogic + extends ComplexParallelProcessingLogic<AdvChemicalProcessorProcessingLogic> { + + public AdvChemicalProcessorProcessingLogic() { + setRecipeMap(RecipeMaps.multiblockChemicalReactorRecipes); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/CokeOvenProcessingLogic.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/CokeOvenProcessingLogic.java new file mode 100644 index 0000000000..1534b05bc3 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/CokeOvenProcessingLogic.java @@ -0,0 +1,79 @@ +package gregtech.common.tileentities.machines.multiblock.logic; + +import static gregtech.api.enums.Mods.Railcraft; +import static net.minecraftforge.oredict.OreDictionary.getOreID; +import static net.minecraftforge.oredict.OreDictionary.getOreIDs; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; + +import gregtech.api.logic.FluidInventoryLogic; +import gregtech.api.logic.ItemInventoryLogic; +import gregtech.api.logic.MuTEProcessingLogic; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_OreDictUnificator; + +public class CokeOvenProcessingLogic extends MuTEProcessingLogic<CokeOvenProcessingLogic> { + + private static final int NORMAL_RECIPE_TIME = 1800; + private static final int WOOD_ORE_ID = getOreID("logWood"); + private static final int COAL_ORE_ID = getOreID("coal"); + private static final int COAL_BLOCK_ORE_ID = getOreID("blockCoal"); + private static final int SUGARCANE_ORE_ID = getOreID("sugarcane"); + private static final int CACTUS_ORE_ID = getOreID("blockCactus"); + private static final int CACTUS_CHARCOAL_ORE_ID = getOreID("itemCharcoalCactus"); + private static final int SUGAR_CHARCOAL_ORE_ID = getOreID("itemCharcoalSugar"); + private int timeMultiplier = 1; + + @Nonnull + @Override + protected Object findRecipe(@Nullable RecipeMap<?> map, @Nonnull ItemInventoryLogic itemInput, + @Nonnull FluidInventoryLogic fluidInput) { + for (ItemStack item : itemInput.getStoredItems()) { + ItemStack output = findRecipe(item); + if (output != null) { + ItemStack input = item.copy(); + input.stackSize = 1; + return null; + // return FindRecipeResult.ofSuccess( + // GT_Values.RA.stdBuilder() + // .itemInputs(input) + // .itemOutputs(output) + // .noFluidInputs() + // .noFluidOutputs() + // .duration(NORMAL_RECIPE_TIME * timeMultiplier) + // .eut(0) + // .build() + // .get()); + } + } + return null; + } + + @Nullable + private ItemStack findRecipe(@Nonnull ItemStack input) { + for (int oreId : getOreIDs(input)) { + if (oreId == COAL_ORE_ID) { + return GT_OreDictUnificator.get("fuelCoke", null, 1); + } else if (oreId == COAL_BLOCK_ORE_ID) { + timeMultiplier = 9; + return GT_ModHandler.getModItem(Railcraft.ID, "cube", 1, 0); + } else if (oreId == WOOD_ORE_ID) { + return new ItemStack(Items.coal, 1, 1); + } else if (oreId == SUGARCANE_ORE_ID) { + return GT_OreDictUnificator.get("itemCharcoalSugar", null, 1); + } else if (oreId == SUGAR_CHARCOAL_ORE_ID) { + return GT_OreDictUnificator.get("itemCokeSugar", null, 1); + } else if (oreId == CACTUS_ORE_ID) { + return GT_OreDictUnificator.get("itemCharcoalCactus", null, 1); + } else if (oreId == CACTUS_CHARCOAL_ORE_ID) { + return GT_OreDictUnificator.get("itemCokeCactus", null, 1); + } + } + return null; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/DistillationTowerProcessingLogic.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/DistillationTowerProcessingLogic.java new file mode 100644 index 0000000000..6f27c9a0e6 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/DistillationTowerProcessingLogic.java @@ -0,0 +1,7 @@ +package gregtech.common.tileentities.machines.multiblock.logic; + +import gregtech.api.logic.ComplexParallelProcessingLogic; + +public class DistillationTowerProcessingLogic extends ComplexParallelProcessingLogic<DistillationTowerProcessingLogic> { + +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/LaserEngraverProcessingLogic.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/LaserEngraverProcessingLogic.java new file mode 100644 index 0000000000..3f4a6bfe70 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/LaserEngraverProcessingLogic.java @@ -0,0 +1,7 @@ +package gregtech.common.tileentities.machines.multiblock.logic; + +import gregtech.api.logic.ComplexParallelProcessingLogic; + +public class LaserEngraverProcessingLogic extends ComplexParallelProcessingLogic<LaserEngraverProcessingLogic> { + +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/LayeredCokeBatteryProcessingLogic.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/LayeredCokeBatteryProcessingLogic.java new file mode 100644 index 0000000000..b2e43b6fa9 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/LayeredCokeBatteryProcessingLogic.java @@ -0,0 +1,7 @@ +package gregtech.common.tileentities.machines.multiblock.logic; + +import gregtech.api.logic.MuTEProcessingLogic; + +public class LayeredCokeBatteryProcessingLogic extends MuTEProcessingLogic<LayeredCokeBatteryProcessingLogic> { + +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/MaceratorProcessingLogic.java b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/MaceratorProcessingLogic.java new file mode 100644 index 0000000000..3f7d8a25f7 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multiblock/logic/MaceratorProcessingLogic.java @@ -0,0 +1,7 @@ +package gregtech.common.tileentities.machines.multiblock.logic; + +import gregtech.api.logic.MuTEProcessingLogic; + +public class MaceratorProcessingLogic extends MuTEProcessingLogic<MaceratorProcessingLogic> { + +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_AlloySmelter_Bronze.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_AlloySmelter_Bronze.java new file mode 100644 index 0000000000..9b2c6b3ada --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_AlloySmelter_Bronze.java @@ -0,0 +1,139 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_ALLOY_SMELTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_ALLOY_SMELTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_ALLOY_SMELTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_ALLOY_SMELTER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_ALLOY_SMELTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_ALLOY_SMELTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_ALLOY_SMELTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_ALLOY_SMELTER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_ALLOY_SMELTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_ALLOY_SMELTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_ALLOY_SMELTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_ALLOY_SMELTER_GLOW; + +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Bronze; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_AlloySmelter_Bronze extends GT_MetaTileEntity_BasicMachine_Bronze { + + public GT_MetaTileEntity_AlloySmelter_Bronze(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Combination Smelter", 2, 1, false); + } + + public GT_MetaTileEntity_AlloySmelter_Bronze(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 2, 1, false); + } + + @Override + protected boolean isBricked() { + return true; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_AlloySmelter_Bronze(mName, mDescriptionArray, mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.alloySmelterRecipes; + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_INDUCTION_LOOP, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_ALLOY_SMELTER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_ALLOY_SMELTER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_ALLOY_SMELTER), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_ALLOY_SMELTER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_ALLOY_SMELTER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_ALLOY_SMELTER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_ALLOY_SMELTER), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_ALLOY_SMELTER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_ALLOY_SMELTER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_ALLOY_SMELTER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_ALLOY_SMELTER), TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_ALLOY_SMELTER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_GLOW) + .glow() + .build() }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_AlloySmelter_Steel.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_AlloySmelter_Steel.java new file mode 100644 index 0000000000..8b96906da1 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_AlloySmelter_Steel.java @@ -0,0 +1,139 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_ALLOY_SMELTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_ALLOY_SMELTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_ALLOY_SMELTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_ALLOY_SMELTER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_ALLOY_SMELTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_ALLOY_SMELTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_ALLOY_SMELTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_ALLOY_SMELTER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_ALLOY_SMELTER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_ALLOY_SMELTER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_ALLOY_SMELTER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_ALLOY_SMELTER_GLOW; + +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Steel; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_AlloySmelter_Steel extends GT_MetaTileEntity_BasicMachine_Steel { + + public GT_MetaTileEntity_AlloySmelter_Steel(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Combination Smelter", 2, 1, true); + } + + public GT_MetaTileEntity_AlloySmelter_Steel(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 2, 1, true); + } + + @Override + protected boolean isBricked() { + return true; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_AlloySmelter_Steel(mName, mDescriptionArray, mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.alloySmelterRecipes; + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_INDUCTION_LOOP, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_ALLOY_SMELTER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_ALLOY_SMELTER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_ALLOY_SMELTER), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_ALLOY_SMELTER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_ALLOY_SMELTER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_ALLOY_SMELTER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_ALLOY_SMELTER), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_ALLOY_SMELTER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_ALLOY_SMELTER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_ALLOY_SMELTER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_ALLOY_SMELTER), TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_ALLOY_SMELTER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_ALLOY_SMELTER_GLOW) + .glow() + .build() }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Compressor_Bronze.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Compressor_Bronze.java new file mode 100644 index 0000000000..ef91ed5baf --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Compressor_Bronze.java @@ -0,0 +1,134 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_COMPRESSOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_COMPRESSOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_COMPRESSOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_COMPRESSOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_COMPRESSOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_COMPRESSOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_COMPRESSOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_COMPRESSOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_COMPRESSOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_COMPRESSOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_COMPRESSOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_COMPRESSOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_COMPRESSOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_COMPRESSOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_COMPRESSOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_COMPRESSOR_GLOW; + +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Bronze; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Compressor_Bronze extends GT_MetaTileEntity_BasicMachine_Bronze { + + public GT_MetaTileEntity_Compressor_Bronze(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Compressing Items", 1, 1, false); + } + + public GT_MetaTileEntity_Compressor_Bronze(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 1, 1, false); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Compressor_Bronze(this.mName, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.compressorRecipes; + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_COMPRESSOR_OP, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_COMPRESSOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_COMPRESSOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_COMPRESSOR), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_COMPRESSOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_COMPRESSOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_COMPRESSOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_COMPRESSOR), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_COMPRESSOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_COMPRESSOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_COMPRESSOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_COMPRESSOR), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_COMPRESSOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_COMPRESSOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_COMPRESSOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_COMPRESSOR), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_COMPRESSOR_GLOW) + .glow() + .build() }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Compressor_Steel.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Compressor_Steel.java new file mode 100644 index 0000000000..c213cf04f5 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Compressor_Steel.java @@ -0,0 +1,134 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_COMPRESSOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_COMPRESSOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_COMPRESSOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_COMPRESSOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_COMPRESSOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_COMPRESSOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_COMPRESSOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_COMPRESSOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_COMPRESSOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_COMPRESSOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_COMPRESSOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_COMPRESSOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_COMPRESSOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_COMPRESSOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_COMPRESSOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_COMPRESSOR_GLOW; + +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Steel; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Compressor_Steel extends GT_MetaTileEntity_BasicMachine_Steel { + + public GT_MetaTileEntity_Compressor_Steel(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Compressing Items", 1, 1, true); + } + + public GT_MetaTileEntity_Compressor_Steel(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 1, 1, true); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Compressor_Steel(this.mName, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.compressorRecipes; + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_COMPRESSOR_OP, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_COMPRESSOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_COMPRESSOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_COMPRESSOR), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_COMPRESSOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_COMPRESSOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_COMPRESSOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_COMPRESSOR), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_COMPRESSOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_COMPRESSOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_COMPRESSOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_COMPRESSOR), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_COMPRESSOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_COMPRESSOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_COMPRESSOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_COMPRESSOR), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_COMPRESSOR_GLOW) + .glow() + .build() }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Extractor_Bronze.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Extractor_Bronze.java new file mode 100644 index 0000000000..6e986992f3 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Extractor_Bronze.java @@ -0,0 +1,134 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_EXTRACTOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_EXTRACTOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_EXTRACTOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_EXTRACTOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_EXTRACTOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_EXTRACTOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_EXTRACTOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_EXTRACTOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_EXTRACTOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_EXTRACTOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_EXTRACTOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_EXTRACTOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_EXTRACTOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_EXTRACTOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_EXTRACTOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_EXTRACTOR_GLOW; + +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Bronze; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Extractor_Bronze extends GT_MetaTileEntity_BasicMachine_Bronze { + + public GT_MetaTileEntity_Extractor_Bronze(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Extracting your first Rubber", 1, 1, false); + } + + public GT_MetaTileEntity_Extractor_Bronze(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 1, 1, false); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Extractor_Bronze(this.mName, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.extractorRecipes; + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_EXTRACTOR_OP, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_EXTRACTOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_EXTRACTOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_SIDE_STEAM_EXTRACTOR), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_EXTRACTOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_EXTRACTOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_EXTRACTOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_EXTRACTOR), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_EXTRACTOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_EXTRACTOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_EXTRACTOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_EXTRACTOR), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_EXTRACTOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_EXTRACTOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_EXTRACTOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_EXTRACTOR), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_EXTRACTOR_GLOW) + .glow() + .build() }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Extractor_Steel.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Extractor_Steel.java new file mode 100644 index 0000000000..6a3d024e25 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Extractor_Steel.java @@ -0,0 +1,134 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_EXTRACTOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_EXTRACTOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_EXTRACTOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_EXTRACTOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_EXTRACTOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_EXTRACTOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_EXTRACTOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_EXTRACTOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_EXTRACTOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_EXTRACTOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_EXTRACTOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_EXTRACTOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_EXTRACTOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_EXTRACTOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_EXTRACTOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_EXTRACTOR_GLOW; + +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Steel; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Extractor_Steel extends GT_MetaTileEntity_BasicMachine_Steel { + + public GT_MetaTileEntity_Extractor_Steel(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Extracting your first Rubber", 1, 1, true); + } + + public GT_MetaTileEntity_Extractor_Steel(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 1, 1, true); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Extractor_Steel(this.mName, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.extractorRecipes; + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_EXTRACTOR_OP, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_EXTRACTOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_EXTRACTOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_SIDE_STEAM_EXTRACTOR), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_EXTRACTOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_EXTRACTOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_EXTRACTOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_EXTRACTOR), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_EXTRACTOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_EXTRACTOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_EXTRACTOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_EXTRACTOR), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_EXTRACTOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_EXTRACTOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_EXTRACTOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_EXTRACTOR), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_EXTRACTOR_GLOW) + .glow() + .build() }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_ForgeHammer_Bronze.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_ForgeHammer_Bronze.java new file mode 100644 index 0000000000..b7d25ac172 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_ForgeHammer_Bronze.java @@ -0,0 +1,202 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_HAMMER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_HAMMER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_HAMMER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_HAMMER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_HAMMER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_HAMMER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_HAMMER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_HAMMER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_HAMMER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_HAMMER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_HAMMER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_HAMMER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_HAMMER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_HAMMER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_HAMMER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_HAMMER_GLOW; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; + +import net.minecraft.block.Block; +import net.minecraftforge.common.util.ForgeDirection; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.enums.ParticleFX; +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Bronze; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.WorldSpawnedEventBuilder.ParticleEventBuilder; + +public class GT_MetaTileEntity_ForgeHammer_Bronze extends GT_MetaTileEntity_BasicMachine_Bronze { + + public GT_MetaTileEntity_ForgeHammer_Bronze(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Forge Hammer", 1, 1, false); + } + + public GT_MetaTileEntity_ForgeHammer_Bronze(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 1, 1, false); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_ForgeHammer_Bronze(this.mName, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.hammerRecipes; + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.RANDOM_ANVIL_USE, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_HAMMER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_HAMMER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_SIDE_STEAM_HAMMER), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_HAMMER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_HAMMER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_HAMMER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_FRONT_STEAM_HAMMER), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_HAMMER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_HAMMER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_HAMMER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_HAMMER), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_HAMMER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_HAMMER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_HAMMER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_HAMMER), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_HAMMER_GLOW) + .glow() + .build() }; + } + + /** + * Handles {@link Block#randomDisplayTick}. Draws Random Sparkles at main face. + * + * @param aBaseMetaTileEntity The entity that will handle the {@see Block#randomDisplayTick} + */ + @SideOnly(Side.CLIENT) + @Override + public void onRandomDisplayTick(IGregTechTileEntity aBaseMetaTileEntity) { + + // Random Sparkles at main face + if (aBaseMetaTileEntity.isActive() && XSTR_INSTANCE.nextInt(3) == 0) { + + final ForgeDirection mainFacing = this.mMainFacing; + + if ((mainFacing.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0 + && aBaseMetaTileEntity.getCoverIDAtSide(mainFacing) == 0 + && !aBaseMetaTileEntity.getOpacityAtSide(mainFacing)) { + + final double oX = aBaseMetaTileEntity.getXCoord(); + final double oY = aBaseMetaTileEntity.getYCoord(); + final double oZ = aBaseMetaTileEntity.getZCoord(); + final double offset = 0.02D; + final double horizontal = 0.5D + XSTR_INSTANCE.nextFloat() * 8D / 16D - 4D / 16D; + + final double x, y, z, mX, mZ; + + y = oY + XSTR_INSTANCE.nextFloat() * 10D / 16D + 5D / 16D; + + if (mainFacing == ForgeDirection.WEST) { + x = oX - offset; + mX = -.05D; + z = oZ + horizontal; + mZ = 0D; + } else if (mainFacing == ForgeDirection.EAST) { + x = oX + offset; + mX = .05D; + z = oZ + horizontal; + mZ = 0D; + } else if (mainFacing == ForgeDirection.NORTH) { + x = oX + horizontal; + mX = 0D; + z = oZ - offset; + mZ = -.05D; + } else // if (frontFacing == ForgeDirection.SOUTH.ordinal()) + { + x = oX + horizontal; + mX = 0D; + z = oZ + offset; + mZ = .05D; + } + + ParticleEventBuilder particleEventBuilder = (new ParticleEventBuilder()).setMotion(mX, 0, mZ) + .setPosition(x, y, z) + .setWorld(getBaseMetaTileEntity().getWorld()); + particleEventBuilder.setIdentifier(ParticleFX.LAVA) + .run(); + } + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_ForgeHammer_Steel.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_ForgeHammer_Steel.java new file mode 100644 index 0000000000..25785f3fa3 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_ForgeHammer_Steel.java @@ -0,0 +1,202 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_HAMMER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_HAMMER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_HAMMER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_HAMMER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_HAMMER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_HAMMER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_HAMMER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_HAMMER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_HAMMER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_HAMMER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_HAMMER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_HAMMER_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_HAMMER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_HAMMER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_HAMMER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_HAMMER_GLOW; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; + +import net.minecraft.block.Block; +import net.minecraftforge.common.util.ForgeDirection; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.api.enums.ParticleFX; +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Steel; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.WorldSpawnedEventBuilder.ParticleEventBuilder; + +public class GT_MetaTileEntity_ForgeHammer_Steel extends GT_MetaTileEntity_BasicMachine_Steel { + + public GT_MetaTileEntity_ForgeHammer_Steel(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Forge Hammer", 1, 1, true); + } + + public GT_MetaTileEntity_ForgeHammer_Steel(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 1, 1, true); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_ForgeHammer_Steel(this.mName, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.hammerRecipes; + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.RANDOM_ANVIL_USE, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_HAMMER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_HAMMER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_SIDE_STEAM_HAMMER), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_HAMMER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_HAMMER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_HAMMER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_FRONT_STEAM_HAMMER), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_HAMMER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_HAMMER_ACTIVE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_HAMMER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_HAMMER), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_HAMMER_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_HAMMER_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_HAMMER_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_HAMMER), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_HAMMER_GLOW) + .glow() + .build() }; + } + + /** + * Handles {@link Block#randomDisplayTick}. Draws Random Sparkles at main face. + * + * @param aBaseMetaTileEntity The entity that will handle the {@see Block#randomDisplayTick} + */ + @SideOnly(Side.CLIENT) + @Override + public void onRandomDisplayTick(IGregTechTileEntity aBaseMetaTileEntity) { + + // Random Sparkles at main face + if (aBaseMetaTileEntity.isActive() && XSTR_INSTANCE.nextInt(3) == 0) { + + final ForgeDirection mainFacing = this.mMainFacing; + + if ((mainFacing.flag & (ForgeDirection.UP.flag | ForgeDirection.DOWN.flag)) == 0 + && aBaseMetaTileEntity.getCoverIDAtSide(mainFacing) == 0 + && !aBaseMetaTileEntity.getOpacityAtSide(mainFacing)) { + + final double oX = aBaseMetaTileEntity.getXCoord(); + final double oY = aBaseMetaTileEntity.getYCoord(); + final double oZ = aBaseMetaTileEntity.getZCoord(); + final double offset = 0.02D; + final double horizontal = 0.5D + XSTR_INSTANCE.nextFloat() * 8D / 16D - 4D / 16D; + + final double x, y, z, mX, mZ; + + y = oY + XSTR_INSTANCE.nextFloat() * 10D / 16D + 5D / 16D; + + if (mainFacing == ForgeDirection.WEST) { + x = oX - offset; + mX = -.05D; + z = oZ + horizontal; + mZ = 0D; + } else if (mainFacing == ForgeDirection.EAST) { + x = oX + offset; + mX = .05D; + z = oZ + horizontal; + mZ = 0D; + } else if (mainFacing == ForgeDirection.NORTH) { + x = oX + horizontal; + mX = 0D; + z = oZ - offset; + mZ = -.05D; + } else // if (frontFacing == ForgeDirection.SOUTH.ordinal()) + { + x = oX + horizontal; + mX = 0D; + z = oZ + offset; + mZ = .05D; + } + + ParticleEventBuilder particleEventBuilder = (new ParticleEventBuilder()).setMotion(mX, 0, mZ) + .setPosition(x, y, z) + .setWorld(getBaseMetaTileEntity().getWorld()); + particleEventBuilder.setIdentifier(ParticleFX.LAVA) + .run(); + } + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Furnace_Bronze.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Furnace_Bronze.java new file mode 100644 index 0000000000..51a91874a0 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Furnace_Bronze.java @@ -0,0 +1,161 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_FURNACE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_FURNACE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_FURNACE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_FURNACE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_FURNACE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_FURNACE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_FURNACE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_FURNACE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_FURNACE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_FURNACE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_FURNACE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_FURNACE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_FURNACE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_FURNACE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_FURNACE_GLOW; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Bronze; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Furnace_Bronze extends GT_MetaTileEntity_BasicMachine_Bronze { + + public GT_MetaTileEntity_Furnace_Bronze(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Smelting things with compressed Steam", 1, 1, false); + } + + public GT_MetaTileEntity_Furnace_Bronze(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 1, 1, false); + } + + @Override + protected boolean isBricked() { + return true; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Furnace_Bronze(this.mName, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.furnaceRecipes; + } + + @Override + public int checkRecipe() { + if (null != (this.mOutputItems[0] = GT_ModHandler.getSmeltingOutput(getInputAt(0), true, getOutputAt(0)))) { + this.mEUt = 4; + this.mMaxProgresstime = 256; + return FOUND_AND_SUCCESSFULLY_USED_RECIPE; + } + return DID_NOT_FIND_RECIPE; + } + + @Override + protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack) + && GT_ModHandler.getSmeltingOutput(GT_Utility.copyAmount(64, aStack), false, null) != null; + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_ELECTROFURNACE_LOOP, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_FURNACE_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_FURNACE_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_SIDE_STEAM_FURNACE), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_FURNACE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_FURNACE_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_FURNACE_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_FRONT_STEAM_FURNACE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_FURNACE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_FURNACE_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_FURNACE_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_FURNACE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_FURNACE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_FURNACE_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_FURNACE_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of( + TextureFactory.of(OVERLAY_BOTTOM_STEAM_FURNACE), + TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_FURNACE_GLOW) + .glow() + .build()) }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Furnace_Steel.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Furnace_Steel.java new file mode 100644 index 0000000000..a151c724f3 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Furnace_Steel.java @@ -0,0 +1,159 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_FURNACE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_FURNACE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_FURNACE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_FURNACE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_FURNACE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_FURNACE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_FURNACE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_FURNACE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_FURNACE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_FURNACE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_FURNACE_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_FURNACE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_FURNACE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_FURNACE_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_FURNACE_GLOW; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.enums.SoundResource; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Steel; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Utility; + +public class GT_MetaTileEntity_Furnace_Steel extends GT_MetaTileEntity_BasicMachine_Steel { + + public GT_MetaTileEntity_Furnace_Steel(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Smelting things with compressed Steam", 1, 1, true); + } + + public GT_MetaTileEntity_Furnace_Steel(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 1, 1, true); + } + + @Override + protected boolean isBricked() { + return true; + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Furnace_Steel(this.mName, this.mDescriptionArray, this.mTextures); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.furnaceRecipes; + } + + @Override + public int checkRecipe() { + if (null != (this.mOutputItems[0] = GT_ModHandler.getSmeltingOutput(getInputAt(0), true, getOutputAt(0)))) { + this.mEUt = 8; + this.mMaxProgresstime = 128; + return FOUND_AND_SUCCESSFULLY_USED_RECIPE; + } + return DID_NOT_FIND_RECIPE; + } + + @Override + protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack) + && GT_ModHandler.getSmeltingOutput(GT_Utility.copyAmount(64, aStack), false, null) != null; + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_ELECTROFURNACE_LOOP, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_FURNACE_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_FURNACE_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_SIDE_STEAM_FURNACE), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_FURNACE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_FURNACE_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_FURNACE_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_FRONT_STEAM_FURNACE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_FURNACE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_FURNACE_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_FURNACE_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_FURNACE), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_FURNACE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_FURNACE_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_FURNACE_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_FURNACE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_FURNACE_GLOW) + .glow() + .build() }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Macerator_Bronze.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Macerator_Bronze.java new file mode 100644 index 0000000000..cdbf9f2123 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Macerator_Bronze.java @@ -0,0 +1,189 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_MACERATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_MACERATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_MACERATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_MACERATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_MACERATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_MACERATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_MACERATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_MACERATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_MACERATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_MACERATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_MACERATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_MACERATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_MACERATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_MACERATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_MACERATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_MACERATOR_GLOW; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.ParticleFX; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.TierEU; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Bronze; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.WorldSpawnedEventBuilder.ParticleEventBuilder; + +public class GT_MetaTileEntity_Macerator_Bronze extends GT_MetaTileEntity_BasicMachine_Bronze { + + public GT_MetaTileEntity_Macerator_Bronze(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Macerating your Ores", 1, 1, false); + } + + public GT_MetaTileEntity_Macerator_Bronze(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 1, 1, false); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Macerator_Bronze(this.mName, this.mDescriptionArray, this.mTextures); + } + + @Override + public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPreTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isClientSide() && aBaseMetaTileEntity.isActive()) { + + if (aBaseMetaTileEntity.getFrontFacing() != ForgeDirection.UP + && aBaseMetaTileEntity.getCoverIDAtSide(ForgeDirection.UP) == 0 + && !aBaseMetaTileEntity.getOpacityAtSide(ForgeDirection.UP)) { + + new ParticleEventBuilder().setMotion(0.0D, 0.0D, 0.0D) + .setIdentifier(ParticleFX.SMOKE) + .setPosition( + aBaseMetaTileEntity.getXCoord() + 0.8F - XSTR_INSTANCE.nextFloat() * 0.6F, + aBaseMetaTileEntity.getYCoord() + 0.9F + XSTR_INSTANCE.nextFloat() * 0.2F, + aBaseMetaTileEntity.getZCoord() + 0.8F - XSTR_INSTANCE.nextFloat() * 0.6F) + .setWorld(getBaseMetaTileEntity().getWorld()) + .run(); + } + } + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.maceratorRecipes; + } + + @Override + public int checkRecipe() { + GT_Recipe tRecipe = getRecipeMap() + .findRecipe(getBaseMetaTileEntity(), mLastRecipe, false, TierEU.LV, null, null, getAllInputs()); + if (tRecipe == null) return DID_NOT_FIND_RECIPE; + if (tRecipe.mCanBeBuffered) mLastRecipe = tRecipe; + if (!canOutput(tRecipe)) { + mOutputBlocked++; + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + } + + if (!tRecipe.isRecipeInputEqual(true, new FluidStack[] { getFillableStack() }, getAllInputs())) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + if (tRecipe.getOutput(0) != null) mOutputItems[0] = tRecipe.getOutput(0); + calculateCustomOverclock(tRecipe); + return FOUND_AND_SUCCESSFULLY_USED_RECIPE; + } + + @Override + protected boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack) + && RecipeMaps.maceratorRecipes.containsInput(GT_Utility.copyAmount(64, aStack)); + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_MACERATOR_OP, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_MACERATOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_MACERATOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_SIDE_STEAM_MACERATOR), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_MACERATOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_MACERATOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_MACERATOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_MACERATOR), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_MACERATOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_MACERATOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_MACERATOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_MACERATOR), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_MACERATOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_MACERATOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_MACERATOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_MACERATOR), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_MACERATOR_GLOW) + .glow() + .build() }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Macerator_Steel.java b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Macerator_Steel.java new file mode 100644 index 0000000000..95d510ffa3 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/steam/GT_MetaTileEntity_Macerator_Steel.java @@ -0,0 +1,188 @@ +package gregtech.common.tileentities.machines.steam; + +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_MACERATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_MACERATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_MACERATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_BOTTOM_STEAM_MACERATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_MACERATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_MACERATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_MACERATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_STEAM_MACERATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_MACERATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_MACERATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_MACERATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_SIDE_STEAM_MACERATOR_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_MACERATOR; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_MACERATOR_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_MACERATOR_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_TOP_STEAM_MACERATOR_GLOW; +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.ParticleFX; +import gregtech.api.enums.SoundResource; +import gregtech.api.enums.TierEU; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_Steel; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.WorldSpawnedEventBuilder; + +public class GT_MetaTileEntity_Macerator_Steel extends GT_MetaTileEntity_BasicMachine_Steel { + + public GT_MetaTileEntity_Macerator_Steel(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, "Macerating your Ores", 1, 1, true); + } + + public GT_MetaTileEntity_Macerator_Steel(String aName, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aDescription, aTextures, 1, 1, true); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new GT_MetaTileEntity_Macerator_Steel(this.mName, this.mDescriptionArray, this.mTextures); + } + + @Override + public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPreTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isClientSide() && aBaseMetaTileEntity.isActive()) { + if (aBaseMetaTileEntity.getFrontFacing() != ForgeDirection.UP + && aBaseMetaTileEntity.getCoverIDAtSide(ForgeDirection.UP) == 0 + && !aBaseMetaTileEntity.getOpacityAtSide(ForgeDirection.UP)) { + + new WorldSpawnedEventBuilder.ParticleEventBuilder().setMotion(0.0D, 0.0D, 0.0D) + .setIdentifier(ParticleFX.SMOKE) + .setPosition( + aBaseMetaTileEntity.getXCoord() + 0.8F - XSTR_INSTANCE.nextFloat() * 0.6F, + aBaseMetaTileEntity.getYCoord() + 0.9F + XSTR_INSTANCE.nextFloat() * 0.2F, + aBaseMetaTileEntity.getZCoord() + 0.8F - XSTR_INSTANCE.nextFloat() * 0.6F) + .setWorld(getBaseMetaTileEntity().getWorld()) + .run(); + } + } + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.maceratorRecipes; + } + + @Override + public int checkRecipe() { + GT_Recipe tRecipe = getRecipeMap() + .findRecipe(getBaseMetaTileEntity(), mLastRecipe, false, TierEU.LV, null, null, getAllInputs()); + if (tRecipe == null) return DID_NOT_FIND_RECIPE; + if (tRecipe.mCanBeBuffered) mLastRecipe = tRecipe; + if (!canOutput(tRecipe)) { + mOutputBlocked++; + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + } + + if (!tRecipe.isRecipeInputEqual(true, new FluidStack[] { getFillableStack() }, getAllInputs())) + return FOUND_RECIPE_BUT_DID_NOT_MEET_REQUIREMENTS; + if (tRecipe.getOutput(0) != null) mOutputItems[0] = tRecipe.getOutput(0); + calculateCustomOverclock(tRecipe); + return FOUND_AND_SUCCESSFULLY_USED_RECIPE; + } + + @Override + public boolean allowPutStackValidated(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return super.allowPutStackValidated(aBaseMetaTileEntity, aIndex, side, aStack) + && RecipeMaps.maceratorRecipes.containsInput(GT_Utility.copyAmount(64, aStack)); + } + + @Override + public void startSoundLoop(byte aIndex, double aX, double aY, double aZ) { + super.startSoundLoop(aIndex, aX, aY, aZ); + if (aIndex == 1) { + GT_Utility.doSoundAtClient(SoundResource.IC2_MACHINES_MACERATOR_OP, 10, 1.0F, aX, aY, aZ); + } + } + + @Override + public void startProcess() { + sendLoopStart((byte) 1); + } + + @Override + public ITexture[] getSideFacingActive(byte aColor) { + return new ITexture[] { super.getSideFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_SIDE_STEAM_MACERATOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_MACERATOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getSideFacingInactive(byte aColor) { + return new ITexture[] { super.getSideFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_SIDE_STEAM_MACERATOR), + TextureFactory.builder() + .addIcon(OVERLAY_SIDE_STEAM_MACERATOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingActive(byte aColor) { + return new ITexture[] { super.getFrontFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_MACERATOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_MACERATOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getFrontFacingInactive(byte aColor) { + return new ITexture[] { super.getFrontFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_FRONT_STEAM_MACERATOR), TextureFactory.builder() + .addIcon(OVERLAY_FRONT_STEAM_MACERATOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingActive(byte aColor) { + return new ITexture[] { super.getTopFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_TOP_STEAM_MACERATOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_MACERATOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getTopFacingInactive(byte aColor) { + return new ITexture[] { super.getTopFacingInactive(aColor)[0], TextureFactory.of(OVERLAY_TOP_STEAM_MACERATOR), + TextureFactory.builder() + .addIcon(OVERLAY_TOP_STEAM_MACERATOR_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingActive(byte aColor) { + return new ITexture[] { super.getBottomFacingActive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_MACERATOR_ACTIVE), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_MACERATOR_ACTIVE_GLOW) + .glow() + .build() }; + } + + @Override + public ITexture[] getBottomFacingInactive(byte aColor) { + return new ITexture[] { super.getBottomFacingInactive(aColor)[0], + TextureFactory.of(OVERLAY_BOTTOM_STEAM_MACERATOR), TextureFactory.builder() + .addIcon(OVERLAY_BOTTOM_STEAM_MACERATOR_GLOW) + .glow() + .build() }; + } +} |