mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 07:27:15 +01:00
- 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:
parent
c46e286844
commit
f19c6ab763
5 changed files with 96 additions and 89 deletions
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
PlayerEntity player) {
|
||||
if (!(state.isIn(BlockTags.LOGS) || AllTags.AllBlockTags.SLIMY_LOGS.matches(state)) || player.isSneaking() || !(iWorld instanceof World))
|
||||
public static void destroyTree(IWorld iWorld, BlockState state, BlockPos pos,
|
||||
PlayerEntity player) {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,51 +1,41 @@
|
|||
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
|
||||
*
|
||||
*
|
||||
* @param reader
|
||||
* @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,9 +102,8 @@ public class TreeCutter {
|
|||
frontier.addAll(logs);
|
||||
while (!frontier.isEmpty()) {
|
||||
BlockPos currentPos = frontier.remove(0);
|
||||
if (!logs.contains(currentPos))
|
||||
if (visited.contains(currentPos))
|
||||
continue;
|
||||
if (!logs.contains(currentPos) && visited.contains(currentPos))
|
||||
continue;
|
||||
visited.add(currentPos);
|
||||
|
||||
BlockState blockState = reader.getBlockState(currentPos);
|
||||
|
@ -158,15 +147,13 @@ public class TreeCutter {
|
|||
return true;
|
||||
if (block instanceof KelpBlock)
|
||||
return true;
|
||||
if (block instanceof KelpTopBlock)
|
||||
return true;
|
||||
return false;
|
||||
return block instanceof KelpTopBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a tree was fully cut by seeing whether the layer above the cut
|
||||
* is not supported by any more logs.
|
||||
*
|
||||
*
|
||||
* @param reader
|
||||
* @param pos
|
||||
* @return
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue