mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-14 14:34:16 +01:00
Actually Tilted
- Unsightly amendments to the track graph for a smoother ride
This commit is contained in:
parent
7dc6fc7576
commit
0dd8c3a4f1
@ -226,6 +226,7 @@ import com.simibubi.create.content.logistics.trains.track.StandardBogeyBlock;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlockItem;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlockStateGenerator;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackModel;
|
||||
import com.simibubi.create.content.schematics.block.SchematicTableBlock;
|
||||
import com.simibubi.create.content.schematics.block.SchematicannonBlock;
|
||||
import com.simibubi.create.foundation.block.BlockStressDefaults;
|
||||
@ -1541,6 +1542,7 @@ public class AllBlocks {
|
||||
.noOcclusion())
|
||||
.addLayer(() -> RenderType::cutoutMipped)
|
||||
.transform(pickaxeOnly())
|
||||
.onRegister(CreateRegistrate.blockModel(() -> TrackModel::new))
|
||||
.blockstate(new TrackBlockStateGenerator()::generate)
|
||||
.tag(AllBlockTags.RELOCATION_NOT_SUPPORTED.tag)
|
||||
.lang("Train Track")
|
||||
|
@ -6,9 +6,11 @@ import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack.Pose;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlockEntityTilt;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackRenderer;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
@ -37,6 +39,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
||||
public Couple<Vec3> starts;
|
||||
public Couple<Vec3> axes;
|
||||
public Couple<Vec3> normals;
|
||||
public Couple<Integer> smoothing;
|
||||
public boolean primary;
|
||||
public boolean hasGirder;
|
||||
|
||||
@ -66,8 +69,15 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
||||
}
|
||||
|
||||
public BezierConnection secondary() {
|
||||
return new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), !primary,
|
||||
hasGirder);
|
||||
BezierConnection bezierConnection =
|
||||
new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), !primary, hasGirder);
|
||||
if (smoothing != null)
|
||||
bezierConnection.smoothing = smoothing.swap();
|
||||
return bezierConnection;
|
||||
}
|
||||
|
||||
public BezierConnection clone() {
|
||||
return secondary().secondary();
|
||||
}
|
||||
|
||||
public BezierConnection(CompoundTag compound, BlockPos localTo) {
|
||||
@ -78,6 +88,10 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
||||
Couple.deserializeEach(compound.getList("Axes", Tag.TAG_COMPOUND), VecHelper::readNBTCompound),
|
||||
Couple.deserializeEach(compound.getList("Normals", Tag.TAG_COMPOUND), VecHelper::readNBTCompound),
|
||||
compound.getBoolean("Primary"), compound.getBoolean("Girder"));
|
||||
|
||||
if (compound.contains("Smoothing"))
|
||||
smoothing =
|
||||
Couple.deserializeEach(compound.getList("Smoothing", Tag.TAG_COMPOUND), NBTHelper::intFromCompound);
|
||||
}
|
||||
|
||||
public CompoundTag write(BlockPos localTo) {
|
||||
@ -91,6 +105,10 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
||||
compound.put("Starts", starts.serializeEach(VecHelper::writeNBTCompound));
|
||||
compound.put("Axes", axes.serializeEach(VecHelper::writeNBTCompound));
|
||||
compound.put("Normals", normals.serializeEach(VecHelper::writeNBTCompound));
|
||||
|
||||
if (smoothing != null)
|
||||
compound.put("Smoothing", smoothing.serializeEach(NBTHelper::intToCompound));
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
@ -98,6 +116,8 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
||||
this(Couple.create(buffer::readBlockPos), Couple.create(() -> VecHelper.read(buffer)),
|
||||
Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)),
|
||||
buffer.readBoolean(), buffer.readBoolean());
|
||||
if (buffer.readBoolean())
|
||||
smoothing = Couple.create(buffer::readVarInt);
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
@ -107,6 +127,9 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
||||
normals.forEach(v -> VecHelper.write(v, buffer));
|
||||
buffer.writeBoolean(primary);
|
||||
buffer.writeBoolean(hasGirder);
|
||||
buffer.writeBoolean(smoothing != null);
|
||||
if (smoothing != null)
|
||||
smoothing.forEach(buffer::writeVarInt);
|
||||
}
|
||||
|
||||
public BlockPos getKey() {
|
||||
@ -117,6 +140,16 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
||||
return primary;
|
||||
}
|
||||
|
||||
public int yOffsetAt(Vec3 end) {
|
||||
if (smoothing == null)
|
||||
return 0;
|
||||
if (TrackBlockEntityTilt.compareHandles(starts.getFirst(), end))
|
||||
return smoothing.getFirst();
|
||||
if (TrackBlockEntityTilt.compareHandles(starts.getSecond(), end))
|
||||
return smoothing.getSecond();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Runtime information
|
||||
|
||||
public double getLength() {
|
||||
|
@ -38,6 +38,10 @@ public interface ITrackBlock {
|
||||
|
||||
public Vec3 getCurveStart(BlockGetter world, BlockPos pos, BlockState state, Vec3 axis);
|
||||
|
||||
public default int getYOffsetAt(BlockGetter world, BlockPos pos, BlockState state, Vec3 end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public BlockState getBogeyAnchor(BlockGetter world, BlockPos pos, BlockState state); // should be on bogey side
|
||||
|
||||
public boolean trackEquals(BlockState state1, BlockState state2);
|
||||
@ -71,10 +75,17 @@ public interface ITrackBlock {
|
||||
.add(0, getElevationAtCenter(world, pos, state), 0);
|
||||
List<DiscoveredLocation> list = new ArrayList<>();
|
||||
TrackShape shape = state.getValue(TrackBlock.SHAPE);
|
||||
getTrackAxes(world, pos, state).forEach(axis -> {
|
||||
addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? d : -d)
|
||||
.add(center), b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD,
|
||||
axis, null);
|
||||
List<Vec3> trackAxes = getTrackAxes(world, pos, state);
|
||||
|
||||
trackAxes.forEach(axis -> {
|
||||
BiFunction<Double, Boolean, Vec3> offsetFactory = (d, b) -> axis.scale(b ? d : -d)
|
||||
.add(center);
|
||||
Function<Boolean, ResourceKey<Level>> dimensionFactory =
|
||||
b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD;
|
||||
Function<Vec3, Integer> yOffsetFactory = v -> getYOffsetAt(world, pos, state, v);
|
||||
|
||||
addToListIfConnected(connectedTo, list, offsetFactory, b -> shape.getNormal(), dimensionFactory,
|
||||
yOffsetFactory, axis, null);
|
||||
});
|
||||
|
||||
return list;
|
||||
@ -82,22 +93,28 @@ public interface ITrackBlock {
|
||||
|
||||
public static void addToListIfConnected(@Nullable TrackNodeLocation fromEnd, Collection<DiscoveredLocation> list,
|
||||
BiFunction<Double, Boolean, Vec3> offsetFactory, Function<Boolean, Vec3> normalFactory,
|
||||
Function<Boolean, ResourceKey<Level>> dimensionFactory, Vec3 axis, BezierConnection viaTurn) {
|
||||
Function<Boolean, ResourceKey<Level>> dimensionFactory, Function<Vec3, Integer> yOffsetFactory, Vec3 axis,
|
||||
BezierConnection viaTurn) {
|
||||
|
||||
Vec3 firstOffset = offsetFactory.apply(0.5d, true);
|
||||
DiscoveredLocation firstLocation =
|
||||
new DiscoveredLocation(dimensionFactory.apply(true), offsetFactory.apply(0.5d, true)).viaTurn(viaTurn)
|
||||
new DiscoveredLocation(dimensionFactory.apply(true), firstOffset).viaTurn(viaTurn)
|
||||
.withNormal(normalFactory.apply(true))
|
||||
.withDirection(axis);
|
||||
.withDirection(axis)
|
||||
.withYOffset(yOffsetFactory.apply(firstOffset));
|
||||
|
||||
Vec3 secondOffset = offsetFactory.apply(0.5d, false);
|
||||
DiscoveredLocation secondLocation =
|
||||
new DiscoveredLocation(dimensionFactory.apply(false), offsetFactory.apply(0.5d, false)).viaTurn(viaTurn)
|
||||
new DiscoveredLocation(dimensionFactory.apply(false), secondOffset).viaTurn(viaTurn)
|
||||
.withNormal(normalFactory.apply(false))
|
||||
.withDirection(axis);
|
||||
.withDirection(axis)
|
||||
.withYOffset(yOffsetFactory.apply(secondOffset));
|
||||
|
||||
if (!firstLocation.dimension.equals(secondLocation.dimension)) {
|
||||
firstLocation.forceNode();
|
||||
secondLocation.forceNode();
|
||||
}
|
||||
|
||||
|
||||
boolean skipFirst = false;
|
||||
boolean skipSecond = false;
|
||||
|
||||
|
@ -67,6 +67,7 @@ public class TrackGraphHelper {
|
||||
TrackNode frontNode = null;
|
||||
TrackNode backNode = null;
|
||||
double position = 0;
|
||||
boolean singleTrackPiece = true;
|
||||
|
||||
for (DiscoveredLocation current : ends) {
|
||||
Vec3 offset = current.getLocation()
|
||||
@ -74,14 +75,19 @@ public class TrackGraphHelper {
|
||||
.normalize()
|
||||
.scale(length);
|
||||
|
||||
boolean forward = offset.distanceToSqr(axis.scale(-1)) < 1 / 4096f;
|
||||
boolean backwards = offset.distanceToSqr(axis) < 1 / 4096f;
|
||||
Vec3 compareOffset = offset.multiply(1, 0, 1)
|
||||
.normalize();
|
||||
boolean forward = compareOffset.distanceToSqr(axis.multiply(-1, 0, -1)
|
||||
.normalize()) < 1 / 4096f;
|
||||
boolean backwards = compareOffset.distanceToSqr(axis.multiply(1, 0, 1)
|
||||
.normalize()) < 1 / 4096f;
|
||||
|
||||
if (!forward && !backwards)
|
||||
continue;
|
||||
|
||||
DiscoveredLocation previous = null;
|
||||
double distance = 0;
|
||||
|
||||
for (int i = 0; i < 100 && distance < 32; i++) {
|
||||
DiscoveredLocation loc = current;
|
||||
if (graph == null)
|
||||
@ -89,6 +95,7 @@ public class TrackGraphHelper {
|
||||
.getGraph(level, loc);
|
||||
|
||||
if (graph == null || graph.locateNode(loc) == null) {
|
||||
singleTrackPiece = false;
|
||||
Collection<DiscoveredLocation> list = ITrackBlock.walkConnectedTracks(level, loc, true);
|
||||
for (DiscoveredLocation discoveredLocation : list) {
|
||||
if (discoveredLocation == previous)
|
||||
@ -121,6 +128,13 @@ public class TrackGraphHelper {
|
||||
if (frontNode == null || backNode == null)
|
||||
return null;
|
||||
|
||||
if (singleTrackPiece)
|
||||
position = frontNode.getLocation()
|
||||
.getLocation()
|
||||
.distanceTo(backNode.getLocation()
|
||||
.getLocation())
|
||||
/ 2.0;
|
||||
|
||||
GraphLocation graphLocation = new GraphLocation();
|
||||
graphLocation.edge = Couple.create(backNode.getLocation(), frontNode.getLocation());
|
||||
graphLocation.position = position;
|
||||
@ -143,6 +157,9 @@ public class TrackGraphHelper {
|
||||
return null;
|
||||
|
||||
TrackNodeLocation targetLoc = new TrackNodeLocation(bc.starts.getSecond()).in(level);
|
||||
if (bc.smoothing != null)
|
||||
targetLoc.yOffsetPixels = bc.smoothing.getSecond();
|
||||
|
||||
for (DiscoveredLocation location : track.getConnected(level, pos, state, true, null)) {
|
||||
TrackGraph graph = Create.RAILWAYS.sided(level)
|
||||
.getGraph(level, location);
|
||||
|
@ -19,13 +19,14 @@ import net.minecraft.world.phys.Vec3;
|
||||
public class TrackNodeLocation extends Vec3i {
|
||||
|
||||
public ResourceKey<Level> dimension;
|
||||
public int yOffsetPixels;
|
||||
|
||||
public TrackNodeLocation(Vec3 vec) {
|
||||
this(vec.x, vec.y, vec.z);
|
||||
}
|
||||
|
||||
public TrackNodeLocation(double p_121865_, double p_121866_, double p_121867_) {
|
||||
super(Math.round(p_121865_ * 2), Math.floor(p_121866_ * 2), Math.round(p_121867_ * 2));
|
||||
super(Math.round(p_121865_ * 2), Math.floor(p_121866_) * 2, Math.round(p_121867_ * 2));
|
||||
}
|
||||
|
||||
public TrackNodeLocation in(Level level) {
|
||||
@ -46,7 +47,7 @@ public class TrackNodeLocation extends Vec3i {
|
||||
}
|
||||
|
||||
public Vec3 getLocation() {
|
||||
return new Vec3(getX() / 2.0, getY() / 2.0, getZ() / 2.0);
|
||||
return new Vec3(getX() / 2.0, getY() / 2.0 + yOffsetPixels / 16.0, getZ() / 2.0);
|
||||
}
|
||||
|
||||
public ResourceKey<Level> getDimension() {
|
||||
@ -60,18 +61,20 @@ public class TrackNodeLocation extends Vec3i {
|
||||
}
|
||||
|
||||
public boolean equalsIgnoreDim(Object pOther) {
|
||||
return super.equals(pOther);
|
||||
return super.equals(pOther) && pOther instanceof TrackNodeLocation tnl && tnl.yOffsetPixels == yOffsetPixels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (this.getY() + (this.getZ() * 31 + dimension.hashCode()) * 31) * 31 + this.getX();
|
||||
return (getY() + ((getZ() + yOffsetPixels * 31) * 31 + dimension.hashCode()) * 31) * 31 + getX();
|
||||
}
|
||||
|
||||
public CompoundTag write(DimensionPalette dimensions) {
|
||||
CompoundTag c = NbtUtils.writeBlockPos(new BlockPos(this));
|
||||
if (dimensions != null)
|
||||
c.putInt("D", dimensions.encode(dimension));
|
||||
if (yOffsetPixels != 0)
|
||||
c.putInt("YO", yOffsetPixels);
|
||||
return c;
|
||||
}
|
||||
|
||||
@ -79,13 +82,15 @@ public class TrackNodeLocation extends Vec3i {
|
||||
TrackNodeLocation location = fromPackedPos(NbtUtils.readBlockPos(tag));
|
||||
if (dimensions != null)
|
||||
location.dimension = dimensions.decode(tag.getInt("D"));
|
||||
location.yOffsetPixels = tag.getInt("YO");
|
||||
return location;
|
||||
}
|
||||
|
||||
public void send(FriendlyByteBuf buffer, DimensionPalette dimensions) {
|
||||
buffer.writeVarInt(this.getX());
|
||||
buffer.writeShort(this.getY());
|
||||
buffer.writeVarInt(this.getZ());
|
||||
buffer.writeVarInt(getX());
|
||||
buffer.writeShort(getY());
|
||||
buffer.writeVarInt(getZ());
|
||||
buffer.writeVarInt(yOffsetPixels);
|
||||
buffer.writeVarInt(dimensions.encode(dimension));
|
||||
}
|
||||
|
||||
@ -95,13 +100,14 @@ public class TrackNodeLocation extends Vec3i {
|
||||
buffer.readShort(),
|
||||
buffer.readVarInt()
|
||||
));
|
||||
location.yOffsetPixels = buffer.readVarInt();
|
||||
location.dimension = dimensions.decode(buffer.readVarInt());
|
||||
return location;
|
||||
}
|
||||
|
||||
public Collection<BlockPos> allAdjacent() {
|
||||
Set<BlockPos> set = new HashSet<>();
|
||||
Vec3 vec3 = getLocation();
|
||||
Vec3 vec3 = getLocation().subtract(0, yOffsetPixels / 16.0, 0);
|
||||
double step = 1 / 8f;
|
||||
for (int x : Iterate.positiveAndNegative)
|
||||
for (int y : Iterate.positiveAndNegative)
|
||||
@ -147,6 +153,11 @@ public class TrackNodeLocation extends Vec3i {
|
||||
this.normal = normal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DiscoveredLocation withYOffset(int yOffsetPixels) {
|
||||
this.yOffsetPixels = yOffsetPixels;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DiscoveredLocation withDirection(Vec3 direction) {
|
||||
this.direction = direction == null ? null : direction.normalize();
|
||||
|
@ -124,7 +124,7 @@ public class TrackBlock extends Block
|
||||
protected void createBlockStateDefinition(Builder<Block, BlockState> p_49915_) {
|
||||
super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_BE, WATERLOGGED));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockPathTypes getAiPathNodeType(BlockState state, BlockGetter world, BlockPos pos, Mob entity) {
|
||||
return BlockPathTypes.RAIL;
|
||||
@ -208,7 +208,7 @@ public class TrackBlock extends Block
|
||||
return;
|
||||
withBlockEntityDo(pLevel, pPos, be -> {
|
||||
be.cancelDrops = true;
|
||||
be.removeInboundConnections();
|
||||
be.removeInboundConnections(true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -233,6 +233,7 @@ public class TrackBlock extends Block
|
||||
@Override
|
||||
public void tick(BlockState state, ServerLevel level, BlockPos pos, Random p_60465_) {
|
||||
TrackPropagator.onRailAdded(level, pos, state);
|
||||
withBlockEntityDo(level, pos, tbe -> tbe.tilt.undoSmoothing());
|
||||
if (!state.getValue(SHAPE)
|
||||
.isPortal())
|
||||
connectToNether(level, pos, state);
|
||||
@ -297,12 +298,14 @@ public class TrackBlock extends Block
|
||||
Player player = level.getNearestPlayer(pos.getX(), pos.getY(), pos.getZ(), 10, Predicates.alwaysTrue());
|
||||
if (player == null)
|
||||
return;
|
||||
player.displayClientMessage(Components.literal("<!> ").append(Lang.translateDirect("portal_track.failed"))
|
||||
player.displayClientMessage(Components.literal("<!> ")
|
||||
.append(Lang.translateDirect("portal_track.failed"))
|
||||
.withStyle(ChatFormatting.GOLD), false);
|
||||
MutableComponent component =
|
||||
failPos != null ? Lang.translateDirect("portal_track." + fail, failPos.getX(), failPos.getY(), failPos.getZ())
|
||||
: Lang.translateDirect("portal_track." + fail);
|
||||
player.displayClientMessage(Components.literal(" - ").withStyle(ChatFormatting.GRAY)
|
||||
MutableComponent component = failPos != null
|
||||
? Lang.translateDirect("portal_track." + fail, failPos.getX(), failPos.getY(), failPos.getZ())
|
||||
: Lang.translateDirect("portal_track." + fail);
|
||||
player.displayClientMessage(Components.literal(" - ")
|
||||
.withStyle(ChatFormatting.GRAY)
|
||||
.append(component.withStyle(st -> st.withColor(0xFFD3B4))), false);
|
||||
}
|
||||
|
||||
@ -361,6 +364,12 @@ public class TrackBlock extends Block
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getYOffsetAt(BlockGetter world, BlockPos pos, BlockState state, Vec3 end) {
|
||||
return getBlockEntityOptional(world, pos).map(tbe -> tbe.tilt.getYOffsetForAxisEnd(end))
|
||||
.orElse(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<DiscoveredLocation> getConnected(BlockGetter worldIn, BlockPos pos, BlockState state,
|
||||
boolean linear, TrackNodeLocation connectedTo) {
|
||||
@ -378,8 +387,8 @@ public class TrackBlock extends Block
|
||||
ITrackBlock.addToListIfConnected(connectedTo, list,
|
||||
(d, b) -> axis.scale(b ? 0 : fromCenter ? -d : d)
|
||||
.add(center),
|
||||
b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, axis,
|
||||
null);
|
||||
b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, v -> 0,
|
||||
axis, null);
|
||||
} else
|
||||
list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo);
|
||||
|
||||
@ -395,7 +404,7 @@ public class TrackBlock extends Block
|
||||
Map<BlockPos, BezierConnection> connections = trackTE.getConnections();
|
||||
connections.forEach((connectedPos, bc) -> ITrackBlock.addToListIfConnected(connectedTo, list,
|
||||
(d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get,
|
||||
b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, null, bc));
|
||||
b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, bc::yOffsetAt, null, bc));
|
||||
|
||||
if (trackTE.boundLocation == null || !(world instanceof ServerLevel level))
|
||||
return list;
|
||||
@ -421,7 +430,7 @@ public class TrackBlock extends Block
|
||||
getTrackAxes(world, pos, state).forEach(axis -> {
|
||||
ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> (b ? axis : boundAxis).scale(d)
|
||||
.add(b ? center : boundCenter), b -> (b ? shape : boundShape).getNormal(),
|
||||
b -> b ? level.dimension() : otherLevel.dimension(), axis, null);
|
||||
b -> b ? level.dimension() : otherLevel.dimension(), v -> 0, axis, null);
|
||||
});
|
||||
|
||||
return list;
|
||||
@ -444,8 +453,10 @@ public class TrackBlock extends Block
|
||||
boolean removeBE = false;
|
||||
if (pState.getValue(HAS_BE) && (!pState.is(pNewState.getBlock()) || !pNewState.getValue(HAS_BE))) {
|
||||
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
|
||||
if (blockEntity instanceof TrackBlockEntity && !pLevel.isClientSide)
|
||||
((TrackBlockEntity) blockEntity).removeInboundConnections();
|
||||
if (blockEntity instanceof TrackBlockEntity tbe && !pLevel.isClientSide) {
|
||||
tbe.cancelDrops |= pNewState.getBlock() == this;
|
||||
tbe.removeInboundConnections(true);
|
||||
}
|
||||
removeBE = true;
|
||||
}
|
||||
|
||||
@ -468,7 +479,7 @@ public class TrackBlock extends Block
|
||||
if (!entry.getValue()
|
||||
.isInside(pos))
|
||||
continue;
|
||||
if (world.getBlockEntity(entry.getKey()) instanceof StationBlockEntity station)
|
||||
if (world.getBlockEntity(entry.getKey())instanceof StationBlockEntity station)
|
||||
if (station.trackClicked(player, hand, this, state, pos))
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
@ -484,7 +495,7 @@ public class TrackBlock extends Block
|
||||
BlockPos girderPos = pPos.below()
|
||||
.offset(vec3.z * side, 0, vec3.x * side);
|
||||
BlockState girderState = pLevel.getBlockState(girderPos);
|
||||
if (girderState.getBlock() instanceof GirderBlock girderBlock
|
||||
if (girderState.getBlock()instanceof GirderBlock girderBlock
|
||||
&& !blockTicks.hasScheduledTick(girderPos, girderBlock))
|
||||
pLevel.scheduleTick(girderPos, girderBlock, 1);
|
||||
}
|
||||
@ -689,7 +700,7 @@ public class TrackBlock extends Block
|
||||
Vec3 normal = null;
|
||||
Vec3 offset = null;
|
||||
|
||||
if (bezierPoint != null && world.getBlockEntity(pos) instanceof TrackBlockEntity trackTE) {
|
||||
if (bezierPoint != null && world.getBlockEntity(pos)instanceof TrackBlockEntity trackTE) {
|
||||
BezierConnection bc = trackTE.connections.get(bezierPoint.curveTarget());
|
||||
if (bc != null) {
|
||||
double length = Mth.floor(bc.getLength() * 2);
|
||||
@ -734,6 +745,16 @@ public class TrackBlock extends Block
|
||||
msr.rotateCentered(Direction.UP, Mth.PI);
|
||||
}
|
||||
|
||||
if (bezierPoint == null && world.getBlockEntity(pos)instanceof TrackBlockEntity trackTE && trackTE.isTilted()) {
|
||||
double yOffset = 0;
|
||||
for (BezierConnection bc : trackTE.connections.values())
|
||||
yOffset += bc.starts.getFirst().y - pos.getY();
|
||||
msr.centre()
|
||||
.rotateX(-direction.getStep() * trackTE.tilt.smoothingAngle.get())
|
||||
.unCentre()
|
||||
.translate(0, yOffset / 2, 0);
|
||||
}
|
||||
|
||||
return switch (type) {
|
||||
case DUAL_SIGNAL -> AllBlockPartials.TRACK_SIGNAL_DUAL_OVERLAY;
|
||||
case OBSERVER -> AllBlockPartials.TRACK_OBSERVER_OVERLAY;
|
||||
@ -779,8 +800,7 @@ public class TrackBlock extends Block
|
||||
public static class RenderProperties extends ReducedDestroyEffects implements MultiPosDestructionHandler {
|
||||
@Override
|
||||
@Nullable
|
||||
public Set<BlockPos> getExtraPositions(ClientLevel level, BlockPos pos, BlockState blockState,
|
||||
int progress) {
|
||||
public Set<BlockPos> getExtraPositions(ClientLevel level, BlockPos pos, BlockState blockState, int progress) {
|
||||
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||
if (blockEntity instanceof TrackBlockEntity track) {
|
||||
return new HashSet<>(track.connections.keySet());
|
||||
|
@ -5,6 +5,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
@ -44,6 +45,8 @@ import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.client.model.data.IModelData;
|
||||
import net.minecraftforge.client.model.data.ModelDataMap;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
public class TrackBlockEntity extends SmartBlockEntity implements ITransformableTE, IMergeableBE {
|
||||
@ -52,11 +55,13 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
||||
boolean cancelDrops;
|
||||
|
||||
public Pair<ResourceKey<Level>, BlockPos> boundLocation;
|
||||
public TrackBlockEntityTilt tilt;
|
||||
|
||||
public TrackBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
connections = new HashMap<>();
|
||||
setLazyTickRate(100);
|
||||
tilt = new TrackBlockEntityTilt(this);
|
||||
}
|
||||
|
||||
public Map<BlockPos, BezierConnection> getConnections() {
|
||||
@ -70,6 +75,12 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
||||
registerToCurveInteraction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
tilt.undoSmoothing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lazyTick() {
|
||||
for (BezierConnection connection : connections.values())
|
||||
@ -103,8 +114,10 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!trackTE.connections.containsKey(worldPosition))
|
||||
if (!trackTE.connections.containsKey(worldPosition)) {
|
||||
trackTE.addConnection(bc.secondary());
|
||||
trackTE.tilt.tryApplySmoothing();
|
||||
}
|
||||
}
|
||||
|
||||
for (BlockPos blockPos : invalid)
|
||||
@ -121,6 +134,9 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
||||
}
|
||||
|
||||
public void removeConnection(BlockPos target) {
|
||||
if (isTilted())
|
||||
tilt.captureSmoothingHandles();
|
||||
|
||||
BezierConnection removed = connections.remove(target);
|
||||
notifyUpdate();
|
||||
|
||||
@ -138,19 +154,20 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
||||
AllPackets.channel.send(packetTarget(), new RemoveBlockEntityPacket(worldPosition));
|
||||
}
|
||||
|
||||
public void removeInboundConnections() {
|
||||
public void removeInboundConnections(boolean dropAndDiscard) {
|
||||
for (BezierConnection bezierConnection : connections.values()) {
|
||||
BlockEntity blockEntity = level.getBlockEntity(bezierConnection.getKey());
|
||||
if (!(blockEntity instanceof TrackBlockEntity))
|
||||
if (!(level.getBlockEntity(bezierConnection.getKey())instanceof TrackBlockEntity tbe))
|
||||
return;
|
||||
TrackBlockEntity other = (TrackBlockEntity) blockEntity;
|
||||
other.removeConnection(bezierConnection.tePositions.getFirst());
|
||||
|
||||
tbe.removeConnection(bezierConnection.tePositions.getFirst());
|
||||
if (!dropAndDiscard)
|
||||
continue;
|
||||
if (!cancelDrops)
|
||||
bezierConnection.spawnItems(level);
|
||||
bezierConnection.spawnDestroyParticles(level);
|
||||
}
|
||||
AllPackets.channel.send(packetTarget(), new RemoveBlockEntityPacket(worldPosition));
|
||||
|
||||
if (dropAndDiscard)
|
||||
AllPackets.channel.send(packetTarget(), new RemoveBlockEntityPacket(worldPosition));
|
||||
}
|
||||
|
||||
public void bind(ResourceKey<Level> boundDimension, BlockPos boundLocation) {
|
||||
@ -158,16 +175,22 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
||||
setChanged();
|
||||
}
|
||||
|
||||
public boolean isTilted() {
|
||||
return tilt.smoothingAngle.isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSafe(CompoundTag tag) {
|
||||
super.writeSafe(tag);
|
||||
writeTurns(tag);
|
||||
writeTurns(tag, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(CompoundTag tag, boolean clientPacket) {
|
||||
super.write(tag, clientPacket);
|
||||
writeTurns(tag);
|
||||
writeTurns(tag, false);
|
||||
if (isTilted())
|
||||
tag.putDouble("Smoothing", tilt.smoothingAngle.get());
|
||||
if (boundLocation == null)
|
||||
return;
|
||||
tag.put("BoundLocation", NbtUtils.writeBlockPos(boundLocation.getSecond()));
|
||||
@ -176,10 +199,11 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
||||
.toString());
|
||||
}
|
||||
|
||||
private void writeTurns(CompoundTag tag) {
|
||||
private void writeTurns(CompoundTag tag, boolean restored) {
|
||||
ListTag listTag = new ListTag();
|
||||
for (BezierConnection bezierConnection : connections.values())
|
||||
listTag.add(bezierConnection.write(worldPosition));
|
||||
listTag.add((restored ? tilt.restoreToOriginalCurve(bezierConnection.clone()) : bezierConnection)
|
||||
.write(worldPosition));
|
||||
tag.put("Connections", listTag);
|
||||
}
|
||||
|
||||
@ -194,6 +218,13 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
||||
connections.put(connection.getKey(), connection);
|
||||
}
|
||||
|
||||
boolean smoothingPreviously = tilt.smoothingAngle.isPresent();
|
||||
tilt.smoothingAngle = Optional.ofNullable(tag.contains("Smoothing") ? tag.getDouble("Smoothing") : null);
|
||||
if (smoothingPreviously != tilt.smoothingAngle.isPresent() && clientPacket) {
|
||||
requestModelDataUpdate();
|
||||
level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 16);
|
||||
}
|
||||
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this));
|
||||
|
||||
if (hasInteractableConnections())
|
||||
@ -233,6 +264,15 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
||||
|
||||
@Override
|
||||
public void transform(StructureTransform transform) {
|
||||
Map<BlockPos, BezierConnection> restoredConnections = new HashMap<>();
|
||||
for (Entry<BlockPos, BezierConnection> entry : connections.entrySet())
|
||||
restoredConnections.put(entry.getKey(),
|
||||
tilt.restoreToOriginalCurve(tilt.restoreToOriginalCurve(entry.getValue()
|
||||
.secondary())
|
||||
.secondary()));
|
||||
connections = restoredConnections;
|
||||
tilt.smoothingAngle = Optional.empty();
|
||||
|
||||
if (transform.rotationAxis != Axis.Y)
|
||||
return;
|
||||
|
||||
@ -300,6 +340,15 @@ public class TrackBlockEntity extends SmartBlockEntity implements ITransformable
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::removeFromCurveInteractionUnsafe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModelData getModelData() {
|
||||
if (!isTilted())
|
||||
return super.getModelData();
|
||||
return new ModelDataMap.Builder()
|
||||
.withInitial(TrackBlockEntityTilt.ASCENDING_PROPERTY, tilt.smoothingAngle.get())
|
||||
.build();
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private void registerToCurveInteractionUnsafe() {
|
||||
TrackBlockOutline.TRACKS_WITH_TURNS.get(level)
|
||||
|
@ -0,0 +1,236 @@
|
||||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||
import com.simibubi.create.content.logistics.trains.TrackPropagator;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.client.model.data.ModelProperty;
|
||||
|
||||
public class TrackBlockEntityTilt {
|
||||
|
||||
public static final ModelProperty<Double> ASCENDING_PROPERTY = new ModelProperty<>();
|
||||
|
||||
public Optional<Double> smoothingAngle;
|
||||
private Couple<Pair<Vec3, Integer>> previousSmoothingHandles;
|
||||
|
||||
private TrackBlockEntity blockEntity;
|
||||
|
||||
public TrackBlockEntityTilt(TrackBlockEntity blockEntity) {
|
||||
this.blockEntity = blockEntity;
|
||||
smoothingAngle = Optional.empty();
|
||||
}
|
||||
|
||||
public void tryApplySmoothing() {
|
||||
if (smoothingAngle.isPresent())
|
||||
return;
|
||||
|
||||
Couple<BezierConnection> discoveredSlopes = Couple.create(null, null);
|
||||
Vec3 axis = null;
|
||||
|
||||
BlockState blockState = blockEntity.getBlockState();
|
||||
BlockPos worldPosition = blockEntity.getBlockPos();
|
||||
Level level = blockEntity.getLevel();
|
||||
|
||||
if (!(blockState.getBlock()instanceof ITrackBlock itb))
|
||||
return;
|
||||
List<Vec3> axes = itb.getTrackAxes(level, worldPosition, blockState);
|
||||
if (axes.size() != 1)
|
||||
return;
|
||||
if (axes.get(0).y != 0)
|
||||
return;
|
||||
if (blockEntity.boundLocation != null)
|
||||
return;
|
||||
|
||||
for (BezierConnection bezierConnection : blockEntity.connections.values()) {
|
||||
if (bezierConnection.starts.getFirst().y == bezierConnection.starts.getSecond().y)
|
||||
continue;
|
||||
if (bezierConnection.axes.getSecond().y != 0)
|
||||
continue;
|
||||
Vec3 normedAxis = bezierConnection.axes.getFirst()
|
||||
.normalize();
|
||||
|
||||
if (axis != null) {
|
||||
if (discoveredSlopes.getSecond() != null)
|
||||
return;
|
||||
if (normedAxis.dot(axis) > -1 + 1 / 64.0)
|
||||
return;
|
||||
discoveredSlopes.setSecond(bezierConnection);
|
||||
continue;
|
||||
}
|
||||
|
||||
axis = normedAxis;
|
||||
discoveredSlopes.setFirst(bezierConnection);
|
||||
}
|
||||
|
||||
if (discoveredSlopes.either(Objects::isNull))
|
||||
return;
|
||||
if (discoveredSlopes.getFirst().starts.getSecond().y > discoveredSlopes.getSecond().starts.getSecond().y)
|
||||
discoveredSlopes = discoveredSlopes.swap();
|
||||
|
||||
Couple<Vec3> lowStarts = discoveredSlopes.getFirst().starts;
|
||||
Couple<Vec3> highStarts = discoveredSlopes.getSecond().starts;
|
||||
Vec3 lowestPoint = lowStarts.getSecond();
|
||||
Vec3 highestPoint = highStarts.getSecond();
|
||||
|
||||
if (lowestPoint.y > lowStarts.getFirst().y)
|
||||
return;
|
||||
if (highestPoint.y < highStarts.getFirst().y)
|
||||
return;
|
||||
|
||||
blockEntity.removeInboundConnections(false);
|
||||
blockEntity.connections.clear();
|
||||
TrackPropagator.onRailRemoved(level, worldPosition, blockState);
|
||||
|
||||
double hDistance = discoveredSlopes.getFirst()
|
||||
.getLength()
|
||||
+ discoveredSlopes.getSecond()
|
||||
.getLength();
|
||||
Vec3 baseAxis = discoveredSlopes.getFirst().axes.getFirst();
|
||||
double baseAxisLength = baseAxis.x != 0 && baseAxis.z != 0 ? Math.sqrt(2) : 1;
|
||||
double vDistance = highestPoint.y - lowestPoint.y;
|
||||
double m = vDistance / (hDistance);
|
||||
|
||||
Vec3 diff = highStarts.getFirst()
|
||||
.subtract(lowStarts.getFirst());
|
||||
boolean flipRotation = diff.dot(new Vec3(1, 0, 2).normalize()) <= 0;
|
||||
smoothingAngle = Optional.of(Math.toDegrees(Mth.atan2(m, 1)) * (flipRotation ? -1 : 1));
|
||||
|
||||
int smoothingParam = Mth.clamp((int) (m * baseAxisLength * 16), 0, 15);
|
||||
|
||||
Couple<Integer> smoothingResult = Couple.create(0, smoothingParam);
|
||||
Vec3 raisedOffset = diff.normalize()
|
||||
.add(0, Mth.clamp(m, 0, 1 - 1 / 512.0), 0)
|
||||
.normalize()
|
||||
.scale(baseAxisLength);
|
||||
|
||||
highStarts.setFirst(lowStarts.getFirst()
|
||||
.add(raisedOffset));
|
||||
|
||||
boolean first = true;
|
||||
for (BezierConnection bezierConnection : discoveredSlopes) {
|
||||
int smoothingToApply = smoothingResult.get(first);
|
||||
|
||||
if (bezierConnection.smoothing == null)
|
||||
bezierConnection.smoothing = Couple.create(0, 0);
|
||||
bezierConnection.smoothing.setFirst(smoothingToApply);
|
||||
bezierConnection.axes.setFirst(bezierConnection.axes.getFirst()
|
||||
.add(0, (first ? 1 : -1) * -m, 0)
|
||||
.normalize());
|
||||
|
||||
first = false;
|
||||
BlockPos otherPosition = bezierConnection.getKey();
|
||||
BlockState otherState = level.getBlockState(otherPosition);
|
||||
if (!(otherState.getBlock() instanceof TrackBlock))
|
||||
continue;
|
||||
level.setBlockAndUpdate(otherPosition, otherState.setValue(TrackBlock.HAS_BE, true));
|
||||
BlockEntity otherBE = level.getBlockEntity(otherPosition);
|
||||
if (otherBE instanceof TrackBlockEntity tbe) {
|
||||
blockEntity.addConnection(bezierConnection);
|
||||
tbe.addConnection(bezierConnection.secondary());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void captureSmoothingHandles() {
|
||||
boolean first = true;
|
||||
previousSmoothingHandles = Couple.create(null, null);
|
||||
for (BezierConnection bezierConnection : blockEntity.connections.values()) {
|
||||
previousSmoothingHandles.set(first, Pair.of(bezierConnection.starts.getFirst(),
|
||||
bezierConnection.smoothing == null ? 0 : bezierConnection.smoothing.getFirst()));
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void undoSmoothing() {
|
||||
if (smoothingAngle.isEmpty())
|
||||
return;
|
||||
if (previousSmoothingHandles == null)
|
||||
return;
|
||||
if (blockEntity.connections.size() == 2)
|
||||
return;
|
||||
|
||||
BlockState blockState = blockEntity.getBlockState();
|
||||
BlockPos worldPosition = blockEntity.getBlockPos();
|
||||
Level level = blockEntity.getLevel();
|
||||
|
||||
List<BezierConnection> validConnections = new ArrayList<>();
|
||||
for (BezierConnection bezierConnection : blockEntity.connections.values()) {
|
||||
BlockPos otherPosition = bezierConnection.getKey();
|
||||
BlockEntity otherBE = level.getBlockEntity(otherPosition);
|
||||
if (otherBE instanceof TrackBlockEntity tbe && tbe.connections.containsKey(worldPosition))
|
||||
validConnections.add(bezierConnection);
|
||||
}
|
||||
|
||||
blockEntity.removeInboundConnections(false);
|
||||
TrackPropagator.onRailRemoved(level, worldPosition, blockState);
|
||||
blockEntity.connections.clear();
|
||||
smoothingAngle = Optional.empty();
|
||||
|
||||
for (BezierConnection bezierConnection : validConnections) {
|
||||
blockEntity.addConnection(restoreToOriginalCurve(bezierConnection));
|
||||
|
||||
BlockPos otherPosition = bezierConnection.getKey();
|
||||
BlockState otherState = level.getBlockState(otherPosition);
|
||||
if (!(otherState.getBlock() instanceof TrackBlock))
|
||||
continue;
|
||||
level.setBlockAndUpdate(otherPosition, otherState.setValue(TrackBlock.HAS_BE, true));
|
||||
BlockEntity otherBE = level.getBlockEntity(otherPosition);
|
||||
if (otherBE instanceof TrackBlockEntity tbe)
|
||||
tbe.addConnection(bezierConnection.secondary());
|
||||
}
|
||||
|
||||
blockEntity.notifyUpdate();
|
||||
previousSmoothingHandles = null;
|
||||
TrackPropagator.onRailAdded(level, worldPosition, blockState);
|
||||
}
|
||||
|
||||
public BezierConnection restoreToOriginalCurve(BezierConnection bezierConnection) {
|
||||
if (bezierConnection.smoothing != null) {
|
||||
bezierConnection.smoothing.setFirst(0);
|
||||
if (bezierConnection.smoothing.getFirst() == 0 && bezierConnection.smoothing.getSecond() == 0)
|
||||
bezierConnection.smoothing = null;
|
||||
}
|
||||
Vec3 raisedStart = bezierConnection.starts.getFirst();
|
||||
bezierConnection.starts.setFirst(new TrackNodeLocation(raisedStart).getLocation());
|
||||
bezierConnection.axes.setFirst(bezierConnection.axes.getFirst()
|
||||
.multiply(1, 0, 1)
|
||||
.normalize());
|
||||
return bezierConnection;
|
||||
}
|
||||
|
||||
public int getYOffsetForAxisEnd(Vec3 end) {
|
||||
if (smoothingAngle.isEmpty())
|
||||
return 0;
|
||||
for (BezierConnection bezierConnection : blockEntity.connections.values())
|
||||
if (compareHandles(bezierConnection.starts.getFirst(), end))
|
||||
return bezierConnection.yOffsetAt(end);
|
||||
if (previousSmoothingHandles == null)
|
||||
return 0;
|
||||
for (Pair<Vec3, Integer> handle : previousSmoothingHandles)
|
||||
if (handle != null && compareHandles(handle.getFirst(), end))
|
||||
return handle.getSecond();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static boolean compareHandles(Vec3 handle1, Vec3 handle2) {
|
||||
return new TrackNodeLocation(handle1).getLocation()
|
||||
.multiply(1, 0, 1)
|
||||
.distanceToSqr(new TrackNodeLocation(handle2).getLocation()
|
||||
.multiply(1, 0, 1)) < 1 / 512f;
|
||||
}
|
||||
|
||||
}
|
@ -66,6 +66,13 @@ public class TrackBlockItem extends BlockItem {
|
||||
.withStyle(ChatFormatting.RED), true);
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
if (level.getBlockEntity(pos) instanceof TrackBlockEntity tbe && tbe.isTilted()) {
|
||||
if (!level.isClientSide)
|
||||
player.displayClientMessage(Lang.translateDirect("track.turn_start")
|
||||
.withStyle(ChatFormatting.RED), true);
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
if (select(level, pos, lookAngle, stack)) {
|
||||
level.playSound(null, pos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, 0.75f, 1);
|
||||
|
@ -191,9 +191,11 @@ public class TrackBlockOutline {
|
||||
|
||||
boolean holdingTrack = AllBlocks.TRACK.isIn(Minecraft.getInstance().player.getMainHandItem());
|
||||
TrackShape shape = blockstate.getValue(TrackBlock.SHAPE);
|
||||
boolean isJunction = shape.isJunction();
|
||||
boolean canConnectFrom = !shape.isJunction()
|
||||
&& !(mc.level.getBlockEntity(pos)instanceof TrackBlockEntity tbe && tbe.isTilted());
|
||||
|
||||
walkShapes(shape, TransformStack.cast(ms), s -> {
|
||||
renderShape(s, ms, vb, holdingTrack ? !isJunction : null);
|
||||
renderShape(s, ms, vb, holdingTrack ? canConnectFrom : null);
|
||||
event.setCanceled(true);
|
||||
});
|
||||
|
||||
@ -288,8 +290,8 @@ public class TrackBlockOutline {
|
||||
renderer.accept(LONG_ORTHO);
|
||||
}
|
||||
|
||||
public static record BezierPointSelection(TrackBlockEntity blockEntity, BezierTrackPointLocation loc, Vec3 vec, Vec3 angles,
|
||||
Vec3 direction) {
|
||||
public static record BezierPointSelection(TrackBlockEntity blockEntity, BezierTrackPointLocation loc, Vec3 vec,
|
||||
Vec3 angles, Vec3 direction) {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import com.simibubi.create.foundation.block.render.QuadHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.client.model.BakedModelWrapper;
|
||||
import net.minecraftforge.client.model.data.IModelData;
|
||||
import net.minecraftforge.client.model.data.ModelDataMap;
|
||||
|
||||
public class TrackModel extends BakedModelWrapper<BakedModel> {
|
||||
|
||||
public TrackModel(BakedModel originalModel) {
|
||||
super(originalModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(BlockState state, Direction side, Random rand, IModelData extraData) {
|
||||
List<BakedQuad> templateQuads = super.getQuads(state, side, rand, extraData);
|
||||
if (templateQuads.isEmpty())
|
||||
return templateQuads;
|
||||
if (!(extraData instanceof ModelDataMap mdm) || !mdm.hasProperty(TrackBlockEntityTilt.ASCENDING_PROPERTY))
|
||||
return templateQuads;
|
||||
|
||||
double angleIn = mdm.getData(TrackBlockEntityTilt.ASCENDING_PROPERTY);
|
||||
double angle = Math.abs(angleIn);
|
||||
boolean flip = angleIn < 0;
|
||||
|
||||
TrackShape trackShape = state.getValue(TrackBlock.SHAPE);
|
||||
double hAngle = switch (trackShape) {
|
||||
case XO -> 0;
|
||||
case PD -> 45;
|
||||
case ZO -> 90;
|
||||
case ND -> 135;
|
||||
default -> 0;
|
||||
};
|
||||
|
||||
Vec3 verticalOffset = new Vec3(0, -0.25, 0);
|
||||
Vec3 diagonalRotationPoint =
|
||||
(trackShape == TrackShape.ND || trackShape == TrackShape.PD) ? new Vec3((Mth.SQRT_OF_TWO - 1) / 2, 0, 0)
|
||||
: Vec3.ZERO;
|
||||
|
||||
UnaryOperator<Vec3> transform = v -> {
|
||||
v = v.add(verticalOffset);
|
||||
v = VecHelper.rotateCentered(v, hAngle, Axis.Y);
|
||||
v = v.add(diagonalRotationPoint);
|
||||
v = VecHelper.rotate(v, angle, Axis.Z);
|
||||
v = v.subtract(diagonalRotationPoint);
|
||||
v = VecHelper.rotateCentered(v, -hAngle + (flip ? 180 : 0), Axis.Y);
|
||||
v = v.subtract(verticalOffset);
|
||||
return v;
|
||||
};
|
||||
|
||||
int size = templateQuads.size();
|
||||
List<BakedQuad> quads = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
BakedQuad quad = QuadHelper.clone(templateQuads.get(i));
|
||||
int[] vertexData = quad.getVertices();
|
||||
for (int j = 0; j < 4; j++)
|
||||
QuadHelper.setXYZ(vertexData, j, transform.apply(QuadHelper.getXYZ(vertexData, j)));
|
||||
quads.add(quad);
|
||||
}
|
||||
|
||||
return quads;
|
||||
}
|
||||
|
||||
}
|
@ -150,6 +150,8 @@ public class TrackPlacement {
|
||||
.tooJumbly();
|
||||
if (!state1.hasProperty(TrackBlock.HAS_BE))
|
||||
return info.withMessage("original_missing");
|
||||
if (level.getBlockEntity(pos2) instanceof TrackBlockEntity tbe && tbe.isTilted())
|
||||
return info.withMessage("turn_start");
|
||||
|
||||
if (axis1.dot(end2.subtract(end1)) < 0) {
|
||||
axis1 = axis1.scale(-1);
|
||||
@ -556,6 +558,8 @@ public class TrackPlacement {
|
||||
|
||||
tte1.addConnection(info.curve);
|
||||
tte2.addConnection(info.curve.secondary());
|
||||
tte1.tilt.tryApplySmoothing();
|
||||
tte2.tilt.tryApplySmoothing();
|
||||
return info;
|
||||
}
|
||||
|
||||
|
@ -107,5 +107,15 @@ public class NBTHelper {
|
||||
return inbt;
|
||||
return new CompoundTag();
|
||||
}
|
||||
|
||||
public static CompoundTag intToCompound(int i) {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
compoundTag.putInt("V", i);
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
public static int intFromCompound(CompoundTag compoundTag) {
|
||||
return compoundTag.getInt("V");
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user