mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-26 17:46:25 -05:00
Block break event (#980)
* Block break event * License headers + after event * Before and after events, testmod * Fix checkstyle * Version bump, fix client method call * Move to one event class * Expand event parameters + javadoc * Add cancelation event and move javadocs * Move JavaDoc + Make success have same function as pass * Fix success bug * Fix documentation again, change approach * Fix checkstyle * Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/BlockBreakEvents.java Co-authored-by: liach <7806504+liach@users.noreply.github.com> * Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/BlockBreakEvents.java Co-authored-by: liach <7806504+liach@users.noreply.github.com> * Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/BlockBreakEvents.java Co-authored-by: liach <7806504+liach@users.noreply.github.com> * Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/BlockBreakEvents.java Co-authored-by: liach <7806504+liach@users.noreply.github.com> * Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/BlockBreakEvents.java Co-authored-by: liach <7806504+liach@users.noreply.github.com> * Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/BlockBreakEvents.java Co-authored-by: liach <7806504+liach@users.noreply.github.com> * Fix checkstyle * Rename stuff * fixes * Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/PlayerBlockBreakEvents.java Co-authored-by: i509VCB <i509vcb@gmail.com> * Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/PlayerBlockBreakEvents.java Co-authored-by: i509VCB <i509vcb@gmail.com> * Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/impl/event/interaction/InteractionEventsRouter.java Co-authored-by: i509VCB <i509vcb@gmail.com> * Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/event/player/PlayerBlockBreakEvents.java Co-authored-by: i509VCB <i509vcb@gmail.com> * Rename Canceled Event Method Name Co-authored-by: liach <7806504+liach@users.noreply.github.com> Co-authored-by: i509VCB <i509vcb@gmail.com>
This commit is contained in:
parent
29679fd6fa
commit
e2e6cdad60
6 changed files with 226 additions and 1 deletions
|
@ -1,5 +1,5 @@
|
||||||
archivesBaseName = "fabric-events-interaction-v0"
|
archivesBaseName = "fabric-events-interaction-v0"
|
||||||
version = getSubprojectVersion(project, "0.3.3")
|
version = getSubprojectVersion(project, "0.4.0")
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(path: ':fabric-api-base', configuration: 'dev')
|
compile project(path: ':fabric-api-base', configuration: 'dev')
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* 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.player;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.event.Event;
|
||||||
|
import net.fabricmc.fabric.api.event.EventFactory;
|
||||||
|
|
||||||
|
public final class PlayerBlockBreakEvents {
|
||||||
|
private PlayerBlockBreakEvents() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback before a block is broken.
|
||||||
|
* Only called on the server, however updates are synced with the client.
|
||||||
|
*
|
||||||
|
* <p>If any listener cancels a block breaking action, that block breaking
|
||||||
|
* action is cancelled and {@link CANCELED} event is fired. Otherwise, the
|
||||||
|
* {@link AFTER} event is fired.</p>
|
||||||
|
*/
|
||||||
|
public static final Event<Before> BEFORE = EventFactory.createArrayBacked(Before.class,
|
||||||
|
(listeners) -> (world, player, pos, state, entity) -> {
|
||||||
|
for (Before event : listeners) {
|
||||||
|
boolean result = event.beforeBlockBreak(world, player, pos, state, entity);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback after a block is broken.
|
||||||
|
*
|
||||||
|
* <p>Only called on a logical server.
|
||||||
|
*/
|
||||||
|
public static final Event<After> AFTER = EventFactory.createArrayBacked(After.class,
|
||||||
|
(listeners) -> (world, player, pos, state, entity) -> {
|
||||||
|
for (After event : listeners) {
|
||||||
|
event.afterBlockBreak(world, player, pos, state, entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback when a block break has been canceled.
|
||||||
|
*
|
||||||
|
* <p>Only called on a logical server. May be used to send packets to revert client-side block changes.
|
||||||
|
*/
|
||||||
|
public static final Event<Canceled> CANCELED = EventFactory.createArrayBacked(Canceled.class,
|
||||||
|
(listeners) -> (world, player, pos, state, entity) -> {
|
||||||
|
for (Canceled event : listeners) {
|
||||||
|
event.onBlockBreakCanceled(world, player, pos, state, entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Before {
|
||||||
|
/**
|
||||||
|
* Called before a block is broken and allows cancelling the block breaking.
|
||||||
|
*
|
||||||
|
* <p>Implementations should not modify the world or assume the block break has completed or failed.</p>
|
||||||
|
*
|
||||||
|
* @param world the world in which the block is broken
|
||||||
|
* @param player the player breaking the block
|
||||||
|
* @param pos the position at which the block is broken
|
||||||
|
* @param state the block state <strong>before</strong> the block is broken
|
||||||
|
* @param blockEntity the block entity <strong>before</strong> the block is broken, can be {@code null}
|
||||||
|
* @return {@code false} to cancel block breaking action, or {@code true} to pass to next listener
|
||||||
|
*/
|
||||||
|
boolean beforeBlockBreak(World world, PlayerEntity player, BlockPos pos, BlockState state, /* Nullable */ BlockEntity blockEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 <strong>before</strong> the block was broken
|
||||||
|
* @param blockEntity the block entity of the broken block, can be {@code null}
|
||||||
|
*/
|
||||||
|
void afterBlockBreak(World world, PlayerEntity player, BlockPos pos, BlockState state, /* Nullable */ BlockEntity blockEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Canceled {
|
||||||
|
/**
|
||||||
|
* Called when a block break has been canceled.
|
||||||
|
*
|
||||||
|
* @param world the world where the block was going to be broken
|
||||||
|
* @param player the player who was going to break the block
|
||||||
|
* @param pos the position where the block was going to be broken
|
||||||
|
* @param state the block state of the block that was going to be broken
|
||||||
|
* @param blockEntity the block entity of the block that was going to be broken, can be {@code null}
|
||||||
|
*/
|
||||||
|
void onBlockBreakCanceled(World world, PlayerEntity player, BlockPos pos, BlockState state, /* Nullable */ BlockEntity blockEntity);
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,9 +16,13 @@
|
||||||
|
|
||||||
package net.fabricmc.fabric.impl.event.interaction;
|
package net.fabricmc.fabric.impl.event.interaction;
|
||||||
|
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
import net.fabricmc.fabric.api.block.BlockAttackInteractionAware;
|
import net.fabricmc.fabric.api.block.BlockAttackInteractionAware;
|
||||||
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
|
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
|
||||||
|
@ -41,5 +45,22 @@ public class InteractionEventsRouter implements ModInitializer {
|
||||||
|
|
||||||
return ActionResult.PASS;
|
return ActionResult.PASS;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is for telling the client that the block wasn't actually broken.
|
||||||
|
* This covers a 3x3 area due to how vanilla redstone handles updates, as it considers
|
||||||
|
* important functions like quasi-connectivity and redstone dust logic
|
||||||
|
*/
|
||||||
|
PlayerBlockBreakEvents.CANCELED.register(((world, player, pos, state, blockEntity) -> {
|
||||||
|
BlockPos cornerPos = pos.add(-1, -1, -1);
|
||||||
|
|
||||||
|
for (int x = 0; x < 3; x++) {
|
||||||
|
for (int y = 0; y < 3; y++) {
|
||||||
|
for (int z = 0; z < 3; z++) {
|
||||||
|
((ServerPlayerEntity) player).networkHandler.sendPacket(new BlockUpdateS2CPacket(world, cornerPos.add(x, y, z)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,11 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
|
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
@ -40,6 +44,7 @@ import net.minecraft.world.World;
|
||||||
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
|
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
|
||||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||||
import net.fabricmc.fabric.api.event.player.UseItemCallback;
|
import net.fabricmc.fabric.api.event.player.UseItemCallback;
|
||||||
|
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
|
||||||
|
|
||||||
@Mixin(ServerPlayerInteractionManager.class)
|
@Mixin(ServerPlayerInteractionManager.class)
|
||||||
public class MixinServerPlayerInteractionManager {
|
public class MixinServerPlayerInteractionManager {
|
||||||
|
@ -81,4 +86,20 @@ public class MixinServerPlayerInteractionManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;onBreak(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Lnet/minecraft/entity/player/PlayerEntity;)V"), method = "tryBreakBlock", locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
|
||||||
|
private void breakBlock(BlockPos pos, CallbackInfoReturnable<Boolean> cir, BlockState state, BlockEntity entity, Block block) {
|
||||||
|
boolean result = PlayerBlockBreakEvents.BEFORE.invoker().beforeBlockBreak(this.world, this.player, pos, state, entity);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
PlayerBlockBreakEvents.CANCELED.invoker().onBlockBreakCanceled(this.world, this.player, pos, state, entity);
|
||||||
|
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;onBroken(Lnet/minecraft/world/WorldAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)V"), method = "tryBreakBlock", locals = LocalCapture.CAPTURE_FAILHARD)
|
||||||
|
private void onBlockBroken(BlockPos pos, CallbackInfoReturnable<Boolean> cir, BlockState state, BlockEntity entity, Block block, boolean b1) {
|
||||||
|
PlayerBlockBreakEvents.AFTER.invoker().afterBlockBreak(this.world, this.player, pos, state, entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* 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.event.interaction;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
|
||||||
|
|
||||||
|
public class PlayerBreakBlockTests implements ModInitializer {
|
||||||
|
public static final Logger LOGGER = LogManager.getLogger("InteractionEventsTest");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
PlayerBlockBreakEvents.BEFORE.register(((world, player, pos, state, entity) -> {
|
||||||
|
return 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.AFTER.register(((world, player, pos, state, entity) -> {
|
||||||
|
LOGGER.info("Block broken at " + pos.getX() + ", " + pos.getY() + ", " + pos.getZ());
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "fabric-events-interaction-v0-testmod",
|
||||||
|
"name": "Fabric Events Interaction (v0) Test Mod",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"environment": "*",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"depends": {
|
||||||
|
"fabric-events-interaction-v0": "*"
|
||||||
|
},
|
||||||
|
"entrypoints": {
|
||||||
|
"main": [
|
||||||
|
"net.fabricmc.fabric.test.event.interaction.PlayerBreakBlockTests"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue