Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ org.gradle.jvmargs=-Xmx1G
fabric_api_version=0.100.3+1.21

# Mod Properties
mod_version = 1.4.147
mod_version = 1.4.147-accuratePlacement_v3
maven_group = carpet-extra
archives_base_name = carpet-extra

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ private BlockState getAlternatePlacement(Block block, ItemPlacementContext conte
{
if (CarpetExtraSettings.accurateBlockPlacement)
{
BlockState tryAlternative = BlockPlacer.alternativeBlockPlacement(block, context);
BlockState tryAlternative = BlockPlacer.alternativeBlockPlacementV3(block.getPlacementState(context), BlockPlacer.UseContext.from(context, context.getHand()));
if (tryAlternative != null)
return tryAlternative;
}
return block.getPlacementState(context);
}

}
221 changes: 215 additions & 6 deletions src/main/java/carpetextra/utils/BlockPlacer.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package carpetextra.utils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import com.google.common.collect.ImmutableSet;
import org.jetbrains.annotations.Nullable;
import net.minecraft.block.BedBlock;
import net.minecraft.block.Block;
Expand All @@ -9,22 +13,120 @@
import net.minecraft.block.enums.BlockHalf;
import net.minecraft.block.enums.ComparatorMode;
import net.minecraft.block.enums.SlabType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.state.property.DirectionProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.state.property.Property;
import net.minecraft.util.Hand;
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)
public static final ImmutableSet<Property<?>> WHITELISTED_PROPERTIES = ImmutableSet.of(
Properties.INVERTED,
Properties.OPEN,
Properties.PERSISTENT,
Properties.CAN_SUMMON,
Properties.ATTACHMENT,
Properties.AXIS,
Properties.BED_PART,
Properties.BLOCK_HALF,
Properties.BLOCK_FACE,
Properties.CHEST_TYPE,
Properties.COMPARATOR_MODE,
Properties.DOOR_HINGE,
Properties.DOUBLE_BLOCK_HALF,
Properties.ORIENTATION,
Properties.RAIL_SHAPE,
Properties.STRAIGHT_RAIL_SHAPE,
Properties.SLAB_TYPE,
Properties.STAIR_SHAPE,
Properties.BITES,
Properties.DELAY,
Properties.NOTE,
Properties.ROTATION
);

// Written by masa
public static <T extends Comparable<T>> BlockState alternativeBlockPlacementV3(BlockState state, UseContext context)
{
Vec3d hitPos = context.getHitPos();
BlockPos blockPos = context.getBlockPos();
int protocolValue = (int) (context.getHitVec().x - (double) context.getPos().getX()) - 2;

if (protocolValue < 0)
{
return state;
}

@Nullable DirectionProperty property = getFirstDirectionProperty(state);

if (property != null && property != Properties.VERTICAL_DIRECTION)
{
state = applyDirectionProperty(state, context, property, protocolValue);

if (state == null)
{
return null;
}

// Consume the bits used for the facing
protocolValue >>>= 3;
}
// Consume the lowest unused bit
protocolValue >>>= 1;

List<Property<?>> propList = new ArrayList<>(state.getBlock().getStateManager().getProperties());
propList.sort(Comparator.comparing(Property::getName));

try
{
for (Property<?> p : propList)
{
if ((p instanceof DirectionProperty) == false &&
WHITELISTED_PROPERTIES.contains(p))
{
@SuppressWarnings("unchecked")
Property<T> prop = (Property<T>) p;
List<T> list = new ArrayList<>(prop.getValues());
list.sort(Comparable::compareTo);

int requiredBits = MathHelper.floorLog2(MathHelper.smallestEncompassingPowerOfTwo(list.size()));
int bitMask = ~(0xFFFFFFFF << requiredBits);
int valueIndex = protocolValue & bitMask;

if (valueIndex >= 0 && valueIndex < list.size())
{
T value = list.get(valueIndex);

if (state.get(prop).equals(value) == false &&
value != SlabType.DOUBLE) // don't allow duping slabs by forcing a double slab via the protocol
{
state = state.with(prop, value);
}

protocolValue >>>= requiredBits;
}
}
}
}
catch (Exception e)
{
// Exception
}

return state;
}

