Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
1 change: 1 addition & 0 deletions patchwork-events-world/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ version = getSubprojectVersion(project, "0.3.0")

dependencies {
implementation project(path: ':patchwork-api-base', configuration: 'dev')
implementation project(path: ':patchwork-extensions-block', configuration: 'dev')
implementation project(path: ':patchwork-fml', configuration: 'dev')
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,21 @@

import java.util.List;

import net.minecraftforge.common.extensions.IForgeBlockState;
import net.minecraftforge.eventbus.api.Event;

import net.minecraft.item.ItemStack;
import net.minecraft.util.DefaultedList;
import net.minecraft.block.BlockState;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;

import net.patchworkmc.impl.extensions.block.BlockHarvestManager;

public class BlockEvent extends Event {
private final IWorld world;
private final BlockPos pos;
Expand Down Expand Up @@ -73,17 +78,14 @@ public BreakEvent(World world, BlockPos pos, BlockState state, PlayerEntity play
this.player = player;
this.exp = 0;

// TODO: BlockState#getExpDrop

/*
// Handle empty block or player unable to break block scenario
if (state == null || !ForgeHooks.canHarvestBlock(state, player, world, pos)) {
if (state == null || !BlockHarvestManager.canHarvestBlock(state, player, world, pos)) {
this.exp = 0;
} else {
int bonusLevel = EnchantmentHelper.getLevel(Enchantments.FORTUNE, player.getHeldItemMainhand());
int silklevel = EnchantmentHelper.getLevel(Enchantments.SILK_TOUCH, player.getHeldItemMainhand());
this.exp = state.getExpDrop(world, pos, bonusLevel, silklevel);
}*/
int bonusLevel = EnchantmentHelper.getLevel(Enchantments.FORTUNE, player.getMainHandStack());
int silklevel = EnchantmentHelper.getLevel(Enchantments.SILK_TOUCH, player.getMainHandStack());
this.exp = ((IForgeBlockState) state).getExpDrop(world, pos, bonusLevel, silklevel);
}
}

public PlayerEntity getPlayer() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,19 @@
import net.minecraftforge.event.world.WorldEvent;

import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DefaultedList;
import net.minecraft.world.World;
import net.minecraft.entity.EntityCategory;
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.EmptyBlockView;
import net.minecraft.world.GameMode;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.biome.Biome;
Expand Down Expand Up @@ -72,6 +77,60 @@ public static void onWorldSave(IWorld world) {
MinecraftForge.EVENT_BUS.post(new WorldEvent.Save(world));
}

/**
* Called by Mixin and ForgeHooks.
* @return experience dropped, -1 = block breaking is cancelled.
*/
public static int onBlockBreakEvent(World world, GameMode gameMode, ServerPlayerEntity player, BlockPos pos) {
// Logic from tryHarvestBlock for pre-canceling the event
boolean preCancelEvent = false;

ItemStack itemstack = player.getMainHandStack();

if (!itemstack.isEmpty() && !itemstack.getItem().canMine(world.getBlockState(pos), world, pos, player)) {
preCancelEvent = true;
}

// method_21701 => canMine
// Isn't the function really canNotMine?

if (player.method_21701(world, pos, gameMode)) {
preCancelEvent = true;
}

// Tell client the block is gone immediately then process events
if (world.getBlockEntity(pos) == null) {
player.networkHandler.sendPacket(new BlockUpdateS2CPacket(EmptyBlockView.INSTANCE, pos));
}

// Post the block break event
BlockState state = world.getBlockState(pos);
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(world, pos, state, player);
event.setCanceled(preCancelEvent);
MinecraftForge.EVENT_BUS.post(event);

// Handle if the event is canceled
if (event.isCanceled()) {
// Let the client know the block still exists
player.networkHandler.sendPacket(new BlockUpdateS2CPacket(world, pos));

// Update any block entity data for this block
BlockEntity entity = world.getBlockEntity(pos);

if (entity != null) {
BlockEntityUpdateS2CPacket packet = entity.toUpdatePacket();

if (packet != null) {
player.networkHandler.sendPacket(packet);
}
}

return -1; // Cancelled
} else {
return event.getExpToDrop();
}
}

// TODO: Leaving this unfired is intentional. See: https://github.com/MinecraftForge/MinecraftForge/issues/5828
public static float fireBlockHarvesting(DefaultedList<ItemStack> drops, World world, BlockPos pos, BlockState state, int fortune, float dropChance, boolean silkTouch, PlayerEntity player) {
BlockEvent.HarvestDropsEvent event = new BlockEvent.HarvestDropsEvent(world, pos, state, fortune, dropChance, drops, player, silkTouch);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,23 @@

package net.patchworkmc.mixin.event.world;

import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.BlockEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.network.ServerPlayerInteractionManager;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.EmptyBlockView;
import net.minecraft.world.GameMode;

import net.patchworkmc.impl.event.world.WorldEvents;
import net.patchworkmc.impl.extensions.block.BlockHarvestManager;

@Mixin(ServerPlayerInteractionManager.class)
public class MixinServerPlayerInteractionManager {
public abstract class MixinServerPlayerInteractionManager {
@Shadow
public ServerWorld world;
@Shadow
Expand All @@ -50,52 +45,17 @@ public class MixinServerPlayerInteractionManager {

@Inject(method = "tryBreakBlock", at = @At("HEAD"), cancellable = true)
private void hookBreakBlock(BlockPos pos, CallbackInfoReturnable<Boolean> callback) {
boolean preCancelEvent = false;

ItemStack itemstack = player.getMainHandStack();

if (!itemstack.isEmpty() && !itemstack.getItem().canMine(world.getBlockState(pos), world, pos, player)) {
preCancelEvent = true;
}

// method_21701 => canMine
// Isn't the function really canNotMine?

if (player.method_21701(world, pos, gameMode)) {
preCancelEvent = true;
}

// Tell client the block is gone immediately then process events
if (world.getBlockEntity(pos) == null) {
player.networkHandler.sendPacket(new BlockUpdateS2CPacket(EmptyBlockView.INSTANCE, pos));
}

// Post the block break event
BlockState state = world.getBlockState(pos);
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(world, pos, state, player);
event.setCanceled(preCancelEvent);
MinecraftForge.EVENT_BUS.post(event);

// Handle if the event is canceled
if (event.isCanceled()) {
// Let the client know the block still exists
player.networkHandler.sendPacket(new BlockUpdateS2CPacket(world, pos));

// Update any block entity data for this block
BlockEntity entity = world.getBlockEntity(pos);

if (entity != null) {
BlockEntityUpdateS2CPacket packet = entity.toUpdatePacket();

if (packet != null) {
player.networkHandler.sendPacket(packet);
}
}
int exp = WorldEvents.onBlockBreakEvent(world, gameMode, player, pos);

if (exp < 0) {
callback.setReturnValue(false);
} else if (event.getExpToDrop() != 0) {
// TODO: Drop experience
throw new UnsupportedOperationException("Cannot drop exp from a BreakEvent yet");
} else {
BlockHarvestManager.pushExpDropStack(exp);
}
}

@Inject(method = "tryBreakBlock", at = @At("RETURN"), cancellable = true)
private void tryBreakBlock_return(BlockPos pos, CallbackInfoReturnable<Boolean> callback) {
BlockHarvestManager.popExpDropStack();
}
}
1 change: 1 addition & 0 deletions patchwork-extensions-block/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ version = getSubprojectVersion(project, "0.3.0")
dependencies {
implementation project(path: ':patchwork-api-base', configuration: 'dev')
implementation project(path: ':patchwork-enum-hacks', configuration: 'dev')
implementation project(path: ':patchwork-extensions-item', configuration: 'dev')
implementation project(path: ':patchwork-tooltype', configuration: 'dev')
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import javax.annotation.Nullable;

import net.minecraftforge.common.IPlantable;
import net.minecraftforge.common.ToolType;

import net.minecraft.block.BedBlock;
import net.minecraft.block.Block;
Expand Down Expand Up @@ -82,10 +83,12 @@
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;

import net.patchworkmc.impl.extensions.block.BlockHarvestManager;
import net.patchworkmc.impl.extensions.block.PatchworkBlock;
import net.patchworkmc.mixin.extensions.block.FireBlockAccessor;
import net.patchworkmc.mixin.extensions.block.PlantBlockAccessor;

public interface IForgeBlock {
public interface IForgeBlock extends PatchworkBlock {
default Block getBlock() {
return (Block) this;
}
Expand Down Expand Up @@ -204,18 +207,18 @@ default BlockEntity createTileEntity(BlockState state, BlockView world) {
return null;
}

/* TODO IForgeBlock#canHarvestBlock indirectly requires ToolType (via ForgeHooks#canHarvestBlock)
/* TODO IForgeBlock#canHarvestBlock indirectly requires ToolType (via ForgeHooks#canHarvestBlock) */
/**
* Determines if the player can harvest this block, obtaining it's drops when the block is destroyed.
*
* @param world The current world
* @param pos The block's current position
* @param player The player damaging the block
* @return True to spawn the drops
*
*/
default boolean canHarvestBlock(BlockState state, BlockView world, BlockPos pos, PlayerEntity player) {
return ForgeHooks.canHarvestBlock(state, player, world, pos);
}*/
return BlockHarvestManager.canHarvestBlock(state, player, world, pos);
}

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

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

/* TODO IForgeBlock#getHarvestTool needs ToolType
/* TODO IForgeBlock#getHarvestTool needs ToolType */
/**
* Queries the class of tool required to harvest this block, if null is returned
* we assume that anything can harvest this block.
*
ToolType getHarvestTool(BlockState state);*/
*/
ToolType getHarvestTool(BlockState state);

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

/* TODO IForgeBlock#isToolEffective needs ToolType
/* TODO IForgeBlock#isToolEffective needs ToolType */
/**
* Checks if the specified tool type is efficient on this block,
* meaning that it digs at full speed.
*
*/
default boolean isToolEffective(BlockState state, ToolType tool) {
if (tool == ToolType.PICKAXE && (this.getBlock() == Blocks.REDSTONE_ORE || this.getBlock() == Blocks.REDSTONE_LAMP || this.getBlock() == Blocks.OBSIDIAN)) {
return false;
}

return tool == getHarvestTool(state);
}*/
}

// TODO Call locations: Forge classes: ForgeHooksClient
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import javax.annotation.Nullable;

import net.minecraftforge.common.IPlantable;
import net.minecraftforge.common.ToolType;

import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider;
Expand Down Expand Up @@ -149,18 +150,18 @@ default BlockEntity createTileEntity(BlockView world) {
return patchwork$getForgeBlock().createTileEntity(getBlockState(), world);
}

/* TODO IForgeBlockState#canHarvestBlock indirectly requires ToolType
/* TODO IForgeBlockState#canHarvestBlock indirectly requires ToolType */
/**
* Determines if the player can harvest this block, obtaining it's drops when the block is destroyed.
*
* @param world The current world
* @param pos The block's current position
* @param player The player damaging the block
* @return True to spawn the drops
*
*/
default boolean canHarvestBlock(BlockView world, BlockPos pos, PlayerEntity player) {
return patchwork$getForgeBlock().canHarvestBlock(getBlockState(), world, pos, player);
}*/
}

/**
* Called when a player removes a block. This is responsible for
Expand Down Expand Up @@ -582,14 +583,14 @@ default boolean getWeakChanges(CollisionView world, BlockPos pos) {
return patchwork$getForgeBlock().getWeakChanges(getBlockState(), world, pos);
}

/* TODO IForgeBlockState#getHarvestTool needs ToolType
/* TODO IForgeBlockState#getHarvestTool needs ToolType */
/**
* Queries the class of tool required to harvest this block, if null is returned
* we assume that anything can harvest this block.
*
*/
default ToolType getHarvestTool() {
return patchwork$getForgeBlock().getHarvestTool(getBlockState());
}*/
}

default int getHarvestLevel() {
return patchwork$getForgeBlock().getHarvestLevel(getBlockState());
Expand All @@ -605,13 +606,15 @@ default boolean isToolEffective(ToolType tool) {
}*/

/**
* TODO: do not bother implementing hooks, deprecated since 1.13
* Can return IExtendedBlockState.
*/
default BlockState getExtendedState(BlockView world, BlockPos pos) {
return patchwork$getForgeBlock().getExtendedState(getBlockState(), world, pos);
}

/**
* TODO: do not bother implementing hooks, deprecated since 1.15
* Queries if this block should render in a given layer.
* A custom {@link net.minecraft.client.render.model.BakedModel} can use {@link net.minecraftforge.client.MinecraftForgeClient#getRenderLayer()} to alter the model based on layer.
*/
Expand Down
Loading