Skip to content

Commit

Permalink
fix: #396 #601 #713 also added player to the use context
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelHillcox committed Feb 26, 2023
1 parent 6660c6c commit c29c4cc
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void render(RenderLevelLastEvent evt, Player player, ItemStack heldItem)
List<BlockPos> coordinates = anchor.orElseGet(() -> {
AbstractMode mode = !this.isExchanger ? GadgetBuilding.getToolMode(heldItem).getMode() : GadgetExchanger.getToolMode(heldItem).getMode();
return mode.getCollection(
new AbstractMode.UseContext(player.level, renderBlockState, lookingAt.getBlockPos(), heldItem, lookingAt.getDirection(), !this.isExchanger && GadgetBuilding.shouldPlaceAtop(heldItem), !this.isExchanger ? GadgetBuilding.getConnectedArea(heldItem) : GadgetExchanger.getConnectedArea(heldItem)),
new AbstractMode.UseContext(player.level, player, renderBlockState, lookingAt.getBlockPos(), heldItem, lookingAt.getDirection(), !this.isExchanger && GadgetBuilding.shouldPlaceAtop(heldItem), !this.isExchanger ? GadgetBuilding.getConnectedArea(heldItem) : GadgetExchanger.getConnectedArea(heldItem)),
player
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ private void build(ServerPlayer player, ItemStack stack) {

Direction sideHit = lookingAt.getDirection();
coords = getToolMode(stack).getMode().getCollection(
new AbstractMode.UseContext(world, blockData.getState(), lookingAt.getBlockPos(), heldItem, sideHit, placeAtop(stack), getConnectedArea(stack)),
new AbstractMode.UseContext(world, player, blockData.getState(), lookingAt.getBlockPos(), heldItem, sideHit, placeAtop(stack), getConnectedArea(stack)),
player
);
} else //If we do have an anchor, erase it (Even if the build fails)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ private void exchange(ServerPlayer player, ItemStack stack) {
// Get the anchor or build the collection
Optional<List<BlockPos>> anchor = GadgetUtils.getAnchor(stack);
List<BlockPos> coords = anchor.orElseGet(
() -> getToolMode(stack).getMode().getCollection(new AbstractMode.UseContext(world, blockData.getState(), lookingAt.getBlockPos(), heldItem, lookingAt.getDirection(), getConnectedArea(heldItem)), player)
() -> getToolMode(stack).getMode().getCollection(new AbstractMode.UseContext(world, player, blockData.getState(), lookingAt.getBlockPos(), heldItem, lookingAt.getDirection(), getConnectedArea(heldItem)), player)
);

if (anchor.isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public AbstractMode(boolean isExchanging) {
* method from having to handle the world etc.
*/
public List<BlockPos> getCollection(UseContext context, Player player) {
BlockPos startPos = this.withOffset(context.getStartPos(), context.getHitSide(), context.isPlaceOnTop());
BlockPos startPos = this.withOffset(context);

// We don't need this unless we're using the exchanger but I also don't want to
// have to remake the state for every block.
Expand All @@ -47,7 +47,7 @@ public List<BlockPos> getCollection(UseContext context, Player player) {
// We alternate the validator as the exchanger requires a more in-depth validation process.
return collect(context, player, startPos)
.stream()
.filter(e -> isExchanging ? this.exchangingValidator(e, lookingAtState, context) : this.validator(player, e, context))
.filter(e -> isExchanging ? this.exchangingValidator(e, lookingAtState, context) : this.validator(e, context))
.sorted(Comparator.comparing((BlockPos pos) -> player.blockPosition().distSqr(pos)))
.collect(Collectors.toList());
}
Expand All @@ -58,8 +58,8 @@ public List<BlockPos> getCollection(UseContext context, Player player) {
* @param context the use context instance
* @return if the block is valid
*/
public boolean validator(Player player, BlockPos pos, UseContext context) {
if (!context.getWorldState(pos).canBeReplaced(context.createBlockUseContext(player)))
public boolean validator(BlockPos pos, UseContext context) {
if (!context.getWorldState(pos).canBeReplaced(context.createBlockUseContext()))
return false;

if (context.world.isOutsideBuildHeight(pos))
Expand Down Expand Up @@ -109,8 +109,8 @@ private boolean exchangingValidator(BlockPos pos, BlockState lookingAtState, Use
return hasSingeValid;
}

public BlockPos withOffset(BlockPos pos, Direction side, boolean placeOnTop) {
return placeOnTop ? pos.relative(side, 1) : pos;
public BlockPos withOffset(UseContext context) {
return context.placeOnTop ? context.startPos.relative(context.hitSide, 1) : context.startPos;
}

public boolean isExchanging() {
Expand All @@ -122,17 +122,19 @@ public static class UseContext {
private final BlockState setState;
private final BlockPos startPos;
private final Direction hitSide;
private final Player player;

private final boolean isFuzzy;
private final boolean placeOnTop;
private final int range;
private final boolean rayTraceFluid;
private final boolean isConnected;

public UseContext(Level world, BlockState setState, BlockPos startPos, ItemStack gadget, Direction hitSide, boolean placeOnTop, boolean isConnected) {
public UseContext(Level world, Player player, BlockState setState, BlockPos startPos, ItemStack gadget, Direction hitSide, boolean placeOnTop, boolean isConnected) {
this.world = world;
this.setState = setState;
this.startPos = startPos;
this.player = player;

this.range = GadgetUtils.getToolRange(gadget);
this.isFuzzy = AbstractGadget.getFuzzy(gadget);
Expand All @@ -143,11 +145,11 @@ public UseContext(Level world, BlockState setState, BlockPos startPos, ItemStack
this.placeOnTop = placeOnTop;
}

public UseContext(Level world, BlockState setState, BlockPos startPos, ItemStack gadget, Direction hitSide, boolean isConnected) {
this(world, setState, startPos, gadget, hitSide, false, isConnected);
public UseContext(Level world, Player player, BlockState setState, BlockPos startPos, ItemStack gadget, Direction hitSide, boolean isConnected) {
this(world, player, setState, startPos, gadget, hitSide, false, isConnected);
}

public BlockPlaceContext createBlockUseContext(Player player) {
public BlockPlaceContext createBlockUseContext() {
return new BlockPlaceContext(
new UseOnContext(
player,
Expand Down Expand Up @@ -197,6 +199,10 @@ public Direction getHitSide() {
return this.hitSide;
}

public Player getPlayer() {
return player;
}

@Override
public String toString() {
return "UseContext{" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@
import java.util.ArrayList;
import java.util.List;

/**
* This implementation is pretty complicate due the convenience settings for placement. We do a relative simple math
* equation to start with, stairs are simple, take the look vector, then in a single direction x + 1, then increase the height.
* <p>
* It gets complicated though as we need to support the following options
* - If the player is higher than the target block we should build the stairs in reverse up to the player
* - If the player is looking at the block one under their feet, and we're on a horizontal facing plane, we should build
* outwards away from the facing plain.
* - If we're looking at the top or bottom of a block, we correct the positioning to build as if we were looking at a face
* of a block that wasn't the top or bottom.
*/
public class StairMode extends AbstractMode {
public StairMode() { super(false); }

Expand All @@ -18,24 +29,50 @@ List<BlockPos> collect(UseContext context, Player player, BlockPos start) {
if (XYZ.isAxisY(side))
side = player.getDirection().getOpposite();

XYZ facingXYZ = XYZ.fromFacing(side);
for( int i = 0; i < context.getRange(); i ++ ) {
// Check to see if we should build up or down from the player
int tmp = start.getY() > player.getY() + 1 ? (i + 1) * -1 : i;
var hitSide = context.getHitSide();
int shiftAxis = (i + 1) * (hitSide == Direction.EAST || hitSide == Direction.SOUTH ? 1 : -1);

if( facingXYZ == XYZ.X )
coordinates.add(new BlockPos(start.getX() + (tmp * (side == Direction.EAST ? -1 : 1)), start.getY() + tmp, start.getZ()));
// Special case for looking at block under your feet and looking at the horizontal axis
if (context.getStartPos().getY() < player.getY() && hitSide.getAxis().isHorizontal()) {
boolean mutateXAxis = hitSide.getAxis() == Direction.Axis.X;
boolean mutateZAxis = hitSide.getAxis() == Direction.Axis.Z;

if( facingXYZ == XYZ.Z )
coordinates.add(new BlockPos(start.getX(), start.getY() + tmp, start.getZ() + (tmp * (side == Direction.SOUTH ? -1 : 1))));
coordinates.add(context.getStartPos().offset(
mutateXAxis ? shiftAxis : 0, // If we're hitting at the X axis we should shift it
context.isPlaceOnTop() ? -i : -(i + 1), // If place on top is on, we should place aside the block, otherwise, in the current one
mutateZAxis ? shiftAxis : 0 // If we're hitting at the Z axis we should shift the Z axis of the block.
));

continue;
}

shiftAxis = i * (side == Direction.EAST || side == Direction.SOUTH ? -1 : 1);
if (start.getY() < player.getY() - 2) {
shiftAxis = shiftAxis * -1;
}

coordinates.add(start.offset(
side.getAxis() == Direction.Axis.X ? shiftAxis : 0,
start.getY() > (player.getY() + 1) ? i * -1 : i, // Check to see if we should build up or down from the player
side.getAxis() == Direction.Axis.Z ? shiftAxis : 0
));
}

return coordinates;
}

@Override
public BlockPos withOffset(BlockPos pos, Direction side, boolean placeOnTop) {
public BlockPos withOffset(UseContext context) {
var side = context.getHitSide();
var placeOnTop = context.isPlaceOnTop();
var pos = context.getStartPos();

// Is top / bottom? Do as normal. Not? then place on top or inside :D
return XYZ.isAxisY(side) ? super.withOffset(pos, side, placeOnTop) : (placeOnTop ? pos.relative(Direction.UP) : pos);
if (side == Direction.DOWN) {
return placeOnTop ? pos.relative(side, 1) : pos;
}

return XYZ.isAxisY(side) ? super.withOffset(context) : (placeOnTop ? pos.relative(Direction.UP) : pos);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ List<BlockPos> collect(UseContext context, Player player, BlockPos start) {
}

@Override
public boolean validator(Player player, BlockPos pos, UseContext context) {
public boolean validator(BlockPos pos, UseContext context) {
// Do our default checks, then do our more complex fuzzy aware checks.
boolean topRow = super.validator(player, pos, context);
boolean topRow = super.validator(pos, context);
if( this.isExchanging() )
return topRow;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ List<BlockPos> collect(UseContext context, Player player, BlockPos start) {
* and ignore placeOnTop as this mode does the action by default.
*/
@Override
public BlockPos withOffset(BlockPos pos, Direction side, boolean placeOnTop) {
return XYZ.isAxisY(side) ? super.withOffset(pos, side, placeOnTop) : pos;
public BlockPos withOffset(UseContext context) {
return XYZ.isAxisY(context.getHitSide()) ? super.withOffset(context) : context.getStartPos();
}
}

Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.direwolf20.buildinggadgets.common.items.modes;

import net.minecraft.world.entity.player.Player;
import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -59,7 +58,7 @@ List<BlockPos> collect(UseContext context, Player player, BlockPos start) {
* and ignore placeOnTop as this mode does the action by default.
*/
@Override
public BlockPos withOffset(BlockPos pos, Direction side, boolean placeOnTop) {
return XYZ.isAxisY(side) ? super.withOffset(pos, side, placeOnTop) : pos;
public BlockPos withOffset(UseContext context) {
return XYZ.isAxisY(context.getHitSide()) ? super.withOffset(context) : context.getStartPos();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ public static boolean anchorBlocks(Player player, ItemStack stack) {
return false;

BlockData blockData = getToolBlock(stack);
AbstractMode.UseContext context = new AbstractMode.UseContext(player.level, blockData.getState(), startBlock, stack, sideHit, stack.getItem() instanceof GadgetBuilding && GadgetBuilding.shouldPlaceAtop(stack), stack.getItem() instanceof GadgetBuilding ? GadgetBuilding.getConnectedArea(stack) : GadgetExchanger.getConnectedArea(stack));
AbstractMode.UseContext context = new AbstractMode.UseContext(player.level, player, blockData.getState(), startBlock, stack, sideHit, stack.getItem() instanceof GadgetBuilding && GadgetBuilding.shouldPlaceAtop(stack), stack.getItem() instanceof GadgetBuilding ? GadgetBuilding.getConnectedArea(stack) : GadgetExchanger.getConnectedArea(stack));

List<BlockPos> coords = stack.getItem() instanceof GadgetBuilding
? GadgetBuilding.getToolMode(stack).getMode().getCollection(context, player)
Expand Down

0 comments on commit c29c4cc

Please sign in to comment.