Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d0ecebb
Block break event
Geometrically Aug 1, 2020
3855414
License headers + after event
Geometrically Aug 1, 2020
b044d49
Before and after events, testmod
Geometrically Aug 1, 2020
328f32c
Fix checkstyle
Geometrically Aug 1, 2020
640185e
Version bump, fix client method call
Geometrically Aug 1, 2020
c375397
Move to one event class
Geometrically Aug 2, 2020
3550936
Expand event parameters + javadoc
Geometrically Aug 2, 2020
c6c8990
Add cancelation event and move javadocs
Geometrically Aug 3, 2020
2d81e83
Move JavaDoc + Make success have same function as pass
Geometrically Aug 3, 2020
eb4bcf3
Fix success bug
Geometrically Aug 3, 2020
ba58c66
Fix documentation again, change approach
Geometrically Aug 3, 2020
7174955
Fix checkstyle
Geometrically Aug 3, 2020
b7a1d42
Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric…
Geometrically Aug 4, 2020
6bc1f00
Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric…
Geometrically Aug 4, 2020
f7edf75
Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric…
Geometrically Aug 4, 2020
c1ba20c
Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric…
Geometrically Aug 4, 2020
dd887c8
Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric…
Geometrically Aug 4, 2020
49039a3
Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric…
Geometrically Aug 4, 2020
8df6d36
Fix checkstyle
Geometrically Aug 4, 2020
da0c4f4
Rename stuff
Geometrically Aug 5, 2020
d95bb88
fixes
Geometrically Aug 7, 2020
94437bb
Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric…
Geometrically Aug 10, 2020
7c486a3
Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric…
Geometrically Aug 10, 2020
f62b978
Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric…
Geometrically Aug 10, 2020
1f752be
Update fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric…
Geometrically Aug 10, 2020
3410825
Rename Canceled Event Method Name
Geometrically Aug 12, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fabric-events-interaction-v0/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
archivesBaseName = "fabric-events-interaction-v0"
version = getSubprojectVersion(project, "0.3.3")
version = getSubprojectVersion(project, "0.4.0")

dependencies {
compile project(path: ':fabric-api-base', configuration: 'dev')
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@

package net.fabricmc.fabric.impl.event.interaction;

import net.minecraft.util.math.BlockPos;
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.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.block.BlockAttackInteractionAware;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
Expand All @@ -41,5 +45,22 @@ public void onInitialize() {

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)));
}
}
}
}));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@
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.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
import net.minecraft.item.ItemStack;
import net.minecraft.server.network.ServerPlayerEntity;
Expand All @@ -40,6 +44,7 @@
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.fabricmc.fabric.api.event.player.UseItemCallback;
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;

@Mixin(ServerPlayerInteractionManager.class)
public class MixinServerPlayerInteractionManager {
Expand Down Expand Up @@ -81,4 +86,20 @@ public void interactItem(ServerPlayerEntity player, World world, ItemStack stack
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);
}
}
Original file line number Diff line number Diff line change
@@ -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());
}));
}
}
16 changes: 16 additions & 0 deletions fabric-events-interaction-v0/src/testmod/resources/fabric.mod.json
Original file line number Diff line number Diff line change
@@ -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"
]
}
}