mirror of
https://github.com/LeavesMC/Leaves.git
synced 2025-12-19 14:59:32 +00:00
486 lines
22 KiB
Diff
486 lines
22 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: violetc <58360096+s-yh-china@users.noreply.github.com>
|
|
Date: Thu, 8 Dec 2022 19:40:00 +0800
|
|
Subject: [PATCH] Alternative block placement Protocol
|
|
|
|
This patch is Powered by
|
|
carpet-extra(https://github.com/gnembon/carpet-extra)
|
|
MasaGadget(https://github.com/plusls/MasaGadget)
|
|
litematica(https://github.com/maruohon/litematica)
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java
|
|
index 96fb69ec6db2e7c8c728435f0c537b076259b2fb..29f38a0a87cb7e27ac18c09dd59e774cfd874592 100644
|
|
--- a/src/main/java/net/minecraft/world/item/BlockItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/BlockItem.java
|
|
@@ -163,6 +163,27 @@ public class BlockItem extends Item {
|
|
@Nullable
|
|
protected BlockState getPlacementState(BlockPlaceContext context) {
|
|
BlockState iblockdata = this.getBlock().getStateForPlacement(context);
|
|
+ // Leaves start - alternativeBlockPlacement
|
|
+ switch (org.leavesmc.leaves.LeavesConfig.alternativeBlockPlacement) {
|
|
+ case CARPET -> {
|
|
+ BlockState tryState = org.leavesmc.leaves.protocol.CarpetAlternativeBlockPlacement.alternativeBlockPlacement(getBlock(), context);
|
|
+ if (tryState != null) {
|
|
+ iblockdata = tryState;
|
|
+ }
|
|
+ }
|
|
+ case CARPET_FIX -> {
|
|
+ BlockState tryState = org.leavesmc.leaves.protocol.CarpetAlternativeBlockPlacement.alternativeBlockPlacementFix(getBlock(), context);
|
|
+ if (tryState != null) {
|
|
+ iblockdata = tryState;
|
|
+ }
|
|
+ }
|
|
+ case LITEMATICA -> {
|
|
+ if (iblockdata != null && this.canPlace(context, iblockdata)) {
|
|
+ return org.leavesmc.leaves.protocol.LitematicaEasyPlaceProtocol.applyPlacementProtocol(iblockdata, context);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Leaves end - alternativeBlockPlacement
|
|
|
|
return iblockdata != null && this.canPlace(context, iblockdata) ? iblockdata : null;
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java b/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java
|
|
index f8f909ebdad5e96379e8bd8c610164ef0697368e..0b761f3ae15ad4a3b8152f497a60403212109534 100644
|
|
--- a/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java
|
|
+++ b/src/main/java/net/minecraft/world/item/StandingAndWallBlockItem.java
|
|
@@ -34,7 +34,7 @@ public class StandingAndWallBlockItem extends BlockItem {
|
|
@Nullable
|
|
@Override
|
|
protected BlockState getPlacementState(BlockPlaceContext context) {
|
|
- BlockState iblockdata = this.wallBlock.getStateForPlacement(context);
|
|
+ BlockState iblockdata = this.wallBlock.getRealStateForPlacement(context); // Leaves - alternativeBlockPlacement
|
|
BlockState iblockdata1 = null;
|
|
Level world = context.getLevel();
|
|
BlockPos blockposition = context.getClickedPos();
|
|
@@ -45,7 +45,7 @@ public class StandingAndWallBlockItem extends BlockItem {
|
|
Direction enumdirection = aenumdirection[j];
|
|
|
|
if (enumdirection != this.attachmentDirection.getOpposite()) {
|
|
- BlockState iblockdata2 = enumdirection == this.attachmentDirection ? this.getBlock().getStateForPlacement(context) : iblockdata;
|
|
+ BlockState iblockdata2 = enumdirection == this.attachmentDirection ? this.getBlock().getRealStateForPlacement(context) : iblockdata; // Leaves - carpetAlternativeBlockPlacement
|
|
|
|
if (iblockdata2 != null && this.canPlace(world, iblockdata2, blockposition)) {
|
|
iblockdata1 = iblockdata2;
|
|
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
|
|
index 997280cd6131b14396d6fb37c293a6d4cc118412..9740426bbe54e23d833cf93346de344ff089168b 100644
|
|
--- a/src/main/java/net/minecraft/world/level/block/Block.java
|
|
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
|
|
@@ -412,6 +412,33 @@ public class Block extends BlockBehaviour implements ItemLike {
|
|
|
|
public void stepOn(Level world, BlockPos pos, BlockState state, Entity entity) {}
|
|
|
|
+ // Leaves start - alternativeBlockPlacement
|
|
+ @Nullable
|
|
+ public BlockState getRealStateForPlacement(BlockPlaceContext ctx) {
|
|
+ BlockState vanillaState = getStateForPlacement(ctx);
|
|
+ switch (org.leavesmc.leaves.LeavesConfig.alternativeBlockPlacement) {
|
|
+ case CARPET -> {
|
|
+ BlockState tryState = org.leavesmc.leaves.protocol.CarpetAlternativeBlockPlacement.alternativeBlockPlacement(this, ctx);
|
|
+ if (tryState != null) {
|
|
+ return tryState;
|
|
+ }
|
|
+ }
|
|
+ case CARPET_FIX -> {
|
|
+ BlockState tryState = org.leavesmc.leaves.protocol.CarpetAlternativeBlockPlacement.alternativeBlockPlacementFix(this, ctx);
|
|
+ if (tryState != null) {
|
|
+ return tryState;
|
|
+ }
|
|
+ }
|
|
+ case LITEMATICA -> {
|
|
+ if (vanillaState != null) {
|
|
+ return org.leavesmc.leaves.protocol.LitematicaEasyPlaceProtocol.applyPlacementProtocol(vanillaState, ctx);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return vanillaState;
|
|
+ }
|
|
+ // Leaves end - alternativeBlockPlacement
|
|
+
|
|
@Nullable
|
|
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
|
|
return this.defaultBlockState();
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/CarpetAlternativeBlockPlacement.java b/src/main/java/org/leavesmc/leaves/protocol/CarpetAlternativeBlockPlacement.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..03978356d2716296f8c5e4173d10862db57a3193
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/CarpetAlternativeBlockPlacement.java
|
|
@@ -0,0 +1,162 @@
|
|
+package org.leavesmc.leaves.protocol;
|
|
+
|
|
+import net.minecraft.core.BlockPos;
|
|
+import net.minecraft.core.Direction;
|
|
+import net.minecraft.util.Mth;
|
|
+import net.minecraft.world.entity.player.Player;
|
|
+import net.minecraft.world.item.context.BlockPlaceContext;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.level.block.BedBlock;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import net.minecraft.world.level.block.ComparatorBlock;
|
|
+import net.minecraft.world.level.block.DirectionalBlock;
|
|
+import net.minecraft.world.level.block.DispenserBlock;
|
|
+import net.minecraft.world.level.block.GlazedTerracottaBlock;
|
|
+import net.minecraft.world.level.block.ObserverBlock;
|
|
+import net.minecraft.world.level.block.RepeaterBlock;
|
|
+import net.minecraft.world.level.block.StairBlock;
|
|
+import net.minecraft.world.level.block.TrapDoorBlock;
|
|
+import net.minecraft.world.level.block.piston.PistonBaseBlock;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
|
+import net.minecraft.world.level.block.state.properties.ComparatorMode;
|
|
+import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
|
+import net.minecraft.world.level.block.state.properties.Half;
|
|
+import net.minecraft.world.level.block.state.properties.Property;
|
|
+import net.minecraft.world.level.block.state.properties.SlabType;
|
|
+import net.minecraft.world.phys.Vec3;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+
|
|
+import javax.annotation.Nullable;
|
|
+import java.util.Objects;
|
|
+
|
|
+public class CarpetAlternativeBlockPlacement {
|
|
+
|
|
+ @Nullable
|
|
+ public static BlockState alternativeBlockPlacement(@NotNull Block block, @NotNull BlockPlaceContext context) {
|
|
+ Vec3 hitPos = context.getClickLocation();
|
|
+ BlockPos blockPos = context.getClickedPos();
|
|
+ double relativeHitX = hitPos.x - blockPos.getX();
|
|
+ BlockState state = block.getStateForPlacement(context);
|
|
+ Player player = context.getPlayer();
|
|
+
|
|
+ if (relativeHitX < 2 || state == null || player == null) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ DirectionProperty directionProp = getFirstDirectionProperty(state);
|
|
+ int protocolValue = ((int) relativeHitX - 2) / 2;
|
|
+
|
|
+ if (directionProp != null) {
|
|
+ Direction origFacing = state.getValue(directionProp);
|
|
+ Direction facing = origFacing;
|
|
+ int facingIndex = protocolValue & 0xF;
|
|
+
|
|
+ if (facingIndex == 6) {
|
|
+ facing = facing.getOpposite();
|
|
+ } else if (facingIndex <= 5) {
|
|
+ facing = Direction.from3DDataValue(facingIndex);
|
|
+ }
|
|
+
|
|
+ if (!directionProp.getPossibleValues().contains(facing)) {
|
|
+ facing = player.getDirection().getOpposite();
|
|
+ }
|
|
+
|
|
+ if (facing != origFacing && directionProp.getPossibleValues().contains(facing)) {
|
|
+ if (state.getBlock() instanceof BedBlock) {
|
|
+ BlockPos headPos = blockPos.relative(facing);
|
|
+
|
|
+ if (!context.getLevel().getBlockState(headPos).canBeReplaced(context)) {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ state = state.setValue(directionProp, facing);
|
|
+ }
|
|
+ } else if (state.hasProperty(BlockStateProperties.AXIS)) {
|
|
+ Direction.Axis axis = Direction.Axis.VALUES[protocolValue % 3];
|
|
+ state = state.setValue(BlockStateProperties.AXIS, axis);
|
|
+ }
|
|
+
|
|
+ protocolValue &= 0xFFFFFFF0;
|
|
+
|
|
+ if (protocolValue >= 16) {
|
|
+ if (block instanceof RepeaterBlock) {
|
|
+ Integer delay = (protocolValue / 16);
|
|
+
|
|
+ if (RepeaterBlock.DELAY.getPossibleValues().contains(delay)) {
|
|
+ state = state.setValue(RepeaterBlock.DELAY, delay);
|
|
+ }
|
|
+ } else if (protocolValue == 16) {
|
|
+ if (block instanceof ComparatorBlock) {
|
|
+ state = state.setValue(ComparatorBlock.MODE, ComparatorMode.SUBTRACT);
|
|
+ } else if (state.hasProperty(BlockStateProperties.HALF) && state.getValue(BlockStateProperties.HALF) == Half.BOTTOM) {
|
|
+ state = state.setValue(BlockStateProperties.HALF, Half.TOP);
|
|
+ } else if (state.hasProperty(BlockStateProperties.SLAB_TYPE) && state.getValue(BlockStateProperties.SLAB_TYPE) == SlabType.BOTTOM) {
|
|
+ state = state.setValue(BlockStateProperties.SLAB_TYPE, SlabType.TOP);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return state;
|
|
+ }
|
|
+
|
|
+ public static BlockState alternativeBlockPlacementFix(Block block, BlockPlaceContext context) {
|
|
+ Direction facing;
|
|
+ Vec3 vec3d = context.getClickLocation();
|
|
+ BlockPos pos = context.getClickedPos();
|
|
+ double hitX = vec3d.x - pos.getX();
|
|
+ if (hitX < 2) {
|
|
+ return null;
|
|
+ }
|
|
+ int code = (int) (hitX - 2) / 2;
|
|
+ Player placer = Objects.requireNonNull(context.getPlayer());
|
|
+ Level world = context.getLevel();
|
|
+
|
|
+ if (block instanceof GlazedTerracottaBlock) {
|
|
+ facing = Direction.from3DDataValue(code);
|
|
+ if (facing == Direction.UP || facing == Direction.DOWN) {
|
|
+ facing = placer.getDirection().getOpposite();
|
|
+ }
|
|
+ return block.defaultBlockState().setValue(GlazedTerracottaBlock.FACING, facing);
|
|
+ } else if (block instanceof ObserverBlock) {
|
|
+ return block.defaultBlockState().setValue(ObserverBlock.FACING, Direction.from3DDataValue(code)).setValue(ObserverBlock.POWERED, true);
|
|
+ } else if (block instanceof RepeaterBlock) {
|
|
+ facing = Direction.from3DDataValue(code % 16);
|
|
+ if (facing == Direction.UP || facing == Direction.DOWN) {
|
|
+ facing = placer.getDirection().getOpposite();
|
|
+ }
|
|
+ return block.defaultBlockState().setValue(RepeaterBlock.FACING, facing).setValue(RepeaterBlock.DELAY, Mth.clamp(code / 16, 1, 4)).setValue(RepeaterBlock.LOCKED, Boolean.FALSE);
|
|
+ } else if (block instanceof TrapDoorBlock) {
|
|
+ facing = Direction.from3DDataValue(code % 16);
|
|
+ if (facing == Direction.UP || facing == Direction.DOWN) {
|
|
+ facing = placer.getDirection().getOpposite();
|
|
+ }
|
|
+ return block.defaultBlockState().setValue(TrapDoorBlock.FACING, facing).setValue(TrapDoorBlock.OPEN, Boolean.FALSE).setValue(TrapDoorBlock.HALF, (code >= 16) ? Half.TOP : Half.BOTTOM).setValue(TrapDoorBlock.OPEN, world.hasNeighborSignal(pos));
|
|
+ } else if (block instanceof ComparatorBlock) {
|
|
+ facing = Direction.from3DDataValue(code % 16);
|
|
+ if ((facing == Direction.UP) || (facing == Direction.DOWN)) {
|
|
+ facing = placer.getDirection().getOpposite();
|
|
+ }
|
|
+ ComparatorMode m = (hitX >= 16) ? ComparatorMode.SUBTRACT : ComparatorMode.COMPARE;
|
|
+ return block.defaultBlockState().setValue(ComparatorBlock.FACING, facing).setValue(ComparatorBlock.POWERED, Boolean.FALSE).setValue(ComparatorBlock.MODE, m);
|
|
+ } else if (block instanceof DispenserBlock) {
|
|
+ return block.defaultBlockState().setValue(DispenserBlock.FACING, Direction.from3DDataValue(code)).setValue(DispenserBlock.TRIGGERED, Boolean.FALSE);
|
|
+ } else if (block instanceof PistonBaseBlock) {
|
|
+ return block.defaultBlockState().setValue(DirectionalBlock.FACING, Direction.from3DDataValue(code)).setValue(PistonBaseBlock.EXTENDED, Boolean.FALSE);
|
|
+ } else if (block instanceof StairBlock) {
|
|
+ return Objects.requireNonNull(block.getStateForPlacement(context)).setValue(StairBlock.FACING, Direction.from3DDataValue(code % 16)).setValue(StairBlock.HALF, (hitX >= 16) ? Half.TOP : Half.BOTTOM);
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ public static DirectionProperty getFirstDirectionProperty(@NotNull BlockState state) {
|
|
+ for (Property<?> prop : state.getProperties()) {
|
|
+ if (prop instanceof DirectionProperty) {
|
|
+ return (DirectionProperty) prop;
|
|
+ }
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/protocol/LitematicaEasyPlaceProtocol.java b/src/main/java/org/leavesmc/leaves/protocol/LitematicaEasyPlaceProtocol.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..92f90ebf04f00341360e9e0ba1da5e0a4688f9eb
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/protocol/LitematicaEasyPlaceProtocol.java
|
|
@@ -0,0 +1,209 @@
|
|
+package org.leavesmc.leaves.protocol;
|
|
+
|
|
+import com.google.common.collect.ImmutableSet;
|
|
+import net.minecraft.core.BlockPos;
|
|
+import net.minecraft.core.Direction;
|
|
+import net.minecraft.util.Mth;
|
|
+import net.minecraft.world.InteractionHand;
|
|
+import net.minecraft.world.entity.LivingEntity;
|
|
+import net.minecraft.world.item.context.BlockPlaceContext;
|
|
+import net.minecraft.world.level.Level;
|
|
+import net.minecraft.world.level.block.BedBlock;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
|
+import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
|
+import net.minecraft.world.level.block.state.properties.Property;
|
|
+import net.minecraft.world.level.block.state.properties.SlabType;
|
|
+import net.minecraft.world.phys.Vec3;
|
|
+import org.leavesmc.leaves.LeavesLogger;
|
|
+
|
|
+import javax.annotation.Nullable;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Comparator;
|
|
+import java.util.List;
|
|
+
|
|
+public class LitematicaEasyPlaceProtocol {
|
|
+
|
|
+ public static final ImmutableSet<Property<?>> WHITELISTED_PROPERTIES = ImmutableSet.of(
|
|
+ BlockStateProperties.INVERTED,
|
|
+ BlockStateProperties.OPEN,
|
|
+ BlockStateProperties.BELL_ATTACHMENT,
|
|
+ BlockStateProperties.AXIS,
|
|
+ BlockStateProperties.BED_PART,
|
|
+ BlockStateProperties.HALF,
|
|
+ BlockStateProperties.ATTACH_FACE,
|
|
+ BlockStateProperties.CHEST_TYPE,
|
|
+ BlockStateProperties.MODE_COMPARATOR,
|
|
+ BlockStateProperties.DOOR_HINGE,
|
|
+ BlockStateProperties.ORIENTATION,
|
|
+ BlockStateProperties.RAIL_SHAPE,
|
|
+ BlockStateProperties.RAIL_SHAPE_STRAIGHT,
|
|
+ BlockStateProperties.SLAB_TYPE,
|
|
+ BlockStateProperties.STAIRS_SHAPE,
|
|
+ BlockStateProperties.BITES,
|
|
+ BlockStateProperties.DELAY,
|
|
+ BlockStateProperties.NOTE,
|
|
+ BlockStateProperties.ROTATION_16
|
|
+ );
|
|
+
|
|
+ public static BlockState applyPlacementProtocol(BlockState state, BlockPlaceContext context) {
|
|
+ return applyPlacementProtocolV3(state, UseContext.from(context, context.getHand()));
|
|
+ }
|
|
+
|
|
+ private static <T extends Comparable<T>> BlockState applyPlacementProtocolV3(BlockState state, UseContext context) {
|
|
+ int protocolValue = (int) (context.getHitVec().x - (double) context.getPos().getX()) - 2;
|
|
+ BlockState oldState = state;
|
|
+ if (protocolValue < 0) {
|
|
+ return oldState;
|
|
+ }
|
|
+
|
|
+ @Nullable DirectionProperty property = CarpetAlternativeBlockPlacement.getFirstDirectionProperty(state);
|
|
+
|
|
+ if (property != null && property != BlockStateProperties.VERTICAL_DIRECTION) {
|
|
+ state = applyDirectionProperty(state, context, property, protocolValue);
|
|
+
|
|
+ if (state == null) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ if (state.canSurvive(context.getWorld(), context.getPos())) {
|
|
+ oldState = state;
|
|
+ } else {
|
|
+ state = oldState;
|
|
+ }
|
|
+
|
|
+ protocolValue >>>= 3;
|
|
+ }
|
|
+
|
|
+ protocolValue >>>= 1;
|
|
+
|
|
+ List<Property<?>> propList = new ArrayList<>(state.getBlock().getStateDefinition().getProperties());
|
|
+ propList.sort(Comparator.comparing(Property::getName));
|
|
+
|
|
+ try {
|
|
+ for (Property<?> p : propList) {
|
|
+ if (!(p instanceof DirectionProperty) && WHITELISTED_PROPERTIES.contains(p)) {
|
|
+ @SuppressWarnings("unchecked")
|
|
+ Property<T> prop = (Property<T>) p;
|
|
+ List<T> list = new ArrayList<>(prop.getPossibleValues());
|
|
+ list.sort(Comparable::compareTo);
|
|
+
|
|
+ int requiredBits = Mth.log2(Mth.smallestEncompassingPowerOfTwo(list.size()));
|
|
+ int bitMask = ~(0xFFFFFFFF << requiredBits);
|
|
+ int valueIndex = protocolValue & bitMask;
|
|
+
|
|
+ if (valueIndex < list.size()) {
|
|
+ T value = list.get(valueIndex);
|
|
+
|
|
+ if (!state.getValue(prop).equals(value) && value != SlabType.DOUBLE) {
|
|
+ state = state.setValue(prop, value);
|
|
+
|
|
+ if (state.canSurvive(context.getWorld(), context.getPos())) {
|
|
+ oldState = state;
|
|
+ } else {
|
|
+ state = oldState;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ protocolValue >>>= requiredBits;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ } catch (Exception e) {
|
|
+ LeavesLogger.LOGGER.warning("Exception trying to apply placement protocol value");
|
|
+ }
|
|
+
|
|
+ if (state.canSurvive(context.getWorld(), context.getPos())) {
|
|
+ return state;
|
|
+ } else {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static BlockState applyDirectionProperty(BlockState state, UseContext context, DirectionProperty property, int protocolValue) {
|
|
+ Direction facingOrig = state.getValue(property);
|
|
+ Direction facing = facingOrig;
|
|
+ int decodedFacingIndex = (protocolValue & 0xF) >> 1;
|
|
+
|
|
+ if (decodedFacingIndex == 6) {
|
|
+ facing = facing.getOpposite();
|
|
+ } else if (decodedFacingIndex <= 5) {
|
|
+ facing = Direction.from3DDataValue(decodedFacingIndex);
|
|
+
|
|
+ if (!property.getPossibleValues().contains(facing)) {
|
|
+ facing = context.getEntity().getDirection().getOpposite();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (facing != facingOrig && property.getPossibleValues().contains(facing)) {
|
|
+ if (state.getBlock() instanceof BedBlock) {
|
|
+ BlockPos headPos = context.pos.relative(facing);
|
|
+ BlockPlaceContext ctx = context.getItemPlacementContext();
|
|
+
|
|
+ if (ctx == null || !context.getWorld().getBlockState(headPos).canBeReplaced(ctx)) {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ state = state.setValue(property, facing);
|
|
+ }
|
|
+
|
|
+ return state;
|
|
+ }
|
|
+
|
|
+ public static class UseContext {
|
|
+
|
|
+ private final Level world;
|
|
+ private final BlockPos pos;
|
|
+ private final Direction side;
|
|
+ private final Vec3 hitVec;
|
|
+ private final LivingEntity entity;
|
|
+ private final InteractionHand hand;
|
|
+ @Nullable
|
|
+ private final BlockPlaceContext itemPlacementContext;
|
|
+
|
|
+ private UseContext(Level world, BlockPos pos, Direction side, Vec3 hitVec, LivingEntity entity, InteractionHand hand, @Nullable BlockPlaceContext itemPlacementContext) {
|
|
+ this.world = world;
|
|
+ this.pos = pos;
|
|
+ this.side = side;
|
|
+ this.hitVec = hitVec;
|
|
+ this.entity = entity;
|
|
+ this.hand = hand;
|
|
+ this.itemPlacementContext = itemPlacementContext;
|
|
+ }
|
|
+
|
|
+ public static UseContext from(BlockPlaceContext ctx, InteractionHand hand) {
|
|
+ Vec3 pos = ctx.getClickLocation();
|
|
+ return new UseContext(ctx.getLevel(), ctx.getClickedPos(), ctx.getClickedFace(), new Vec3(pos.x, pos.y, pos.z), ctx.getPlayer(), hand, ctx);
|
|
+ }
|
|
+
|
|
+ public Level getWorld() {
|
|
+ return this.world;
|
|
+ }
|
|
+
|
|
+ public BlockPos getPos() {
|
|
+ return this.pos;
|
|
+ }
|
|
+
|
|
+ public Direction getSide() {
|
|
+ return this.side;
|
|
+ }
|
|
+
|
|
+ public Vec3 getHitVec() {
|
|
+ return this.hitVec;
|
|
+ }
|
|
+
|
|
+ public LivingEntity getEntity() {
|
|
+ return this.entity;
|
|
+ }
|
|
+
|
|
+ public InteractionHand getHand() {
|
|
+ return this.hand;
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ public BlockPlaceContext getItemPlacementContext() {
|
|
+ return this.itemPlacementContext;
|
|
+ }
|
|
+ }
|
|
+}
|