Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Commit 7d7f2b1

Browse files
Impl removedByPlayer and canHarvestBlock in IForgeBlock (#126)
* Impl removedByPlayer and canHarvestBlock in IForgeBlock * Apply kitlith's suggestions * Fix ThreadLocal memory leakage * Apply suggestions * Remove unneeded dependency Co-authored-by: TheGlitch76 <glitchieproductionsofficial@gmail.com>
1 parent 31e2fca commit 7d7f2b1

File tree

22 files changed

+635
-92
lines changed

22 files changed

+635
-92
lines changed

patchwork-events-world/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ version = getSubprojectVersion(project, "0.3.0")
33

44
dependencies {
55
implementation project(path: ':patchwork-api-base', configuration: 'dev')
6+
implementation project(path: ':patchwork-extensions-block', configuration: 'dev')
67
}

patchwork-events-world/src/main/java/net/minecraftforge/event/world/BlockEvent.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,21 @@
2121

2222
import java.util.List;
2323

24+
import net.minecraftforge.common.extensions.IForgeBlockState;
2425
import net.minecraftforge.eventbus.api.Event;
2526

2627
import net.minecraft.item.ItemStack;
2728
import net.minecraft.util.DefaultedList;
2829
import net.minecraft.block.BlockState;
30+
import net.minecraft.enchantment.EnchantmentHelper;
31+
import net.minecraft.enchantment.Enchantments;
2932
import net.minecraft.entity.player.PlayerEntity;
3033
import net.minecraft.util.math.BlockPos;
3134
import net.minecraft.world.IWorld;
3235
import net.minecraft.world.World;
3336

37+
import net.patchworkmc.impl.extensions.block.BlockHarvestManager;
38+
3439
public class BlockEvent extends Event {
3540
private final IWorld world;
3641
private final BlockPos pos;
@@ -73,17 +78,14 @@ public BreakEvent(World world, BlockPos pos, BlockState state, PlayerEntity play
7378
this.player = player;
7479
this.exp = 0;
7580

76-
// TODO: BlockState#getExpDrop
77-
78-
/*
7981
// Handle empty block or player unable to break block scenario
80-
if (state == null || !ForgeHooks.canHarvestBlock(state, player, world, pos)) {
82+
if (state == null || !BlockHarvestManager.canHarvestBlock(state, player, world, pos)) {
8183
this.exp = 0;
8284
} else {
83-
int bonusLevel = EnchantmentHelper.getLevel(Enchantments.FORTUNE, player.getHeldItemMainhand());
84-
int silklevel = EnchantmentHelper.getLevel(Enchantments.SILK_TOUCH, player.getHeldItemMainhand());
85-
this.exp = state.getExpDrop(world, pos, bonusLevel, silklevel);
86-
}*/
85+
int bonusLevel = EnchantmentHelper.getLevel(Enchantments.FORTUNE, player.getMainHandStack());
86+
int silklevel = EnchantmentHelper.getLevel(Enchantments.SILK_TOUCH, player.getMainHandStack());
87+
this.exp = ((IForgeBlockState) state).getExpDrop(world, pos, bonusLevel, silklevel);
88+
}
8789
}
8890

8991
public PlayerEntity getPlayer() {

patchwork-events-world/src/main/java/net/patchworkmc/impl/event/world/WorldEvents.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,19 @@
2828
import net.minecraftforge.event.world.WorldEvent;
2929

3030
import net.minecraft.block.BlockState;
31+
import net.minecraft.block.entity.BlockEntity;
3132
import net.minecraft.entity.player.PlayerEntity;
3233
import net.minecraft.item.ItemStack;
3334
import net.minecraft.util.DefaultedList;
3435
import net.minecraft.world.World;
3536
import net.minecraft.entity.EntityCategory;
37+
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
38+
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
3639
import net.minecraft.server.network.ServerPlayerEntity;
3740
import net.minecraft.server.world.ServerWorld;
3841
import net.minecraft.util.math.BlockPos;
42+
import net.minecraft.world.EmptyBlockView;
43+
import net.minecraft.world.GameMode;
3944
import net.minecraft.util.math.ChunkPos;
4045
import net.minecraft.world.IWorld;
4146
import net.minecraft.world.biome.Biome;
@@ -72,6 +77,60 @@ public static void onWorldSave(IWorld world) {
7277
MinecraftForge.EVENT_BUS.post(new WorldEvent.Save(world));
7378
}
7479

80+
/**
81+
* Called by Mixin and ForgeHooks.
82+
* @return experience dropped, -1 = block breaking is cancelled.
83+
*/
84+
public static int onBlockBreakEvent(World world, GameMode gameMode, ServerPlayerEntity player, BlockPos pos) {
85+
// Logic from tryHarvestBlock for pre-canceling the event
86+
boolean preCancelEvent = false;
87+
88+
ItemStack itemstack = player.getMainHandStack();
89+
90+
if (!itemstack.isEmpty() && !itemstack.getItem().canMine(world.getBlockState(pos), world, pos, player)) {
91+
preCancelEvent = true;
92+
}
93+
94+
// method_21701 => canMine
95+
// Isn't the function really canNotMine?
96+
97+
if (player.method_21701(world, pos, gameMode)) {
98+
preCancelEvent = true;
99+
}
100+
101+
// Tell client the block is gone immediately then process events
102+
if (world.getBlockEntity(pos) == null) {
103+
player.networkHandler.sendPacket(new BlockUpdateS2CPacket(EmptyBlockView.INSTANCE, pos));
104+
}
105+
106+
// Post the block break event
107+
BlockState state = world.getBlockState(pos);
108+
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(world, pos, state, player);
109+
event.setCanceled(preCancelEvent);
110+
MinecraftForge.EVENT_BUS.post(event);
111+
112+
// Handle if the event is canceled
113+
if (event.isCanceled()) {
114+
// Let the client know the block still exists
115+
player.networkHandler.sendPacket(new BlockUpdateS2CPacket(world, pos));
116+
117+
// Update any block entity data for this block
118+
BlockEntity entity = world.getBlockEntity(pos);
119+
120+
if (entity != null) {
121+
BlockEntityUpdateS2CPacket packet = entity.toUpdatePacket();
122+
123+
if (packet != null) {
124+
player.networkHandler.sendPacket(packet);
125+
}
126+
}
127+
128+
return -1; // Cancelled
129+
} else {
130+
return event.getExpToDrop();
131+
}
132+
}
133+
75134
// TODO: Leaving this unfired is intentional. See: https://github.com/MinecraftForge/MinecraftForge/issues/5828
76135
public static float fireBlockHarvesting(DefaultedList<ItemStack> drops, World world, BlockPos pos, BlockState state, int fortune, float dropChance, boolean silkTouch, PlayerEntity player) {
77136
BlockEvent.HarvestDropsEvent event = new BlockEvent.HarvestDropsEvent(world, pos, state, fortune, dropChance, drops, player, silkTouch);

patchwork-events-world/src/main/java/net/patchworkmc/mixin/event/world/MixinServerPlayerInteractionManager.java

Lines changed: 13 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,23 @@
1919

2020
package net.patchworkmc.mixin.event.world;
2121

22-
import net.minecraftforge.common.MinecraftForge;
23-
import net.minecraftforge.event.world.BlockEvent;
2422
import org.spongepowered.asm.mixin.Mixin;
2523
import org.spongepowered.asm.mixin.Shadow;
2624
import org.spongepowered.asm.mixin.injection.At;
2725
import org.spongepowered.asm.mixin.injection.Inject;
2826
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
2927

30-
import net.minecraft.block.BlockState;
31-
import net.minecraft.block.entity.BlockEntity;
32-
import net.minecraft.item.ItemStack;
33-
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
34-
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
3528
import net.minecraft.server.network.ServerPlayerEntity;
3629
import net.minecraft.server.network.ServerPlayerInteractionManager;
3730
import net.minecraft.server.world.ServerWorld;
3831
import net.minecraft.util.math.BlockPos;
39-
import net.minecraft.world.EmptyBlockView;
4032
import net.minecraft.world.GameMode;
4133

34+
import net.patchworkmc.impl.event.world.WorldEvents;
35+
import net.patchworkmc.impl.extensions.block.BlockHarvestManager;
36+
4237
@Mixin(ServerPlayerInteractionManager.class)
43-
public class MixinServerPlayerInteractionManager {
38+
public abstract class MixinServerPlayerInteractionManager {
4439
@Shadow
4540
public ServerWorld world;
4641
@Shadow
@@ -50,52 +45,17 @@ public class MixinServerPlayerInteractionManager {
5045

5146
@Inject(method = "tryBreakBlock", at = @At("HEAD"), cancellable = true)
5247
private void hookBreakBlock(BlockPos pos, CallbackInfoReturnable<Boolean> callback) {
53-
boolean preCancelEvent = false;
54-
55-
ItemStack itemstack = player.getMainHandStack();
56-
57-
if (!itemstack.isEmpty() && !itemstack.getItem().canMine(world.getBlockState(pos), world, pos, player)) {
58-
preCancelEvent = true;
59-
}
60-
61-
// method_21701 => canMine
62-
// Isn't the function really canNotMine?
63-
64-
if (player.method_21701(world, pos, gameMode)) {
65-
preCancelEvent = true;
66-
}
67-
68-
// Tell client the block is gone immediately then process events
69-
if (world.getBlockEntity(pos) == null) {
70-
player.networkHandler.sendPacket(new BlockUpdateS2CPacket(EmptyBlockView.INSTANCE, pos));
71-
}
72-
73-
// Post the block break event
74-
BlockState state = world.getBlockState(pos);
75-
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(world, pos, state, player);
76-
event.setCanceled(preCancelEvent);
77-
MinecraftForge.EVENT_BUS.post(event);
78-
79-
// Handle if the event is canceled
80-
if (event.isCanceled()) {
81-
// Let the client know the block still exists
82-
player.networkHandler.sendPacket(new BlockUpdateS2CPacket(world, pos));
83-
84-
// Update any block entity data for this block
85-
BlockEntity entity = world.getBlockEntity(pos);
86-
87-
if (entity != null) {
88-
BlockEntityUpdateS2CPacket packet = entity.toUpdatePacket();
89-
90-
if (packet != null) {
91-
player.networkHandler.sendPacket(packet);
92-
}
93-
}
48+
int exp = WorldEvents.onBlockBreakEvent(world, gameMode, player, pos);
9449

50+
if (exp < 0) {
9551
callback.setReturnValue(false);
96-
} else if (event.getExpToDrop() != 0) {
97-
// TODO: Drop experience
98-
throw new UnsupportedOperationException("Cannot drop exp from a BreakEvent yet");
52+
} else {
53+
BlockHarvestManager.pushExpDropStack(exp);
9954
}
10055
}
56+
57+
@Inject(method = "tryBreakBlock", at = @At("RETURN"), cancellable = true)
58+
private void tryBreakBlock_return(BlockPos pos, CallbackInfoReturnable<Boolean> callback) {
59+
BlockHarvestManager.popExpDropStack();
60+
}
10161
}

patchwork-events-world/src/main/resources/fabric.mod.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
"PatchworkMC"
1414
],
1515
"depends": {
16-
"patchwork-api-base": "*"
16+
"patchwork-api-base": "*",
17+
"patchwork-extensions-block": "*"
1718
},
1819
"mixins": [
1920
"patchwork-events-world.mixins.json"

patchwork-extensions-block/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ version = getSubprojectVersion(project, "0.3.0")
44
dependencies {
55
implementation project(path: ':patchwork-api-base', configuration: 'dev')
66
implementation project(path: ':patchwork-enum-hacks', configuration: 'dev')
7+
implementation project(path: ':patchwork-extensions-item', configuration: 'dev')
78
implementation project(path: ':patchwork-tooltype', configuration: 'dev')
89
}
910

patchwork-extensions-block/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import javax.annotation.Nullable;
2828

2929
import net.minecraftforge.common.IPlantable;
30+
import net.minecraftforge.common.ToolType;
3031

3132
import net.minecraft.block.BedBlock;
3233
import net.minecraft.block.Block;
@@ -82,10 +83,12 @@
8283
import net.fabricmc.api.EnvType;
8384
import net.fabricmc.api.Environment;
8485

86+
import net.patchworkmc.impl.extensions.block.BlockHarvestManager;
87+
import net.patchworkmc.impl.extensions.block.PatchworkBlock;
8588
import net.patchworkmc.mixin.extensions.block.FireBlockAccessor;
8689
import net.patchworkmc.mixin.extensions.block.PlantBlockAccessor;
8790

88-
public interface IForgeBlock {
91+
public interface IForgeBlock extends PatchworkBlock {
8992
default Block getBlock() {
9093
return (Block) this;
9194
}
@@ -204,18 +207,18 @@ default BlockEntity createTileEntity(BlockState state, BlockView world) {
204207
return null;
205208
}
206209

207-
/* TODO IForgeBlock#canHarvestBlock indirectly requires ToolType (via ForgeHooks#canHarvestBlock)
210+
/* TODO IForgeBlock#canHarvestBlock indirectly requires ToolType (via ForgeHooks#canHarvestBlock) */
208211
/**
209212
* Determines if the player can harvest this block, obtaining it's drops when the block is destroyed.
210213
*
211214
* @param world The current world
212215
* @param pos The block's current position
213216
* @param player The player damaging the block
214217
* @return True to spawn the drops
215-
*
218+
*/
216219
default boolean canHarvestBlock(BlockState state, BlockView world, BlockPos pos, PlayerEntity player) {
217-
return ForgeHooks.canHarvestBlock(state, player, world, pos);
218-
}*/
220+
return BlockHarvestManager.canHarvestBlock(state, player, world, pos);
221+
}
219222

220223
// TODO Call locations: Patches: ServerPlayerInteractionManager*
221224
/**
@@ -240,7 +243,7 @@ default boolean canHarvestBlock(BlockState state, BlockView world, BlockPos pos,
240243
*/
241244
default boolean removedByPlayer(BlockState state, World world, BlockPos pos, PlayerEntity player, boolean willHarvest, FluidState fluid) {
242245
getBlock().onBreak(world, pos, state, player);
243-
return world.removeBlock(pos, false);
246+
return world.setBlockState(pos, fluid.getBlockState(), world.isClient ? 11 : 3);
244247
}
245248

246249
// TODO Call locations: Patches: LivingEntity*, PlayerEntity*, Forge classes: ForgeEventFactory (called from LivingEntity patch)
@@ -645,6 +648,7 @@ default boolean isBeaconBase(BlockState state, CollisionView world, BlockPos pos
645648
// TODO Call locations: Forge classes: BreakEvent*
646649
/**
647650
* Gathers how much experience this block drops when broken.
651+
* TODO: there's no equivalent callback in Fabric API, so for now Fabric mods should always return 0 here.
648652
*
649653
* @param state The current state
650654
* @param world The world
@@ -778,12 +782,12 @@ default boolean getWeakChanges(BlockState state, CollisionView world, BlockPos p
778782
return false;
779783
}
780784

781-
/* TODO IForgeBlock#getHarvestTool needs ToolType
785+
/* TODO IForgeBlock#getHarvestTool needs ToolType */
782786
/**
783787
* Queries the class of tool required to harvest this block, if null is returned
784788
* we assume that anything can harvest this block.
785-
*
786-
ToolType getHarvestTool(BlockState state);*/
789+
*/
790+
ToolType getHarvestTool(BlockState state);
787791

788792
// TODO Call locations: Patches: PickaxeItem*, Forge classes: ForgeHooks*
789793
/**
@@ -793,18 +797,18 @@ default boolean getWeakChanges(BlockState state, CollisionView world, BlockPos p
793797
*/
794798
int getHarvestLevel(BlockState state);
795799

796-
/* TODO IForgeBlock#isToolEffective needs ToolType
800+
/* TODO IForgeBlock#isToolEffective needs ToolType */
797801
/**
798802
* Checks if the specified tool type is efficient on this block,
799803
* meaning that it digs at full speed.
800-
*
804+
*/
801805
default boolean isToolEffective(BlockState state, ToolType tool) {
802806
if (tool == ToolType.PICKAXE && (this.getBlock() == Blocks.REDSTONE_ORE || this.getBlock() == Blocks.REDSTONE_LAMP || this.getBlock() == Blocks.OBSIDIAN)) {
803807
return false;
804808
}
805809

806810
return tool == getHarvestTool(state);
807-
}*/
811+
}
808812

809813
// TODO Call locations: Forge classes: ForgeHooksClient
810814
/**

0 commit comments

Comments
 (0)