mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 07:27:15 +01:00
Assisted Placement, Part I
- refactor existing placement helpers - add placement helpers for cogs and shafts
This commit is contained in:
parent
743d303bbe
commit
e950aa268f
15 changed files with 666 additions and 308 deletions
|
@ -1,28 +1,21 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.bearing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.foundation.block.ProperDirectionalBlock;
|
||||
import com.simibubi.create.foundation.utility.DyeHelper;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
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.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.BlockItemUseContext;
|
||||
import net.minecraft.item.DyeColor;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ShearsItem;
|
||||
import net.minecraft.item.*;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
|
@ -35,6 +28,13 @@ import net.minecraft.util.math.shapes.VoxelShape;
|
|||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class SailBlock extends ProperDirectionalBlock {
|
||||
|
||||
public static SailBlock frame(Properties properties) {
|
||||
|
@ -45,7 +45,9 @@ public class SailBlock extends ProperDirectionalBlock {
|
|||
return new SailBlock(properties, false);
|
||||
}
|
||||
|
||||
private boolean frame;
|
||||
private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper());
|
||||
|
||||
private final boolean frame;
|
||||
|
||||
protected SailBlock(Properties p_i48415_1_, boolean frame) {
|
||||
super(p_i48415_1_);
|
||||
|
@ -55,27 +57,27 @@ public class SailBlock extends ProperDirectionalBlock {
|
|||
@Override
|
||||
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
||||
BlockState state = super.getStateForPlacement(context);
|
||||
return state.with(FACING, state.get(FACING)
|
||||
.getOpposite());
|
||||
return state.with(FACING, state.get(FACING).getOpposite());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand,
|
||||
BlockRayTraceResult ray) {
|
||||
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult ray) {
|
||||
ItemStack heldItem = player.getHeldItem(hand);
|
||||
|
||||
if (AllBlocks.SAIL.isIn(heldItem) || AllBlocks.SAIL_FRAME.isIn(heldItem)) {
|
||||
Direction offset =
|
||||
SailBlockPlacementHelper.getPlacementOffset(world, state.get(FACING), pos, ray.getHitVec());
|
||||
if (offset == null)
|
||||
return ActionResultType.SUCCESS;
|
||||
IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId);
|
||||
PlacementOffset offset = placementHelper.getOffset(world, state, pos, ray);
|
||||
|
||||
if (!offset.isSuccessful())
|
||||
return ActionResultType.PASS;
|
||||
|
||||
BlockState blockState = ((BlockItem) heldItem.getItem()).getBlock()
|
||||
.getDefaultState()
|
||||
.with(FACING, state.get(FACING));
|
||||
BlockPos offsetPos = pos.offset(offset);
|
||||
.getDefaultState()
|
||||
.with(FACING, state.get(FACING));
|
||||
BlockPos offsetPos = new BlockPos(offset.getPos());
|
||||
if (!world.isRemote && world.getBlockState(offsetPos)
|
||||
.getMaterial()
|
||||
.isReplaceable()) {
|
||||
.getMaterial()
|
||||
.isReplaceable()) {
|
||||
world.setBlockState(offsetPos, blockState);
|
||||
if (!player.isCreative())
|
||||
heldItem.shrink(1);
|
||||
|
@ -94,7 +96,7 @@ public class SailBlock extends ProperDirectionalBlock {
|
|||
|
||||
for (DyeColor color : DyeColor.values()) {
|
||||
if (!heldItem.getItem()
|
||||
.isIn(DyeHelper.getTagOfDye(color)))
|
||||
.isIn(DyeHelper.getTagOfDye(color)))
|
||||
continue;
|
||||
if (!world.isRemote)
|
||||
applyDye(state, world, pos, color);
|
||||
|
@ -106,8 +108,8 @@ public class SailBlock extends ProperDirectionalBlock {
|
|||
|
||||
protected void applyDye(BlockState state, World world, BlockPos pos, @Nullable DyeColor color) {
|
||||
BlockState newState =
|
||||
(color == null ? AllBlocks.SAIL_FRAME : AllBlocks.DYED_SAILS[color.ordinal()]).getDefaultState()
|
||||
.with(FACING, state.get(FACING));
|
||||
(color == null ? AllBlocks.SAIL_FRAME : AllBlocks.DYED_SAILS[color.ordinal()]).getDefaultState()
|
||||
.with(FACING, state.get(FACING));
|
||||
|
||||
// Dye the block itself
|
||||
if (state != newState) {
|
||||
|
@ -118,7 +120,7 @@ public class SailBlock extends ProperDirectionalBlock {
|
|||
// Dye all adjacent
|
||||
for (Direction d : Iterate.directions) {
|
||||
if (d.getAxis() == state.get(FACING)
|
||||
.getAxis())
|
||||
.getAxis())
|
||||
continue;
|
||||
BlockPos offset = pos.offset(d);
|
||||
BlockState adjacentState = world.getBlockState(offset);
|
||||
|
@ -145,7 +147,7 @@ public class SailBlock extends ProperDirectionalBlock {
|
|||
|
||||
for (Direction d : Iterate.directions) {
|
||||
if (d.getAxis() == state.get(FACING)
|
||||
.getAxis())
|
||||
.getAxis())
|
||||
continue;
|
||||
BlockPos offset = currentPos.offset(d);
|
||||
if (visited.contains(offset))
|
||||
|
@ -163,26 +165,23 @@ public class SailBlock extends ProperDirectionalBlock {
|
|||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_,
|
||||
ISelectionContext p_220053_4_) {
|
||||
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_, ISelectionContext p_220053_4_) {
|
||||
return (frame ? AllShapes.SAIL_FRAME : AllShapes.SAIL).get(state.get(FACING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, IBlockReader p_220071_2_, BlockPos p_220071_3_,
|
||||
ISelectionContext p_220071_4_) {
|
||||
public VoxelShape getCollisionShape(BlockState state, IBlockReader p_220071_2_, BlockPos p_220071_3_, ISelectionContext p_220071_4_) {
|
||||
if (frame)
|
||||
return AllShapes.SAIL_FRAME_COLLISION.get(state.get(FACING));
|
||||
return getShape(state, p_220071_2_, p_220071_3_, p_220071_4_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getPickBlock(BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos,
|
||||
PlayerEntity player) {
|
||||
public ItemStack getPickBlock(BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos, PlayerEntity player) {
|
||||
ItemStack pickBlock = super.getPickBlock(state, target, world, pos, player);
|
||||
if (pickBlock.isEmpty())
|
||||
return AllBlocks.SAIL.get()
|
||||
.getPickBlock(state, target, world, pos, player);
|
||||
.getPickBlock(state, target, world, pos, player);
|
||||
return pickBlock;
|
||||
}
|
||||
|
||||
|
@ -209,4 +208,32 @@ public class SailBlock extends ProperDirectionalBlock {
|
|||
|
||||
}
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
private static class PlacementHelper implements IPlacementHelper {
|
||||
@Override
|
||||
public Predicate<ItemStack> getItemPredicate() {
|
||||
return i -> AllBlocks.SAIL.isIn(i) || AllBlocks.SAIL_FRAME.isIn(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<BlockState> getStatePredicate() {
|
||||
return s -> s.getBlock() instanceof SailBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) {
|
||||
List<Direction> directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getHitVec(), state.get(SailBlock.FACING).getAxis(), dir -> world.getBlockState(pos.offset(dir)).getMaterial().isReplaceable());
|
||||
|
||||
if (directions.isEmpty())
|
||||
return PlacementOffset.fail();
|
||||
else {
|
||||
return PlacementOffset.success(pos.offset(directions.get(0)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), state.get(FACING));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.bearing;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.player.ClientPlayerEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
public class SailBlockPlacementHelper {
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void tick() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
RayTraceResult objectMouseOver = mc.objectMouseOver;
|
||||
ClientWorld world = mc.world;
|
||||
ClientPlayerEntity player = mc.player;
|
||||
if (!(objectMouseOver instanceof BlockRayTraceResult))
|
||||
return;
|
||||
BlockRayTraceResult ray = (BlockRayTraceResult) objectMouseOver;
|
||||
if (!isHoldingSail(player))
|
||||
return;
|
||||
BlockPos pos = ray.getPos();
|
||||
BlockState blockState = world.getBlockState(pos);
|
||||
if (!(blockState.getBlock() instanceof SailBlock))
|
||||
return;
|
||||
|
||||
Direction sailFacing = blockState.get(SailBlock.FACING);
|
||||
Direction offset = getPlacementOffset(world, sailFacing, pos, ray.getHitVec());
|
||||
if (offset == null)
|
||||
return;
|
||||
|
||||
Vec3d centerOf = VecHelper.getCenterOf(pos);
|
||||
Vec3d offsetVec = new Vec3d(offset.getDirectionVec());
|
||||
|
||||
if (!world.getBlockState(pos.offset(offset))
|
||||
.getMaterial()
|
||||
.isReplaceable())
|
||||
return;
|
||||
|
||||
for (Direction caretDirection : Iterate.directions) {
|
||||
if (caretDirection.getAxis() == offset.getAxis())
|
||||
continue;
|
||||
if (caretDirection.getAxis() == sailFacing.getAxis())
|
||||
continue;
|
||||
|
||||
Vec3d otherOffset = new Vec3d(caretDirection.getDirectionVec()).scale(.25f);
|
||||
Vec3d start = offsetVec.scale(.75f)
|
||||
.add(otherOffset);
|
||||
Vec3d target = centerOf.add(offsetVec);
|
||||
CreateClient.outliner.showLine("sailHelp" + caretDirection, centerOf.add(start), target)
|
||||
.lineWidth(1 / 16f);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public static boolean isHoldingSail(PlayerEntity player) {
|
||||
for (Hand hand : Hand.values()) {
|
||||
ItemStack heldItem = player.getHeldItem(hand);
|
||||
if (AllBlocks.SAIL.isIn(heldItem) || AllBlocks.SAIL_FRAME.isIn(heldItem))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Direction getPlacementOffset(World world, Direction sailDirection, BlockPos pos, Vec3d hit) {
|
||||
Direction argMin = null;
|
||||
float min = Float.MAX_VALUE;
|
||||
Vec3d diffFromCentre = hit.subtract(VecHelper.getCenterOf(pos));
|
||||
for (Direction side : Iterate.directions) {
|
||||
if (side.getAxis() == sailDirection.getAxis())
|
||||
continue;
|
||||
if (!world.getBlockState(pos.offset(side))
|
||||
.getMaterial()
|
||||
.isReplaceable())
|
||||
continue;
|
||||
float distance = (float) new Vec3d(side.getDirectionVec()).distanceTo(diffFromCentre);
|
||||
if (distance > min)
|
||||
continue;
|
||||
min = distance;
|
||||
argMin = side;
|
||||
}
|
||||
return argMin;
|
||||
}
|
||||
|
||||
}
|
|
@ -77,7 +77,7 @@ public class PistonContraption extends TranslatingContraption {
|
|||
return false;
|
||||
|
||||
if (blockState.get(MechanicalPistonBlock.STATE) == PistonState.EXTENDED) {
|
||||
while (PistonPolePlacementHelper.matchesAxis(nextBlock, direction.getAxis()) || isPistonHead(nextBlock) && nextBlock.get(FACING) == direction) {
|
||||
while (PistonExtensionPoleBlock.PlacementHelper.get().matchesAxis(nextBlock, direction.getAxis()) || isPistonHead(nextBlock) && nextBlock.get(FACING) == direction) {
|
||||
|
||||
actualStart = actualStart.offset(direction);
|
||||
poles.add(new BlockInfo(actualStart, nextBlock.with(FACING, direction), null));
|
||||
|
@ -104,7 +104,7 @@ public class PistonContraption extends TranslatingContraption {
|
|||
nextBlock = world.getBlockState(end.offset(direction.getOpposite()));
|
||||
int extensionsInBack = 0;
|
||||
|
||||
while (PistonPolePlacementHelper.matchesAxis(nextBlock, direction.getAxis())) {
|
||||
while (PistonExtensionPoleBlock.PlacementHelper.get().matchesAxis(nextBlock, direction.getAxis())) {
|
||||
end = end.offset(direction.getOpposite());
|
||||
poles.add(new BlockInfo(end, nextBlock.with(FACING, direction), null));
|
||||
extensionsInBack++;
|
||||
|
|
|
@ -5,7 +5,11 @@ import com.simibubi.create.AllShapes;
|
|||
import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*;
|
||||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||
import com.simibubi.create.foundation.block.ProperDirectionalBlock;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
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 com.simibubi.create.foundation.utility.placement.util.PoleHelper;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.IWaterLoggable;
|
||||
|
@ -30,10 +34,14 @@ import net.minecraft.world.IBlockReader;
|
|||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*;
|
||||
|
||||
public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements IWrenchable, IWaterLoggable {
|
||||
|
||||
private static final int placementHelperId = PlacementHelpers.register(PlacementHelper.get());
|
||||
|
||||
public PistonExtensionPoleBlock(Properties properties) {
|
||||
super(properties);
|
||||
setDefaultState(getDefaultState().with(FACING, Direction.UP).with(BlockStateProperties.WATERLOGGED, false));
|
||||
|
@ -107,12 +115,13 @@ public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements
|
|||
ItemStack heldItem = player.getHeldItem(hand);
|
||||
|
||||
if (AllBlocks.PISTON_EXTENSION_POLE.isIn(heldItem) && !player.isSneaking()) {
|
||||
Pair<Direction, Integer> offset = PistonPolePlacementHelper.getPlacementOffset(world, state.get(FACING).getAxis(), pos, ray.getHitVec());
|
||||
IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId);
|
||||
PlacementOffset offset = placementHelper.getOffset(world, state, pos, ray);
|
||||
|
||||
if (offset == null || offset.getSecond() == 0)
|
||||
if (!offset.isSuccessful())
|
||||
return ActionResultType.PASS;
|
||||
|
||||
BlockPos newPos = pos.offset(offset.getFirst(), offset.getSecond());
|
||||
BlockPos newPos = new BlockPos(offset.getPos());
|
||||
|
||||
if (!world.getBlockState(newPos).getMaterial().isReplaceable())
|
||||
return ActionResultType.PASS;
|
||||
|
@ -120,7 +129,7 @@ public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements
|
|||
if (world.isRemote)
|
||||
return ActionResultType.SUCCESS;
|
||||
|
||||
world.setBlockState(newPos, AllBlocks.PISTON_EXTENSION_POLE.getDefaultState().with(FACING, state.get(FACING)));
|
||||
world.setBlockState(newPos, offset.getTransform().apply(AllBlocks.PISTON_EXTENSION_POLE.getDefaultState()));
|
||||
if (!player.isCreative())
|
||||
heldItem.shrink(1);
|
||||
|
||||
|
@ -149,4 +158,27 @@ public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements
|
|||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
public static class PlacementHelper extends PoleHelper<Direction> {
|
||||
|
||||
private static final PlacementHelper instance = new PlacementHelper();
|
||||
|
||||
public static PlacementHelper get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private PlacementHelper(){
|
||||
super(
|
||||
AllBlocks.PISTON_EXTENSION_POLE::has,
|
||||
state -> state.get(FACING).getAxis(),
|
||||
FACING
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<ItemStack> getItemPredicate() {
|
||||
return AllBlocks.PISTON_EXTENSION_POLE::isIn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.piston;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class PistonPolePlacementHelper {
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void tick() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
ClientWorld world = mc.world;
|
||||
|
||||
if (!(mc.objectMouseOver instanceof BlockRayTraceResult))
|
||||
return;
|
||||
|
||||
BlockRayTraceResult ray = (BlockRayTraceResult) mc.objectMouseOver;
|
||||
|
||||
if (mc.player != null && !isHoldingPole(mc.player))
|
||||
return;
|
||||
|
||||
if (mc.player.isSneaking())
|
||||
return;
|
||||
|
||||
BlockPos pos = ray.getPos();
|
||||
BlockState state = world.getBlockState(pos);
|
||||
if (!(state.getBlock() instanceof PistonExtensionPoleBlock))
|
||||
return;
|
||||
|
||||
Pair<Direction, Integer> offset = getPlacementOffset(world, state.get(PistonExtensionPoleBlock.FACING).getAxis(), pos, ray.getHitVec());
|
||||
if (offset == null || offset.getSecond() == 0)
|
||||
return;
|
||||
|
||||
Direction hitFace = ray.getFace();
|
||||
|
||||
if (hitFace.getAxis() == offset.getFirst().getAxis())
|
||||
return;
|
||||
|
||||
Vec3d hitCenter = VecHelper.getCenterOf(pos).add(new Vec3d(hitFace.getDirectionVec()).scale(0.3));
|
||||
|
||||
//get the two perpendicular directions to form the arrow
|
||||
Direction[] directions = Arrays.stream(Direction.Axis.values()).filter(axis -> axis != hitFace.getAxis() && axis != offset.getFirst().getAxis()).map(Iterate::directionsInAxis).findFirst().orElse(new Direction[]{});
|
||||
Vec3d startOffset = new Vec3d(offset.getFirst().getDirectionVec());
|
||||
Vec3d start = hitCenter.add(startOffset);
|
||||
for (Direction dir : directions) {
|
||||
Vec3d arrowOffset = new Vec3d(dir.getDirectionVec()).scale(.25);
|
||||
Vec3d target = hitCenter.add(startOffset.scale(0.75)).add(arrowOffset);
|
||||
CreateClient.outliner.showLine("poleHelp" + offset.getFirst() + dir, start, target).lineWidth(1/16f);
|
||||
}
|
||||
}
|
||||
|
||||
// first indicates the direction that the position needs to be offset into
|
||||
// second indicates by how many blocks the position needs to be offset by; is 0 if there was no valid position on either end of the pole
|
||||
public static Pair<Direction, Integer> getPlacementOffset(World world, Direction.Axis poleAxis, BlockPos pos, Vec3d hit) {
|
||||
Pair<Direction, Integer> offset = null;
|
||||
double min = Double.MAX_VALUE;
|
||||
Vec3d localPos = hit.subtract(VecHelper.getCenterOf(pos));
|
||||
|
||||
//find target direction
|
||||
for (Direction dir : Iterate.directionsInAxis(poleAxis)) {
|
||||
double distance = new Vec3d(dir.getDirectionVec()).distanceTo(localPos);
|
||||
if (distance > min)
|
||||
continue;
|
||||
min = distance;
|
||||
offset = Pair.of(dir, 0);
|
||||
}
|
||||
|
||||
if (offset == null)//??
|
||||
return null;
|
||||
|
||||
//check for space at the end of the pole
|
||||
int poles = attachedPoles(world, pos, offset.getFirst());
|
||||
BlockState state = world.getBlockState(pos.offset(offset.getFirst(), poles + 1));
|
||||
|
||||
if (state.getMaterial().isReplaceable()) {
|
||||
offset.setSecond(poles + 1);
|
||||
return offset;
|
||||
}
|
||||
|
||||
//check the other end of the pole
|
||||
offset.setFirst(offset.getFirst().getOpposite());
|
||||
poles = attachedPoles(world, pos, offset.getFirst());
|
||||
state = world.getBlockState(pos.offset(offset.getFirst(), poles + 1));
|
||||
|
||||
if (state.getMaterial().isReplaceable()) {
|
||||
offset.setSecond(poles + 1);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
public static int attachedPoles(World world, BlockPos pos, Direction direction) {
|
||||
BlockPos checkPos = pos.offset(direction);
|
||||
BlockState state = world.getBlockState(checkPos);
|
||||
int count = 0;
|
||||
while (matchesAxis(state, direction.getAxis())) {
|
||||
count++;
|
||||
checkPos = checkPos.offset(direction);
|
||||
state = world.getBlockState(checkPos);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//checks if the given state is a piston pole on the given axis
|
||||
public static boolean matchesAxis(BlockState state, Direction.Axis axis) {
|
||||
return AllBlocks.PISTON_EXTENSION_POLE.has(state) && state.get(PistonExtensionPoleBlock.FACING).getAxis() == axis;
|
||||
}
|
||||
|
||||
public static boolean isHoldingPole(PlayerEntity player) {
|
||||
return Arrays.stream(Hand.values()).anyMatch(hand -> AllBlocks.PISTON_EXTENSION_POLE.isIn(player.getHeldItem(hand)));
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,6 @@ import com.simibubi.create.AllItems;
|
|||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.piston.PistonExtensionPoleBlock;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.piston.PistonPolePlacementHelper;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.gui.GuiGameElement;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBox;
|
||||
|
@ -14,7 +13,6 @@ import com.simibubi.create.foundation.utility.Iterate;
|
|||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.foundation.utility.outliner.Outline;
|
||||
import com.simibubi.create.foundation.utility.outliner.Outliner.OutlineEntry;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
|
@ -106,7 +104,7 @@ public class GoggleOverlayRenderer {
|
|||
int poles = 1;
|
||||
boolean pistonFound = false;
|
||||
for (Direction dir : directions) {
|
||||
int attachedPoles = PistonPolePlacementHelper.attachedPoles(world, pos, dir);
|
||||
int attachedPoles = PistonExtensionPoleBlock.PlacementHelper.get().attachedPoles(world, pos, dir);
|
||||
poles += attachedPoles;
|
||||
pistonFound |= world.getBlockState(pos.offset(dir, attachedPoles + 1))
|
||||
.getBlock() instanceof MechanicalPistonBlock;
|
||||
|
|
|
@ -5,7 +5,6 @@ import com.simibubi.create.AllShapes;
|
|||
import com.simibubi.create.content.contraptions.base.IRotate;
|
||||
import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerBlock;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
|
@ -69,9 +68,7 @@ public class CogWheelBlock extends AbstractShaftBlock {
|
|||
|
||||
@Override
|
||||
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
||||
BlockPos placedOnPos = context.getPos()
|
||||
.offset(context.getFace()
|
||||
.getOpposite());
|
||||
BlockPos placedOnPos = context.getPos().offset(context.getFace().getOpposite());
|
||||
World world = context.getWorld();
|
||||
BlockState placedAgainst = world.getBlockState(placedOnPos);
|
||||
Block block = placedAgainst.getBlock();
|
||||
|
@ -80,7 +77,8 @@ public class CogWheelBlock extends AbstractShaftBlock {
|
|||
.down());
|
||||
IFluidState ifluidstate = context.getWorld().getFluidState(context.getPos());
|
||||
if (AllBlocks.ROTATION_SPEED_CONTROLLER.has(stateBelow) && isLarge) {
|
||||
return this.getDefaultState().with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER))
|
||||
return this.getDefaultState()
|
||||
.with(BlockStateProperties.WATERLOGGED, ifluidstate.getFluid() == Fluids.WATER)
|
||||
.with(AXIS, stateBelow.get(SpeedControllerBlock.HORIZONTAL_AXIS) == Axis.X ? Axis.Z : Axis.X);
|
||||
}
|
||||
|
||||
|
@ -89,10 +87,11 @@ public class CogWheelBlock extends AbstractShaftBlock {
|
|||
Axis preferredAxis = getPreferredAxis(context);
|
||||
if (preferredAxis != null)
|
||||
return this.getDefaultState()
|
||||
.with(AXIS, preferredAxis).with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
|
||||
.with(AXIS, preferredAxis)
|
||||
.with(BlockStateProperties.WATERLOGGED, ifluidstate.getFluid() == Fluids.WATER);
|
||||
return this.getDefaultState()
|
||||
.with(AXIS, context.getFace()
|
||||
.getAxis()).with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
|
||||
.with(AXIS, context.getFace().getAxis())
|
||||
.with(BlockStateProperties.WATERLOGGED, ifluidstate.getFluid() == Fluids.WATER);
|
||||
}
|
||||
|
||||
return getDefaultState().with(AXIS, ((IRotate) block).getRotationAxis(placedAgainst));
|
||||
|
|
|
@ -1,38 +1,76 @@
|
|||
package com.simibubi.create.content.contraptions.relays.elementary;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
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.BlockItem;
|
||||
import net.minecraft.item.BlockItemUseContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.Direction.AxisDirection;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock.AXIS;
|
||||
|
||||
public class CogwheelBlockItem extends BlockItem {
|
||||
|
||||
boolean large;
|
||||
|
||||
private final int placementHelperId;
|
||||
|
||||
public CogwheelBlockItem(CogWheelBlock block, Properties builder) {
|
||||
super(block, builder);
|
||||
large = block.isLarge;
|
||||
|
||||
placementHelperId = PlacementHelpers.register(large ? new LargeCogHelper() : new SmallCogHelper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResultType tryPlace(BlockItemUseContext context) {
|
||||
Direction face = context.getFace();
|
||||
BlockPos placedOnPos = context.getPos().offset(face.getOpposite());
|
||||
BlockState placedOnState = context.getWorld().getBlockState(placedOnPos);
|
||||
IPlacementHelper helper = PlacementHelpers.get(placementHelperId);
|
||||
World world = context.getWorld();
|
||||
BlockPos pos = context.getPos().offset(context.getFace().getOpposite());
|
||||
BlockState state = world.getBlockState(pos);
|
||||
|
||||
if (!(placedOnState.getBlock() instanceof CogWheelBlock))
|
||||
if (!helper.getStatePredicate().test(state))
|
||||
return super.tryPlace(context);
|
||||
|
||||
PlacementOffset offset = helper.getOffset(world, state, pos, new BlockRayTraceResult(context.getHitVec(), context.getFace(), pos, true));
|
||||
|
||||
if (!offset.isSuccessful())
|
||||
return super.tryPlace(context);
|
||||
|
||||
BlockPos newPos = new BlockPos(offset.getPos());
|
||||
|
||||
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 (!(placedOnState.getBlock() instanceof CogWheelBlock))
|
||||
return super.tryPlace(context);
|
||||
if (face.getAxis() == placedOnState.get(CogWheelBlock.AXIS))
|
||||
return super.tryPlace(context);
|
||||
|
@ -67,7 +105,7 @@ public class CogwheelBlockItem extends BlockItem {
|
|||
return ActionResultType.FAIL;
|
||||
}
|
||||
|
||||
return super.tryPlace(context);
|
||||
return super.tryPlace(context);*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -107,4 +145,137 @@ public class CogwheelBlockItem extends BlockItem {
|
|||
return super.placeBlock(context, state);
|
||||
}
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
private static class SmallCogHelper extends DiagonalCogHelper {
|
||||
|
||||
@Override
|
||||
public Predicate<ItemStack> getItemPredicate() {
|
||||
return AllBlocks.COGWHEEL::isIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) {
|
||||
if (hitOnShaft(state, ray))
|
||||
return PlacementOffset.fail();
|
||||
|
||||
if (!((CogWheelBlock) state.getBlock()).isLarge) {
|
||||
List<Direction> directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getHitVec(), state.get(AXIS));
|
||||
|
||||
for (Direction dir : directions) {
|
||||
BlockPos newPos = pos.offset(dir);
|
||||
|
||||
if (hasLargeCogwheelNeighbor(world, newPos, state.get(AXIS)))
|
||||
continue;
|
||||
|
||||
if (!world.getBlockState(newPos).getMaterial().isReplaceable())
|
||||
continue;
|
||||
|
||||
return PlacementOffset.success(newPos, s -> s.with(AXIS, state.get(AXIS)));
|
||||
|
||||
}
|
||||
|
||||
return PlacementOffset.fail();
|
||||
}
|
||||
|
||||
return super.getOffset(world, state, pos, ray);
|
||||
}
|
||||
|
||||
@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(AXIS)), ((CogWheelBlock) state.getBlock()).isLarge ? 1.5D : 0.75D);
|
||||
}
|
||||
}
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
private static class LargeCogHelper extends DiagonalCogHelper {
|
||||
|
||||
@Override
|
||||
public Predicate<ItemStack> getItemPredicate() {
|
||||
return AllBlocks.LARGE_COGWHEEL::isIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) {
|
||||
if (hitOnShaft(state, ray))
|
||||
return PlacementOffset.fail();
|
||||
|
||||
if (((CogWheelBlock) state.getBlock()).isLarge) {
|
||||
Direction side = IPlacementHelper.orderedByDistanceOnlyAxis(pos, ray.getHitVec(), state.get(AXIS)).get(0);
|
||||
List<Direction> directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getHitVec(), state.get(AXIS));
|
||||
for (Direction dir : directions) {
|
||||
BlockPos newPos = pos.offset(dir).offset(side);
|
||||
if (!world.getBlockState(newPos).getMaterial().isReplaceable())
|
||||
continue;
|
||||
|
||||
return PlacementOffset.success(newPos, s -> s.with(AXIS, dir.getAxis()));
|
||||
}
|
||||
|
||||
return PlacementOffset.fail();
|
||||
}
|
||||
|
||||
return super.getOffset(world, state, pos, ray);
|
||||
}
|
||||
}
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
private abstract static class DiagonalCogHelper implements IPlacementHelper {
|
||||
|
||||
@Override
|
||||
public Predicate<BlockState> getStatePredicate() {
|
||||
return s -> s.getBlock() instanceof CogWheelBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) {
|
||||
//diagonal gears of different size
|
||||
Direction closest = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getHitVec(), state.get(AXIS)).get(0);
|
||||
List<Direction> directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getHitVec(), state.get(AXIS), d -> d.getAxis() != closest.getAxis());
|
||||
|
||||
for (Direction dir : directions) {
|
||||
BlockPos newPos = pos.offset(dir).offset(closest);
|
||||
if (!world.getBlockState(newPos).getMaterial().isReplaceable())
|
||||
continue;
|
||||
|
||||
if (AllBlocks.COGWHEEL.has(state) && hasSmallCogwheelNeighbor(world, newPos, state.get(AXIS)))
|
||||
continue;
|
||||
|
||||
return PlacementOffset.success(newPos, s -> s.with(AXIS, state.get(AXIS)));
|
||||
}
|
||||
|
||||
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, state.get(AXIS)), 1D);
|
||||
}
|
||||
|
||||
protected boolean hitOnShaft(BlockState state, BlockRayTraceResult ray) {
|
||||
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) {
|
||||
for (Direction dir : Iterate.directions) {
|
||||
if (dir.getAxis() == axis)
|
||||
continue;
|
||||
|
||||
if (AllBlocks.LARGE_COGWHEEL.has(world.getBlockState(pos.offset(dir))))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean hasSmallCogwheelNeighbor(World world, BlockPos pos, Direction.Axis axis) {
|
||||
for (Direction dir : Iterate.directions) {
|
||||
if (dir.getAxis() == axis)
|
||||
continue;
|
||||
|
||||
if (AllBlocks.COGWHEEL.has(world.getBlockState(pos.offset(dir))))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,18 @@ import com.simibubi.create.AllShapes;
|
|||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock;
|
||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||
|
||||
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 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;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
|
@ -18,8 +25,12 @@ import net.minecraft.util.math.shapes.VoxelShape;
|
|||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ShaftBlock extends AbstractShaftBlock {
|
||||
|
||||
private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper());
|
||||
|
||||
public ShaftBlock(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
@ -45,7 +56,7 @@ public class ShaftBlock extends AbstractShaftBlock {
|
|||
|
||||
@Override
|
||||
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand,
|
||||
BlockRayTraceResult p_225533_6_) {
|
||||
BlockRayTraceResult ray) {
|
||||
if (player.isSneaking() || !player.isAllowEdit())
|
||||
return ActionResultType.PASS;
|
||||
|
||||
|
@ -66,6 +77,52 @@ public class ShaftBlock extends AbstractShaftBlock {
|
|||
return ActionResultType.SUCCESS;
|
||||
}
|
||||
|
||||
IPlacementHelper helper = PlacementHelpers.get(placementHelperId);
|
||||
if (helper.getItemPredicate().test(heldItem)) {
|
||||
PlacementOffset offset = helper.getOffset(world, state, pos, ray);
|
||||
|
||||
if (!offset.isSuccessful())
|
||||
return ActionResultType.PASS;
|
||||
|
||||
BlockPos newPos = new BlockPos(offset.getPos());
|
||||
|
||||
if (!world.getBlockState(newPos).getMaterial().isReplaceable())
|
||||
return ActionResultType.PASS;
|
||||
|
||||
if (world.isRemote)
|
||||
return ActionResultType.SUCCESS;
|
||||
|
||||
Block block = ((BlockItem) heldItem.getItem()).getBlock();
|
||||
world.setBlockState(newPos, offset.getTransform().apply(block.getDefaultState()));
|
||||
if (!player.isCreative())
|
||||
heldItem.shrink(1);
|
||||
|
||||
return ActionResultType.SUCCESS;
|
||||
}
|
||||
|
||||
return ActionResultType.PASS;
|
||||
}
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
private static class PlacementHelper extends PoleHelper<Direction.Axis> {
|
||||
//used for extending a shaft in its axis, like the piston poles. works with shafts and cogs
|
||||
|
||||
private PlacementHelper(){
|
||||
super(
|
||||
state -> state.getBlock() instanceof AbstractShaftBlock,
|
||||
state -> state.get(AXIS),
|
||||
AXIS
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<ItemStack> getItemPredicate() {
|
||||
return i -> i.getItem() instanceof BlockItem && ((BlockItem) i.getItem()).getBlock() instanceof AbstractShaftBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<BlockState> getStatePredicate() {
|
||||
return AllBlocks.SHAFT::has;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
package com.simibubi.create.events;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.simibubi.create.AllFluids;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.contraptions.KineticDebugger;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.SailBlockPlacementHelper;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisRangeDisplay;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.piston.PistonPolePlacementHelper;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandlerClient;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingPhysics;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingRenderer;
|
||||
|
@ -36,7 +31,7 @@ import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkRenderer;
|
|||
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueRenderer;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
|
||||
|
||||
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
|
@ -61,6 +56,9 @@ import net.minecraftforge.event.world.WorldEvent;
|
|||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@EventBusSubscriber(value = Dist.CLIENT)
|
||||
public class ClientEvents {
|
||||
|
||||
|
@ -103,8 +101,7 @@ public class ClientEvents {
|
|||
ExtendoGripRenderHandler.tick();
|
||||
// CollisionDebugger.tick();
|
||||
ArmInteractionPointHandler.tick();
|
||||
SailBlockPlacementHelper.tick();
|
||||
PistonPolePlacementHelper.tick();
|
||||
PlacementHelpers.tick();
|
||||
CreateClient.outliner.tickOutlines();
|
||||
}
|
||||
|
||||
|
@ -137,8 +134,8 @@ public class ClientEvents {
|
|||
return;
|
||||
|
||||
onRenderHotbar(new MatrixStack(), Minecraft.getInstance()
|
||||
.getBufferBuilders()
|
||||
.getEntityVertexConsumers(), 0xF000F0, OverlayTexture.DEFAULT_UV);
|
||||
.getBufferBuilders()
|
||||
.getEntityVertexConsumers(), 0xF000F0, OverlayTexture.DEFAULT_UV);
|
||||
}
|
||||
|
||||
public static void onRenderHotbar(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) {
|
||||
|
@ -154,7 +151,7 @@ public class ClientEvents {
|
|||
|
||||
ItemStack stack = event.getItemStack();
|
||||
String translationKey = stack.getItem()
|
||||
.getTranslationKey(stack);
|
||||
.getTranslationKey(stack);
|
||||
if (!translationKey.startsWith(itemPrefix) && !translationKey.startsWith(blockPrefix))
|
||||
return;
|
||||
|
||||
|
@ -163,7 +160,7 @@ public class ClientEvents {
|
|||
List<ITextComponent> toolTip = new ArrayList<>();
|
||||
toolTip.add(itemTooltip.remove(0));
|
||||
TooltipHelper.getTooltip(stack)
|
||||
.addInformation(toolTip);
|
||||
.addInformation(toolTip);
|
||||
itemTooltip.addAll(0, toolTip);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import net.minecraft.util.Direction.Axis;
|
|||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
public class Iterate {
|
||||
|
@ -15,6 +16,7 @@ public class Iterate {
|
|||
public static final Direction[] directions = Direction.values();
|
||||
public static final Direction[] horizontalDirections = getHorizontals();
|
||||
public static final Axis[] axes = Axis.values();
|
||||
public static final EnumSet<Direction.Axis> axisSet = EnumSet.allOf(Direction.Axis.class);
|
||||
|
||||
private static Direction[] getHorizontals() {
|
||||
Direction[] directions = new Direction[4];
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
package com.simibubi.create.foundation.utility.placement;
|
||||
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
public interface IPlacementHelper {
|
||||
|
||||
/**
|
||||
* @return a predicate that gets tested with the items held in the players hands,
|
||||
* should return true if this placement helper is active with the given item
|
||||
*/
|
||||
Predicate<ItemStack> getItemPredicate();
|
||||
|
||||
/**
|
||||
* @return a predicate that gets tested with the blockstate the player is looking at
|
||||
* should return true if this placement helper is active with the given blockstate
|
||||
*/
|
||||
Predicate<BlockState> getStatePredicate();
|
||||
|
||||
/**
|
||||
* @return PlacementOffset.fail() if no valid offset could be found.
|
||||
* PlacementOffset.success(newPos) with newPos being the new position the block should be placed at
|
||||
*/
|
||||
PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray);
|
||||
|
||||
//only gets called when placementOffset is successful
|
||||
default void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos), VecHelper.getCenterOf(offset.getPos()), ray.getFace());
|
||||
}
|
||||
|
||||
static void renderArrow(Vec3d center, Vec3d target, Direction arrowPlane) {
|
||||
renderArrow(center, target, arrowPlane, 1D);
|
||||
}
|
||||
static void renderArrow(Vec3d center, Vec3d target, Direction arrowPlane, double distanceFromCenter) {
|
||||
Vec3d direction = target.subtract(center).normalize();
|
||||
Vec3d facing = new Vec3d(arrowPlane.getDirectionVec());
|
||||
Vec3d start = center.add(direction);
|
||||
Vec3d offset = direction.scale(distanceFromCenter-1);
|
||||
Vec3d offsetA = direction.crossProduct(facing).normalize().scale(.25);
|
||||
Vec3d offsetB = facing.crossProduct(direction).normalize().scale(.25);
|
||||
Vec3d endA = center.add(direction.scale(.75)).add(offsetA);
|
||||
Vec3d endB = center.add(direction.scale(.75)).add(offsetB);
|
||||
CreateClient.outliner.showLine("placementArrowA" + center + target, start.add(offset), endA.add(offset)).lineWidth(1/16f);
|
||||
CreateClient.outliner.showLine("placementArrowB" + center + target, start.add(offset), endB.add(offset)).lineWidth(1/16f);
|
||||
}
|
||||
|
||||
/*@OnlyIn(Dist.CLIENT)
|
||||
static void renderArrow(Vec3d center, Direction towards, BlockRayTraceResult ray) {
|
||||
Direction hitFace = ray.getFace();
|
||||
|
||||
if (hitFace.getAxis() == towards.getAxis())
|
||||
return;
|
||||
|
||||
//get the two perpendicular directions to form the arrow
|
||||
Direction[] directions = Arrays.stream(Direction.Axis.values()).filter(axis -> axis != hitFace.getAxis() && axis != towards.getAxis()).map(Iterate::directionsInAxis).findFirst().orElse(new Direction[]{});
|
||||
Vec3d startOffset = new Vec3d(towards.getDirectionVec());
|
||||
Vec3d start = center.add(startOffset);
|
||||
for (Direction dir : directions) {
|
||||
Vec3d arrowOffset = new Vec3d(dir.getDirectionVec()).scale(.25);
|
||||
Vec3d target = center.add(startOffset.scale(0.75)).add(arrowOffset);
|
||||
CreateClient.outliner.showLine("placementArrow" + towards + dir, start, target).lineWidth(1/16f);
|
||||
}
|
||||
}*/
|
||||
|
||||
static List<Direction> orderedByDistanceOnlyAxis(BlockPos pos, Vec3d hit, Direction.Axis axis) {
|
||||
return orderedByDistance(pos, hit, dir -> dir.getAxis() == axis);
|
||||
}
|
||||
|
||||
static List<Direction> orderedByDistanceOnlyAxis(BlockPos pos, Vec3d hit, Direction.Axis axis, Predicate<Direction> includeDirection) {
|
||||
return orderedByDistance(pos, hit, ((Predicate<Direction>) dir -> dir.getAxis() == axis).and(includeDirection));
|
||||
}
|
||||
|
||||
static List<Direction> orderedByDistanceExceptAxis(BlockPos pos, Vec3d hit, Direction.Axis axis) {
|
||||
return orderedByDistance(pos, hit, dir -> dir.getAxis() != axis);
|
||||
}
|
||||
|
||||
static List<Direction> orderedByDistanceExceptAxis(BlockPos pos, Vec3d hit, Direction.Axis axis, Predicate<Direction> includeDirection) {
|
||||
return orderedByDistance(pos, hit, ((Predicate<Direction>) dir -> dir.getAxis() != axis).and(includeDirection));
|
||||
}
|
||||
|
||||
static List<Direction> orderedByDistance(BlockPos pos, Vec3d hit) {
|
||||
return orderedByDistance(pos, hit, _$ -> true);
|
||||
}
|
||||
|
||||
static List<Direction> orderedByDistance(BlockPos pos, Vec3d hit, Predicate<Direction> includeDirection) {
|
||||
Vec3d centerToHit = hit.subtract(VecHelper.getCenterOf(pos));
|
||||
return Arrays.stream(Iterate.directions)
|
||||
.filter(includeDirection)
|
||||
.map(dir -> Pair.of(dir, new Vec3d(dir.getDirectionVec()).distanceTo(centerToHit)))
|
||||
.sorted(Comparator.comparingDouble(Pair::getSecond))
|
||||
.map(Pair::getFirst)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.simibubi.create.foundation.utility.placement;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PlacementHelpers {
|
||||
|
||||
private static final List<IPlacementHelper> helpers = new ArrayList<>();
|
||||
|
||||
public static int register(IPlacementHelper helper) {
|
||||
helpers.add(helper);
|
||||
return helpers.size() - 1;
|
||||
}
|
||||
|
||||
public static IPlacementHelper get(int id) {
|
||||
if (id < 0 || id >= helpers.size())
|
||||
throw new ArrayIndexOutOfBoundsException("id " + id + " for placement helper not known");
|
||||
|
||||
return helpers.get(id);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void tick() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
ClientWorld world = mc.world;
|
||||
|
||||
if (world == null)
|
||||
return;
|
||||
|
||||
if (!(mc.objectMouseOver instanceof BlockRayTraceResult))
|
||||
return;
|
||||
|
||||
BlockRayTraceResult ray = (BlockRayTraceResult) mc.objectMouseOver;
|
||||
|
||||
if (mc.player == null)
|
||||
return;
|
||||
|
||||
List<IPlacementHelper> filteredForHeldItem = helpers.stream().filter(helper -> Arrays.stream(Hand.values()).anyMatch(hand -> helper.getItemPredicate().test(mc.player.getHeldItem(hand)))).collect(Collectors.toList());
|
||||
if (filteredForHeldItem.isEmpty())
|
||||
return;
|
||||
|
||||
if (mc.player.isSneaking())//for now, disable all helpers when sneaking TODO add helpers that respect sneaking but still show position
|
||||
return;
|
||||
|
||||
BlockPos pos = ray.getPos();
|
||||
BlockState state = world.getBlockState(pos);
|
||||
|
||||
List<IPlacementHelper> filteredForState = filteredForHeldItem.stream().filter(helper -> helper.getStatePredicate().test(state)).collect(Collectors.toList());
|
||||
|
||||
if (filteredForState.isEmpty())
|
||||
return;
|
||||
|
||||
for (IPlacementHelper h : filteredForState) {
|
||||
PlacementOffset offset = h.getOffset(world, state, pos, ray);
|
||||
|
||||
if (offset.isSuccessful()) {
|
||||
h.renderAt(pos, state, ray, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.simibubi.create.foundation.utility.placement;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class PlacementOffset {
|
||||
|
||||
private final boolean success;
|
||||
private final Vec3i pos;
|
||||
private final Function<BlockState, BlockState> stateTransform;
|
||||
|
||||
private PlacementOffset(boolean success, Vec3i pos, Function<BlockState, BlockState> transform) {
|
||||
this.success = success;
|
||||
this.pos = pos;
|
||||
this.stateTransform = transform == null ? Function.identity() : transform;
|
||||
}
|
||||
|
||||
public static PlacementOffset fail() {
|
||||
return new PlacementOffset(false, Vec3i.NULL_VECTOR, null);
|
||||
}
|
||||
|
||||
public static PlacementOffset success(Vec3i pos) {
|
||||
return new PlacementOffset(true, pos, null);
|
||||
}
|
||||
|
||||
public static PlacementOffset success(Vec3i pos, Function<BlockState, BlockState> transform) {
|
||||
return new PlacementOffset(true, pos, transform);
|
||||
}
|
||||
|
||||
public boolean isSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public Vec3i getPos() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public Function<BlockState, BlockState> getTransform() {
|
||||
return stateTransform;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.simibubi.create.foundation.utility.placement.util;
|
||||
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
||||
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.state.IProperty;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
public abstract class PoleHelper<T extends Comparable<T>> implements IPlacementHelper {
|
||||
|
||||
protected final Predicate<BlockState> statePredicate;
|
||||
protected final IProperty<T> property;
|
||||
protected final Function<BlockState, Direction.Axis> axisFunction;
|
||||
|
||||
public PoleHelper(Predicate<BlockState> statePredicate, Function<BlockState, Direction.Axis> axisFunction, IProperty<T> property) {
|
||||
this.statePredicate = statePredicate;
|
||||
this.axisFunction = axisFunction;
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public boolean matchesAxis(BlockState state, Direction.Axis axis) {
|
||||
if (!statePredicate.test(state))
|
||||
return false;
|
||||
|
||||
return axisFunction.apply(state) == axis;
|
||||
}
|
||||
|
||||
public int attachedPoles(World world, BlockPos pos, Direction direction) {
|
||||
BlockPos checkPos = pos.offset(direction);
|
||||
BlockState state = world.getBlockState(checkPos);
|
||||
int count = 0;
|
||||
while (matchesAxis(state, direction.getAxis())) {
|
||||
count++;
|
||||
checkPos = checkPos.offset(direction);
|
||||
state = world.getBlockState(checkPos);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<BlockState> getStatePredicate() {
|
||||
return this.statePredicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlacementOffset getOffset(World world, BlockState state, BlockPos pos, BlockRayTraceResult ray) {
|
||||
List<Direction> directions = IPlacementHelper.orderedByDistance(pos, ray.getHitVec(), dir -> dir.getAxis() == axisFunction.apply(state));
|
||||
for (Direction dir : directions) {
|
||||
int poles = attachedPoles(world, pos, dir);
|
||||
BlockPos newPos = pos.offset(dir, poles + 1);
|
||||
BlockState newState = world.getBlockState(newPos);
|
||||
|
||||
if (newState.getMaterial().isReplaceable())
|
||||
return PlacementOffset.success(newPos, bState -> bState.with(property, state.get(property)));
|
||||
|
||||
}
|
||||
|
||||
return PlacementOffset.fail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAt(BlockPos pos, BlockState state, BlockRayTraceResult ray, PlacementOffset offset) {
|
||||
Vec3d centerOffset = new Vec3d(ray.getFace().getDirectionVec()).scale(.3);
|
||||
IPlacementHelper.renderArrow(VecHelper.getCenterOf(pos).add(centerOffset), VecHelper.getCenterOf(offset.getPos()).add(centerOffset), ray.getFace(), 0.75D);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue