diff --git a/src/generated/resources/data/create/tags/blocks/tree_attachments.json b/src/generated/resources/data/create/tags/blocks/tree_attachments.json new file mode 100644 index 000000000..dc79f54a0 --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/tree_attachments.json @@ -0,0 +1,10 @@ +{ + "replace": false, + "values": [ + "minecraft:bee_nest", + "minecraft:vine", + "minecraft:moss_carpet", + "minecraft:shroomlight", + "minecraft:cocoa" + ] +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/AllTags.java b/src/main/java/com/simibubi/create/AllTags.java index 5a9633245..0d4e62e15 100644 --- a/src/main/java/com/simibubi/create/AllTags.java +++ b/src/main/java/com/simibubi/create/AllTags.java @@ -123,6 +123,7 @@ public class AllTags { WINDMILL_SAILS, WINDOWABLE, WRENCH_PICKUP, + TREE_ATTACHMENTS, RELOCATION_NOT_SUPPORTED(FORGE), WG_STONE(FORGE), @@ -415,6 +416,9 @@ public class AllTags { Blocks.COMPARATOR, Blocks.OBSERVER, Blocks.REDSTONE_WALL_TORCH, Blocks.PISTON, Blocks.STICKY_PISTON, Blocks.TRIPWIRE, Blocks.TRIPWIRE_HOOK, Blocks.DAYLIGHT_DETECTOR, Blocks.TARGET, Blocks.HOPPER); + AllBlockTags.TREE_ATTACHMENTS.add(Blocks.BEE_NEST, Blocks.VINE, Blocks.MOSS_CARPET, Blocks.SHROOMLIGHT, + Blocks.COCOA); + AllBlockTags.ORE_OVERRIDE_STONE.includeAll(BlockTags.STONE_ORE_REPLACEABLES); registerCompat(); 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 a3702184d..01382d641 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 @@ -478,8 +478,7 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity { public static boolean isSawable(BlockState stateToBreak) { if (stateToBreak.is(BlockTags.SAPLINGS)) return false; - if (stateToBreak.is(BlockTags.LOGS) || AllTags.AllBlockTags.SLIMY_LOGS.matches(stateToBreak) - || (stateToBreak.is(BlockTags.LEAVES))) + if (TreeCutter.isLog(stateToBreak) || (stateToBreak.is(BlockTags.LEAVES))) return true; Block block = stateToBreak.getBlock(); if (block instanceof BambooBlock) 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 af46f9b98..9cfe0d88f 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java +++ b/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java @@ -8,12 +8,14 @@ import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Predicate; import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.simibubi.create.AllTags; +import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.compat.Mods; import com.simibubi.create.compat.dynamictrees.DynamicTree; @@ -42,12 +44,13 @@ 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); + return Mods.DYNAMICTREES.runIfInstalled(() -> () -> DynamicTree.isDynamicBranch(startBlock)) + .orElse(false); } @Nonnull public static Optional findDynamicTree(Block startBlock, BlockPos pos) { - if (canDynamicTreeCutFrom(startBlock)) + if (canDynamicTreeCutFrom(startBlock)) return Mods.DYNAMICTREES.runIfInstalled(() -> () -> new DynamicTree(pos)); return Optional.empty(); } @@ -121,59 +124,63 @@ public class TreeCutter { if (!isLog(reader.getBlockState(currentPos))) continue; logs.add(currentPos); - addNeighbours(currentPos, frontier, visited); + forNeighbours(currentPos, visited, true, p -> frontier.add(new BlockPos(p))); } // Find all leaves visited.clear(); visited.addAll(logs); frontier.addAll(logs); + while (!frontier.isEmpty()) { - BlockPos currentPos = frontier.remove(0); - if (!logs.contains(currentPos) && visited.contains(currentPos)) + BlockPos prevPos = frontier.remove(0); + if (!logs.contains(prevPos) && visited.contains(prevPos)) continue; - visited.add(currentPos); - BlockState blockState = reader.getBlockState(currentPos); - boolean isLog = isLog(blockState); - boolean isLeaf = isLeaf(blockState); - boolean isGenericLeaf = isLeaf || isNonDecayingLeaf(blockState); + visited.add(prevPos); + BlockState prevState = reader.getBlockState(prevPos); + int prevLeafDistance = isLeaf(prevState) ? getLeafDistance(prevState) : 0; - if (!isLog && !isGenericLeaf) - continue; - if (isGenericLeaf) - leaves.add(currentPos); + forNeighbours(prevPos, visited, false, currentPos -> { + BlockState state = reader.getBlockState(currentPos); + BlockPos subtract = currentPos.subtract(pos); + BlockPos currentPosImmutable = currentPos.immutable(); + + if (AllBlockTags.TREE_ATTACHMENTS.matches(state)) { + leaves.add(currentPosImmutable); + visited.add(currentPosImmutable); + return; + } - IntegerProperty distanceProperty = LeavesBlock.DISTANCE; - for (Property property : blockState.getValues() - .keySet()) - if (property instanceof IntegerProperty ip && property.getName() - .equals("distance")) - distanceProperty = ip; - - int distance = !isLeaf ? 0 : blockState.getValue(distanceProperty); - for (Direction direction : Iterate.directions) { - BlockPos offset = currentPos.relative(direction); - if (visited.contains(offset)) - continue; - BlockState state = reader.getBlockState(offset); - BlockPos subtract = offset.subtract(pos); - - for (Property property : state.getValues().keySet()) - if (property instanceof IntegerProperty ip && property.getName().equals("distance")) - distanceProperty = ip; - int horizontalDistance = Math.max(Math.abs(subtract.getX()), Math.abs(subtract.getZ())); - if (isLeaf(state) && state.getValue(distanceProperty) > distance - || isNonDecayingLeaf(state) && horizontalDistance < 4) - frontier.add(offset); - } + if (horizontalDistance <= nonDecayingLeafDistance(state)) { + leaves.add(currentPosImmutable); + frontier.add(currentPosImmutable); + return; + } + if (isLeaf(state) && getLeafDistance(state) > prevLeafDistance) { + leaves.add(currentPosImmutable); + frontier.add(currentPosImmutable); + return; + } + + }); } return new Tree(logs, leaves); } + private static int getLeafDistance(BlockState state) { + IntegerProperty distanceProperty = LeavesBlock.DISTANCE; + for (Property property : state.getValues() + .keySet()) + if (property instanceof IntegerProperty ip && property.getName() + .equals("distance")) + distanceProperty = ip; + return state.getValue(distanceProperty); + } + public static boolean isChorus(BlockState stateAbove) { return stateAbove.getBlock() instanceof ChorusPlantBlock || stateAbove.getBlock() instanceof ChorusFlowerBlock; } @@ -232,23 +239,32 @@ public class TreeCutter { return true; } - private static void addNeighbours(BlockPos pos, List frontier, Set visited) { - BlockPos.betweenClosedStream(pos.offset(-1, -1, -1), pos.offset(1, 1, 1)) + private static void forNeighbours(BlockPos pos, Set visited, boolean up, Consumer acceptor) { + BlockPos.betweenClosedStream(pos.offset(-1, up ? 0 : -1, -1), pos.offset(1, 1, 1)) .filter(((Predicate) visited::contains).negate()) - .forEach(p -> frontier.add(new BlockPos(p))); + .forEach(acceptor); } - private static boolean isLog(BlockState state) { - return state.is(BlockTags.LOGS) || AllTags.AllBlockTags.SLIMY_LOGS.matches(state); + public static boolean isLog(BlockState state) { + return state.is(BlockTags.LOGS) || AllTags.AllBlockTags.SLIMY_LOGS.matches(state) + || state.is(Blocks.MUSHROOM_STEM); } - private static boolean isNonDecayingLeaf(BlockState state) { - return state.is(BlockTags.WART_BLOCKS) || state.getBlock() == Blocks.SHROOMLIGHT; + private static int nonDecayingLeafDistance(BlockState state) { + if (state.is(Blocks.RED_MUSHROOM_BLOCK)) + return 2; + if (state.is(Blocks.BROWN_MUSHROOM_BLOCK)) + return 3; + if (state.is(BlockTags.WART_BLOCKS) || state.is(Blocks.WEEPING_VINES) || state.is(Blocks.WEEPING_VINES_PLANT)) + return 3; + return -1; } private static boolean isLeaf(BlockState state) { - for (Property property : state.getValues().keySet()) - if (property instanceof IntegerProperty && property.getName().equals("distance")) + for (Property property : state.getValues() + .keySet()) + if (property instanceof IntegerProperty && property.getName() + .equals("distance")) return true; return false; } diff --git a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationServerWorld.java b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationServerWorld.java index ad855a7a7..c99761ef5 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationServerWorld.java +++ b/src/main/java/com/simibubi/create/foundation/utility/worldWrappers/PlacementSimulationServerWorld.java @@ -7,6 +7,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.FluidState; public class PlacementSimulationServerWorld extends WrappedServerWorld { public HashMap blocksAdded; @@ -52,5 +53,10 @@ public class PlacementSimulationServerWorld extends WrappedServerWorld { return blocksAdded.get(pos); return Blocks.AIR.defaultBlockState(); } - + + @Override + public FluidState getFluidState(BlockPos pos) { + return getBlockState(pos).getFluidState(); + } + }