mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 07:27:15 +01:00
Dynamic trees compat (WIP)
This commit is contained in:
parent
ca5b9b4fb9
commit
7ae89ef4e3
7 changed files with 139 additions and 14 deletions
|
@ -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")
|
||||
|
|
34
src/main/java/com/simibubi/create/compat/Mods.java
Normal file
34
src/main/java/com/simibubi/create/compat/Mods.java
Normal 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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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<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));
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -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<IRecipe<?>> types = RecipeConditions.isOfType(AllRecipeTypes.CUTTING.getType(),
|
||||
|
@ -366,6 +368,12 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
|
|||
|
||||
@Override
|
||||
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);
|
||||
TreeCutter.findTree(world, breakingPos).destroyBlocks(world, null, this::dropItemFromCutTree);
|
||||
}
|
||||
|
|
|
@ -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<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
|
||||
*
|
||||
* @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<BlockPos> logs = new ArrayList<>();
|
||||
logs.add(pos);
|
||||
|
||||
List<BlockPos> leaves = new ArrayList<>();
|
||||
Set<BlockPos> visited = new HashSet<>();
|
||||
List<BlockPos> 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
|
||||
|
|
Loading…
Reference in a new issue