From 7ae89ef4e31bd1a1138cab401597fc2efa9ad758 Mon Sep 17 00:00:00 2001 From: grimmauld Date: Thu, 20 May 2021 08:31:35 +0200 Subject: [PATCH 1/4] Dynamic trees compat (WIP) --- build.gradle | 2 + .../java/com/simibubi/create/compat/Mods.java | 34 +++++++++++++++ .../compat/dynamictrees/DynamicTree.java | 42 +++++++++++++++++++ .../BlockBreakingMovementBehaviour.java | 11 +++-- .../actors/SawMovementBehaviour.java | 15 +++++++ .../components/saw/SawTileEntity.java | 10 ++++- .../create/foundation/utility/TreeCutter.java | 39 ++++++++++++----- 7 files changed, 139 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/simibubi/create/compat/Mods.java create mode 100644 src/main/java/com/simibubi/create/compat/dynamictrees/DynamicTree.java diff --git a/build.gradle b/build.gradle index c1cdabd3f..fafdf0df7 100644 --- a/build.gradle +++ b/build.gradle @@ -126,6 +126,8 @@ dependencies { runtimeOnly fg.deobf("mezz.jei:jei-1.16.4:${jei_version}") // implementation fg.deobf("curse.maven:druidcraft-340991:3101903") + implementation fg.deobf("curse.maven:dynamictrees-252818:3302576") + // i'll leave this here commented for easier testing //runtimeOnly fg.deobf("vazkii.arl:AutoRegLib:1.4-35.69") diff --git a/src/main/java/com/simibubi/create/compat/Mods.java b/src/main/java/com/simibubi/create/compat/Mods.java new file mode 100644 index 000000000..0fb250033 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/Mods.java @@ -0,0 +1,34 @@ +package com.simibubi.create.compat; + +import net.minecraftforge.fml.ModList; + +import java.util.Optional; +import java.util.function.Supplier; + +/** + * For compatibility with and without another mod present, we have to define load conditions of the specific code + */ +public enum Mods { + DYNAMICTREES; + + /** + * @return a boolean of whether the mod is loaded or not + */ + public boolean isLoaded() { + return ModList.get().isLoaded(asId()); + } + + public String asId() { + return name().toLowerCase(); + } + + /** + * Simple hook to run code if a mod is installed + * @param toRun will be run if the mod is loaded + */ + public Optional runIfInstalled(Supplier> toRun) { + if (isLoaded()) + return Optional.of(toRun.get().get()); + return Optional.empty(); + } +} diff --git a/src/main/java/com/simibubi/create/compat/dynamictrees/DynamicTree.java b/src/main/java/com/simibubi/create/compat/dynamictrees/DynamicTree.java new file mode 100644 index 000000000..e115b6879 --- /dev/null +++ b/src/main/java/com/simibubi/create/compat/dynamictrees/DynamicTree.java @@ -0,0 +1,42 @@ +package com.simibubi.create.compat.dynamictrees; + +import java.util.function.BiConsumer; + +import javax.annotation.Nullable; + +import com.ferreusveritas.dynamictrees.api.TreeHelper; +import com.ferreusveritas.dynamictrees.blocks.branches.BranchBlock; +import com.ferreusveritas.dynamictrees.util.BranchDestructionData; +import com.simibubi.create.foundation.utility.AbstractBlockBreakQueue; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class DynamicTree extends AbstractBlockBreakQueue { + private final BlockPos startCutPos; + + public DynamicTree(BlockPos startCutPos) { + this.startCutPos = startCutPos; + } + + @Override + public void destroyBlocks(World world, ItemStack toDamage, @Nullable PlayerEntity playerEntity, BiConsumer drop) { + BranchBlock start = TreeHelper.getBranch(world.getBlockState(startCutPos)); + if (start == null) + return; + + BranchDestructionData data = start.destroyBranchFromNode(world, startCutPos, Direction.DOWN, false, playerEntity); + + // Feed all the tree drops to drop bi-consumer + data.leavesDrops.forEach(stackPos -> drop.accept(stackPos.pos.add(startCutPos), stackPos.stack)); + start.getLogDrops(world, startCutPos, data.species, data.woodVolume).forEach(stack -> drop.accept(startCutPos, stack)); + } + + public static boolean isDynamicBranch(Block block) { + return TreeHelper.isBranch(block); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingMovementBehaviour.java index 14c090563..419a5a577 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingMovementBehaviour.java @@ -166,10 +166,10 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { float breakSpeed = MathHelper.clamp(Math.abs(context.getAnimationSpeed()) / 500f, 1 / 128f, 16f); destroyProgress += MathHelper.clamp((int) (breakSpeed / blockHardness), 1, 10 - destroyProgress); world.playSound(null, breakingPos, stateToBreak.getSoundType().getHitSound(), SoundCategory.NEUTRAL, .25f, 1); - + if (destroyProgress >= 10) { world.sendBlockBreakProgress(id, breakingPos, -1); - + // break falling blocks from top to bottom BlockPos ogPos = breakingPos; BlockState stateAbove = world.getBlockState(breakingPos.up()); @@ -178,8 +178,9 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { stateAbove = world.getBlockState(breakingPos.up()); } stateToBreak = world.getBlockState(breakingPos); - + context.stall = false; + if (shouldDestroyStartBlock(stateToBreak)) BlockHelper.destroyBlock(context.world, breakingPos, 1f, stack -> this.dropItem(context, stack)); onBlockBroken(context, ogPos, stateToBreak); ticksUntilNextProgress = -1; @@ -195,6 +196,10 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { data.putInt("Progress", destroyProgress); } + protected boolean shouldDestroyStartBlock(BlockState stateToBreak) { + return true; + } + public boolean canBreak(World world, BlockPos breakingPos, BlockState state) { float blockHardness = state.getBlockHardness(world, breakingPos); return BlockBreakingKineticTileEntity.isBreakable(state, blockHardness); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SawMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SawMovementBehaviour.java index e8ec8a692..a24d69459 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SawMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SawMovementBehaviour.java @@ -5,6 +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.AbstractBlockBreakQueue; import com.simibubi.create.foundation.utility.TreeCutter; import com.simibubi.create.foundation.utility.VecHelper; @@ -22,6 +23,8 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.items.ItemHandlerHelper; +import java.util.Optional; + public class SawMovementBehaviour extends BlockBreakingMovementBehaviour { @Override @@ -57,6 +60,13 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour { protected void onBlockBroken(MovementContext context, BlockPos pos, BlockState brokenState) { if (brokenState.isIn(BlockTags.LEAVES)) return; + + Optional dynamicTree = TreeCutter.findDynamicTree(brokenState.getBlock(), pos); + if (dynamicTree.isPresent()) { + dynamicTree.get().destroyBlocks(context.world, null, (stack, dropPos) -> dropItemFromCutTree(context, stack, dropPos)); + return; + } + TreeCutter.findTree(context.world, pos).destroyBlocks(context.world, null, (stack, dropPos) -> dropItemFromCutTree(context, stack, dropPos)); } @@ -80,6 +90,11 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour { SawRenderer.renderInContraption(context, ms, msLocal, buffer); } + @Override + protected boolean shouldDestroyStartBlock(BlockState stateToBreak) { + return !TreeCutter.canDynamicTreeCutFrom(stateToBreak.getBlock()); + } + @Override protected DamageSource getDamageSource() { return SawBlock.damageSourceSaw; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java index f7eca3cc1..1af805fd6 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.contraptions.components.saw; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.Optional; import java.util.Random; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -18,6 +19,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.AbstractBlockBreakQueue; import com.simibubi.create.foundation.utility.TreeCutter; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.recipe.RecipeConditions; @@ -280,7 +282,7 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity { * RecipeConditions.isOfType(IRecipeType.STONECUTTING, * AllRecipeTypes.CUTTING.getType()) : * RecipeConditions.isOfType(AllRecipeTypes.CUTTING.getType()); - * + * */ Predicate> types = RecipeConditions.isOfType(AllRecipeTypes.CUTTING.getType(), @@ -366,6 +368,12 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity { @Override public void onBlockBroken(BlockState stateToBreak) { + Optional dynamicTree = TreeCutter.findDynamicTree(stateToBreak.getBlock(), breakingPos); + if (dynamicTree.isPresent()) { + dynamicTree.get().destroyBlocks(world, null, this::dropItemFromCutTree); + return; + } + super.onBlockBroken(stateToBreak); TreeCutter.findTree(world, breakingPos).destroyBlocks(world, null, this::dropItemFromCutTree); } diff --git a/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java b/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java index d1191082d..e92c788c3 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java +++ b/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java @@ -5,6 +5,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Predicate; @@ -14,6 +15,10 @@ import javax.annotation.Nullable; import com.simibubi.create.AllTags; +import com.simibubi.create.compat.Mods; + +import com.simibubi.create.compat.dynamictrees.DynamicTree; + import net.minecraft.block.BambooBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -36,30 +41,44 @@ import net.minecraft.world.World; public class TreeCutter { public static final Tree NO_TREE = new Tree(Collections.emptyList(), Collections.emptyList()); + public static boolean canDynamicTreeCutFrom(Block startBlock) { + return Mods.DYNAMICTREES.runIfInstalled(() -> () -> DynamicTree.isDynamicBranch(startBlock)).orElse(false); + } + + @Nonnull + public static Optional findDynamicTree(Block startBlock, BlockPos pos) { + if (canDynamicTreeCutFrom(startBlock)) { + return Mods.DYNAMICTREES.runIfInstalled(() -> () -> new DynamicTree(pos)); + } + return Optional.empty(); + } + /** * Finds a tree at the given pos. Block at the position should be air * - * @param reader + * @param world * @param pos * @return null if not found or not fully cut */ @Nonnull - public static Tree findTree(@Nullable IBlockReader reader, BlockPos pos) { - if (reader == null) + public static AbstractBlockBreakQueue findTree(@Nullable IBlockReader world, BlockPos pos) { + if (world == null) return NO_TREE; List logs = new ArrayList<>(); + logs.add(pos); + List leaves = new ArrayList<>(); Set visited = new HashSet<>(); List frontier = new LinkedList<>(); // Bamboo, Sugar Cane, Cactus - BlockState stateAbove = reader.getBlockState(pos.up()); + BlockState stateAbove = world.getBlockState(pos.up()); if (isVerticalPlant(stateAbove)) { logs.add(pos.up()); for (int i = 1; i < 256; i++) { BlockPos current = pos.up(i); - if (!isVerticalPlant(reader.getBlockState(current))) + if (!isVerticalPlant(world.getBlockState(current))) break; logs.add(current); } @@ -78,7 +97,7 @@ public class TreeCutter { BlockPos offset = current.offset(direction); if (visited.contains(offset)) continue; - if (!isChorus(reader.getBlockState(offset))) + if (!isChorus(world.getBlockState(offset))) continue; frontier.add(offset); } @@ -88,7 +107,7 @@ public class TreeCutter { } // Regular Tree - if (!validateCut(reader, pos)) + if (!validateCut(world, pos)) return NO_TREE; visited.add(pos); @@ -102,7 +121,7 @@ public class TreeCutter { continue; visited.add(currentPos); - if (!isLog(reader.getBlockState(currentPos))) + if (!isLog(world.getBlockState(currentPos))) continue; logs.add(currentPos); addNeighbours(currentPos, frontier, visited); @@ -118,7 +137,7 @@ public class TreeCutter { continue; visited.add(currentPos); - BlockState blockState = reader.getBlockState(currentPos); + BlockState blockState = world.getBlockState(currentPos); boolean isLog = isLog(blockState); boolean isLeaf = isLeaf(blockState); boolean isGenericLeaf = isLeaf || isNonDecayingLeaf(blockState); @@ -133,7 +152,7 @@ public class TreeCutter { BlockPos offset = currentPos.offset(direction); if (visited.contains(offset)) continue; - BlockState state = reader.getBlockState(offset); + BlockState state = world.getBlockState(offset); BlockPos subtract = offset.subtract(pos); int horizontalDistance = Math.max(Math.abs(subtract.getX()), Math.abs(subtract.getZ())); if (isLeaf(state) && state.get(LeavesBlock.DISTANCE) > distance From ad37c5d949f6051b86d34fa57dd26dc788e7b31a Mon Sep 17 00:00:00 2001 From: grimmauld Date: Thu, 20 May 2021 08:39:22 +0200 Subject: [PATCH 2/4] fix javadoc --- src/main/java/com/simibubi/create/compat/Mods.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/simibubi/create/compat/Mods.java b/src/main/java/com/simibubi/create/compat/Mods.java index 0fb250033..cf9ec4e2a 100644 --- a/src/main/java/com/simibubi/create/compat/Mods.java +++ b/src/main/java/com/simibubi/create/compat/Mods.java @@ -12,19 +12,23 @@ public enum Mods { DYNAMICTREES; /** - * @return a boolean of whether the mod is loaded or not + * @return a boolean of whether the mod is loaded or not based on mod id */ public boolean isLoaded() { return ModList.get().isLoaded(asId()); } + /** + * @return the mod id + */ public String asId() { return name().toLowerCase(); } /** * Simple hook to run code if a mod is installed - * @param toRun will be run if the mod is loaded + * @param toRun will be run only if the mod is loaded + * @return Optional.empty() if the mod is not loaded, otherwise an Optional of the return value of the given supplier */ public Optional runIfInstalled(Supplier> toRun) { if (isLoaded()) From 918c8082b1a279c1caafb6cd9c5541d9ef6bcc3c Mon Sep 17 00:00:00 2001 From: grimmauld Date: Thu, 20 May 2021 08:42:29 +0200 Subject: [PATCH 3/4] clear unnecessary diffs --- .../create/foundation/utility/TreeCutter.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java b/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java index e92c788c3..598ec71cd 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java +++ b/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java @@ -56,29 +56,27 @@ public class TreeCutter { /** * Finds a tree at the given pos. Block at the position should be air * - * @param world + * @param reader * @param pos * @return null if not found or not fully cut */ @Nonnull - public static AbstractBlockBreakQueue findTree(@Nullable IBlockReader world, BlockPos pos) { - if (world == null) + public static Tree findTree(@Nullable IBlockReader reader, BlockPos pos) { + if (reader == null) return NO_TREE; List logs = new ArrayList<>(); - logs.add(pos); - List leaves = new ArrayList<>(); Set visited = new HashSet<>(); List frontier = new LinkedList<>(); // Bamboo, Sugar Cane, Cactus - BlockState stateAbove = world.getBlockState(pos.up()); + BlockState stateAbove = reader.getBlockState(pos.up()); if (isVerticalPlant(stateAbove)) { logs.add(pos.up()); for (int i = 1; i < 256; i++) { BlockPos current = pos.up(i); - if (!isVerticalPlant(world.getBlockState(current))) + if (!isVerticalPlant(reader.getBlockState(current))) break; logs.add(current); } @@ -97,7 +95,7 @@ public class TreeCutter { BlockPos offset = current.offset(direction); if (visited.contains(offset)) continue; - if (!isChorus(world.getBlockState(offset))) + if (!isChorus(reader.getBlockState(offset))) continue; frontier.add(offset); } @@ -107,7 +105,7 @@ public class TreeCutter { } // Regular Tree - if (!validateCut(world, pos)) + if (!validateCut(reader, pos)) return NO_TREE; visited.add(pos); @@ -121,7 +119,7 @@ public class TreeCutter { continue; visited.add(currentPos); - if (!isLog(world.getBlockState(currentPos))) + if (!isLog(reader.getBlockState(currentPos))) continue; logs.add(currentPos); addNeighbours(currentPos, frontier, visited); @@ -137,7 +135,7 @@ public class TreeCutter { continue; visited.add(currentPos); - BlockState blockState = world.getBlockState(currentPos); + BlockState blockState = reader.getBlockState(currentPos); boolean isLog = isLog(blockState); boolean isLeaf = isLeaf(blockState); boolean isGenericLeaf = isLeaf || isNonDecayingLeaf(blockState); @@ -152,7 +150,7 @@ public class TreeCutter { BlockPos offset = currentPos.offset(direction); if (visited.contains(offset)) continue; - BlockState state = world.getBlockState(offset); + BlockState state = reader.getBlockState(offset); BlockPos subtract = offset.subtract(pos); int horizontalDistance = Math.max(Math.abs(subtract.getX()), Math.abs(subtract.getZ())); if (isLeaf(state) && state.get(LeavesBlock.DISTANCE) > distance From 9763631984aca214c641584397e0ebe8928bfe85 Mon Sep 17 00:00:00 2001 From: grimmauld Date: Sat, 26 Jun 2021 19:13:44 +0200 Subject: [PATCH 4/4] Fix up the dynamic trees --- build.gradle | 6 ++++- .../compat/dynamictrees/DynamicTree.java | 27 ++++++++++++++++--- .../components/saw/SawTileEntity.java | 2 ++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index fafdf0df7..ff291cd2a 100644 --- a/build.gradle +++ b/build.gradle @@ -107,6 +107,10 @@ repositories { maven { url = "https://www.cursemaven.com" } + maven { + //location of the maven for dynamic trees + url "http://harleyoconnor.com/maven" + } } configurations { @@ -126,7 +130,7 @@ dependencies { runtimeOnly fg.deobf("mezz.jei:jei-1.16.4:${jei_version}") // implementation fg.deobf("curse.maven:druidcraft-340991:3101903") - implementation fg.deobf("curse.maven:dynamictrees-252818:3302576") + implementation fg.deobf("com.ferreusveritas.dynamictrees:DynamicTrees-1.16.5:0.10.0-Beta12.1") // i'll leave this here commented for easier testing diff --git a/src/main/java/com/simibubi/create/compat/dynamictrees/DynamicTree.java b/src/main/java/com/simibubi/create/compat/dynamictrees/DynamicTree.java index e115b6879..fa6463858 100644 --- a/src/main/java/com/simibubi/create/compat/dynamictrees/DynamicTree.java +++ b/src/main/java/com/simibubi/create/compat/dynamictrees/DynamicTree.java @@ -6,10 +6,12 @@ import javax.annotation.Nullable; import com.ferreusveritas.dynamictrees.api.TreeHelper; import com.ferreusveritas.dynamictrees.blocks.branches.BranchBlock; +import com.ferreusveritas.dynamictrees.blocks.branches.TrunkShellBlock; import com.ferreusveritas.dynamictrees.util.BranchDestructionData; import com.simibubi.create.foundation.utility.AbstractBlockBreakQueue; import net.minecraft.block.Block; +import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; @@ -17,7 +19,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public class DynamicTree extends AbstractBlockBreakQueue { - private final BlockPos startCutPos; + private BlockPos startCutPos; public DynamicTree(BlockPos startCutPos) { this.startCutPos = startCutPos; @@ -26,9 +28,16 @@ public class DynamicTree extends AbstractBlockBreakQueue { @Override public void destroyBlocks(World world, ItemStack toDamage, @Nullable PlayerEntity playerEntity, BiConsumer drop) { BranchBlock start = TreeHelper.getBranch(world.getBlockState(startCutPos)); - if (start == null) + if (start == null) //if start is null, it was not a branch + start = setBranchToShellMuse(world, world.getBlockState(startCutPos)); //we check for a trunk shell instead + + if (start == null) //if it is null again, it was neither a branch nor a trunk shell and thus we return return; + // Play and render block break sound and particles + world.playEvent(null, 2001, startCutPos, Block.getStateId(world.getBlockState(startCutPos))); + // Actually breaks the tree + BranchDestructionData data = start.destroyBranchFromNode(world, startCutPos, Direction.DOWN, false, playerEntity); // Feed all the tree drops to drop bi-consumer @@ -36,7 +45,19 @@ public class DynamicTree extends AbstractBlockBreakQueue { start.getLogDrops(world, startCutPos, data.species, data.woodVolume).forEach(stack -> drop.accept(startCutPos, stack)); } + private BranchBlock setBranchToShellMuse(World world, BlockState state){ + Block block = state.getBlock(); + if (block instanceof TrunkShellBlock){ + TrunkShellBlock.ShellMuse muse = ((TrunkShellBlock)block).getMuse(world, startCutPos); + if (muse != null){ + startCutPos = muse.pos; //the cut pos is moved to the center of the trunk + return TreeHelper.getBranch(muse.state); + } + } + return null; + } + public static boolean isDynamicBranch(Block block) { - return TreeHelper.isBranch(block); + return TreeHelper.isBranch(block) || block instanceof TrunkShellBlock; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java index 1af805fd6..2e4edd2a1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java @@ -410,6 +410,8 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity { return true; if (block instanceof ChorusPlantBlock) return true; + if (TreeCutter.canDynamicTreeCutFrom(block)) + return true; return false; }