Assisted Placement, Part II

- helpers now respect waterlogging
- add placement helpers for rsc's cogwheel as well as machines with integrated cogwheels
This commit is contained in:
Zelophed 2020-12-19 15:58:03 +01:00
parent e2437d1a5c
commit f45c0ca182
7 changed files with 221 additions and 38 deletions

View file

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

View file

@ -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;
}

View file

@ -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<ItemStack> getItemPredicate() {
return AllBlocks.LARGE_COGWHEEL::isIn;
}
@Override
public Predicate<BlockState> 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));
}
}
}

View file

@ -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<BlockState> 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<ItemStack> getItemPredicate() {
return AllBlocks.LARGE_COGWHEEL::isIn;
}
@Override
public Predicate<BlockState> 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<Direction> 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)));
}
}
}

View file

@ -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;
}

View file

@ -95,6 +95,14 @@ public interface IPlacementHelper {
return orderedByDistance(pos, hit, ((Predicate<Direction>) dir -> dir.getAxis() != axis).and(includeDirection));
}
static List<Direction> orderedByDistanceExceptAxis(BlockPos pos, Vec3d hit, Direction.Axis first, Direction.Axis second) {
return orderedByDistanceExceptAxis(pos, hit, first, d -> d.getAxis() != second);
}
static List<Direction> orderedByDistanceExceptAxis(BlockPos pos, Vec3d hit, Direction.Axis first, Direction.Axis second, Predicate<Direction> includeDirection) {
return orderedByDistanceExceptAxis(pos, hit, first, ((Predicate<Direction>) d -> d.getAxis() != second).and(includeDirection));
}
static List<Direction> 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);
}
}

View file

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