public static BlockState alternativeBlockPlacementV2(Block block, UseContext context)
{
Vec3d hitPos = context.getHitVec();
BlockPos blockPos = context.getPos();
double relativeHitX = hitPos.x - blockPos.getX();
BlockState state = block.getPlacementState(context);
BlockState state = block.getPlacementState(context.getItemPlacementContext());

if (relativeHitX < 2 || state == null) // vanilla handling
return null;
Expand All @@ -51,7 +153,7 @@ else if (facingIndex >= 0 && facingIndex <= 5)

if (directionProp.getValues().contains(facing) == false)
{
facing = context.getPlayer().getHorizontalFacing().getOpposite();
facing = context.getEntity().getHorizontalFacing().getOpposite();
}

if (facing != origFacing && directionProp.getValues().contains(facing))
Expand All @@ -60,7 +162,7 @@ else if (facingIndex >= 0 && facingIndex <= 5)
{
BlockPos headPos = blockPos.offset(facing);

if (context.getWorld().getBlockState(headPos).canReplace(context) == false)
if (context.getWorld().getBlockState(headPos).canReplace(context.getItemPlacementContext()) == false)
{
return null;
}
Expand Down Expand Up @@ -110,6 +212,46 @@ else if (state.contains(Properties.SLAB_TYPE) &&
return state;
}

private static BlockState applyDirectionProperty(BlockState state, UseContext context,
DirectionProperty property, int protocolValue)
{
Direction facingOrig = state.get(property);
Direction facing = facingOrig;
int decodedFacingIndex = (protocolValue & 0xF) >> 1;

if (decodedFacingIndex == 6) // the opposite of the normal facing requested
{
facing = facing.getOpposite();
}
else if (decodedFacingIndex >= 0 && decodedFacingIndex <= 5)
{
facing = Direction.byId(decodedFacingIndex);

if (property.getValues().contains(facing) == false)
{
facing = context.getEntity().getHorizontalFacing().getOpposite();
}
}

if (facing != facingOrig && property.getValues().contains(facing))
{
if (state.getBlock() instanceof BedBlock)
{
BlockPos headPos = context.getPos().offset(facing);
ItemPlacementContext ctx = context.getItemPlacementContext();

if (context.getWorld().getBlockState(headPos).canReplace(ctx) == false)
{
return null;
}
}

state = state.with(property, facing);
}

return state;
}

@Nullable
public static DirectionProperty getFirstDirectionProperty(BlockState state)
{
Expand All @@ -123,4 +265,71 @@ public static DirectionProperty getFirstDirectionProperty(BlockState state)

return null;
}

public static class UseContext
{
private final World world;
private final BlockPos pos;
private final Direction side;
private final Vec3d hitVec;
private final LivingEntity entity;
private final Hand hand;
@Nullable
private final ItemPlacementContext itemPlacementContext;

private UseContext(World world, BlockPos pos, Direction side, Vec3d hitVec,
LivingEntity entity, Hand hand, @Nullable ItemPlacementContext 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(ItemPlacementContext ctx, Hand hand)
{
Vec3d pos = ctx.getHitPos();
return new UseContext(ctx.getWorld(), ctx.getBlockPos(), ctx.getSide(), new Vec3d(pos.x, pos.y, pos.z),
ctx.getPlayer(), hand, ctx);
}

public World getWorld()
{
return this.world;
}

public BlockPos getPos()
{
return this.pos;
}

public Direction getSide()
{
return this.side;
}

public Vec3d getHitVec()
{
return this.hitVec;
}

public LivingEntity getEntity()
{
return this.entity;
}

public Hand getHand()
{
return this.hand;
}

@Nullable
public ItemPlacementContext getItemPlacementContext()
{
return this.itemPlacementContext;
}
}
}