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,