- Deforester now hits forge hooks for tool break, block break, times used.

-Moved deforester not loosing durability from leaves to DeforesterItem instead of Tree mining
- added destroyBlocks method in TreeCutter$Tree for less doubled code
- Mechanical Saws currently break the tree with an empty "hand" as they did before
- Silktouch and Fortune enchants are now being applied from deforesters
This commit is contained in:
grimmauld 2021-04-07 14:07:06 +02:00
parent c46e286844
commit f19c6ab763
5 changed files with 96 additions and 89 deletions

View file

@ -5,9 +5,7 @@ import com.simibubi.create.content.contraptions.components.saw.SawBlock;
import com.simibubi.create.content.contraptions.components.saw.SawRenderer;
import com.simibubi.create.content.contraptions.components.saw.SawTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.TreeCutter;
import com.simibubi.create.foundation.utility.TreeCutter.Tree;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState;
@ -59,14 +57,7 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour {
protected void onBlockBroken(MovementContext context, BlockPos pos, BlockState brokenState) {
if (brokenState.isIn(BlockTags.LEAVES))
return;
Tree tree = TreeCutter.cutTree(context.world, pos);
if (tree != null) {
for (BlockPos log : tree.logs)
BlockHelper.destroyBlock(context.world, log, 1 / 2f, stack -> dropItemFromCutTree(context, log, stack));
for (BlockPos leaf : tree.leaves)
BlockHelper.destroyBlock(context.world, leaf, 1 / 8f,
stack -> dropItemFromCutTree(context, leaf, stack));
}
TreeCutter.findTree(context.world, pos).destroyBlocks(context.world, null, (stack, dropPos) -> dropItemFromCutTree(context, stack, dropPos));
}
public void dropItemFromCutTree(MovementContext context, BlockPos pos, ItemStack stack) {

View file

@ -1,9 +1,6 @@
package com.simibubi.create.content.contraptions.components.saw;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -18,9 +15,7 @@ import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.TreeCutter;
import com.simibubi.create.foundation.utility.TreeCutter.Tree;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.recipe.RecipeConditions;
import com.simibubi.create.foundation.utility.recipe.RecipeFinder;
@ -360,13 +355,7 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
@Override
public void onBlockBroken(BlockState stateToBreak) {
super.onBlockBroken(stateToBreak);
Tree tree = TreeCutter.cutTree(world, breakingPos);
if (tree != null) {
for (BlockPos log : tree.logs)
BlockHelper.destroyBlock(world, log, 1 / 2f, stack -> dropItemFromCutTree(log, stack));
for (BlockPos leaf : tree.leaves)
BlockHelper.destroyBlock(world, leaf, 1 / 8f, stack -> dropItemFromCutTree(leaf, stack));
}
TreeCutter.findTree(world, breakingPos).destroyBlocks(world, null, this::dropItemFromCutTree);
}
public void dropItemFromCutTree(BlockPos pos, ItemStack stack) {

View file

@ -2,18 +2,17 @@ package com.simibubi.create.content.curiosities.tools;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllTags;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.TreeCutter;
import com.simibubi.create.foundation.utility.TreeCutter.Tree;
import com.simibubi.create.foundation.utility.VecHelper;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.block.BlockState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.AxeItem;
import net.minecraft.item.ItemStack;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.IWorld;
@ -23,37 +22,31 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@EventBusSubscriber(bus = Bus.FORGE)
public class DeforesterItem extends AxeItem {
private static boolean deforesting = false; // required as to not run into "recursions" over forge events on tree cutting
public DeforesterItem(Properties builder) {
super(AllToolTiers.RADIANT, 5.0F, -3.1F, builder);
}
// Moved away from Item#onBlockDestroyed as it does not get called in Creative
public static void destroyTree(ItemStack stack, IWorld iWorld, BlockState state, BlockPos pos,
public static void destroyTree(IWorld iWorld, BlockState state, BlockPos pos,
PlayerEntity player) {
if (!(state.isIn(BlockTags.LOGS) || AllTags.AllBlockTags.SLIMY_LOGS.matches(state)) || player.isSneaking() || !(iWorld instanceof World))
if (deforesting ||!(state.isIn(BlockTags.LOGS) || AllTags.AllBlockTags.SLIMY_LOGS.matches(state)) || player.isSneaking() || !(iWorld instanceof World))
return;
World worldIn = (World) iWorld;
Tree tree = TreeCutter.cutTree(worldIn, pos);
if (tree == null)
return;
boolean dropBlock = !player.isCreative();
Vector3d vec = player.getLookVec();
for (BlockPos log : tree.logs)
BlockHelper.destroyBlock(worldIn, log, 1 / 2f, item -> {
if (dropBlock) {
dropItemFromCutTree(worldIn, pos, vec, log, item);
stack.damageItem(1, player, p -> p.sendBreakAnimation(Hand.MAIN_HAND));
}
});
for (BlockPos leaf : tree.leaves)
BlockHelper.destroyBlock(worldIn, leaf, 1 / 8f, item -> {
if (dropBlock)
dropItemFromCutTree(worldIn, pos, vec, leaf, item);
});
deforesting = true;
TreeCutter.findTree(worldIn, pos).destroyBlocks(worldIn, player, (dropPos, item) -> dropItemFromCutTree(worldIn, pos, vec, dropPos, item));
deforesting = false;
}
@SubscribeEvent
@ -61,7 +54,7 @@ public class DeforesterItem extends AxeItem {
ItemStack heldItemMainhand = event.getPlayer().getHeldItemMainhand();
if (!AllItems.DEFORESTER.isIn(heldItemMainhand))
return;
destroyTree(heldItemMainhand, event.getWorld(), event.getState(), event.getPos(), event.getPlayer());
destroyTree(event.getWorld(), event.getState(), event.getPos(), event.getPlayer());
}
public static void dropItemFromCutTree(World world, BlockPos breakingPos, Vector3d fallDirection, BlockPos pos,
@ -73,4 +66,10 @@ public class DeforesterItem extends AxeItem {
world.addEntity(entity);
}
@Override
public boolean onBlockDestroyed(ItemStack stack, World world, BlockState state, BlockPos pos, LivingEntity entity) {
if (!state.isIn(BlockTags.LEAVES))
super.onBlockDestroyed(stack, world, state, pos, entity);
return true;
}
}

View file

@ -4,6 +4,9 @@ import java.util.function.Consumer;
import javax.annotation.Nullable;
import net.minecraft.stats.Stats;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.BlockEvent;
import org.apache.commons.lang3.mutable.MutableInt;
import com.simibubi.create.AllBlocks;
@ -184,16 +187,33 @@ public class BlockHelper {
public static void destroyBlock(World world, BlockPos pos, float effectChance,
Consumer<ItemStack> droppedItemCallback) {
destroyBlockAs(world, pos, null, ItemStack.EMPTY, effectChance, droppedItemCallback);
}
public static void destroyBlockAs(World world, BlockPos pos, @Nullable PlayerEntity player, ItemStack usedTool, float effectChance,
Consumer<ItemStack> droppedItemCallback) {
FluidState fluidState = world.getFluidState(pos);
BlockState state = world.getBlockState(pos);
if (world.rand.nextFloat() < effectChance)
world.playEvent(2001, pos, Block.getStateId(state));
TileEntity tileentity = state.hasTileEntity() ? world.getTileEntity(pos) : null;
if (player != null) {
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(world, pos, state, player);
MinecraftForge.EVENT_BUS.post(event);
if (event.isCanceled())
return;
if (event.getExpToDrop() > 0 && world instanceof ServerWorld)
state.getBlock().dropXpOnBlockBreak((ServerWorld) world, pos, event.getExpToDrop());
usedTool.onBlockDestroyed(world, state, pos, player);
player.addStat(Stats.BLOCK_MINED.get(state.getBlock()));
}
if (world instanceof ServerWorld && world.getGameRules()
.getBoolean(GameRules.DO_TILE_DROPS) && !world.restoringBlockSnapshots) {
for (ItemStack itemStack : Block.getDrops(state, (ServerWorld) world, pos, tileentity))
.getBoolean(GameRules.DO_TILE_DROPS) && !world.restoringBlockSnapshots && (player == null || !player.isCreative())) {
for (ItemStack itemStack : Block.getDrops(state, (ServerWorld) world, pos, tileentity,
player, usedTool))
droppedItemCallback.accept(itemStack);
state.spawnAdditionalDrops((ServerWorld) world, pos, ItemStack.EMPTY);
}

View file

@ -1,42 +1,28 @@
package com.simibubi.create.foundation.utility;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterators;
import com.simibubi.create.AllTags;
import net.minecraft.block.BambooBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.CactusBlock;
import net.minecraft.block.ChorusFlowerBlock;
import net.minecraft.block.ChorusPlantBlock;
import net.minecraft.block.KelpBlock;
import net.minecraft.block.KelpTopBlock;
import net.minecraft.block.LeavesBlock;
import net.minecraft.block.SugarCaneBlock;
import net.minecraft.block.*;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.event.ForgeEventFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
public class TreeCutter {
public static final Tree NO_TREE = new Tree(Collections.emptyList(), Collections.emptyList());
public static class Tree {
public List<BlockPos> logs;
public List<BlockPos> leaves;
public Tree(List<BlockPos> logs, List<BlockPos> leaves) {
this.logs = logs;
this.leaves = leaves;
}
}
/**
* Finds a tree at the given pos. Block at the position should be air
@ -45,7 +31,11 @@ public class TreeCutter {
* @param pos
* @return null if not found or not fully cut
*/
public static Tree cutTree(IBlockReader reader, BlockPos pos) {
@Nonnull
public static Tree findTree(@Nullable IBlockReader reader, BlockPos pos) {
if (reader == null)
return NO_TREE;
List<BlockPos> logs = new ArrayList<>();
List<BlockPos> leaves = new ArrayList<>();
Set<BlockPos> visited = new HashSet<>();
@ -87,7 +77,7 @@ public class TreeCutter {
// Regular Tree
if (!validateCut(reader, pos))
return null;
return NO_TREE;
visited.add(pos);
BlockPos.getAllInBox(pos.add(-1, 0, -1), pos.add(1, 1, 1))
@ -112,8 +102,7 @@ public class TreeCutter {
frontier.addAll(logs);
while (!frontier.isEmpty()) {
BlockPos currentPos = frontier.remove(0);
if (!logs.contains(currentPos))
if (visited.contains(currentPos))
if (!logs.contains(currentPos) && visited.contains(currentPos))
continue;
visited.add(currentPos);
@ -158,9 +147,7 @@ public class TreeCutter {
return true;
if (block instanceof KelpBlock)
return true;
if (block instanceof KelpTopBlock)
return true;
return false;
return block instanceof KelpTopBlock;
}
/**
@ -206,7 +193,7 @@ public class TreeCutter {
private static void addNeighbours(BlockPos pos, List<BlockPos> frontier, Set<BlockPos> visited) {
BlockPos.getAllInBox(pos.add(-1, -1, -1), pos.add(1, 1, 1))
.filter(Predicates.not(visited::contains))
.filter(((Predicate<BlockPos>) visited::contains).negate())
.forEach(p -> frontier.add(new BlockPos(p)));
}
@ -222,4 +209,25 @@ public class TreeCutter {
return state.contains(LeavesBlock.DISTANCE);
}
public static class Tree {
private final List<BlockPos> logs;
private final List<BlockPos> leaves;
public Tree(List<BlockPos> logs, List<BlockPos> leaves) {
this.logs = logs;
this.leaves = leaves;
}
public void destroyBlocks(World world, @Nullable LivingEntity entity, BiConsumer<BlockPos, ItemStack> drop) {
PlayerEntity playerEntity = entity instanceof PlayerEntity ? ((PlayerEntity) entity) : null;
ItemStack toDamage = playerEntity != null && !playerEntity.isCreative() ? playerEntity.getHeldItemMainhand() : ItemStack.EMPTY;
Iterators.concat(logs.iterator(), leaves.iterator()).forEachRemaining(pos -> {
ItemStack usedTool = toDamage.copy();
BlockHelper.destroyBlockAs(world, pos, playerEntity, toDamage, 1 / 2f, stack -> drop.accept(pos, stack));
if (toDamage.isEmpty() && !usedTool.isEmpty())
ForgeEventFactory.onPlayerDestroyItem(playerEntity, usedTool, Hand.MAIN_HAND);
});
}
}
}