Dynamic trees compat (WIP)

This commit is contained in:
grimmauld 2021-05-20 08:31:35 +02:00
parent ca5b9b4fb9
commit 7ae89ef4e3
7 changed files with 139 additions and 14 deletions

View file

@ -126,6 +126,8 @@ dependencies {
runtimeOnly fg.deobf("mezz.jei:jei-1.16.4:${jei_version}") runtimeOnly fg.deobf("mezz.jei:jei-1.16.4:${jei_version}")
// implementation fg.deobf("curse.maven:druidcraft-340991:3101903") // 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 // i'll leave this here commented for easier testing
//runtimeOnly fg.deobf("vazkii.arl:AutoRegLib:1.4-35.69") //runtimeOnly fg.deobf("vazkii.arl:AutoRegLib:1.4-35.69")

View file

@ -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 <T> Optional<T> runIfInstalled(Supplier<Supplier<T>> toRun) {
if (isLoaded())
return Optional.of(toRun.get().get());
return Optional.empty();
}
}

View file

@ -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<BlockPos, ItemStack> 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);
}
}

View file

@ -180,6 +180,7 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour {
stateToBreak = world.getBlockState(breakingPos); stateToBreak = world.getBlockState(breakingPos);
context.stall = false; context.stall = false;
if (shouldDestroyStartBlock(stateToBreak))
BlockHelper.destroyBlock(context.world, breakingPos, 1f, stack -> this.dropItem(context, stack)); BlockHelper.destroyBlock(context.world, breakingPos, 1f, stack -> this.dropItem(context, stack));
onBlockBroken(context, ogPos, stateToBreak); onBlockBroken(context, ogPos, stateToBreak);
ticksUntilNextProgress = -1; ticksUntilNextProgress = -1;
@ -195,6 +196,10 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour {
data.putInt("Progress", destroyProgress); data.putInt("Progress", destroyProgress);
} }
protected boolean shouldDestroyStartBlock(BlockState stateToBreak) {
return true;
}
public boolean canBreak(World world, BlockPos breakingPos, BlockState state) { public boolean canBreak(World world, BlockPos breakingPos, BlockState state) {
float blockHardness = state.getBlockHardness(world, breakingPos); float blockHardness = state.getBlockHardness(world, breakingPos);
return BlockBreakingKineticTileEntity.isBreakable(state, blockHardness); return BlockBreakingKineticTileEntity.isBreakable(state, blockHardness);

View file

@ -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.SawRenderer;
import com.simibubi.create.content.contraptions.components.saw.SawTileEntity; import com.simibubi.create.content.contraptions.components.saw.SawTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; 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.TreeCutter;
import com.simibubi.create.foundation.utility.VecHelper; 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.api.distmarker.OnlyIn;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
import java.util.Optional;
public class SawMovementBehaviour extends BlockBreakingMovementBehaviour { public class SawMovementBehaviour extends BlockBreakingMovementBehaviour {
@Override @Override
@ -57,6 +60,13 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour {
protected void onBlockBroken(MovementContext context, BlockPos pos, BlockState brokenState) { protected void onBlockBroken(MovementContext context, BlockPos pos, BlockState brokenState) {
if (brokenState.isIn(BlockTags.LEAVES)) if (brokenState.isIn(BlockTags.LEAVES))
return; return;
Optional<AbstractBlockBreakQueue> 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)); 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); SawRenderer.renderInContraption(context, ms, msLocal, buffer);
} }
@Override
protected boolean shouldDestroyStartBlock(BlockState stateToBreak) {
return !TreeCutter.canDynamicTreeCutFrom(stateToBreak.getBlock());
}
@Override @Override
protected DamageSource getDamageSource() { protected DamageSource getDamageSource() {
return SawBlock.damageSourceSaw; return SawBlock.damageSourceSaw;

View file

@ -3,6 +3,7 @@ package com.simibubi.create.content.contraptions.components.saw;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.Random; import java.util.Random;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; 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.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; 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.TreeCutter;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.recipe.RecipeConditions; import com.simibubi.create.foundation.utility.recipe.RecipeConditions;
@ -366,6 +368,12 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
@Override @Override
public void onBlockBroken(BlockState stateToBreak) { public void onBlockBroken(BlockState stateToBreak) {
Optional<AbstractBlockBreakQueue> dynamicTree = TreeCutter.findDynamicTree(stateToBreak.getBlock(), breakingPos);
if (dynamicTree.isPresent()) {
dynamicTree.get().destroyBlocks(world, null, this::dropItemFromCutTree);
return;
}
super.onBlockBroken(stateToBreak); super.onBlockBroken(stateToBreak);
TreeCutter.findTree(world, breakingPos).destroyBlocks(world, null, this::dropItemFromCutTree); TreeCutter.findTree(world, breakingPos).destroyBlocks(world, null, this::dropItemFromCutTree);
} }

View file

@ -5,6 +5,7 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -14,6 +15,10 @@ import javax.annotation.Nullable;
import com.simibubi.create.AllTags; 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.BambooBlock;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -36,30 +41,44 @@ import net.minecraft.world.World;
public class TreeCutter { public class TreeCutter {
public static final Tree NO_TREE = new Tree(Collections.emptyList(), Collections.emptyList()); 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<AbstractBlockBreakQueue> 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 * Finds a tree at the given pos. Block at the position should be air
* *
* @param reader * @param world
* @param pos * @param pos
* @return null if not found or not fully cut * @return null if not found or not fully cut
*/ */
@Nonnull @Nonnull
public static Tree findTree(@Nullable IBlockReader reader, BlockPos pos) { public static AbstractBlockBreakQueue findTree(@Nullable IBlockReader world, BlockPos pos) {
if (reader == null) if (world == null)
return NO_TREE; return NO_TREE;
List<BlockPos> logs = new ArrayList<>(); List<BlockPos> logs = new ArrayList<>();
logs.add(pos);
List<BlockPos> leaves = new ArrayList<>(); List<BlockPos> leaves = new ArrayList<>();
Set<BlockPos> visited = new HashSet<>(); Set<BlockPos> visited = new HashSet<>();
List<BlockPos> frontier = new LinkedList<>(); List<BlockPos> frontier = new LinkedList<>();
// Bamboo, Sugar Cane, Cactus // Bamboo, Sugar Cane, Cactus
BlockState stateAbove = reader.getBlockState(pos.up()); BlockState stateAbove = world.getBlockState(pos.up());
if (isVerticalPlant(stateAbove)) { if (isVerticalPlant(stateAbove)) {
logs.add(pos.up()); logs.add(pos.up());
for (int i = 1; i < 256; i++) { for (int i = 1; i < 256; i++) {
BlockPos current = pos.up(i); BlockPos current = pos.up(i);
if (!isVerticalPlant(reader.getBlockState(current))) if (!isVerticalPlant(world.getBlockState(current)))
break; break;
logs.add(current); logs.add(current);
} }
@ -78,7 +97,7 @@ public class TreeCutter {
BlockPos offset = current.offset(direction); BlockPos offset = current.offset(direction);
if (visited.contains(offset)) if (visited.contains(offset))
continue; continue;
if (!isChorus(reader.getBlockState(offset))) if (!isChorus(world.getBlockState(offset)))
continue; continue;
frontier.add(offset); frontier.add(offset);
} }
@ -88,7 +107,7 @@ public class TreeCutter {
} }
// Regular Tree // Regular Tree
if (!validateCut(reader, pos)) if (!validateCut(world, pos))
return NO_TREE; return NO_TREE;
visited.add(pos); visited.add(pos);
@ -102,7 +121,7 @@ public class TreeCutter {
continue; continue;
visited.add(currentPos); visited.add(currentPos);
if (!isLog(reader.getBlockState(currentPos))) if (!isLog(world.getBlockState(currentPos)))
continue; continue;
logs.add(currentPos); logs.add(currentPos);
addNeighbours(currentPos, frontier, visited); addNeighbours(currentPos, frontier, visited);
@ -118,7 +137,7 @@ public class TreeCutter {
continue; continue;
visited.add(currentPos); visited.add(currentPos);
BlockState blockState = reader.getBlockState(currentPos); BlockState blockState = world.getBlockState(currentPos);
boolean isLog = isLog(blockState); boolean isLog = isLog(blockState);
boolean isLeaf = isLeaf(blockState); boolean isLeaf = isLeaf(blockState);
boolean isGenericLeaf = isLeaf || isNonDecayingLeaf(blockState); boolean isGenericLeaf = isLeaf || isNonDecayingLeaf(blockState);
@ -133,7 +152,7 @@ public class TreeCutter {
BlockPos offset = currentPos.offset(direction); BlockPos offset = currentPos.offset(direction);
if (visited.contains(offset)) if (visited.contains(offset))
continue; continue;
BlockState state = reader.getBlockState(offset); BlockState state = world.getBlockState(offset);
BlockPos subtract = offset.subtract(pos); BlockPos subtract = offset.subtract(pos);
int horizontalDistance = Math.max(Math.abs(subtract.getX()), Math.abs(subtract.getZ())); int horizontalDistance = Math.max(Math.abs(subtract.getX()), Math.abs(subtract.getZ()));
if (isLeaf(state) && state.get(LeavesBlock.DISTANCE) > distance if (isLeaf(state) && state.get(LeavesBlock.DISTANCE) > distance