mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 23:47:38 +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;
|
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.AllBlocks;
|
||||||
import com.simibubi.create.AllShapes;
|
import com.simibubi.create.AllShapes;
|
||||||
import com.simibubi.create.foundation.block.ProperDirectionalBlock;
|
import com.simibubi.create.foundation.block.ProperDirectionalBlock;
|
||||||
import com.simibubi.create.foundation.utility.DyeHelper;
|
import com.simibubi.create.foundation.utility.DyeHelper;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
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.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.BlockItem;
|
import net.minecraft.item.*;
|
||||||
import net.minecraft.item.BlockItemUseContext;
|
|
||||||
import net.minecraft.item.DyeColor;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import net.minecraft.item.ShearsItem;
|
|
||||||
import net.minecraft.util.ActionResultType;
|
import net.minecraft.util.ActionResultType;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.Hand;
|
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.IBlockReader;
|
||||||
import net.minecraft.world.World;
|
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 class SailBlock extends ProperDirectionalBlock {
|
||||||
|
|
||||||
public static SailBlock frame(Properties properties) {
|
public static SailBlock frame(Properties properties) {
|
||||||
|
@ -45,7 +45,9 @@ public class SailBlock extends ProperDirectionalBlock {
|
||||||
return new SailBlock(properties, false);
|
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) {
|
protected SailBlock(Properties p_i48415_1_, boolean frame) {
|
||||||
super(p_i48415_1_);
|
super(p_i48415_1_);
|
||||||
|
@ -55,27 +57,27 @@ public class SailBlock extends ProperDirectionalBlock {
|
||||||
@Override
|
@Override
|
||||||
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
||||||
BlockState state = super.getStateForPlacement(context);
|
BlockState state = super.getStateForPlacement(context);
|
||||||
return state.with(FACING, state.get(FACING)
|
return state.with(FACING, state.get(FACING).getOpposite());
|
||||||
.getOpposite());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand,
|
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult ray) {
|
||||||
BlockRayTraceResult ray) {
|
|
||||||
ItemStack heldItem = player.getHeldItem(hand);
|
ItemStack heldItem = player.getHeldItem(hand);
|
||||||
|
|
||||||
if (AllBlocks.SAIL.isIn(heldItem) || AllBlocks.SAIL_FRAME.isIn(heldItem)) {
|
if (AllBlocks.SAIL.isIn(heldItem) || AllBlocks.SAIL_FRAME.isIn(heldItem)) {
|
||||||
Direction offset =
|
IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId);
|
||||||
SailBlockPlacementHelper.getPlacementOffset(world, state.get(FACING), pos, ray.getHitVec());
|
PlacementOffset offset = placementHelper.getOffset(world, state, pos, ray);
|
||||||
if (offset == null)
|
|
||||||
return ActionResultType.SUCCESS;
|
if (!offset.isSuccessful())
|
||||||
|
return ActionResultType.PASS;
|
||||||
|
|
||||||
BlockState blockState = ((BlockItem) heldItem.getItem()).getBlock()
|
BlockState blockState = ((BlockItem) heldItem.getItem()).getBlock()
|
||||||
.getDefaultState()
|
.getDefaultState()
|
||||||
.with(FACING, state.get(FACING));
|
.with(FACING, state.get(FACING));
|
||||||
BlockPos offsetPos = pos.offset(offset);
|
BlockPos offsetPos = new BlockPos(offset.getPos());
|
||||||
if (!world.isRemote && world.getBlockState(offsetPos)
|
if (!world.isRemote && world.getBlockState(offsetPos)
|
||||||
.getMaterial()
|
.getMaterial()
|
||||||
.isReplaceable()) {
|
.isReplaceable()) {
|
||||||
world.setBlockState(offsetPos, blockState);
|
world.setBlockState(offsetPos, blockState);
|
||||||
if (!player.isCreative())
|
if (!player.isCreative())
|
||||||
heldItem.shrink(1);
|
heldItem.shrink(1);
|
||||||
|
@ -94,7 +96,7 @@ public class SailBlock extends ProperDirectionalBlock {
|
||||||
|
|
||||||
for (DyeColor color : DyeColor.values()) {
|
for (DyeColor color : DyeColor.values()) {
|
||||||
if (!heldItem.getItem()
|
if (!heldItem.getItem()
|
||||||
.isIn(DyeHelper.getTagOfDye(color)))
|
.isIn(DyeHelper.getTagOfDye(color)))
|
||||||
continue;
|
continue;
|
||||||
if (!world.isRemote)
|
if (!world.isRemote)
|
||||||
applyDye(state, world, pos, color);
|
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) {
|
protected void applyDye(BlockState state, World world, BlockPos pos, @Nullable DyeColor color) {
|
||||||
BlockState newState =
|
BlockState newState =
|
||||||
(color == null ? AllBlocks.SAIL_FRAME : AllBlocks.DYED_SAILS[color.ordinal()]).getDefaultState()
|
(color == null ? AllBlocks.SAIL_FRAME : AllBlocks.DYED_SAILS[color.ordinal()]).getDefaultState()
|
||||||
.with(FACING, state.get(FACING));
|
.with(FACING, state.get(FACING));
|
||||||
|
|
||||||
// Dye the block itself
|
// Dye the block itself
|
||||||
if (state != newState) {
|
if (state != newState) {
|
||||||
|
@ -118,7 +120,7 @@ public class SailBlock extends ProperDirectionalBlock {
|
||||||
// Dye all adjacent
|
// Dye all adjacent
|
||||||
for (Direction d : Iterate.directions) {
|
for (Direction d : Iterate.directions) {
|
||||||
if (d.getAxis() == state.get(FACING)
|
if (d.getAxis() == state.get(FACING)
|
||||||
.getAxis())
|
.getAxis())
|
||||||
continue;
|
continue;
|
||||||
BlockPos offset = pos.offset(d);
|
BlockPos offset = pos.offset(d);
|
||||||
BlockState adjacentState = world.getBlockState(offset);
|
BlockState adjacentState = world.getBlockState(offset);
|
||||||
|
@ -145,7 +147,7 @@ public class SailBlock extends ProperDirectionalBlock {
|
||||||
|
|
||||||
for (Direction d : Iterate.directions) {
|
for (Direction d : Iterate.directions) {
|
||||||
if (d.getAxis() == state.get(FACING)
|
if (d.getAxis() == state.get(FACING)
|
||||||
.getAxis())
|
.getAxis())
|
||||||
continue;
|
continue;
|
||||||
BlockPos offset = currentPos.offset(d);
|
BlockPos offset = currentPos.offset(d);
|
||||||
if (visited.contains(offset))
|
if (visited.contains(offset))
|
||||||
|
@ -163,26 +165,23 @@ public class SailBlock extends ProperDirectionalBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_,
|
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_, ISelectionContext p_220053_4_) {
|
||||||
ISelectionContext p_220053_4_) {
|
|
||||||
return (frame ? AllShapes.SAIL_FRAME : AllShapes.SAIL).get(state.get(FACING));
|
return (frame ? AllShapes.SAIL_FRAME : AllShapes.SAIL).get(state.get(FACING));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VoxelShape getCollisionShape(BlockState state, IBlockReader p_220071_2_, BlockPos p_220071_3_,
|
public VoxelShape getCollisionShape(BlockState state, IBlockReader p_220071_2_, BlockPos p_220071_3_, ISelectionContext p_220071_4_) {
|
||||||
ISelectionContext p_220071_4_) {
|
|
||||||
if (frame)
|
if (frame)
|
||||||
return AllShapes.SAIL_FRAME_COLLISION.get(state.get(FACING));
|
return AllShapes.SAIL_FRAME_COLLISION.get(state.get(FACING));
|
||||||
return getShape(state, p_220071_2_, p_220071_3_, p_220071_4_);
|
return getShape(state, p_220071_2_, p_220071_3_, p_220071_4_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack getPickBlock(BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos,
|
public ItemStack getPickBlock(BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos, PlayerEntity player) {
|
||||||
PlayerEntity player) {
|
|
||||||
ItemStack pickBlock = super.getPickBlock(state, target, world, pos, player);
|
ItemStack pickBlock = super.getPickBlock(state, target, world, pos, player);
|
||||||
if (pickBlock.isEmpty())
|
if (pickBlock.isEmpty())
|
||||||
return AllBlocks.SAIL.get()
|
return AllBlocks.SAIL.get()
|
||||||
.getPickBlock(state, target, world, pos, player);
|
.getPickBlock(state, target, world, pos, player);
|
||||||
return pickBlock;
|
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;
|
return false;
|
||||||
|
|
||||||
if (blockState.get(MechanicalPistonBlock.STATE) == PistonState.EXTENDED) {
|
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);
|
actualStart = actualStart.offset(direction);
|
||||||
poles.add(new BlockInfo(actualStart, nextBlock.with(FACING, direction), null));
|
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()));
|
nextBlock = world.getBlockState(end.offset(direction.getOpposite()));
|
||||||
int extensionsInBack = 0;
|
int extensionsInBack = 0;
|
||||||
|
|
||||||
while (PistonPolePlacementHelper.matchesAxis(nextBlock, direction.getAxis())) {
|
while (PistonExtensionPoleBlock.PlacementHelper.get().matchesAxis(nextBlock, direction.getAxis())) {
|
||||||
end = end.offset(direction.getOpposite());
|
end = end.offset(direction.getOpposite());
|
||||||
poles.add(new BlockInfo(end, nextBlock.with(FACING, direction), null));
|
poles.add(new BlockInfo(end, nextBlock.with(FACING, direction), null));
|
||||||
extensionsInBack++;
|
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.components.structureMovement.piston.MechanicalPistonBlock.*;
|
||||||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||||
import com.simibubi.create.foundation.block.ProperDirectionalBlock;
|
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.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.IWaterLoggable;
|
import net.minecraft.block.IWaterLoggable;
|
||||||
|
@ -30,10 +34,14 @@ import net.minecraft.world.IBlockReader;
|
||||||
import net.minecraft.world.IWorld;
|
import net.minecraft.world.IWorld;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*;
|
import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*;
|
||||||
|
|
||||||
public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements IWrenchable, IWaterLoggable {
|
public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements IWrenchable, IWaterLoggable {
|
||||||
|
|
||||||
|
private static final int placementHelperId = PlacementHelpers.register(PlacementHelper.get());
|
||||||
|
|
||||||
public PistonExtensionPoleBlock(Properties properties) {
|
public PistonExtensionPoleBlock(Properties properties) {
|
||||||
super(properties);
|
super(properties);
|
||||||
setDefaultState(getDefaultState().with(FACING, Direction.UP).with(BlockStateProperties.WATERLOGGED, false));
|
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);
|
ItemStack heldItem = player.getHeldItem(hand);
|
||||||
|
|
||||||
if (AllBlocks.PISTON_EXTENSION_POLE.isIn(heldItem) && !player.isSneaking()) {
|
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;
|
return ActionResultType.PASS;
|
||||||
|
|
||||||
BlockPos newPos = pos.offset(offset.getFirst(), offset.getSecond());
|
BlockPos newPos = new BlockPos(offset.getPos());
|
||||||
|
|
||||||
if (!world.getBlockState(newPos).getMaterial().isReplaceable())
|
if (!world.getBlockState(newPos).getMaterial().isReplaceable())
|
||||||
return ActionResultType.PASS;
|
return ActionResultType.PASS;
|
||||||
|
@ -120,7 +129,7 @@ public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements
|
||||||
if (world.isRemote)
|
if (world.isRemote)
|
||||||
return ActionResultType.SUCCESS;
|
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())
|
if (!player.isCreative())
|
||||||
heldItem.shrink(1);
|
heldItem.shrink(1);
|
||||||
|
|
||||||
|
@ -149,4 +158,27 @@ public class PistonExtensionPoleBlock extends ProperDirectionalBlock implements
|
||||||
}
|
}
|
||||||
return state;
|
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.CreateClient;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock;
|
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.PistonExtensionPoleBlock;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.piston.PistonPolePlacementHelper;
|
|
||||||
import com.simibubi.create.foundation.config.AllConfigs;
|
import com.simibubi.create.foundation.config.AllConfigs;
|
||||||
import com.simibubi.create.foundation.gui.GuiGameElement;
|
import com.simibubi.create.foundation.gui.GuiGameElement;
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBox;
|
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.Lang;
|
||||||
import com.simibubi.create.foundation.utility.outliner.Outline;
|
import com.simibubi.create.foundation.utility.outliner.Outline;
|
||||||
import com.simibubi.create.foundation.utility.outliner.Outliner.OutlineEntry;
|
import com.simibubi.create.foundation.utility.outliner.Outliner.OutlineEntry;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.screen.Screen;
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
@ -106,7 +104,7 @@ public class GoggleOverlayRenderer {
|
||||||
int poles = 1;
|
int poles = 1;
|
||||||
boolean pistonFound = false;
|
boolean pistonFound = false;
|
||||||
for (Direction dir : directions) {
|
for (Direction dir : directions) {
|
||||||
int attachedPoles = PistonPolePlacementHelper.attachedPoles(world, pos, dir);
|
int attachedPoles = PistonExtensionPoleBlock.PlacementHelper.get().attachedPoles(world, pos, dir);
|
||||||
poles += attachedPoles;
|
poles += attachedPoles;
|
||||||
pistonFound |= world.getBlockState(pos.offset(dir, attachedPoles + 1))
|
pistonFound |= world.getBlockState(pos.offset(dir, attachedPoles + 1))
|
||||||
.getBlock() instanceof MechanicalPistonBlock;
|
.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.base.IRotate;
|
||||||
import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerBlock;
|
import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerBlock;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.fluid.Fluids;
|
import net.minecraft.fluid.Fluids;
|
||||||
|
@ -69,9 +68,7 @@ public class CogWheelBlock extends AbstractShaftBlock {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
||||||
BlockPos placedOnPos = context.getPos()
|
BlockPos placedOnPos = context.getPos().offset(context.getFace().getOpposite());
|
||||||
.offset(context.getFace()
|
|
||||||
.getOpposite());
|
|
||||||
World world = context.getWorld();
|
World world = context.getWorld();
|
||||||
BlockState placedAgainst = world.getBlockState(placedOnPos);
|
BlockState placedAgainst = world.getBlockState(placedOnPos);
|
||||||
Block block = placedAgainst.getBlock();
|
Block block = placedAgainst.getBlock();
|
||||||
|
@ -80,7 +77,8 @@ public class CogWheelBlock extends AbstractShaftBlock {
|
||||||
.down());
|
.down());
|
||||||
IFluidState ifluidstate = context.getWorld().getFluidState(context.getPos());
|
IFluidState ifluidstate = context.getWorld().getFluidState(context.getPos());
|
||||||
if (AllBlocks.ROTATION_SPEED_CONTROLLER.has(stateBelow) && isLarge) {
|
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);
|
.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);
|
Axis preferredAxis = getPreferredAxis(context);
|
||||||
if (preferredAxis != null)
|
if (preferredAxis != null)
|
||||||
return this.getDefaultState()
|
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()
|
return this.getDefaultState()
|
||||||
.with(AXIS, context.getFace()
|
.with(AXIS, context.getFace().getAxis())
|
||||||
.getAxis()).with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
|
.with(BlockStateProperties.WATERLOGGED, ifluidstate.getFluid() == Fluids.WATER);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getDefaultState().with(AXIS, ((IRotate) block).getRotationAxis(placedAgainst));
|
return getDefaultState().with(AXIS, ((IRotate) block).getRotationAxis(placedAgainst));
|
||||||
|
|
|
@ -1,38 +1,76 @@
|
||||||
package com.simibubi.create.content.contraptions.relays.elementary;
|
package com.simibubi.create.content.contraptions.relays.elementary;
|
||||||
|
|
||||||
import com.simibubi.create.AllBlocks;
|
import com.simibubi.create.AllBlocks;
|
||||||
|
import com.simibubi.create.AllShapes;
|
||||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
import com.simibubi.create.foundation.advancement.AllTriggers;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
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.block.BlockState;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.BlockItem;
|
import net.minecraft.item.BlockItem;
|
||||||
import net.minecraft.item.BlockItemUseContext;
|
import net.minecraft.item.BlockItemUseContext;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.ActionResultType;
|
import net.minecraft.util.ActionResultType;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.Direction.Axis;
|
import net.minecraft.util.Direction.Axis;
|
||||||
import net.minecraft.util.Direction.AxisDirection;
|
import net.minecraft.util.Direction.AxisDirection;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.BlockRayTraceResult;
|
||||||
import net.minecraft.world.World;
|
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 {
|
public class CogwheelBlockItem extends BlockItem {
|
||||||
|
|
||||||
boolean large;
|
boolean large;
|
||||||
|
|
||||||
|
private final int placementHelperId;
|
||||||
|
|
||||||
public CogwheelBlockItem(CogWheelBlock block, Properties builder) {
|
public CogwheelBlockItem(CogWheelBlock block, Properties builder) {
|
||||||
super(block, builder);
|
super(block, builder);
|
||||||
large = block.isLarge;
|
large = block.isLarge;
|
||||||
|
|
||||||
|
placementHelperId = PlacementHelpers.register(large ? new LargeCogHelper() : new SmallCogHelper());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResultType tryPlace(BlockItemUseContext context) {
|
public ActionResultType tryPlace(BlockItemUseContext context) {
|
||||||
Direction face = context.getFace();
|
IPlacementHelper helper = PlacementHelpers.get(placementHelperId);
|
||||||
BlockPos placedOnPos = context.getPos().offset(face.getOpposite());
|
World world = context.getWorld();
|
||||||
BlockState placedOnState = context.getWorld().getBlockState(placedOnPos);
|
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);
|
return super.tryPlace(context);
|
||||||
if (face.getAxis() == placedOnState.get(CogWheelBlock.AXIS))
|
if (face.getAxis() == placedOnState.get(CogWheelBlock.AXIS))
|
||||||
return super.tryPlace(context);
|
return super.tryPlace(context);
|
||||||
|
@ -67,7 +105,7 @@ public class CogwheelBlockItem extends BlockItem {
|
||||||
return ActionResultType.FAIL;
|
return ActionResultType.FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.tryPlace(context);
|
return super.tryPlace(context);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -107,4 +145,137 @@ public class CogwheelBlockItem extends BlockItem {
|
||||||
return super.placeBlock(context, state);
|
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.base.KineticTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock;
|
import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock;
|
||||||
import com.simibubi.create.foundation.advancement.AllTriggers;
|
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.block.BlockState;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.BlockItem;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.ActionResultType;
|
import net.minecraft.util.ActionResultType;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.BlockRayTraceResult;
|
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.IBlockReader;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class ShaftBlock extends AbstractShaftBlock {
|
public class ShaftBlock extends AbstractShaftBlock {
|
||||||
|
|
||||||
|
private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper());
|
||||||
|
|
||||||
public ShaftBlock(Properties properties) {
|
public ShaftBlock(Properties properties) {
|
||||||
super(properties);
|
super(properties);
|
||||||
}
|
}
|
||||||
|
@ -45,7 +56,7 @@ public class ShaftBlock extends AbstractShaftBlock {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand,
|
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand,
|
||||||
BlockRayTraceResult p_225533_6_) {
|
BlockRayTraceResult ray) {
|
||||||
if (player.isSneaking() || !player.isAllowEdit())
|
if (player.isSneaking() || !player.isAllowEdit())
|
||||||
return ActionResultType.PASS;
|
return ActionResultType.PASS;
|
||||||
|
|
||||||
|
@ -66,6 +77,52 @@ public class ShaftBlock extends AbstractShaftBlock {
|
||||||
return ActionResultType.SUCCESS;
|
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;
|
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;
|
package com.simibubi.create.events;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import com.simibubi.create.AllFluids;
|
import com.simibubi.create.AllFluids;
|
||||||
import com.simibubi.create.Create;
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.CreateClient;
|
import com.simibubi.create.CreateClient;
|
||||||
import com.simibubi.create.content.contraptions.KineticDebugger;
|
import com.simibubi.create.content.contraptions.KineticDebugger;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler;
|
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.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.CouplingHandlerClient;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingPhysics;
|
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingPhysics;
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingRenderer;
|
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.tileEntity.behaviour.scrollvalue.ScrollValueRenderer;
|
||||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||||
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
|
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
|
||||||
|
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
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.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@EventBusSubscriber(value = Dist.CLIENT)
|
@EventBusSubscriber(value = Dist.CLIENT)
|
||||||
public class ClientEvents {
|
public class ClientEvents {
|
||||||
|
|
||||||
|
@ -103,8 +101,7 @@ public class ClientEvents {
|
||||||
ExtendoGripRenderHandler.tick();
|
ExtendoGripRenderHandler.tick();
|
||||||
// CollisionDebugger.tick();
|
// CollisionDebugger.tick();
|
||||||
ArmInteractionPointHandler.tick();
|
ArmInteractionPointHandler.tick();
|
||||||
SailBlockPlacementHelper.tick();
|
PlacementHelpers.tick();
|
||||||
PistonPolePlacementHelper.tick();
|
|
||||||
CreateClient.outliner.tickOutlines();
|
CreateClient.outliner.tickOutlines();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,8 +134,8 @@ public class ClientEvents {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
onRenderHotbar(new MatrixStack(), Minecraft.getInstance()
|
onRenderHotbar(new MatrixStack(), Minecraft.getInstance()
|
||||||
.getBufferBuilders()
|
.getBufferBuilders()
|
||||||
.getEntityVertexConsumers(), 0xF000F0, OverlayTexture.DEFAULT_UV);
|
.getEntityVertexConsumers(), 0xF000F0, OverlayTexture.DEFAULT_UV);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onRenderHotbar(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) {
|
public static void onRenderHotbar(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) {
|
||||||
|
@ -154,7 +151,7 @@ public class ClientEvents {
|
||||||
|
|
||||||
ItemStack stack = event.getItemStack();
|
ItemStack stack = event.getItemStack();
|
||||||
String translationKey = stack.getItem()
|
String translationKey = stack.getItem()
|
||||||
.getTranslationKey(stack);
|
.getTranslationKey(stack);
|
||||||
if (!translationKey.startsWith(itemPrefix) && !translationKey.startsWith(blockPrefix))
|
if (!translationKey.startsWith(itemPrefix) && !translationKey.startsWith(blockPrefix))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -163,7 +160,7 @@ public class ClientEvents {
|
||||||
List<ITextComponent> toolTip = new ArrayList<>();
|
List<ITextComponent> toolTip = new ArrayList<>();
|
||||||
toolTip.add(itemTooltip.remove(0));
|
toolTip.add(itemTooltip.remove(0));
|
||||||
TooltipHelper.getTooltip(stack)
|
TooltipHelper.getTooltip(stack)
|
||||||
.addInformation(toolTip);
|
.addInformation(toolTip);
|
||||||
itemTooltip.addAll(0, toolTip);
|
itemTooltip.addAll(0, toolTip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import net.minecraft.util.Direction.Axis;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Iterate {
|
public class Iterate {
|
||||||
|
@ -15,6 +16,7 @@ public class Iterate {
|
||||||
public static final Direction[] directions = Direction.values();
|
public static final Direction[] directions = Direction.values();
|
||||||
public static final Direction[] horizontalDirections = getHorizontals();
|
public static final Direction[] horizontalDirections = getHorizontals();
|
||||||
public static final Axis[] axes = Axis.values();
|
public static final Axis[] axes = Axis.values();
|
||||||
|
public static final EnumSet<Direction.Axis> axisSet = EnumSet.allOf(Direction.Axis.class);
|
||||||
|
|
||||||
private static Direction[] getHorizontals() {
|
private static Direction[] getHorizontals() {
|
||||||
Direction[] directions = new Direction[4];
|
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