From 45897e4c1820c7e7eb00ebf8f406c19a4d6db4f5 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 29 Apr 2020 19:12:42 +0200 Subject: [PATCH] Mechanical Ploughs - Added the Mechanical Plough - Mounted Drills now briefly stall a contraption after breaking a block below falling blocks (sand, gravel, etc) - Mechanical Saws can now harvest Bamboo, Chorus, Kelp, Sugar Cane, Cactus, Melons and Pumpkins - Fixed harvester position inconsistency when moved vertically - Fixed saws/drills not hurting entities in some cases - Fixed saws/drill throwing back hurt entities in weird directions --- .../java/com/simibubi/create/AllBlocks.java | 4 +- .../create/foundation/utility/TreeCutter.java | 63 ++++++++++ .../components/actors/AttachedActorBlock.java | 60 ++++++++++ .../BlockBreakingMovementBehaviour.java | 90 ++++++++++---- .../actors/DrillMovementBehaviour.java | 10 +- .../components/actors/HarvesterBlock.java | 59 +-------- .../actors/HarvesterMovementBehaviour.java | 2 +- .../components/actors/PloughBlock.java | 34 ++++++ .../actors/PloughMovementBehaviour.java | 88 ++++++++++++++ .../actors/SawMovementBehaviour.java | 8 +- .../contraptions/BlockMovementTraits.java | 5 +- .../components/saw/SawTileEntity.java | 32 ++++- .../assets/create/blockstates/plough.json | 14 +++ .../resources/assets/create/lang/en_us.json | 12 +- .../assets/create/models/block/plough.json | 113 ++++++++++++++++++ .../assets/create/models/item/plough.json | 3 + .../create/loot_tables/blocks/plough.json | 19 +++ .../crafting_shaped/contraptions/plough.json | 29 +++++ 18 files changed, 550 insertions(+), 95 deletions(-) create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/components/actors/AttachedActorBlock.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughBlock.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughMovementBehaviour.java create mode 100644 src/main/resources/assets/create/blockstates/plough.json create mode 100644 src/main/resources/assets/create/models/block/plough.json create mode 100644 src/main/resources/assets/create/models/item/plough.json create mode 100644 src/main/resources/data/create/loot_tables/blocks/plough.json create mode 100644 src/main/resources/data/create/recipes/crafting_shaped/contraptions/plough.json diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 9cb2e32ff..10cde1866 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -14,6 +14,7 @@ import com.simibubi.create.modules.IModule; import com.simibubi.create.modules.contraptions.CasingBlock; import com.simibubi.create.modules.contraptions.components.actors.DrillBlock; import com.simibubi.create.modules.contraptions.components.actors.HarvesterBlock; +import com.simibubi.create.modules.contraptions.components.actors.PloughBlock; import com.simibubi.create.modules.contraptions.components.actors.PortableStorageInterfaceBlock; import com.simibubi.create.modules.contraptions.components.clock.CuckooClockBlock; import com.simibubi.create.modules.contraptions.components.contraptions.bearing.ClockworkBearingBlock; @@ -162,9 +163,10 @@ public enum AllBlocks { ROTATION_CHASSIS(new RadialChassisBlock()), DRILL(new DrillBlock()), SAW(new SawBlock()), - HARVESTER(new HarvesterBlock()), DEPLOYER(new DeployerBlock()), PORTABLE_STORAGE_INTERFACE(new PortableStorageInterfaceBlock()), + PLOUGH(new PloughBlock()), + HARVESTER(new HarvesterBlock()), ANALOG_LEVER(new AnalogLeverBlock()), ANDESITE_CASING(new CasingBlock("andesite_casing")), 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 7635aa7bc..5849c8625 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java +++ b/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java @@ -1,6 +1,7 @@ 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; @@ -8,8 +9,16 @@ import java.util.Set; import com.google.common.base.Predicates; +import net.minecraft.block.BambooBlock; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; +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.tags.BlockTags; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; @@ -40,6 +49,41 @@ public class TreeCutter { Set visited = new HashSet<>(); List frontier = new LinkedList<>(); + // Bamboo, Sugar Cane, Cactus + 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(reader.getBlockState(current))) + break; + logs.add(current); + } + Collections.reverse(logs); + return new Tree(logs, leaves); + } + + // Chorus + if (isChorus(stateAbove)) { + frontier.add(pos.up()); + while (!frontier.isEmpty()) { + BlockPos current = frontier.remove(0); + visited.add(current); + logs.add(current); + for (Direction direction : Iterate.directions) { + BlockPos offset = current.offset(direction); + if (visited.contains(offset)) + continue; + if (!isChorus(reader.getBlockState(offset))) + continue; + frontier.add(offset); + } + } + Collections.reverse(logs); + return new Tree(logs, leaves); + } + + // Regular Tree if (!validateCut(reader, pos)) return null; @@ -94,6 +138,25 @@ public class TreeCutter { return new Tree(logs, leaves); } + public static boolean isChorus(BlockState stateAbove) { + return stateAbove.getBlock() instanceof ChorusPlantBlock || stateAbove.getBlock() instanceof ChorusFlowerBlock; + } + + public static boolean isVerticalPlant(BlockState stateAbove) { + Block block = stateAbove.getBlock(); + if (block instanceof BambooBlock) + return true; + if (block instanceof CactusBlock) + return true; + if (block instanceof SugarCaneBlock) + return true; + if (block instanceof KelpBlock) + return true; + if (block instanceof KelpTopBlock) + return true; + return false; + } + /** * Checks whether a tree was fully cut by seeing whether the layer above the cut * is not supported by any more logs. diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/AttachedActorBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/AttachedActorBlock.java new file mode 100644 index 000000000..c738f69b1 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/AttachedActorBlock.java @@ -0,0 +1,60 @@ +package com.simibubi.create.modules.contraptions.components.actors; + +import com.simibubi.create.foundation.utility.AllShapes; +import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.HorizontalBlock; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.state.StateContainer.Builder; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.shapes.ISelectionContext; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorldReader; + +public abstract class AttachedActorBlock extends HorizontalBlock implements IPortableBlock { + + public AttachedActorBlock() { + super(Properties.from(Blocks.IRON_BLOCK)); + } + + @Override + public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { + Direction direction = state.get(HORIZONTAL_FACING); + return AllShapes.HARVESTER_BASE.get(direction); + } + + @Override + protected void fillStateContainer(Builder builder) { + builder.add(HORIZONTAL_FACING); + super.fillStateContainer(builder); + } + + @Override + public boolean isValidPosition(BlockState state, IWorldReader worldIn, BlockPos pos) { + Direction direction = state.get(HORIZONTAL_FACING); + BlockPos offset = pos.offset(direction.getOpposite()); + return Block.hasSolidSide(worldIn.getBlockState(offset), worldIn, offset, direction); + } + + @Override + public BlockState getStateForPlacement(BlockItemUseContext context) { + Direction facing; + if (context.getFace().getAxis().isVertical()) + facing = context.getPlacementHorizontalFacing().getOpposite(); + else { + BlockState blockState = + context.getWorld().getBlockState(context.getPos().offset(context.getFace().getOpposite())); + if (blockState.getBlock() instanceof AttachedActorBlock) + facing = blockState.get(HORIZONTAL_FACING); + else + facing = context.getFace(); + } + return getDefaultState().with(HORIZONTAL_FACING, facing); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/BlockBreakingMovementBehaviour.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/BlockBreakingMovementBehaviour.java index c7c2ef8af..438c17094 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/BlockBreakingMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/BlockBreakingMovementBehaviour.java @@ -6,9 +6,11 @@ import com.simibubi.create.modules.contraptions.components.contraptions.Movement import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext; import net.minecraft.block.BlockState; +import net.minecraft.block.FallingBlock; import net.minecraft.entity.Entity; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.NBTUtil; import net.minecraft.util.DamageSource; @@ -32,30 +34,10 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { World world = context.world; BlockState stateVisited = world.getBlockState(pos); + if (!stateVisited.isNormalCube(world, pos)) + damageEntities(context, pos, world); if (world.isRemote) return; - if (stateVisited.getCollisionShape(world, pos).isEmpty()) { - DamageSource damageSource = getDamageSource(); - if (damageSource == null) - return; - for (Entity entity : world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(pos))) { - - if (entity instanceof ItemEntity) - return; - if (entity instanceof ContraptionEntity) - return; - if (entity instanceof AbstractMinecartEntity) - for (Entity passenger : entity.getRecursivePassengers()) - if (passenger instanceof ContraptionEntity - && ((ContraptionEntity) passenger).getContraption() == context.contraption) - return; - - float damage = (float) MathHelper.clamp(Math.abs(context.relativeMotion.length() * 10) + 1, 5, 20); - entity.attackEntityFrom(damageSource, damage); - entity.setMotion(entity.getMotion().add(context.relativeMotion.scale(3))); - } - return; - } if (!canBreak(world, pos, stateVisited)) return; @@ -63,10 +45,39 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { context.stall = true; } + public void damageEntities(MovementContext context, BlockPos pos, World world) { + DamageSource damageSource = getDamageSource(); + if (damageSource == null && !throwsEntities()) + return; + Entities: for (Entity entity : world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(pos))) { + if (entity instanceof ItemEntity) + continue; + if (entity instanceof ContraptionEntity) + continue; + if (entity instanceof AbstractMinecartEntity) + for (Entity passenger : entity.getRecursivePassengers()) + if (passenger instanceof ContraptionEntity + && ((ContraptionEntity) passenger).getContraption() == context.contraption) + continue Entities; + + float damage = (float) MathHelper.clamp(Math.abs(context.relativeMotion.length() * 10) + 1, 5, 20); + if (damageSource != null && !world.isRemote) + entity.attackEntityFrom(damageSource, damage); + if (throwsEntities() && (world.isRemote == (entity instanceof PlayerEntity))) { + entity.setMotion(entity.getMotion().add(context.motion.add(0, context.motion.length() / 4f, 0))); + entity.velocityChanged = true; + } + } + } + protected DamageSource getDamageSource() { return null; } + protected boolean throwsEntities() { + return getDamageSource() != null; + } + @Override public void stopMoving(MovementContext context) { CompoundNBT data = context.data; @@ -89,6 +100,27 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { @Override public void tick(MovementContext context) { + tickBreaker(context); + + CompoundNBT data = context.data; + if (!data.contains("WaitingTicks")) + return; + + int waitingTicks = data.getInt("WaitingTicks"); + if (waitingTicks-- > 0) { + data.putInt("WaitingTicks", waitingTicks); + context.stall = true; + return; + } + + BlockPos pos = NBTUtil.readBlockPos(data.getCompound("LastPos")); + data.remove("WaitingTicks"); + data.remove("LastPos"); + context.stall = false; + visitNewPosition(context, pos); + } + + public void tickBreaker(MovementContext context) { CompoundNBT data = context.data; if (context.world.isRemote) return; @@ -129,13 +161,13 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { if (destroyProgress >= 10) { BlockHelper.destroyBlock(context.world, breakingPos, 1f, stack -> this.dropItem(context, stack)); - onBlockBroken(context, breakingPos); + context.stall = false; + onBlockBroken(context, breakingPos, stateToBreak); ticksUntilNextProgress = -1; world.sendBlockBreakProgress(id, breakingPos, -1); data.remove("Progress"); data.remove("TicksUntilNextProgress"); data.remove("BreakingPos"); - context.stall = false; return; } @@ -150,7 +182,15 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { return BlockBreakingKineticTileEntity.isBreakable(state, blockHardness); } - protected void onBlockBroken(MovementContext context, BlockPos pos) { + protected void onBlockBroken(MovementContext context, BlockPos pos, BlockState brokenState) { + BlockState above = context.world.getBlockState(pos.up()); + if (!(above.getBlock() instanceof FallingBlock)) + return; + + CompoundNBT data = context.data; + data.putInt("WaitingTicks", 10); + data.put("LastPos", NBTUtil.writeBlockPos(pos)); + context.stall = true; } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/DrillMovementBehaviour.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/DrillMovementBehaviour.java index 9fdc5a399..be4ff48b1 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/DrillMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/DrillMovementBehaviour.java @@ -4,8 +4,11 @@ import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext; +import net.minecraft.block.BlockState; import net.minecraft.util.DamageSource; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -27,10 +30,15 @@ public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour { public SuperByteBuffer renderInContraption(MovementContext context) { return DrillTileEntityRenderer.renderInContraption(context); } - + @Override protected DamageSource getDamageSource() { return DrillBlock.damageSourceDrill; } + @Override + public boolean canBreak(World world, BlockPos breakingPos, BlockState state) { + return super.canBreak(world, breakingPos, state) && !state.getCollisionShape(world, breakingPos).isEmpty(); + } + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterBlock.java index 0ed7177f3..c2f00dc68 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterBlock.java @@ -1,34 +1,17 @@ package com.simibubi.create.modules.contraptions.components.actors; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.utility.AllShapes; import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock; import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour; -import net.minecraft.block.Block; import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.HorizontalBlock; -import net.minecraft.block.material.PushReaction; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.state.StateContainer.Builder; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.BlockRenderLayer; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.shapes.ISelectionContext; -import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; -import net.minecraft.world.IWorldReader; -public class HarvesterBlock extends HorizontalBlock implements IPortableBlock { +public class HarvesterBlock extends AttachedActorBlock implements IPortableBlock { public static MovementBehaviour MOVEMENT = new HarvesterMovementBehaviour(); - public HarvesterBlock() { - super(Properties.from(Blocks.IRON_BLOCK)); - } - @Override public boolean hasTileEntity(BlockState state) { return true; @@ -39,51 +22,11 @@ public class HarvesterBlock extends HorizontalBlock implements IPortableBlock { return new HarvesterTileEntity(); } - @Override - public PushReaction getPushReaction(BlockState state) { - return PushReaction.PUSH_ONLY; - } - - @Override - public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { - Direction direction = state.get(HORIZONTAL_FACING); - return AllShapes.HARVESTER_BASE.get(direction); - } - - @Override - protected void fillStateContainer(Builder builder) { - builder.add(HORIZONTAL_FACING); - super.fillStateContainer(builder); - } - @Override public BlockRenderLayer getRenderLayer() { return BlockRenderLayer.CUTOUT; } - @Override - public boolean isValidPosition(BlockState state, IWorldReader worldIn, BlockPos pos) { - Direction direction = state.get(HORIZONTAL_FACING); - BlockPos offset = pos.offset(direction.getOpposite()); - return Block.hasSolidSide(worldIn.getBlockState(offset), worldIn, offset, direction); - } - - @Override - public BlockState getStateForPlacement(BlockItemUseContext context) { - Direction facing; - if (context.getFace().getAxis().isVertical()) - facing = context.getPlacementHorizontalFacing().getOpposite(); - else { - BlockState blockState = - context.getWorld().getBlockState(context.getPos().offset(context.getFace().getOpposite())); - if (AllBlocks.HARVESTER.typeOf(blockState)) - facing = blockState.get(HORIZONTAL_FACING); - else - facing = context.getFace(); - } - return getDefaultState().with(HORIZONTAL_FACING, facing); - } - @Override public MovementBehaviour getMovementBehaviour() { return MOVEMENT; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterMovementBehaviour.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterMovementBehaviour.java index 2f3bfe2b0..83a8548b4 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterMovementBehaviour.java @@ -42,7 +42,7 @@ public class HarvesterMovementBehaviour extends MovementBehaviour { @Override public Vec3d getActiveAreaOffset(MovementContext context) { - return new Vec3d(context.state.get(HORIZONTAL_FACING).getDirectionVec()).scale(.5); + return new Vec3d(context.state.get(HORIZONTAL_FACING).getDirectionVec()).scale(.45); } @Override diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughBlock.java new file mode 100644 index 000000000..9c263de6c --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughBlock.java @@ -0,0 +1,34 @@ +package com.simibubi.create.modules.contraptions.components.actors; + +import java.util.UUID; + +import com.mojang.authlib.GameProfile; +import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour; + +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.util.FakePlayer; + +public class PloughBlock extends AttachedActorBlock { + + public static MovementBehaviour MOVEMENT = new PloughMovementBehaviour(); + + @Override + public MovementBehaviour getMovementBehaviour() { + return MOVEMENT; + } + + /** + * The OnHoeUse event takes a player, so we better not pass null + */ + static class PloughFakePlayer extends FakePlayer { + + public static final GameProfile PLOUGH_PROFILE = + new GameProfile(UUID.fromString("9e2faded-eeee-4ec2-c314-dad129ae971d"), "Plough"); + + public PloughFakePlayer(ServerWorld world) { + super(world, PLOUGH_PROFILE); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughMovementBehaviour.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughMovementBehaviour.java new file mode 100644 index 000000000..24b57f619 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughMovementBehaviour.java @@ -0,0 +1,88 @@ +package com.simibubi.create.modules.contraptions.components.actors; + +import static net.minecraft.block.HorizontalBlock.HORIZONTAL_FACING; + +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.modules.contraptions.components.actors.PloughBlock.PloughFakePlayer; +import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext; + +import net.minecraft.block.BlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; +import net.minecraft.item.Items; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.RayTraceContext.BlockMode; +import net.minecraft.util.math.RayTraceContext.FluidMode; +import net.minecraft.util.math.RayTraceResult.Type; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; + +public class PloughMovementBehaviour extends BlockBreakingMovementBehaviour { + + @Override + public boolean isActive(MovementContext context) { + return !VecHelper.isVecPointingTowards(context.relativeMotion, + context.state.get(HORIZONTAL_FACING).getOpposite()); + } + + @Override + public void visitNewPosition(MovementContext context, BlockPos pos) { + super.visitNewPosition(context, pos); + + World world = context.world; + if (world.isRemote) + return; + BlockPos below = pos.down(); + if (!world.isBlockPresent(below)) + return; + + Vec3d vec = VecHelper.getCenterOf(pos); + PloughFakePlayer player = getPlayer(context); + + if (player == null) + return; + + BlockRayTraceResult ray = world + .rayTraceBlocks(new RayTraceContext(vec, vec.add(0, -1, 0), BlockMode.OUTLINE, FluidMode.NONE, player)); + if (ray == null || ray.getType() != Type.BLOCK) + return; + + ItemUseContext ctx = new ItemUseContext(player, Hand.MAIN_HAND, ray); + new ItemStack(Items.DIAMOND_HOE).onItemUse(ctx); + } + + @Override + public Vec3d getActiveAreaOffset(MovementContext context) { + return new Vec3d(context.state.get(HORIZONTAL_FACING).getDirectionVec()).scale(.45); + } + + @Override + protected boolean throwsEntities() { + return true; + } + + @Override + public boolean canBreak(World world, BlockPos breakingPos, BlockState state) { + return state.getCollisionShape(world, breakingPos).isEmpty(); + } + + @Override + public void stopMoving(MovementContext context) { + if (context.temporaryData instanceof PloughFakePlayer) + ((PloughFakePlayer) context.temporaryData).remove(); + } + + private PloughFakePlayer getPlayer(MovementContext context) { + if (!(context.temporaryData instanceof PloughFakePlayer) && context.world instanceof ServerWorld) { + PloughFakePlayer player = new PloughFakePlayer((ServerWorld) context.world); + player.setHeldItem(Hand.MAIN_HAND, new ItemStack(Items.DIAMOND_HOE)); + context.temporaryData = player; + } + return (PloughFakePlayer) context.temporaryData; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/SawMovementBehaviour.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/SawMovementBehaviour.java index 00071f5ea..4c0036de2 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/SawMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/SawMovementBehaviour.java @@ -6,6 +6,7 @@ import com.simibubi.create.foundation.utility.TreeCutter.Tree; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext; import com.simibubi.create.modules.contraptions.components.saw.SawBlock; +import com.simibubi.create.modules.contraptions.components.saw.SawTileEntity; import net.minecraft.block.BlockState; import net.minecraft.entity.item.ItemEntity; @@ -31,12 +32,13 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour { @Override public boolean canBreak(World world, BlockPos breakingPos, BlockState state) { - return super.canBreak(world, breakingPos, state) - && (state.isIn(BlockTags.LOGS) || state.isIn(BlockTags.LEAVES)); + return super.canBreak(world, breakingPos, state) && SawTileEntity.isSawable(state); } @Override - protected void onBlockBroken(MovementContext context, BlockPos pos) { + 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) diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/BlockMovementTraits.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/BlockMovementTraits.java index 21ea16106..96e7419cb 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/BlockMovementTraits.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/BlockMovementTraits.java @@ -1,6 +1,7 @@ package com.simibubi.create.modules.contraptions.components.contraptions; import com.simibubi.create.AllBlocks; +import com.simibubi.create.modules.contraptions.components.actors.AttachedActorBlock; import com.simibubi.create.modules.contraptions.components.actors.HarvesterBlock; import com.simibubi.create.modules.contraptions.components.actors.PortableStorageInterfaceBlock; import com.simibubi.create.modules.contraptions.components.contraptions.bearing.ClockworkBearingBlock; @@ -175,7 +176,7 @@ public class BlockMovementTraits { return direction == (state.get(BlockStateProperties.HANGING) ? Direction.UP : Direction.DOWN); if (block instanceof AbstractRailBlock) return direction == Direction.DOWN; - if (block instanceof HarvesterBlock) + if (block instanceof AttachedActorBlock) return direction == state.get(HarvesterBlock.HORIZONTAL_FACING).getOpposite(); return false; } @@ -191,7 +192,7 @@ public class BlockMovementTraits { return state.get(BlockStateProperties.FACING) == facing; if (AllBlocks.PORTABLE_STORAGE_INTERFACE.typeOf(state)) return state.get(PortableStorageInterfaceBlock.FACING) == facing; - if (AllBlocks.HARVESTER.typeOf(state)) + if (state.getBlock() instanceof AttachedActorBlock) return state.get(BlockStateProperties.HORIZONTAL_FACING) == facing; if (AllBlocks.ROPE_PULLEY.typeOf(state)) return facing == Direction.DOWN; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/saw/SawTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/saw/SawTileEntity.java index fb695c9f8..34c08729e 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/saw/SawTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/saw/SawTileEntity.java @@ -24,7 +24,15 @@ import com.simibubi.create.modules.contraptions.components.actors.BlockBreakingK import com.simibubi.create.modules.contraptions.processing.ProcessingInventory; import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; +import net.minecraft.block.BambooBlock; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.block.CactusBlock; +import net.minecraft.block.ChorusPlantBlock; +import net.minecraft.block.KelpBlock; +import net.minecraft.block.KelpTopBlock; +import net.minecraft.block.StemGrownBlock; +import net.minecraft.block.SugarCaneBlock; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; @@ -379,7 +387,29 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity { @Override public boolean canBreak(BlockState stateToBreak, float blockHardness) { - return super.canBreak(stateToBreak, blockHardness) && stateToBreak.isIn(BlockTags.LOGS); + boolean sawable = isSawable(stateToBreak); + return super.canBreak(stateToBreak, blockHardness) && sawable; + } + + public static boolean isSawable(BlockState stateToBreak) { + if (stateToBreak.isIn(BlockTags.LOGS) || stateToBreak.isIn(BlockTags.LEAVES)) + return true; + Block block = stateToBreak.getBlock(); + if (block instanceof BambooBlock) + return true; + if (block instanceof StemGrownBlock) + return true; + if (block instanceof CactusBlock) + return true; + if (block instanceof SugarCaneBlock) + return true; + if (block instanceof KelpBlock) + return true; + if (block instanceof KelpTopBlock) + return true; + if (block instanceof ChorusPlantBlock) + return true; + return false; } } diff --git a/src/main/resources/assets/create/blockstates/plough.json b/src/main/resources/assets/create/blockstates/plough.json new file mode 100644 index 000000000..1805fe595 --- /dev/null +++ b/src/main/resources/assets/create/blockstates/plough.json @@ -0,0 +1,14 @@ +{ + "forge_marker": 1, + "defaults": { + "model": "create:block/plough" + }, + "variants": { + "facing": { + "north": { "y": 180 }, + "south": {}, + "east": { "y": 270 }, + "west": { "y": 90 } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/lang/en_us.json b/src/main/resources/assets/create/lang/en_us.json index b8b7668f5..6bb894769 100644 --- a/src/main/resources/assets/create/lang/en_us.json +++ b/src/main/resources/assets/create/lang/en_us.json @@ -99,6 +99,7 @@ "block.create.drill": "Mechanical Drill", "block.create.portable_storage_interface": "Portable Storage Interface", "block.create.harvester": "Mechanical Harvester", + "block.create.plough": "Mechanical Plough", "block.create.saw": "Mechanical Saw", "block.create.water_wheel": "Water Wheel", "block.create.mechanical_press": "Mechanical Press", @@ -986,16 +987,21 @@ "block.create.rotation_chassis.tooltip.action1": "Makes the clicked face _Sticky_. When Chassis move, all designated blocks attached to the sticky side are moved with it.", "block.create.drill.tooltip": "MECHANICAL DRILL", - "block.create.drill.tooltip.summary": "A mechanical device suitable for _breaking_ _blocks_. It is movable with _Mechanical_ _Pistons_ or _Bearings_.", + "block.create.drill.tooltip.summary": "A mechanical device suitable for _breaking_ _blocks_. It is movable with _Mechanical_ _Pistons_, _Bearings_ or other controllers.", "block.create.drill.tooltip.condition1": "When Rotated", "block.create.drill.tooltip.behaviour1": "Acts as a _stationary_ Block Breaker. Also _hurts_ _entities_ in its effective area.", "block.create.drill.tooltip.condition2": "While Moving", "block.create.drill.tooltip.behaviour2": "Breaks Blocks with which the drill collides.", "block.create.harvester.tooltip": "MECHANICAL HARVESTER", - "block.create.harvester.tooltip.summary": "A mechanical plant cutter suitable for medium scale crop automation. It is movable with _Mechanical_ _Pistons_ or _Bearings_.", + "block.create.harvester.tooltip.summary": "A mechanical plant cutter suitable for medium scale crop automation. It is movable with _Mechanical_ _Pistons_, _Bearings_ or other controllers.", "block.create.harvester.tooltip.condition1": "While Moving", "block.create.harvester.tooltip.behaviour1": "_Harvests_ all _mature_ _crops_ which which the blade collides and reset them to their initial growth state.", + + "block.create.plough.tooltip": "MECHANICAL PLOUGH", + "block.create.plough.tooltip.summary": "A mechanical plough has a variety of uses. It is movable with _Mechanical_ _Pistons_, _Bearings_ or other controllers.", + "block.create.plough.tooltip.condition1": "While Moving", + "block.create.plough.tooltip.behaviour1": "_Breaks_ _blocks_ which _cannot_ _be_ _collided_ with, such as torches, tracks or snow layers. _Applies_ its _motion_ to _entities_ without hurting them. _Tills_ _soil_ _blocks_ as though a Hoe would be used on them.", "block.create.saw.tooltip": "MECHANICAL SAW", "block.create.saw.tooltip.summary": "Suitable for _cutting_ _trees_ effectively and for _cutting_ _blocks_ into their carpentered counterparts. It is movable using _Mechanical_ _Pistons_ or _Bearings_.", @@ -1025,7 +1031,7 @@ "block.create.redstone_bridge.tooltip.action2": "Toggles between _Receiver_ and _Transmitter_ Mode.", "block.create.contact.tooltip": "REDSTONE CONTACT", - "block.create.contact.tooltip.summary": "Only emits redstone power in pairs. It is movable with _Mechanical_ _Pistons_ or _Bearings_.", + "block.create.contact.tooltip.summary": "Only emits redstone power in pairs. It is movable with _Mechanical_ _Pistons_, _Bearings_ or other controllers.", "block.create.contact.tooltip.condition1": "When facing other Contact", "block.create.contact.tooltip.behaviour1": "Provides a _Redstone_ _Signal_.", "block.create.contact.tooltip.condition2": "While Moving", diff --git a/src/main/resources/assets/create/models/block/plough.json b/src/main/resources/assets/create/models/block/plough.json new file mode 100644 index 000000000..9c678684d --- /dev/null +++ b/src/main/resources/assets/create/models/block/plough.json @@ -0,0 +1,113 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "block/anvil", + "particle": "create:block/andesite_casing_short", + "andesite_casing_short": "create:block/andesite_casing_short" + }, + "elements": [ + { + "name": "Core", + "from": [0, 2, 0], + "to": [16, 14, 2.9], + "faces": { + "north": {"uv": [0, 4, 16, 16], "texture": "#andesite_casing_short"}, + "east": {"uv": [2, 0, 14, 3], "rotation": 270, "texture": "#andesite_casing_short"}, + "south": {"uv": [0, 4, 16, 16], "texture": "#andesite_casing_short"}, + "west": {"uv": [2, 0, 14, 3], "rotation": 90, "texture": "#andesite_casing_short"}, + "up": {"uv": [0, 0, 16, 2.9], "rotation": 180, "texture": "#andesite_casing_short"}, + "down": {"uv": [0, 0, 16, 2.9], "texture": "#andesite_casing_short"} + } + }, + { + "name": "Attachment", + "from": [0.1, 4, 6], + "to": [2, 7, 15], + "rotation": {"angle": 22.5, "axis": "x", "origin": [0, 10, 3]}, + "faces": { + "north": {"uv": [0, 0, 1.9, 3], "texture": "#andesite_casing_short"}, + "east": {"uv": [0, 0, 9, 3], "texture": "#andesite_casing_short"}, + "south": {"uv": [0.1, 8, 2, 11], "texture": "#andesite_casing_short"}, + "west": {"uv": [0, 0, 9, 3], "texture": "#andesite_casing_short"}, + "up": {"uv": [0, 4, 1.9, 13], "texture": "#andesite_casing_short"}, + "down": {"uv": [0, 4, 1.9, 13], "texture": "#andesite_casing_short"} + } + }, + { + "name": "Attachment", + "from": [2.1, 5, 5], + "to": [14, 6, 17], + "rotation": {"angle": 22.5, "axis": "x", "origin": [0, 10, 3]}, + "faces": { + "north": {"uv": [0, 0, 11.9, 1], "texture": "#andesite_casing_short"}, + "east": {"uv": [0, 0, 12, 1], "texture": "#1"}, + "south": {"uv": [2, 15, 13.9, 16], "texture": "#1"}, + "west": {"uv": [0, 0, 12, 1], "texture": "#1"}, + "up": {"uv": [2, 2, 13.9, 14], "texture": "#1"}, + "down": {"uv": [2, 4, 13.9, 16], "texture": "#1"} + } + }, + { + "name": "Attachment", + "from": [14, 4, 6], + "to": [15.9, 7, 15], + "rotation": {"angle": 22.5, "axis": "x", "origin": [0, 10, 3]}, + "faces": { + "north": {"uv": [0, 0, 1.9, 3], "texture": "#andesite_casing_short"}, + "east": {"uv": [0, 0, 9, 3], "texture": "#andesite_casing_short"}, + "south": {"uv": [14, 8, 15.9, 11], "texture": "#andesite_casing_short"}, + "west": {"uv": [0, 0, 9, 3], "texture": "#andesite_casing_short"}, + "up": {"uv": [14, 4, 15.9, 13], "texture": "#andesite_casing_short"}, + "down": {"uv": [14, 4, 15.9, 13], "texture": "#andesite_casing_short"} + } + }, + { + "name": "Attachment", + "from": [0, 4, 2.9], + "to": [16, 7, 6], + "rotation": {"angle": 0, "axis": "x", "origin": [0, 10, 2]}, + "faces": { + "north": {"uv": [0, 0, 16, 3], "texture": "#andesite_casing_short"}, + "east": {"uv": [0, 0, 3.1, 3], "texture": "#andesite_casing_short"}, + "south": {"uv": [0, 0, 16, 3], "texture": "#andesite_casing_short"}, + "west": {"uv": [0, 0, 3.1, 3], "texture": "#andesite_casing_short"}, + "up": {"uv": [0, 0, 16, 3], "rotation": 180, "texture": "#andesite_casing_short"}, + "down": {"uv": [0, 0, 16, 3], "texture": "#andesite_casing_short"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, -135, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 225, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 45, 0], + "translation": [1, 0, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "rotation": [0, 180, 0], + "translation": [0, 0, -4], + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/plough.json b/src/main/resources/assets/create/models/item/plough.json new file mode 100644 index 000000000..241430659 --- /dev/null +++ b/src/main/resources/assets/create/models/item/plough.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/plough" +} \ No newline at end of file diff --git a/src/main/resources/data/create/loot_tables/blocks/plough.json b/src/main/resources/data/create/loot_tables/blocks/plough.json new file mode 100644 index 000000000..3714a2487 --- /dev/null +++ b/src/main/resources/data/create/loot_tables/blocks/plough.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "create:plough" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/create/recipes/crafting_shaped/contraptions/plough.json b/src/main/resources/data/create/recipes/crafting_shaped/contraptions/plough.json new file mode 100644 index 000000000..9547e94b5 --- /dev/null +++ b/src/main/resources/data/create/recipes/crafting_shaped/contraptions/plough.json @@ -0,0 +1,29 @@ +{ + "type": "crafting_shaped", + "pattern": [ + "III", + "AAA", + " C " + ], + "key": { + "C": { + "item": "create:andesite_casing" + }, + "I": { + "tag": "forge:plates/iron" + }, + "A": { + "item": "create:andesite_alloy" + } + }, + "result": { + "item": "create:plough", + "count": 1 + }, + "conditions": [ + { + "type": "create:module", + "module": "contraptions" + } + ] +} \ No newline at end of file