From 343c71d8e25624a12df0d1fadb1fffa24c62028c Mon Sep 17 00:00:00 2001 From: Clark Fischer Date: Wed, 11 Oct 2023 14:22:21 -0700 Subject: [PATCH] Account for exterior block hardness in break speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Players were able to cheese hard block collection by surrounding hard blocks with softer blocks. For example, it was possible to mine up to 8 obsidian at cobblestone break-speed by targeting cobblestone when breaking. To solve this, a new `AbstractBlockState` mixin was introduced. I tried to solve this at other levels (preferably without a mixin), but wasn't able to get all the necessary information anywhere other than at the BlockState level. The minimal breaking delta (which is effectively the same as maximum block hardness) is used instead of the targeted block hardness. Using the average basically didn't solve the issue—it was possible to surround a hard block with softer blocks to 'dilute' the hardness. Fixes https://github.com/Draylar/magna/issues/14 Signed-off-by: Clark Fischer --- .../magna/mixin/AbstractBlockStateMixin.java | 62 +++++++++++++++++++ src/main/resources/magna.mixins.json | 1 + .../dev/draylar/magna/test/MagnaTest.java | 13 ++++ 3 files changed, 76 insertions(+) create mode 100644 src/main/java/dev/draylar/magna/mixin/AbstractBlockStateMixin.java diff --git a/src/main/java/dev/draylar/magna/mixin/AbstractBlockStateMixin.java b/src/main/java/dev/draylar/magna/mixin/AbstractBlockStateMixin.java new file mode 100644 index 0000000..9fd5e81 --- /dev/null +++ b/src/main/java/dev/draylar/magna/mixin/AbstractBlockStateMixin.java @@ -0,0 +1,62 @@ +package dev.draylar.magna.mixin; + +import dev.draylar.magna.api.MagnaTool; +import net.minecraft.block.AbstractBlock; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.List; + +/** + * A mixin that calculates the block breaking delta for {@link MagnaTool MagnaTool}s. + */ +@Mixin(AbstractBlock.AbstractBlockState.class) +public class AbstractBlockStateMixin { + /** + * Compute the block breaking delta for {@link MagnaTool}s. If the held item is not a MagnaTool, this mixin + * does nothing. + * + *

The delta is computed by taking the minimum delta of the affected blocks. Mining speed is effectively limited + * by the hardest block being broken. + */ + @Inject( + method = "calcBlockBreakingDelta", + at = @At("HEAD"), + cancellable = true + ) + public void calcBlockBreakingDelta(PlayerEntity player, BlockView world, BlockPos pos, CallbackInfoReturnable cir) { + ItemStack stack = player.getInventory().getMainHandStack(); + if (stack.getItem() instanceof MagnaTool tool) { + cir.cancel(); + int radius = tool.getRadius(stack); + cir.setReturnValue(calculateDelta(tool, player, radius)); + } + } + + @Unique + private static float calculateDelta(final MagnaTool tool, final PlayerEntity player, final int radius) { + World world = player.getWorld(); + + // Even though we already have the BlockPosition that the player is targeting, the side information wasn't + // passed along, which is necessary for figuring out how to expand the radius. Just throw that away and + // recompute. + List blocks = tool.getBlockFinder().findPositions(world, player, radius); + + return blocks.stream() + .map(pos -> { + BlockState state = world.getBlockState(pos); + //noinspection deprecation + return state.getBlock().calcBlockBreakingDelta(state, player, world, pos); + }) + .min(Float::compare).orElseThrow(); + } +} diff --git a/src/main/resources/magna.mixins.json b/src/main/resources/magna.mixins.json index 833c6a8..be088b4 100644 --- a/src/main/resources/magna.mixins.json +++ b/src/main/resources/magna.mixins.json @@ -3,6 +3,7 @@ "package": "dev.draylar.magna.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ + "AbstractBlockStateMixin", "BlockMixin", "PlayerInventoryMixin", "ServerPlayerInteractionManagerMixin", diff --git a/src/testmod/java/dev/draylar/magna/test/MagnaTest.java b/src/testmod/java/dev/draylar/magna/test/MagnaTest.java index b190af5..286a582 100644 --- a/src/testmod/java/dev/draylar/magna/test/MagnaTest.java +++ b/src/testmod/java/dev/draylar/magna/test/MagnaTest.java @@ -4,6 +4,7 @@ import dev.draylar.magna.item.ExcavatorItem; import dev.draylar.magna.item.HammerItem; import net.fabricmc.api.ModInitializer; +import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -31,6 +32,18 @@ public void onInitialize() { new HammerItem(ToolMaterials.DIAMOND, 0, 0, new Item.Settings()) ); + // Standard hammer with a particularly slow mining speed. Useful for testing break speed. + Registry.register( + Registries.ITEM, + new Identifier("magna", "hammer_slow_test"), + new HammerItem(ToolMaterials.DIAMOND, 0, 0, new Item.Settings()) { + @Override + public float getMiningSpeedMultiplier(ItemStack stack, BlockState state) { + return 1.0f; + } + } + ); + // Standard Hammer with a tool material of Diamond and a modified depth. Registry.register( Registries.ITEM,