From 6b8ca226da2325452f68a24931b24583e9f2dd98 Mon Sep 17 00:00:00 2001 From: Zorbatron <46525467+Zorbatron@users.noreply.github.com> Date: Fri, 2 May 2025 13:56:29 -0400 Subject: [PATCH 1/9] Allow block breakers to face any direction Don't allow block breakers to break liquid blocks --- .../electric/MetaTileEntityBlockBreaker.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java index 9e5a81f5299..eac5facdbcf 100644 --- a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java +++ b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java @@ -13,6 +13,7 @@ import gregtech.client.utils.RenderUtil; import net.minecraft.block.Block; +import net.minecraft.block.BlockLiquid; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.client.resources.I18n; @@ -44,6 +45,7 @@ import com.cleanroommc.modularui.widgets.ItemSlot; import com.cleanroommc.modularui.widgets.SlotGroupWidget; import com.cleanroommc.modularui.widgets.layout.Grid; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -80,12 +82,14 @@ public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, @Override public void update() { super.update(); - if (!getWorld().isRemote && getOffsetTimer() % 5 == 0) { - pushItemsIntoNearbyHandlers(getOutputFacing()); - } + if (!getWorld().isRemote) { + if (getOffsetTimer() % 5 == 0) { + pushItemsIntoNearbyHandlers(getOutputFacing()); + } + if (breakProgressTicksLeft > 0) { - --this.breakProgressTicksLeft; + --breakProgressTicksLeft; if (breakProgressTicksLeft == 0 && energyContainer.getEnergyStored() >= getEnergyPerBlockBreak()) { BlockPos blockPos = getPos().offset(getFrontFacing()); IBlockState blockState = getWorld().getBlockState(blockPos); @@ -97,9 +101,6 @@ public void update() { List drops = attemptBreakBlockAndObtainDrops(blockPos, blockState, entityPlayer); addToInventoryOrDropItems(drops); } - this.breakProgressTicksLeft = 0; - this.currentBlockHardness = 0.0f; - energyContainer.removeEnergy(getEnergyPerBlockBreak()); } } @@ -109,10 +110,11 @@ public void update() { EntityPlayer entityPlayer = GregFakePlayer.get((WorldServer) getWorld()); float hardness = blockState.getBlockHardness(getWorld(), blockPos); boolean skipBlock = blockState.getMaterial() == Material.AIR || - blockState.getBlock().isAir(blockState, getWorld(), getPos()); + blockState.getBlock().isAir(blockState, getWorld(), getPos()) || + blockState.getBlock() instanceof BlockLiquid; if (hardness >= 0.0f && !skipBlock && getWorld().isBlockModifiable(entityPlayer, blockPos)) { - this.breakProgressTicksLeft = getTicksPerBlockBreak(hardness); - this.currentBlockHardness = hardness; + breakProgressTicksLeft = getTicksPerBlockBreak(hardness); + currentBlockHardness = hardness; } } } @@ -179,19 +181,19 @@ public void readFromNBT(NBTTagCompound data) { } @Override - public void writeInitialSyncData(PacketBuffer buf) { + public void writeInitialSyncData(@NotNull PacketBuffer buf) { super.writeInitialSyncData(buf); buf.writeByte(getOutputFacing().getIndex()); } @Override - public void receiveInitialSyncData(PacketBuffer buf) { + public void receiveInitialSyncData(@NotNull PacketBuffer buf) { super.receiveInitialSyncData(buf); this.outputFacing = EnumFacing.VALUES[buf.readByte()]; } @Override - public void receiveCustomData(int dataId, PacketBuffer buf) { + public void receiveCustomData(int dataId, @NotNull PacketBuffer buf) { super.receiveCustomData(dataId, buf); if (dataId == UPDATE_OUTPUT_FACING) { this.outputFacing = EnumFacing.VALUES[buf.readByte()]; @@ -203,7 +205,7 @@ public void receiveCustomData(int dataId, PacketBuffer buf) { public boolean isValidFrontFacing(EnumFacing facing) { // use direct outputFacing field instead of getter method because otherwise // it will just return SOUTH for null output facing - return super.isValidFrontFacing(facing) && facing != outputFacing; + return facing != outputFacing; } public EnumFacing getOutputFacing() { @@ -290,7 +292,8 @@ public boolean getIsWeatherOrTerrainResistant() { } @Override - public void addInformation(ItemStack stack, @Nullable World player, List tooltip, boolean advanced) { + public void addInformation(ItemStack stack, @Nullable World player, @NotNull List tooltip, + boolean advanced) { super.addInformation(stack, player, tooltip, advanced); tooltip.add(I18n.format("gregtech.machine.block_breaker.tooltip")); tooltip.add(I18n.format("gregtech.universal.tooltip.uses_per_op", getEnergyPerBlockBreak())); From 16e667a82d5fcb5acaae85568d6b339d8ffd885c Mon Sep 17 00:00:00 2001 From: Zorbatron <46525467+Zorbatron@users.noreply.github.com> Date: Fri, 2 May 2025 13:59:31 -0400 Subject: [PATCH 2/9] oops --- .../metatileentities/electric/MetaTileEntityBlockBreaker.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java index eac5facdbcf..42cefd755d1 100644 --- a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java +++ b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java @@ -101,6 +101,9 @@ public void update() { List drops = attemptBreakBlockAndObtainDrops(blockPos, blockState, entityPlayer); addToInventoryOrDropItems(drops); } + + currentBlockHardness = 0.0f; + energyContainer.removeEnergy(getEnergyPerBlockBreak()); } } From 1cb6b62e82422fb2fffdb99a33211ff142588bb8 Mon Sep 17 00:00:00 2001 From: Zorbatron <46525467+Zorbatron@users.noreply.github.com> Date: Tue, 26 Aug 2025 18:23:53 -0400 Subject: [PATCH 3/9] Add support for FTB Utilities --- dependencies.gradle | 2 + .../gregtech/api/util/GregFakePlayer.java | 43 +++++++++++----- src/main/java/gregtech/api/util/Mods.java | 5 ++ .../electric/MetaTileEntityBlockBreaker.java | 50 ++++++++++++------- 4 files changed, 71 insertions(+), 29 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 74ea3cf0e06..6a45ca2165f 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -52,6 +52,8 @@ dependencies { compileOnly("curse.maven:journeymap-32274:5172461") // Journeymap 5.7.1p3 compileOnly("curse.maven:voxelmap-225179:3029445") // VoxelMap 1.9.28 compileOnly("curse.maven:xaeros-263420:5394758") // Xaero's Minimap 24.2.0 + devOnlyNonPublishable rfg.deobf("curse.maven:ftb-library-legacy-forge-237167:2985811") // FTB Library 5.4.7.2 + devOnlyNonPublishable rfg.deobf("curse.maven:ftb-utilities-forge-237102:3157548") // FTB Utilities 5.4.1.131 compileOnly rfg.deobf("curse.maven:opencomputers-223008:5274236") // OpenComputers 1.8.5+179e1c3 compileOnly rfg.deobf("curse.maven:hwyla-253449:2568751") // HWYLA 1.8.26-B41 compileOnly rfg.deobf("curse.maven:baubles-227083:2518667") // Baubles 1.5.2 diff --git a/src/main/java/gregtech/api/util/GregFakePlayer.java b/src/main/java/gregtech/api/util/GregFakePlayer.java index 672f8be98dc..524f59702dc 100644 --- a/src/main/java/gregtech/api/util/GregFakePlayer.java +++ b/src/main/java/gregtech/api/util/GregFakePlayer.java @@ -11,32 +11,51 @@ import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.util.FakePlayer; -import net.minecraftforge.common.util.FakePlayerFactory; import net.minecraftforge.common.util.ITeleporter; import net.minecraftforge.fml.common.FMLCommonHandler; import com.mojang.authlib.GameProfile; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.lang.ref.WeakReference; +import java.util.Map; import java.util.UUID; public class GregFakePlayer extends EntityPlayer { - private static final GameProfile GREGTECH = new GameProfile(UUID.fromString("518FDF18-EC2A-4322-832A-58ED1721309B"), - "[GregTech]"); - private static WeakReference GREGTECH_PLAYER = null; + private static final String FAKE_NAME = "[GregTech]"; + private static final UUID FAKE_UUID = UUID.fromString("518FDF18-EC2A-4322-832A-58ED1721309B"); + private static final GameProfile FAKE_PROFILE = new GameProfile(FAKE_UUID, FAKE_NAME); + private static final Map PROFILE_CACHE = new Object2ObjectOpenHashMap<>(); + private static final Map> GREGTECH_PLAYERS = new Object2ObjectOpenHashMap<>(); - public static FakePlayer get(WorldServer world) { - FakePlayer ret = GREGTECH_PLAYER != null ? GREGTECH_PLAYER.get() : null; - if (ret == null) { - ret = FakePlayerFactory.get(world, GREGTECH); - GREGTECH_PLAYER = new WeakReference<>(ret); + public static @NotNull FakePlayer get(@NotNull WorldServer world) { + return get(world, FAKE_PROFILE); + } + + public static @NotNull FakePlayer get(@NotNull WorldServer world, @Nullable UUID fakePlayerUUID) { + return get(world, fakePlayerUUID == null ? FAKE_PROFILE : + PROFILE_CACHE.computeIfAbsent(fakePlayerUUID, id -> new GameProfile(id, FAKE_NAME))); + } + + public static @NotNull FakePlayer get(@NotNull WorldServer world, @NotNull GameProfile fakePlayerProfile) { + UUID id = fakePlayerProfile.getId(); + if (GREGTECH_PLAYERS.containsKey(id)) { + FakePlayer fakePlayer = GREGTECH_PLAYERS.get(id).get(); + if (fakePlayer != null) { + return fakePlayer; + } } - return ret; + + FakePlayer fakePlayer = new FakePlayer(world, fakePlayerProfile); + GREGTECH_PLAYERS.put(id, new WeakReference<>(fakePlayer)); + return fakePlayer; } - public GregFakePlayer(World worldIn) { - super(worldIn, GREGTECH); + public GregFakePlayer(@NotNull World worldIn) { + super(worldIn, FAKE_PROFILE); } @Override diff --git a/src/main/java/gregtech/api/util/Mods.java b/src/main/java/gregtech/api/util/Mods.java index 9b56b74688d..4cbd4031fa3 100644 --- a/src/main/java/gregtech/api/util/Mods.java +++ b/src/main/java/gregtech/api/util/Mods.java @@ -46,6 +46,9 @@ public enum Mods { ForestryApiculture(Names.FORESTRY, forestryModule(Names.FORESTRY_APICULTURE)), ForestryArboriculture(Names.FORESTRY, forestryModule(Names.FORESTRY_ARBORICULTURE)), ForestryLepidopterology(Names.FORESTRY, forestryModule(Names.FORESTRY_LEPIDOPTEROLOGY)), + FTB_LIB(Names.FTB_LIB), + // FTB Utilities hard deps on ftb lib so you don't have to check if both are loaded + FTB_UTILITIES(Names.FTB_UTILITIES), GalacticraftCore(Names.GALACTICRAFT_CORE), Genetics(Names.GENETICS), GregTech(Names.GREGTECH), @@ -118,6 +121,8 @@ public static class Names { public static final String FORESTRY_APICULTURE = "apiculture"; public static final String FORESTRY_ARBORICULTURE = "arboriculture"; public static final String FORESTRY_LEPIDOPTEROLOGY = "lepidopterology"; + public static final String FTB_LIB = "ftblib"; + public static final String FTB_UTILITIES = "ftbutilities"; public static final String GALACTICRAFT_CORE = "galacticraftcore"; public static final String GENETICS = "genetics"; public static final String GREGTECH = GTValues.MODID; diff --git a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java index 42cefd755d1..ccd68fe8207 100644 --- a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java +++ b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java @@ -9,6 +9,7 @@ import gregtech.api.util.BlockUtility; import gregtech.api.util.GTTransferUtils; import gregtech.api.util.GregFakePlayer; +import gregtech.api.util.Mods; import gregtech.client.renderer.texture.Textures; import gregtech.client.utils.RenderUtil; @@ -45,6 +46,9 @@ import com.cleanroommc.modularui.widgets.ItemSlot; import com.cleanroommc.modularui.widgets.SlotGroupWidget; import com.cleanroommc.modularui.widgets.layout.Grid; +import com.feed_the_beast.ftblib.lib.math.ChunkDimPos; +import com.feed_the_beast.ftbutilities.data.ClaimedChunk; +import com.feed_the_beast.ftbutilities.data.ClaimedChunks; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -83,22 +87,32 @@ public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, public void update() { super.update(); - if (!getWorld().isRemote) { - if (getOffsetTimer() % 5 == 0) { - pushItemsIntoNearbyHandlers(getOutputFacing()); + World world = getWorld(); + if (!world.isRemote) { + EntityPlayer fakePlayer = GregFakePlayer.get((WorldServer) world, getOwner()); + BlockPos selfPos = getPos(); + BlockPos lookingAtPos = selfPos.offset(getFrontFacing()); + + boolean canEditBlock = world.isBlockModifiable(fakePlayer, lookingAtPos); + if (Mods.FTB_UTILITIES.isModLoaded()) { + ClaimedChunks instance = ClaimedChunks.instance; + ClaimedChunk claimedChunk = instance + .getChunk(new ChunkDimPos(lookingAtPos, world.provider.getDimension())); + if (claimedChunk != null) { + canEditBlock &= claimedChunk.getTeam() + .hasStatus(instance.universe.getPlayer(getOwner()), + claimedChunk.getData().getEditBlocksStatus()); + } } if (breakProgressTicksLeft > 0) { --breakProgressTicksLeft; if (breakProgressTicksLeft == 0 && energyContainer.getEnergyStored() >= getEnergyPerBlockBreak()) { - BlockPos blockPos = getPos().offset(getFrontFacing()); - IBlockState blockState = getWorld().getBlockState(blockPos); - EntityPlayer entityPlayer = GregFakePlayer.get((WorldServer) getWorld()); - float hardness = blockState.getBlockHardness(getWorld(), blockPos); - - if (hardness >= 0.0f && getWorld().isBlockModifiable(entityPlayer, blockPos) && - Math.abs(hardness - currentBlockHardness) < 0.5f) { - List drops = attemptBreakBlockAndObtainDrops(blockPos, blockState, entityPlayer); + IBlockState blockState = getWorld().getBlockState(lookingAtPos); + float hardness = blockState.getBlockHardness(getWorld(), lookingAtPos); + + if (hardness >= 0.0f && canEditBlock && Math.abs(hardness - currentBlockHardness) < 0.5f) { + List drops = attemptBreakBlockAndObtainDrops(lookingAtPos, blockState, fakePlayer); addToInventoryOrDropItems(drops); } @@ -107,19 +121,21 @@ public void update() { } } - if (breakProgressTicksLeft == 0 && isBlockRedstonePowered()) { - BlockPos blockPos = getPos().offset(getFrontFacing()); - IBlockState blockState = getWorld().getBlockState(blockPos); - EntityPlayer entityPlayer = GregFakePlayer.get((WorldServer) getWorld()); - float hardness = blockState.getBlockHardness(getWorld(), blockPos); + if (breakProgressTicksLeft == 0 && isBlockRedstonePowered() && canEditBlock) { + IBlockState blockState = getWorld().getBlockState(lookingAtPos); + float hardness = blockState.getBlockHardness(getWorld(), lookingAtPos); boolean skipBlock = blockState.getMaterial() == Material.AIR || blockState.getBlock().isAir(blockState, getWorld(), getPos()) || blockState.getBlock() instanceof BlockLiquid; - if (hardness >= 0.0f && !skipBlock && getWorld().isBlockModifiable(entityPlayer, blockPos)) { + if (!skipBlock && hardness >= 0.0f) { breakProgressTicksLeft = getTicksPerBlockBreak(hardness); currentBlockHardness = hardness; } } + + if (getOffsetTimer() % 5 == 0) { + pushItemsIntoNearbyHandlers(getOutputFacing()); + } } } From 1f265df79550bb938f61d6a3b0189778da37293a Mon Sep 17 00:00:00 2001 From: Zorbatron <46525467+Zorbatron@users.noreply.github.com> Date: Tue, 26 Aug 2025 20:35:55 -0400 Subject: [PATCH 4/9] refactor for cleanliness and add support for adding custom predicates to block breaking certain blocks --- .../api/util/function/TriPredicate.java | 7 + .../electric/MetaTileEntityBlockBreaker.java | 150 +++++++++++------- 2 files changed, 99 insertions(+), 58 deletions(-) create mode 100644 src/main/java/gregtech/api/util/function/TriPredicate.java diff --git a/src/main/java/gregtech/api/util/function/TriPredicate.java b/src/main/java/gregtech/api/util/function/TriPredicate.java new file mode 100644 index 00000000000..29ffe61028a --- /dev/null +++ b/src/main/java/gregtech/api/util/function/TriPredicate.java @@ -0,0 +1,7 @@ +package gregtech.api.util.function; + +@FunctionalInterface +public interface TriPredicate { + + boolean test(A a, B b, C c); +} diff --git a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java index ccd68fe8207..c79b37b845c 100644 --- a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java +++ b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java @@ -10,12 +10,12 @@ import gregtech.api.util.GTTransferUtils; import gregtech.api.util.GregFakePlayer; import gregtech.api.util.Mods; +import gregtech.api.util.function.TriPredicate; import gregtech.client.renderer.texture.Textures; import gregtech.client.utils.RenderUtil; import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; -import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.client.resources.I18n; import net.minecraft.entity.item.EntityItem; @@ -31,6 +31,7 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import net.minecraft.world.WorldServer; +import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.items.IItemHandlerModifiable; import codechicken.lib.raytracer.CuboidRayTraceResult; @@ -46,9 +47,12 @@ import com.cleanroommc.modularui.widgets.ItemSlot; import com.cleanroommc.modularui.widgets.SlotGroupWidget; import com.cleanroommc.modularui.widgets.layout.Grid; +import com.feed_the_beast.ftblib.lib.EnumTeamStatus; +import com.feed_the_beast.ftblib.lib.data.ForgePlayer; import com.feed_the_beast.ftblib.lib.math.ChunkDimPos; import com.feed_the_beast.ftbutilities.data.ClaimedChunk; import com.feed_the_beast.ftbutilities.data.ClaimedChunks; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -63,6 +67,42 @@ public class MetaTileEntityBlockBreaker extends TieredMetaTileEntity { private EnumFacing outputFacing; private int breakProgressTicksLeft; private float currentBlockHardness; + private static final List<@NotNull TriPredicate<@NotNull World, @NotNull BlockPos, @NotNull FakePlayer>> PREDICATE_LIST = new ObjectArrayList<>( + 2); + + static { + PREDICATE_LIST.add((world, blockPos, fakePlayer) -> !world.isAirBlock(blockPos)); + PREDICATE_LIST.add( + (world, blockPos, fakePlayer) -> !(world.getBlockState(blockPos).getBlock() instanceof BlockLiquid)); + PREDICATE_LIST.add((world, blockPos, fakePlayer) -> world.isBlockModifiable(fakePlayer, blockPos)); + if (Mods.FTB_UTILITIES.isModLoaded()) { + PREDICATE_LIST.add((world, blockPos, fakePlayer) -> { + ClaimedChunks instance = ClaimedChunks.instance; + ClaimedChunk claimedChunk = instance.getChunk(new ChunkDimPos(blockPos, world.provider.getDimension())); + if (claimedChunk != null) { + ForgePlayer forgePlayer = instance.universe.getPlayer(fakePlayer.getUniqueID()); + EnumTeamStatus status = claimedChunk.getData().getEditBlocksStatus(); + return !claimedChunk.getTeam().hasStatus(forgePlayer, status); + } else { + return true; + } + }); + } + } + + /** + * Add a predicate check to the block breaker. Intended to be used to prevent a certain block from being broken. + *
+ * Warning! the {@link FakePlayer} passed to the predicate is not a real player, but a fake one with + * the same UUID as the real player who placed the block breaker
+ * Return {@code false} to cancel a break attempt on this block.
+ * Return {@code true} to move onto the next predicate, and eventually break the block only if all other predicates + * returned {@code false}. + */ + @SuppressWarnings("unused") + public static void registerBlockBreakerPredicate(@NotNull TriPredicate<@NotNull World, @NotNull BlockPos, @NotNull FakePlayer> predicate) { + PREDICATE_LIST.add(predicate); + } public MetaTileEntityBlockBreaker(ResourceLocation metaTileEntityId, int tier) { super(metaTileEntityId, tier); @@ -89,84 +129,78 @@ public void update() { World world = getWorld(); if (!world.isRemote) { - EntityPlayer fakePlayer = GregFakePlayer.get((WorldServer) world, getOwner()); - BlockPos selfPos = getPos(); - BlockPos lookingAtPos = selfPos.offset(getFrontFacing()); + tryBreakBlock(world); - boolean canEditBlock = world.isBlockModifiable(fakePlayer, lookingAtPos); - if (Mods.FTB_UTILITIES.isModLoaded()) { - ClaimedChunks instance = ClaimedChunks.instance; - ClaimedChunk claimedChunk = instance - .getChunk(new ChunkDimPos(lookingAtPos, world.provider.getDimension())); - if (claimedChunk != null) { - canEditBlock &= claimedChunk.getTeam() - .hasStatus(instance.universe.getPlayer(getOwner()), - claimedChunk.getData().getEditBlocksStatus()); - } + if (getOffsetTimer() % 5 == 0) { + pushItemsIntoNearbyHandlers(getOutputFacing()); } + } + } - if (breakProgressTicksLeft > 0) { - --breakProgressTicksLeft; - if (breakProgressTicksLeft == 0 && energyContainer.getEnergyStored() >= getEnergyPerBlockBreak()) { - IBlockState blockState = getWorld().getBlockState(lookingAtPos); - float hardness = blockState.getBlockHardness(getWorld(), lookingAtPos); - - if (hardness >= 0.0f && canEditBlock && Math.abs(hardness - currentBlockHardness) < 0.5f) { - List drops = attemptBreakBlockAndObtainDrops(lookingAtPos, blockState, fakePlayer); - addToInventoryOrDropItems(drops); - } + protected void tryBreakBlock(@NotNull World world) { + BlockPos selfPos = getPos(); + BlockPos lookingAtPos = selfPos.offset(getFrontFacing()); + FakePlayer fakePlayer = GregFakePlayer.get((WorldServer) world, getOwner()); - currentBlockHardness = 0.0f; - energyContainer.removeEnergy(getEnergyPerBlockBreak()); - } + for (TriPredicate predicate : PREDICATE_LIST) { + if (!predicate.test(world, lookingAtPos, fakePlayer)) { + return; } + } - if (breakProgressTicksLeft == 0 && isBlockRedstonePowered() && canEditBlock) { - IBlockState blockState = getWorld().getBlockState(lookingAtPos); - float hardness = blockState.getBlockHardness(getWorld(), lookingAtPos); - boolean skipBlock = blockState.getMaterial() == Material.AIR || - blockState.getBlock().isAir(blockState, getWorld(), getPos()) || - blockState.getBlock() instanceof BlockLiquid; - if (!skipBlock && hardness >= 0.0f) { - breakProgressTicksLeft = getTicksPerBlockBreak(hardness); - currentBlockHardness = hardness; - } + IBlockState blockState = world.getBlockState(lookingAtPos); + if (breakProgressTicksLeft > 0 && --breakProgressTicksLeft == 0 && + energyContainer.getEnergyStored() >= getEnergyPerBlockBreak()) { + float hardness = blockState.getBlockHardness(world, lookingAtPos); + if (hardness >= 0.0f && Math.abs(hardness - currentBlockHardness) < 0.5f) { + List drops = attemptBreakBlockAndObtainDrops(world, lookingAtPos, blockState, fakePlayer); + addToInventoryOrDropItems(drops, world, getFrontFacing()); } - if (getOffsetTimer() % 5 == 0) { - pushItemsIntoNearbyHandlers(getOutputFacing()); + currentBlockHardness = 0.0f; + energyContainer.removeEnergy(getEnergyPerBlockBreak()); + } + + if (breakProgressTicksLeft == 0 && isBlockRedstonePowered()) { + float hardness = blockState.getBlockHardness(world, lookingAtPos); + if (hardness >= 0.0f) { + breakProgressTicksLeft = getTicksPerBlockBreak(hardness); + currentBlockHardness = hardness; } } } - private void addToInventoryOrDropItems(List drops) { - EnumFacing outputFacing = getOutputFacing(); - double itemSpawnX = getPos().getX() + 0.5 + outputFacing.getXOffset(); - double itemSpawnY = getPos().getY() + 0.5 + outputFacing.getYOffset(); - double itemSpawnZ = getPos().getZ() + 0.5 + outputFacing.getZOffset(); + protected void addToInventoryOrDropItems(@NotNull List drops, @NotNull World world, + @NotNull EnumFacing frontFacing) { + double itemSpawnX = getPos().getX() + 0.5 + frontFacing.getXOffset(); + double itemSpawnY = getPos().getY() + 0.5 + frontFacing.getYOffset(); + double itemSpawnZ = getPos().getZ() + 0.5 + frontFacing.getZOffset(); for (ItemStack itemStack : drops) { ItemStack remainStack = GTTransferUtils.insertItem(exportItems, itemStack, false); if (!remainStack.isEmpty()) { - EntityItem entityitem = new EntityItem(getWorld(), itemSpawnX, itemSpawnY, itemSpawnZ, remainStack); + EntityItem entityitem = new EntityItem(world, itemSpawnX, itemSpawnY, itemSpawnZ, remainStack); entityitem.setDefaultPickupDelay(); - getWorld().spawnEntity(entityitem); + world.spawnEntity(entityitem); } } } - private List attemptBreakBlockAndObtainDrops(BlockPos blockPos, IBlockState blockState, - EntityPlayer entityPlayer) { - TileEntity tileEntity = getWorld().getTileEntity(blockPos); - boolean result = blockState.getBlock().removedByPlayer(blockState, getWorld(), blockPos, entityPlayer, true); + protected @NotNull List attemptBreakBlockAndObtainDrops(@NotNull World world, + @NotNull BlockPos lookingAtPos, + @NotNull IBlockState blockState, + @NotNull EntityPlayer entityPlayer) { + TileEntity tileEntity = world.getTileEntity(lookingAtPos); + Block block = blockState.getBlock(); + boolean result = block.removedByPlayer(blockState, world, lookingAtPos, entityPlayer, true); if (result) { - getWorld().playEvent(null, 2001, blockPos, Block.getStateId(blockState)); - blockState.getBlock().onPlayerDestroy(getWorld(), blockPos, blockState); + world.playEvent(null, 2001, lookingAtPos, Block.getStateId(blockState)); + block.onPlayerDestroy(world, lookingAtPos, blockState); BlockUtility.startCaptureDrops(); - blockState.getBlock().harvestBlock(getWorld(), entityPlayer, blockPos, blockState, tileEntity, - ItemStack.EMPTY); + block.harvestBlock(world, entityPlayer, lookingAtPos, blockState, tileEntity, ItemStack.EMPTY); return BlockUtility.stopCaptureDrops(); } + return Collections.emptyList(); } @@ -249,23 +283,23 @@ public void setFrontFacing(EnumFacing frontFacing) { } } - private int getEnergyPerBlockBreak() { + public int getEnergyPerBlockBreak() { return (int) GTValues.V[getTier()]; } - private int getInventorySize() { + protected int getInventorySize() { int sizeRoot = (1 + getTier()); return sizeRoot * sizeRoot; } - private int getTicksPerBlockBreak(float blockHardness) { + public int getTicksPerBlockBreak(float blockHardness) { int ticksPerOneDurability = 5; int totalTicksPerBlock = (int) Math.ceil(ticksPerOneDurability * blockHardness); float efficiencyMultiplier = 1.0f - getEfficiencyMultiplier(); return (int) Math.ceil(totalTicksPerBlock * efficiencyMultiplier); } - private float getEfficiencyMultiplier() { + public float getEfficiencyMultiplier() { return 1.0f - MathHelper.clamp(1.0f - 0.2f * (getTier() - 1.0f), 0.1f, 1.0f); } From 044eb1d82d9c8c4ffdfbd548dcf5a5ad2ae8a78b Mon Sep 17 00:00:00 2001 From: Zorbatron <46525467+Zorbatron@users.noreply.github.com> Date: Tue, 26 Aug 2025 21:08:06 -0400 Subject: [PATCH 5/9] Fix skulls dropping the item instead of it being picked up --- .../electric/MetaTileEntityBlockBreaker.java | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java index c79b37b845c..c7028de6876 100644 --- a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java +++ b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java @@ -16,6 +16,7 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; +import net.minecraft.block.BlockSkull; import net.minecraft.block.state.IBlockState; import net.minecraft.client.resources.I18n; import net.minecraft.entity.item.EntityItem; @@ -191,14 +192,27 @@ protected void addToInventoryOrDropItems(@NotNull List drops, @NotNul @NotNull EntityPlayer entityPlayer) { TileEntity tileEntity = world.getTileEntity(lookingAtPos); Block block = blockState.getBlock(); - boolean result = block.removedByPlayer(blockState, world, lookingAtPos, entityPlayer, true); - if (result) { - world.playEvent(null, 2001, lookingAtPos, Block.getStateId(blockState)); - block.onPlayerDestroy(world, lookingAtPos, blockState); - + if (block instanceof BlockSkull) { BlockUtility.startCaptureDrops(); - block.harvestBlock(world, entityPlayer, lookingAtPos, blockState, tileEntity, ItemStack.EMPTY); - return BlockUtility.stopCaptureDrops(); + boolean result = block.removedByPlayer(blockState, world, lookingAtPos, entityPlayer, true); + List drops = BlockUtility.stopCaptureDrops(); + + if (result) { + world.playEvent(null, 2001, lookingAtPos, Block.getStateId(blockState)); + block.onPlayerDestroy(world, lookingAtPos, blockState); + + block.harvestBlock(world, entityPlayer, lookingAtPos, blockState, tileEntity, ItemStack.EMPTY); + return drops; + } + } else { + if (block.removedByPlayer(blockState, world, lookingAtPos, entityPlayer, true)) { + world.playEvent(null, 2001, lookingAtPos, Block.getStateId(blockState)); + block.onPlayerDestroy(world, lookingAtPos, blockState); + + BlockUtility.startCaptureDrops(); + block.harvestBlock(world, entityPlayer, lookingAtPos, blockState, tileEntity, ItemStack.EMPTY); + return BlockUtility.stopCaptureDrops(); + } } return Collections.emptyList(); From 38c504e60cfe74bd43e9bc2d6a8df1cd1b3fc7ce Mon Sep 17 00:00:00 2001 From: Zorbatron <46525467+Zorbatron@users.noreply.github.com> Date: Fri, 12 Sep 2025 09:59:12 -0400 Subject: [PATCH 6/9] Extract block permission check out into util method --- .../java/gregtech/api/util/FTBChunksUtil.java | 30 +++++++++++++++++++ .../electric/MetaTileEntityBlockBreaker.java | 22 +++----------- 2 files changed, 34 insertions(+), 18 deletions(-) create mode 100644 src/main/java/gregtech/api/util/FTBChunksUtil.java diff --git a/src/main/java/gregtech/api/util/FTBChunksUtil.java b/src/main/java/gregtech/api/util/FTBChunksUtil.java new file mode 100644 index 00000000000..3e15d999b20 --- /dev/null +++ b/src/main/java/gregtech/api/util/FTBChunksUtil.java @@ -0,0 +1,30 @@ +package gregtech.api.util; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import com.feed_the_beast.ftblib.lib.EnumTeamStatus; +import com.feed_the_beast.ftblib.lib.data.ForgePlayer; +import com.feed_the_beast.ftblib.lib.math.ChunkDimPos; +import com.feed_the_beast.ftbutilities.data.ClaimedChunk; +import com.feed_the_beast.ftbutilities.data.ClaimedChunks; +import org.jetbrains.annotations.NotNull; + +public class FTBChunksUtil { + + public static boolean isBlockModifiableByPlayer(@NotNull World world, @NotNull BlockPos blockPos, + @NotNull EntityPlayer player) { + if (!Mods.FTB_UTILITIES.isModLoaded()) return true; + + ClaimedChunks instance = ClaimedChunks.instance; + ClaimedChunk claimedChunk = instance.getChunk(new ChunkDimPos(blockPos, world.provider.getDimension())); + if (claimedChunk != null) { + ForgePlayer forgePlayer = instance.universe.getPlayer(player.getUniqueID()); + EnumTeamStatus status = claimedChunk.getData().getEditBlocksStatus(); + return !claimedChunk.getTeam().hasStatus(forgePlayer, status); + } + + return true; + } +} diff --git a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java index c7028de6876..7959fa71db7 100644 --- a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java +++ b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java @@ -7,6 +7,7 @@ import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; import gregtech.api.mui.GTGuis; import gregtech.api.util.BlockUtility; +import gregtech.api.util.FTBChunksUtil; import gregtech.api.util.GTTransferUtils; import gregtech.api.util.GregFakePlayer; import gregtech.api.util.Mods; @@ -48,11 +49,6 @@ import com.cleanroommc.modularui.widgets.ItemSlot; import com.cleanroommc.modularui.widgets.SlotGroupWidget; import com.cleanroommc.modularui.widgets.layout.Grid; -import com.feed_the_beast.ftblib.lib.EnumTeamStatus; -import com.feed_the_beast.ftblib.lib.data.ForgePlayer; -import com.feed_the_beast.ftblib.lib.math.ChunkDimPos; -import com.feed_the_beast.ftbutilities.data.ClaimedChunk; -import com.feed_the_beast.ftbutilities.data.ClaimedChunks; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -69,7 +65,7 @@ public class MetaTileEntityBlockBreaker extends TieredMetaTileEntity { private int breakProgressTicksLeft; private float currentBlockHardness; private static final List<@NotNull TriPredicate<@NotNull World, @NotNull BlockPos, @NotNull FakePlayer>> PREDICATE_LIST = new ObjectArrayList<>( - 2); + 3); static { PREDICATE_LIST.add((world, blockPos, fakePlayer) -> !world.isAirBlock(blockPos)); @@ -77,17 +73,7 @@ public class MetaTileEntityBlockBreaker extends TieredMetaTileEntity { (world, blockPos, fakePlayer) -> !(world.getBlockState(blockPos).getBlock() instanceof BlockLiquid)); PREDICATE_LIST.add((world, blockPos, fakePlayer) -> world.isBlockModifiable(fakePlayer, blockPos)); if (Mods.FTB_UTILITIES.isModLoaded()) { - PREDICATE_LIST.add((world, blockPos, fakePlayer) -> { - ClaimedChunks instance = ClaimedChunks.instance; - ClaimedChunk claimedChunk = instance.getChunk(new ChunkDimPos(blockPos, world.provider.getDimension())); - if (claimedChunk != null) { - ForgePlayer forgePlayer = instance.universe.getPlayer(fakePlayer.getUniqueID()); - EnumTeamStatus status = claimedChunk.getData().getEditBlocksStatus(); - return !claimedChunk.getTeam().hasStatus(forgePlayer, status); - } else { - return true; - } - }); + PREDICATE_LIST.add(FTBChunksUtil::isBlockModifiableByPlayer); } } @@ -95,7 +81,7 @@ public class MetaTileEntityBlockBreaker extends TieredMetaTileEntity { * Add a predicate check to the block breaker. Intended to be used to prevent a certain block from being broken. *
* Warning! the {@link FakePlayer} passed to the predicate is not a real player, but a fake one with - * the same UUID as the real player who placed the block breaker
+ * the same UUID as the real player who placed the block breaker.
* Return {@code false} to cancel a break attempt on this block.
* Return {@code true} to move onto the next predicate, and eventually break the block only if all other predicates * returned {@code false}. From d9ad9d8d60ab897d5213a9629825ea0b2295c511 Mon Sep 17 00:00:00 2001 From: Zorbatron <46525467+Zorbatron@users.noreply.github.com> Date: Fri, 12 Sep 2025 09:59:58 -0400 Subject: [PATCH 7/9] Add getters for ticks left and block hardness for potential future uses :shrug: --- .../electric/MetaTileEntityBlockBreaker.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java index 7959fa71db7..ccb4f4cac03 100644 --- a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java +++ b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java @@ -261,11 +261,12 @@ public boolean isValidFrontFacing(EnumFacing facing) { return facing != outputFacing; } + @NotNull public EnumFacing getOutputFacing() { return outputFacing == null ? EnumFacing.SOUTH : outputFacing; } - public void setOutputFacing(EnumFacing outputFacing) { + public void setOutputFacing(@NotNull EnumFacing outputFacing) { this.outputFacing = outputFacing; if (!getWorld().isRemote) { notifyBlockUpdate(); @@ -275,12 +276,10 @@ public void setOutputFacing(EnumFacing outputFacing) { } @Override - public void setFrontFacing(EnumFacing frontFacing) { + public void setFrontFacing(@NotNull EnumFacing frontFacing) { super.setFrontFacing(frontFacing); - if (this.outputFacing == null) { - // set initial output facing as opposite to front - setOutputFacing(frontFacing.getOpposite()); - } + // Set initial output facing as opposite to front + setOutputFacing(frontFacing.getOpposite()); } public int getEnergyPerBlockBreak() { @@ -303,6 +302,14 @@ public float getEfficiencyMultiplier() { return 1.0f - MathHelper.clamp(1.0f - 0.2f * (getTier() - 1.0f), 0.1f, 1.0f); } + public int getBreakProgressTicksLeft() { + return breakProgressTicksLeft; + } + + public float getCurrentBlockHardness() { + return currentBlockHardness; + } + @Override protected IItemHandlerModifiable createExportItemHandler() { return new GTItemStackHandler(this, getInventorySize()); From 4ff21f852a4126ff9888d9cf5635d09d50f49e81 Mon Sep 17 00:00:00 2001 From: Zorbatron <46525467+Zorbatron@users.noreply.github.com> Date: Fri, 12 Sep 2025 10:08:02 -0400 Subject: [PATCH 8/9] Add overload and javadocs for aforementioned extracted method --- .../java/gregtech/api/util/FTBChunksUtil.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/gregtech/api/util/FTBChunksUtil.java b/src/main/java/gregtech/api/util/FTBChunksUtil.java index 3e15d999b20..063cf0f3d83 100644 --- a/src/main/java/gregtech/api/util/FTBChunksUtil.java +++ b/src/main/java/gregtech/api/util/FTBChunksUtil.java @@ -11,16 +11,37 @@ import com.feed_the_beast.ftbutilities.data.ClaimedChunks; import org.jetbrains.annotations.NotNull; +import java.util.UUID; + public class FTBChunksUtil { + /** + * Check if a {@link BlockPos} is modifiable by a player abiding by FTB chunk rules, if this block is in a claimed + * chunk.
+ * Will always return {@code true} if + * FTBUtilities isn't present or the + * {@link BlockPos} isn't in a claimed chunk. + */ public static boolean isBlockModifiableByPlayer(@NotNull World world, @NotNull BlockPos blockPos, @NotNull EntityPlayer player) { + return isBlockModifiableByPlayer(world, blockPos, player.getUniqueID()); + } + + /** + * Check if a {@link BlockPos} is modifiable by a player abiding by FTB chunk rules, if this block is in a claimed + * chunk.
+ * Will always return {@code true} if + * FTBUtilities isn't present or the + * {@link BlockPos} isn't in a claimed chunk. + */ + public static boolean isBlockModifiableByPlayer(@NotNull World world, @NotNull BlockPos blockPos, + @NotNull UUID playerID) { if (!Mods.FTB_UTILITIES.isModLoaded()) return true; ClaimedChunks instance = ClaimedChunks.instance; ClaimedChunk claimedChunk = instance.getChunk(new ChunkDimPos(blockPos, world.provider.getDimension())); if (claimedChunk != null) { - ForgePlayer forgePlayer = instance.universe.getPlayer(player.getUniqueID()); + ForgePlayer forgePlayer = instance.universe.getPlayer(playerID); EnumTeamStatus status = claimedChunk.getData().getEditBlocksStatus(); return !claimedChunk.getTeam().hasStatus(forgePlayer, status); } From b1022ab55565badf02436475262504fb15f4eb2f Mon Sep 17 00:00:00 2001 From: Zorbatron <46525467+Zorbatron@users.noreply.github.com> Date: Mon, 15 Sep 2025 21:21:40 -0400 Subject: [PATCH 9/9] Move the helper class to the integration package --- .../electric/MetaTileEntityBlockBreaker.java | 4 ++-- .../ftb/utility/FTBChunksHelper.java} | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) rename src/main/java/gregtech/{api/util/FTBChunksUtil.java => integration/ftb/utility/FTBChunksHelper.java} (93%) diff --git a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java index ccb4f4cac03..5d574ef1668 100644 --- a/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java +++ b/src/main/java/gregtech/common/metatileentities/electric/MetaTileEntityBlockBreaker.java @@ -7,13 +7,13 @@ import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; import gregtech.api.mui.GTGuis; import gregtech.api.util.BlockUtility; -import gregtech.api.util.FTBChunksUtil; import gregtech.api.util.GTTransferUtils; import gregtech.api.util.GregFakePlayer; import gregtech.api.util.Mods; import gregtech.api.util.function.TriPredicate; import gregtech.client.renderer.texture.Textures; import gregtech.client.utils.RenderUtil; +import gregtech.integration.ftb.utility.FTBChunksHelper; import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; @@ -73,7 +73,7 @@ public class MetaTileEntityBlockBreaker extends TieredMetaTileEntity { (world, blockPos, fakePlayer) -> !(world.getBlockState(blockPos).getBlock() instanceof BlockLiquid)); PREDICATE_LIST.add((world, blockPos, fakePlayer) -> world.isBlockModifiable(fakePlayer, blockPos)); if (Mods.FTB_UTILITIES.isModLoaded()) { - PREDICATE_LIST.add(FTBChunksUtil::isBlockModifiableByPlayer); + PREDICATE_LIST.add(FTBChunksHelper::isBlockModifiableByPlayer); } } diff --git a/src/main/java/gregtech/api/util/FTBChunksUtil.java b/src/main/java/gregtech/integration/ftb/utility/FTBChunksHelper.java similarity index 93% rename from src/main/java/gregtech/api/util/FTBChunksUtil.java rename to src/main/java/gregtech/integration/ftb/utility/FTBChunksHelper.java index 063cf0f3d83..6e5802817b0 100644 --- a/src/main/java/gregtech/api/util/FTBChunksUtil.java +++ b/src/main/java/gregtech/integration/ftb/utility/FTBChunksHelper.java @@ -1,4 +1,6 @@ -package gregtech.api.util; +package gregtech.integration.ftb.utility; + +import gregtech.api.util.Mods; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.math.BlockPos; @@ -13,7 +15,9 @@ import java.util.UUID; -public class FTBChunksUtil { +public final class FTBChunksHelper { + + private FTBChunksHelper() {} /** * Check if a {@link BlockPos} is modifiable by a player abiding by FTB chunk rules, if this block is in a claimed