From f45c0ca182652f34e8ba28011afbc3c21e7bde40 Mon Sep 17 00:00:00 2001 From: Zelophed Date: Sat, 19 Dec 2020 15:58:03 +0100 Subject: [PATCH] Assisted Placement, Part II - helpers now respect waterlogging - add placement helpers for rsc's cogwheel as well as machines with integrated cogwheels --- .../structureMovement/bearing/SailBlock.java | 15 +-- .../piston/PistonExtensionPoleBlock.java | 9 +- .../relays/advanced/SpeedControllerBlock.java | 70 +++++++++++- .../relays/elementary/CogwheelBlockItem.java | 103 ++++++++++++++---- .../relays/elementary/ShaftBlock.java | 10 +- .../utility/placement/IPlacementHelper.java | 16 +++ .../utility/placement/PlacementOffset.java | 36 ++++++ 7 files changed, 221 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java index d6b021dea..fbc1517c7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java @@ -68,20 +68,21 @@ public class SailBlock extends ProperDirectionalBlock { IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); PlacementOffset offset = placementHelper.getOffset(world, state, pos, ray); - if (!offset.isSuccessful()) + if (!offset.isReplaceable(world)) return ActionResultType.PASS; - BlockState blockState = ((BlockItem) heldItem.getItem()).getBlock() + offset.placeInWorld(world, ((BlockItem) heldItem.getItem()).getBlock().getDefaultState(), player, heldItem); + + /*BlockState blockState = ((BlockItem) heldItem.getItem()).getBlock() .getDefaultState() .with(FACING, state.get(FACING)); BlockPos offsetPos = new BlockPos(offset.getPos()); - if (!world.isRemote && world.getBlockState(offsetPos) - .getMaterial() - .isReplaceable()) { + if (!world.isRemote && world.getBlockState(offsetPos).getMaterial().isReplaceable()) { world.setBlockState(offsetPos, blockState); if (!player.isCreative()) heldItem.shrink(1); - } + }*/ + return ActionResultType.SUCCESS; } @@ -227,7 +228,7 @@ public class SailBlock extends ProperDirectionalBlock { if (directions.isEmpty()) return PlacementOffset.fail(); else { - return PlacementOffset.success(pos.offset(directions.get(0))); + return PlacementOffset.success(pos.offset(directions.get(0)), s -> s.with(FACING, state.get(FACING))); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java index 10248461e..27460381f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonExtensionPoleBlock.java @@ -118,20 +118,19 @@ public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId); PlacementOffset offset = placementHelper.getOffset(world, state, pos, ray); - if (!offset.isSuccessful()) + if (!offset.isReplaceable(world)) return ActionResultType.PASS; - BlockPos newPos = new BlockPos(offset.getPos()); + offset.placeInWorld(world, AllBlocks.PISTON_EXTENSION_POLE.getDefaultState(), player, heldItem); - if (!world.getBlockState(newPos).getMaterial().isReplaceable()) - return ActionResultType.PASS; + /*BlockPos newPos = new BlockPos(offset.getPos()); if (world.isRemote) return ActionResultType.SUCCESS; world.setBlockState(newPos, offset.getTransform().apply(AllBlocks.PISTON_EXTENSION_POLE.getDefaultState())); if (!player.isCreative()) - heldItem.shrink(1); + heldItem.shrink(1);*/ return ActionResultType.SUCCESS; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java index 6da015608..7604042ff 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/SpeedControllerBlock.java @@ -1,21 +1,38 @@ package com.simibubi.create.content.contraptions.relays.advanced; +import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock; import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock; - +import com.simibubi.create.content.contraptions.relays.elementary.CogwheelBlockItem; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.placement.IPlacementHelper; +import com.simibubi.create.foundation.utility.placement.PlacementHelpers; +import com.simibubi.create.foundation.utility.placement.PlacementOffset; +import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.BlockItemUseContext; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; + +import java.util.function.Predicate; public class SpeedControllerBlock extends HorizontalAxisKineticBlock { + private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); + public SpeedControllerBlock(Properties properties) { super(properties); } @@ -33,9 +50,60 @@ public class SpeedControllerBlock extends HorizontalAxisKineticBlock { return super.getStateForPlacement(context); } + @Override + public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult ray) { + + IPlacementHelper helper = PlacementHelpers.get(placementHelperId); + ItemStack heldItem = player.getHeldItem(hand); + if (helper.matchesItem(heldItem)) { + PlacementOffset offset = helper.getOffset(world, state, pos, ray); + + if (!offset.isReplaceable(world)) + return ActionResultType.PASS; + + offset.placeInWorld(world, AllBlocks.LARGE_COGWHEEL.getDefaultState(), player, heldItem); + + return ActionResultType.SUCCESS; + + } + + return ActionResultType.PASS; + } + @Override public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { return AllShapes.SPEED_CONTROLLER.get(state.get(HORIZONTAL_AXIS)); } + @MethodsReturnNonnullByDefault + private static class PlacementHelper implements IPlacementHelper { + @Override + public Predicate getItemPredicate() { + return AllBlocks.LARGE_COGWHEEL::isIn; + } + + @Override + public Predicate getStatePredicate() { + return AllBlocks.ROTATION_SPEED_CONTROLLER::has; + } + + @Override + public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { + BlockPos newPos = pos.up(); + if (!world.getBlockState(newPos).getMaterial().isReplaceable()) + return PlacementOffset.fail(); + + Axis newAxis = state.get(HORIZONTAL_AXIS) == Axis.X ? Axis.Z : Axis.X; + + if (CogwheelBlockItem.DiagonalCogHelper.hasLargeCogwheelNeighbor(world, newPos, newAxis) || CogwheelBlockItem.DiagonalCogHelper.hasSmallCogwheelNeighbor(world, newPos, newAxis)) + return PlacementOffset.fail(); + + return PlacementOffset.success(newPos, s -> s.with(CogWheelBlock.AXIS, newAxis)); + } + + @Override + public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) { + IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, state.get(HORIZONTAL_AXIS) == Axis.X ? Axis.Z : Axis.X)); + } + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java index 568238b4c..94cc8e993 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/CogwheelBlockItem.java @@ -2,6 +2,9 @@ package com.simibubi.create.content.contraptions.relays.elementary; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; +import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; +import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; +import com.simibubi.create.content.contraptions.base.IRotate; import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.VecHelper; @@ -32,43 +35,51 @@ public class CogwheelBlockItem extends BlockItem { boolean large; private final int placementHelperId; + private final int integratedCogHelperId; public CogwheelBlockItem(CogWheelBlock block, Properties builder) { super(block, builder); large = block.isLarge; placementHelperId = PlacementHelpers.register(large ? new LargeCogHelper() : new SmallCogHelper()); + integratedCogHelperId = large ? PlacementHelpers.register(new IntegratedCogHelper()) : -1; } @Override public ActionResultType tryPlace(BlockItemUseContext context) { - IPlacementHelper helper = PlacementHelpers.get(placementHelperId); World world = context.getWorld(); BlockPos pos = context.getPos().offset(context.getFace().getOpposite()); BlockState state = world.getBlockState(pos); - if (!helper.getStatePredicate().test(state)) - return super.tryPlace(context); + IPlacementHelper helper = PlacementHelpers.get(placementHelperId); - PlacementOffset offset = helper.getOffset(world, state, pos, new BlockRayTraceResult(context.getHitVec(), context.getFace(), pos, true)); + if (helper.matchesState(state)) { + PlacementOffset offset = helper.getOffset(world, state, pos, new BlockRayTraceResult(context.getHitVec(), context.getFace(), pos, true)); - if (!offset.isSuccessful()) - return super.tryPlace(context); + if (!offset.isReplaceable(world)) + return super.tryPlace(context); - BlockPos newPos = new BlockPos(offset.getPos()); + offset.placeInWorld(world, this, context.getPlayer(), context.getItem()); - if (!world.getBlockState(newPos).getMaterial().isReplaceable()) - return ActionResultType.PASS; - - if (world.isRemote) return ActionResultType.SUCCESS; - - world.setBlockState(newPos, offset.getTransform().apply(this.getBlock().getDefaultState())); - if (context.getPlayer() != null && !context.getPlayer().isCreative()) { - context.getItem().shrink(1); } - return ActionResultType.SUCCESS; + if (integratedCogHelperId != -1) { + helper = PlacementHelpers.get(integratedCogHelperId); + + if (helper.matchesState(state)) { + PlacementOffset offset = helper.getOffset(world, state, pos, new BlockRayTraceResult(context.getHitVec(), context.getFace(), pos, true)); + + if (!offset.isReplaceable(world)) + return super.tryPlace(context); + + offset.placeInWorld(world, this, context.getPlayer(), context.getItem()); + + return ActionResultType.SUCCESS; + } + } + + return super.tryPlace(context); /*if (!(placedOnState.getBlock() instanceof CogWheelBlock)) return super.tryPlace(context); @@ -218,7 +229,7 @@ public class CogwheelBlockItem extends BlockItem { } @MethodsReturnNonnullByDefault - private abstract static class DiagonalCogHelper implements IPlacementHelper { + public abstract static class DiagonalCogHelper implements IPlacementHelper { @Override public Predicate getStatePredicate() { @@ -254,7 +265,7 @@ public class CogwheelBlockItem extends BlockItem { return AllShapes.SIX_VOXEL_POLE.get(state.get(AXIS)).getBoundingBox().grow(0.001).contains(ray.getHitVec().subtract(ray.getHitVec().align(Iterate.axisSet))); } - protected boolean hasLargeCogwheelNeighbor(World world, BlockPos pos, Direction.Axis axis) { + static public boolean hasLargeCogwheelNeighbor(World world, BlockPos pos, Direction.Axis axis) { for (Direction dir : Iterate.directions) { if (dir.getAxis() == axis) continue; @@ -266,7 +277,7 @@ public class CogwheelBlockItem extends BlockItem { return false; } - protected boolean hasSmallCogwheelNeighbor(World world, BlockPos pos, Direction.Axis axis) { + static public boolean hasSmallCogwheelNeighbor(World world, BlockPos pos, Direction.Axis axis) { for (Direction dir : Iterate.directions) { if (dir.getAxis() == axis) continue; @@ -278,4 +289,58 @@ public class CogwheelBlockItem extends BlockItem { return false; } } + + @MethodsReturnNonnullByDefault + public static class IntegratedCogHelper implements IPlacementHelper { + + @Override + public Predicate getItemPredicate() { + return AllBlocks.LARGE_COGWHEEL::isIn; + } + + @Override + public Predicate getStatePredicate() { + return s -> !AllBlocks.COGWHEEL.has(s) && s.getBlock() instanceof IRotate && ((IRotate) s.getBlock()).hasIntegratedCogwheel(null, null, null); + } + + @Override + public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) { + Direction face = ray.getFace(); + Axis newAxis; + + if (state.has(HorizontalKineticBlock.HORIZONTAL_FACING)) + newAxis = state.get(HorizontalKineticBlock.HORIZONTAL_FACING).getAxis(); + else if (state.has(DirectionalKineticBlock.FACING)) + newAxis = state.get(DirectionalKineticBlock.FACING).getAxis(); + else + newAxis = Axis.Y; + + if (face.getAxis() == newAxis) + return PlacementOffset.fail(); + + List directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getHitVec(), face.getAxis(), newAxis); + + for (Direction d : directions) { + BlockPos newPos = pos.offset(face).offset(d); + + if (!world.getBlockState(newPos).getMaterial().isReplaceable()) + continue; + + if (DiagonalCogHelper.hasLargeCogwheelNeighbor(world, newPos, newAxis) || DiagonalCogHelper.hasSmallCogwheelNeighbor(world, newPos, newAxis)) + return PlacementOffset.fail(); + + return PlacementOffset.success(newPos, s -> s.with(CogWheelBlock.AXIS, newAxis)); + } + + return PlacementOffset.fail(); + } + + @Override + public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) { + IPlacementHelper.renderArrow( + VecHelper.getCenterOf(pos), + VecHelper.getCenterOf(offset.getPos()), + Direction.getFacingFromAxis(Direction.AxisDirection.POSITIVE, offset.getTransform().apply(AllBlocks.LARGE_COGWHEEL.getDefaultState()).get(AXIS))); + } + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java index b4584c8ee..f1094dcc0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/ShaftBlock.java @@ -10,7 +10,6 @@ import com.simibubi.create.foundation.utility.placement.PlacementHelpers; import com.simibubi.create.foundation.utility.placement.PlacementOffset; import com.simibubi.create.foundation.utility.placement.util.PoleHelper; import mcp.MethodsReturnNonnullByDefault; -import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.BlockItem; @@ -81,13 +80,12 @@ public class ShaftBlock extends AbstractShaftBlock { if (helper.getItemPredicate().test(heldItem)) { PlacementOffset offset = helper.getOffset(world, state, pos, ray); - if (!offset.isSuccessful()) + if (!offset.isReplaceable(world)) return ActionResultType.PASS; - BlockPos newPos = new BlockPos(offset.getPos()); + offset.placeInWorld(world, (BlockItem) heldItem.getItem(), player, heldItem); - if (!world.getBlockState(newPos).getMaterial().isReplaceable()) - return ActionResultType.PASS; + /*BlockPos newPos = new BlockPos(offset.getPos()); if (world.isRemote) return ActionResultType.SUCCESS; @@ -95,7 +93,7 @@ public class ShaftBlock extends AbstractShaftBlock { Block block = ((BlockItem) heldItem.getItem()).getBlock(); world.setBlockState(newPos, offset.getTransform().apply(block.getDefaultState())); if (!player.isCreative()) - heldItem.shrink(1); + heldItem.shrink(1);*/ return ActionResultType.SUCCESS; } diff --git a/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java b/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java index 685323076..2cb70be61 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/placement/IPlacementHelper.java @@ -95,6 +95,14 @@ public interface IPlacementHelper { return orderedByDistance(pos, hit, ((Predicate) dir -> dir.getAxis() != axis).and(includeDirection)); } + static List orderedByDistanceExceptAxis(BlockPos pos, Vec3d hit, Direction.Axis first, Direction.Axis second) { + return orderedByDistanceExceptAxis(pos, hit, first, d -> d.getAxis() != second); + } + + static List orderedByDistanceExceptAxis(BlockPos pos, Vec3d hit, Direction.Axis first, Direction.Axis second, Predicate includeDirection) { + return orderedByDistanceExceptAxis(pos, hit, first, ((Predicate) d -> d.getAxis() != second).and(includeDirection)); + } + static List orderedByDistance(BlockPos pos, Vec3d hit) { return orderedByDistance(pos, hit, _$ -> true); } @@ -108,4 +116,12 @@ public interface IPlacementHelper { .map(Pair::getFirst) .collect(Collectors.toList()); } + + default boolean matchesItem(ItemStack item) { + return getItemPredicate().test(item); + } + + default boolean matchesState(BlockState state) { + return getStatePredicate().test(state); + } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementOffset.java b/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementOffset.java index 4d8f28faf..059150f22 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementOffset.java +++ b/src/main/java/com/simibubi/create/foundation/utility/placement/PlacementOffset.java @@ -1,7 +1,15 @@ package com.simibubi.create.foundation.utility.placement; import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.fluid.Fluids; +import net.minecraft.fluid.IFluidState; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3i; +import net.minecraft.world.World; import java.util.function.Function; @@ -40,4 +48,32 @@ public class PlacementOffset { public Function getTransform() { return stateTransform; } + + public boolean isReplaceable(World world) { + if (!success) + return false; + + return world.getBlockState(new BlockPos(pos)).getMaterial().isReplaceable(); + } + + public void placeInWorld(World world, BlockItem blockItem, PlayerEntity player, ItemStack item) { + placeInWorld(world, blockItem.getBlock().getDefaultState(), player, item); + } + + public void placeInWorld(World world, BlockState defaultState, PlayerEntity player, ItemStack item) { + if (world.isRemote) + return; + + BlockPos newPos = new BlockPos(pos); + BlockState state = stateTransform.apply(defaultState); + if (state.has(BlockStateProperties.WATERLOGGED)) { + IFluidState fluidState = world.getFluidState(newPos); + state = state.with(BlockStateProperties.WATERLOGGED, fluidState.getFluid() == Fluids.WATER); + } + + world.setBlockState(newPos, state); + + if (!player.isCreative()) + item.shrink(1); + } }