diff --git a/fabric-events-interaction-v0/src/client/java/net/fabricmc/fabric/api/event/client/player/ClientPlayerBlockBreakEvents.java b/fabric-events-interaction-v0/src/client/java/net/fabricmc/fabric/api/event/client/player/ClientPlayerBlockBreakEvents.java
new file mode 100644
index 000000000..d817088c3
--- /dev/null
+++ b/fabric-events-interaction-v0/src/client/java/net/fabricmc/fabric/api/event/client/player/ClientPlayerBlockBreakEvents.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.api.event.client.player;
+
+import net.minecraft.block.BlockState;
+import net.minecraft.client.network.ClientPlayerEntity;
+import net.minecraft.client.world.ClientWorld;
+import net.minecraft.util.math.BlockPos;
+
+import net.fabricmc.fabric.api.event.Event;
+import net.fabricmc.fabric.api.event.EventFactory;
+
+/**
+ * Contains client side events triggered by block breaking.
+ *
+ *
For preventing block breaking client side and other purposes, see {@link net.fabricmc.fabric.api.event.player.AttackBlockCallback}.
+ * For server side block break events, see {@link net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents}.
+ */
+public class ClientPlayerBlockBreakEvents {
+ /**
+ * Callback after a block is broken client side.
+ *
+ *
Only called client side. For server side see {@link net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents#AFTER}
+ */
+ public static final Event AFTER = EventFactory.createArrayBacked(After.class,
+ (listeners) -> (world, player, pos, state) -> {
+ for (After event : listeners) {
+ event.afterBlockBreak(world, player, pos, state);
+ }
+ }
+ );
+
+ @FunctionalInterface
+ public interface After {
+ /**
+ * Called after a block is successfully broken.
+ *
+ * @param world the world where the block was broken
+ * @param player the player who broke the block
+ * @param pos the position where the block was broken
+ * @param state the block state before the block was broken
+ */
+ void afterBlockBreak(ClientWorld world, ClientPlayerEntity player, BlockPos pos, BlockState state);
+ }
+}
diff --git a/fabric-events-interaction-v0/src/client/java/net/fabricmc/fabric/mixin/event/interaction/client/ClientPlayerInteractionManagerMixin.java b/fabric-events-interaction-v0/src/client/java/net/fabricmc/fabric/mixin/event/interaction/client/ClientPlayerInteractionManagerMixin.java
index 272ed6c48..ab3ba8b67 100644
--- a/fabric-events-interaction-v0/src/client/java/net/fabricmc/fabric/mixin/event/interaction/client/ClientPlayerInteractionManagerMixin.java
+++ b/fabric-events-interaction-v0/src/client/java/net/fabricmc/fabric/mixin/event/interaction/client/ClientPlayerInteractionManagerMixin.java
@@ -24,7 +24,9 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
@@ -46,7 +48,9 @@ import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.GameMode;
+import net.minecraft.world.World;
+import net.fabricmc.fabric.api.event.client.player.ClientPlayerBlockBreakEvents;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.fabricmc.fabric.api.event.player.AttackEntityCallback;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
@@ -90,6 +94,11 @@ public abstract class ClientPlayerInteractionManagerMixin {
}
}
+ @Inject(method = "breakBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;onBroken(Lnet/minecraft/world/WorldAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)V"), locals = LocalCapture.CAPTURE_FAILHARD)
+ private void fabric$onBlockBroken(BlockPos pos, CallbackInfoReturnable cir, World world, BlockState blockState) {
+ ClientPlayerBlockBreakEvents.AFTER.invoker().afterBlockBreak(client.world, client.player, pos, blockState);
+ }
+
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;sendSequencedPacket(Lnet/minecraft/client/world/ClientWorld;Lnet/minecraft/client/network/SequencedPacketCreator;)V"), method = "interactBlock", cancellable = true)
public void interactBlock(ClientPlayerEntity player, Hand hand, BlockHitResult blockHitResult, CallbackInfoReturnable info) {
// hook interactBlock between the world border check and the actual block interaction to invoke the use block event first
@@ -141,5 +150,5 @@ public abstract class ClientPlayerInteractionManagerMixin {
}
@Shadow
- public abstract void sendSequencedPacket(ClientWorld clientWorld, SequencedPacketCreator supplier);
+ protected abstract void sendSequencedPacket(ClientWorld clientWorld, SequencedPacketCreator supplier);
}
diff --git a/fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/PlayerBlockBreakEvents.java b/fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/PlayerBlockBreakEvents.java
index 7e28b2f1e..c4dad44be 100644
--- a/fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/PlayerBlockBreakEvents.java
+++ b/fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/PlayerBlockBreakEvents.java
@@ -27,6 +27,9 @@ import net.minecraft.world.World;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
+/**
+ * Contains server side events triggered by block breaking.
+ */
public final class PlayerBlockBreakEvents {
private PlayerBlockBreakEvents() { }
@@ -53,10 +56,11 @@ public final class PlayerBlockBreakEvents {
);
/**
- * Callback after a block is broken.
+ * Callback after a block is broken server side.
*
- * Only called on a logical server.
+ *
Only called on a logical server. For client side see {@link net.fabricmc.fabric.api.event.client.player.ClientPlayerBlockBreakEvents#AFTER}
*/
+ @SuppressWarnings("JavadocReference")
public static final Event AFTER = EventFactory.createArrayBacked(After.class,
(listeners) -> (world, player, pos, state, entity) -> {
for (After event : listeners) {
diff --git a/fabric-events-interaction-v0/src/testmod/java/net/fabricmc/fabric/test/event/interaction/PlayerBreakBlockTests.java b/fabric-events-interaction-v0/src/testmod/java/net/fabricmc/fabric/test/event/interaction/PlayerBreakBlockTests.java
index 6a510ec62..dd148f94a 100644
--- a/fabric-events-interaction-v0/src/testmod/java/net/fabricmc/fabric/test/event/interaction/PlayerBreakBlockTests.java
+++ b/fabric-events-interaction-v0/src/testmod/java/net/fabricmc/fabric/test/event/interaction/PlayerBreakBlockTests.java
@@ -29,16 +29,10 @@ public class PlayerBreakBlockTests implements ModInitializer {
@Override
public void onInitialize() {
- PlayerBlockBreakEvents.BEFORE.register(((world, player, pos, state, entity) -> {
- return state.getBlock() != Blocks.BEDROCK;
- }));
+ PlayerBlockBreakEvents.BEFORE.register(((world, player, pos, state, entity) -> state.getBlock() != Blocks.BEDROCK));
- PlayerBlockBreakEvents.CANCELED.register(((world, player, pos, state, entity) -> {
- LOGGER.info("Block break event canceled at " + pos.getX() + ", " + pos.getY() + ", " + pos.getZ());
- }));
+ PlayerBlockBreakEvents.CANCELED.register(((world, player, pos, state, entity) -> LOGGER.info("Block break event canceled at {}, {}, {} (client-side = {})", pos.getX(), pos.getY(), pos.getZ(), world.isClient())));
- PlayerBlockBreakEvents.AFTER.register(((world, player, pos, state, entity) -> {
- LOGGER.info("Block broken at " + pos.getX() + ", " + pos.getY() + ", " + pos.getZ());
- }));
+ PlayerBlockBreakEvents.AFTER.register(((world, player, pos, state, entity) -> LOGGER.info("Block broken at {}, {}, {} (client-side = {})", pos.getX(), pos.getY(), pos.getZ(), world.isClient())));
}
}
diff --git a/fabric-events-interaction-v0/src/testmod/resources/fabric.mod.json b/fabric-events-interaction-v0/src/testmod/resources/fabric.mod.json
index f3ad498eb..0bbca916a 100644
--- a/fabric-events-interaction-v0/src/testmod/resources/fabric.mod.json
+++ b/fabric-events-interaction-v0/src/testmod/resources/fabric.mod.json
@@ -19,6 +19,7 @@
],
"client": [
"net.fabricmc.fabric.test.client.event.interaction.ClientPreAttackTests",
+ "net.fabricmc.fabric.test.client.event.interaction.ClientPlayerBlockBreakTests",
"net.fabricmc.fabric.test.client.event.interaction.PlayerPickBlockTests"
]
}
diff --git a/fabric-events-interaction-v0/src/testmodClient/java/net/fabricmc/fabric/test/client/event/interaction/ClientPlayerBlockBreakTests.java b/fabric-events-interaction-v0/src/testmodClient/java/net/fabricmc/fabric/test/client/event/interaction/ClientPlayerBlockBreakTests.java
new file mode 100644
index 000000000..c980e2779
--- /dev/null
+++ b/fabric-events-interaction-v0/src/testmodClient/java/net/fabricmc/fabric/test/client/event/interaction/ClientPlayerBlockBreakTests.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.test.client.event.interaction;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.fabricmc.api.ClientModInitializer;
+import net.fabricmc.fabric.api.event.client.player.ClientPlayerBlockBreakEvents;
+
+public class ClientPlayerBlockBreakTests implements ClientModInitializer {
+ public static final Logger LOGGER = LoggerFactory.getLogger(ClientPlayerBlockBreakTests.class);
+
+ @Override
+ public void onInitializeClient() {
+ ClientPlayerBlockBreakEvents.AFTER.register(((world, player, pos, state) -> LOGGER.info("Block broken at {}, {}, {} (client-side = {})", pos.getX(), pos.getY(), pos.getZ(), world.isClient())));
+ }
+}