diff --git a/src/main/java/gregtech/api/capability/GregtechDataCodes.java b/src/main/java/gregtech/api/capability/GregtechDataCodes.java index e425d3339e4..ea548fe15ce 100644 --- a/src/main/java/gregtech/api/capability/GregtechDataCodes.java +++ b/src/main/java/gregtech/api/capability/GregtechDataCodes.java @@ -42,8 +42,11 @@ public static int assignId() { public static final int INIT_CLIPBOARD_NBT = assignId(); public static final int UPDATE_UI = assignId(); // 10-36 - // Pump + // Pump, Miner public static final int PUMP_HEAD_LEVEL = assignId(); + // Miner + public static final int MINER_UPDATE_PREVIEW = assignId(); + public static final int MINER_UPDATE_ACTIVE = assignId(); // Item Collector, Magic Energy Absorber, Large Boiler, Steam Oven public static final int IS_WORKING = assignId(); diff --git a/src/main/java/gregtech/api/capability/IMiner.java b/src/main/java/gregtech/api/capability/IMiner.java deleted file mode 100644 index 4b82046f399..00000000000 --- a/src/main/java/gregtech/api/capability/IMiner.java +++ /dev/null @@ -1,22 +0,0 @@ -package gregtech.api.capability; - -import codechicken.lib.vec.Cuboid6; - -public interface IMiner { - - Cuboid6 PIPE_CUBOID = new Cuboid6(4 / 16.0, 0.0, 4 / 16.0, 12 / 16.0, 1.0, 12 / 16.0); - - boolean drainEnergy(boolean simulate); - - default boolean drainFluid(boolean simulate) { - return true; - } - - boolean isInventoryFull(); - - void setInventoryFull(boolean isFull); - - default int getWorkingArea(int maximumRadius) { - return maximumRadius * 2 + 1; - } -} diff --git a/src/main/java/gregtech/api/capability/impl/RecipeLogicSteam.java b/src/main/java/gregtech/api/capability/impl/RecipeLogicSteam.java index c5d7dcbb960..b0b981ee856 100644 --- a/src/main/java/gregtech/api/capability/impl/RecipeLogicSteam.java +++ b/src/main/java/gregtech/api/capability/impl/RecipeLogicSteam.java @@ -3,28 +3,15 @@ import gregtech.api.GTValues; import gregtech.api.capability.GregtechDataCodes; import gregtech.api.capability.IVentable; -import gregtech.api.damagesources.DamageSources; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.recipes.Recipe; import gregtech.api.recipes.RecipeMap; import gregtech.api.util.GTUtility; import gregtech.common.ConfigHolder; -import gregtech.core.advancement.AdvancementTriggers; -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.init.SoundEvents; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; -import net.minecraft.util.EntitySelectors; import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumParticleTypes; -import net.minecraft.util.SoundCategory; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.WorldServer; import net.minecraftforge.fluids.IFluidTank; import org.jetbrains.annotations.NotNull; @@ -126,46 +113,15 @@ public void receiveInitialSyncData(@NotNull PacketBuffer buf) { @Override public void tryDoVenting() { - BlockPos machinePos = metaTileEntity.getPos(); - EnumFacing ventingSide = getVentingSide(); - BlockPos ventingBlockPos = machinePos.offset(ventingSide); - IBlockState blockOnPos = metaTileEntity.getWorld().getBlockState(ventingBlockPos); - if (blockOnPos.getCollisionBoundingBox(metaTileEntity.getWorld(), ventingBlockPos) == Block.NULL_AABB) { - performVentingAnimation(ventingBlockPos, machinePos); - } else if (GTUtility.tryBreakSnow(metaTileEntity.getWorld(), ventingBlockPos, blockOnPos, false)) { - performVentingAnimation(ventingBlockPos, machinePos); - } else if (!ventingStuck) { + if (GTUtility.tryVenting(metaTileEntity.getWorld(), metaTileEntity.getPos(), getVentingSide(), + this.isHighPressure ? 12 : 6, true, + ConfigHolder.machines.machineSounds && !this.metaTileEntity.isMuffled())) { + setNeedsVenting(false); + } else { setVentingStuck(true); } } - private void performVentingAnimation(BlockPos ventingBlockPos, BlockPos machinePos) { - metaTileEntity.getWorld() - .getEntitiesWithinAABB(EntityLivingBase.class, new AxisAlignedBB(ventingBlockPos), - EntitySelectors.CAN_AI_TARGET) - .forEach(entity -> { - entity.attackEntityFrom(DamageSources.getHeatDamage(), this.isHighPressure ? 12.0f : 6.0f); - if (entity instanceof EntityPlayerMP) { - AdvancementTriggers.STEAM_VENT_DEATH.trigger((EntityPlayerMP) entity); - } - }); - WorldServer world = (WorldServer) metaTileEntity.getWorld(); - double posX = machinePos.getX() + 0.5 + ventingSide.getXOffset() * 0.6; - double posY = machinePos.getY() + 0.5 + ventingSide.getYOffset() * 0.6; - double posZ = machinePos.getZ() + 0.5 + ventingSide.getZOffset() * 0.6; - - world.spawnParticle(EnumParticleTypes.CLOUD, posX, posY, posZ, - 7 + world.rand.nextInt(3), - ventingSide.getXOffset() / 2.0, - ventingSide.getYOffset() / 2.0, - ventingSide.getZOffset() / 2.0, 0.1); - if (ConfigHolder.machines.machineSounds && !metaTileEntity.isMuffled()) { - world.playSound(null, posX, posY, posZ, SoundEvents.BLOCK_LAVA_EXTINGUISH, SoundCategory.BLOCKS, 1.0f, - 1.0f); - } - setNeedsVenting(false); - } - @Override public void update() { if (getMetaTileEntity().getWorld().isRemote) diff --git a/src/main/java/gregtech/api/capability/impl/miner/MinerLogic.java b/src/main/java/gregtech/api/capability/impl/miner/MinerLogic.java deleted file mode 100644 index 5b1ca454f3d..00000000000 --- a/src/main/java/gregtech/api/capability/impl/miner/MinerLogic.java +++ /dev/null @@ -1,768 +0,0 @@ -package gregtech.api.capability.impl.miner; - -import gregtech.api.capability.GregtechDataCodes; -import gregtech.api.capability.IMiner; -import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.api.recipes.Recipe; -import gregtech.api.recipes.RecipeMap; -import gregtech.api.unification.OreDictUnifier; -import gregtech.api.unification.ore.OrePrefix; -import gregtech.api.util.GTLog; -import gregtech.api.util.GTTransferUtils; -import gregtech.api.util.GTUtility; -import gregtech.client.renderer.ICubeRenderer; -import gregtech.client.renderer.texture.Textures; -import gregtech.common.ConfigHolder; - -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.init.Blocks; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagInt; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.NonNullList; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import net.minecraft.world.WorldServer; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -import codechicken.lib.render.CCRenderState; -import codechicken.lib.render.pipeline.IVertexOperation; -import codechicken.lib.vec.Matrix4; -import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.NotNull; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicInteger; - -public class MinerLogic { - - private static final short MAX_SPEED = Short.MAX_VALUE; - private static final byte POWER = 5; - private static final byte TICK_TOLERANCE = 20; - private static final double DIVIDEND = MAX_SPEED * Math.pow(TICK_TOLERANCE, POWER); - - protected final MetaTileEntity metaTileEntity; - protected final IMiner miner; - - private final int fortune; - private final int speed; - private final int maximumRadius; - - private final ICubeRenderer PIPE_TEXTURE; - - private final LinkedList blocksToMine = new LinkedList<>(); - - private final AtomicInteger x = new AtomicInteger(Integer.MAX_VALUE); - private final AtomicInteger y = new AtomicInteger(Integer.MAX_VALUE); - private final AtomicInteger z = new AtomicInteger(Integer.MAX_VALUE); - private final AtomicInteger startX = new AtomicInteger(Integer.MAX_VALUE); - private final AtomicInteger startZ = new AtomicInteger(Integer.MAX_VALUE); - private final AtomicInteger startY = new AtomicInteger(Integer.MAX_VALUE); - private final AtomicInteger pipeY = new AtomicInteger(Integer.MAX_VALUE); - private final AtomicInteger mineX = new AtomicInteger(Integer.MAX_VALUE); - private final AtomicInteger mineZ = new AtomicInteger(Integer.MAX_VALUE); - private final AtomicInteger mineY = new AtomicInteger(Integer.MAX_VALUE); - - private int pipeLength = 0; - private int currentRadius; - private boolean isDone; - private boolean isActive = false; - private boolean isWorkingEnabled = true; - protected boolean wasActiveAndNeedsUpdate; - - private final IBlockState oreReplacementBlock = findMiningReplacementBlock(); - - /** - * Creates the general logic for all in-world ore block miners - * - * @param metaTileEntity the {@link MetaTileEntity} this logic belongs to - * @param fortune the fortune amount to apply when mining ores - * @param speed the speed in ticks per block mined - * @param maximumRadius the maximum radius (square shaped) the miner can mine in - */ - public MinerLogic(@NotNull MetaTileEntity metaTileEntity, int fortune, int speed, int maximumRadius, - ICubeRenderer pipeTexture) { - this.metaTileEntity = metaTileEntity; - this.miner = (IMiner) metaTileEntity; - this.fortune = fortune; - this.speed = speed; - this.currentRadius = maximumRadius; - this.maximumRadius = maximumRadius; - this.isDone = false; - this.PIPE_TEXTURE = pipeTexture; - } - - private static IBlockState findMiningReplacementBlock() { - String[] blockDescription = StringUtils.split(ConfigHolder.machines.replaceMinedBlocksWith, ":"); - Block replacementBlock; - - if (blockDescription.length == 2) { - replacementBlock = Block.getBlockFromName(ConfigHolder.machines.replaceMinedBlocksWith); - } else { - replacementBlock = Block.getBlockFromName(String.format("%s:%s", blockDescription[0], blockDescription[1])); - } - if (replacementBlock == null) { - GTLog.logger.error("Miner Config Replacement block was null, replacing with Cobblestone"); - return Blocks.COBBLESTONE.getDefaultState(); - } - - // check for meta - if (blockDescription.length > 2 && !blockDescription[2].isEmpty()) { - return replacementBlock.getDefaultState().getBlock() - .getStateFromMeta(Integer.parseInt(blockDescription[2])); - } - - return replacementBlock.getDefaultState(); - } - - /** - * Performs the actual mining in world - * Call this method every tick in update - */ - public void performMining() { - // Needs to be server side - if (metaTileEntity.getWorld().isRemote) - return; - - // Inactive miners do nothing - if (!this.isWorkingEnabled) - return; - - // check if mining is possible - if (!checkCanMine()) - return; - - // if the inventory is not full, drain energy etc. from the miner - // the storages have already been checked earlier - if (!miner.isInventoryFull()) { - // always drain storages when working, even if blocksToMine ends up being empty - drainStorages(false); - - // since energy is being consumed the miner is now active - if (!this.isActive) - setActive(true); - } else { - // the miner cannot drain, therefore it is inactive - if (this.isActive) - setActive(false); - } - - // drill a hole beneath the miner and extend the pipe downwards by one - WorldServer world = (WorldServer) metaTileEntity.getWorld(); - if (mineY.get() < pipeY.get()) { - world.destroyBlock( - new BlockPos(metaTileEntity.getPos().getX(), pipeY.get(), metaTileEntity.getPos().getZ()), false); - pipeY.decrementAndGet(); - incrementPipeLength(); - } - - // check if the miner needs new blocks to mine and get them if needed - checkBlocksToMine(); - - // if there are blocks to mine and the correct amount of time has passed, do the mining - if (metaTileEntity.getOffsetTimer() % this.speed == 0 && !blocksToMine.isEmpty()) { - NonNullList blockDrops = NonNullList.create(); - IBlockState blockState = metaTileEntity.getWorld().getBlockState(blocksToMine.getFirst()); - - // check to make sure the ore is still there, - while (!GTUtility.isOre(GTUtility.toItem(blockState))) { - blocksToMine.removeFirst(); - if (blocksToMine.isEmpty()) break; - blockState = metaTileEntity.getWorld().getBlockState(blocksToMine.getFirst()); - } - // When we are here we have an ore to mine! I'm glad we aren't threaded - if (!blocksToMine.isEmpty() & GTUtility.isOre(GTUtility.toItem(blockState))) { - // get the small ore drops, if a small ore - getSmallOreBlockDrops(blockDrops, world, blocksToMine.getFirst(), blockState); - // get the block's drops. - getRegularBlockDrops(blockDrops, world, blocksToMine.getFirst(), blockState); - // try to insert them - mineAndInsertItems(blockDrops, world); - } - - } - - if (blocksToMine.isEmpty()) { - // there were no blocks to mine, so the current position is the previous position - x.set(mineX.get()); - y.set(mineY.get()); - z.set(mineZ.get()); - - // attempt to get more blocks to mine, if there are none, the miner is done mining - blocksToMine.addAll(getBlocksToMine()); - if (blocksToMine.isEmpty()) { - this.isDone = true; - this.wasActiveAndNeedsUpdate = true; - this.setActive(false); - } - } - } - - /** - * @return true if the miner is able to mine, else false - */ - protected boolean checkCanMine() { - // if the miner is finished, the target coordinates are invalid, or it cannot drain storages, stop - if (checkShouldStop()) { - // if the miner is not finished and has invalid coordinates, get new and valid starting coordinates - if (!isDone && checkCoordinatesInvalid(x, y, z)) - initPos(metaTileEntity.getPos(), currentRadius); - - // don't do anything else this time - return false; - } - return true; - } - - protected boolean checkShouldStop() { - return isDone || checkCoordinatesInvalid(x, y, z) || !drainStorages(true); - } - - /** - * Called after each block is mined, used to perform additional actions afterwards - */ - protected void onMineOperation() {} - - /** - * called in order to drain anything the miner needs to drain in order to run - * only drains energy by default - */ - protected boolean drainStorages(boolean simulate) { - return miner.drainEnergy(simulate); - } - - /** - * called to handle mining small ores - * - * @param blockDrops the List of items to fill after the operation - * @param world the {@link WorldServer} the miner is in - * @param blockToMine the {@link BlockPos} of the block being mined - * @param blockState the {@link IBlockState} of the block being mined - */ - protected void getSmallOreBlockDrops(NonNullList blockDrops, WorldServer world, BlockPos blockToMine, - IBlockState blockState) { - /* - * small ores - * if orePrefix of block in blockPos is small - * applyTieredHammerNoRandomDrops... - * else - * current code... - */ - } - - /** - * called to handle mining regular ores and blocks - * - * @param blockDrops the List of items to fill after the operation - * @param world the {@link WorldServer} the miner is in - * @param blockToMine the {@link BlockPos} of the block being mined - * @param blockState the {@link IBlockState} of the block being mined - */ - protected void getRegularBlockDrops(NonNullList blockDrops, WorldServer world, BlockPos blockToMine, - @NotNull IBlockState blockState) { - blockState.getBlock().getDrops(blockDrops, world, blockToMine, blockState, 0); // regular ores do not get - // fortune applied - } - - /** - * called in order to insert the mined items into the inventory and actually remove the block in world - * marks the inventory as full if the items cannot fit, and not full if it previously was full and items could fit - * - * @param blockDrops the List of items to insert - * @param world the {@link WorldServer} the miner is in - */ - private void mineAndInsertItems(NonNullList blockDrops, WorldServer world) { - // If the block's drops can fit in the inventory, move the previously mined position to the block - // replace the ore block with cobblestone instead of breaking it to prevent mob spawning - // remove the ore block's position from the mining queue - if (GTTransferUtils.addItemsToItemHandler(metaTileEntity.getExportItems(), true, blockDrops)) { - GTTransferUtils.addItemsToItemHandler(metaTileEntity.getExportItems(), false, blockDrops); - world.setBlockState(blocksToMine.getFirst(), oreReplacementBlock); - mineX.set(blocksToMine.getFirst().getX()); - mineZ.set(blocksToMine.getFirst().getZ()); - mineY.set(blocksToMine.getFirst().getY()); - blocksToMine.removeFirst(); - onMineOperation(); - - // if the inventory was previously considered full, mark it as not since an item was able to fit - if (miner.isInventoryFull()) - miner.setInventoryFull(false); - } else { - // the ore block was not able to fit, so the inventory is considered full - miner.setInventoryFull(true); - } - } - - /** - * This method designates the starting position for mining blocks - * - * @param pos the {@link BlockPos} of the miner itself - * @param currentRadius the currently set mining radius - */ - public void initPos(@NotNull BlockPos pos, int currentRadius) { - x.set(pos.getX() - currentRadius); - z.set(pos.getZ() - currentRadius); - y.set(pos.getY() - 1); - startX.set(pos.getX() - currentRadius); - startZ.set(pos.getZ() - currentRadius); - startY.set(pos.getY()); - pipeY.set(pos.getY() - 1); - mineX.set(pos.getX() - currentRadius); - mineZ.set(pos.getZ() - currentRadius); - mineY.set(pos.getY() - 1); - } - - /** - * Checks if the current coordinates are invalid - * - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @return {@code true} if the coordinates are invalid, else false - */ - private static boolean checkCoordinatesInvalid(@NotNull AtomicInteger x, @NotNull AtomicInteger y, - @NotNull AtomicInteger z) { - return x.get() == Integer.MAX_VALUE && y.get() == Integer.MAX_VALUE && z.get() == Integer.MAX_VALUE; - } - - /** - * Checks whether there are any more blocks to mine, if there are currently none queued - */ - public void checkBlocksToMine() { - if (blocksToMine.isEmpty()) - blocksToMine.addAll(getBlocksToMine()); - } - - /** - * Recalculates the mining area, refills the block list and restarts the miner, if it was done - */ - public void resetArea() { - initPos(metaTileEntity.getPos(), currentRadius); - if (this.isDone) this.setWorkingEnabled(false); - this.isDone = false; - blocksToMine.clear(); - checkBlocksToMine(); - resetPipeLength(); - } - - /** - * Gets the blocks to mine - * - * @return a {@link LinkedList} of {@link BlockPos} for each ore to mine - */ - private LinkedList getBlocksToMine() { - LinkedList blocks = new LinkedList<>(); - - // determine how many blocks to retrieve this time - double quotient = getQuotient(getMeanTickTime(metaTileEntity.getWorld())); - int calcAmount = quotient < 1 ? 1 : (int) (Math.min(quotient, Short.MAX_VALUE)); - int calculated = 0; - - // keep getting blocks until the target amount is reached - while (calculated < calcAmount) { - // moving down the y-axis - if (y.get() > 0) { - // moving across the z-axis - if (z.get() <= startZ.get() + currentRadius * 2) { - // check every block along the x-axis - if (x.get() <= startX.get() + currentRadius * 2) { - BlockPos blockPos = new BlockPos(x.get(), y.get(), z.get()); - IBlockState state = metaTileEntity.getWorld().getBlockState(blockPos); - if (state.getBlock().blockHardness >= 0 && - metaTileEntity.getWorld().getTileEntity(blockPos) == null && - GTUtility.isOre(GTUtility.toItem(state))) { - blocks.addLast(blockPos); - } - // move to the next x position - x.incrementAndGet(); - } else { - // reset x and move to the next z layer - x.set(startX.get()); - z.incrementAndGet(); - } - } else { - // reset z and move to the next y layer - z.set(startZ.get()); - y.decrementAndGet(); - } - } else - return blocks; - - // only count iterations where blocks were found - if (!blocks.isEmpty()) - calculated++; - } - return blocks; - } - - /** - * @param values to find the mean of - * @return the mean value - */ - private static long mean(@NotNull long[] values) { - if (values.length == 0L) - return 0L; - - long sum = 0L; - for (long v : values) - sum += v; - return sum / values.length; - } - - /** - * @param world the {@link World} to get the average tick time of - * @return the mean tick time - */ - private static double getMeanTickTime(@NotNull World world) { - return mean(Objects.requireNonNull(world.getMinecraftServer()).tickTimeArray) * 1.0E-6D; - } - - /** - * gets the quotient for determining the amount of blocks to mine - * - * @param base is a value used for calculation, intended to be the mean tick time of the world the miner is in - * @return the quotient - */ - private static double getQuotient(double base) { - return DIVIDEND / Math.pow(base, POWER); - } - - /** - * Applies a fortune hammer to block drops based on a tier value, intended for small ores - * - * @param blockState the block being mined - * @param drops where the drops are stored to - * @param fortuneLevel the level of fortune used - * @param map the recipemap from which to get the drops - * @param tier the tier at which the operation is performed, used for calculating the chanced output boost - */ - protected static void applyTieredHammerNoRandomDrops(@NotNull IBlockState blockState, List drops, - int fortuneLevel, @NotNull RecipeMap map, int tier) { - ItemStack itemStack = GTUtility.toItem(blockState); - Recipe recipe = map.findRecipe(Long.MAX_VALUE, Collections.singletonList(itemStack), Collections.emptyList()); - if (recipe != null && !recipe.getOutputs().isEmpty()) { - drops.clear(); - for (ItemStack outputStack : recipe.getResultItemOutputs(GTUtility.getTierByVoltage(recipe.getEUt()), tier, - map)) { - outputStack = outputStack.copy(); - if (OreDictUnifier.getPrefix(outputStack) == OrePrefix.crushed) { - if (fortuneLevel > 0) { - outputStack.grow(outputStack.getCount() * fortuneLevel); - } - } - drops.add(outputStack); - } - } - } - - /** - * Increments the pipe rendering length by one, signaling that the miner's y level has moved down by one - */ - private void incrementPipeLength() { - this.pipeLength++; - this.metaTileEntity.writeCustomData(GregtechDataCodes.PUMP_HEAD_LEVEL, b -> b.writeInt(pipeLength)); - this.metaTileEntity.markDirty(); - } - - /** - * Resets the pipe length to zero - */ - private void resetPipeLength() { - this.pipeLength = 0; - this.metaTileEntity.writeCustomData(GregtechDataCodes.PUMP_HEAD_LEVEL, b -> b.writeInt(pipeLength)); - this.metaTileEntity.markDirty(); - } - - /** - * renders the pipe beneath the miner - */ - @SideOnly(Side.CLIENT) - public void renderPipe(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { - Textures.PIPE_IN_OVERLAY.renderSided(EnumFacing.DOWN, renderState, translation, pipeline); - for (int i = 0; i < this.pipeLength; i++) { - translation.translate(0.0, -1.0, 0.0); - getPipeTexture().render(renderState, translation, pipeline, IMiner.PIPE_CUBOID); - } - } - - @SideOnly(Side.CLIENT) - protected ICubeRenderer getPipeTexture() { - return PIPE_TEXTURE; - } - - /** - * writes all needed values to NBT - * This MUST be called and returned in the MetaTileEntity's {@link MetaTileEntity#writeToNBT(NBTTagCompound)} method - */ - public NBTTagCompound writeToNBT(@NotNull NBTTagCompound data) { - data.setTag("xPos", new NBTTagInt(x.get())); - data.setTag("yPos", new NBTTagInt(y.get())); - data.setTag("zPos", new NBTTagInt(z.get())); - data.setTag("mxPos", new NBTTagInt(mineX.get())); - data.setTag("myPos", new NBTTagInt(mineY.get())); - data.setTag("mzPos", new NBTTagInt(mineZ.get())); - data.setTag("sxPos", new NBTTagInt(startX.get())); - data.setTag("syPos", new NBTTagInt(startY.get())); - data.setTag("szPos", new NBTTagInt(startZ.get())); - data.setTag("tempY", new NBTTagInt(pipeY.get())); - data.setTag("isActive", new NBTTagInt(this.isActive ? 1 : 0)); - data.setTag("isWorkingEnabled", new NBTTagInt(this.isWorkingEnabled ? 1 : 0)); - data.setTag("wasActiveAndNeedsUpdate", new NBTTagInt(this.wasActiveAndNeedsUpdate ? 1 : 0)); - data.setTag("pipeLength", new NBTTagInt(pipeLength)); - data.setTag("currentRadius", new NBTTagInt(currentRadius)); - data.setTag("isDone", new NBTTagInt(isDone ? 1 : 0)); - return data; - } - - /** - * reads all needed values from NBT - * This MUST be called and returned in the MetaTileEntity's {@link MetaTileEntity#readFromNBT(NBTTagCompound)} - * method - */ - public void readFromNBT(@NotNull NBTTagCompound data) { - x.set(data.getInteger("xPos")); - y.set(data.getInteger("yPos")); - z.set(data.getInteger("zPos")); - mineX.set(data.getInteger("mxPos")); - mineY.set(data.getInteger("myPos")); - mineZ.set(data.getInteger("mzPos")); - startX.set(data.getInteger("sxPos")); - startY.set(data.getInteger("syPos")); - startZ.set(data.getInteger("szPos")); - pipeY.set(data.getInteger("tempY")); - setActive(data.getInteger("isActive") != 0); - setWorkingEnabled(data.getInteger("isWorkingEnabled") != 0); - setWasActiveAndNeedsUpdate(data.getInteger("wasActiveAndNeedsUpdate") != 0); - pipeLength = data.getInteger("pipeLength"); - this.currentRadius = data.getInteger("currentRadius"); - this.isDone = data.getInteger("isDone") != 0; - } - - /** - * writes all needed values to InitialSyncData - * This MUST be called and returned in the MetaTileEntity's - * {@link MetaTileEntity#writeInitialSyncData(PacketBuffer)} method - */ - public void writeInitialSyncData(@NotNull PacketBuffer buf) { - buf.writeInt(pipeLength); - buf.writeBoolean(this.isActive); - buf.writeBoolean(this.isWorkingEnabled); - buf.writeBoolean(this.wasActiveAndNeedsUpdate); - } - - /** - * reads all needed values from InitialSyncData - * This MUST be called and returned in the MetaTileEntity's - * {@link MetaTileEntity#receiveInitialSyncData(PacketBuffer)} method - */ - public void receiveInitialSyncData(@NotNull PacketBuffer buf) { - this.pipeLength = buf.readInt(); - setActive(buf.readBoolean()); - setWorkingEnabled(buf.readBoolean()); - setWasActiveAndNeedsUpdate(buf.readBoolean()); - } - - /** - * reads all needed values from CustomData - * This MUST be called and returned in the MetaTileEntity's - * {@link MetaTileEntity#receiveCustomData(int, PacketBuffer)} method - */ - public void receiveCustomData(int dataId, PacketBuffer buf) { - if (dataId == GregtechDataCodes.PUMP_HEAD_LEVEL) { - this.pipeLength = buf.readInt(); - metaTileEntity.scheduleRenderUpdate(); - } else if (dataId == GregtechDataCodes.WORKABLE_ACTIVE) { - this.isActive = buf.readBoolean(); - metaTileEntity.scheduleRenderUpdate(); - } else if (dataId == GregtechDataCodes.WORKING_ENABLED) { - this.isWorkingEnabled = buf.readBoolean(); - metaTileEntity.scheduleRenderUpdate(); - } - } - - /** - * @return the current x value - */ - public AtomicInteger getX() { - return x; - } - - /** - * @return the current y value - */ - public AtomicInteger getY() { - return y; - } - - /** - * @return the current z value - */ - public AtomicInteger getZ() { - return z; - } - - /** - * @return the previously mined x value - */ - public AtomicInteger getMineX() { - return mineX; - } - - /** - * @return the previously mined y value - */ - public AtomicInteger getMineY() { - return mineY; - } - - /** - * @return the previously mined z value - */ - public AtomicInteger getMineZ() { - return mineZ; - } - - /** - * @return the starting x value - */ - public AtomicInteger getStartX() { - return startX; - } - - /** - * @return the starting y value - */ - public AtomicInteger getStartY() { - return startY; - } - - /** - * @return the starting z value - */ - public AtomicInteger getStartZ() { - return startZ; - } - - /** - * @return the pipe y value - */ - public AtomicInteger getPipeY() { - return pipeY; - } - - /** - * @return the miner's maximum radius - */ - public int getMaximumRadius() { - return this.maximumRadius; - } - - /** - * @return the miner's current radius - */ - public int getCurrentRadius() { - return this.currentRadius; - } - - /** - * @param currentRadius the radius to set the miner to use - */ - public void setCurrentRadius(int currentRadius) { - this.currentRadius = currentRadius; - } - - /** - * @return true if the miner is finished working - */ - public boolean isDone() { - return this.isDone; - } - - /** - * @return true if the miner is active - */ - public boolean isActive() { - return this.isActive; - } - - /** - * @param isActive the new state of the miner's activity: true to change to active, else false - */ - public void setActive(boolean isActive) { - if (this.isActive != isActive) { - this.isActive = isActive; - this.metaTileEntity.markDirty(); - if (metaTileEntity.getWorld() != null && !metaTileEntity.getWorld().isRemote) { - this.metaTileEntity.writeCustomData(GregtechDataCodes.WORKABLE_ACTIVE, - buf -> buf.writeBoolean(isActive)); - } - } - } - - /** - * @param isWorkingEnabled the new state of the miner's ability to work: true to change to enabled, else false - */ - public void setWorkingEnabled(boolean isWorkingEnabled) { - if (this.isWorkingEnabled != isWorkingEnabled) { - this.isWorkingEnabled = isWorkingEnabled; - metaTileEntity.markDirty(); - if (metaTileEntity.getWorld() != null && !metaTileEntity.getWorld().isRemote) { - if (!isWorkingEnabled) resetArea(); - - this.metaTileEntity.writeCustomData(GregtechDataCodes.WORKING_ENABLED, - buf -> buf.writeBoolean(isWorkingEnabled)); - } - } - } - - /** - * @return whether working is enabled for the logic - */ - public boolean isWorkingEnabled() { - return isWorkingEnabled; - } - - /** - * @return whether the miner is currently working - */ - public boolean isWorking() { - return isActive && isWorkingEnabled; - } - - /** - * @return whether the miner was active and needs an update - */ - public boolean wasActiveAndNeedsUpdate() { - return this.wasActiveAndNeedsUpdate; - } - - /** - * set whether the miner was active and needs an update - * - * @param wasActiveAndNeedsUpdate the state to set - */ - public void setWasActiveAndNeedsUpdate(boolean wasActiveAndNeedsUpdate) { - this.wasActiveAndNeedsUpdate = wasActiveAndNeedsUpdate; - } - - /** - * @return the miner's fortune level - */ - public int getFortune() { - return this.fortune; - } - - /** - * @return the miner's speed in ticks - */ - public int getSpeed() { - return this.speed; - } -} diff --git a/src/main/java/gregtech/api/capability/impl/miner/MultiblockMinerLogic.java b/src/main/java/gregtech/api/capability/impl/miner/MultiblockMinerLogic.java deleted file mode 100644 index 6585c7e93cc..00000000000 --- a/src/main/java/gregtech/api/capability/impl/miner/MultiblockMinerLogic.java +++ /dev/null @@ -1,160 +0,0 @@ -package gregtech.api.capability.impl.miner; - -import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.api.metatileentity.multiblock.MultiblockControllerBase; -import gregtech.api.recipes.RecipeMap; -import gregtech.client.renderer.ICubeRenderer; - -import net.minecraft.block.state.IBlockState; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.NonNullList; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.WorldServer; -import net.minecraft.world.chunk.Chunk; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -import org.jetbrains.annotations.NotNull; - -public class MultiblockMinerLogic extends MinerLogic { - - private static final int CHUNK_LENGTH = 16; - - private final RecipeMap blockDropRecipeMap; - - private int voltageTier; - private int overclockAmount = 0; - - private boolean isChunkMode; - private boolean isSilkTouchMode; - - /** - * Creates the logic for multiblock ore block miners - * - * @param metaTileEntity the {@link MetaTileEntity} this logic belongs to - * @param fortune the fortune amount to apply when mining ores - * @param speed the speed in ticks per block mined - * @param maximumRadius the maximum radius (square shaped) the miner can mine in - */ - public MultiblockMinerLogic(MetaTileEntity metaTileEntity, int fortune, int speed, int maximumRadius, - RecipeMap blockDropRecipeMap) { - super(metaTileEntity, fortune, speed, maximumRadius, null); - this.blockDropRecipeMap = blockDropRecipeMap; - } - - @Override - protected boolean drainStorages(boolean simulate) { - return super.drainStorages(simulate) && miner.drainFluid(simulate); - } - - @Override - protected void getSmallOreBlockDrops(NonNullList blockDrops, WorldServer world, BlockPos blockToMine, - IBlockState blockState) { - // Small ores: use (fortune bonus + overclockAmount) value here for fortune, since every overclock increases the - // yield for small ores - super.getSmallOreBlockDrops(blockDrops, world, blockToMine, blockState); - } - - @Override - protected void getRegularBlockDrops(NonNullList blockDrops, WorldServer world, BlockPos blockToMine, - @NotNull IBlockState blockState) { - if (!isSilkTouchMode) // 3X the ore compared to the single blocks - applyTieredHammerNoRandomDrops(blockState, blockDrops, 3, this.blockDropRecipeMap, this.voltageTier); - else - super.getRegularBlockDrops(blockDrops, world, blockToMine, blockState); - } - - @Override - public void initPos(@NotNull BlockPos pos, int currentRadius) { - if (!isChunkMode) { - super.initPos(pos, currentRadius); - } else { - WorldServer world = (WorldServer) this.metaTileEntity.getWorld(); - Chunk origin = world.getChunk(this.metaTileEntity.getPos()); - ChunkPos startPos = (world.getChunk(origin.x - currentRadius / CHUNK_LENGTH, - origin.z - currentRadius / CHUNK_LENGTH)).getPos(); - getX().set(startPos.getXStart()); - getY().set(this.metaTileEntity.getPos().getY() - 1); - getZ().set(startPos.getZStart()); - getStartX().set(startPos.getXStart()); - getStartY().set(this.metaTileEntity.getPos().getY()); - getStartZ().set(startPos.getZStart()); - getMineX().set(startPos.getXStart()); - getMineY().set(this.metaTileEntity.getPos().getY() - 1); - getMineZ().set(startPos.getZStart()); - getPipeY().set(this.metaTileEntity.getPos().getY() - 1); - } - } - - public void setVoltageTier(int tier) { - this.voltageTier = tier; - } - - public void setOverclockAmount(int amount) { - this.overclockAmount = amount; - } - - public int getOverclockAmount() { - return this.overclockAmount; - } - - public boolean isChunkMode() { - return this.isChunkMode; - } - - public void setChunkMode(boolean isChunkMode) { - if (!isWorking()) { - this.isChunkMode = isChunkMode; - if (!metaTileEntity.getWorld().isRemote) { - resetArea(); - } - } - } - - public boolean isSilkTouchMode() { - return this.isSilkTouchMode; - } - - public void setSilkTouchMode(boolean isSilkTouchMode) { - if (!isWorking()) { - this.isSilkTouchMode = isSilkTouchMode; - } - } - - @SideOnly(Side.CLIENT) - @Override - protected ICubeRenderer getPipeTexture() { - return ((MultiblockControllerBase) metaTileEntity).getBaseTexture(null); - } - - @Override - public NBTTagCompound writeToNBT(@NotNull NBTTagCompound data) { - data.setBoolean("isChunkMode", isChunkMode); - data.setBoolean("isSilkTouchMode", isSilkTouchMode); - return super.writeToNBT(data); - } - - @Override - public void readFromNBT(@NotNull NBTTagCompound data) { - this.isChunkMode = data.getBoolean("isChunkMode"); - this.isSilkTouchMode = data.getBoolean("isSilkTouchMode"); - super.readFromNBT(data); - } - - @Override - public void writeInitialSyncData(@NotNull PacketBuffer buf) { - super.writeInitialSyncData(buf); - buf.writeBoolean(this.isChunkMode); - buf.writeBoolean(this.isSilkTouchMode); - } - - @Override - public void receiveInitialSyncData(@NotNull PacketBuffer buf) { - super.receiveInitialSyncData(buf); - this.isChunkMode = buf.readBoolean(); - this.isSilkTouchMode = buf.readBoolean(); - } -} diff --git a/src/main/java/gregtech/api/capability/impl/miner/SteamMinerLogic.java b/src/main/java/gregtech/api/capability/impl/miner/SteamMinerLogic.java deleted file mode 100644 index 3d20620db2a..00000000000 --- a/src/main/java/gregtech/api/capability/impl/miner/SteamMinerLogic.java +++ /dev/null @@ -1,39 +0,0 @@ -package gregtech.api.capability.impl.miner; - -import gregtech.api.capability.IVentable; -import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.client.renderer.ICubeRenderer; - -public class SteamMinerLogic extends MinerLogic { - - /** - * Creates the logic for steam miners - * - * @param metaTileEntity the {@link MetaTileEntity} this logic belongs to - * @param fortune the fortune amount to apply when mining ores - * @param speed the speed in ticks per block mined - * @param maximumRadius the maximum radius (square shaped) the miner can mine in - */ - public SteamMinerLogic(MetaTileEntity metaTileEntity, int fortune, int speed, int maximumRadius, - ICubeRenderer pipeTexture) { - super(metaTileEntity, fortune, speed, maximumRadius, pipeTexture); - } - - @Override - protected boolean checkCanMine() { - IVentable machine = (IVentable) metaTileEntity; - if (machine.isNeedsVenting()) { - machine.tryDoVenting(); - if (machine.isVentingStuck()) - return false; - } - - return super.checkCanMine(); - } - - @Override - protected void onMineOperation() { - super.onMineOperation(); - ((IVentable) metaTileEntity).setNeedsVenting(true); - } -} diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index e85bffcfe97..a24a26cb099 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -116,8 +116,10 @@ public class GuiTextures { public static final TextureArea BUTTON_NO_FLEX = TextureArea.fullImage("textures/gui/widget/button_no_flex.png"); public static final TextureArea BUTTON_MULTI_MAP = TextureArea .fullImage("textures/gui/widget/button_multi_map.png"); - public static final TextureArea BUTTON_MINER_MODES = TextureArea - .fullImage("textures/gui/widget/button_miner_modes.png"); + public static final TextureArea BUTTON_MINER_AREA_PREVIEW = TextureArea + .fullImage("textures/gui/widget/button_miner_area_preview.png"); + public static final TextureArea BUTTON_MINER_CONFIG_MODE = TextureArea + .fullImage("textures/gui/widget/button_miner_config_mode.png"); public static final TextureArea BUTTON_THROTTLE_MINUS = TextureArea .fullImage("textures/gui/widget/button_throttle_minus.png"); public static final TextureArea BUTTON_THROTTLE_PLUS = TextureArea @@ -408,6 +410,8 @@ public class GuiTextures { .fullImage("textures/gui/progress_bar/progress_bar_turbine_rotor_durability.png"); public static final TextureArea PROGRESS_BAR_FLUID_RIG_DEPLETION = TextureArea .fullImage("textures/gui/progress_bar/progress_bar_fluid_rig_depletion.png"); + public static final TextureArea PROGRESS_BAR_MINER_DRILLING_FLUID = TextureArea + .fullImage("textures/gui/progress_bar/progress_bar_miner_drilling_fluid.png"); // Fusion reactor diagram progress bar parts public static final TextureArea PROGRESS_BAR_FUSION_REACTOR_DIAGRAM_BL = TextureArea diff --git a/src/main/java/gregtech/api/unification/OreDictUnifier.java b/src/main/java/gregtech/api/unification/OreDictUnifier.java index a945fe5b4f5..54d00cd5a81 100644 --- a/src/main/java/gregtech/api/unification/OreDictUnifier.java +++ b/src/main/java/gregtech/api/unification/OreDictUnifier.java @@ -172,11 +172,15 @@ public static void onItemRegistration(OreRegisterEvent event) { @NotNull public static Set getOreDictionaryNames(@NotNull ItemStack itemStack) { if (itemStack.isEmpty()) return Collections.emptySet(); - ItemVariantMap> nameEntry = stackOreDictName.get(itemStack.getItem()); + return getOreDictionaryNames(itemStack.getItem(), itemStack.getItemDamage()); + } + + @NotNull + public static Set getOreDictionaryNames(@NotNull Item item, int metadata) { + ItemVariantMap> nameEntry = stackOreDictName.get(item); if (nameEntry == null) return Collections.emptySet(); - short itemDamage = (short) itemStack.getItemDamage(); - Set names = nameEntry.get(itemDamage); - Set wildcardNames = itemDamage == GTValues.W ? null : nameEntry.get(GTValues.W); + Set names = nameEntry.get((short) metadata); + Set wildcardNames = metadata == GTValues.W ? null : nameEntry.get(GTValues.W); if (names == null) { return wildcardNames == null ? Collections.emptySet() : Collections.unmodifiableSet(wildcardNames); } else if (wildcardNames == null || names == wildcardNames) { // single variant items have identical entries @@ -225,8 +229,12 @@ public static List getAllWithOreDictionaryName(String oreDictionaryNa @Nullable public static MaterialStack getMaterial(ItemStack itemStack) { - if (itemStack.isEmpty()) return null; - ItemAndMetadata key = new ItemAndMetadata(itemStack); + return itemStack.isEmpty() ? null : getMaterial(itemStack.getItem(), itemStack.getItemDamage()); + } + + @Nullable + public static MaterialStack getMaterial(@NotNull Item item, int metadata) { + ItemAndMetadata key = new ItemAndMetadata(item, metadata); UnificationEntry entry = getOrWildcard(stackUnificationInfo, key); if (entry != null) { Material entryMaterial = entry.material; @@ -248,9 +256,13 @@ public static ItemMaterialInfo getMaterialInfo(ItemStack itemStack) { } @Nullable - public static OrePrefix getPrefix(ItemStack itemStack) { - if (itemStack.isEmpty()) return null; - UnificationEntry entry = getOrWildcard(stackUnificationInfo, new ItemAndMetadata(itemStack)); + public static OrePrefix getPrefix(@NotNull ItemStack itemStack) { + return itemStack.isEmpty() ? null : getPrefix(itemStack.getItem(), itemStack.getItemDamage()); + } + + @Nullable + public static OrePrefix getPrefix(@NotNull Item item, int metadata) { + UnificationEntry entry = getOrWildcard(stackUnificationInfo, new ItemAndMetadata(item, metadata)); return entry != null ? entry.orePrefix : null; } diff --git a/src/main/java/gregtech/api/unification/stack/ItemAndMetadata.java b/src/main/java/gregtech/api/unification/stack/ItemAndMetadata.java index d1ac6e8179e..f826854d41b 100644 --- a/src/main/java/gregtech/api/unification/stack/ItemAndMetadata.java +++ b/src/main/java/gregtech/api/unification/stack/ItemAndMetadata.java @@ -44,20 +44,13 @@ public ItemAndMetadata toWildcard() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ItemAndMetadata)) return false; - - ItemAndMetadata that = (ItemAndMetadata) o; - - if (itemDamage != that.itemDamage) return false; - return item.equals(that.item); + return this == o || + o instanceof ItemAndMetadata that && itemDamage == that.itemDamage && item.equals(that.item); } @Override public int hashCode() { - int result = item.hashCode(); - result = 31 * result + itemDamage; - return result; + return 31 * item.hashCode() + itemDamage; } @Override diff --git a/src/main/java/gregtech/api/util/BlockUtility.java b/src/main/java/gregtech/api/util/BlockUtility.java index 77b816da15a..1dcc43cc531 100644 --- a/src/main/java/gregtech/api/util/BlockUtility.java +++ b/src/main/java/gregtech/api/util/BlockUtility.java @@ -1,11 +1,17 @@ package gregtech.api.util; +import gregtech.api.unification.OreDictUnifier; +import gregtech.api.unification.ore.OrePrefix; + import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.NonNullList; +import it.unimi.dsi.fastutil.objects.Object2BooleanMap; +import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2DoubleMap; import it.unimi.dsi.fastutil.objects.Object2DoubleMaps; import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap; @@ -17,8 +23,9 @@ public class BlockUtility { private static final BlockWrapper WRAPPER = new BlockWrapper(); - + private static final Object2BooleanMap ORE_CACHE = new Object2BooleanOpenHashMap<>(); private static final Object2DoubleMap walkingSpeedBonusInternal = new Object2DoubleOpenHashMap<>(); + /** * View-only collection of block states that give speed bonus when walking over it. The bonus value is a percentage * value that gets added to the player speed; for example, a bonus value of {@link 0.25} will add 25% of extra speed @@ -41,27 +48,35 @@ public class BlockUtility { */ public static final double STUDS_WALKING_SPEED_BONUS = 0.25; - private static class BlockWrapper extends Block { - - public BlockWrapper() { - super(Material.AIR); - } - - @NotNull - @Override - public NonNullList captureDrops(boolean start) { - return super.captureDrops(start); - } - } - public static void startCaptureDrops() { WRAPPER.captureDrops(true); } + @NotNull public static NonNullList stopCaptureDrops() { return WRAPPER.captureDrops(false); } + public static boolean isOre(@NotNull IBlockState state) { + return ORE_CACHE.computeIfAbsent(Objects.requireNonNull(state, "state == null"), s -> { + Item item = Item.getItemFromBlock(s.getBlock()); + int meta = s.getBlock().getMetaFromState(s); + OrePrefix orePrefix = OreDictUnifier.getPrefix(item, meta); + return orePrefix != null && orePrefix.name().startsWith("ore"); + }); + } + + /** + * Mark a block state as an ore / not an ore, for miners and prospectors. + * + * @param state A block state + * @param isOre Whether this block state is an ore or not + * @throws NullPointerException if {@code state == null} + */ + public static void markBlockstateAsOre(@NotNull IBlockState state, boolean isOre) { + ORE_CACHE.put(Objects.requireNonNull(state, "state == null"), isOre); + } + /** * Set walking speed bonus for the block state. The bonus value is a percentage value that gets added to the player * speed; for example, a bonus value of {@link 0.25} will add 25% of extra speed to the player. @@ -80,4 +95,17 @@ public static void setWalkingSpeedBonus(@NotNull IBlockState state, double amoun walkingSpeedBonusInternal.put(state, amount); } } + + private static class BlockWrapper extends Block { + + public BlockWrapper() { + super(Material.AIR); + } + + @NotNull + @Override + public NonNullList captureDrops(boolean start) { + return super.captureDrops(start); + } + } } diff --git a/src/main/java/gregtech/api/util/GTUtility.java b/src/main/java/gregtech/api/util/GTUtility.java index 2b95a31fe0f..917604be7f7 100644 --- a/src/main/java/gregtech/api/util/GTUtility.java +++ b/src/main/java/gregtech/api/util/GTUtility.java @@ -5,6 +5,7 @@ import gregtech.api.block.machines.MachineItemBlock; import gregtech.api.capability.IMultipleTankHandler; import gregtech.api.cover.CoverDefinition; +import gregtech.api.damagesources.DamageSources; import gregtech.api.fluids.GTFluid; import gregtech.api.gui.widgets.ProgressWidget; import gregtech.api.items.behavior.CoverItemBehavior; @@ -18,12 +19,16 @@ import gregtech.api.recipes.RecipeMap; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.ore.OrePrefix; +import gregtech.core.advancement.AdvancementTriggers; +import net.minecraft.block.Block; import net.minecraft.block.BlockRedstoneWire; import net.minecraft.block.BlockSnow; import net.minecraft.block.material.MapColor; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.init.SoundEvents; import net.minecraft.inventory.Slot; @@ -32,14 +37,13 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.SoundCategory; +import net.minecraft.util.*; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import net.minecraft.world.WorldServer; import net.minecraft.world.biome.Biome; import net.minecraftforge.common.BiomeDictionary; import net.minecraftforge.common.util.Constants; @@ -630,7 +634,11 @@ public static ItemStack toItem(IBlockState state, int amount) { return new ItemStack(state.getBlock(), amount, state.getBlock().getMetaFromState(state)); } - public static boolean isOre(ItemStack item) { + /** + * @deprecated use {@link BlockUtility#isOre(IBlockState)} or check it yourself + */ + @Deprecated + public static boolean isOre(@NotNull ItemStack item) { OrePrefix orePrefix = OreDictUnifier.getPrefix(item); return orePrefix != null && orePrefix.name().startsWith("ore"); } @@ -763,6 +771,54 @@ public static boolean isBlockSnow(@NotNull IBlockState blockState) { return blockState.getBlock() == Blocks.SNOW_LAYER || blockState.getBlock() == Blocks.SNOW; } + /** + * Try to vent. Also does venting things (spawning particles, playing sounds, damaging entities etc.) on success. + * + * @param world World + * @param machinePos Position of the machine + * @param ventingSide Venting side + * @param ventingDamage Damage to be applied on entities in the venting block; default value is {@code 6} for + * regular steam machines, and {@code 12} for high-pressure steam machines. + * @param spawnParticle Whether to spawn particles or not + * @param playSound Whether to play sounds or not + * @return {@code true} if vented + */ + public static boolean tryVenting(@NotNull World world, @NotNull BlockPos machinePos, + @NotNull EnumFacing ventingSide, float ventingDamage, + boolean spawnParticle, boolean playSound) { + BlockPos ventingPos = machinePos.offset(ventingSide); + IBlockState ventingState = world.getBlockState(ventingPos); + if (ventingState.getCollisionBoundingBox(world, ventingPos) == Block.NULL_AABB || + tryBreakSnow(world, ventingPos, ventingState, false)) { + if (ventingDamage > 0) { + for (EntityLivingBase entity : world.getEntitiesWithinAABB(EntityLivingBase.class, + new AxisAlignedBB(ventingPos), EntitySelectors.CAN_AI_TARGET)) { + entity.attackEntityFrom(DamageSources.getHeatDamage(), ventingDamage); + if (entity instanceof EntityPlayerMP player) { + AdvancementTriggers.STEAM_VENT_DEATH.trigger(player); + } + } + } + double posX = machinePos.getX() + 0.5 + ventingSide.getXOffset() * 0.6; + double posY = machinePos.getY() + 0.5 + ventingSide.getYOffset() * 0.6; + double posZ = machinePos.getZ() + 0.5 + ventingSide.getZOffset() * 0.6; + + if (spawnParticle && world instanceof WorldServer worldServer) { + worldServer.spawnParticle(EnumParticleTypes.CLOUD, posX, posY, posZ, + 7 + world.rand.nextInt(3), + ventingSide.getXOffset() / 2.0, + ventingSide.getYOffset() / 2.0, + ventingSide.getZOffset() / 2.0, 0.1); + } + if (playSound) { + world.playSound(null, posX, posY, posZ, SoundEvents.BLOCK_LAVA_EXTINGUISH, SoundCategory.BLOCKS, 1.0f, + 1.0f); + } + return true; + } + return false; + } + /** * Attempt to break a (single) snow layer at the given BlockPos. * Will also turn snow blocks into snow layers at height 7. diff --git a/src/main/java/gregtech/client/ClientProxy.java b/src/main/java/gregtech/client/ClientProxy.java index 0210563b18c..0e08caf1a3b 100644 --- a/src/main/java/gregtech/client/ClientProxy.java +++ b/src/main/java/gregtech/client/ClientProxy.java @@ -13,6 +13,7 @@ import gregtech.api.util.ModCompatibility; import gregtech.client.model.customtexture.CustomTextureModelHandler; import gregtech.client.model.customtexture.MetadataSectionCTM; +import gregtech.client.model.miningpipe.MiningPipeModels; import gregtech.client.renderer.handler.FacadeRenderer; import gregtech.client.renderer.handler.MetaTileEntityRenderer; import gregtech.client.renderer.pipe.*; @@ -89,6 +90,7 @@ public void onPreLoad() { MetaEntities.initRenderers(); TextureUtils.addIconRegister(GTFluidRegistration.INSTANCE::registerSprites); TextureUtils.addIconRegister(PipeRenderer::initializeRestrictor); + MiningPipeModels.init(); } @Override diff --git a/src/main/java/gregtech/client/model/miningpipe/MiningPipeModel.java b/src/main/java/gregtech/client/model/miningpipe/MiningPipeModel.java new file mode 100644 index 00000000000..934e6d60ffb --- /dev/null +++ b/src/main/java/gregtech/client/model/miningpipe/MiningPipeModel.java @@ -0,0 +1,14 @@ +package gregtech.client.model.miningpipe; + +import net.minecraft.client.renderer.block.model.IBakedModel; + +import org.jetbrains.annotations.NotNull; + +public interface MiningPipeModel { + + @NotNull + IBakedModel getBaseModel(); + + @NotNull + IBakedModel getBottomModel(); +} diff --git a/src/main/java/gregtech/client/model/miningpipe/MiningPipeModels.java b/src/main/java/gregtech/client/model/miningpipe/MiningPipeModels.java new file mode 100644 index 00000000000..7574d677e49 --- /dev/null +++ b/src/main/java/gregtech/client/model/miningpipe/MiningPipeModels.java @@ -0,0 +1,12 @@ +package gregtech.client.model.miningpipe; + +public class MiningPipeModels { + + private MiningPipeModels() {} + + public static void init() {} + + public static final SimpleMiningPipeModel STEEL = SimpleMiningPipeModel.register("steel"); + public static final SimpleMiningPipeModel TITANIUM = SimpleMiningPipeModel.register("titanium"); + public static final SimpleMiningPipeModel TUNGSTEN_STEEL = SimpleMiningPipeModel.register("tungsten_steel"); +} diff --git a/src/main/java/gregtech/client/model/miningpipe/SimpleMiningPipeModel.java b/src/main/java/gregtech/client/model/miningpipe/SimpleMiningPipeModel.java new file mode 100644 index 00000000000..46b7d061204 --- /dev/null +++ b/src/main/java/gregtech/client/model/miningpipe/SimpleMiningPipeModel.java @@ -0,0 +1,118 @@ +package gregtech.client.model.miningpipe; + +import gregtech.api.GTValues; +import gregtech.api.util.GTLog; +import gregtech.api.util.GTUtility; + +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.event.ModelBakeEvent; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.client.model.IModel; +import net.minecraftforge.client.model.ModelLoader; +import net.minecraftforge.client.model.ModelLoaderRegistry; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; + +import com.google.common.base.Suppliers; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.function.Supplier; + +@Mod.EventBusSubscriber(modid = GTValues.MODID, value = Side.CLIENT) +public final class SimpleMiningPipeModel implements MiningPipeModel { + + private static final Map MINING_PIPE_MODELS = new Object2ObjectOpenHashMap<>(); + private static final Supplier MISSING_MODEL_MEMOIZE = Suppliers.memoize(() -> { + IModel model = ModelLoaderRegistry.getMissingModel(); + return model.bake(model.getDefaultState(), DefaultVertexFormats.ITEM, ModelLoader.defaultTextureGetter()); + }); + + @NotNull + public static SimpleMiningPipeModel register(@NotNull String type) { + return MINING_PIPE_MODELS.computeIfAbsent(type, SimpleMiningPipeModel::new); + } + + @NotNull + public final String type; + + @Nullable + private IBakedModel baseModel; + @Nullable + private IModel unbakedBaseModel; + @Nullable + private IBakedModel bottomModel; + @Nullable + private IModel unbakedBottomModel; + + private SimpleMiningPipeModel(@NotNull String type) { + this.type = type; + } + + @NotNull + @Override + public IBakedModel getBaseModel() { + return this.baseModel != null ? this.baseModel : MISSING_MODEL_MEMOIZE.get(); + } + + @NotNull + @Override + public IBakedModel getBottomModel() { + return this.bottomModel != null ? this.bottomModel : MISSING_MODEL_MEMOIZE.get(); + } + + @Override + public String toString() { + return "MiningPipeModel{type='" + type + "'}"; + } + + @SubscribeEvent + public static void onTextureStitch(TextureStitchEvent.Pre event) { + for (SimpleMiningPipeModel miningPipe : MINING_PIPE_MODELS.values()) { + miningPipe.unbakedBaseModel = loadModel(event, + GTUtility.gregtechId("block/mining_pipe/" + miningPipe.type)); + miningPipe.unbakedBottomModel = loadModel(event, + GTUtility.gregtechId("block/mining_pipe/" + miningPipe.type + "_bottom")); + } + } + + @Nullable + private static IModel loadModel(TextureStitchEvent.Pre event, ResourceLocation modelLocation) { + IModel model; + try { + model = ModelLoaderRegistry.getModel(modelLocation); + } catch (Exception e) { + GTLog.logger.error("Failed to load material model {}:", modelLocation, e); + return null; + } + for (ResourceLocation texture : model.getTextures()) { + event.getMap().registerSprite(texture); + } + return model; + } + + @SubscribeEvent + public static void onModelBake(ModelBakeEvent event) { + for (SimpleMiningPipeModel miningPipe : MINING_PIPE_MODELS.values()) { + if (miningPipe.unbakedBaseModel != null) { + miningPipe.baseModel = miningPipe.unbakedBaseModel.bake( + miningPipe.unbakedBaseModel.getDefaultState(), + DefaultVertexFormats.ITEM, + ModelLoader.defaultTextureGetter()); + miningPipe.unbakedBaseModel = null; + } + if (miningPipe.unbakedBottomModel != null) { + miningPipe.bottomModel = miningPipe.unbakedBottomModel.bake( + miningPipe.unbakedBottomModel.getDefaultState(), + DefaultVertexFormats.ITEM, + ModelLoader.defaultTextureGetter()); + miningPipe.unbakedBottomModel = null; + } + } + } +} diff --git a/src/main/java/gregtech/client/renderer/handler/MiningPipeRenderer.java b/src/main/java/gregtech/client/renderer/handler/MiningPipeRenderer.java new file mode 100644 index 00000000000..343760198a0 --- /dev/null +++ b/src/main/java/gregtech/client/renderer/handler/MiningPipeRenderer.java @@ -0,0 +1,48 @@ +package gregtech.client.renderer.handler; + +import gregtech.client.utils.MinerRenderHelper; +import gregtech.common.entities.MiningPipeEntity; + +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.entity.Render; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.util.ResourceLocation; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class MiningPipeRenderer extends Render> { + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Render iHateJavaGenerics(RenderManager manager) { + return (Render) (Render) new MiningPipeRenderer(manager); + } + + public MiningPipeRenderer(RenderManager manager) { + super(manager); + this.shadowSize = 0; + } + + @Override + public void doRender(@NotNull MiningPipeEntity entity, double x, double y, double z, float entityYaw, + float partialTicks) { + boolean renderOutlines = this.renderOutlines; + if (renderOutlines) { + GlStateManager.enableColorMaterial(); + GlStateManager.enableOutlineMode(this.getTeamColor(entity)); + } + + MinerRenderHelper.renderPipe(x, y, z, partialTicks, entity); + + if (renderOutlines) { + GlStateManager.disableOutlineMode(); + GlStateManager.disableColorMaterial(); + } + } + + @Nullable + @Override + protected ResourceLocation getEntityTexture(@NotNull MiningPipeEntity entity) { + return null; + } +} diff --git a/src/main/java/gregtech/client/renderer/texture/Textures.java b/src/main/java/gregtech/client/renderer/texture/Textures.java index 39db1d4f0e2..d8fb67f238d 100644 --- a/src/main/java/gregtech/client/renderer/texture/Textures.java +++ b/src/main/java/gregtech/client/renderer/texture/Textures.java @@ -262,6 +262,7 @@ public class Textures { "machines/world_accelerator"); public static final OrientedOverlayRenderer WORLD_ACCELERATOR_TE_OVERLAY = new OrientedOverlayRenderer( "machines/world_accelerator_te"); + public static final OrientedOverlayRenderer MINER_OVERLAY = new OrientedOverlayRenderer("machines/miner"); // Simple Overlay Renderers public static final SimpleOverlayRenderer SCREEN = new SimpleOverlayRenderer("overlay/machine/overlay_screen"); @@ -418,10 +419,6 @@ public class Textures { "overlay/machine/overlay_maintenance_cleaning"); public static final SimpleOverlayRenderer MUFFLER_OVERLAY = new SimpleOverlayRenderer( "overlay/machine/overlay_muffler"); - public static final SimpleOverlayRenderer STEAM_MINER_OVERLAY = new SimpleOverlayRenderer( - "overlay/machine/overlay_steam_miner"); - public static final SimpleOverlayRenderer CHUNK_MINER_OVERLAY = new SimpleOverlayRenderer( - "overlay/machine/overlay_chunk_miner"); public static final SimpleOverlayRenderer BLANK_SCREEN = new SimpleOverlayRenderer( "overlay/machine/overlay_blank_screen"); public static final SimpleOverlayRenderer DATA_ACCESS_HATCH = new SimpleOverlayRenderer( @@ -501,7 +498,6 @@ public class Textures { "overlay/appeng/me_input_hatch"); public static final SimpleOverlayRenderer ME_OUTPUT_BUS = new SimpleOverlayRenderer("overlay/appeng/me_output_bus"); public static final SimpleOverlayRenderer ME_INPUT_BUS = new SimpleOverlayRenderer("overlay/appeng/me_input_bus"); - public static final ResourceLocation ACE_CAPE_TEXTURE = gregtechId("textures/capes/acecape.png"); public static final ResourceLocation AGENDER_CAPE_TEXTURE = gregtechId("textures/capes/agendercape.png"); public static final ResourceLocation AROMANTIC_CAPE_TEXTURE = gregtechId("textures/capes/aromanticcape.png"); diff --git a/src/main/java/gregtech/client/utils/MinerRenderHelper.java b/src/main/java/gregtech/client/utils/MinerRenderHelper.java new file mode 100644 index 00000000000..fb2db16ad75 --- /dev/null +++ b/src/main/java/gregtech/client/utils/MinerRenderHelper.java @@ -0,0 +1,401 @@ +package gregtech.client.utils; + +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.util.GTUtility; +import gregtech.client.model.miningpipe.MiningPipeModel; +import gregtech.common.entities.MiningPipeEntity; +import gregtech.common.metatileentities.miner.Miner; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.culling.ClippingHelperImpl; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockPos.MutableBlockPos; + +import org.jetbrains.annotations.NotNull; +import org.lwjgl.opengl.GL11; + +import javax.vecmath.Vector3f; + +public class MinerRenderHelper { + + private MinerRenderHelper() {} + + public static final ResourceLocation MINER_AREA_PREVIEW_TEXTURE = GTUtility.gregtechId( + "textures/fx/miner_area_preview.png"); + + private static final long TEXTURE_WRAP_INTERVAL_NANOSECONDS = 3_000_000_000L; + + private static final ClippingHelperImpl clippingHelper = new ClippingHelperImpl(); + + private static final Vector3f[] nearPlaneVectors = { + new Vector3f(), new Vector3f(), new Vector3f(), new Vector3f() + }; + + // 3*4 augmented matrix, last 4 elements are for swap buffer (because im a good progranmer) + private static final float[] mat = new float[16]; + + // reusing static field to prevent heap pollution + private static final SATTestResult sat = new SATTestResult(); + private static final Vector3f vec1 = new Vector3f(), vec2 = new Vector3f(); + + private static int prevFrameIndex = -1; + + private static void updateFrustum() { + int index = Minecraft.getMinecraft().frameTimer.getIndex(); + if (prevFrameIndex == index) return; + prevFrameIndex = index; + clippingHelper.init(); + } + + public static void renderPipe(double x, double y, double z, float partialTicks, + @NotNull MiningPipeEntity entity) { + if (entity.getMTE() == null || entity.length <= 0) return; + updateFrustum(); + + x -= entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks; + y -= entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks; + z -= entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks; + + Minecraft mc = Minecraft.getMinecraft(); + BlockPos origin = entity.getOrigin(); + MutableBlockPos mpos = new MutableBlockPos(origin); + Tessellator t = Tessellator.getInstance(); + BufferBuilder buffer = t.getBuffer(); + MiningPipeModel model = entity.getMTE().getMiningPipeModel(); + + RenderHelper.disableStandardItemLighting(); + GlStateManager.shadeModel(Minecraft.isAmbientOcclusionEnabled() ? GL11.GL_SMOOTH : GL11.GL_FLAT); + GlStateManager.bindTexture(mc.getTextureMapBlocks().getGlTextureId()); + buffer.setTranslation(x, y, z); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); + for (int i = 0, len = entity.length; i < len; i++) { + mpos.setY(entity.y - len + i); + // me epicly dodging AABB allocations by plugging in primitive values directly (very epic) + if (!clippingHelper.isBoxInFrustum( + mpos.getX() + .25 + x, mpos.getY() + y, mpos.getZ() + .25 + z, + mpos.getX() + .75 + x, mpos.getY() + 1 + y, mpos.getZ() + .75 + z)) { + continue; + } + + mc.blockRenderDispatcher.getBlockModelRenderer().renderModel(entity.world, + i == (len - 1) && entity.end ? model.getBottomModel() : model.getBaseModel(), + entity.world.getBlockState(mpos), mpos, buffer, false); + } + buffer.setTranslation(0, 0, 0); + t.draw(); + RenderHelper.enableStandardItemLighting(); + } + + /** + * Draw an area preview. + * + * @param box area + * @param pos block position + * @param x X position; generally {@code cameraX + blockX} + * @param y Y position; generally {@code cameraY + blockY} + * @param z Z position; generally {@code cameraZ + blockZ} + */ + public static void renderAreaPreview(@NotNull AxisAlignedBB box, @NotNull BlockPos pos, + double x, double y, double z) { + // skull emoji + + // positions + double minX = box.minX + x - pos.getX(), maxX = box.maxX + x - pos.getX(); + double minY = Math.max(0, box.minY) + y - pos.getY(), maxY = box.maxY + y - pos.getY(); + double minZ = box.minZ + z - pos.getZ(), maxZ = box.maxZ + z - pos.getZ(); + + boolean isBoxClippingThroughCamera = isBoxClippingThroughCamera(minX, maxX, minY, maxY, minZ, maxZ); + + // texture UVs + double texOffset = (System.nanoTime() % TEXTURE_WRAP_INTERVAL_NANOSECONDS) / + (double) (TEXTURE_WRAP_INTERVAL_NANOSECONDS); + + double dx = (box.maxX - box.minX); + double dy = (box.maxY - Math.max(0, box.minY)); + double dz = (box.maxZ - box.minZ); + + double uMax = texOffset + box.maxX - Math.floor(box.maxX); + double uMax2 = uMax - dy; + double uMin = uMax - dx; + double uMin2 = uMin - dy; + double vMax = texOffset + box.maxZ - Math.floor(box.maxZ); + double vMax2 = vMax - dy; + double vMin = vMax - dz; + double vMin2 = vMin - dy; + double vMin3 = vMin2 + dz; + + GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); + GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); + Minecraft.getMinecraft().getTextureManager().bindTexture(MINER_AREA_PREVIEW_TEXTURE); + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, + DestFactor.ZERO); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + + for (boolean looped = false;; looped = true) { + int alpha = looped ? 70 : 200; + + if (looped) { + GlStateManager.disableDepth(); + // only draw inner parts of the border when camera is inside it + if (isBoxClippingThroughCamera) { + GlStateManager.disableCull(); + } + } + + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_LMAP_COLOR); + + // UP + v(buffer, minX, maxY, maxZ, uMin, vMax, alpha); + v(buffer, maxX, maxY, maxZ, uMax, vMax, alpha); + v(buffer, maxX, maxY, minZ, uMax, vMin, alpha); + v(buffer, minX, maxY, minZ, uMin, vMin, alpha); + + // NORTH + v(buffer, minX, maxY, minZ, uMin, vMin, alpha); + v(buffer, maxX, maxY, minZ, uMax, vMin, alpha); + v(buffer, maxX, minY, minZ, uMax, vMin2, alpha); + v(buffer, minX, minY, minZ, uMin, vMin2, alpha); + + // SOUTH + v(buffer, minX, minY, maxZ, uMin, vMax2, alpha); + v(buffer, maxX, minY, maxZ, uMax, vMax2, alpha); + v(buffer, maxX, maxY, maxZ, uMax, vMax, alpha); + v(buffer, minX, maxY, maxZ, uMin, vMax, alpha); + + // WEST + v(buffer, minX, minY, maxZ, uMin2, vMax, alpha); + v(buffer, minX, maxY, maxZ, uMin, vMax, alpha); + v(buffer, minX, maxY, minZ, uMin, vMin, alpha); + v(buffer, minX, minY, minZ, uMin2, vMin, alpha); + + // EAST + v(buffer, maxX, minY, minZ, uMax2, vMin, alpha); + v(buffer, maxX, maxY, minZ, uMax, vMin, alpha); + v(buffer, maxX, maxY, maxZ, uMax, vMax, alpha); + v(buffer, maxX, minY, maxZ, uMax2, vMax, alpha); + + // DOWN + v(buffer, minX, minY, minZ, uMin, vMin2, alpha); + v(buffer, maxX, minY, minZ, uMax, vMin2, alpha); + v(buffer, maxX, minY, maxZ, uMax, vMin3, alpha); + v(buffer, minX, minY, maxZ, uMin, vMin3, alpha); + + tessellator.draw(); + + if (looped) { + GlStateManager.enableDepth(); + if (isBoxClippingThroughCamera) { + GlStateManager.enableCull(); + } + break; + } + } + + GlStateManager.enableLighting(); + } + + private static void v(BufferBuilder buffer, double x, double y, double z, double u, double v, int alpha) { + buffer.pos(x, y, z).tex(u, v).lightmap(240, 240).color(255, 255, 255, alpha).endVertex(); + } + + /** + * Check if given AABB is clipping through camera. + */ + public static boolean isBoxClippingThroughCamera(double minX, double maxX, + double minY, double maxY, + double minZ, double maxZ) { + updateFrustum(); + + // obtain 4 vertices of near plane rectangle + // just halt and return false as a fallback, theoretically possible if view matrix got somehow borked + if (!calculateIntersectingPoint(0, 0, 2)) return false; + if (!calculateIntersectingPoint(1, 1, 2)) return false; + if (!calculateIntersectingPoint(2, 1, 3)) return false; + if (!calculateIntersectingPoint(3, 0, 3)) return false; + + // divide the near plane rectangle to 2 triangles, then do some intersection tests + float minXf = (float) minX, maxXf = (float) maxX, + minYf = (float) minY, maxYf = (float) maxY, + minZf = (float) minZ, maxZf = (float) maxZ; + return intersects(0, 1, 2, minXf, maxXf, minYf, maxYf, minZf, maxZf) || + intersects(0, 2, 3, minXf, maxXf, minYf, maxYf, minZf, maxZf); + } + + /** + * Tries to calculate an intersecting point between 2 specified planes and the near plane. If an intersecting point + * can be derived, {@code true} will be returned and the value will be stored in {@code vectorIndex}-th element of + * {@link #nearPlaneVectors}. If planes have no single intersecting point (either because they don't intersect, or + * have infinitely many solutions), {@code false} will be returned. + */ + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private static boolean calculateIntersectingPoint(int vectorIndex, int plane1, int plane2) { + System.arraycopy(clippingHelper.frustum[5], 0, mat, 0, 4); // near plane + System.arraycopy(clippingHelper.frustum[plane1], 0, mat, 4, 4); + System.arraycopy(clippingHelper.frustum[plane2], 0, mat, 8, 4); + + // shoutouts to wikipedia and gauss and row-echelon or sth idk + for (int i = 0; i < 3; i++) { + // find the k-th pivot + int maxRow = 0; + float maxValue = -1; + for (int r = i; r < 3; r++) { + float abs = Math.abs(getMatrixValue(i, r)); + if (maxValue < abs) { + maxRow = r; + maxValue = abs; + } + } + + // no pivot in this column, this means the system has no one unique solution + // since we don't care about calculating intersections in a form other than a point, we can just halt here + if (maxValue == 0) return false; + + swapRow(i, maxRow); + // do for all rows below pivot + for (int r = i + 1; r < 3; r++) { + float f = getMatrixValue(i, r) / getMatrixValue(i, i); + // fill with zeros the lower part of pivot column + setMatrixValue(i, r, 0); + for (int c = i + 1; c < 4; c++) { + setMatrixValue(c, r, getMatrixValue(c, r) - getMatrixValue(c, i) * f); + } + } + } + + // back substitution???? i guess?????? + float z = getMatrixValue(3, 2) / getMatrixValue(2, 2); + float y = (getMatrixValue(3, 1) - z * getMatrixValue(2, 1)) / getMatrixValue(1, 1); + float x = (getMatrixValue(3, 0) - z * getMatrixValue(2, 0) - y * getMatrixValue(1, 0)) / getMatrixValue(0, 0); + + // idk + if (!Float.isFinite(x) || !Float.isFinite(y) || !Float.isFinite(z)) return false; + nearPlaneVectors[vectorIndex].set(-x, -y, -z); + return true; + } + + /** + * Check if a triangle made of {@code p1}, {@code p2}, and {@code p3}-th element of {@link #nearPlaneVectors} + * intersects with given AABB. (Source) + */ + @SuppressWarnings("SameParameterValue") + private static boolean intersects(int p1, int p2, int p3, + float minX, float maxX, + float minY, float maxY, + float minZ, float maxZ) { + // Test the box normals (x-, y- and z-axes) + for (int i = 0; i < 3; i++) { + sat.projectTriangle(p1, p2, p3, i == 0 ? 1 : 0, i == 1 ? 1 : 0, i == 2 ? 1 : 0); + if (sat.max < switch (i) { + case 0 -> minX; + case 1 -> minY; + default -> minZ; + } || sat.min > switch (i) { + case 0 -> maxX; + case 1 -> maxY; + default -> maxZ; + }) return false; + } + + // Test the triangle normal + vec1.sub(nearPlaneVectors[p2], nearPlaneVectors[p1]); + vec2.sub(nearPlaneVectors[p3], nearPlaneVectors[p1]); + vec1.cross(vec1, vec2); + vec1.normalize(); + double triangleOffset = vec1.dot(nearPlaneVectors[p1]); + sat.projectAABB(minX, maxX, minY, maxY, minZ, maxZ, + vec1.x, vec1.y, vec1.z); + if (sat.max < triangleOffset || sat.min > triangleOffset) return false; + + // Test the nine edge cross-products + for (int i = 0; i < 3; i++) { + // The box normals are the same as it's edge tangents + vec1.sub(nearPlaneVectors[(i) % 3], nearPlaneVectors[(i + 1) % 3]); + for (int j = 0; j < 3; j++) { + vec2.set(j == 0 ? 1 : 0, j == 1 ? 1 : 0, j == 2 ? 1 : 0); + vec2.cross(vec1, vec2); + + sat.projectAABB(minX, maxX, minY, maxY, minZ, maxZ, vec2.x, vec2.y, vec2.z); + float boxMin = sat.min, boxMax = sat.max; + sat.projectTriangle(p1, p2, p3, vec2.x, vec2.y, vec2.z); + if (boxMax <= sat.min || boxMin >= sat.max) return false; + } + } + + // No separating axis found. + return true; + } + + private static float getMatrixValue(int col, int row) { + if (col < 0 || col >= 4) throw new IndexOutOfBoundsException("col == " + col); + if (row < 0 || row >= 3) throw new IndexOutOfBoundsException("row == " + row); + return mat[row * 4 + col]; + } + + private static void setMatrixValue(int col, int row, float val) { + if (col < 0 || col >= 4) throw new IndexOutOfBoundsException("col == " + col); + if (row < 0 || row >= 3) throw new IndexOutOfBoundsException("row == " + row); + mat[row * 4 + col] = val; + } + + private static void swapRow(int r1, int r2) { + if (r1 < 0 || r1 >= 3) throw new IndexOutOfBoundsException("r1 == " + r1); + if (r2 < 0 || r2 >= 3) throw new IndexOutOfBoundsException("r2 == " + r2); + if (r1 == r2) return; + System.arraycopy(mat, r1 * 4, mat, 12, 4); + System.arraycopy(mat, r2 * 4, mat, r1 * 4, 4); + System.arraycopy(mat, 12, mat, r2 * 4, 4); + } + + private static final class SATTestResult { + + private float min, max; + + void projectTriangle(int p1, int p2, int p3, + float axisX, float axisY, float axisZ) { + this.min = Float.POSITIVE_INFINITY; + this.max = Float.NEGATIVE_INFINITY; + + Vector3f v = nearPlaneVectors[p1]; + project(v.x, v.y, v.z, axisX, axisY, axisZ); + v = nearPlaneVectors[p2]; + project(v.x, v.y, v.z, axisX, axisY, axisZ); + v = nearPlaneVectors[p3]; + project(v.x, v.y, v.z, axisX, axisY, axisZ); + } + + void projectAABB(float minX, float maxX, + float minY, float maxY, + float minZ, float maxZ, + float axisX, float axisY, float axisZ) { + this.min = Float.POSITIVE_INFINITY; + this.max = Float.NEGATIVE_INFINITY; + + for (int i = 0; i <= 0b111; i++) { + project((i & 0b001) != 0 ? maxX : minX, + (i & 0b010) != 0 ? maxY : minY, + (i & 0b100) != 0 ? maxZ : minZ, + axisX, axisY, axisZ); + } + } + + private void project(float x, float y, float z, + float axisX, float axisY, float axisZ) { + float dot = x * axisX + y * axisY + z * axisZ; + if (dot < this.min) this.min = dot; + if (dot > this.max) this.max = dot; + } + } +} diff --git a/src/main/java/gregtech/common/MetaEntities.java b/src/main/java/gregtech/common/MetaEntities.java index 00efb35f87d..126fedf6fd9 100644 --- a/src/main/java/gregtech/common/MetaEntities.java +++ b/src/main/java/gregtech/common/MetaEntities.java @@ -4,9 +4,11 @@ import gregtech.api.util.GTUtility; import gregtech.client.renderer.handler.DynamiteRenderer; import gregtech.client.renderer.handler.GTBoatRenderer; +import gregtech.client.renderer.handler.MiningPipeRenderer; import gregtech.client.renderer.handler.PortalRenderer; import gregtech.common.entities.DynamiteEntity; import gregtech.common.entities.GTBoatEntity; +import gregtech.common.entities.MiningPipeEntity; import gregtech.common.entities.PortalEntity; import net.minecraft.client.Minecraft; @@ -24,6 +26,8 @@ public static void init() { GregTechAPI.instance, 64, 5, true); EntityRegistry.registerModEntity(GTUtility.gregtechId("gtboat"), GTBoatEntity.class, "GTBoat", 3, GregTechAPI.instance, 64, 2, true); + EntityRegistry.registerModEntity(GTUtility.gregtechId("mining_pipe"), MiningPipeEntity.class, "MiningPipe", 4, + GregTechAPI.instance, 0, 2, false); } @SideOnly(Side.CLIENT) @@ -32,5 +36,6 @@ public static void initRenderers() { manager -> new DynamiteRenderer(manager, Minecraft.getMinecraft().getRenderItem())); RenderingRegistry.registerEntityRenderingHandler(PortalEntity.class, PortalRenderer::new); RenderingRegistry.registerEntityRenderingHandler(GTBoatEntity.class, GTBoatRenderer::new); + RenderingRegistry.registerEntityRenderingHandler(MiningPipeEntity.class, MiningPipeRenderer::iHateJavaGenerics); } } diff --git a/src/main/java/gregtech/common/entities/MiningPipeEntity.java b/src/main/java/gregtech/common/entities/MiningPipeEntity.java new file mode 100644 index 00000000000..125405311fc --- /dev/null +++ b/src/main/java/gregtech/common/entities/MiningPipeEntity.java @@ -0,0 +1,128 @@ +package gregtech.common.entities; + +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.common.metatileentities.miner.Miner; + +import net.minecraft.block.material.EnumPushReaction; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ITeleporter; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Section of the mining pipe. The pipe should be divided into multiple segments due to a naive algorithm used in AABB + * checks making exceptionally large bounding boxes not work properly + */ +public class MiningPipeEntity extends Entity { + + @Nullable + private final MTE mte; + private final BlockPos origin; + + public int y; + public int length; + public boolean end; + + private int prevLength = -1; + + protected MiningPipeEntity(@NotNull World world, @Nullable MTE mte, @NotNull BlockPos origin) { + super(world); + this.setSize(.5f, 0); + this.setNoGravity(true); + this.noClip = true; + this.preventEntitySpawning = true; + this.setEntityInvulnerable(true); + + this.mte = mte; + this.origin = origin; + } + + @SuppressWarnings("unused") + public MiningPipeEntity(@NotNull World world) { + this(world, null, BlockPos.ORIGIN); + } + + public MiningPipeEntity(@NotNull MTE mte, @NotNull BlockPos origin) { + this(mte.getWorld(), mte, origin.toImmutable()); + this.setPosition(this.origin.getX() + .5, this.origin.getY(), this.origin.getZ() + .5); + } + + @Nullable + public MTE getMTE() { + return mte; + } + + @NotNull + public BlockPos getOrigin() { + return origin; + } + + @Override + protected void entityInit() {} + + @Override + public void onUpdate() { + if (this.mte == null || !this.mte.isValid()) { + setDead(); + return; + } + + int length = this.length; + if (length != this.prevLength) { + this.prevLength = length; + setPosition(this.posX, this.y - length, this.posZ); + setSize(.5f, length); + } + + this.firstUpdate = false; + } + + @Override + public boolean doesEntityNotTriggerPressurePlate() { + return true; + } + + @Override + public boolean canRenderOnFire() { + return false; + } + + @Override + public boolean canBeAttackedWithItem() { + return false; + } + + @NotNull + @Override + public EnumPushReaction getPushReaction() { + return EnumPushReaction.IGNORE; + } + + @Nullable + @Override + public AxisAlignedBB getCollisionBox(@NotNull Entity entity) { + return entity.canBePushed() ? entity.getEntityBoundingBox() : null; + } + + @Nullable + @Override + public AxisAlignedBB getCollisionBoundingBox() { + return this.getEntityBoundingBox(); + } + + @Override + public Entity changeDimension(int dim, @NotNull ITeleporter teleporter) { + return this; + } + + @Override + protected void readEntityFromNBT(@NotNull NBTTagCompound tag) {} + + @Override + protected void writeEntityToNBT(@NotNull NBTTagCompound tag) {} +} diff --git a/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java b/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java index c346ac65e23..84c32da7b48 100644 --- a/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java +++ b/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java @@ -30,7 +30,6 @@ import gregtech.common.metatileentities.electric.MetaTileEntityHull; import gregtech.common.metatileentities.electric.MetaTileEntityItemCollector; import gregtech.common.metatileentities.electric.MetaTileEntityMagicEnergyAbsorber; -import gregtech.common.metatileentities.electric.MetaTileEntityMiner; import gregtech.common.metatileentities.electric.MetaTileEntityPump; import gregtech.common.metatileentities.electric.MetaTileEntityRockBreaker; import gregtech.common.metatileentities.electric.MetaTileEntitySingleCombustion; @@ -38,6 +37,9 @@ import gregtech.common.metatileentities.electric.MetaTileEntityTransformer; import gregtech.common.metatileentities.electric.MetaTileEntityWorldAccelerator; import gregtech.common.metatileentities.electric.SimpleMachineMetaTileEntityResizable; +import gregtech.common.metatileentities.miner.LargeMinerTypes; +import gregtech.common.metatileentities.miner.MetaTileEntityLargeMiner; +import gregtech.common.metatileentities.miner.MetaTileEntityMiner; import gregtech.common.metatileentities.multi.BoilerType; import gregtech.common.metatileentities.multi.MetaTileEntityCokeOven; import gregtech.common.metatileentities.multi.MetaTileEntityCokeOvenHatch; @@ -59,7 +61,6 @@ import gregtech.common.metatileentities.multi.electric.MetaTileEntityHPCA; import gregtech.common.metatileentities.multi.electric.MetaTileEntityImplosionCompressor; import gregtech.common.metatileentities.multi.electric.MetaTileEntityLargeChemicalReactor; -import gregtech.common.metatileentities.multi.electric.MetaTileEntityLargeMiner; import gregtech.common.metatileentities.multi.electric.MetaTileEntityMultiSmelter; import gregtech.common.metatileentities.multi.electric.MetaTileEntityNetworkSwitch; import gregtech.common.metatileentities.multi.electric.MetaTileEntityPowerSubstation; @@ -107,7 +108,6 @@ import gregtech.common.metatileentities.steam.SteamFurnace; import gregtech.common.metatileentities.steam.SteamHammer; import gregtech.common.metatileentities.steam.SteamMacerator; -import gregtech.common.metatileentities.steam.SteamMiner; import gregtech.common.metatileentities.steam.SteamRockBreaker; import gregtech.common.metatileentities.steam.boiler.SteamCoalBoiler; import gregtech.common.metatileentities.steam.boiler.SteamLavaBoiler; @@ -326,7 +326,6 @@ public class MetaTileEntities { public static SteamAlloySmelter STEAM_ALLOY_SMELTER_STEEL; public static SteamRockBreaker STEAM_ROCK_BREAKER_BRONZE; public static SteamRockBreaker STEAM_ROCK_BREAKER_STEEL; - public static SteamMiner STEAM_MINER; public static MetaTileEntityPumpHatch PUMP_OUTPUT_HATCH; public static MetaTileEntityPrimitiveWaterPump PRIMITIVE_WATER_PUMP; public static MetaTileEntityMagicEnergyAbsorber MAGIC_ENERGY_ABSORBER; @@ -465,7 +464,7 @@ public static void init() { STEAM_ROCK_BREAKER_STEEL = registerMetaTileEntity(20, new SteamRockBreaker(gregtechId("steam_rock_breaker_steel"), true)); - STEAM_MINER = registerMetaTileEntity(21, new SteamMiner(gregtechId("steam_miner"), 320, 4, 0)); + // Steam Miner ("gregtech:steam_miner"), ID 21; added by external addon for compatibility // Electric Furnace, IDs 50-64 registerSimpleMetaTileEntity(ELECTRIC_FURNACE, 50, "electric_furnace", RecipeMaps.FURNACE_RECIPES, @@ -655,9 +654,9 @@ public static void init() { // Chunk Miner, IDs 920-934 - MINER[0] = registerMetaTileEntity(920, new MetaTileEntityMiner(gregtechId("miner.lv"), 1, 160, 8, 1)); - MINER[1] = registerMetaTileEntity(921, new MetaTileEntityMiner(gregtechId("miner.mv"), 2, 80, 16, 2)); - MINER[2] = registerMetaTileEntity(922, new MetaTileEntityMiner(gregtechId("miner.hv"), 3, 40, 24, 3)); + MINER[0] = registerMetaTileEntity(920, new MetaTileEntityMiner(gregtechId("miner.lv"), 1, 160, 17)); + MINER[1] = registerMetaTileEntity(921, new MetaTileEntityMiner(gregtechId("miner.mv"), 2, 80, 33)); + MINER[2] = registerMetaTileEntity(922, new MetaTileEntityMiner(gregtechId("miner.hv"), 3, 40, 49)); // Diesel Generator, IDs 935-949 COMBUSTION_GENERATOR[0] = registerMetaTileEntity(935, @@ -776,12 +775,12 @@ public static void init() { STEAM_OVEN = registerMetaTileEntity(1024, new MetaTileEntitySteamOven(gregtechId("steam_oven"))); STEAM_GRINDER = registerMetaTileEntity(1025, new MetaTileEntitySteamGrinder(gregtechId("steam_grinder"))); - BASIC_LARGE_MINER = registerMetaTileEntity(1026, - new MetaTileEntityLargeMiner(gregtechId("large_miner.ev"), GTValues.EV, 16, 3, 4, Materials.Steel, 8)); + BASIC_LARGE_MINER = registerMetaTileEntity(1026, new MetaTileEntityLargeMiner(gregtechId("large_miner.ev"), + GTValues.EV, 16, 3, 8, LargeMinerTypes.STEEL)); LARGE_MINER = registerMetaTileEntity(1027, new MetaTileEntityLargeMiner(gregtechId("large_miner.iv"), - GTValues.IV, 4, 5, 5, Materials.Titanium, 16)); + GTValues.IV, 4, 5, 16, LargeMinerTypes.TITANIUM)); ADVANCED_LARGE_MINER = registerMetaTileEntity(1028, new MetaTileEntityLargeMiner(gregtechId("large_miner.luv"), - GTValues.LuV, 1, 7, 6, Materials.TungstenSteel, 32)); + GTValues.LuV, 1, 7, 32, LargeMinerTypes.TUNGSTEN_STEEL)); CENTRAL_MONITOR = registerMetaTileEntity(1029, new MetaTileEntityCentralMonitor(gregtechId("central_monitor"))); @@ -1287,7 +1286,7 @@ public static void registerMetaTileEntities( } public static T registerMetaTileEntity(int id, T sampleMetaTileEntity) { - if (sampleMetaTileEntity instanceof IMultiblockAbilityPart abilityPart) { + if (sampleMetaTileEntity instanceof IMultiblockAbilityPartabilityPart) { MultiblockAbility.registerMultiblockAbility(abilityPart.getAbility(), sampleMetaTileEntity); } if (sampleMetaTileEntity instanceof MultiblockControllerBase && Loader.isModLoaded(GTValues.MODID_JEI)) { diff --git a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityMiner.java b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityMiner.java deleted file mode 100644 index 91fd07df207..00000000000 --- a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityMiner.java +++ /dev/null @@ -1,323 +0,0 @@ -package gregtech.common.metatileentities.electric; - -import gregtech.api.GTValues; -import gregtech.api.capability.GregtechTileCapabilities; -import gregtech.api.capability.IControllable; -import gregtech.api.capability.IMiner; -import gregtech.api.capability.impl.EnergyContainerHandler; -import gregtech.api.capability.impl.NotifiableItemStackHandler; -import gregtech.api.capability.impl.miner.MinerLogic; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.ModularUI; -import gregtech.api.gui.widgets.AdvancedTextWidget; -import gregtech.api.gui.widgets.SlotWidget; -import gregtech.api.items.itemhandlers.GTItemStackHandler; -import gregtech.api.metatileentity.IDataInfoProvider; -import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.api.metatileentity.TieredMetaTileEntity; -import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; -import gregtech.client.renderer.texture.Textures; -import gregtech.core.sound.GTSoundEvents; - -import net.minecraft.client.resources.I18n; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.*; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.Style; -import net.minecraft.util.text.TextComponentTranslation; -import net.minecraft.util.text.TextFormatting; -import net.minecraft.world.World; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemStackHandler; - -import codechicken.lib.raytracer.CuboidRayTraceResult; -import codechicken.lib.render.CCRenderState; -import codechicken.lib.render.pipeline.IVertexOperation; -import codechicken.lib.vec.Matrix4; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.List; - -public class MetaTileEntityMiner extends TieredMetaTileEntity implements IMiner, IControllable, IDataInfoProvider { - - private final ItemStackHandler chargerInventory; - - private final int inventorySize; - private final long energyPerTick; - private boolean isInventoryFull = false; - - private final MinerLogic minerLogic; - - public MetaTileEntityMiner(ResourceLocation metaTileEntityId, int tier, int speed, int maximumRadius, int fortune) { - super(metaTileEntityId, tier); - this.inventorySize = (tier + 1) * (tier + 1); - this.energyPerTick = GTValues.V[tier - 1]; - this.minerLogic = new MinerLogic(this, fortune, speed, maximumRadius, Textures.SOLID_STEEL_CASING); - this.chargerInventory = new GTItemStackHandler(this, 1); - initializeInventory(); - } - - @Override - public MetaTileEntity createMetaTileEntity(IGregTechTileEntity tileEntity) { - return new MetaTileEntityMiner(metaTileEntityId, getTier(), this.minerLogic.getSpeed(), - this.minerLogic.getMaximumRadius(), this.minerLogic.getFortune()); - } - - @Override - protected IItemHandlerModifiable createImportItemHandler() { - return new NotifiableItemStackHandler(this, 0, this, false); - } - - @Override - protected IItemHandlerModifiable createExportItemHandler() { - return new NotifiableItemStackHandler(this, inventorySize, this, true); - } - - @Override - @SideOnly(Side.CLIENT) - public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { - super.renderMetaTileEntity(renderState, translation, pipeline); - Textures.SCREEN.renderSided(EnumFacing.UP, renderState, translation, pipeline); - for (EnumFacing renderSide : EnumFacing.HORIZONTALS) { - if (renderSide == getFrontFacing()) { - Textures.PIPE_OUT_OVERLAY.renderSided(renderSide, renderState, translation, pipeline); - } else - Textures.CHUNK_MINER_OVERLAY.renderSided(renderSide, renderState, translation, pipeline); - } - minerLogic.renderPipe(renderState, translation, pipeline); - } - - @Override - protected ModularUI createUI(@NotNull EntityPlayer entityPlayer) { - int rowSize = (int) Math.sqrt(inventorySize); - ModularUI.Builder builder = new ModularUI.Builder(GuiTextures.BACKGROUND, 195, 176); - builder.bindPlayerInventory(entityPlayer.inventory, 94); - - if (getTier() == GTValues.HV) { - for (int y = 0; y < rowSize; y++) { - for (int x = 0; x < rowSize; x++) { - int index = y * rowSize + x; - builder.widget( - new SlotWidget(exportItems, index, 151 - rowSize * 9 + x * 18, 18 + y * 18, true, false) - .setBackgroundTexture(GuiTextures.SLOT)); - } - } - } else { - for (int y = 0; y < rowSize; y++) { - for (int x = 0; x < rowSize; x++) { - int index = y * rowSize + x; - builder.widget( - new SlotWidget(exportItems, index, 142 - rowSize * 9 + x * 18, 18 + y * 18, true, false) - .setBackgroundTexture(GuiTextures.SLOT)); - } - } - } - - builder.image(7, 16, 105, 75, GuiTextures.DISPLAY) - .label(6, 6, getMetaFullName()); - builder.widget(new AdvancedTextWidget(10, 19, this::addDisplayText, 0xFFFFFF) - .setMaxWidthLimit(84)); - builder.widget(new AdvancedTextWidget(70, 19, this::addDisplayText2, 0xFFFFFF) - .setMaxWidthLimit(84)); - builder.widget(new SlotWidget(chargerInventory, 0, 171, 152) - .setBackgroundTexture(GuiTextures.SLOT, GuiTextures.CHARGER_OVERLAY)); - - return builder.build(getHolder(), entityPlayer); - } - - private void addDisplayText(@NotNull List textList) { - int workingArea = getWorkingArea(minerLogic.getCurrentRadius()); - textList.add(new TextComponentTranslation("gregtech.machine.miner.startx", this.minerLogic.getX().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.starty", this.minerLogic.getY().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.startz", this.minerLogic.getZ().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.working_area", workingArea, workingArea)); - if (this.minerLogic.isDone()) - textList.add(new TextComponentTranslation("gregtech.machine.miner.done") - .setStyle(new Style().setColor(TextFormatting.GREEN))); - else if (this.minerLogic.isWorking()) - textList.add(new TextComponentTranslation("gregtech.machine.miner.working") - .setStyle(new Style().setColor(TextFormatting.GOLD))); - else if (!this.isWorkingEnabled()) - textList.add(new TextComponentTranslation("gregtech.multiblock.work_paused")); - if (isInventoryFull) - textList.add(new TextComponentTranslation("gregtech.machine.miner.invfull") - .setStyle(new Style().setColor(TextFormatting.RED))); - if (!drainEnergy(true)) - textList.add(new TextComponentTranslation("gregtech.machine.miner.needspower") - .setStyle(new Style().setColor(TextFormatting.RED))); - } - - private void addDisplayText2(@NotNull List textList) { - textList.add(new TextComponentTranslation("gregtech.machine.miner.minex", this.minerLogic.getMineX().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.miney", this.minerLogic.getMineY().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.minez", this.minerLogic.getMineZ().get())); - } - - @Override - public void addInformation(ItemStack stack, @Nullable World player, @NotNull List tooltip, - boolean advanced) { - int currentArea = getWorkingArea(minerLogic.getCurrentRadius()); - tooltip.add(I18n.format("gregtech.machine.miner.tooltip", currentArea, currentArea)); - tooltip.add(I18n.format("gregtech.universal.tooltip.uses_per_tick", energyPerTick) + TextFormatting.GRAY + - ", " + I18n.format("gregtech.machine.miner.per_block", this.minerLogic.getSpeed() / 20)); - tooltip.add(I18n.format("gregtech.universal.tooltip.voltage_in", energyContainer.getInputVoltage(), - GTValues.VNF[getTier()])); - tooltip.add( - I18n.format("gregtech.universal.tooltip.energy_storage_capacity", energyContainer.getEnergyCapacity())); - int maxArea = getWorkingArea(minerLogic.getMaximumRadius()); - tooltip.add(I18n.format("gregtech.universal.tooltip.working_area_max", maxArea, maxArea)); - } - - @Override - public void addToolUsages(ItemStack stack, @Nullable World world, List tooltip, boolean advanced) { - tooltip.add(I18n.format("gregtech.tool_action.screwdriver.toggle_mode_covers")); - tooltip.add(I18n.format("gregtech.tool_action.wrench.set_facing")); - tooltip.add(I18n.format("gregtech.tool_action.soft_mallet.reset")); - super.addToolUsages(stack, world, tooltip, advanced); - } - - @Override - public boolean drainEnergy(boolean simulate) { - long resultEnergy = energyContainer.getEnergyStored() - energyPerTick; - if (resultEnergy >= 0L && resultEnergy <= energyContainer.getEnergyCapacity()) { - if (!simulate) - energyContainer.removeEnergy(energyPerTick); - return true; - } - return false; - } - - @Override - public void update() { - super.update(); - this.minerLogic.performMining(); - if (!getWorld().isRemote) { - ((EnergyContainerHandler) this.energyContainer).dischargeOrRechargeEnergyContainers(chargerInventory, 0); - - if (getOffsetTimer() % 5 == 0) - pushItemsIntoNearbyHandlers(getFrontFacing()); - - if (this.minerLogic.wasActiveAndNeedsUpdate()) { - this.minerLogic.setWasActiveAndNeedsUpdate(false); - this.minerLogic.setActive(false); - } - } - } - - @Override - public boolean onScrewdriverClick(EntityPlayer playerIn, EnumHand hand, EnumFacing facing, - CuboidRayTraceResult hitResult) { - if (getWorld().isRemote) return true; - - if (!this.isActive()) { - int currentRadius = this.minerLogic.getCurrentRadius(); - if (currentRadius == 1) - this.minerLogic.setCurrentRadius(this.minerLogic.getMaximumRadius()); - else if (playerIn.isSneaking()) - this.minerLogic.setCurrentRadius(Math.max(1, Math.round(currentRadius / 2.0f))); - else - this.minerLogic.setCurrentRadius(Math.max(1, currentRadius - 1)); - - this.minerLogic.resetArea(); - - int workingArea = getWorkingArea(minerLogic.getCurrentRadius()); - playerIn.sendMessage( - new TextComponentTranslation("gregtech.machine.miner.working_area", workingArea, workingArea)); - } else { - playerIn.sendMessage(new TextComponentTranslation("gregtech.machine.miner.errorradius")); - } - return true; - } - - @Override - public NBTTagCompound writeToNBT(NBTTagCompound data) { - super.writeToNBT(data); - data.setTag("ChargerInventory", chargerInventory.serializeNBT()); - return this.minerLogic.writeToNBT(data); - } - - @Override - public void readFromNBT(NBTTagCompound data) { - super.readFromNBT(data); - this.chargerInventory.deserializeNBT(data.getCompoundTag("ChargerInventory")); - this.minerLogic.readFromNBT(data); - } - - @Override - public void writeInitialSyncData(PacketBuffer buf) { - super.writeInitialSyncData(buf); - this.minerLogic.writeInitialSyncData(buf); - } - - @Override - public void receiveInitialSyncData(PacketBuffer buf) { - super.receiveInitialSyncData(buf); - this.minerLogic.receiveInitialSyncData(buf); - } - - @Override - public void receiveCustomData(int dataId, PacketBuffer buf) { - super.receiveCustomData(dataId, buf); - this.minerLogic.receiveCustomData(dataId, buf); - } - - @Override - public T getCapability(Capability capability, EnumFacing side) { - if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { - return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); - } - return super.getCapability(capability, side); - } - - @Override - public void clearMachineInventory(NonNullList itemBuffer) { - super.clearMachineInventory(itemBuffer); - clearInventory(itemBuffer, chargerInventory); - } - - @Override - public boolean isInventoryFull() { - return isInventoryFull; - } - - @Override - public void setInventoryFull(boolean isFull) { - this.isInventoryFull = isFull; - } - - @Override - public boolean isWorkingEnabled() { - return this.minerLogic.isWorkingEnabled(); - } - - @Override - public void setWorkingEnabled(boolean isActivationAllowed) { - this.minerLogic.setWorkingEnabled(isActivationAllowed); - } - - @Override - public SoundEvent getSound() { - return GTSoundEvents.MINER; - } - - @Override - public boolean isActive() { - return minerLogic.isActive() && isWorkingEnabled(); - } - - @NotNull - @Override - public List getDataInfo() { - int workingArea = getWorkingArea(minerLogic.getCurrentRadius()); - return Collections.singletonList( - new TextComponentTranslation("gregtech.machine.miner.working_area", workingArea, workingArea)); - } -} diff --git a/src/main/java/gregtech/common/metatileentities/miner/LargeMinerType.java b/src/main/java/gregtech/common/metatileentities/miner/LargeMinerType.java new file mode 100644 index 00000000000..833a30b792d --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/miner/LargeMinerType.java @@ -0,0 +1,33 @@ +package gregtech.common.metatileentities.miner; + +import gregtech.api.metatileentity.multiblock.IMultiblockPart; +import gregtech.api.pattern.TraceabilityPredicate; +import gregtech.client.model.miningpipe.MiningPipeModel; +import gregtech.client.renderer.ICubeRenderer; + +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface LargeMinerType { + + @NotNull + TraceabilityPredicate getCasing(); + + @NotNull + TraceabilityPredicate getFrame(); + + @SideOnly(Side.CLIENT) + @NotNull + ICubeRenderer getFrontOverlay(); + + @SideOnly(Side.CLIENT) + @NotNull + ICubeRenderer getBaseTexture(@Nullable IMultiblockPart sourcePart); + + @SideOnly(Side.CLIENT) + @NotNull + MiningPipeModel getMiningPipeModel(); +} diff --git a/src/main/java/gregtech/common/metatileentities/miner/LargeMinerTypes.java b/src/main/java/gregtech/common/metatileentities/miner/LargeMinerTypes.java new file mode 100644 index 00000000000..acb8b4bf253 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/miner/LargeMinerTypes.java @@ -0,0 +1,76 @@ +package gregtech.common.metatileentities.miner; + +import gregtech.api.metatileentity.multiblock.IMultiblockPart; +import gregtech.api.metatileentity.multiblock.MultiblockControllerBase; +import gregtech.api.pattern.TraceabilityPredicate; +import gregtech.api.unification.material.Materials; +import gregtech.client.model.miningpipe.MiningPipeModel; +import gregtech.client.model.miningpipe.MiningPipeModels; +import gregtech.client.renderer.ICubeRenderer; +import gregtech.client.renderer.texture.Textures; +import gregtech.common.blocks.BlockMetalCasing; +import gregtech.common.blocks.MetaBlocks; + +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public enum LargeMinerTypes implements LargeMinerType { + + STEEL, + TITANIUM, + TUNGSTEN_STEEL; + + @NotNull + public TraceabilityPredicate getCasing() { + return MultiblockControllerBase.states(switch (this) { + case STEEL -> MetaBlocks.METAL_CASING.getState(BlockMetalCasing.MetalCasingType.STEEL_SOLID); + case TITANIUM -> MetaBlocks.METAL_CASING.getState(BlockMetalCasing.MetalCasingType.TITANIUM_STABLE); + case TUNGSTEN_STEEL -> MetaBlocks.METAL_CASING + .getState(BlockMetalCasing.MetalCasingType.TUNGSTENSTEEL_ROBUST); + }); + } + + @NotNull + public TraceabilityPredicate getFrame() { + return MultiblockControllerBase.frames(switch (this) { + case STEEL -> Materials.Steel; + case TITANIUM -> Materials.Titanium; + case TUNGSTEN_STEEL -> Materials.TungstenSteel; + }); + } + + @NotNull + @Override + @SideOnly(Side.CLIENT) + public ICubeRenderer getBaseTexture(@Nullable IMultiblockPart sourcePart) { + return switch (this) { + case STEEL -> Textures.SOLID_STEEL_CASING; + case TITANIUM -> Textures.STABLE_TITANIUM_CASING; + case TUNGSTEN_STEEL -> Textures.ROBUST_TUNGSTENSTEEL_CASING; + }; + } + + @NotNull + @Override + public MiningPipeModel getMiningPipeModel() { + return switch (this) { + case STEEL -> MiningPipeModels.STEEL; + case TITANIUM -> MiningPipeModels.TITANIUM; + case TUNGSTEN_STEEL -> MiningPipeModels.TUNGSTEN_STEEL; + }; + } + + @NotNull + @Override + @SideOnly(Side.CLIENT) + public ICubeRenderer getFrontOverlay() { + return switch (this) { + case STEEL -> Textures.LARGE_MINER_OVERLAY_BASIC; + case TITANIUM -> Textures.LARGE_MINER_OVERLAY_ADVANCED; + case TUNGSTEN_STEEL -> Textures.LARGE_MINER_OVERLAY_ADVANCED_2; + }; + } +} diff --git a/src/main/java/gregtech/common/metatileentities/miner/MetaTileEntityLargeMiner.java b/src/main/java/gregtech/common/metatileentities/miner/MetaTileEntityLargeMiner.java new file mode 100644 index 00000000000..f9417309651 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/miner/MetaTileEntityLargeMiner.java @@ -0,0 +1,687 @@ +package gregtech.common.metatileentities.miner; + +import gregtech.api.GTValues; +import gregtech.api.capability.GregtechTileCapabilities; +import gregtech.api.capability.IControllable; +import gregtech.api.capability.IEnergyContainer; +import gregtech.api.capability.IMultipleTankHandler; +import gregtech.api.capability.impl.CommonFluidFilters; +import gregtech.api.capability.impl.EnergyContainerList; +import gregtech.api.capability.impl.FluidTankList; +import gregtech.api.capability.impl.ItemHandlerList; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.ModularUI; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.TextureArea; +import gregtech.api.gui.widgets.AdvancedTextWidget; +import gregtech.api.gui.widgets.ImageCycleButtonWidget; +import gregtech.api.items.itemhandlers.GTItemStackHandler; +import gregtech.api.items.toolitem.ToolHelper; +import gregtech.api.metatileentity.IDataInfoProvider; +import gregtech.api.metatileentity.IFastRenderMetaTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; +import gregtech.api.metatileentity.multiblock.IMultiblockPart; +import gregtech.api.metatileentity.multiblock.IProgressBarMultiblock; +import gregtech.api.metatileentity.multiblock.MultiblockAbility; +import gregtech.api.metatileentity.multiblock.MultiblockDisplayText; +import gregtech.api.metatileentity.multiblock.MultiblockWithDisplayBase; +import gregtech.api.pattern.BlockPattern; +import gregtech.api.pattern.FactoryBlockPattern; +import gregtech.api.pattern.PatternMatchContext; +import gregtech.api.recipes.RecipeMaps; +import gregtech.api.unification.material.Materials; +import gregtech.api.util.GTTransferUtils; +import gregtech.api.util.GTUtility; +import gregtech.api.util.TextComponentUtil; +import gregtech.client.model.miningpipe.MiningPipeModel; +import gregtech.client.renderer.ICubeRenderer; +import gregtech.client.renderer.texture.Textures; +import gregtech.core.sound.GTSoundEvents; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockPos.MutableBlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.event.ClickEvent; +import net.minecraft.util.text.event.HoverEvent; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.items.IItemHandlerModifiable; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.vec.Matrix4; +import com.google.common.collect.Lists; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +import static gregtech.api.unification.material.Materials.DrillingFluid; + +public class MetaTileEntityLargeMiner extends MultiblockWithDisplayBase + implements Miner, IControllable, IDataInfoProvider, IFastRenderMetaTileEntity, + IProgressBarMultiblock { + + @NotNull + public final LargeMinerType type; + public final int tier; + public final int drillingFluidConsumePerTick; + + private final MultiblockMinerLogic minerLogic; + + private IEnergyContainer energyContainer; + protected IMultipleTankHandler inputFluidInventory; + protected IItemHandlerModifiable outputInventory; + + // last mined ore block + protected final MutableBlockPos lastMinedOre = new MutableBlockPos(); + protected boolean hasLastMinedOre; + // number of ores processed so far + protected int minedOreCount; + + private boolean inventoryFull; + + public MetaTileEntityLargeMiner(ResourceLocation metaTileEntityId, int tier, int speed, int maxChunkDiameter, + int drillingFluidConsumePerTick, @NotNull LargeMinerType type) { + super(metaTileEntityId); + this.type = Objects.requireNonNull(type, "type == null"); + this.tier = tier; + this.drillingFluidConsumePerTick = drillingFluidConsumePerTick; + this.minerLogic = new MultiblockMinerLogic(this, speed, maxChunkDiameter); + } + + @Override + public MetaTileEntity createMetaTileEntity(IGregTechTileEntity tileEntity) { + return new MetaTileEntityLargeMiner(metaTileEntityId, this.tier, this.minerLogic.getWorkFrequency(), + this.minerLogic.getMaximumChunkDiameter(), + this.drillingFluidConsumePerTick, this.type); + } + + @Override + public void invalidateStructure() { + super.invalidateStructure(); + this.inputFluidInventory = new FluidTankList(true); + this.outputInventory = new GTItemStackHandler(this, 0); + this.energyContainer = new EnergyContainerList(Lists.newArrayList()); + } + + @Override + protected void formStructure(PatternMatchContext context) { + super.formStructure(context); + this.inputFluidInventory = new FluidTankList(false, getAbilities(MultiblockAbility.IMPORT_FLUIDS)); + this.outputInventory = new ItemHandlerList(getAbilities(MultiblockAbility.EXPORT_ITEMS)); + this.energyContainer = new EnergyContainerList(getAbilities(MultiblockAbility.INPUT_ENERGY)); + } + + public int getEnergyTier() { + if (energyContainer == null) return this.tier; + return Math.min(this.tier + 1, + Math.max(this.tier, GTUtility.getFloorTierByVoltage(energyContainer.getInputVoltage()))); + } + + @Override + public boolean drainMiningResources(@NotNull MinedBlockType minedBlockType, boolean pipeExtended, + boolean simulate) { + if (minedBlockType == MinedBlockType.NOTHING) return true; + if (!drainEnergy(true) || !drainFluid(true)) return false; + if (!simulate) { + drainEnergy(false); + drainFluid(false); + } + return true; + } + + protected boolean drainEnergy(boolean simulate) { + long energyToDrain = GTValues.VA[getEnergyTier()]; + long resultEnergy = energyContainer.getEnergyStored() - energyToDrain; + if (resultEnergy >= 0L && resultEnergy <= energyContainer.getEnergyCapacity()) { + if (!simulate) { + energyContainer.changeEnergy(-energyToDrain); + } + return true; + } + return false; + } + + protected boolean drainFluid(boolean simulate) { + int overclockAmount = getEnergyTier() - this.tier + 1; + int amount = this.drillingFluidConsumePerTick * overclockAmount; + FluidStack drained = this.inputFluidInventory.drain(DrillingFluid.getFluid(amount), !simulate); + return drained != null && drained.amount >= amount; + } + + @Override + public boolean collectBlockDrops(@NotNull World world, @NotNull BlockPos pos, @NotNull IBlockState state) { + NonNullList drops = NonNullList.create(); + IItemHandlerModifiable inventory = this.outputInventory; + + if (this.minerLogic.isSilkTouchMode()) { + drops.add(ToolHelper.getSilkTouchDrop(state)); + } else if (MinerUtil.applyTieredHammerDrops(GTUtility.toItem(state), drops, + this.getEnergyTier(), RecipeMaps.MACERATOR_RECIPES, 3) == 0) { + state.getBlock().getDrops(drops, world, pos, state, 0); // fallback + } + boolean result = GTTransferUtils.addItemsToItemHandler(inventory, true, drops); + this.inventoryFull = result; + if (result) GTTransferUtils.addItemsToItemHandler(inventory, false, drops); + return result; + } + + @Override + public void onMineOperation(@NotNull BlockPos pos, boolean isOre, boolean isOrigin) { + if (isOre) { + this.lastMinedOre.setPos(pos); + this.hasLastMinedOre = true; + this.minedOreCount++; + } + } + + @NotNull + @Override + @SideOnly(Side.CLIENT) + public MiningPipeModel getMiningPipeModel() { + return this.type.getMiningPipeModel(); + } + + @Override + @SideOnly(Side.CLIENT) + public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { + super.renderMetaTileEntity(renderState, translation, pipeline); + this.getFrontOverlay().renderOrientedState(renderState, translation, pipeline, getFrontFacing(), isActive(), + isWorkingEnabled()); + if (isStructureFormed()) { + EnumFacing f = getFrontFacing().getOpposite(); + Textures.PIPE_IN_OVERLAY.renderSided(EnumFacing.DOWN, renderState, + translation.copy().translate(f.getXOffset(), 0, f.getZOffset()), pipeline); + } + } + + @Override + public void renderMetaTileEntity(double x, double y, double z, float partialTicks) { + MiningArea previewArea = this.minerLogic.getPreviewArea(); + if (previewArea != null) previewArea.renderMetaTileEntity(this, x, y, z, partialTicks); + } + + @Override + public void renderMetaTileEntityFast(CCRenderState renderState, Matrix4 translation, float partialTicks) { + MiningArea previewArea = this.minerLogic.getPreviewArea(); + if (previewArea != null) previewArea.renderMetaTileEntityFast(this, renderState, translation, partialTicks); + } + + @Override + public AxisAlignedBB getRenderBoundingBox() { + MiningArea previewArea = this.minerLogic.getPreviewArea(); + return previewArea != null ? previewArea.getRenderBoundingBox() : MinerUtil.EMPTY_AABB; + } + + @Override + public boolean shouldRenderInPass(int pass) { + MiningArea previewArea = this.minerLogic.getPreviewArea(); + return previewArea != null && previewArea.shouldRenderInPass(pass); + } + + @Override + public boolean isGlobalRenderer() { + return true; + } + + @Override + protected void updateFormedValid() { + this.minerLogic.update(); + } + + @Override + public void update() { + super.update(); + if (this.getWorld().isRemote) { + this.minerLogic.update(); + } + } + + @NotNull + @Override + protected BlockPattern createStructurePattern() { + return FactoryBlockPattern.start() + .aisle("XXX", "#F#", "#F#", "#F#", "###", "###", "###") + .aisle("XXX", "FCF", "FCF", "FCF", "#F#", "#F#", "#F#") + .aisle("XSX", "#F#", "#F#", "#F#", "###", "###", "###") + .where('S', selfPredicate()) + .where('X', this.type.getCasing() + .or(abilities(MultiblockAbility.EXPORT_ITEMS).setMaxGlobalLimited(1).setPreviewCount(1)) + .or(abilities(MultiblockAbility.IMPORT_FLUIDS).setExactLimit(1).setPreviewCount(1)) + .or(abilities(MultiblockAbility.INPUT_ENERGY).setMinGlobalLimited(1).setMaxGlobalLimited(3) + .setPreviewCount(1))) + .where('C', this.type.getCasing()) + .where('F', this.type.getFrame()) + .where('#', any()) + .build(); + } + + @Override + public String[] getDescription() { + return new String[] { I18n.format("gregtech.machine.miner.multi.description") }; + } + + @Override + public void addInformation(ItemStack stack, @Nullable World player, @NotNull List tooltip, + boolean advanced) { + int workingAreaChunks = this.minerLogic.getMaximumChunkDiameter(); + tooltip.add(I18n.format("gregtech.machine.miner.multi.modes")); + tooltip.add(I18n.format("gregtech.machine.miner.multi.production")); + tooltip.add(I18n.format("gregtech.machine.miner.fluid_usage", this.drillingFluidConsumePerTick, + DrillingFluid.getLocalizedName())); + tooltip.add(I18n.format("gregtech.universal.tooltip.working_area_chunks_max", workingAreaChunks, + workingAreaChunks)); + tooltip.add(I18n.format("gregtech.universal.tooltip.energy_tier_range", GTValues.VNF[this.tier], + GTValues.VNF[this.tier + 1])); + } + + @Override + public void addToolUsages(ItemStack stack, @Nullable World world, List tooltip, boolean advanced) { + tooltip.add(I18n.format("gregtech.tool_action.screwdriver.toggle_mode_covers")); + tooltip.add(I18n.format("gregtech.tool_action.wrench.set_facing")); + if (getSound() != null) { + tooltip.add(I18n.format("gregtech.tool_action.hammer")); + } + tooltip.add(I18n.format("gregtech.tool_action.crowbar")); + } + + @Nullable + private AtomicBoolean uiConfigModeStateHolder; + + @Override + protected ModularUI.Builder createUITemplate(EntityPlayer entityPlayer) { + AtomicBoolean stateHolder = new AtomicBoolean(); + this.uiConfigModeStateHolder = stateHolder; + ModularUI.Builder b = super.createUITemplate(entityPlayer); + b.widget(new AdvancedTextWidget(9, 20, l -> addRealDisplayText(l, stateHolder.get()), 0xFFFFFF) + .setMaxWidthLimit(181) + .setClickHandler(this::handleDisplayClick)); + this.uiConfigModeStateHolder = null; + return b; + } + + @NotNull + @Override + protected Widget getFlexButton(int x, int y, int width, int height) { + AtomicBoolean stateHolder = this.uiConfigModeStateHolder; + if (stateHolder == null) return super.getFlexButton(x, y, width, height); + return new ImageCycleButtonWidget(x, y, width, height, GuiTextures.BUTTON_MINER_CONFIG_MODE, + stateHolder::get, stateHolder::set) + .setTooltipHoverString(i -> i == 0 ? + "gregtech.machine.miner.button.tooltip.info" : + "gregtech.machine.miner.button.tooltip.config"); + } + + @Override + protected void addDisplayText(List textList) {} // unused + + protected void addRealDisplayText(List textList, boolean configMode) { + if (!configMode) { + super.addDisplayText(textList); + } + + if (!this.isStructureFormed()) return; + + if (!configMode) { + if (energyContainer != null && energyContainer.getEnergyCapacity() > 0) { + int energyContainer = getEnergyTier(); + long maxVoltage = GTValues.V[energyContainer]; + String voltageName = GTValues.VNF[energyContainer]; + textList.add(new TextComponentTranslation("gregtech.multiblock.max_energy_per_tick", maxVoltage, + voltageName)); + } + } + + ITextComponent areaText; + int area, maxArea; + if (this.minerLogic.isChunkMode()) { + area = this.minerLogic.getCurrentChunkDiameter(); + maxArea = this.minerLogic.getMaximumChunkDiameter(); + areaText = new TextComponentTranslation("gregtech.machine.miner.display.working_area.chunks", area, area); + } else { + area = this.minerLogic.getCurrentDiameter(); + maxArea = this.minerLogic.getMaximumDiameter(); + areaText = new TextComponentTranslation("gregtech.machine.miner.display.working_area", area, area); + } + + if (configMode) { + areaText.appendText(" ").appendSibling(incrButton(area, maxArea, MinerUtil.DISPLAY_CLICK_AREA_INCR)) + .appendText(" ").appendSibling(decrButton(area, 1, MinerUtil.DISPLAY_CLICK_AREA_DECR)) + .appendText(" ").appendSibling(previewAreaButton(this.minerLogic.isPreviewEnabled())); + } + + textList.add(areaText); + + if (configMode) { + int yLimit = this.minerLogic.getYLimit(); + ITextComponent value; + ITextComponent hoverText; + if (yLimit > 0) { + value = new TextComponentString(String.format("%,d", yLimit)); + hoverText = new TextComponentTranslation("gregtech.machine.miner.display.y_limit.value_hover_tooltip", + value.createCopy()); + } else { + value = new TextComponentTranslation("gregtech.machine.miner.display.y_limit.no_value"); + hoverText = new TextComponentTranslation( + "gregtech.machine.miner.display.y_limit.value_hover_tooltip.no_value"); + } + textList.add(new TextComponentTranslation( + "gregtech.machine.miner.display.y_limit", new TextComponentString("") + .appendSibling(incrButton(yLimit, Integer.MAX_VALUE, MinerUtil.DISPLAY_CLICK_Y_LIMIT_INCR)) + .appendText(" ").appendSibling(decrButton(yLimit, 0, MinerUtil.DISPLAY_CLICK_Y_LIMIT_DECR)) + .appendText(" ").appendSibling(value)) + .setStyle(new Style() + .setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverText)))); + + textList.add(new TextComponentTranslation("gregtech.machine.miner.display.repeat", + toggleButton(this.minerLogic.isRepeat(), this.minerLogic.isWorking(), + MinerUtil.DISPLAY_CLICK_REPEAT_ENABLE, MinerUtil.DISPLAY_CLICK_REPEAT_DISABLE))); + + textList.add(new TextComponentTranslation("gregtech.machine.miner.display.chunk_mode", + toggleButton(this.minerLogic.isChunkMode(), this.minerLogic.isWorking(), + MinerUtil.DISPLAY_CLICK_CHUNK_MODE_ENABLE, MinerUtil.DISPLAY_CLICK_CHUNK_MODE_DISABLE))); + + textList.add(new TextComponentTranslation("gregtech.machine.miner.display.silk_touch", + toggleButton(this.minerLogic.isSilkTouchMode(), this.minerLogic.isWorking(), + MinerUtil.DISPLAY_CLICK_SILK_TOUCH_ENABLE, MinerUtil.DISPLAY_CLICK_SILK_TOUCH_DISABLE))); + + ITextComponent replaceOreText = new TextComponentTranslation( + this.minerLogic.getOreReplacement().getBlock().getTranslationKey() + ".name"); + if (!this.minerLogic.isWorking()) { + replaceOreText = new TextComponentString("[") + .appendSibling(replaceOreText.setStyle(new Style().setColor(TextFormatting.AQUA))) + .appendText("]").setStyle(button(this.minerLogic.isReplaceOreWithAir() ? + MinerUtil.DISPLAY_CLICK_REPLACE_ORE_DISABLE : + MinerUtil.DISPLAY_CLICK_REPLACE_ORE_ENABLE)); + } + + textList.add(new TextComponentTranslation("gregtech.machine.miner.display.replace_ore", replaceOreText)); + } else { + appendWorkingStatus(textList); + + textList.add(new TextComponentTranslation( + "gregtech.machine.miner.display.stats.total_mined", this.minedOreCount)); + if (this.hasLastMinedOre) { + textList.add(new TextComponentTranslation( + "gregtech.machine.miner.display.stats.last_mined", + this.lastMinedOre.getX(), this.lastMinedOre.getY(), this.lastMinedOre.getZ())); + } + } + } + + protected void appendWorkingStatus(List textList) { + if (!this.minerLogic.isDone()) { + MiningArea miningArea = minerLogic.getMiningArea(); + if (miningArea != null) { + MutableBlockPos mpos = new MutableBlockPos(); + if (miningArea.getCurrentBlockPos(mpos)) { + if (this.minerLogic.isWorking()) { + textList.add(TextComponentUtil.translationWithColor(TextFormatting.GOLD, + "gregtech.machine.miner.display.working", mpos.getX(), mpos.getY(), mpos.getZ())); + } else if (!isWorkingEnabled()) { + textList.add(new TextComponentTranslation("gregtech.multiblock.work_paused")); + } + return; + } + } + } + textList.add(TextComponentUtil.translationWithColor(TextFormatting.GREEN, + "gregtech.machine.miner.display.done")); + } + + @NotNull + protected static ITextComponent previewAreaButton(boolean previewEnabled) { + return new TextComponentTranslation(previewEnabled ? + "gregtech.machine.miner.display.working_area.hide_preview" : + "gregtech.machine.miner.display.working_area.preview") + .setStyle(button(previewEnabled ? MinerUtil.DISPLAY_CLICK_AREA_PREVIEW_HIDE : + MinerUtil.DISPLAY_CLICK_AREA_PREVIEW)); + } + + @NotNull + protected static ITextComponent incrButton(int currentValue, int maxValue, @NotNull String event) { + return currentValue >= maxValue ? + new TextComponentTranslation("gregtech.machine.miner.display.incr.disabled") : + new TextComponentTranslation("gregtech.machine.miner.display.incr").setStyle(button(event)); + } + + @NotNull + protected static ITextComponent decrButton(int currentValue, int minValue, @NotNull String event) { + return currentValue <= minValue ? + new TextComponentTranslation("gregtech.machine.miner.display.decr.disabled") : + new TextComponentTranslation("gregtech.machine.miner.display.decr").setStyle(button(event)); + } + + @NotNull + protected static ITextComponent toggleButton(boolean currentValue, boolean canInteract, @NotNull String onEvent, + @NotNull String offEvent) { + return canInteract ? + new TextComponentTranslation(currentValue ? + "gregtech.machine.miner.display.enabled" : "gregtech.machine.miner.display.disabled") : + new TextComponentTranslation(currentValue ? + "gregtech.machine.miner.display.toggle.enabled" : + "gregtech.machine.miner.display.toggle.disabled") + .setStyle(button(currentValue ? offEvent : onEvent)); + } + + @NotNull + protected static Style button(@NotNull String event) { + return new Style().setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "@!" + event)); + } + + @Override + protected void handleDisplayClick(String componentData, Widget.ClickData clickData) { + switch (componentData) { + case MinerUtil.DISPLAY_CLICK_AREA_PREVIEW -> this.minerLogic.setPreviewEnabled(true); + case MinerUtil.DISPLAY_CLICK_AREA_PREVIEW_HIDE -> this.minerLogic.setPreviewEnabled(false); + case MinerUtil.DISPLAY_CLICK_AREA_DECR -> { + int diff = clickData.isShiftClick ? 5 : 1; + if (this.minerLogic.isChunkMode()) { + this.minerLogic.setCurrentChunkDiameter(this.minerLogic.getCurrentChunkDiameter() - diff); + } else { + this.minerLogic.setCurrentDiameter(this.minerLogic.getCurrentDiameter() - diff); + } + } + case MinerUtil.DISPLAY_CLICK_AREA_INCR -> { + int diff = clickData.isShiftClick ? 5 : 1; + if (this.minerLogic.isChunkMode()) { + this.minerLogic.setCurrentChunkDiameter(this.minerLogic.getCurrentChunkDiameter() + diff); + } else { + this.minerLogic.setCurrentDiameter(this.minerLogic.getCurrentDiameter() + diff); + } + } + case MinerUtil.DISPLAY_CLICK_Y_LIMIT_DECR -> this.minerLogic.setYLimit(Math.max(0, + this.minerLogic.getYLimit() - (clickData.isShiftClick ? 5 : 1))); + case MinerUtil.DISPLAY_CLICK_Y_LIMIT_INCR -> { + int yLimit = this.minerLogic.getYLimit() + (clickData.isShiftClick ? 5 : 1); + if (yLimit < 0) yLimit = this.minerLogic.getYLimit() < 0 ? 0 : Integer.MAX_VALUE; + this.minerLogic.setYLimit(yLimit); + } + case MinerUtil.DISPLAY_CLICK_REPEAT_ENABLE -> this.minerLogic.setRepeat(true); + case MinerUtil.DISPLAY_CLICK_REPEAT_DISABLE -> this.minerLogic.setRepeat(false); + case MinerUtil.DISPLAY_CLICK_REPLACE_ORE_ENABLE -> this.minerLogic.setReplaceOreWithAir(true); + case MinerUtil.DISPLAY_CLICK_REPLACE_ORE_DISABLE -> this.minerLogic.setReplaceOreWithAir(false); + case MinerUtil.DISPLAY_CLICK_CHUNK_MODE_ENABLE -> this.minerLogic.setChunkMode(true); + case MinerUtil.DISPLAY_CLICK_CHUNK_MODE_DISABLE -> this.minerLogic.setChunkMode(false); + case MinerUtil.DISPLAY_CLICK_SILK_TOUCH_ENABLE -> this.minerLogic.setSilkTouchMode(true); + case MinerUtil.DISPLAY_CLICK_SILK_TOUCH_DISABLE -> this.minerLogic.setSilkTouchMode(false); + } + } + + @Override + protected void addWarningText(List textList) { + MultiblockDisplayText.builder(textList, isStructureFormed(), false) + .addMaintenanceProblemLines(getMaintenanceProblems()) + .addLowPowerLine(isStructureFormed() && !drainEnergy(true)) + .addCustom(l -> { + if (isStructureFormed()) { + if (inventoryFull) { + l.add(new TextComponentTranslation("gregtech.machine.miner.display.inventory_full") + .setStyle(new Style().setColor(TextFormatting.RED))); + } + } + }); + } + + @Override + protected void addErrorText(List textList) { + MultiblockDisplayText.builder(textList, isStructureFormed()) + .addCustom(l -> { + if (!drainFluid(true)) { + l.add(new TextComponentTranslation("gregtech.machine.miner.multi.needsfluid") + .setStyle(new Style().setColor(TextFormatting.RED))); + } + }); + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + this.minerLogic.writeToNBT(data); + + if (this.hasLastMinedOre) { + data.setInteger("lastMinedOreX", this.lastMinedOre.getX()); + data.setInteger("lastMinedOreY", this.lastMinedOre.getY()); + data.setInteger("lastMinedOreZ", this.lastMinedOre.getZ()); + } + + data.setInteger("minedOreCount", this.minedOreCount); + + return data; + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + this.minerLogic.readFromNBT(data); + if (data.hasKey("lastMinedOreX", Constants.NBT.TAG_INT)) { + this.lastMinedOre.setPos(data.getInteger("lastMinedOreX"), + data.getInteger("lastMinedOreY"), + data.getInteger("lastMinedOreZ")); + this.hasLastMinedOre = true; + } else { + this.hasLastMinedOre = false; + } + + this.minedOreCount = Math.max(0, data.getInteger("minedOreCount")); + } + + @Override + public void writeInitialSyncData(PacketBuffer buf) { + super.writeInitialSyncData(buf); + this.minerLogic.writeInitialSyncData(buf); + } + + @Override + public void receiveInitialSyncData(PacketBuffer buf) { + super.receiveInitialSyncData(buf); + this.minerLogic.receiveInitialSyncData(buf); + } + + @Override + public void receiveCustomData(int dataId, PacketBuffer buf) { + super.receiveCustomData(dataId, buf); + this.minerLogic.receiveCustomData(dataId, buf); + } + + @Override + @SideOnly(Side.CLIENT) + public ICubeRenderer getBaseTexture(@Nullable IMultiblockPart sourcePart) { + return this.type.getBaseTexture(sourcePart); + } + + @NotNull + @Override + @SideOnly(Side.CLIENT) + protected ICubeRenderer getFrontOverlay() { + return this.type.getFrontOverlay(); + } + + @Override + public boolean hasMaintenanceMechanics() { + return false; + } + + @Override + public boolean isWorkingEnabled() { + return this.minerLogic.isWorkingEnabled(); + } + + @Override + public void setWorkingEnabled(boolean isActivationAllowed) { + this.minerLogic.setWorkingEnabled(isActivationAllowed); + } + + @Override + public T getCapability(Capability capability, EnumFacing side) { + if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { + return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); + } + return super.getCapability(capability, side); + } + + @Override + public SoundEvent getSound() { + return GTSoundEvents.MINER; + } + + @Override + public boolean isActive() { + return isStructureFormed() && minerLogic.isActive(); + } + + @NotNull + @Override + public List getDataInfo() { + int diameter = this.minerLogic.getCurrentDiameter(); + return Collections.singletonList( + new TextComponentTranslation("gregtech.machine.miner.working_area", diameter, diameter)); + } + + @Override + protected boolean shouldShowVoidingModeButton() { + return false; + } + + @Override + public double getFillPercentage(int index) { + long drillingFluidAmount = 0, fluidCapacity = 0; + for (IMultipleTankHandler.MultiFluidTankEntry tank : this.inputFluidInventory.getFluidTanks()) { + FluidStack fluid = tank.getFluid(); + if (fluid != null && CommonFluidFilters.matchesFluid(fluid, Materials.DrillingFluid)) { + drillingFluidAmount += tank.getFluidAmount(); + } + fluidCapacity += tank.getCapacity(); + } + return (double) drillingFluidAmount / fluidCapacity; + } + + @Override + public TextureArea getProgressBarTexture(int index) { + return GuiTextures.PROGRESS_BAR_MINER_DRILLING_FLUID; + } +} diff --git a/src/main/java/gregtech/common/metatileentities/miner/MetaTileEntityMiner.java b/src/main/java/gregtech/common/metatileentities/miner/MetaTileEntityMiner.java new file mode 100644 index 00000000000..e1bcf9f7c82 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/miner/MetaTileEntityMiner.java @@ -0,0 +1,331 @@ +package gregtech.common.metatileentities.miner; + +import gregtech.api.GTValues; +import gregtech.api.capability.GregtechTileCapabilities; +import gregtech.api.capability.IControllable; +import gregtech.api.capability.impl.EnergyContainerHandler; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.ModularUI; +import gregtech.api.gui.widgets.AdvancedTextWidget; +import gregtech.api.gui.widgets.ClickButtonWidget; +import gregtech.api.gui.widgets.ImageWidget; +import gregtech.api.gui.widgets.ProgressWidget; +import gregtech.api.gui.widgets.SlotWidget; +import gregtech.api.gui.widgets.ToggleButtonWidget; +import gregtech.api.items.itemhandlers.GTItemStackHandler; +import gregtech.api.metatileentity.IDataInfoProvider; +import gregtech.api.metatileentity.IFastRenderMetaTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.TieredMetaTileEntity; +import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; +import gregtech.api.util.GTTransferUtils; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import gregtech.client.model.miningpipe.MiningPipeModel; +import gregtech.client.model.miningpipe.MiningPipeModels; +import gregtech.client.renderer.texture.Textures; +import gregtech.core.sound.GTSoundEvents; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemStackHandler; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.vec.Matrix4; +import com.google.common.math.IntMath; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.math.RoundingMode; +import java.util.Collections; +import java.util.List; + +public class MetaTileEntityMiner extends TieredMetaTileEntity + implements Miner, IControllable, IDataInfoProvider, IFastRenderMetaTileEntity { + + private final ItemStackHandler chargerInventory; + + private final int inventorySize; + private final long energyPerTick; + + private final MinerLogic minerLogic; + + public MetaTileEntityMiner(@NotNull ResourceLocation metaTileEntityId, int tier, int workFrequency, + int maximumDiameter) { + super(metaTileEntityId, tier); + this.inventorySize = (tier + 1) * (tier + 1); + this.energyPerTick = GTValues.V[tier - 1]; + this.minerLogic = new MinerLogic<>(this, workFrequency, maximumDiameter); + this.chargerInventory = new GTItemStackHandler(this, 1); + initializeInventory(); + } + + @Override + public MetaTileEntity createMetaTileEntity(IGregTechTileEntity tileEntity) { + return new MetaTileEntityMiner(metaTileEntityId, getTier(), this.minerLogic.getWorkFrequency(), + this.minerLogic.getMaximumDiameter()); + } + + @Override + protected IItemHandlerModifiable createExportItemHandler() { + return new GTItemStackHandler(this, inventorySize); + } + + @Override + @SideOnly(Side.CLIENT) + public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { + super.renderMetaTileEntity(renderState, translation, pipeline); + Textures.MINER_OVERLAY.renderOrientedState(renderState, translation, pipeline, getFrontFacing(), + minerLogic.isActive(), minerLogic.isWorkingEnabled()); + } + + @Override + public void renderMetaTileEntity(double x, double y, double z, float partialTicks) { + MiningArea previewArea = this.minerLogic.getPreviewArea(); + if (previewArea != null) previewArea.renderMetaTileEntity(this, x, y, z, partialTicks); + } + + @Override + public void renderMetaTileEntityFast(CCRenderState renderState, Matrix4 translation, float partialTicks) { + MiningArea previewArea = this.minerLogic.getPreviewArea(); + if (previewArea != null) previewArea.renderMetaTileEntityFast(this, renderState, translation, partialTicks); + } + + @Override + public AxisAlignedBB getRenderBoundingBox() { + MiningArea previewArea = this.minerLogic.getPreviewArea(); + return previewArea != null ? previewArea.getRenderBoundingBox() : MinerUtil.EMPTY_AABB; + } + + @Override + public boolean shouldRenderInPass(int pass) { + MiningArea previewArea = this.minerLogic.getPreviewArea(); + return previewArea != null && previewArea.shouldRenderInPass(pass); + } + + @Override + public boolean isGlobalRenderer() { + return true; + } + + @Override + protected ModularUI createUI(@NotNull EntityPlayer entityPlayer) { + IItemHandlerModifiable exportItems = this.getExportItems(); + int slots = exportItems.getSlots(); + int columns = IntMath.sqrt(slots, RoundingMode.UP); + int xStart = (176 - (18 * columns)) / 2; + int yOffset = Math.max(0, 16 + ((columns + 1) * 18) + 4 - 80); + int yStart = yOffset > 0 ? 16 : 21; + int sideWidgetY = yStart + (columns * 18 - 20) / 2; + + ModularUI.Builder builder = ModularUI.defaultBuilder(yOffset) + .label(5, 5, getMetaFullName()) + .widget(new ToggleButtonWidget(152, yStart, 18, 18, + GuiTextures.BUTTON_MINER_AREA_PREVIEW, + this.minerLogic::isPreviewEnabled, this.minerLogic::setPreviewEnabled)) + .widget(new ClickButtonWidget(161, yStart + 18 + 2, 9, 9, + "", cd -> this.minerLogic.setCurrentDiameter( + this.minerLogic.getCurrentDiameter() + (cd.isShiftClick ? 5 : 1))) + .setButtonTexture(GuiTextures.BUTTON_INT_CIRCUIT_PLUS)) + .widget(new ClickButtonWidget(161, yStart + 18 + 2 + 9, 9, 9, + "", cd -> this.minerLogic.setCurrentDiameter( + this.minerLogic.getCurrentDiameter() - (cd.isShiftClick ? 5 : 1))) + .setButtonTexture(GuiTextures.BUTTON_INT_CIRCUIT_MINUS)) + .widget(new AdvancedTextWidget(159, yStart + 18 + 2 + (18 - 11) / 2, list -> { + int currentDiameter = this.minerLogic.getCurrentDiameter(); + list.add(new TextComponentString(currentDiameter + "x" + currentDiameter)); + }, 0x404040) { + + @Override + protected void onSizeUpdate() { // >:( + Size size = this.getSize(); + this.setSelfPosition(new Position(159 - size.width, this.getSelfPosition().y)); + } + }) + .widget(new SlotWidget(this.chargerInventory, 0, 79, 62 + yOffset, true, true, false) + .setBackgroundTexture(GuiTextures.SLOT, GuiTextures.CHARGER_OVERLAY) + .setTooltipText("gregtech.gui.charger_slot.tooltip", GTValues.VNF[getTier()], + GTValues.VNF[getTier()])); + + for (int i = 0; i < slots; i++) { + builder.slot(exportItems, i, xStart + 18 * (i % columns), yStart + 18 * (i / columns), + true, false, GuiTextures.SLOT); + } + + builder.widget( + new ProgressWidget(this.minerLogic::getWorkProgress, xStart - 4 - 20, sideWidgetY, 20, 20, + GuiTextures.PROGRESS_BAR_MACERATE, ProgressWidget.MoveType.HORIZONTAL)) + .widget( + new ImageWidget(xStart - 4 - 20, sideWidgetY + 20, 18, 18, + GuiTextures.INDICATOR_NO_ENERGY) + .setIgnoreColor(true) + .setPredicate(minerLogic::hasNotEnoughEnergy)) + .widget( + new ImageWidget(152, 63 + yOffset, 17, 17, + GTValues.XMAS.get() ? GuiTextures.GREGTECH_LOGO_XMAS : GuiTextures.GREGTECH_LOGO) + .setIgnoreColor(true)) + .bindPlayerInventory(entityPlayer.inventory, GuiTextures.SLOT, yOffset); + + return builder.build(getHolder(), entityPlayer); + } + + @Override + public void addInformation(ItemStack stack, @Nullable World player, @NotNull List tooltip, + boolean advanced) { + tooltip.add(I18n.format("gregtech.machine.miner.tooltip")); + tooltip.add( + I18n.format("gregtech.universal.tooltip.uses_per_tick", energyPerTick) + TextFormatting.GRAY + ", " + + I18n.format("gregtech.machine.miner.per_block", this.minerLogic.getWorkFrequency() / 20)); + tooltip.add(I18n.format("gregtech.universal.tooltip.voltage_in", energyContainer.getInputVoltage(), + GTValues.VNF[getTier()])); + tooltip.add( + I18n.format("gregtech.universal.tooltip.energy_storage_capacity", energyContainer.getEnergyCapacity())); + int maxArea = minerLogic.getMaximumDiameter(); + tooltip.add(I18n.format("gregtech.universal.tooltip.working_area_max", maxArea, maxArea)); + } + + @Override + public void addToolUsages(ItemStack stack, @Nullable World world, List tooltip, boolean advanced) { + tooltip.add(I18n.format("gregtech.tool_action.screwdriver.toggle_mode_covers")); + tooltip.add(I18n.format("gregtech.tool_action.wrench.set_facing")); + tooltip.add(I18n.format("gregtech.tool_action.soft_mallet.reset")); + super.addToolUsages(stack, world, tooltip, advanced); + } + + @Override + public boolean drainMiningResources(@NotNull MinedBlockType minedBlockType, boolean pipeExtended, + boolean simulate) { + if (minedBlockType == MinedBlockType.NOTHING) return true; + long resultEnergy = energyContainer.getEnergyStored() - energyPerTick; + if (resultEnergy < 0 || resultEnergy > energyContainer.getEnergyCapacity()) return false; + if (!simulate) { + energyContainer.removeEnergy(energyPerTick); + } + return true; + } + + @Override + public boolean collectBlockDrops(@NotNull World world, @NotNull BlockPos pos, @NotNull IBlockState state) { + NonNullList drops = NonNullList.create(); + IItemHandlerModifiable inventory = getExportItems(); + state.getBlock().getDrops(drops, world, pos, state, 0); + if (GTTransferUtils.addItemsToItemHandler(inventory, true, drops)) { + GTTransferUtils.addItemsToItemHandler(inventory, false, drops); + return true; + } else { + return false; + } + } + + @NotNull + @Override + @SideOnly(Side.CLIENT) + public MiningPipeModel getMiningPipeModel() { + return MiningPipeModels.STEEL; + } + + @Override + public void update() { + super.update(); + this.minerLogic.update(); + if (!getWorld().isRemote) { + ((EnergyContainerHandler) this.energyContainer).dischargeOrRechargeEnergyContainers(chargerInventory, 0); + if (getOffsetTimer() % 5 == 0) + pushItemsIntoNearbyHandlers(getFrontFacing()); + } + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + data.setTag("ChargerInventory", chargerInventory.serializeNBT()); + return this.minerLogic.writeToNBT(data); + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + this.chargerInventory.deserializeNBT(data.getCompoundTag("ChargerInventory")); + this.minerLogic.readFromNBT(data); + } + + @Override + public void writeInitialSyncData(@NotNull PacketBuffer buf) { + super.writeInitialSyncData(buf); + this.minerLogic.writeInitialSyncData(buf); + } + + @Override + public void receiveInitialSyncData(@NotNull PacketBuffer buf) { + super.receiveInitialSyncData(buf); + this.minerLogic.receiveInitialSyncData(buf); + } + + @Override + public void receiveCustomData(int dataId, @NotNull PacketBuffer buf) { + super.receiveCustomData(dataId, buf); + this.minerLogic.receiveCustomData(dataId, buf); + } + + @Override + public T getCapability(Capability capability, EnumFacing side) { + if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { + return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); + } + return super.getCapability(capability, side); + } + + @Override + public void clearMachineInventory(NonNullList itemBuffer) { + super.clearMachineInventory(itemBuffer); + clearInventory(itemBuffer, chargerInventory); + } + + @Override + public boolean isWorkingEnabled() { + return this.minerLogic.isWorkingEnabled(); + } + + @Override + public void setWorkingEnabled(boolean isActivationAllowed) { + this.minerLogic.setWorkingEnabled(isActivationAllowed); + } + + @Override + public SoundEvent getSound() { + return GTSoundEvents.MINER; + } + + @Override + public boolean isActive() { + return minerLogic.isActive(); + } + + @NotNull + @Override + public List getDataInfo() { + int diameter = minerLogic.getCurrentDiameter(); + return Collections.singletonList( + new TextComponentTranslation("gregtech.machine.miner.working_area", diameter, diameter)); + } +} diff --git a/src/main/java/gregtech/common/metatileentities/miner/Miner.java b/src/main/java/gregtech/common/metatileentities/miner/Miner.java new file mode 100644 index 00000000000..62f5c8e1ac4 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/miner/Miner.java @@ -0,0 +1,71 @@ +package gregtech.common.metatileentities.miner; + +import gregtech.client.model.miningpipe.MiningPipeModel; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import org.jetbrains.annotations.NotNull; + +public interface Miner { + + /** + * Try to drain all mining resources required for one operation. (e.g. energy, mining fluids) + * + * @param minedBlockType Type of the block mined + * @param pipeExtended Whether the pipe length got extended + * @param simulate If {@code true}, this action will not affect the state of the game + * @return Whether the action was successful + */ + boolean drainMiningResources(@NotNull MinedBlockType minedBlockType, boolean pipeExtended, boolean simulate); + + /** + * Try to collect drops from the block. {@code true} is returned if the block drop is successfully collected; + * {@code false} means the operation cannot be done (ex. not enough inventory space to store the drops). Returning + * {@code false} will momentarily halt the miner operation. + * + * @param world the {@link World} the miner is in + * @param pos the {@link BlockPos} of the block being mined + * @param state the {@link IBlockState} of the block being mined + * @return Whether the action was successful + */ + boolean collectBlockDrops(@NotNull World world, @NotNull BlockPos pos, @NotNull IBlockState state); + + @NotNull + @SideOnly(Side.CLIENT) + MiningPipeModel getMiningPipeModel(); + + default boolean canOperate() { + return true; + } + + /** + * Called after each block is mined. + * + * @param pos position of the block mined + * @param isOre whether it was ore block + * @param isOrigin whether it was origin (the block mining pipe goes in) + */ + default void onMineOperation(@NotNull BlockPos pos, boolean isOre, boolean isOrigin) {} + + /** + * Type of the block mined. + */ + enum MinedBlockType { + /** + * Mined nothing + */ + NOTHING, + /** + * Mined an ore + */ + ORE, + /** + * Mined a block that isn't an ore, like a block in the center (pipe column). + */ + BLOCK + } +} diff --git a/src/main/java/gregtech/common/metatileentities/miner/MinerLogic.java b/src/main/java/gregtech/common/metatileentities/miner/MinerLogic.java new file mode 100644 index 00000000000..1536ada98c8 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/miner/MinerLogic.java @@ -0,0 +1,468 @@ +package gregtech.common.metatileentities.miner; + +import gregtech.api.capability.GregtechDataCodes; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.util.BlockUtility; +import gregtech.common.entities.MiningPipeEntity; +import gregtech.common.metatileentities.miner.Miner.MinedBlockType; + +import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockPos.MutableBlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class MinerLogic { + + protected final MTE mte; + + private final int workFrequency; + private final int maximumDiameter; + + private final MutableBlockPos mpos = new MutableBlockPos(); + + protected int currentDiameter; + + // flag indicating the miner has finished its action + protected boolean done; + + private boolean workingEnabled = true; + + // pipe length used for rendering purposes + private int pipeLength; + + // transient fields below (not saved to NBT) + + @Nullable + private MiningArea miningArea; + + private boolean active; + private int workDelay; + // flag indicating mining area should be rebuilt + protected boolean rebuildMiningArea; + // flag for area preview + private boolean preview; + private int prevPipeLength; + + private boolean hasNotEnoughEnergy; + + // remote instances only, contains MiningArea instances deserialized from packet + @Nullable + private MiningArea previewArea; + + private final List> pipeEntities = new ArrayList<>(); + + /** + * Creates the general logic for all in-world ore block miners + * + * @param mte the {@link MetaTileEntity} this logic belongs to + * @param workFrequency work frequency in ticks. In other words, the miner will operate every + * {@code workFrequency} ticks; once a second in {@code 20}, every other tick in {@code 2}, + * and each tick in {@code 1}. + * @param maximumDiameter the maximum diameter of a square the miner can mine in + * @throws IllegalArgumentException if {@code workFrequency <= 0} + * @throws NullPointerException if {@code mte == null} + */ + public MinerLogic(@NotNull MTE mte, int workFrequency, int maximumDiameter) { + if (workFrequency <= 0) throw new IllegalArgumentException("workFrequency <= 0"); + this.mte = Objects.requireNonNull(mte, "mte == null"); + this.workDelay = this.workFrequency = workFrequency; + this.currentDiameter = this.maximumDiameter = maximumDiameter; + } + + public int getWorkFrequency() { + return this.workFrequency; + } + + public int getMaximumDiameter() { + return this.maximumDiameter; + } + + public int getCurrentDiameter() { + return this.currentDiameter; + } + + /** + * @param currentDiameter the radius to set the miner to use + */ + public void setCurrentDiameter(int currentDiameter) { + currentDiameter = Math.max(1, Math.min(currentDiameter, getMaximumDiameter())); + if (this.currentDiameter != currentDiameter) { + this.currentDiameter = currentDiameter; + this.rebuildMiningArea = true; + this.mte.markDirty(); + } + } + + public boolean isActive() { + return this.active; + } + + public int getPipeLength() { + return this.pipeLength; + } + + @Nullable + public MiningArea getPreviewArea() { + return this.previewArea; + } + + public double getWorkProgress() { + if (!isWorking()) return 0; + if (getWorkFrequency() == 2) return 1; + return 1 - (double) workDelay / getWorkFrequency(); + } + + /** + * @return whether working is enabled for the logic + */ + public boolean isWorkingEnabled() { + return this.workingEnabled; + } + + /** + * @param isWorkingEnabled the new state of the miner's ability to work: true to change to enabled, else false + */ + public void setWorkingEnabled(boolean isWorkingEnabled) { + if (this.workingEnabled != isWorkingEnabled) { + this.workingEnabled = isWorkingEnabled; + this.mte.markDirty(); + if (mte.getWorld() != null && !mte.getWorld().isRemote) { + this.mte.writeCustomData(GregtechDataCodes.WORKING_ENABLED, buf -> buf.writeBoolean(isWorkingEnabled)); + } + } + } + + public boolean isPreviewEnabled() { + return preview; + } + + public void setPreviewEnabled(boolean previewEnabled) { + if (this.preview != previewEnabled) { + this.preview = previewEnabled; + updatePreview(); + } + } + + /** + * @return whether the miner is currently working + */ + public boolean isWorking() { + return this.miningArea != null && !this.done && isWorkingEnabled() && !hasNotEnoughEnergy(); + } + + public boolean hasNotEnoughEnergy() { + return hasNotEnoughEnergy; + } + + public boolean isDone() { + return done; + } + + /** + * @return origin position of the miner. Block boundary will be centered around this position, and mining pipes will + * be rendered under this position. + */ + @NotNull + protected BlockPos getOrigin() { + return mte.getPos(); + } + + @Nullable + public final MiningArea getMiningArea() { + return this.miningArea; + } + + /** + * Create instance of {@link MiningArea} based on current state. + * + * @return new {@link MiningArea} instance + */ + @NotNull + protected MiningArea createMiningArea() { + BlockPos origin = getOrigin(); + int radius = this.currentDiameter / 2; + int startX = origin.getX() - radius; + int startZ = origin.getZ() - radius; + return new SimpleMiningArea(startX, origin.getY() - 1, startZ, + startX + this.currentDiameter, Integer.MIN_VALUE, startZ + this.currentDiameter); + } + + /** + * Recalculates the mining area and restarts the miner, if it was done + */ + public void reset() { + setPipeLength(0); + rebuildMiningArea(); + this.done = false; + } + + private void rebuildMiningArea() { + this.rebuildMiningArea = false; + this.miningArea = Objects.requireNonNull(createMiningArea(), "createMiningArea() returned null!"); + if (isPreviewEnabled()) { + updatePreview(); + } + } + + protected void updatePreview() { + this.mte.writeCustomData(GregtechDataCodes.MINER_UPDATE_PREVIEW, this::writePreviewUpdatePacket); + } + + /** + * Performs the actual mining in world. Call this method every tick in update. + */ + public void update() { + if (!this.mte.getWorld().isRemote) { + // rebuild scan area every tick regardless of miner status, for accurate preview + if (this.rebuildMiningArea || this.miningArea == null) { + reset(); + } + + updateLogic(); + } + + if (this.prevPipeLength != this.pipeLength) { + this.prevPipeLength = this.pipeLength; + int pipeIndex = 0; + int y = this.getOrigin().getY(); + int yEnd = y - this.pipeLength; + MiningPipeEntity entity = null; + + while (y > yEnd) { // divide segments every 16 blocks, aligned with Y position + int length = y % 16; + if (length == 0) length = 16; + length = Math.min(length, y - yEnd); + + entity = this.pipeEntities.size() > pipeIndex ? this.pipeEntities.get(pipeIndex) : null; + + if (entity == null || !entity.isEntityAlive()) { + entity = new MiningPipeEntity<>(this.mte, this.getOrigin()); + if (pipeIndex < this.pipeEntities.size()) this.pipeEntities.set(pipeIndex, entity); + else this.pipeEntities.add(entity); + this.mte.getWorld().spawnEntity(entity); + } + + entity.y = y; + entity.length = length; + entity.end = false; + y -= length; + pipeIndex++; + } + + if (entity != null) entity.end = true; + + for (int i = this.pipeEntities.size() - 1; i >= pipeIndex; i--) { + this.pipeEntities.remove(i).setDead(); + } + } + } + + protected void updateLogic() { + if (this.mte.drainMiningResources(MinedBlockType.ORE, true, true)) { + this.hasNotEnoughEnergy = false; + } else { + this.hasNotEnoughEnergy = true; + return; + } + + mine(Objects.requireNonNull(this.miningArea)); + boolean active = !this.done; + if (this.active != active) { + this.active = active; + this.mte.writeCustomData(GregtechDataCodes.MINER_UPDATE_ACTIVE, b -> b.writeBoolean(active)); + } + } + + protected void mine(@NotNull MiningArea miningArea) { + if (this.done || --this.workDelay > 0) return; + this.workDelay = this.workFrequency; + if (!this.workingEnabled || !this.mte.canOperate()) return; + + World world = mte.getWorld(); + BlockPos origin = getOrigin(); + MutableBlockPos pos = this.mpos; + + for (int i = MinerUtil.MAX_BLOCK_SCAN; i > 0; i--) { + if (!miningArea.getCurrentBlockPos(pos) || mte.getWorld().isOutsideBuildHeight(pos)) { + this.done = true; + return; + } + IBlockState state = world.getBlockState(pos); + boolean isOrigin = pos.getX() == origin.getX() && pos.getZ() == origin.getZ(); + + // skip air, unbreakable blocks, TE blocks & liquids + if (state.getMaterial() == Material.AIR || + state.getBlockHardness(world, pos) < 0 || + state.getBlock().hasTileEntity(state) || + state.getMaterial().isLiquid()) { + miningArea.nextBlock(); + if (!isOrigin) { + continue; + } + // center block (where mining pipes goes in) can be skipped by this, it'll probably look kind of janky + // but it's 100x better than voiding bedrock + if (!this.mte.drainMiningResources(MinedBlockType.NOTHING, true, false)) { + return; + } + setPipeLength(this.pipeLength + 1); + this.workDelay /= 2; + return; + } + + boolean isOre = BlockUtility.isOre(state); + if (!isOrigin && !isOre) { + miningArea.nextBlock(); + continue; + } + + if (!this.mte.drainMiningResources(isOre ? MinedBlockType.ORE : MinedBlockType.BLOCK, true, false)) { + return; + } + + if (isOre && !this.mte.collectBlockDrops(world, pos, state)) { + return; + } + world.setBlockState(pos, isOrigin ? Blocks.AIR.getDefaultState() : getOreReplacement()); + if (isOrigin) setPipeLength(this.pipeLength + 1); + miningArea.nextBlock(); + this.mte.onMineOperation(pos, isOre, isOrigin); + this.mte.markDirty(); + return; + + } + this.workDelay = 1; // re-scan next tick + } + + @NotNull + protected IBlockState getOreReplacement() { + return MinerUtil.getOreReplacement(); + } + + private void setPipeLength(int length) { + if (this.pipeLength == length) return; + this.pipeLength = length; + this.mte.markDirty(); + this.mte.writeCustomData(GregtechDataCodes.PUMP_HEAD_LEVEL, b -> b.writeVarInt(length)); + } + + protected void writePreviewUpdatePacket(@NotNull PacketBuffer buffer) { + if (this.preview) { + MiningArea miningArea = this.miningArea; + if (miningArea != null) { + buffer.writeBoolean(true); + miningArea.writePreviewPacket(buffer); + return; + } + } + buffer.writeBoolean(false); + } + + protected void readPreviewUpdatePacket(@NotNull PacketBuffer buffer) { + this.previewArea = buffer.readBoolean() ? readPreviewArea(buffer) : null; + } + + @NotNull + protected MiningArea readPreviewArea(@NotNull PacketBuffer buffer) { + return SimpleMiningArea.readPreview(buffer); + } + + /** + * Write states to NBT. Call this method in {@link MetaTileEntity#writeToNBT(NBTTagCompound)}. + */ + @NotNull + public NBTTagCompound writeToNBT(@NotNull NBTTagCompound data) { + data.setInteger("currentDiameter", this.currentDiameter); + if (!this.workingEnabled) data.setBoolean("disabled", true); + if (this.done) data.setBoolean("done", true); + + data.setInteger("pipeLength", this.pipeLength); + + if (this.miningArea != null) { + this.miningArea.write(data); + } + + return data; + } + + /** + * Read states from NBT. Call this method in {@link MetaTileEntity#readFromNBT(NBTTagCompound)}. + */ + public void readFromNBT(@NotNull NBTTagCompound data) { + this.rebuildMiningArea = false; + + if (data.hasKey("xPos", Constants.NBT.TAG_INT)) { + // retro save compat + this.currentDiameter = MathHelper.clamp(data.getInteger("currentRadius") * 2 + 1, 1, getMaximumDiameter()); + + this.workingEnabled = data.getInteger("isWorkingEnabled") != 0; + this.pipeLength = data.getInteger("pipeLength"); + return; + } + + this.currentDiameter = MathHelper.clamp(data.getInteger("currentDiameter"), 1, getMaximumDiameter()); + this.workingEnabled = !data.getBoolean("disabled"); + this.done = data.getBoolean("done"); + + this.pipeLength = Math.max(0, data.getInteger("pipeLength")); + + this.miningArea = createMiningArea(); + // Shouldn't be a problem but whatever + // noinspection ConstantValue + if (this.miningArea != null) { + this.miningArea.read(data); + } + } + + /** + * Write states to packet buffer. Call this method in {@link MetaTileEntity#writeInitialSyncData(PacketBuffer)}. + */ + public void writeInitialSyncData(@NotNull PacketBuffer buf) { + buf.writeVarInt(this.pipeLength); + buf.writeBoolean(this.workingEnabled); + buf.writeBoolean(this.done); + buf.writeBoolean(this.active); + writePreviewUpdatePacket(buf); + } + + /** + * Read states from packet buffer. Call this method in {@link MetaTileEntity#receiveInitialSyncData(PacketBuffer)}. + */ + public void receiveInitialSyncData(@NotNull PacketBuffer buf) { + this.pipeLength = buf.readVarInt(); + this.workingEnabled = buf.readBoolean(); + this.done = buf.readBoolean(); + this.active = buf.readBoolean(); + readPreviewUpdatePacket(buf); + } + + /** + * Callback for handling custom data packet sent by miner logic. Call this method in + * {@link MetaTileEntity#receiveCustomData(int, PacketBuffer)}. + */ + public void receiveCustomData(int dataId, @NotNull PacketBuffer buf) { + if (dataId == GregtechDataCodes.PUMP_HEAD_LEVEL) { + this.pipeLength = buf.readVarInt(); + } else if (dataId == GregtechDataCodes.WORKING_ENABLED) { + this.workingEnabled = buf.readBoolean(); + this.mte.scheduleRenderUpdate(); + } else if (dataId == GregtechDataCodes.MINER_UPDATE_PREVIEW) { + readPreviewUpdatePacket(buf); + } else if (dataId == GregtechDataCodes.MINER_UPDATE_ACTIVE) { + this.active = buf.readBoolean(); + this.mte.scheduleRenderUpdate(); + } + } +} diff --git a/src/main/java/gregtech/common/metatileentities/miner/MinerUtil.java b/src/main/java/gregtech/common/metatileentities/miner/MinerUtil.java new file mode 100644 index 00000000000..692ed542e6e --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/miner/MinerUtil.java @@ -0,0 +1,115 @@ +package gregtech.common.metatileentities.miner; + +import gregtech.api.GTValues; +import gregtech.api.recipes.Recipe; +import gregtech.api.recipes.RecipeMap; +import gregtech.api.unification.OreDictUnifier; +import gregtech.api.unification.ore.OrePrefix; +import gregtech.api.util.GTLog; +import gregtech.api.util.GTUtility; +import gregtech.common.ConfigHolder; + +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.AxisAlignedBB; + +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class MinerUtil { + + private MinerUtil() {} + + /** + * Maximum amount of blocks individual miners can scan in one tick + */ + public static final int MAX_BLOCK_SCAN = 200; + + public static final String DISPLAY_CLICK_AREA_PREVIEW = "preview_area"; + public static final String DISPLAY_CLICK_AREA_PREVIEW_HIDE = "hide_preview_area"; + public static final String DISPLAY_CLICK_AREA_DECR = "decr_area"; + public static final String DISPLAY_CLICK_AREA_INCR = "incr_area"; + public static final String DISPLAY_CLICK_Y_LIMIT_DECR = "decr_y_limit"; + public static final String DISPLAY_CLICK_Y_LIMIT_INCR = "incr_y_limit"; + public static final String DISPLAY_CLICK_REPEAT_ENABLE = "enable_repeat"; + public static final String DISPLAY_CLICK_REPEAT_DISABLE = "disable_repeat"; + public static final String DISPLAY_CLICK_REPLACE_ORE_ENABLE = "enable_replace_ore"; + public static final String DISPLAY_CLICK_REPLACE_ORE_DISABLE = "disable_replace_ore"; + public static final String DISPLAY_CLICK_CHUNK_MODE_ENABLE = "enable_chunk_mode"; + public static final String DISPLAY_CLICK_CHUNK_MODE_DISABLE = "disable_chunk_mode"; + public static final String DISPLAY_CLICK_SILK_TOUCH_ENABLE = "enable_silk_touch"; + public static final String DISPLAY_CLICK_SILK_TOUCH_DISABLE = "disable_silk_touch"; + + public static final AxisAlignedBB EMPTY_AABB = new AxisAlignedBB(0, 0, 0, 0, 0, 0); + + private static String oreReplacementConfigCache; + private static IBlockState oreReplacement; + + @NotNull + @SuppressWarnings("deprecation") + public static IBlockState getOreReplacement() { + String config = ConfigHolder.machines.replaceMinedBlocksWith; + if (Objects.equals(oreReplacementConfigCache, config)) { + return oreReplacement; + } + + oreReplacementConfigCache = config; + + String[] blockDescription = StringUtils.split(config, ":"); + String blockName = blockDescription.length <= 2 ? config : blockDescription[0] + ":" + blockDescription[1]; + Block block = Block.getBlockFromName(blockName); + + if (block == null) { + GTLog.logger.error( + "Invalid configuration on entry 'machines/replaceMinedBlocksWith': Cannot find block with name '{}', using cobblestone as fallback.", + blockName); + return oreReplacement = Blocks.COBBLESTONE.getDefaultState(); + } else if (blockDescription.length <= 2 || blockDescription[2].isEmpty()) { + return oreReplacement = block.getDefaultState(); + } else { + try { + return oreReplacement = block.getDefaultState().getBlock() + .getStateFromMeta(Integer.parseInt(blockDescription[2])); + } catch (NumberFormatException ex) { + GTLog.logger.error( + "Invalid configuration on entry 'machines/replaceMinedBlocksWith': Cannot parse metadata value '{}' as integer, using cobblestone as fallback.", + blockDescription[2]); + return oreReplacement = Blocks.COBBLESTONE.getDefaultState(); + } + } + } + + /** + * Applies a fortune hammer to block drops based on a tier value. + * + * @param stack the item stack to check for recipes + * @param drops where the drops are stored to + * @return amount of items inserted to {@code drops} + */ + public static int applyTieredHammerDrops(@NotNull ItemStack stack, @NotNull List drops, + int energyTier, @NotNull RecipeMap blockDropRecipeMap, + int oreMultiplier) { + Recipe recipe = blockDropRecipeMap.findRecipe( + GTValues.V[energyTier], + Collections.singletonList(stack), + Collections.emptyList()); + if (recipe == null || recipe.getOutputs().isEmpty()) return 0; + int c = 0; + for (ItemStack output : recipe.getResultItemOutputs(GTUtility.getTierByVoltage(recipe.getEUt()), energyTier, + blockDropRecipeMap)) { + output = output.copy(); + if (oreMultiplier > 0 && OreDictUnifier.getPrefix(output) == OrePrefix.crushed) { + output.grow(output.getCount() * oreMultiplier); + } + drops.add(output); + c++; + } + return c; + } +} diff --git a/src/main/java/gregtech/common/metatileentities/miner/MiningArea.java b/src/main/java/gregtech/common/metatileentities/miner/MiningArea.java new file mode 100644 index 00000000000..224d11f94cb --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/miner/MiningArea.java @@ -0,0 +1,79 @@ +package gregtech.common.metatileentities.miner; + +import gregtech.api.metatileentity.IFastRenderMetaTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos.MutableBlockPos; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.vec.Matrix4; +import org.jetbrains.annotations.NotNull; + +/** + * Object representing operation area of {@link MinerLogic}. + */ +public interface MiningArea { + + /** + * Get current block position for processing. If this method returns {@code true}, {@code mpos} argument should be + * modified to the block position. Return value of {@code false} indicates there aren't any block left to process. + *
+ * Calling this method does not affect the state. Use {@link #nextBlock()} for advancing to next block. + * + * @param mpos Mutable block position + * @return {@code true} if {@code mpos} is set to current block position for processing, {@code false} otherwise + */ + boolean getCurrentBlockPos(@NotNull MutableBlockPos mpos); + + /** + * Move on to next block for processing, if it exists. Does nothing if there aren't any block left to process. + * + * @see #getCurrentBlockPos(MutableBlockPos) + */ + void nextBlock(); + + /** + * Reset the cursor to starting point (i.e. re-start iteration from start) + */ + void reset(); + + @SideOnly(Side.CLIENT) + default void renderMetaTileEntityFast(@NotNull MetaTileEntity mte, @NotNull CCRenderState renderState, + @NotNull Matrix4 translation, float partialTicks) {} + + @SideOnly(Side.CLIENT) + default void renderMetaTileEntity(@NotNull MetaTileEntity mte, double x, double y, double z, float partialTicks) {} + + @NotNull + AxisAlignedBB getRenderBoundingBox(); + + default boolean shouldRenderInPass(int pass) { + return pass == IFastRenderMetaTileEntity.RENDER_PASS_TRANSLUCENT; + } + + /** + * Write any persistent data here. + * + * @param data NBT data + */ + void write(@NotNull NBTTagCompound data); + + /** + * Read any persistent data here. + * + * @param data NBT data + */ + void read(@NotNull NBTTagCompound data); + + /** + * Write data for area preview. + * + * @param buffer Packet buffer + */ + void writePreviewPacket(@NotNull PacketBuffer buffer); +} diff --git a/src/main/java/gregtech/common/metatileentities/miner/MultiblockMinerLogic.java b/src/main/java/gregtech/common/metatileentities/miner/MultiblockMinerLogic.java new file mode 100644 index 00000000000..6c30406d8a0 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/miner/MultiblockMinerLogic.java @@ -0,0 +1,194 @@ +package gregtech.common.metatileentities.miner; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockPos.MutableBlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.common.util.Constants; + +import org.jetbrains.annotations.NotNull; + +public class MultiblockMinerLogic extends MinerLogic { + + private final int maximumChunkDiameter; + + private final MutableBlockPos mpos = new MutableBlockPos(); + + private int currentChunkDiameter; + + private boolean chunkMode; + private boolean silkTouchMode; + + // non-negative value to limit Y level + private int yLimit; + + // bool config for repeating the operation after finished + private boolean repeat; + + // flag for disabling ore replacement (if true, ores will be replaced with air instead of whatever block that was + // specified in the config) + private boolean replaceOreWithAir; + + public MultiblockMinerLogic(@NotNull MetaTileEntityLargeMiner largeMiner, int workFrequency, + int maximumChunkDiameter) { + super(largeMiner, workFrequency, maximumChunkDiameter * 16); + this.currentChunkDiameter = this.maximumChunkDiameter = maximumChunkDiameter; + } + + @Override + protected void mine(@NotNull MiningArea miningArea) { + if (this.done && this.repeat) { + miningArea.reset(); + this.done = false; + } + super.mine(miningArea); + if (this.done && this.repeat) { + miningArea.reset(); + this.done = false; + } + } + + @NotNull + @Override + protected IBlockState getOreReplacement() { + return this.replaceOreWithAir ? Blocks.AIR.getDefaultState() : super.getOreReplacement(); + } + + @NotNull + @Override + protected MiningArea createMiningArea() { + BlockPos origin = getOrigin(); + if (this.chunkMode) { + int chunkRadius = this.currentChunkDiameter / 2; + int originChunkX = (origin.getX() >> 4) - chunkRadius; + int originChunkZ = (origin.getZ() >> 4) - chunkRadius; + return new SimpleMiningArea((originChunkX) * 16, + origin.getY() - 1, + (originChunkZ) * 16, + (originChunkX + currentChunkDiameter) * 16, + getYLimit() > 0 ? origin.getY() - getYLimit() : Integer.MIN_VALUE, + (originChunkZ + currentChunkDiameter) * 16); + } else { + int radius = this.currentDiameter / 2; + int startX = origin.getX() - radius; + int startY = origin.getY() - 1; + int startZ = origin.getZ() - radius; + int endX = startX + this.currentDiameter; + int endY = getYLimit() > 0 ? origin.getY() - getYLimit() : Integer.MIN_VALUE; + int endZ = startZ + this.currentDiameter; + return new SimpleMiningArea(startX, startY, startZ, endX, endY, endZ); + } + } + + @NotNull + @Override + protected BlockPos getOrigin() { + return this.mpos.setPos(this.mte.getPos()).move(this.mte.getFrontFacing().getOpposite()); + } + + public int getMaximumChunkDiameter() { + return maximumChunkDiameter; + } + + public int getCurrentChunkDiameter() { + return currentChunkDiameter; + } + + public void setCurrentChunkDiameter(int currentChunkDiameter) { + currentChunkDiameter = Math.max(1, Math.min(currentChunkDiameter, getMaximumChunkDiameter())); + setChunkMode(true); + if (this.currentChunkDiameter != currentChunkDiameter) { + this.currentChunkDiameter = currentChunkDiameter; + this.rebuildMiningArea = true; + this.mte.markDirty(); + } + } + + @Override + public void setCurrentDiameter(int currentDiameter) { + setChunkMode(false); + super.setCurrentDiameter(currentDiameter); + } + + public boolean isChunkMode() { + return this.chunkMode; + } + + public void setChunkMode(boolean chunkMode) { + if (this.chunkMode == chunkMode) return; + this.chunkMode = chunkMode; + this.rebuildMiningArea = true; + this.mte.markDirty(); + } + + public boolean isSilkTouchMode() { + return this.silkTouchMode; + } + + public void setSilkTouchMode(boolean silkTouchMode) { + if (isWorking() || this.silkTouchMode == silkTouchMode) return; + this.silkTouchMode = silkTouchMode; + this.mte.markDirty(); + } + + public int getYLimit() { + return yLimit; + } + + public void setYLimit(int yLimit) { + if (this.yLimit == yLimit) return; + this.yLimit = yLimit; + this.rebuildMiningArea = true; + this.mte.markDirty(); + if (this.isPreviewEnabled()) { + updatePreview(); + } + } + + public boolean isRepeat() { + return repeat; + } + + public void setRepeat(boolean repeat) { + if (isWorking() || this.repeat == repeat) return; + this.repeat = repeat; + this.mte.markDirty(); + } + + public boolean isReplaceOreWithAir() { + return replaceOreWithAir; + } + + public void setReplaceOreWithAir(boolean replaceOreWithAir) { + if (isWorking() || this.replaceOreWithAir == replaceOreWithAir) return; + this.replaceOreWithAir = replaceOreWithAir; + this.mte.markDirty(); + } + + @NotNull + @Override + public NBTTagCompound writeToNBT(@NotNull NBTTagCompound data) { + if (this.chunkMode) data.setBoolean("chunkMode", true); + if (this.silkTouchMode) data.setBoolean("silkTouch", true); + data.setInteger("currentChunkDiameter", currentChunkDiameter); + if (this.yLimit > 0) data.setInteger("yLimit", this.yLimit); + if (this.repeat) data.setBoolean("repeat", true); + if (this.replaceOreWithAir) data.setBoolean("replaceWithAir", true); + return super.writeToNBT(data); + } + + @Override + public void readFromNBT(@NotNull NBTTagCompound data) { + this.chunkMode = data.getBoolean("chunkMode") || data.getBoolean("isChunkMode"); + this.silkTouchMode = data.getBoolean("silkTouch") || data.getBoolean("isSilkTouchMode"); + this.currentChunkDiameter = data.hasKey("currentChunkDiameter", Constants.NBT.TAG_INT) ? + MathHelper.clamp(data.getInteger("currentChunkDiameter"), 1, getMaximumChunkDiameter()) : + getMaximumChunkDiameter(); + this.yLimit = Math.max(0, data.getInteger("yLimit")); + this.repeat = data.getBoolean("repeat"); + this.replaceOreWithAir = data.getBoolean("replaceWithAir"); + super.readFromNBT(data); + } +} diff --git a/src/main/java/gregtech/common/metatileentities/miner/SimpleMiningArea.java b/src/main/java/gregtech/common/metatileentities/miner/SimpleMiningArea.java new file mode 100644 index 00000000000..a424019ace7 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/miner/SimpleMiningArea.java @@ -0,0 +1,148 @@ +package gregtech.common.metatileentities.miner; + +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.client.utils.MinerRenderHelper; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos.MutableBlockPos; +import net.minecraftforge.client.MinecraftForgeClient; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static gregtech.api.metatileentity.IFastRenderMetaTileEntity.RENDER_PASS_TRANSLUCENT; + +/** + * Simple implementation of {@link MiningArea}. Defines cube-shaped mining area with simple iteration logic. + */ +public class SimpleMiningArea implements MiningArea { + + private static final double PREVIEW_OFFSET = 1 / 16.0; + + public final int startX; + public final int startY; + public final int startZ; + public final int endX; + public final int endY; + public final int endZ; + + /** + * Index for current block position. This implementation of {@link MiningArea} operates by first mapping each block + * in given area to non-negative long indices, then processing it by incrementing internal counter starting from 0. + *
+ * The area iterates through X plane first, then Z plane, before moving down one Y block. + */ + private long currentBlock; + + @Nullable + private AxisAlignedBB boundingBoxCache; + + /** + * @param startX Min X position, inclusive + * @param startY Max Y position, inclusive + * @param startZ Min Z position, inclusive + * @param endX Max X position, inclusive + * @param endY Min Y position, inclusive + * @param endZ Max Z position, inclusive + */ + public SimpleMiningArea(int startX, int startY, int startZ, int endX, int endY, int endZ) { + this.startX = startX; + this.startY = startY; + this.startZ = startZ; + this.endX = endX; + this.endY = endY; + this.endZ = endZ; + } + + @NotNull + public static SimpleMiningArea readPreview(@NotNull PacketBuffer buffer) { + return new SimpleMiningArea(buffer.readInt(), buffer.readInt(), buffer.readInt(), buffer.readInt(), + buffer.readInt(), buffer.readInt()); + } + + @Override + public boolean getCurrentBlockPos(@NotNull MutableBlockPos mpos) { + long index = this.currentBlock; + if (index < 0) return false; + int sizeX = this.endX - this.startX; + int sizeZ = this.endZ - this.startZ; + if (sizeX <= 0 || sizeZ <= 0) return false; + + int x = this.startX + (int) (index % sizeX); + index /= sizeX; + int z = this.startZ + (int) (index % sizeZ); + int y = this.startY - (int) (index / sizeZ); + + if (y < this.endY) return false; + + mpos.setPos(x, y, z); + return true; + } + + @Override + public void nextBlock() { + this.currentBlock++; + } + + @Override + public void reset() { + this.currentBlock = 0; + } + + @Override + @SideOnly(Side.CLIENT) + public void renderMetaTileEntity(@NotNull MetaTileEntity mte, double x, double y, double z, float partialTicks) { + if (MinecraftForgeClient.getRenderPass() == RENDER_PASS_TRANSLUCENT) { + MinerRenderHelper.renderAreaPreview(this.getRenderBoundingBox(), mte.getPos(), x, y, z); + } + } + + @NotNull + @Override + public AxisAlignedBB getRenderBoundingBox() { + if (this.boundingBoxCache == null) { + return this.boundingBoxCache = new AxisAlignedBB( + startX + PREVIEW_OFFSET, + endY == Integer.MIN_VALUE ? Double.NEGATIVE_INFINITY : endY + PREVIEW_OFFSET, + startZ + PREVIEW_OFFSET, + endX - PREVIEW_OFFSET, startY + 1 - PREVIEW_OFFSET, endZ - PREVIEW_OFFSET); + } + return this.boundingBoxCache; + } + + @Override + public void write(@NotNull NBTTagCompound data) { + data.setLong("i", this.currentBlock); + } + + @Override + public void read(@NotNull NBTTagCompound data) { + this.currentBlock = Math.max(0, data.getLong("i")); + } + + @Override + public void writePreviewPacket(@NotNull PacketBuffer buffer) { + buffer.writeInt(startX); + buffer.writeInt(startY); + buffer.writeInt(startZ); + buffer.writeInt(endX); + buffer.writeInt(endY); + buffer.writeInt(endZ); + } + + @Override + public String toString() { + return "SimpleMiningArea{" + + "startX=" + startX + + ", startY=" + startY + + ", startZ=" + startZ + + ", endX=" + endX + + ", endZ=" + endZ + + ", currentBlock=" + currentBlock + + '}'; + } +} diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCleanroom.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCleanroom.java index b9fd8ebf60c..2da88926c92 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCleanroom.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityCleanroom.java @@ -21,6 +21,7 @@ import gregtech.common.blocks.BlockGlassCasing; import gregtech.common.blocks.MetaBlocks; import gregtech.common.metatileentities.MetaTileEntities; +import gregtech.common.metatileentities.miner.MetaTileEntityLargeMiner; import gregtech.common.metatileentities.multi.MetaTileEntityCokeOven; import gregtech.common.metatileentities.multi.MetaTileEntityPrimitiveBlastFurnace; import gregtech.common.metatileentities.multi.MetaTileEntityPrimitiveWaterPump; diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFluidDrill.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFluidDrill.java index a1501dd6f65..9f5e7d7282f 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFluidDrill.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityFluidDrill.java @@ -211,7 +211,7 @@ protected void addWarningText(List textList) { if (isStructureFormed() && minerLogic.isInventoryFull()) { tl.add(TextComponentUtil.translationWithColor( TextFormatting.YELLOW, - "gregtech.machine.miner.invfull")); + "gregtech.machine.fluid_drilling_rig.inventory_full")); } }); } diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityLargeMiner.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityLargeMiner.java deleted file mode 100644 index cc2b78fa6ba..00000000000 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityLargeMiner.java +++ /dev/null @@ -1,561 +0,0 @@ -package gregtech.common.metatileentities.multi.electric; - -import gregtech.api.GTValues; -import gregtech.api.capability.*; -import gregtech.api.capability.impl.EnergyContainerList; -import gregtech.api.capability.impl.FluidTankList; -import gregtech.api.capability.impl.ItemHandlerList; -import gregtech.api.capability.impl.miner.MultiblockMinerLogic; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.ModularUI; -import gregtech.api.gui.Widget; -import gregtech.api.gui.widgets.AdvancedTextWidget; -import gregtech.api.gui.widgets.ImageCycleButtonWidget; -import gregtech.api.items.itemhandlers.GTItemStackHandler; -import gregtech.api.metatileentity.IDataInfoProvider; -import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; -import gregtech.api.metatileentity.multiblock.IMultiblockPart; -import gregtech.api.metatileentity.multiblock.MultiblockAbility; -import gregtech.api.metatileentity.multiblock.MultiblockDisplayText; -import gregtech.api.metatileentity.multiblock.MultiblockWithDisplayBase; -import gregtech.api.pattern.BlockPattern; -import gregtech.api.pattern.FactoryBlockPattern; -import gregtech.api.pattern.PatternMatchContext; -import gregtech.api.pattern.TraceabilityPredicate; -import gregtech.api.recipes.RecipeMaps; -import gregtech.api.unification.material.Material; -import gregtech.api.unification.material.Materials; -import gregtech.api.util.GTUtility; -import gregtech.api.util.TextComponentUtil; -import gregtech.client.renderer.ICubeRenderer; -import gregtech.client.renderer.texture.Textures; -import gregtech.common.blocks.BlockMetalCasing; -import gregtech.common.blocks.MetaBlocks; -import gregtech.core.sound.GTSoundEvents; - -import net.minecraft.block.state.IBlockState; -import net.minecraft.client.resources.I18n; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagInt; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.SoundEvent; -import net.minecraft.util.text.*; -import net.minecraft.world.World; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -import net.minecraftforge.items.IItemHandlerModifiable; - -import codechicken.lib.raytracer.CuboidRayTraceResult; -import codechicken.lib.render.CCRenderState; -import codechicken.lib.render.pipeline.IVertexOperation; -import codechicken.lib.vec.Matrix4; -import com.google.common.collect.Lists; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.List; - -import static gregtech.api.unification.material.Materials.DrillingFluid; - -public class MetaTileEntityLargeMiner extends MultiblockWithDisplayBase - implements IMiner, IControllable, IDataInfoProvider { - - private static final int CHUNK_LENGTH = 16; - - private final Material material; - private final int tier; - - private IEnergyContainer energyContainer; - protected IMultipleTankHandler inputFluidInventory; - protected IItemHandlerModifiable outputInventory; - - private boolean silkTouch = false; - private boolean chunkMode = false; - - private boolean isInventoryFull = false; - - private final int drillingFluidConsumePerTick; - - private final MultiblockMinerLogic minerLogic; - - public MetaTileEntityLargeMiner(ResourceLocation metaTileEntityId, int tier, int speed, int maximumChunkDiameter, - int fortune, Material material, int drillingFluidConsumePerTick) { - super(metaTileEntityId); - this.material = material; - this.tier = tier; - this.drillingFluidConsumePerTick = drillingFluidConsumePerTick; - this.minerLogic = new MultiblockMinerLogic(this, fortune, speed, maximumChunkDiameter * CHUNK_LENGTH / 2, - RecipeMaps.MACERATOR_RECIPES); - } - - @Override - public MetaTileEntity createMetaTileEntity(IGregTechTileEntity tileEntity) { - return new MetaTileEntityLargeMiner(metaTileEntityId, this.tier, this.minerLogic.getSpeed(), - this.minerLogic.getMaximumRadius() * 2 / CHUNK_LENGTH, this.minerLogic.getFortune(), getMaterial(), - getDrillingFluidConsumePerTick()); - } - - @Override - public void invalidateStructure() { - super.invalidateStructure(); - resetTileAbilities(); - if (this.minerLogic.isActive()) - this.minerLogic.setActive(false); - } - - @Override - protected void formStructure(PatternMatchContext context) { - super.formStructure(context); - initializeAbilities(); - } - - private void initializeAbilities() { - this.inputFluidInventory = new FluidTankList(false, getAbilities(MultiblockAbility.IMPORT_FLUIDS)); - this.outputInventory = new ItemHandlerList(getAbilities(MultiblockAbility.EXPORT_ITEMS)); - this.energyContainer = new EnergyContainerList(getAbilities(MultiblockAbility.INPUT_ENERGY)); - this.minerLogic.setVoltageTier(GTUtility.getTierByVoltage(this.energyContainer.getInputVoltage())); - this.minerLogic.setOverclockAmount( - Math.max(1, GTUtility.getTierByVoltage(this.energyContainer.getInputVoltage()) - this.tier)); - this.minerLogic.initPos(getPos(), this.minerLogic.getCurrentRadius()); - } - - private void resetTileAbilities() { - this.inputFluidInventory = new FluidTankList(true); - this.outputInventory = new GTItemStackHandler(this, 0); - this.energyContainer = new EnergyContainerList(Lists.newArrayList()); - } - - public int getEnergyTier() { - if (energyContainer == null) return this.tier; - return Math.min(this.tier + 1, - Math.max(this.tier, GTUtility.getFloorTierByVoltage(energyContainer.getInputVoltage()))); - } - - @Override - public boolean drainEnergy(boolean simulate) { - long energyToDrain = GTValues.VA[getEnergyTier()]; - long resultEnergy = energyContainer.getEnergyStored() - energyToDrain; - if (resultEnergy >= 0L && resultEnergy <= energyContainer.getEnergyCapacity()) { - if (!simulate) - energyContainer.changeEnergy(-energyToDrain); - return true; - } - return false; - } - - @Override - public boolean drainFluid(boolean simulate) { - FluidStack drillingFluid = DrillingFluid - .getFluid(this.drillingFluidConsumePerTick * this.minerLogic.getOverclockAmount()); - FluidStack fluidStack = inputFluidInventory.getTankAt(0).getFluid(); - if (fluidStack != null && fluidStack.isFluidEqual(DrillingFluid.getFluid(1)) && - fluidStack.amount >= drillingFluid.amount) { - if (!simulate) - inputFluidInventory.drain(drillingFluid, true); - return true; - } - return false; - } - - @SideOnly(Side.CLIENT) - @Override - public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { - super.renderMetaTileEntity(renderState, translation, pipeline); - this.getFrontOverlay().renderOrientedState(renderState, translation, pipeline, getFrontFacing(), - this.minerLogic.isWorking(), this.isWorkingEnabled()); - minerLogic.renderPipe(renderState, translation, pipeline); - } - - @Override - protected void updateFormedValid() { - this.minerLogic.performMining(); - if (!getWorld().isRemote && this.minerLogic.wasActiveAndNeedsUpdate()) { - this.minerLogic.setWasActiveAndNeedsUpdate(false); - this.minerLogic.setActive(false); - } - } - - @Override - protected BlockPattern createStructurePattern() { - return FactoryBlockPattern.start() - .aisle("XXX", "#F#", "#F#", "#F#", "###", "###", "###") - .aisle("XXX", "FCF", "FCF", "FCF", "#F#", "#F#", "#F#") - .aisle("XSX", "#F#", "#F#", "#F#", "###", "###", "###") - .where('S', selfPredicate()) - .where('X', states(getCasingState()) - .or(abilities(MultiblockAbility.EXPORT_ITEMS).setMaxGlobalLimited(1).setPreviewCount(1)) - .or(abilities(MultiblockAbility.IMPORT_FLUIDS).setExactLimit(1).setPreviewCount(1)) - .or(abilities(MultiblockAbility.INPUT_ENERGY).setMinGlobalLimited(1).setMaxGlobalLimited(3) - .setPreviewCount(1))) - .where('C', states(getCasingState())) - .where('F', getFramePredicate()) - .where('#', any()) - .build(); - } - - @Override - public String[] getDescription() { - return new String[] { I18n.format("gregtech.machine.miner.multi.description") }; - } - - @Override - public void addInformation(ItemStack stack, @Nullable World player, @NotNull List tooltip, - boolean advanced) { - int workingAreaChunks = this.minerLogic.getCurrentRadius() * 2 / CHUNK_LENGTH; - tooltip.add(I18n.format("gregtech.machine.miner.multi.modes")); - tooltip.add(I18n.format("gregtech.machine.miner.multi.production")); - tooltip.add(I18n.format("gregtech.machine.miner.fluid_usage", getDrillingFluidConsumePerTick(), - DrillingFluid.getLocalizedName())); - tooltip.add(I18n.format("gregtech.universal.tooltip.working_area_chunks_max", workingAreaChunks, - workingAreaChunks)); - tooltip.add(I18n.format("gregtech.universal.tooltip.energy_tier_range", GTValues.VNF[this.tier], - GTValues.VNF[this.tier + 1])); - } - - @Override - public void addToolUsages(ItemStack stack, @Nullable World world, List tooltip, boolean advanced) { - tooltip.add(I18n.format("gregtech.tool_action.screwdriver.toggle_mode_covers")); - tooltip.add(I18n.format("gregtech.tool_action.wrench.set_facing")); - if (getSound() != null) { - tooltip.add(I18n.format("gregtech.tool_action.hammer")); - } - tooltip.add(I18n.format("gregtech.tool_action.crowbar")); - } - - @Override - protected void addDisplayText(List textList) { - super.addDisplayText(textList); - - if (this.isStructureFormed()) { - if (energyContainer != null && energyContainer.getEnergyCapacity() > 0) { - int energyContainer = getEnergyTier(); - long maxVoltage = GTValues.V[energyContainer]; - String voltageName = GTValues.VNF[energyContainer]; - textList.add(new TextComponentTranslation("gregtech.multiblock.max_energy_per_tick", maxVoltage, - voltageName)); - } - - int workingAreaChunks = this.minerLogic.getCurrentRadius() * 2 / CHUNK_LENGTH; - int workingArea = getWorkingArea(minerLogic.getCurrentRadius()); - textList.add(new TextComponentTranslation("gregtech.machine.miner.startx", - this.minerLogic.getX().get() == Integer.MAX_VALUE ? 0 : this.minerLogic.getX().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.starty", - this.minerLogic.getY().get() == Integer.MAX_VALUE ? 0 : this.minerLogic.getY().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.startz", - this.minerLogic.getZ().get() == Integer.MAX_VALUE ? 0 : this.minerLogic.getZ().get())); - if (this.minerLogic.isChunkMode()) { - textList.add(new TextComponentTranslation("gregtech.machine.miner.working_area_chunks", - workingAreaChunks, workingAreaChunks)); - } else { - textList.add( - new TextComponentTranslation("gregtech.machine.miner.working_area", workingArea, workingArea)); - } - if (this.minerLogic.isDone()) - textList.add(new TextComponentTranslation("gregtech.machine.miner.done") - .setStyle(new Style().setColor(TextFormatting.GREEN))); - else if (this.minerLogic.isWorking()) - textList.add(new TextComponentTranslation("gregtech.machine.miner.working") - .setStyle(new Style().setColor(TextFormatting.GOLD))); - else if (!this.isWorkingEnabled()) - textList.add(new TextComponentTranslation("gregtech.multiblock.work_paused")); - } - } - - private void addDisplayText2(List textList) { - if (this.isStructureFormed()) { - ITextComponent mCoords = new TextComponentString(" ") - .appendSibling(new TextComponentTranslation("gregtech.machine.miner.minex", - this.minerLogic.getMineX().get())) - .appendText("\n ") - .appendSibling(new TextComponentTranslation("gregtech.machine.miner.miney", - this.minerLogic.getMineY().get())) - .appendText("\n ") - .appendSibling(new TextComponentTranslation("gregtech.machine.miner.minez", - this.minerLogic.getMineZ().get())); - textList.add(mCoords); - } - } - - @Override - protected void addWarningText(List textList) { - MultiblockDisplayText.builder(textList, isStructureFormed(), false) - .addLowPowerLine(isStructureFormed() && !drainEnergy(true)) - .addCustom(tl -> { - if (isStructureFormed() && isInventoryFull) { - tl.add(TextComponentUtil.translationWithColor( - TextFormatting.YELLOW, - "gregtech.machine.miner.invfull")); - } - }); - } - - @Override - protected void addErrorText(List textList) { - super.addErrorText(textList); - if (isStructureFormed() && !drainFluid(true)) { - textList.add(TextComponentUtil.translationWithColor(TextFormatting.RED, - "gregtech.machine.miner.multi.needsfluid")); - } - } - - public IBlockState getCasingState() { - if (this.material.equals(Materials.Titanium)) - return MetaBlocks.METAL_CASING.getState(BlockMetalCasing.MetalCasingType.TITANIUM_STABLE); - if (this.material.equals(Materials.TungstenSteel)) - return MetaBlocks.METAL_CASING.getState(BlockMetalCasing.MetalCasingType.TUNGSTENSTEEL_ROBUST); - return MetaBlocks.METAL_CASING.getState(BlockMetalCasing.MetalCasingType.STEEL_SOLID); - } - - @NotNull - private TraceabilityPredicate getFramePredicate() { - if (this.material.equals(Materials.Titanium)) - return frames(Materials.Titanium); - if (this.material.equals(Materials.TungstenSteel)) - return frames(Materials.TungstenSteel); - return frames(Materials.Steel); - } - - @SideOnly(Side.CLIENT) - @Override - public ICubeRenderer getBaseTexture(IMultiblockPart sourcePart) { - if (this.material.equals(Materials.Titanium)) - return Textures.STABLE_TITANIUM_CASING; - if (this.material.equals(Materials.TungstenSteel)) - return Textures.ROBUST_TUNGSTENSTEEL_CASING; - return Textures.SOLID_STEEL_CASING; - } - - @Override - public NBTTagCompound writeToNBT(NBTTagCompound data) { - super.writeToNBT(data); - data.setTag("chunkMode", new NBTTagInt(chunkMode ? 1 : 0)); - data.setTag("silkTouch", new NBTTagInt(silkTouch ? 1 : 0)); - return this.minerLogic.writeToNBT(data); - } - - @Override - public void readFromNBT(NBTTagCompound data) { - super.readFromNBT(data); - chunkMode = data.getInteger("chunkMode") != 0; - silkTouch = data.getInteger("silkTouch") != 0; - this.minerLogic.readFromNBT(data); - } - - @Override - public void writeInitialSyncData(PacketBuffer buf) { - super.writeInitialSyncData(buf); - this.minerLogic.writeInitialSyncData(buf); - } - - @Override - public void receiveInitialSyncData(PacketBuffer buf) { - super.receiveInitialSyncData(buf); - this.minerLogic.receiveInitialSyncData(buf); - } - - @Override - public void receiveCustomData(int dataId, PacketBuffer buf) { - super.receiveCustomData(dataId, buf); - this.minerLogic.receiveCustomData(dataId, buf); - } - - @SideOnly(Side.CLIENT) - @NotNull - @Override - protected ICubeRenderer getFrontOverlay() { - if (this.tier == 5) - return Textures.LARGE_MINER_OVERLAY_ADVANCED; - if (this.tier == 6) - return Textures.LARGE_MINER_OVERLAY_ADVANCED_2; - return Textures.LARGE_MINER_OVERLAY_BASIC; - } - - public long getMaxVoltage() { - return GTValues.V[GTUtility.getTierByVoltage(energyContainer.getInputVoltage())]; - } - - @Override - protected ModularUI.Builder createUITemplate(EntityPlayer entityPlayer) { - ModularUI.Builder builder = super.createUITemplate(entityPlayer); - builder.widget(new AdvancedTextWidget(63, 31, this::addDisplayText2, 0xFFFFFF) - .setMaxWidthLimit(68).setClickHandler(this::handleDisplayClick)); - return builder; - } - - // used for UI - private int getCurrentMode() { - // 0 -> not chunk mode, not silk touch mode - if (!minerLogic.isChunkMode() && !minerLogic.isSilkTouchMode()) { - return 0; - } - // 1 -> is chunk mode, not silk touch mode - if (minerLogic.isChunkMode() && !minerLogic.isSilkTouchMode()) { - return 1; - } - // 2 -> not chunk mode, is silk touch mode - if (!minerLogic.isChunkMode() && minerLogic.isSilkTouchMode()) { - return 2; - } - // 3 -> is chunk mode, is silk touch mode - return 3; - } - - // used for UI - private void setCurrentMode(int mode) { - switch (mode) { - case 0 -> { - minerLogic.setChunkMode(false); - minerLogic.setSilkTouchMode(false); - } - case 1 -> { - minerLogic.setChunkMode(true); - minerLogic.setSilkTouchMode(false); - } - case 2 -> { - minerLogic.setChunkMode(false); - minerLogic.setSilkTouchMode(true); - } - default -> { - minerLogic.setChunkMode(true); - minerLogic.setSilkTouchMode(true); - } - } - } - - @Override - protected @NotNull Widget getFlexButton(int x, int y, int width, int height) { - return new ImageCycleButtonWidget(x, y, width, height, GuiTextures.BUTTON_MINER_MODES, 4, this::getCurrentMode, - this::setCurrentMode) - .setTooltipHoverString(mode -> switch (mode) { - case 0 -> "gregtech.multiblock.miner.neither_mode"; - case 1 -> "gregtech.multiblock.miner.chunk_mode"; - case 2 -> "gregtech.multiblock.miner.silk_touch_mode"; - default -> "gregtech.multiblock.miner.both_modes"; - }); - } - - @Override - public boolean onScrewdriverClick(EntityPlayer playerIn, EnumHand hand, EnumFacing facing, - CuboidRayTraceResult hitResult) { - if (getWorld().isRemote || !this.isStructureFormed()) - return true; - - if (!this.isActive()) { - int currentRadius = this.minerLogic.getCurrentRadius(); - if (this.minerLogic.isChunkMode()) { - if (currentRadius - CHUNK_LENGTH <= 0) { - this.minerLogic.setCurrentRadius(this.minerLogic.getMaximumRadius()); - } else { - this.minerLogic.setCurrentRadius(currentRadius - CHUNK_LENGTH); - } - int workingAreaChunks = this.minerLogic.getCurrentRadius() * 2 / CHUNK_LENGTH; - playerIn.sendMessage(new TextComponentTranslation("gregtech.machine.miner.working_area_chunks", - workingAreaChunks, workingAreaChunks)); - } else { - if (currentRadius - CHUNK_LENGTH / 2 <= 0) { - this.minerLogic.setCurrentRadius(this.minerLogic.getMaximumRadius()); - } else { - this.minerLogic.setCurrentRadius(currentRadius - CHUNK_LENGTH / 2); - } - int workingArea = getWorkingArea(minerLogic.getCurrentRadius()); - playerIn.sendMessage(new TextComponentTranslation("gregtech.universal.tooltip.working_area", - workingArea, workingArea)); - } - this.minerLogic.resetArea(); - } else { - playerIn.sendMessage(new TextComponentTranslation("gregtech.machine.miner.errorradius")); - } - return true; - } - - @Override - public boolean hasMaintenanceMechanics() { - return false; - } - - @Override - public boolean isInventoryFull() { - return this.isInventoryFull; - } - - @Override - public void setInventoryFull(boolean isFull) { - this.isInventoryFull = isFull; - } - - public Material getMaterial() { - return material; - } - - public int getTier() { - return this.tier; - } - - public int getDrillingFluidConsumePerTick() { - return this.drillingFluidConsumePerTick; - } - - @Override - public boolean isWorkingEnabled() { - return this.minerLogic.isWorkingEnabled(); - } - - @Override - public void setWorkingEnabled(boolean isActivationAllowed) { - this.minerLogic.setWorkingEnabled(isActivationAllowed); - } - - public int getMaxChunkRadius() { - return this.minerLogic.getMaximumRadius() / CHUNK_LENGTH; - } - - @Override - public T getCapability(Capability capability, EnumFacing side) { - if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { - return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); - } - return super.getCapability(capability, side); - } - - @Override - public IItemHandlerModifiable getExportItems() { - return this.outputInventory; - } - - @Override - public SoundEvent getSound() { - return GTSoundEvents.MINER; - } - - @Override - public boolean isActive() { - return minerLogic.isActive() && isWorkingEnabled(); - } - - @NotNull - @Override - public List getDataInfo() { - int workingArea = getWorkingArea(this.minerLogic.getCurrentRadius()); - return Collections.singletonList( - new TextComponentTranslation("gregtech.machine.miner.working_area", workingArea, workingArea)); - } - - @Override - protected boolean shouldShowVoidingModeButton() { - return false; - } - - @Override - public boolean allowsExtendedFacing() { - return false; - } -} diff --git a/src/main/java/gregtech/common/metatileentities/steam/SteamMiner.java b/src/main/java/gregtech/common/metatileentities/steam/SteamMiner.java deleted file mode 100644 index e3d3c75cb12..00000000000 --- a/src/main/java/gregtech/common/metatileentities/steam/SteamMiner.java +++ /dev/null @@ -1,356 +0,0 @@ -package gregtech.common.metatileentities.steam; - -import gregtech.api.capability.*; -import gregtech.api.capability.impl.CommonFluidFilters; -import gregtech.api.capability.impl.FilteredFluidHandler; -import gregtech.api.capability.impl.FluidTankList; -import gregtech.api.capability.impl.NotifiableItemStackHandler; -import gregtech.api.capability.impl.miner.MinerLogic; -import gregtech.api.capability.impl.miner.SteamMinerLogic; -import gregtech.api.damagesources.DamageSources; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.ModularUI; -import gregtech.api.gui.widgets.AdvancedTextWidget; -import gregtech.api.gui.widgets.SlotWidget; -import gregtech.api.metatileentity.IDataInfoProvider; -import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; -import gregtech.api.util.GTUtility; -import gregtech.client.renderer.texture.Textures; -import gregtech.client.renderer.texture.cube.SimpleSidedCubeRenderer; -import gregtech.common.ConfigHolder; - -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.I18n; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.SoundEvents; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.*; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.Style; -import net.minecraft.util.text.TextComponentTranslation; -import net.minecraft.util.text.TextFormatting; -import net.minecraft.world.World; -import net.minecraft.world.WorldServer; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; -import net.minecraftforge.items.IItemHandlerModifiable; - -import codechicken.lib.render.CCRenderState; -import codechicken.lib.render.pipeline.ColourMultiplier; -import codechicken.lib.render.pipeline.IVertexOperation; -import codechicken.lib.vec.Matrix4; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.tuple.Pair; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.List; - -public class SteamMiner extends MetaTileEntity implements IMiner, IControllable, IVentable, IDataInfoProvider { - - private boolean needsVenting = false; - private boolean ventingStuck = false; - - private final int inventorySize; - private final int energyPerTick; - private boolean isInventoryFull = false; - - private final MinerLogic minerLogic; - - public SteamMiner(ResourceLocation metaTileEntityId, int speed, int maximumRadius, int fortune) { - super(metaTileEntityId); - this.inventorySize = 4; - this.energyPerTick = 16; - this.minerLogic = new SteamMinerLogic(this, fortune, speed, maximumRadius, Textures.BRONZE_PLATED_BRICKS); - initializeInventory(); - } - - @Override - public MetaTileEntity createMetaTileEntity(IGregTechTileEntity tileEntity) { - return new SteamMiner(metaTileEntityId, this.minerLogic.getSpeed(), this.minerLogic.getMaximumRadius(), - this.minerLogic.getFortune()); - } - - @Override - public FluidTankList createImportFluidHandler() { - return new FluidTankList(false, new FilteredFluidHandler(16000).setFilter(CommonFluidFilters.STEAM)); - } - - protected IItemHandlerModifiable createImportItemHandler() { - return new NotifiableItemStackHandler(this, 0, this, false); - } - - @Override - protected IItemHandlerModifiable createExportItemHandler() { - return new NotifiableItemStackHandler(this, inventorySize, this, true); - } - - @Override - @SideOnly(Side.CLIENT) - public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { - ColourMultiplier multiplier = new ColourMultiplier( - GTUtility.convertRGBtoOpaqueRGBA_CL(getPaintingColorForRendering())); - IVertexOperation[] coloredPipeline = ArrayUtils.add(pipeline, multiplier); - Textures.STEAM_CASING_BRONZE.render(renderState, translation, coloredPipeline); - for (EnumFacing renderSide : EnumFacing.HORIZONTALS) { - if (renderSide == getFrontFacing()) { - Textures.PIPE_OUT_OVERLAY.renderSided(renderSide, renderState, translation, pipeline); - } else - Textures.STEAM_MINER_OVERLAY.renderSided(renderSide, renderState, translation, coloredPipeline); - } - Textures.STEAM_VENT_OVERLAY.renderSided(EnumFacing.UP, renderState, translation, pipeline); - Textures.PIPE_IN_OVERLAY.renderSided(EnumFacing.DOWN, renderState, translation, pipeline); - minerLogic.renderPipe(renderState, translation, pipeline); - } - - @Override - protected ModularUI createUI(EntityPlayer entityPlayer) { - int rowSize = (int) Math.sqrt(inventorySize); - - ModularUI.Builder builder = ModularUI.builder(GuiTextures.BACKGROUND_STEAM.get(false), 175, 176); - builder.bindPlayerInventory(entityPlayer.inventory, 94); - - for (int y = 0; y < rowSize; y++) { - for (int x = 0; x < rowSize; x++) { - int index = y * rowSize + x; - builder.widget(new SlotWidget(exportItems, index, 142 - rowSize * 9 + x * 18, 18 + y * 18, true, false) - .setBackgroundTexture(GuiTextures.SLOT_STEAM.get(false))); - } - } - builder.bindPlayerInventory(entityPlayer.inventory, GuiTextures.SLOT_STEAM.get(false), 10); - - builder.image(7, 16, 105, 75, GuiTextures.DISPLAY_STEAM.get(false)) - .label(6, 6, getMetaFullName()); - builder.widget(new AdvancedTextWidget(10, 19, this::addDisplayText, 0xFFFFFF) - .setMaxWidthLimit(84)); - builder.widget(new AdvancedTextWidget(70, 19, this::addDisplayText2, 0xFFFFFF) - .setMaxWidthLimit(84)); - - return builder.build(getHolder(), entityPlayer); - } - - void addDisplayText(List textList) { - int workingArea = getWorkingArea(minerLogic.getCurrentRadius()); - textList.add(new TextComponentTranslation("gregtech.machine.miner.startx", this.minerLogic.getX().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.starty", this.minerLogic.getY().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.startz", this.minerLogic.getZ().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.working_area", workingArea, workingArea)); - if (this.minerLogic.isDone()) - textList.add(new TextComponentTranslation("gregtech.machine.miner.done") - .setStyle(new Style().setColor(TextFormatting.GREEN))); - else if (this.minerLogic.isWorking()) - textList.add(new TextComponentTranslation("gregtech.machine.miner.working") - .setStyle(new Style().setColor(TextFormatting.GOLD))); - else if (!this.isWorkingEnabled()) - textList.add(new TextComponentTranslation("gregtech.multiblock.work_paused")); - if (this.isInventoryFull) - textList.add(new TextComponentTranslation("gregtech.machine.miner.invfull") - .setStyle(new Style().setColor(TextFormatting.RED))); - if (ventingStuck) - textList.add(new TextComponentTranslation("gregtech.machine.steam_miner.vent") - .setStyle(new Style().setColor(TextFormatting.RED))); - else if (!drainEnergy(true)) - textList.add(new TextComponentTranslation("gregtech.machine.steam_miner.steam") - .setStyle(new Style().setColor(TextFormatting.RED))); - } - - void addDisplayText2(List textList) { - textList.add(new TextComponentTranslation("gregtech.machine.miner.minex", this.minerLogic.getMineX().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.miney", this.minerLogic.getMineY().get())); - textList.add(new TextComponentTranslation("gregtech.machine.miner.minez", this.minerLogic.getMineZ().get())); - } - - @Override - public void addInformation(ItemStack stack, @Nullable World player, List tooltip, boolean advanced) { - tooltip.add(I18n.format("gregtech.universal.tooltip.uses_per_tick_steam", energyPerTick) + TextFormatting.GRAY + - ", " + I18n.format("gregtech.machine.miner.per_block", this.minerLogic.getSpeed() / 20)); - int maxArea = getWorkingArea(minerLogic.getMaximumRadius()); - tooltip.add(I18n.format("gregtech.universal.tooltip.working_area", maxArea, maxArea)); - } - - @Override - public void addToolUsages(ItemStack stack, @Nullable World world, List tooltip, boolean advanced) { - tooltip.add(I18n.format("gregtech.tool_action.screwdriver.access_covers")); - tooltip.add(I18n.format("gregtech.tool_action.wrench.set_facing")); - tooltip.add(I18n.format("gregtech.tool_action.soft_mallet.reset")); - super.addToolUsages(stack, world, tooltip, advanced); - } - - public boolean drainEnergy(boolean simulate) { - int resultSteam = importFluids.getTankAt(0).getFluidAmount() - energyPerTick; - if (!ventingStuck && resultSteam >= 0L && resultSteam <= importFluids.getTankAt(0).getCapacity()) { - if (!simulate) - importFluids.getTankAt(0).drain(energyPerTick, true); - return true; - } - return false; - } - - @Override - public void update() { - super.update(); - this.minerLogic.performMining(); - if (!getWorld().isRemote) { - if (getOffsetTimer() % 5 == 0) - pushItemsIntoNearbyHandlers(getFrontFacing()); - - if (this.minerLogic.wasActiveAndNeedsUpdate()) { - this.minerLogic.setWasActiveAndNeedsUpdate(false); - this.minerLogic.setActive(false); - } - } - } - - @Override - public NBTTagCompound writeToNBT(NBTTagCompound data) { - super.writeToNBT(data); - data.setBoolean("needsVenting", this.needsVenting); - data.setBoolean("ventingStuck", this.ventingStuck); - return this.minerLogic.writeToNBT(data); - } - - @Override - public void readFromNBT(NBTTagCompound data) { - super.readFromNBT(data); - this.needsVenting = data.getBoolean("needsVenting"); - this.ventingStuck = data.getBoolean("ventingStuck"); - this.minerLogic.readFromNBT(data); - } - - @Override - public void writeInitialSyncData(PacketBuffer buf) { - super.writeInitialSyncData(buf); - buf.writeBoolean(this.needsVenting); - buf.writeBoolean(this.ventingStuck); - this.minerLogic.writeInitialSyncData(buf); - } - - @Override - public void receiveInitialSyncData(PacketBuffer buf) { - super.receiveInitialSyncData(buf); - this.needsVenting = buf.readBoolean(); - this.ventingStuck = buf.readBoolean(); - this.minerLogic.receiveInitialSyncData(buf); - } - - @Override - public void receiveCustomData(int dataId, PacketBuffer buf) { - super.receiveCustomData(dataId, buf); - if (dataId == GregtechDataCodes.NEEDS_VENTING) { - this.needsVenting = buf.readBoolean(); - } else if (dataId == GregtechDataCodes.VENTING_STUCK) { - this.ventingStuck = buf.readBoolean(); - } - this.minerLogic.receiveCustomData(dataId, buf); - } - - @SideOnly(Side.CLIENT) - public Pair getParticleTexture() { - return Pair.of(Textures.STEAM_CASING_BRONZE.getSpriteOnSide(SimpleSidedCubeRenderer.RenderSide.TOP), - getPaintingColorForRendering()); - } - - public void setVentingStuck(boolean ventingStuck) { - this.ventingStuck = ventingStuck; - if (!this.getWorld().isRemote) { - this.markDirty(); - this.writeCustomData(GregtechDataCodes.VENTING_STUCK, (buf) -> buf.writeBoolean(ventingStuck)); - } - } - - @Override - public void setNeedsVenting(boolean needsVenting) { - this.needsVenting = needsVenting; - if (!needsVenting && this.ventingStuck) - this.setVentingStuck(false); - - if (!this.getWorld().isRemote) { - this.markDirty(); - this.writeCustomData(GregtechDataCodes.NEEDS_VENTING, (buf) -> buf.writeBoolean(needsVenting)); - } - } - - @Override - public T getCapability(Capability capability, EnumFacing side) { - if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { - return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); - } - return super.getCapability(capability, side); - } - - @Override - public boolean isInventoryFull() { - return isInventoryFull; - } - - @Override - public void setInventoryFull(boolean isFull) { - this.isInventoryFull = isFull; - } - - @Override - public boolean isWorkingEnabled() { - return this.minerLogic.isWorkingEnabled(); - } - - @Override - public void setWorkingEnabled(boolean isActivationAllowed) { - this.minerLogic.setWorkingEnabled(isActivationAllowed); - } - - @Override - public boolean isNeedsVenting() { - return this.needsVenting; - } - - @Override - public void tryDoVenting() { - BlockPos machinePos = this.getPos(); - EnumFacing ventingSide = EnumFacing.UP; - BlockPos ventingBlockPos = machinePos.offset(ventingSide); - IBlockState blockOnPos = this.getWorld().getBlockState(ventingBlockPos); - if (blockOnPos.getCollisionBoundingBox(this.getWorld(), ventingBlockPos) == Block.NULL_AABB) { - this.getWorld() - .getEntitiesWithinAABB(EntityLivingBase.class, new AxisAlignedBB(ventingBlockPos), - EntitySelectors.CAN_AI_TARGET) - .forEach((entity) -> entity.attackEntityFrom(DamageSources.getHeatDamage(), 6.0F)); - WorldServer world = (WorldServer) this.getWorld(); - double posX = (double) machinePos.getX() + 0.5D + (double) ventingSide.getXOffset() * 0.6D; - double posY = (double) machinePos.getY() + 0.5D + (double) ventingSide.getYOffset() * 0.6D; - double posZ = (double) machinePos.getZ() + 0.5D + (double) ventingSide.getZOffset() * 0.6D; - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, posX, posY, posZ, 7 + world.rand.nextInt(3), - (double) ventingSide.getXOffset() / 2.0D, (double) ventingSide.getYOffset() / 2.0D, - (double) ventingSide.getZOffset() / 2.0D, 0.1D); - if (ConfigHolder.machines.machineSounds && !this.isMuffled()) { - world.playSound(null, posX, posY, posZ, SoundEvents.BLOCK_LAVA_EXTINGUISH, SoundCategory.BLOCKS, 1.0F, - 1.0F); - } - this.setNeedsVenting(false); - } else if (!this.ventingStuck) { - this.setVentingStuck(true); - } - } - - @Override - public boolean isVentingStuck() { - return ventingStuck; - } - - @NotNull - @Override - public List getDataInfo() { - int workingArea = getWorkingArea(this.minerLogic.getCurrentRadius()); - return Collections.singletonList( - new TextComponentTranslation("gregtech.machine.miner.working_area", workingArea, workingArea)); - } -} diff --git a/src/main/java/gregtech/common/terminal/app/prospector/widget/WidgetProspectingMap.java b/src/main/java/gregtech/common/terminal/app/prospector/widget/WidgetProspectingMap.java index 106b142c66f..698be63082d 100644 --- a/src/main/java/gregtech/common/terminal/app/prospector/widget/WidgetProspectingMap.java +++ b/src/main/java/gregtech/common/terminal/app/prospector/widget/WidgetProspectingMap.java @@ -23,6 +23,7 @@ import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; import net.minecraft.util.math.BlockPos; @@ -125,7 +126,7 @@ public void detectAndSendChanges() { playerChunkZ, (int) player.posX, (int) player.posZ, this.mode); switch (mode) { - case ORE: + case ORE -> { BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { @@ -133,42 +134,43 @@ public void detectAndSendChanges() { for (int y = 1; y < ySize; y++) { pos.setPos(x, y, z); IBlockState state = chunk.getBlockState(pos); - ItemStack itemBlock = GTUtility.toItem(state); - if (GTUtility.isOre(itemBlock)) { - boolean added = false; - String oreDictString = OreDictUnifier.getOreDictionaryNames(itemBlock).stream() - .findFirst() - .orElse(""); - OrePrefix prefix = OreDictUnifier.getPrefix(itemBlock); - if (prefix != null) { - for (StoneType type : StoneType.STONE_TYPE_REGISTRY) { - if (type.processingPrefix == prefix && type.shouldBeDroppedAsItem) { - packet.addBlock(x, y, z, oreDictString); + if (!BlockUtility.isOre(state)) continue; + + Item item = Item.getItemFromBlock(state.getBlock()); + int meta = state.getBlock().getMetaFromState(state); + boolean added = false; + String oreDictString = OreDictUnifier.getOreDictionaryNames(item, meta).stream() + .findFirst() + .orElse(""); + OrePrefix prefix = OreDictUnifier.getPrefix(item, meta); + if (prefix != null) { + for (StoneType type : StoneType.STONE_TYPE_REGISTRY) { + if (type.processingPrefix == prefix && type.shouldBeDroppedAsItem) { + packet.addBlock(x, y, z, oreDictString); + added = true; + break; + } else if (type.processingPrefix == prefix) { + MaterialStack materialStack = OreDictUnifier.getMaterial(item, meta); + if (materialStack != null) { + String oreDict = "ore" + + oreDictString.replaceFirst(prefix.name(), ""); + packet.addBlock(x, y, z, oreDict); added = true; break; - } else if (type.processingPrefix == prefix) { - MaterialStack materialStack = OreDictUnifier.getMaterial(itemBlock); - if (materialStack != null) { - String oreDict = "ore" + - oreDictString.replaceFirst(prefix.name(), ""); - packet.addBlock(x, y, z, oreDict); - added = true; - break; - } } } } - // Probably other mod's ores - if (!added) { - // Fallback - packet.addBlock(x, y, z, oreDictString); - } + } + // Probably other mod's ores + if (!added) { + // Fallback + packet.addBlock(x, y, z, oreDictString); } } } } - break; - case FLUID: + } + case FLUID -> { BedrockFluidVeinHandler.FluidVeinWorldEntry fStack = BedrockFluidVeinHandler .getFluidVeinWorldEntry(world, chunk.x, chunk.z); if (fStack != null && fStack.getDefinition() != null) { @@ -183,9 +185,7 @@ public void detectAndSendChanges() { packet.addBlock(0, 1, 0, fluid.getName()); } } - break; - default: - break; + } } writeUpdateInfo(2, packet::writePacketData); chunkIndex++; diff --git a/src/main/java/gregtech/loaders/recipe/MetaTileEntityLoader.java b/src/main/java/gregtech/loaders/recipe/MetaTileEntityLoader.java index 9cb0e321a0e..4ab3a49c389 100644 --- a/src/main/java/gregtech/loaders/recipe/MetaTileEntityLoader.java +++ b/src/main/java/gregtech/loaders/recipe/MetaTileEntityLoader.java @@ -520,11 +520,6 @@ public static void init() { new UnificationEntry(OrePrefix.plate, Materials.WroughtIron), 'S', new UnificationEntry(OrePrefix.plate, Materials.Steel), 'P', new UnificationEntry(OrePrefix.pipeSmallFluid, Materials.TinAlloy)); - ModHandler.addShapedRecipe(true, "steam_miner", MetaTileEntities.STEAM_MINER.getStackForm(), "DSD", "SMS", - "GSG", 'M', MetaBlocks.STEAM_CASING.getItemVariant(BRONZE_HULL), 'S', - new UnificationEntry(OrePrefix.pipeNormalFluid, Materials.Bronze), 'D', - new UnificationEntry(OrePrefix.gem, Materials.Diamond), 'G', - new UnificationEntry(OrePrefix.gearSmall, Materials.Bronze)); // MULTI BLOCK CONTROLLERS ModHandler.addShapedRecipe(true, "bronze_primitive_blast_furnace", @@ -891,8 +886,8 @@ public static void init() { 'W', CABLE, 'S', OreDictNames.chestWood, 'G', GRINDER); registerMachineRecipe(MetaTileEntities.WORLD_ACCELERATOR, "IGI", "FHF", "IGI", 'H', HULL, 'F', EMITTER, 'G', SENSOR, 'I', FIELD_GENERATOR); - registerMachineRecipe(MetaTileEntities.MINER, "MMM", "WHW", "CSC", 'M', MOTOR, 'W', CABLE, 'H', HULL, 'C', - CIRCUIT, 'S', SENSOR); + registerMachineRecipe(MetaTileEntities.MINER, "MSM", "WHW", "CGC", 'M', MOTOR, 'W', CABLE, 'H', HULL, 'C', + CIRCUIT, 'S', SENSOR, 'G', MetaItems.COMPONENT_GRINDER_DIAMOND); registerMachineRecipe(MetaTileEntities.MUFFLER_HATCH, "HM", "PR", 'H', HULL, 'M', MOTOR, 'P', PIPE_NORMAL, 'R', ROTOR); diff --git a/src/main/java/gregtech/loaders/recipe/MetaTileEntityMachineRecipeLoader.java b/src/main/java/gregtech/loaders/recipe/MetaTileEntityMachineRecipeLoader.java index cc01014c03a..02b7dfbeae4 100644 --- a/src/main/java/gregtech/loaders/recipe/MetaTileEntityMachineRecipeLoader.java +++ b/src/main/java/gregtech/loaders/recipe/MetaTileEntityMachineRecipeLoader.java @@ -889,6 +889,7 @@ public static void init() { .input(ELECTRIC_PUMP_EV, 4) .input(CONVEYOR_MODULE_EV, 4) .input(gear, Tungsten, 4) + .input(COMPONENT_GRINDER_TUNGSTEN) .circuitMeta(2) .output(BASIC_LARGE_MINER) .duration(400).EUt(VA[EV]).buildAndRegister(); @@ -901,6 +902,7 @@ public static void init() { .input(ELECTRIC_PUMP_IV, 4) .input(CONVEYOR_MODULE_IV, 4) .input(gear, Iridium, 4) + .input(COMPONENT_GRINDER_TUNGSTEN) .circuitMeta(2) .output(LARGE_MINER) .duration(400).EUt(VA[IV]).buildAndRegister(); @@ -913,6 +915,7 @@ public static void init() { .input(ELECTRIC_PUMP_LuV, 4) .input(CONVEYOR_MODULE_LuV, 4) .input(gear, Ruridit, 4) + .input(COMPONENT_GRINDER_TUNGSTEN) .circuitMeta(2) .output(ADVANCED_LARGE_MINER) .duration(400).EUt(VA[LuV]).buildAndRegister(); diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index f4525a2dc5c..00eb3d66c49 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -2923,8 +2923,6 @@ gregtech.machine.steam_rock_breaker_bronze.name=Steam Rock Breaker gregtech.machine.steam_rock_breaker_bronze.tooltip=Requires §bWater§7 and §cLava§7 horizontally adjacent gregtech.machine.steam_rock_breaker_steel.name=High Pressure Steam Rock Breaker gregtech.machine.steam_rock_breaker_steel.tooltip=Requires §bWater§7 and §cLava§7 horizontally adjacent -gregtech.machine.steam_miner.name=Steam Miner -gregtech.machine.steam_miner.tooltip=Mines ores below the Miner! # Generators gregtech.machine.combustion_generator.tooltip=Requires flammable Liquids @@ -4737,7 +4735,7 @@ gregtech.machine.fusion_reactor.overclocking=Overclocks double energy and halve gregtech.machine.miner.lv.name=Basic Miner gregtech.machine.miner.mv.name=Advanced Miner gregtech.machine.miner.hv.name=Advanced Miner II -gregtech.machine.miner.tooltip=Mines ores below the Miner! Starts as §f%sx%s §7area +gregtech.machine.miner.tooltip=Mines ores below the Miner! gregtech.machine.miner.per_block=§7takes §f%,ds §7per Block gregtech.machine.large_miner.ev.name=Basic Ore Drilling Plant @@ -4749,16 +4747,38 @@ gregtech.machine.miner.fluid_usage=Uses §f%,d L/t §7of §f%s§7, doubled per o gregtech.machine.miner.multi.description=A multiblock mining machine that covers a large area and produces huge quantity of ore. gregtech.machine.miner.multi.needsfluid=No Drilling Fluid! -gregtech.machine.miner.startx=sX: %d -gregtech.machine.miner.starty=sY: %d -gregtech.machine.miner.startz=sZ: %d -gregtech.machine.miner.minex=mX: %d -gregtech.machine.miner.miney=mY: %d -gregtech.machine.miner.minez=mZ: %d -gregtech.machine.miner.radius=Radius: %d gregtech.machine.miner.working_area=Working Area: %dx%d blocks gregtech.machine.miner.working_area_chunks=Working Area: %dx%d chunks -gregtech.machine.miner.chunkradius=Chunk Radius: %d + +gregtech.machine.miner.button.tooltip.info=Information +gregtech.machine.miner.button.tooltip.config=Configuration + +gregtech.machine.miner.display.working_area=Working Area: %sx%s blocks +gregtech.machine.miner.display.working_area.chunks=Working Area: %sx%s chunks +gregtech.machine.miner.display.working_area.preview=[§bPreview§r] +gregtech.machine.miner.display.working_area.hide_preview=[§bHide Preview§r] +gregtech.machine.miner.display.y_limit=Y Limit: %s +gregtech.machine.miner.display.y_limit.no_value=No limit +gregtech.machine.miner.display.y_limit.value_hover_tooltip=Miner will operate in §6%s§r Y layer(s) before halting. +gregtech.machine.miner.display.y_limit.value_hover_tooltip.no_value=Miner will operate until hitting the bedrock layer. +gregtech.machine.miner.display.repeat=Repeat after finished: %s +gregtech.machine.miner.display.chunk_mode=Chunk Mode: %s +gregtech.machine.miner.display.silk_touch=Silk Touch: %s +gregtech.machine.miner.display.replace_ore=Replace ore with: %s +gregtech.machine.miner.display.decr=[§b-§r] +gregtech.machine.miner.display.decr.disabled=[§8-§r] +gregtech.machine.miner.display.incr=[§b+§r] +gregtech.machine.miner.display.incr.disabled=[§8+§r] +gregtech.machine.miner.display.enabled=§aOn§r +gregtech.machine.miner.display.disabled=§cOff§r +gregtech.machine.miner.display.toggle.enabled=[§aOn§r] +gregtech.machine.miner.display.toggle.disabled=[§cOff§r] +gregtech.machine.miner.display.stats.total_mined=Mined %s ores in total +gregtech.machine.miner.display.stats.last_mined=Last Block Mined: [%s %s %s] + +gregtech.machine.miner.display.done=Done! +gregtech.machine.miner.display.working=Mining [%s %s %s] +gregtech.machine.miner.display.inventory_full=Inventory Full! gregtech.machine.fluid_drilling_rig.mv.name=Basic Fluid Drilling Rig gregtech.machine.fluid_drilling_rig.hv.name=Advanced Fluid Drilling Rig @@ -4767,6 +4787,7 @@ gregtech.machine.fluid_drilling_rig.description=Drills fluids from veins under b gregtech.machine.fluid_drilling_rig.production=§eProduction Multiplier: §f%dx, %fx overclocked gregtech.machine.fluid_drilling_rig.depletion=§bDepletion Rate: §f%s%% gregtech.machine.fluid_drilling_rig.shows_depletion=Shows fluid vein depletion info +gregtech.machine.fluid_drilling_rig.inventory_full=Inventory Full! gregtech.machine.cleanroom.name=Cleanroom gregtech.machine.cleanroom.tooltip.1=Place machines inside to run cleanroom recipes. @@ -5610,19 +5631,6 @@ gregtech.multiblock.large_boiler.explosion_tooltip=Will explode if provided Fuel gregtech.multiblock.large_boiler.water_bar_hover=Water: %s gregtech.multiblock.large_boiler.no_water=No Water! -gregtech.machine.miner.done=Done! -gregtech.machine.miner.working=Working... -gregtech.machine.miner.invfull=Inventory Full! -gregtech.machine.miner.needspower=Needs Power! -gregtech.machine.steam_miner.vent=Venting Blocked! -gregtech.machine.steam_miner.steam=Needs Steam! -gregtech.machine.miner.errorradius=§cCannot change radius while working! - -gregtech.multiblock.miner.neither_mode=Chunk Mode: §cDisabled§r/nSilk Touch Mode: §cDisabled§r/n§7Switching requires an idle machine. -gregtech.multiblock.miner.chunk_mode=Chunk Mode: §aEnabled§r/nSilk Touch Mode: §cDisabled§r/n§7Switching requires an idle machine. -gregtech.multiblock.miner.silk_touch_mode=Chunk Mode: §cDisabled§r/nSilk Touch Mode: §aEnabled§r/n§7Switching requires an idle machine. -gregtech.multiblock.miner.both_modes=Chunk Mode: §aEnabled§r/nSilk Touch Mode: §aEnabled§r/n§7Switching requires an idle machine. - gregtech.multiblock.fluid_rig.drilled_fluid=Fluid: %s gregtech.multiblock.fluid_rig.no_fluid_in_area=None in Area. gregtech.multiblock.fluid_rig.fluid_amount=Pumping Rate: %s diff --git a/src/main/resources/assets/gregtech/models/block/mining_pipe/base.json b/src/main/resources/assets/gregtech/models/block/mining_pipe/base.json new file mode 100644 index 00000000000..51906fa69f2 --- /dev/null +++ b/src/main/resources/assets/gregtech/models/block/mining_pipe/base.json @@ -0,0 +1,18 @@ +{ + "parent": "block/block", + "textures": { + "particle": "#texture" + }, + "elements": [ + { + "from": [ 4, 0, 4], + "to": [12, 16, 12], + "faces": { + "north": { "texture": "#texture", "tintindex": 0 }, + "east": { "texture": "#texture", "tintindex": 0 }, + "south": { "texture": "#texture", "tintindex": 0 }, + "west": { "texture": "#texture", "tintindex": 0 } + } + } + ] +} diff --git a/src/main/resources/assets/gregtech/models/block/mining_pipe/base_bottom.json b/src/main/resources/assets/gregtech/models/block/mining_pipe/base_bottom.json new file mode 100644 index 00000000000..39e4cd64cb7 --- /dev/null +++ b/src/main/resources/assets/gregtech/models/block/mining_pipe/base_bottom.json @@ -0,0 +1,19 @@ +{ + "parent": "block/block", + "textures": { + "particle": "#texture" + }, + "elements": [ + { + "from": [ 4, 0, 4], + "to": [12, 16, 12], + "faces": { + "down": { "texture": "#texture", "tintindex": 0, "cullface": "down" }, + "north": { "texture": "#texture", "tintindex": 0 }, + "east": { "texture": "#texture", "tintindex": 0 }, + "south": { "texture": "#texture", "tintindex": 0 }, + "west": { "texture": "#texture", "tintindex": 0 } + } + } + ] +} diff --git a/src/main/resources/assets/gregtech/models/block/mining_pipe/steel.json b/src/main/resources/assets/gregtech/models/block/mining_pipe/steel.json new file mode 100644 index 00000000000..f4dfd6084ad --- /dev/null +++ b/src/main/resources/assets/gregtech/models/block/mining_pipe/steel.json @@ -0,0 +1,6 @@ +{ + "parent": "gregtech:block/mining_pipe/base", + "textures": { + "texture": "gregtech:blocks/casings/solid/machine_casing_solid_steel" + } +} diff --git a/src/main/resources/assets/gregtech/models/block/mining_pipe/steel_bottom.json b/src/main/resources/assets/gregtech/models/block/mining_pipe/steel_bottom.json new file mode 100644 index 00000000000..bcaa69e6a56 --- /dev/null +++ b/src/main/resources/assets/gregtech/models/block/mining_pipe/steel_bottom.json @@ -0,0 +1,6 @@ +{ + "parent": "gregtech:block/mining_pipe/base_bottom", + "textures": { + "texture": "gregtech:blocks/casings/solid/machine_casing_solid_steel" + } +} diff --git a/src/main/resources/assets/gregtech/models/block/mining_pipe/titanium.json b/src/main/resources/assets/gregtech/models/block/mining_pipe/titanium.json new file mode 100644 index 00000000000..da90a41d088 --- /dev/null +++ b/src/main/resources/assets/gregtech/models/block/mining_pipe/titanium.json @@ -0,0 +1,6 @@ +{ + "parent": "gregtech:block/mining_pipe/base", + "textures": { + "texture": "gregtech:blocks/casings/solid/machine_casing_stable_titanium" + } +} diff --git a/src/main/resources/assets/gregtech/models/block/mining_pipe/titanium_bottom.json b/src/main/resources/assets/gregtech/models/block/mining_pipe/titanium_bottom.json new file mode 100644 index 00000000000..f06256d6ec5 --- /dev/null +++ b/src/main/resources/assets/gregtech/models/block/mining_pipe/titanium_bottom.json @@ -0,0 +1,6 @@ +{ + "parent": "gregtech:block/mining_pipe/base_bottom", + "textures": { + "texture": "gregtech:blocks/casings/solid/machine_casing_stable_titanium" + } +} diff --git a/src/main/resources/assets/gregtech/models/block/mining_pipe/tungsten_steel.json b/src/main/resources/assets/gregtech/models/block/mining_pipe/tungsten_steel.json new file mode 100644 index 00000000000..56c4704db8a --- /dev/null +++ b/src/main/resources/assets/gregtech/models/block/mining_pipe/tungsten_steel.json @@ -0,0 +1,6 @@ +{ + "parent": "gregtech:block/mining_pipe/base", + "textures": { + "texture": "gregtech:blocks/casings/solid/machine_casing_robust_tungstensteel" + } +} diff --git a/src/main/resources/assets/gregtech/models/block/mining_pipe/tungsten_steel_bottom.json b/src/main/resources/assets/gregtech/models/block/mining_pipe/tungsten_steel_bottom.json new file mode 100644 index 00000000000..235af1a2697 --- /dev/null +++ b/src/main/resources/assets/gregtech/models/block/mining_pipe/tungsten_steel_bottom.json @@ -0,0 +1,6 @@ +{ + "parent": "gregtech:block/mining_pipe/base_bottom", + "textures": { + "texture": "gregtech:blocks/casings/solid/machine_casing_robust_tungstensteel" + } +} diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back.png new file mode 100644 index 00000000000..78888e5ad81 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active.png new file mode 100644 index 00000000000..56295646d20 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active.png.mcmeta b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active.png.mcmeta new file mode 100644 index 00000000000..60af678259b --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation":{ + "frametime":4 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active_emissive.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active_emissive.png new file mode 100644 index 00000000000..8abaae07db1 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active_emissive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active_emissive.png.mcmeta b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active_emissive.png.mcmeta new file mode 100644 index 00000000000..60af678259b --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_back_active_emissive.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation":{ + "frametime":4 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_bottom.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_bottom.png new file mode 100644 index 00000000000..efa4dfedd83 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_bottom.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_bottom_active.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_bottom_active.png new file mode 100644 index 00000000000..efa4dfedd83 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_bottom_active.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_front.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_front.png new file mode 100644 index 00000000000..f90afa31e03 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_front.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_front_active.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_front_active.png new file mode 100644 index 00000000000..f90afa31e03 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_front_active.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side.png new file mode 100644 index 00000000000..78888e5ad81 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active.png new file mode 100644 index 00000000000..56295646d20 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active.png.mcmeta b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active.png.mcmeta new file mode 100644 index 00000000000..60af678259b --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation":{ + "frametime":4 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active_emissive.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active_emissive.png new file mode 100644 index 00000000000..8abaae07db1 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active_emissive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active_emissive.png.mcmeta b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active_emissive.png.mcmeta new file mode 100644 index 00000000000..60af678259b --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_side_active_emissive.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation":{ + "frametime":4 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top.png new file mode 100644 index 00000000000..2d111eebad6 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_active.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_active.png new file mode 100644 index 00000000000..dde5384b499 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_active.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_active_emissive.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_active_emissive.png new file mode 100644 index 00000000000..c1e09484f30 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_active_emissive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_active_emissive.png.mcmeta b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_active_emissive.png.mcmeta new file mode 100644 index 00000000000..60af678259b --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_active_emissive.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation":{ + "frametime":4 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_emissive.png b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_emissive.png new file mode 100644 index 00000000000..dde5384b499 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/machines/miner/overlay_top_emissive.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/overlay/machine/overlay_chunk_miner.png b/src/main/resources/assets/gregtech/textures/blocks/overlay/machine/overlay_chunk_miner.png deleted file mode 100644 index 6d13954c4b5..00000000000 Binary files a/src/main/resources/assets/gregtech/textures/blocks/overlay/machine/overlay_chunk_miner.png and /dev/null differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/overlay/machine/overlay_steam_miner.png b/src/main/resources/assets/gregtech/textures/blocks/overlay/machine/overlay_steam_miner.png deleted file mode 100644 index 92452781ee4..00000000000 Binary files a/src/main/resources/assets/gregtech/textures/blocks/overlay/machine/overlay_steam_miner.png and /dev/null differ diff --git a/src/main/resources/assets/gregtech/textures/fx/miner_area_preview.png b/src/main/resources/assets/gregtech/textures/fx/miner_area_preview.png new file mode 100644 index 00000000000..516a443461c Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/fx/miner_area_preview.png differ diff --git a/src/main/resources/assets/gregtech/textures/gui/progress_bar/progress_bar_miner_drilling_fluid.png b/src/main/resources/assets/gregtech/textures/gui/progress_bar/progress_bar_miner_drilling_fluid.png new file mode 100644 index 00000000000..d30ea84ede2 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/gui/progress_bar/progress_bar_miner_drilling_fluid.png differ diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/button_miner_area_preview.png b/src/main/resources/assets/gregtech/textures/gui/widget/button_miner_area_preview.png new file mode 100644 index 00000000000..f32c0dd6e0a Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/gui/widget/button_miner_area_preview.png differ diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/button_miner_config_mode.png b/src/main/resources/assets/gregtech/textures/gui/widget/button_miner_config_mode.png new file mode 100644 index 00000000000..4e2fc39e0ec Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/gui/widget/button_miner_config_mode.png differ diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/button_miner_modes.png b/src/main/resources/assets/gregtech/textures/gui/widget/button_miner_modes.png deleted file mode 100644 index dbc5ffbbfbf..00000000000 Binary files a/src/main/resources/assets/gregtech/textures/gui/widget/button_miner_modes.png and /dev/null differ