In good Shape

- Improved selection boundaries of Track blocks
This commit is contained in:
simibubi 2022-04-13 03:06:35 +02:00
parent 517fad7a62
commit 99a6836a1d
9 changed files with 414 additions and 41 deletions

View file

@ -1,5 +1,6 @@
package com.simibubi.create; package com.simibubi.create;
import static net.minecraft.core.Direction.EAST;
import static net.minecraft.core.Direction.NORTH; import static net.minecraft.core.Direction.NORTH;
import static net.minecraft.core.Direction.SOUTH; import static net.minecraft.core.Direction.SOUTH;
import static net.minecraft.core.Direction.UP; import static net.minecraft.core.Direction.UP;
@ -7,6 +8,7 @@ import static net.minecraft.core.Direction.UP;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import com.simibubi.create.content.logistics.block.chute.ChuteShapes; import com.simibubi.create.content.logistics.block.chute.ChuteShapes;
import com.simibubi.create.content.logistics.trains.track.TrackVoxelShapes;
import com.simibubi.create.foundation.utility.VoxelShaper; import com.simibubi.create.foundation.utility.VoxelShaper;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
@ -28,11 +30,12 @@ public class AllShapes {
CASING_13PX = shape(0, 0, 0, 16, 13, 16).forDirectional(), CASING_13PX = shape(0, 0, 0, 16, 13, 16).forDirectional(),
CASING_12PX = shape(0, 0, 0, 16, 12, 16).forDirectional(), CASING_12PX = shape(0, 0, 0, 16, 12, 16).forDirectional(),
CASING_11PX = shape(0, 0, 0, 16, 11, 16).forDirectional(), CASING_11PX = shape(0, 0, 0, 16, 11, 16).forDirectional(),
MOTOR_BLOCK = shape(3, 0, 3, 13, 14, 13).forDirectional(), TRACK = shape(0, 0, 0, 16, 4, 16).forDirectional(), MOTOR_BLOCK = shape(3, 0, 3, 13, 14, 13).forDirectional(),
FOUR_VOXEL_POLE = shape(6, 0, 6, 10, 16, 10).forAxis(), SIX_VOXEL_POLE = shape(5, 0, 5, 11, 16, 11).forAxis(), FOUR_VOXEL_POLE = shape(6, 0, 6, 10, 16, 10).forAxis(), SIX_VOXEL_POLE = shape(5, 0, 5, 11, 16, 11).forAxis(),
EIGHT_VOXEL_POLE = shape(4, 0, 4, 12, 16, 12).forAxis(), TEN_VOXEL_POLE = shape(3, 0, 3, 13, 16, 13).forAxis(), EIGHT_VOXEL_POLE = shape(4, 0, 4, 12, 16, 12).forAxis(), TEN_VOXEL_POLE = shape(3, 0, 3, 13, 16, 13).forAxis(),
FURNACE_ENGINE = shape(1, 1, 0, 15, 15, 16).add(0, 0, 9, 16, 16, 14) FURNACE_ENGINE = shape(1, 1, 0, 15, 15, 16).add(0, 0, 9, 16, 16, 14)
.forHorizontal(Direction.SOUTH), .forHorizontal(SOUTH),
PORTABLE_STORAGE_INTERFACE = shape(0, 0, 0, 16, 14, 16).forDirectional(), PORTABLE_STORAGE_INTERFACE = shape(0, 0, 0, 16, 14, 16).forDirectional(),
PULLEY = shape(0, 0, 0, 16, 16, 2).add(1, 1, 2, 15, 15, 14) PULLEY = shape(0, 0, 0, 16, 16, 2).add(1, 1, 2, 15, 15, 14)
.add(2, 13, 2, 14, 16, 14) .add(2, 13, 2, 14, 16, 14)
@ -87,19 +90,19 @@ public class AllShapes {
.add(5, 14, 4, 11, 15, 10) .add(5, 14, 4, 11, 15, 10)
.add(5, 15, 5, 11, 16, 9) .add(5, 15, 5, 11, 16, 9)
.add(5, 16, 6, 11, 17, 8) .add(5, 16, 6, 11, 17, 8)
.forHorizontal(Direction.SOUTH), .forHorizontal(SOUTH),
SMART_FLUID_PIPE_WALL = shape(4, 0, 4, 12, 16, 12).add(3, 3, 3, 13, 13, 13) SMART_FLUID_PIPE_WALL = shape(4, 0, 4, 12, 16, 12).add(3, 3, 3, 13, 13, 13)
.add(5, 5, 13, 11, 13, 14) .add(5, 5, 13, 11, 13, 14)
.add(5, 6, 14, 11, 12, 15) .add(5, 6, 14, 11, 12, 15)
.add(5, 7, 15, 11, 11, 16) .add(5, 7, 15, 11, 11, 16)
.add(5, 8, 16, 11, 10, 17) .add(5, 8, 16, 11, 10, 17)
.forHorizontal(Direction.SOUTH), .forHorizontal(SOUTH),
SMART_FLUID_PIPE_CEILING = shape(4, 4, 0, 12, 12, 16).add(3, 3, 3, 13, 13, 13) SMART_FLUID_PIPE_CEILING = shape(4, 4, 0, 12, 12, 16).add(3, 3, 3, 13, 13, 13)
.add(5, 2, 3, 11, 3, 11) .add(5, 2, 3, 11, 3, 11)
.add(5, 1, 4, 11, 2, 10) .add(5, 1, 4, 11, 2, 10)
.add(5, 0, 5, 11, 1, 9) .add(5, 0, 5, 11, 1, 9)
.add(5, -1, 6, 11, 0, 8) .add(5, -1, 6, 11, 0, 8)
.forHorizontal(Direction.SOUTH), .forHorizontal(SOUTH),
PUMP = shape(2, 0, 2, 14, 5, 14).add(4, 0, 4, 12, 16, 12) PUMP = shape(2, 0, 2, 14, 5, 14).add(4, 0, 4, 12, 16, 12)
.add(3, 12, 3, 13, 16, 13) .add(3, 12, 3, 13, 16, 13)
.forDirectional(Direction.UP), .forDirectional(Direction.UP),
@ -125,9 +128,9 @@ public class AllShapes {
NIXIE_TUBE_CEILING = shape(9, 4, 5, 15, 16, 11).add(1, 4, 5, 7, 16, 11) NIXIE_TUBE_CEILING = shape(9, 4, 5, 15, 16, 11).add(1, 4, 5, 7, 16, 11)
.forHorizontalAxis(), .forHorizontalAxis(),
NIXIE_TUBE_WALL = shape(5, 9, 0, 11, 15, 12).add(5, 1, 0, 11, 7, 12) NIXIE_TUBE_WALL = shape(5, 9, 0, 11, 15, 12).add(5, 1, 0, 11, 7, 12)
.forHorizontal(Direction.SOUTH), .forHorizontal(SOUTH),
FLAP_DISPLAY = shape(0, 0, 3, 16, 16, 13).forHorizontal(Direction.SOUTH), FLAP_DISPLAY = shape(0, 0, 3, 16, 16, 13).forHorizontal(SOUTH),
DATA_GATHERER = shape(1, 0, 1, 15, 6, 15).add(3, 5, 3, 13, 9, 13) DATA_GATHERER = shape(1, 0, 1, 15, 6, 15).add(3, 5, 3, 13, 9, 13)
.forDirectional(), .forDirectional(),
@ -140,7 +143,11 @@ public class AllShapes {
.forHorizontalAxis(), .forHorizontalAxis(),
STEAM_ENGINE_WALL = shape(1, 1, 0, 15, 15, 3).add(3, 3, 0, 13, 13, 15) STEAM_ENGINE_WALL = shape(1, 1, 0, 15, 15, 3).add(3, 3, 0, 13, 13, 15)
.add(1, 4, 5, 15, 12, 13) .add(1, 4, 5, 15, 12, 13)
.forHorizontal(Direction.SOUTH) .forHorizontal(SOUTH),
TRACK_ORTHO = shape(TrackVoxelShapes.orthogonal()).forHorizontal(NORTH),
TRACK_ASC = shape(TrackVoxelShapes.ascending()).forHorizontal(SOUTH),
TRACK_DIAG = shape(TrackVoxelShapes.diagonal()).forHorizontal(SOUTH)
; ;
@ -165,11 +172,19 @@ public class AllShapes {
// Static Block Shapes // Static Block Shapes
public static final VoxelShape public static final VoxelShape
BASIN_BLOCK_SHAPE = shape(0, 2, 0, 16, 16, 16).erase(2, 2, 2, 14, 16, 14) TRACK_CROSS = shape(TRACK_ORTHO.get(SOUTH)).add(TRACK_ORTHO.get(EAST))
.add(2, 0, 2, 14, 2, 14) .build(),
.build(), BASIN_RAYTRACE_SHAPE =
shape(0, 2, 0, 16, 16, 16).add(2, 0, 2, 14, 2, 14) TRACK_CROSS_DIAG = shape(TRACK_DIAG.get(SOUTH)).add(TRACK_DIAG.get(EAST))
.build(), .build(),
TRACK_FALLBACK = shape(0, 0, 0, 16, 4, 16).build(),
BASIN_BLOCK_SHAPE = shape(0, 2, 0, 16, 16, 16).erase(2, 2, 2, 14, 16, 14)
.add(2, 0, 2, 14, 2, 14)
.build(),
BASIN_RAYTRACE_SHAPE = shape(0, 2, 0, 16, 16, 16).add(2, 0, 2, 14, 2, 14)
.build(),
BASIN_COLLISION_SHAPE = shape(0, 2, 0, 16, 13, 16).erase(2, 5, 2, 14, 16, 14) BASIN_COLLISION_SHAPE = shape(0, 2, 0, 16, 13, 16).erase(2, 5, 2, 14, 16, 14)
.add(2, 0, 2, 14, 2, 14) .add(2, 0, 2, 14, 2, 14)
.build(), .build(),
@ -240,7 +255,12 @@ public class AllShapes {
// More Shapers // More Shapers
public static final VoxelShaper public static final VoxelShaper
MECHANICAL_PISTON_HEAD = shape(PISTON_HEAD).forDirectional(), MECHANICAL_PISTON = CASING_12PX, TRACK_CROSS_ORTHO_DIAG = shape(TRACK_DIAG.get(SOUTH)).add(TRACK_ORTHO.get(EAST))
.forHorizontal(SOUTH), TRACK_CROSS_DIAG_ORTHO =
shape(TRACK_DIAG.get(SOUTH)).add(TRACK_ORTHO.get(SOUTH))
.forHorizontal(SOUTH),
MECHANICAL_PISTON_HEAD = shape(PISTON_HEAD).forDirectional(), MECHANICAL_PISTON = CASING_12PX,
MECHANICAL_PISTON_EXTENDED = shape(PISTON_EXTENDED).forDirectional(), MECHANICAL_PISTON_EXTENDED = shape(PISTON_EXTENDED).forDirectional(),
SMALL_GEAR = shape(SMALL_GEAR_SHAPE).add(SIX_VOXEL_POLE.get(Axis.Y)) SMALL_GEAR = shape(SMALL_GEAR_SHAPE).add(SIX_VOXEL_POLE.get(Axis.Y))
.forAxis(), .forAxis(),

View file

@ -1,11 +1,18 @@
package com.simibubi.create.content.logistics.trains.track; package com.simibubi.create.content.logistics.trains.track;
import static com.simibubi.create.AllShapes.TRACK_ASC;
import static com.simibubi.create.AllShapes.TRACK_CROSS_DIAG_ORTHO;
import static com.simibubi.create.AllShapes.TRACK_CROSS_ORTHO_DIAG;
import static com.simibubi.create.AllShapes.TRACK_DIAG;
import static com.simibubi.create.AllShapes.TRACK_ORTHO;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Random; import java.util.Random;
import java.util.function.Consumer;
import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.util.transform.TransformStack; import com.jozufozu.flywheel.util.transform.TransformStack;
@ -25,6 +32,7 @@ import com.simibubi.create.content.logistics.trains.TrackNodeLocation.Discovered
import com.simibubi.create.content.logistics.trains.TrackPropagator; import com.simibubi.create.content.logistics.trains.TrackPropagator;
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType;
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity;
import com.simibubi.create.foundation.block.render.ReducedDestroyEffects;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
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;
@ -64,6 +72,7 @@ import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.ticks.LevelTickAccess; import net.minecraft.world.ticks.LevelTickAccess;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.IBlockRenderProperties;
public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrackBlock { public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrackBlock {
@ -81,6 +90,11 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_TURN)); super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_TURN));
} }
@OnlyIn(Dist.CLIENT)
public void initializeClient(Consumer<IBlockRenderProperties> consumer) {
consumer.accept(new ReducedDestroyEffects());
}
@Override @Override
public BlockState getStateForPlacement(BlockPlaceContext ctx) { public BlockState getStateForPlacement(BlockPlaceContext ctx) {
BlockState stateForPlacement = super.getStateForPlacement(ctx); BlockState stateForPlacement = super.getStateForPlacement(ctx);
@ -260,7 +274,48 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
@Override @Override
public VoxelShape getShape(BlockState state, BlockGetter p_60556_, BlockPos p_60557_, CollisionContext p_60558_) { public VoxelShape getShape(BlockState state, BlockGetter p_60556_, BlockPos p_60557_, CollisionContext p_60558_) {
return AllShapes.TRACK.get(Direction.UP); return getFullShape(state);
}
@Override
public VoxelShape getInteractionShape(BlockState state, BlockGetter pLevel, BlockPos pPos) {
return getFullShape(state);
}
private VoxelShape getFullShape(BlockState state) {
switch (state.getValue(SHAPE)) {
case AE:
return TRACK_ASC.get(Direction.EAST);
case AW:
return TRACK_ASC.get(Direction.WEST);
case AN:
return TRACK_ASC.get(Direction.NORTH);
case AS:
return TRACK_ASC.get(Direction.SOUTH);
case CR_D:
return AllShapes.TRACK_CROSS_DIAG;
case CR_NDX:
return TRACK_CROSS_ORTHO_DIAG.get(Direction.SOUTH);
case CR_NDZ:
return TRACK_CROSS_DIAG_ORTHO.get(Direction.SOUTH);
case CR_O:
return AllShapes.TRACK_CROSS;
case CR_PDX:
return TRACK_CROSS_DIAG_ORTHO.get(Direction.EAST);
case CR_PDZ:
return TRACK_CROSS_ORTHO_DIAG.get(Direction.EAST);
case ND:
return TRACK_DIAG.get(Direction.SOUTH);
case PD:
return TRACK_DIAG.get(Direction.EAST);
case XO:
return TRACK_ORTHO.get(Direction.EAST);
case ZO:
return TRACK_ORTHO.get(Direction.SOUTH);
case NONE:
default:
}
return AllShapes.TRACK_FALLBACK;
} }
@Override @Override
@ -296,7 +351,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
TrackRemoval.wrenched(context.getClickedPos()); TrackRemoval.wrenched(context.getClickedPos());
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} }
@Override @Override
public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) { public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) {
if (context.getLevel().isClientSide) if (context.getLevel().isClientSide)

View file

@ -0,0 +1,118 @@
package com.simibubi.create.content.logistics.trains.track;
import java.util.function.Consumer;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.AllShapes;
import com.simibubi.create.foundation.utility.AngleHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.DrawSelectionEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@EventBusSubscriber(Dist.CLIENT)
public class TrackBlockOutline {
@SubscribeEvent
public static void drawCustomBlockSelection(DrawSelectionEvent.HighlightBlock event) {
Minecraft mc = Minecraft.getInstance();
BlockHitResult target = event.getTarget();
BlockPos pos = target.getBlockPos();
BlockState blockstate = mc.level.getBlockState(pos);
if (!(blockstate.getBlock() instanceof TrackBlock))
return;
if (!mc.level.getWorldBorder()
.isWithinBounds(pos))
return;
VertexConsumer vb = event.getMultiBufferSource()
.getBuffer(RenderType.lines());
PoseStack ms = event.getPoseStack();
ms.pushPose();
Vec3 camPos = event.getCamera()
.getPosition();
ms.translate(pos.getX() - camPos.x, pos.getY() - camPos.y, pos.getZ() - camPos.z);
walkShapes(blockstate.getValue(TrackBlock.SHAPE), TransformStack.cast(ms), s -> {
event.setCanceled(true);
PoseStack.Pose transform = ms.last();
s.forAllEdges((x1, y1, z1, x2, y2, z2) -> {
float xDiff = (float) (x2 - x1);
float yDiff = (float) (y2 - y1);
float zDiff = (float) (z2 - z1);
float length = Mth.sqrt(xDiff * xDiff + yDiff * yDiff + zDiff * zDiff);
xDiff /= length;
yDiff /= length;
zDiff /= length;
vb.vertex(transform.pose(), (float) x1, (float) y1, (float) z1)
.color(0f, 0f, 0f, .4f)
.normal(transform.normal(), xDiff, yDiff, zDiff)
.endVertex();
vb.vertex(transform.pose(), (float) x2, (float) y2, (float) z2)
.color(0f, 0f, 0f, .4f)
.normal(transform.normal(), xDiff, yDiff, zDiff)
.endVertex();
});
});
ms.popPose();
}
private static final VoxelShape LONG_CROSS =
Shapes.or(TrackVoxelShapes.longOrthogonalZ(), TrackVoxelShapes.longOrthogonalX());
private static final VoxelShape LONG_ORTHO = TrackVoxelShapes.longOrthogonalZ();
private static void walkShapes(TrackShape shape, TransformStack msr, Consumer<VoxelShape> renderer) {
float angle45 = Mth.PI / 4;
if (shape == TrackShape.XO || shape == TrackShape.CR_NDX || shape == TrackShape.CR_PDX)
renderer.accept(AllShapes.TRACK_ORTHO.get(Direction.EAST));
else if (shape == TrackShape.ZO || shape == TrackShape.CR_NDZ || shape == TrackShape.CR_PDZ)
renderer.accept(AllShapes.TRACK_ORTHO.get(Direction.SOUTH));
if (shape == TrackShape.PD || shape == TrackShape.CR_PDX || shape == TrackShape.CR_PDZ) {
msr.rotateCentered(Direction.UP, angle45);
renderer.accept(LONG_ORTHO);
} else if (shape == TrackShape.ND || shape == TrackShape.CR_NDX || shape == TrackShape.CR_NDZ) {
msr.rotateCentered(Direction.UP, -Mth.PI / 4);
renderer.accept(LONG_ORTHO);
}
if (shape == TrackShape.CR_O)
renderer.accept(AllShapes.TRACK_CROSS);
else if (shape == TrackShape.CR_D) {
msr.rotateCentered(Direction.UP, angle45);
renderer.accept(LONG_CROSS);
}
if (!(shape == TrackShape.AE || shape == TrackShape.AN || shape == TrackShape.AW || shape == TrackShape.AS))
return;
msr.translate(0, 1, 0);
msr.rotateCentered(Direction.UP, Mth.PI - AngleHelper.rad(shape.getModelRotation()));
msr.rotateXRadians(angle45);
msr.translate(0, -3 / 16f, 1 / 16f);
renderer.accept(LONG_ORTHO);
}
}

View file

@ -0,0 +1,56 @@
package com.simibubi.create.content.logistics.trains.track;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
public class TrackVoxelShapes {
public static VoxelShape orthogonal() {
return Block.box(-14, 0, 0, 16 + 14, 4, 16);
}
public static VoxelShape longOrthogonalX() {
return Block.box(-3.3, 0, -14, 19.3, 4, 16 + 14);
}
public static VoxelShape longOrthogonalZ() {
return Block.box(-14, 0, -3.3, 16 + 14, 4, 19.3);
}
public static VoxelShape ascending() {
VoxelShape shape = Block.box(-14, 0, 0, 16 + 14, 4, 4);
VoxelShape[] shapes = new VoxelShape[6];
for (int i = 0; i < 6; i++) {
int off = (i + 1) * 2;
shapes[i] = Block.box(-14, off, off, 16 + 14, 4 + off, 4 + off);
}
return Shapes.or(shape, shapes);
}
public static VoxelShape diagonal() {
VoxelShape shape = Block.box(0, 0, 0, 16, 4, 16);
VoxelShape[] shapes = new VoxelShape[12];
int off = 0;
for (int i = 0; i < 6; i++) {
off = (i + 1) * 2;
shapes[i * 2] = Block.box(off, 0, off, 16 + off, 4, 16 + off);
shapes[i * 2 + 1] = Block.box(-off, 0, -off, 16 - off, 4, 16 - off);
}
shape = Shapes.or(shape, shapes);
off = 10 * 2;
shape = Shapes.join(shape, Block.box(off, 0, off, 16 + off, 4, 16 + off), BooleanOp.ONLY_FIRST);
shape = Shapes.join(shape, Block.box(-off, 0, -off, 16 - off, 4, 16 - off), BooleanOp.ONLY_FIRST);
off = 4 * 2;
shape = Shapes.or(shape, Block.box(off, 0, off, 16 + off, 4, 16 + off));
shape = Shapes.or(shape, Block.box(-off, 0, -off, 16 - off, 4, 16 - off));
return shape.optimize();
}
}

View file

@ -0,0 +1,98 @@
package com.simibubi.create.foundation.block;
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.RaycastHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.ForgeMod;
public class BigOutlines {
static BlockHitResult result = null;
public static void pick() {
Minecraft mc = Minecraft.getInstance();
if (!(mc.cameraEntity instanceof LocalPlayer player))
return;
if (mc.level == null)
return;
result = null;
Vec3 origin = player.getEyePosition(AnimationTickHolder.getPartialTicks(mc.level));
double maxRange = mc.hitResult == null ? Double.MAX_VALUE
: mc.hitResult.getLocation()
.distanceToSqr(origin);
AttributeInstance range = player.getAttribute(ForgeMod.REACH_DISTANCE.get());
Vec3 target = RaycastHelper.getTraceTarget(player, Math.min(maxRange, range.getValue()) + 1, origin);
RaycastHelper.rayTraceUntil(origin, target, pos -> {
MutableBlockPos p = BlockPos.ZERO.mutable();
for (int x = -1; x <= 1; x++) {
for (int z = -1; z <= 1; z++) {
p.set(pos.getX() + x, pos.getY(), pos.getZ() + z);
BlockState blockState = mc.level.getBlockState(p);
// Could be a dedicated interface for big blocks
if (!(blockState.getBlock() instanceof TrackBlock))
continue;
BlockHitResult hit = blockState.getInteractionShape(mc.level, p)
.clip(origin, target, p.immutable());
if (hit == null)
continue;
if (result != null && Vec3.atCenterOf(p)
.distanceToSqr(origin) >= Vec3.atCenterOf(result.getBlockPos())
.distanceToSqr(origin))
continue;
Vec3 vec = hit.getLocation();
double interactionDist = vec.distanceToSqr(origin);
if (interactionDist >= maxRange)
continue;
BlockPos hitPos = hit.getBlockPos();
// pacifies ServerGamePacketListenerImpl.handleUseItemOn
vec = vec.subtract(Vec3.atCenterOf(hitPos));
vec = VecHelper.clampComponentWise(vec, 1);
vec = vec.add(Vec3.atCenterOf(hitPos));
result = new BlockHitResult(vec, hit.getDirection(), hitPos, hit.isInside());
}
}
return result != null;
});
if (result != null)
mc.hitResult = result;
}
static boolean isValidPos(Player player, BlockPos pos) {
// verify that the server will accept the fake result
double x = player.getX() - (pos.getX() + .5);
double y = player.getY() - (pos.getY() + .5) + 1.5;
double z = player.getZ() - (pos.getZ() + .5);
double distSqr = x * x + y * y + z * z;
double maxDist = player.getAttribute(ForgeMod.REACH_DISTANCE.get())
.getValue() + 1;
maxDist *= maxDist;
return distSqr <= maxDist;
}
}

View file

@ -13,7 +13,7 @@ import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.client.IBlockRenderProperties; import net.minecraftforge.client.IBlockRenderProperties;
public class ReducedDestroyEffects implements IBlockRenderProperties { public class ReducedDestroyEffects implements IBlockRenderProperties {
@Override @Override
public boolean addDestroyEffects(BlockState state, Level worldIn, BlockPos pos, ParticleEngine manager) { public boolean addDestroyEffects(BlockState state, Level worldIn, BlockPos pos, ParticleEngine manager) {
if (!(worldIn instanceof ClientLevel)) if (!(worldIn instanceof ClientLevel))
@ -27,34 +27,35 @@ public class ReducedDestroyEffects implements IBlockRenderProperties {
if (state.isAir()) if (state.isAir())
return true; return true;
voxelshape.forAllBoxes((p_172273_, p_172274_, p_172275_, p_172276_, p_172277_, p_172278_) -> { voxelshape.forAllBoxes((x1, y1, z1, x2, y2, z2) -> {
double d1 = Math.min(1.0D, p_172276_ - p_172273_); double w = x2 - x1;
double d2 = Math.min(1.0D, p_172277_ - p_172274_); double h = y2 - y1;
double d3 = Math.min(1.0D, p_172278_ - p_172275_); double l = z2 - z1;
int i = Math.max(2, Mth.ceil(d1 / 0.25D)); int xParts = Math.max(2, Mth.ceil(Math.min(1, w) * 4));
int j = Math.max(2, Mth.ceil(d2 / 0.25D)); int yParts = Math.max(2, Mth.ceil(Math.min(1, h) * 4));
int k = Math.max(2, Mth.ceil(d3 / 0.25D)); int zParts = Math.max(2, Mth.ceil(Math.min(1, l) * 4));
for (int l = 0; l < i; ++l) { for (int xIndex = 0; xIndex < xParts; ++xIndex) {
for (int i1 = 0; i1 < j; ++i1) { for (int yIndex = 0; yIndex < yParts; ++yIndex) {
for (int j1 = 0; j1 < k; ++j1) { for (int zIndex = 0; zIndex < zParts; ++zIndex) {
if (world.random.nextDouble() > chance) if (world.random.nextDouble() > chance)
continue; continue;
double d4 = ((double) l + 0.5D) / (double) i; double d4 = (xIndex + .5) / xParts;
double d5 = ((double) i1 + 0.5D) / (double) j; double d5 = (yIndex + .5) / yParts;
double d6 = ((double) j1 + 0.5D) / (double) k; double d6 = (zIndex + .5) / zParts;
double d7 = d4 * d1 + p_172273_; double x = pos.getX() + d4 * w + x1;
double d8 = d5 * d2 + p_172274_; double y = pos.getY() + d5 * h + y1;
double d9 = d6 * d3 + p_172275_; double z = pos.getZ() + d6 * l + z1;
manager.add(new TerrainParticle(world, pos.getX() + d7, pos.getY() + d8, pos.getZ() + d9,
d4 - 0.5D, d5 - 0.5D, d6 - 0.5D, state, pos).updateSprite(state, pos)); manager.add(new TerrainParticle(world, x, y, z, d4 - 0.5D, d5 - 0.5D, d6 - 0.5D, state, pos)
.updateSprite(state, pos));
} }
} }
} }
}); });
return true; return true;
} }
} }

View file

@ -0,0 +1,23 @@
package com.simibubi.create.foundation.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.simibubi.create.foundation.block.BigOutlines;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
@Mixin(GameRenderer.class)
public class GameRendererMixin {
@Inject(at = @At("TAIL"), method = "pick")
private void bigShapePick(CallbackInfo ci) {
BigOutlines.pick();
}
}

View file

@ -3,6 +3,7 @@ package com.simibubi.create.foundation.utility;
import java.util.function.Predicate; import java.util.function.Predicate;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@ -64,10 +65,10 @@ public class RaycastHelper {
int y = Mth.floor(start.y); int y = Mth.floor(start.y);
int z = Mth.floor(start.z); int z = Mth.floor(start.z);
BlockPos currentPos = new BlockPos(x, y, z); MutableBlockPos currentPos = new BlockPos(x, y, z).mutable();
if (predicate.test(currentPos)) if (predicate.test(currentPos))
return new PredicateTraceResult(currentPos, Direction.getNearest(dx - x, dy - y, dz - z)); return new PredicateTraceResult(currentPos.immutable(), Direction.getNearest(dx - x, dy - y, dz - z));
int remainingDistance = 200; int remainingDistance = 200;
@ -158,10 +159,10 @@ public class RaycastHelper {
x = Mth.floor(start.x) - (enumfacing == Direction.EAST ? 1 : 0); x = Mth.floor(start.x) - (enumfacing == Direction.EAST ? 1 : 0);
y = Mth.floor(start.y) - (enumfacing == Direction.UP ? 1 : 0); y = Mth.floor(start.y) - (enumfacing == Direction.UP ? 1 : 0);
z = Mth.floor(start.z) - (enumfacing == Direction.SOUTH ? 1 : 0); z = Mth.floor(start.z) - (enumfacing == Direction.SOUTH ? 1 : 0);
currentPos = new BlockPos(x, y, z); currentPos.set(x, y, z);
if (predicate.test(currentPos)) if (predicate.test(currentPos))
return new PredicateTraceResult(currentPos, enumfacing); return new PredicateTraceResult(currentPos.immutable(), enumfacing);
} }
return new PredicateTraceResult(); return new PredicateTraceResult();

View file

@ -19,6 +19,7 @@
"HeavyBootsOnPlayerMixin", "HeavyBootsOnPlayerMixin",
"ModelDataRefreshMixin", "ModelDataRefreshMixin",
"WindowResizeMixin", "WindowResizeMixin",
"GameRendererMixin",
"accessor.AgeableListModelAccessor", "accessor.AgeableListModelAccessor",
"accessor.GameRendererAccessor", "accessor.GameRendererAccessor",
"accessor.ParticleEngineAccessor" "accessor.ParticleEngineAccessor"