diff --git a/src/main/java/carpetextra/utils/BlockPlacer.java b/src/main/java/carpetextra/utils/BlockPlacer.java index 002baf41..b2afdcfa 100644 --- a/src/main/java/carpetextra/utils/BlockPlacer.java +++ b/src/main/java/carpetextra/utils/BlockPlacer.java @@ -1,118 +1,131 @@ package carpetextra.utils; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.ComparatorBlock; -import net.minecraft.block.DispenserBlock; -import net.minecraft.block.FacingBlock; -import net.minecraft.block.GlazedTerracottaBlock; -import net.minecraft.block.HorizontalFacingBlock; -import net.minecraft.block.ObserverBlock; -import net.minecraft.block.PistonBlock; -import net.minecraft.block.RepeaterBlock; -import net.minecraft.block.StairsBlock; -import net.minecraft.block.TrapdoorBlock; -import net.minecraft.block.enums.BlockHalf; -import net.minecraft.block.enums.ComparatorMode; +import net.minecraft.block.*; +import net.minecraft.block.enums.*; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemPlacementContext; +import net.minecraft.state.property.DirectionProperty; +import net.minecraft.state.property.Property; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -public class BlockPlacer -{ - public static BlockState alternativeBlockPlacement(Block block, ItemPlacementContext context)//World worldIn, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer) - { - //actual alternative block placement code +public class BlockPlacer { + private static DirectionProperty getFirstDirectionProperty(BlockState state) { + for (Property prop : state.getProperties()) { + if (prop instanceof DirectionProperty) { + return (DirectionProperty) prop; + } + } + return null; + } + private static boolean isBlockAttachableChest(Block originBlock, Direction facing, BlockPos checkPos, World world) { + BlockState checkState = world.getBlockState(checkPos); + if (checkState == null) { + return false; + } + if (originBlock.equals(checkState.getBlock())) { + return checkState.get(ChestBlock.FACING).equals(facing) && checkState.get(ChestBlock.CHEST_TYPE) == ChestType.SINGLE; + } + return false; + } + private static boolean isBlockOffsetNotReplaceableBlock(BlockPos checkPos, Direction facing, World world){ + return !world.getBlockState(checkPos.offset(facing)).getMaterial().isReplaceable(); + } - Direction facing; - Vec3d vec3d = context.getHitPos(); - BlockPos pos = context.getBlockPos(); - double hitX = vec3d.x - pos.getX(); - if (hitX<2) // vanilla - return null; - int code = (int)(hitX-2)/2; - // - // now it would be great if hitX was adjusted in context to original range from 0.0 to 1.0 - // since its actually using it. Its private - maybe with Reflections? - // - PlayerEntity placer = context.getPlayer(); - World world = context.getWorld(); + public static BlockState alternativeBlockPlacement(Block block, ItemPlacementContext context)//World worldIn, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer) + { + //actual alternative block placement code - if (block instanceof GlazedTerracottaBlock) - { - facing = Direction.byId(code); - if(facing == Direction.UP || facing == Direction.DOWN) - { - facing = placer.getHorizontalFacing().getOpposite(); - } - return block.getDefaultState().with(HorizontalFacingBlock.FACING, facing); - } - else if (block instanceof ObserverBlock) - { - return block.getDefaultState() - .with(FacingBlock.FACING, Direction.byId(code)) - .with(ObserverBlock.POWERED, true); - } - else if (block instanceof RepeaterBlock) - { - facing = Direction.byId(code % 16); - if(facing == Direction.UP || facing == Direction.DOWN) - { - facing = placer.getHorizontalFacing().getOpposite(); - } - return block.getDefaultState() - .with(HorizontalFacingBlock.FACING, facing) - .with(RepeaterBlock.DELAY, MathHelper.clamp(code / 16, 1, 4)) - .with(RepeaterBlock.LOCKED, Boolean.FALSE); - } - else if (block instanceof TrapdoorBlock) - { - facing = Direction.byId(code % 16); - if(facing == Direction.UP || facing == Direction.DOWN) - { - facing = placer.getHorizontalFacing().getOpposite(); - } - return block.getDefaultState() - .with(TrapdoorBlock.FACING, facing) - .with(TrapdoorBlock.OPEN, Boolean.FALSE) - .with(TrapdoorBlock.HALF, (code >= 16) ? BlockHalf.TOP : BlockHalf.BOTTOM) - .with(TrapdoorBlock.OPEN, world.isReceivingRedstonePower(pos)); - } - else if (block instanceof ComparatorBlock) - { - facing = Direction.byId(code % 16); - if((facing == Direction.UP) || (facing == Direction.DOWN)) - { - facing = placer.getHorizontalFacing().getOpposite(); - } - ComparatorMode m = (hitX >= 16)?ComparatorMode.SUBTRACT: ComparatorMode.COMPARE; - return block.getDefaultState() - .with(HorizontalFacingBlock.FACING, facing) - .with(ComparatorBlock.POWERED, Boolean.FALSE) - .with(ComparatorBlock.MODE, m); - } - else if (block instanceof DispenserBlock) - { - return block.getDefaultState() - .with(DispenserBlock.FACING, Direction.byId(code)) - .with(DispenserBlock.TRIGGERED, Boolean.FALSE); - } - else if (block instanceof PistonBlock) - { - return block.getDefaultState() - .with(FacingBlock.FACING, Direction.byId(code)) - .with(PistonBlock.EXTENDED, Boolean.FALSE); - } - else if (block instanceof StairsBlock) - { - return block.getPlacementState(context)//worldIn, pos, facing, hitX, hitY, hitZ, meta, placer) - .with(StairsBlock.FACING, Direction.byId(code % 16)) - .with(StairsBlock.HALF, ( hitX >= 16)?BlockHalf.TOP : BlockHalf.BOTTOM); - } - return null; - } + Direction facing; + Vec3d vec3d = context.getHitPos(); + BlockPos pos = context.getBlockPos(); + double hitX = vec3d.x - pos.getX(); + BlockState state = block.getDefaultState(); + DirectionProperty directionProperty = getFirstDirectionProperty(state); + if (hitX < 2 || !(block instanceof AbstractRailBlock || block instanceof PillarBlock) && directionProperty == null) // vanilla + return null; + int code = (int) (hitX - 2) / 2; + + // + // now it would be great if hitX was adjusted in context to original range from 0.0 to 1.0 + // since its actually using it. Its private - maybe with Reflections? + // + PlayerEntity placer = context.getPlayer(); + World world = context.getWorld(); + if (block instanceof AbstractRailBlock){ + RailShape shapeEnumFound = RailShape.values()[code%RailShape.values().length]; //avoid NPE + if (block instanceof RailBlock) + { + return state.with(RailBlock.SHAPE,shapeEnumFound); + } + else if (block instanceof DetectorRailBlock) + { + return state.with(DetectorRailBlock.SHAPE,shapeEnumFound); + } + else + { + return state.with(PoweredRailBlock.SHAPE,shapeEnumFound); + } + } else if (block instanceof PillarBlock) { + return state.with(PillarBlock.AXIS, Direction.Axis.values()[code % Direction.Axis.VALUES.length]); + } + else + { + int FacingId = code % 16; + facing = Direction.byId(FacingId); + if (!directionProperty.getValues().contains(facing)) { + if (placer == null){ + facing = Direction.NORTH; + } else { + facing = placer.getHorizontalFacing().getOpposite(); + } + } + state = state.with(directionProperty, facing); + } + //check blocks with additional states first + if (block instanceof RepeaterBlock) { + state = state + .with(RepeaterBlock.DELAY, MathHelper.clamp(code / 16, 1, 4)) + .with(RepeaterBlock.LOCKED, Boolean.FALSE); + } else if (block instanceof TrapdoorBlock) { + state = state + .with(TrapdoorBlock.OPEN, Boolean.FALSE) + .with(TrapdoorBlock.HALF, (code >= 16) ? BlockHalf.TOP : BlockHalf.BOTTOM) + .with(TrapdoorBlock.OPEN, world.isReceivingRedstonePower(pos)); + } else if (block instanceof ComparatorBlock) { + ComparatorMode m = (hitX >= 16) ? ComparatorMode.SUBTRACT : ComparatorMode.COMPARE; + state = state + .with(ComparatorBlock.POWERED, Boolean.FALSE) + .with(ComparatorBlock.MODE, m); + } else if (block instanceof StairsBlock) { + state = block.getPlacementState(context); //worldIn, pos, facing, hitX, hitY, hitZ, meta, placer) + if(state == null) {return null;} + return state.with(StairsBlock.FACING, facing) + .with(StairsBlock.HALF, (hitX >= 16) ? BlockHalf.TOP : BlockHalf.BOTTOM); + } else if (block instanceof WallMountedBlock) { + return state.with(WallMountedBlock.FACE, (code >= 32) ? WallMountLocation.CEILING: (code >= 16) ? WallMountLocation.WALL : WallMountLocation.FLOOR). + with(WallMountedBlock.FACING, facing); + } else if (block instanceof WallSkullBlock){ + return state.with(WallMountedBlock.FACING, facing); + } + else if (block instanceof ChestBlock) + { + if (isBlockAttachableChest(block, facing, pos.offset(facing.rotateYClockwise()), world)) { + return state.with(ChestBlock.CHEST_TYPE, ChestType.LEFT); + } + else if (isBlockAttachableChest(block, facing, pos.offset(facing.rotateYCounterclockwise()), world)) { + return state.with(ChestBlock.CHEST_TYPE, ChestType.RIGHT); + } + return state.with(ChestBlock.CHEST_TYPE, ChestType.SINGLE); + } else if (block instanceof BedBlock && isBlockOffsetNotReplaceableBlock(pos, facing, world)) { + return null; + } else if (block instanceof DoorBlock && isBlockOffsetNotReplaceableBlock(pos, Direction.UP, world)) { + return null; + } + return state; + } } +