mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 23:47:38 +01:00
Rise of the Jank II
- Girders can now connect to brackets vertically - Fixed girders not updating connections when built with placement assist - Tracks now actively update girder shapes placed beneath the ties - Fixed bezier girder texture inconsistencies to the block models - Fixed flywheel rendered tracks creating headless instances - Fixed track not removing its tileentity properly when changing to basic state - Fixed track rendering not using the correct normals for diffuse - Fixed tracks not rendering in schematic previews - Tracks now transform correctly in schematics - Fixed tracks not validating for target track after placement via schematic - Tracks can now merge TE data when placed into each other via schematic - Fixed junctions not working correctly with graph building
This commit is contained in:
parent
2b750c943a
commit
2ca099ce6b
27 changed files with 574 additions and 283 deletions
|
@ -114,8 +114,9 @@ public class AllBlockPartials {
|
|||
TRACK_SEGMENT_LEFT = block("track/segment_left"),
|
||||
TRACK_SEGMENT_RIGHT = block("track/segment_right"),
|
||||
TRACK_TIE = block("track/tie"),
|
||||
GIRDER_SEGMENT = block("metal_girder/segment"),
|
||||
GIRDER_SEGMENT_2 = block("metal_girder/segment2"),
|
||||
GIRDER_SEGMENT_TOP = block("metal_girder/segment_top"),
|
||||
GIRDER_SEGMENT_MIDDLE = block("metal_girder/segment_middle"),
|
||||
GIRDER_SEGMENT_BOTTOM = block("metal_girder/segment_bottom"),
|
||||
|
||||
TRACK_STATION_OVERLAY = block("track/station_overlay"),
|
||||
TRACK_STATION_OVERLAY_DIAGONAL = block("track/station_overlay_diagonal"),
|
||||
|
|
|
@ -40,11 +40,11 @@ import net.minecraft.world.phys.Vec3;
|
|||
public class StructureTransform {
|
||||
|
||||
// Assuming structures cannot be rotated around multiple axes at once
|
||||
Rotation rotation;
|
||||
int angle;
|
||||
Axis rotationAxis;
|
||||
BlockPos offset;
|
||||
Mirror mirror;
|
||||
public Axis rotationAxis;
|
||||
public BlockPos offset;
|
||||
public int angle;
|
||||
public Rotation rotation;
|
||||
public Mirror mirror;
|
||||
|
||||
private StructureTransform(BlockPos offset, int angle, Axis axis, Rotation rotation, Mirror mirror) {
|
||||
this.offset = offset;
|
||||
|
@ -88,6 +88,15 @@ public class StructureTransform {
|
|||
mirror = Mirror.NONE;
|
||||
}
|
||||
|
||||
public Vec3 applyWithoutOffsetUncentered(Vec3 localVec) {
|
||||
Vec3 vec = localVec;
|
||||
if (mirror != null)
|
||||
vec = VecHelper.mirror(vec, mirror);
|
||||
if (rotationAxis != null)
|
||||
vec = VecHelper.rotate(vec, angle, rotationAxis);
|
||||
return vec;
|
||||
}
|
||||
|
||||
public Vec3 applyWithoutOffset(Vec3 localVec) {
|
||||
Vec3 vec = localVec;
|
||||
if (mirror != null)
|
||||
|
|
|
@ -55,6 +55,11 @@ public class BracketedTileEntityBehaviour extends TileEntityBehaviour {
|
|||
this.bracket = Optional.of(state);
|
||||
reRender = true;
|
||||
tileEntity.notifyUpdate();
|
||||
Level world = getWorld();
|
||||
if (world.isClientSide)
|
||||
return;
|
||||
tileEntity.getBlockState()
|
||||
.updateNeighbourShapes(world, getPos(), 3);
|
||||
}
|
||||
|
||||
public void transformBracket(StructureTransform transform) {
|
||||
|
@ -71,10 +76,15 @@ public class BracketedTileEntityBehaviour extends TileEntityBehaviour {
|
|||
world.levelEvent(2001, getPos(), Block.getId(getBracket()));
|
||||
this.bracket = Optional.empty();
|
||||
reRender = true;
|
||||
if (inOnReplacedContext)
|
||||
if (inOnReplacedContext) {
|
||||
tileEntity.sendData();
|
||||
else
|
||||
tileEntity.notifyUpdate();
|
||||
return;
|
||||
}
|
||||
tileEntity.notifyUpdate();
|
||||
if (world.isClientSide)
|
||||
return;
|
||||
tileEntity.getBlockState()
|
||||
.updateNeighbourShapes(world, getPos(), 3);
|
||||
}
|
||||
|
||||
public boolean isBracketPresent() {
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.simibubi.create.content.curiosities.girder;
|
|||
|
||||
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
|
@ -10,7 +12,7 @@ import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileE
|
|||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||
import com.simibubi.create.content.logistics.block.chute.AbstractChuteBlock;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlock.TrackShape;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackShape;
|
||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
||||
|
@ -19,6 +21,7 @@ import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
|
@ -107,6 +110,12 @@ public class GirderBlock extends Block implements SimpleWaterloggedBlock, IWrenc
|
|||
return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : Fluids.EMPTY.defaultFluidState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(BlockState p_60462_, ServerLevel p_60463_, BlockPos p_60464_, Random p_60465_) {
|
||||
Block.updateOrDestroy(p_60462_, Block.updateFromNeighbourShapes(p_60462_, p_60463_, p_60464_), p_60463_,
|
||||
p_60464_, 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState updateShape(BlockState state, Direction direction, BlockState neighbourState, LevelAccessor world,
|
||||
BlockPos pos, BlockPos neighbourPos) {
|
||||
|
|
|
@ -17,6 +17,7 @@ import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
|||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraftforge.common.ForgeMod;
|
||||
|
@ -94,7 +95,8 @@ public class GirderPlacementHelper implements IPlacementHelper {
|
|||
.isReplaceable())
|
||||
continue;
|
||||
|
||||
return PlacementOffset.success(newPos, bState -> withAxis(bState, dir.getAxis()));
|
||||
return PlacementOffset.success(newPos,
|
||||
bState -> Block.updateFromNeighbourShapes(withAxis(bState, dir.getAxis()), world, newPos));
|
||||
}
|
||||
|
||||
return PlacementOffset.fail();
|
||||
|
|
|
@ -4,7 +4,7 @@ import java.util.Iterator;
|
|||
|
||||
import com.jozufozu.flywheel.repack.joml.Math;
|
||||
import com.jozufozu.flywheel.util.transform.MatrixTransformStack;
|
||||
import com.mojang.math.Matrix4f;
|
||||
import com.mojang.blaze3d.vertex.PoseStack.Pose;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackRenderer;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
@ -24,7 +24,6 @@ import net.minecraftforge.api.distmarker.OnlyIn;
|
|||
public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
||||
|
||||
public Couple<BlockPos> tePositions;
|
||||
public Couple<Boolean> trackEnds;
|
||||
public Couple<Vec3> starts;
|
||||
public Couple<Vec3> axes;
|
||||
public Couple<Vec3> normals;
|
||||
|
@ -44,37 +43,37 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
private double handleLength;
|
||||
|
||||
public BezierConnection(Couple<BlockPos> positions, Couple<Vec3> starts, Couple<Vec3> axes, Couple<Vec3> normals,
|
||||
Couple<Boolean> targets, boolean primary, boolean girder) {
|
||||
boolean primary, boolean girder) {
|
||||
tePositions = positions;
|
||||
this.starts = starts;
|
||||
this.axes = axes;
|
||||
this.normals = normals;
|
||||
this.trackEnds = targets;
|
||||
this.primary = primary;
|
||||
this.hasGirder = girder;
|
||||
resolved = false;
|
||||
}
|
||||
|
||||
public BezierConnection secondary() {
|
||||
return new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), trackEnds.swap(),
|
||||
false, hasGirder);
|
||||
return new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), false, hasGirder);
|
||||
}
|
||||
|
||||
public BezierConnection(CompoundTag compound) {
|
||||
this(Couple.deserializeEach(compound.getList("Positions", Tag.TAG_COMPOUND), NbtUtils::readBlockPos),
|
||||
Couple.deserializeEach(compound.getList("Starts", Tag.TAG_COMPOUND), VecHelper::readNBTCompound),
|
||||
public BezierConnection(CompoundTag compound, BlockPos localTo) {
|
||||
this(Couple.deserializeEach(compound.getList("Positions", Tag.TAG_COMPOUND), NbtUtils::readBlockPos)
|
||||
.map(b -> b.offset(localTo)),
|
||||
Couple.deserializeEach(compound.getList("Starts", Tag.TAG_COMPOUND), VecHelper::readNBTCompound)
|
||||
.map(v -> v.add(Vec3.atLowerCornerOf(localTo))),
|
||||
Couple.deserializeEach(compound.getList("Axes", Tag.TAG_COMPOUND), VecHelper::readNBTCompound),
|
||||
Couple.deserializeEach(compound.getList("Normals", Tag.TAG_COMPOUND), VecHelper::readNBTCompound),
|
||||
Couple.create(compound.getBoolean("TrackEnd1"), compound.getBoolean("TrackEnd2")),
|
||||
compound.getBoolean("Primary"), compound.getBoolean("Girder"));
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
public CompoundTag write(BlockPos localTo) {
|
||||
Couple<BlockPos> tePositions = this.tePositions.map(b -> b.subtract(localTo));
|
||||
Couple<Vec3> starts = this.starts.map(v -> v.subtract(Vec3.atLowerCornerOf(localTo)));
|
||||
|
||||
CompoundTag compound = new CompoundTag();
|
||||
compound.putBoolean("Girder", hasGirder);
|
||||
compound.putBoolean("Primary", primary);
|
||||
compound.putBoolean("TrackEnd1", trackEnds.getFirst());
|
||||
compound.putBoolean("TrackEnd2", trackEnds.getSecond());
|
||||
compound.put("Positions", tePositions.serializeEach(NbtUtils::writeBlockPos));
|
||||
compound.put("Starts", starts.serializeEach(VecHelper::writeNBTCompound));
|
||||
compound.put("Axes", axes.serializeEach(VecHelper::writeNBTCompound));
|
||||
|
@ -85,7 +84,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
public BezierConnection(FriendlyByteBuf buffer) {
|
||||
this(Couple.create(buffer::readBlockPos), Couple.create(() -> VecHelper.read(buffer)),
|
||||
Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)),
|
||||
Couple.create(buffer::readBoolean), buffer.readBoolean(), buffer.readBoolean());
|
||||
buffer.readBoolean(), buffer.readBoolean());
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
|
@ -93,7 +92,6 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
starts.forEach(v -> VecHelper.write(v, buffer));
|
||||
axes.forEach(v -> VecHelper.write(v, buffer));
|
||||
normals.forEach(v -> VecHelper.write(v, buffer));
|
||||
trackEnds.forEach(buffer::writeBoolean);
|
||||
buffer.writeBoolean(primary);
|
||||
buffer.writeBoolean(hasGirder);
|
||||
}
|
||||
|
@ -344,8 +342,8 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
@OnlyIn(Dist.CLIENT)
|
||||
public static class SegmentAngles {
|
||||
|
||||
public Matrix4f tieTransform;
|
||||
public Couple<Matrix4f> railTransforms;
|
||||
public Pose tieTransform;
|
||||
public Couple<Pose> railTransforms;
|
||||
public BlockPos lightPosition;
|
||||
|
||||
}
|
||||
|
@ -353,8 +351,8 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
@OnlyIn(Dist.CLIENT)
|
||||
public static class GirderAngles {
|
||||
|
||||
public Couple<Matrix4f> beams;
|
||||
public Couple<Couple<Matrix4f>> beamCaps;
|
||||
public Couple<Pose> beams;
|
||||
public Couple<Couple<Pose>> beamCaps;
|
||||
public BlockPos lightPosition;
|
||||
|
||||
}
|
||||
|
@ -398,8 +396,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
.rotateZRadians(tieAngles.z)
|
||||
.translate(-1 / 2f, -2 / 16f - 1 / 256f, 0);
|
||||
angles.tieTransform = mts.unwrap()
|
||||
.last()
|
||||
.pose();
|
||||
.last();
|
||||
angles.railTransforms = Couple.create(null, null);
|
||||
|
||||
// Rails
|
||||
|
@ -418,8 +415,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
.translate(0, -2 / 16f + (i % 2 == 0 ? 1 : -1) / 2048f - 1 / 256f, -1 / 32f)
|
||||
.scale(1, 1, (float) diff.length() * scale);
|
||||
angles.railTransforms.set(first, mts.unwrap()
|
||||
.last()
|
||||
.pose());
|
||||
.last());
|
||||
}
|
||||
|
||||
previousOffsets = railOffsets;
|
||||
|
@ -494,8 +490,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
.translate(0, 2 / 16f + (segment.index % 2 == 0 ? 1 : -1) / 2048f - 1 / 1024f, -1 / 32f)
|
||||
.scale(1, 1, (float) beamDiff.length() * scale);
|
||||
angles.beams.set(first, mts.unwrap()
|
||||
.last()
|
||||
.pose());
|
||||
.last());
|
||||
|
||||
// Caps
|
||||
for (boolean top : Iterate.trueAndFalse) {
|
||||
|
@ -516,8 +511,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
|||
.scale(1, 1, (float) diff.length() * scale);
|
||||
angles.beamCaps.get(top)
|
||||
.set(first, mts.unwrap()
|
||||
.last()
|
||||
.pose());
|
||||
.last());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains;
|
|||
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.util.Mth;
|
||||
|
@ -60,11 +61,11 @@ public class TrackEdge {
|
|||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
return isTurn() ? turn.write() : new CompoundTag();
|
||||
return isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag();
|
||||
}
|
||||
|
||||
public static TrackEdge read(CompoundTag tag) {
|
||||
return new TrackEdge(tag.contains("Positions") ? new BezierConnection(tag) : null);
|
||||
return new TrackEdge(tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ public class TrackGraphHelper {
|
|||
double length = axis.length();
|
||||
|
||||
List<Pair<BlockPos, DiscoveredLocation>> ends =
|
||||
TrackPropagator.getEnds(level, pos, trackBlockState, null, true);
|
||||
TrackPropagator.getEnds(level, pos, trackBlockState, true, null, null);
|
||||
|
||||
TrackGraph graph = null;
|
||||
TrackNode frontNode = null;
|
||||
|
@ -46,7 +46,7 @@ public class TrackGraphHelper {
|
|||
for (int i = 0; i < 32; i++) {
|
||||
DiscoveredLocation loc = current;
|
||||
List<Pair<BlockPos, DiscoveredLocation>> list =
|
||||
TrackPropagator.getEnds(level, currentPos, level.getBlockState(currentPos), current, true);
|
||||
TrackPropagator.getEnds(level, currentPos, level.getBlockState(currentPos), true, current, null);
|
||||
if (!list.isEmpty()) {
|
||||
currentPos = list.get(0)
|
||||
.getFirst();
|
||||
|
|
|
@ -13,7 +13,7 @@ import javax.annotation.Nullable;
|
|||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlock.TrackShape;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackShape;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackTileEntity;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
@ -47,11 +47,10 @@ public class TrackPropagator {
|
|||
currentPos = pos;
|
||||
currentNode = location;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void onRailRemoved(LevelAccessor reader, BlockPos pos, BlockState state) {
|
||||
List<Pair<BlockPos, DiscoveredLocation>> ends = getEnds(reader, pos, state, null, false);
|
||||
List<Pair<BlockPos, DiscoveredLocation>> ends = getEnds(reader, pos, state, false, null, null);
|
||||
TrackGraph foundGraph = null;
|
||||
GlobalRailwayManager manager = Create.RAILWAYS;
|
||||
TrackGraphSync sync = manager.sync;
|
||||
|
@ -78,9 +77,16 @@ public class TrackPropagator {
|
|||
for (Pair<BlockPos, DiscoveredLocation> removedEnd : ends) {
|
||||
BlockPos adjPos = removedEnd.getFirst();
|
||||
BlockState adjState = reader.getBlockState(adjPos);
|
||||
|
||||
if (!getEnds(reader, adjPos, adjState, removedEnd.getSecond(), true).isEmpty())
|
||||
toUpdate.add(onRailAdded(reader, adjPos, adjState));
|
||||
List<Pair<BlockPos, DiscoveredLocation>> adjEnds =
|
||||
getEnds(reader, adjPos, adjState, true, removedEnd.getSecond(), null);
|
||||
if (adjEnds.isEmpty())
|
||||
continue;
|
||||
Vec3 filter = adjEnds.get(0)
|
||||
.getSecond()
|
||||
.getLocation()
|
||||
.subtract(removedEnd.getSecond()
|
||||
.getLocation());
|
||||
toUpdate.add(onRailAdded(reader, adjPos, adjState, filter.normalize()));
|
||||
}
|
||||
|
||||
for (TrackGraph railGraph : toUpdate)
|
||||
|
@ -89,7 +95,7 @@ public class TrackPropagator {
|
|||
manager.markTracksDirty();
|
||||
}
|
||||
|
||||
public static TrackGraph onRailAdded(LevelAccessor reader, BlockPos pos, BlockState state) {
|
||||
public static TrackGraph onRailAdded(LevelAccessor reader, BlockPos pos, BlockState state, Vec3 axisFilter) {
|
||||
// 1. Remove all immediately reachable node locations
|
||||
|
||||
GlobalRailwayManager manager = Create.RAILWAYS;
|
||||
|
@ -97,7 +103,7 @@ public class TrackPropagator {
|
|||
List<FrontierEntry> frontier = new ArrayList<>();
|
||||
Set<DiscoveredLocation> visited = new HashSet<>();
|
||||
Set<TrackGraph> connectedGraphs = new HashSet<>();
|
||||
addInitialEndsOf(reader, pos, state, frontier, false);
|
||||
addInitialEndsOf(reader, pos, state, frontier, false, axisFilter);
|
||||
|
||||
int emergencyExit = 1000;
|
||||
while (!frontier.isEmpty()) {
|
||||
|
@ -155,7 +161,7 @@ public class TrackPropagator {
|
|||
|
||||
// 2. Find the first graph node candidate nearby
|
||||
|
||||
addInitialEndsOf(reader, pos, state, frontier, true);
|
||||
addInitialEndsOf(reader, pos, state, frontier, true, axisFilter);
|
||||
|
||||
emergencyExit = 1000;
|
||||
while (!frontier.isEmpty()) {
|
||||
|
@ -229,8 +235,8 @@ public class TrackPropagator {
|
|||
}
|
||||
|
||||
private static void addInitialEndsOf(LevelAccessor reader, BlockPos pos, BlockState state,
|
||||
List<FrontierEntry> frontier, boolean ignoreTurns) {
|
||||
for (Pair<BlockPos, DiscoveredLocation> initial : getEnds(reader, pos, state, null, ignoreTurns))
|
||||
List<FrontierEntry> frontier, boolean ignoreTurns, Vec3 axisFilter) {
|
||||
for (Pair<BlockPos, DiscoveredLocation> initial : getEnds(reader, pos, state, ignoreTurns, null, axisFilter))
|
||||
frontier.add(new FrontierEntry(initial.getFirst(), pos, initial.getSecond()));
|
||||
}
|
||||
|
||||
|
@ -255,13 +261,13 @@ public class TrackPropagator {
|
|||
}
|
||||
|
||||
for (Pair<BlockPos, DiscoveredLocation> pair : getEnds(reader, prevPos, reader.getBlockState(prevPos),
|
||||
entry.currentNode, false))
|
||||
false, entry.currentNode, null))
|
||||
if (!pair.getSecond()
|
||||
.equals(entry.prevNode))
|
||||
ends.add(pair);
|
||||
}
|
||||
|
||||
ends.addAll(getEnds(reader, entry.currentPos, currentState, entry.currentNode, false));
|
||||
ends.addAll(getEnds(reader, entry.currentPos, currentState, false, entry.currentNode, null));
|
||||
return ends;
|
||||
}
|
||||
|
||||
|
@ -304,7 +310,7 @@ public class TrackPropagator {
|
|||
|
||||
// TODO ITrackBlock
|
||||
public static List<Pair<BlockPos, DiscoveredLocation>> getEnds(LevelReader reader, BlockPos pos, BlockState state,
|
||||
@Nullable DiscoveredLocation fromEnd, boolean ignoreTurns) {
|
||||
boolean ignoreTurns, @Nullable DiscoveredLocation fromEnd, @Nullable Vec3 axisFilter) {
|
||||
Vec3 center = VecHelper.getCenterOf(pos);
|
||||
List<Pair<BlockPos, DiscoveredLocation>> list = new ArrayList<>();
|
||||
|
||||
|
@ -315,21 +321,36 @@ public class TrackPropagator {
|
|||
if (state.getValue(TrackBlock.HAS_TURN) && blockEntity instanceof TrackTileEntity && !ignoreTurns) {
|
||||
TrackTileEntity trackTileEntity = (TrackTileEntity) blockEntity;
|
||||
trackTileEntity.getConnections()
|
||||
.forEach(map -> map.forEach((connectedPos, bc) -> addToSet(fromEnd, list,
|
||||
(d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get,
|
||||
bc)));
|
||||
.forEach((connectedPos, bc) -> {
|
||||
Vec3 curveHandle = bc.axes.getFirst();
|
||||
if (axisFilter != null && !testAxisFilter(curveHandle.normalize(), axisFilter))
|
||||
return;
|
||||
addToSet(fromEnd, list,
|
||||
(d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b),
|
||||
bc.normals::get, bc);
|
||||
});
|
||||
}
|
||||
|
||||
TrackShape shape = state.getValue(TrackBlock.SHAPE);
|
||||
if (shape != TrackShape.NONE)
|
||||
shape.getAxes()
|
||||
.forEach(axis -> addToSet(fromEnd, list, (d, b) -> axis.scale(b ? d : -d)
|
||||
if (shape == TrackShape.NONE)
|
||||
return list;
|
||||
|
||||
shape.getAxes()
|
||||
.forEach(axis -> {
|
||||
if (axisFilter != null && !testAxisFilter(axis.normalize(), axisFilter))
|
||||
return;
|
||||
addToSet(fromEnd, list, (d, b) -> axis.scale(b ? d : -d)
|
||||
.add(center)
|
||||
.add(0, axis.y == 0 ? -.5 : 0, 0), b -> shape.getNormal(), null));
|
||||
.add(0, axis.y == 0 ? -.5 : 0, 0), b -> shape.getNormal(), null);
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static boolean testAxisFilter(Vec3 axis, Vec3 filter) {
|
||||
return Mth.equal(axis.distanceToSqr(filter), 0) || Mth.equal(axis.distanceToSqr(filter.scale(-1)), 0);
|
||||
}
|
||||
|
||||
private static void addToSet(DiscoveredLocation fromEnd, List<Pair<BlockPos, DiscoveredLocation>> list,
|
||||
BiFunction<Double, Boolean, Vec3> offsetFactory, Function<Boolean, Vec3> normalFactory,
|
||||
BezierConnection viaTurn) {
|
||||
|
|
|
@ -326,7 +326,7 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
|
||||
DiscoveredLocation location = null;
|
||||
List<Pair<BlockPos, DiscoveredLocation>> ends =
|
||||
TrackPropagator.getEnds(level, trackPosition, trackState, null, true);
|
||||
TrackPropagator.getEnds(level, trackPosition, trackState, true, null, null);
|
||||
for (Pair<BlockPos, DiscoveredLocation> pair : ends)
|
||||
if (trackPosition.relative(assemblyDirection)
|
||||
.equals(pair.getFirst()))
|
||||
|
|
|
@ -4,7 +4,6 @@ import java.util.List;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.core.PartialModel;
|
||||
import com.jozufozu.flywheel.util.transform.MatrixTransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
@ -15,12 +14,12 @@ import com.simibubi.create.AllTileEntities;
|
|||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
|
||||
import com.simibubi.create.content.curiosities.girder.GirderBlock;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.TrackPropagator;
|
||||
import com.simibubi.create.content.logistics.trains.management.StationTileEntity;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -29,18 +28,20 @@ import net.minecraft.core.Direction.Axis;
|
|||
import net.minecraft.core.Direction.AxisDirection;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.Mirror;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition.Builder;
|
||||
|
@ -62,74 +63,6 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
public static final EnumProperty<TrackShape> SHAPE = EnumProperty.create("shape", TrackShape.class);
|
||||
public static final BooleanProperty HAS_TURN = BooleanProperty.create("turn");
|
||||
|
||||
public enum TrackShape implements StringRepresentable {
|
||||
NONE("", Vec3.ZERO),
|
||||
ZO("z_ortho", new Vec3(0, 0, 1)),
|
||||
XO("x_ortho", new Vec3(1, 0, 0)),
|
||||
PD("diag", new Vec3(1, 0, 1)),
|
||||
ND("diag_2", new Vec3(-1, 0, 1)),
|
||||
AN("ascending", 180, new Vec3(0, 1, -1), new Vec3(0, 1, 1)),
|
||||
AS("ascending", 0, new Vec3(0, 1, 1), new Vec3(0, 1, -1)),
|
||||
AE("ascending", 270, new Vec3(1, 1, 0), new Vec3(-1, 1, 0)),
|
||||
AW("ascending", 90, new Vec3(-1, 1, 0), new Vec3(1, 1, 0)),
|
||||
|
||||
CR_O("cross_ortho", new Vec3(0, 0, 1), new Vec3(1, 0, 0)),
|
||||
CR_D("cross_diag", new Vec3(1, 0, 1), new Vec3(-1, 0, 1)),
|
||||
CR_PDX("cross_d1_xo", new Vec3(1, 0, 0), new Vec3(1, 0, 1)),
|
||||
CR_PDZ("cross_d1_zo", new Vec3(0, 0, 1), new Vec3(1, 0, 1)),
|
||||
CR_NDX("cross_d2_xo", new Vec3(1, 0, 0), new Vec3(-1, 0, 1)),
|
||||
CR_NDZ("cross_d2_zo", new Vec3(0, 0, 1), new Vec3(-1, 0, 1));
|
||||
|
||||
private String model;
|
||||
private List<Vec3> axes;
|
||||
private int modelRotation;
|
||||
private Vec3 normal;
|
||||
|
||||
private TrackShape(String model, Vec3 axis) {
|
||||
this(model, 0, axis, new Vec3(0, 1, 0));
|
||||
}
|
||||
|
||||
private TrackShape(String model, Vec3 axis, Vec3 secondAxis) {
|
||||
this.model = model;
|
||||
this.modelRotation = 0;
|
||||
this.normal = new Vec3(0, 1, 0);
|
||||
this.axes = ImmutableList.of(axis, secondAxis);
|
||||
}
|
||||
|
||||
private TrackShape(String model, int modelRotation, Vec3 axis, Vec3 normal) {
|
||||
this.model = model;
|
||||
this.modelRotation = modelRotation;
|
||||
this.normal = normal.normalize();
|
||||
this.axes = ImmutableList.of(axis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSerializedName() {
|
||||
return Lang.asId(name());
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public List<Vec3> getAxes() {
|
||||
return axes;
|
||||
}
|
||||
|
||||
public boolean isJunction() {
|
||||
return axes.size() > 1;
|
||||
}
|
||||
|
||||
public Vec3 getNormal() {
|
||||
return normal;
|
||||
}
|
||||
|
||||
public int getModelRotation() {
|
||||
return modelRotation;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public TrackBlock(Properties p_49795_) {
|
||||
super(p_49795_);
|
||||
registerDefaultState(defaultBlockState().setValue(SHAPE, TrackShape.ZO)
|
||||
|
@ -201,14 +134,18 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
public void onPlace(BlockState pState, Level pLevel, BlockPos pPos, BlockState pOldState, boolean pIsMoving) {
|
||||
if (pOldState.getBlock() == this && pState.setValue(HAS_TURN, true) == pOldState.setValue(HAS_TURN, true))
|
||||
return;
|
||||
if (pLevel.isClientSide)
|
||||
return;
|
||||
LevelTickAccess<Block> blockTicks = pLevel.getBlockTicks();
|
||||
if (!blockTicks.hasScheduledTick(pPos, this))
|
||||
pLevel.scheduleTick(pPos, this, 1);
|
||||
updateGirders(pState, pLevel, pPos, blockTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(BlockState p_60462_, ServerLevel p_60463_, BlockPos p_60464_, Random p_60465_) {
|
||||
TrackPropagator.onRailAdded(p_60463_, p_60464_, p_60462_);
|
||||
for (Vec3 axis : getTrackAxes(p_60463_, p_60464_, p_60462_))
|
||||
TrackPropagator.onRailAdded(p_60463_, p_60464_, p_60462_, axis.normalize());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -216,7 +153,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
boolean removeTE = false;
|
||||
if (pState.getValue(HAS_TURN) && (!pState.is(pNewState.getBlock()) || !pNewState.getValue(HAS_TURN))) {
|
||||
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
|
||||
if (blockEntity instanceof TrackTileEntity)
|
||||
if (blockEntity instanceof TrackTileEntity && !pLevel.isClientSide)
|
||||
((TrackTileEntity) blockEntity).removeInboundConnections();
|
||||
removeTE = true;
|
||||
}
|
||||
|
@ -225,6 +162,8 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
TrackPropagator.onRailRemoved(pLevel, pPos, pState);
|
||||
if (removeTE)
|
||||
pLevel.removeBlockEntity(pPos);
|
||||
if (!pLevel.isClientSide)
|
||||
updateGirders(pState, pLevel, pPos, pLevel.getBlockTicks());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -253,14 +192,24 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
// if (asItem() == itemInHand.getItem()) {
|
||||
// TrackConnectionPlacementHandler.select(world, pos, player.getLookAngle(), itemInHand);
|
||||
// return InteractionResult.SUCCESS;
|
||||
// }
|
||||
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
private void updateGirders(BlockState pState, Level pLevel, BlockPos pPos, LevelTickAccess<Block> blockTicks) {
|
||||
for (Vec3 vec3 : getTrackAxes(pLevel, pPos, pState)) {
|
||||
if (vec3.length() > 1 || vec3.y != 0)
|
||||
continue;
|
||||
for (int side : Iterate.positiveAndNegative) {
|
||||
BlockPos girderPos = pPos.below()
|
||||
.offset(vec3.z * side, 0, vec3.x * side);
|
||||
BlockState girderState = pLevel.getBlockState(girderPos);
|
||||
if (girderState.getBlock()instanceof GirderBlock girderBlock
|
||||
&& !blockTicks.hasScheduledTick(girderPos, girderBlock))
|
||||
pLevel.scheduleTick(girderPos, girderBlock, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSurvive(BlockState state, LevelReader reader, BlockPos pos) {
|
||||
return reader.getBlockState(pos.below())
|
||||
|
@ -298,16 +247,21 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
.add(0, (vertical ? 0 : -.5f), 0)
|
||||
.add(axis.scale(.5));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public InteractionResult onWrenched(BlockState state, UseOnContext context) {
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState overlay(BlockGetter world, BlockPos pos, BlockState existing, BlockState placed) {
|
||||
if (placed.getBlock() != this)
|
||||
return existing;
|
||||
|
||||
|
||||
TrackShape existingShape = existing.getValue(SHAPE);
|
||||
TrackShape placedShape = placed.getValue(SHAPE);
|
||||
TrackShape combinedShape = null;
|
||||
|
||||
|
||||
for (boolean flip : Iterate.trueAndFalse) {
|
||||
TrackShape s1 = flip ? existingShape : placedShape;
|
||||
TrackShape s2 = flip ? placedShape : existingShape;
|
||||
|
@ -324,26 +278,22 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
if (s1 == TrackShape.ZO && s2 == TrackShape.ND)
|
||||
combinedShape = TrackShape.CR_NDZ;
|
||||
}
|
||||
|
||||
|
||||
if (combinedShape != null)
|
||||
existing = existing.setValue(SHAPE, combinedShape);
|
||||
return existing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getRotatedBlockState(BlockState state, Direction targetedFace) {
|
||||
switch (state.getValue(SHAPE)) {
|
||||
case ND:
|
||||
return state.setValue(SHAPE, TrackShape.XO);
|
||||
case PD:
|
||||
return state.setValue(SHAPE, TrackShape.ZO);
|
||||
case XO:
|
||||
return state.setValue(SHAPE, TrackShape.PD);
|
||||
case ZO:
|
||||
return state.setValue(SHAPE, TrackShape.ND);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
public BlockState rotate(BlockState state, Rotation pRotation) {
|
||||
return state.setValue(SHAPE, state.getValue(SHAPE)
|
||||
.rotate(pRotation));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState mirror(BlockState state, Mirror pMirror) {
|
||||
return state.setValue(SHAPE, state.getValue(SHAPE)
|
||||
.mirror(pMirror));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -113,20 +113,17 @@ public class TrackBlockItem extends BlockItem {
|
|||
|
||||
ITrackBlock track = (ITrackBlock) block;
|
||||
Pair<Vec3, AxisDirection> nearestTrackAxis = track.getNearestTrackAxis(world, pos, blockState, lookVec);
|
||||
Vec3 axis = nearestTrackAxis.getFirst();
|
||||
boolean front = nearestTrackAxis.getSecond() == AxisDirection.POSITIVE;
|
||||
Vec3 axis = nearestTrackAxis.getFirst()
|
||||
.scale(nearestTrackAxis.getSecond() == AxisDirection.POSITIVE ? -1 : 1);
|
||||
Vec3 end = track.getCurveStart(world, pos, blockState, axis);
|
||||
Vec3 normal = track.getUpNormal(world, pos, blockState)
|
||||
.normalize();
|
||||
|
||||
axis = axis.scale(front ? -1 : 1);
|
||||
Vec3 end = track.getCurveStart(world, pos, blockState, axis);
|
||||
|
||||
CompoundTag compoundTag = heldItem.getOrCreateTagElement("ConnectingFrom");
|
||||
compoundTag.put("Pos", NbtUtils.writeBlockPos(pos));
|
||||
compoundTag.put("Axis", VecHelper.writeNBT(axis));
|
||||
compoundTag.put("Normal", VecHelper.writeNBT(normal));
|
||||
compoundTag.put("End", VecHelper.writeNBT(end));
|
||||
compoundTag.putBoolean("Front", front);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackBlock.TrackShape;
|
||||
import com.simibubi.create.foundation.data.SpecialBlockStateGen;
|
||||
import com.tterrag.registrate.providers.DataGenContext;
|
||||
import com.tterrag.registrate.providers.RegistrateBlockstateProvider;
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.simibubi.create.content.logistics.trains.track;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -12,11 +11,11 @@ import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
|
|||
import com.jozufozu.flywheel.core.Materials;
|
||||
import com.jozufozu.flywheel.core.materials.model.ModelData;
|
||||
import com.jozufozu.flywheel.light.LightUpdater;
|
||||
import com.jozufozu.flywheel.util.FlwUtil;
|
||||
import com.jozufozu.flywheel.util.box.GridAlignedBB;
|
||||
import com.jozufozu.flywheel.util.box.ImmutableBox;
|
||||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack.Pose;
|
||||
import com.simibubi.create.AllBlockPartials;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles;
|
||||
|
@ -39,13 +38,12 @@ public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
|
|||
|
||||
@Override
|
||||
public void update() {
|
||||
if (blockEntity.connections.stream()
|
||||
.allMatch(Map::isEmpty)) {
|
||||
if (blockEntity.connections.isEmpty())
|
||||
return;
|
||||
}
|
||||
|
||||
instances = blockEntity.connections.stream()
|
||||
.flatMap(FlwUtil::mapValues)
|
||||
remove();
|
||||
instances = blockEntity.connections.values()
|
||||
.stream()
|
||||
.map(this::createInstance)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
|
@ -56,10 +54,8 @@ public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
|
|||
@Override
|
||||
public ImmutableBox getVolume() {
|
||||
List<BlockPos> out = new ArrayList<>();
|
||||
out.addAll(blockEntity.connections.getFirst()
|
||||
.keySet());
|
||||
out.addAll(blockEntity.connections.getSecond()
|
||||
.keySet());
|
||||
out.addAll(blockEntity.connections.keySet());
|
||||
out.addAll(blockEntity.connections.keySet());
|
||||
return GridAlignedBB.containingAll(out);
|
||||
}
|
||||
|
||||
|
@ -129,12 +125,15 @@ public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
|
|||
var modelIndex = i - 1;
|
||||
|
||||
ties[modelIndex].setTransform(pose)
|
||||
.mulPose(segment.tieTransform);
|
||||
.mulPose(segment.tieTransform.pose())
|
||||
.mulNormal(segment.tieTransform.normal());
|
||||
tiesLightPos[modelIndex] = segment.lightPosition.offset(tePosition);
|
||||
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
Pose transform = segment.railTransforms.get(first);
|
||||
(first ? this.left : this.right)[modelIndex].setTransform(pose)
|
||||
.mulPose(segment.railTransforms.get(first));
|
||||
.mulPose(transform.pose())
|
||||
.mulNormal(transform.normal());
|
||||
(first ? leftLightPos : rightLightPos)[modelIndex] = segment.lightPosition.offset(tePosition);
|
||||
}
|
||||
}
|
||||
|
@ -185,8 +184,9 @@ public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
|
|||
beams = Couple.create(() -> new ModelData[segCount]);
|
||||
beamCaps = Couple.create(() -> Couple.create(() -> new ModelData[segCount]));
|
||||
lightPos = new BlockPos[segCount];
|
||||
beams.forEach(mat.getModel(AllBlockPartials.GIRDER_SEGMENT_2)::createInstances);
|
||||
beamCaps.forEach(c -> c.forEach(mat.getModel(AllBlockPartials.GIRDER_SEGMENT)::createInstances));
|
||||
beams.forEach(mat.getModel(AllBlockPartials.GIRDER_SEGMENT_MIDDLE)::createInstances);
|
||||
beamCaps.forEachWithContext((c, top) -> c.forEach(mat.getModel(top ? AllBlockPartials.GIRDER_SEGMENT_TOP
|
||||
: AllBlockPartials.GIRDER_SEGMENT_BOTTOM)::createInstances));
|
||||
|
||||
GirderAngles[] bakedGirders = bc.getBakedGirders();
|
||||
for (int i = 1; i < bakedGirders.length; i++) {
|
||||
|
@ -195,13 +195,18 @@ public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
|
|||
lightPos[modelIndex] = segment.lightPosition.offset(tePosition);
|
||||
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
Pose beamTransform = segment.beams.get(first);
|
||||
beams.get(first)[modelIndex].setTransform(pose)
|
||||
.mulPose(segment.beams.get(first));
|
||||
for (boolean top : Iterate.trueAndFalse)
|
||||
.mulPose(beamTransform.pose())
|
||||
.mulNormal(beamTransform.normal());
|
||||
for (boolean top : Iterate.trueAndFalse) {
|
||||
Pose beamCapTransform = segment.beamCaps.get(top)
|
||||
.get(first);
|
||||
beamCaps.get(top)
|
||||
.get(first)[modelIndex].setTransform(pose)
|
||||
.mulPose(segment.beamCaps.get(top)
|
||||
.get(first));
|
||||
.mulPose(beamCapTransform.pose())
|
||||
.mulNormal(beamCapTransform.normal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,11 +84,10 @@ public class TrackPlacement {
|
|||
|
||||
ITrackBlock track = (ITrackBlock) state2.getBlock();
|
||||
Pair<Vec3, AxisDirection> nearestTrackAxis = track.getNearestTrackAxis(level, pos2, state2, lookVec);
|
||||
Vec3 axis2 = nearestTrackAxis.getFirst();
|
||||
boolean front2 = nearestTrackAxis.getSecond() == AxisDirection.POSITIVE;
|
||||
Vec3 axis2 = nearestTrackAxis.getFirst()
|
||||
.scale(nearestTrackAxis.getSecond() == AxisDirection.POSITIVE ? -1 : 1);
|
||||
Vec3 normal2 = track.getUpNormal(level, pos2, state2)
|
||||
.normalize();
|
||||
axis2 = axis2.scale(front2 ? -1 : 1);
|
||||
Vec3 normedAxis2 = axis2.normalize();
|
||||
Vec3 end2 = track.getCurveStart(level, pos2, state2, axis2);
|
||||
|
||||
|
@ -137,7 +136,6 @@ public class TrackPlacement {
|
|||
if ((parallel && normedAxis1.dot(normedAxis2) > 0) || (!parallel && (intersect[0] < 0 || intersect[1] < 0))) {
|
||||
axis2 = axis2.scale(-1);
|
||||
normedAxis2 = normedAxis2.scale(-1);
|
||||
front2 = !front2;
|
||||
end2 = track.getCurveStart(level, pos2, state2, axis2);
|
||||
if (level.isClientSide) {
|
||||
info.end2 = end2;
|
||||
|
@ -161,7 +159,7 @@ public class TrackPlacement {
|
|||
BlockPos targetPos2 = pos2.offset(offset2.x, offset2.y, offset2.z);
|
||||
info.curve = new BezierConnection(Couple.create(targetPos1, targetPos2),
|
||||
Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2),
|
||||
Couple.create(normal1, normal2), Couple.create(front1, front2), true, girder);
|
||||
Couple.create(normal1, normal2), true, girder);
|
||||
}
|
||||
|
||||
// S curve or Straight
|
||||
|
@ -281,7 +279,7 @@ public class TrackPlacement {
|
|||
if (dist2 > dist1)
|
||||
ex2 = (float) ((dist2 - dist1) / axis2.length());
|
||||
|
||||
double turnSize = Math.min(dist1, dist2);
|
||||
double turnSize = Math.min(dist1, dist2) - .1d;
|
||||
boolean ninety = (absAngle + .25f) % 90 < 1;
|
||||
|
||||
if (intersect[0] < 0 || intersect[1] < 0)
|
||||
|
@ -312,7 +310,7 @@ public class TrackPlacement {
|
|||
info.curve = skipCurve ? null
|
||||
: new BezierConnection(Couple.create(targetPos1, targetPos2),
|
||||
Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2),
|
||||
Couple.create(normal1, normal2), Couple.create(front1, front2), true, girder);
|
||||
Couple.create(normal1, normal2), true, girder);
|
||||
|
||||
info.valid = true;
|
||||
|
||||
|
@ -324,13 +322,15 @@ public class TrackPlacement {
|
|||
Vec3 axis = first ? axis1 : axis2;
|
||||
BlockPos pos = first ? pos1 : pos2;
|
||||
BlockState state = first ? state1 : state2;
|
||||
if (state.hasProperty(TrackBlock.HAS_TURN))
|
||||
state = state.setValue(TrackBlock.HAS_TURN, false);
|
||||
|
||||
for (int i = 0; i < extent; i++) {
|
||||
Vec3 offset = axis.scale(i);
|
||||
BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z);
|
||||
BlockState stateAtPos = level.getBlockState(offsetPos);
|
||||
BlockState toPlace = state;
|
||||
|
||||
|
||||
boolean canPlace = stateAtPos.getMaterial()
|
||||
.isReplaceable();
|
||||
if (stateAtPos.getBlock()instanceof ITrackBlock trackAtPos) {
|
||||
|
@ -361,8 +361,8 @@ public class TrackPlacement {
|
|||
|
||||
TrackTileEntity tte1 = (TrackTileEntity) te1;
|
||||
TrackTileEntity tte2 = (TrackTileEntity) te2;
|
||||
tte1.addConnection(front1, info.curve);
|
||||
tte2.addConnection(front2, info.curve.secondary());
|
||||
tte1.addConnection(info.curve);
|
||||
tte2.addConnection(info.curve.secondary());
|
||||
return info;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT;
|
||||
import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_2;
|
||||
import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_BOTTOM;
|
||||
import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_MIDDLE;
|
||||
import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_TOP;
|
||||
import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_LEFT;
|
||||
import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_RIGHT;
|
||||
import static com.simibubi.create.AllBlockPartials.TRACK_TIE;
|
||||
|
@ -10,6 +11,7 @@ import com.jozufozu.flywheel.backend.Backend;
|
|||
import com.jozufozu.flywheel.repack.joml.Math;
|
||||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack.Pose;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles;
|
||||
|
@ -29,6 +31,7 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
@ -40,22 +43,21 @@ public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
|
|||
@Override
|
||||
protected void renderSafe(TrackTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light,
|
||||
int overlay) {
|
||||
if (Backend.isOn())
|
||||
Level level = te.getLevel();
|
||||
if (Backend.canUseInstancing(level))
|
||||
return;
|
||||
|
||||
VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped());
|
||||
te.connections.forEach(map -> map.values()
|
||||
.forEach(bc -> renderBezierTurn(bc, ms, vb)));
|
||||
te.connections.values()
|
||||
.forEach(bc -> renderBezierTurn(level, bc, ms, vb));
|
||||
}
|
||||
|
||||
public static void renderBezierTurn(BezierConnection bc, PoseStack ms, VertexConsumer vb) {
|
||||
public static void renderBezierTurn(Level level, BezierConnection bc, PoseStack ms, VertexConsumer vb) {
|
||||
if (!bc.isPrimary())
|
||||
return;
|
||||
|
||||
ms.pushPose();
|
||||
BlockPos tePosition = bc.tePositions.getFirst();
|
||||
BlockState air = Blocks.AIR.defaultBlockState();
|
||||
ClientLevel level = Minecraft.getInstance().level;
|
||||
SegmentAngles[] segments = bc.getBakedSegments();
|
||||
|
||||
TransformStack.cast(ms)
|
||||
|
@ -68,17 +70,19 @@ public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
|
|||
int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition));
|
||||
|
||||
CachedBufferer.partial(TRACK_TIE, air)
|
||||
.mulPose(segment.tieTransform)
|
||||
.disableDiffuseMult()
|
||||
.mulPose(segment.tieTransform.pose())
|
||||
.mulNormal(segment.tieTransform.normal())
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
|
||||
for (boolean first : Iterate.trueAndFalse)
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
Pose transform = segment.railTransforms.get(first);
|
||||
CachedBufferer.partial(first ? TRACK_SEGMENT_LEFT : TRACK_SEGMENT_RIGHT, air)
|
||||
.mulPose(segment.railTransforms.get(first))
|
||||
.disableDiffuseMult()
|
||||
.mulPose(transform.pose())
|
||||
.mulNormal(transform.normal())
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
}
|
||||
}
|
||||
|
||||
ms.popPose();
|
||||
|
@ -97,19 +101,22 @@ public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
|
|||
int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition));
|
||||
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
CachedBufferer.partial(GIRDER_SEGMENT_2, air)
|
||||
.mulPose(segment.beams.get(first))
|
||||
.disableDiffuseMult()
|
||||
Pose beamTransform = segment.beams.get(first);
|
||||
CachedBufferer.partial(GIRDER_SEGMENT_MIDDLE, air)
|
||||
.mulPose(beamTransform.pose())
|
||||
.mulNormal(beamTransform.normal())
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
|
||||
for (boolean top : Iterate.trueAndFalse)
|
||||
CachedBufferer.partial(GIRDER_SEGMENT, air)
|
||||
.mulPose(segment.beamCaps.get(top)
|
||||
.get(first))
|
||||
.disableDiffuseMult()
|
||||
for (boolean top : Iterate.trueAndFalse) {
|
||||
Pose beamCapTransform = segment.beamCaps.get(top)
|
||||
.get(first);
|
||||
CachedBufferer.partial(top ? GIRDER_SEGMENT_TOP : GIRDER_SEGMENT_BOTTOM, air)
|
||||
.mulPose(beamCapTransform.pose())
|
||||
.mulNormal(beamCapTransform.normal())
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraft.world.level.block.Mirror;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public enum TrackShape implements StringRepresentable {
|
||||
NONE("", Vec3.ZERO),
|
||||
ZO("z_ortho", new Vec3(0, 0, 1)),
|
||||
XO("x_ortho", new Vec3(1, 0, 0)),
|
||||
PD("diag", new Vec3(1, 0, 1)),
|
||||
ND("diag_2", new Vec3(-1, 0, 1)),
|
||||
AN("ascending", 180, new Vec3(0, 1, -1), new Vec3(0, 1, 1)),
|
||||
AS("ascending", 0, new Vec3(0, 1, 1), new Vec3(0, 1, -1)),
|
||||
AE("ascending", 270, new Vec3(1, 1, 0), new Vec3(-1, 1, 0)),
|
||||
AW("ascending", 90, new Vec3(-1, 1, 0), new Vec3(1, 1, 0)),
|
||||
|
||||
CR_O("cross_ortho", new Vec3(0, 0, 1), new Vec3(1, 0, 0)),
|
||||
CR_D("cross_diag", new Vec3(1, 0, 1), new Vec3(-1, 0, 1)),
|
||||
CR_PDX("cross_d1_xo", new Vec3(1, 0, 0), new Vec3(1, 0, 1)),
|
||||
CR_PDZ("cross_d1_zo", new Vec3(0, 0, 1), new Vec3(1, 0, 1)),
|
||||
CR_NDX("cross_d2_xo", new Vec3(1, 0, 0), new Vec3(-1, 0, 1)),
|
||||
CR_NDZ("cross_d2_zo", new Vec3(0, 0, 1), new Vec3(-1, 0, 1));
|
||||
|
||||
private String model;
|
||||
private List<Vec3> axes;
|
||||
private int modelRotation;
|
||||
private Vec3 normal;
|
||||
|
||||
static EnumMap<TrackShape, TrackShape> zMirror = new EnumMap<>(TrackShape.class),
|
||||
xMirror = new EnumMap<>(TrackShape.class), clockwise = new EnumMap<>(TrackShape.class);
|
||||
|
||||
static {
|
||||
zMirror.putAll(ImmutableMap.<TrackShape, TrackShape>builder()
|
||||
.put(PD, ND)
|
||||
.put(ND, PD)
|
||||
.put(AN, AS)
|
||||
.put(AS, AN)
|
||||
.put(CR_PDX, CR_NDX)
|
||||
.put(CR_NDX, CR_PDX)
|
||||
.put(CR_PDZ, CR_NDZ)
|
||||
.put(CR_NDZ, CR_PDZ)
|
||||
.build());
|
||||
|
||||
xMirror.putAll(ImmutableMap.<TrackShape, TrackShape>builder()
|
||||
.put(PD, ND)
|
||||
.put(ND, PD)
|
||||
.put(AE, AW)
|
||||
.put(AW, AE)
|
||||
.put(CR_PDX, CR_NDX)
|
||||
.put(CR_NDX, CR_PDX)
|
||||
.put(CR_PDZ, CR_NDZ)
|
||||
.put(CR_NDZ, CR_PDZ)
|
||||
.build());
|
||||
|
||||
clockwise.putAll(ImmutableMap.<TrackShape, TrackShape>builder()
|
||||
.put(PD, ND)
|
||||
.put(ND, PD)
|
||||
.put(XO, ZO)
|
||||
.put(ZO, XO)
|
||||
.put(AE, AS)
|
||||
.put(AS, AW)
|
||||
.put(AW, AN)
|
||||
.put(AN, AE)
|
||||
.put(CR_PDX, CR_NDZ)
|
||||
.put(CR_NDX, CR_PDZ)
|
||||
.put(CR_PDZ, CR_NDX)
|
||||
.put(CR_NDZ, CR_PDX)
|
||||
.build());
|
||||
}
|
||||
|
||||
private TrackShape(String model, Vec3 axis) {
|
||||
this(model, 0, axis, new Vec3(0, 1, 0));
|
||||
}
|
||||
|
||||
private TrackShape(String model, Vec3 axis, Vec3 secondAxis) {
|
||||
this.model = model;
|
||||
this.modelRotation = 0;
|
||||
this.normal = new Vec3(0, 1, 0);
|
||||
this.axes = ImmutableList.of(axis, secondAxis);
|
||||
}
|
||||
|
||||
private TrackShape(String model, int modelRotation, Vec3 axis, Vec3 normal) {
|
||||
this.model = model;
|
||||
this.modelRotation = modelRotation;
|
||||
this.normal = normal.normalize();
|
||||
this.axes = ImmutableList.of(axis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSerializedName() {
|
||||
return Lang.asId(name());
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public List<Vec3> getAxes() {
|
||||
return axes;
|
||||
}
|
||||
|
||||
public boolean isJunction() {
|
||||
return axes.size() > 1;
|
||||
}
|
||||
|
||||
public Vec3 getNormal() {
|
||||
return normal;
|
||||
}
|
||||
|
||||
public int getModelRotation() {
|
||||
return modelRotation;
|
||||
}
|
||||
|
||||
public TrackShape mirror(Mirror mirror) {
|
||||
return mirror == Mirror.NONE ? this
|
||||
: mirror == Mirror.FRONT_BACK ? xMirror.getOrDefault(this, this) : zMirror.getOrDefault(this, this);
|
||||
}
|
||||
|
||||
public TrackShape rotate(Rotation rotation) {
|
||||
TrackShape shape = this;
|
||||
for (int i = 0; i < rotation.ordinal(); i++)
|
||||
shape = clockwise.getOrDefault(shape, shape);
|
||||
return shape;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,102 +1,118 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.tileEntity.IMergeableTE;
|
||||
import com.simibubi.create.foundation.tileEntity.RemoveTileEntityPacket;
|
||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
public class TrackTileEntity extends SmartTileEntity {
|
||||
public class TrackTileEntity extends SmartTileEntity implements ITransformableTE, IMergeableTE {
|
||||
|
||||
Couple<Map<BlockPos, BezierConnection>> connections;
|
||||
Map<BlockPos, BezierConnection> connections;
|
||||
boolean connectionsValidated;
|
||||
|
||||
public TrackTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
connections = Couple.create(HashMap::new);
|
||||
connections = new HashMap<>();
|
||||
connectionsValidated = false;
|
||||
}
|
||||
|
||||
public Couple<Map<BlockPos, BezierConnection>> getConnections() {
|
||||
public Map<BlockPos, BezierConnection> getConnections() {
|
||||
if (!level.isClientSide && !connectionsValidated)
|
||||
validateConnections();
|
||||
return connections;
|
||||
}
|
||||
|
||||
public void addConnection(boolean front, BezierConnection connection) {
|
||||
connections.get(front)
|
||||
.put(connection.getKey(), connection);
|
||||
notifyUpdate();
|
||||
level.scheduleTick(worldPosition, getBlockState().getBlock(), 1);
|
||||
private void validateConnections() {
|
||||
Set<BlockPos> invalid = new HashSet<>();
|
||||
for (Entry<BlockPos, BezierConnection> entry : connections.entrySet()) {
|
||||
BlockPos key = entry.getKey();
|
||||
BezierConnection bc = entry.getValue();
|
||||
if (key.equals(bc.getKey()) && worldPosition.equals(bc.tePositions.getFirst())) {
|
||||
BlockEntity blockEntity = level.getBlockEntity(key);
|
||||
if (blockEntity instanceof TrackTileEntity trackTE && trackTE.connections.containsKey(worldPosition))
|
||||
continue;
|
||||
}
|
||||
invalid.add(key);
|
||||
}
|
||||
|
||||
connectionsValidated = true;
|
||||
for (BlockPos blockPos : invalid)
|
||||
removeConnection(blockPos);
|
||||
}
|
||||
|
||||
public void removeConnection(boolean front, BlockPos target) {
|
||||
connections.get(front)
|
||||
.remove(target);
|
||||
public void addConnection(BezierConnection connection) {
|
||||
connections.put(connection.getKey(), connection);
|
||||
level.scheduleTick(worldPosition, getBlockState().getBlock(), 1);
|
||||
notifyUpdate();
|
||||
}
|
||||
|
||||
// TODO remove TE when all connections removed. seems tricky without a packet
|
||||
// because level.removeBlockEntity apparently no longer syncs
|
||||
public void removeConnection(BlockPos target) {
|
||||
connections.remove(target);
|
||||
notifyUpdate();
|
||||
if (!connections.isEmpty())
|
||||
return;
|
||||
|
||||
// if (connections.getFirst()
|
||||
// .isEmpty()
|
||||
// && connections.getSecond()
|
||||
// .isEmpty()) {
|
||||
// BlockState blockState = getBlockState();
|
||||
// if (!blockState.hasProperty(TrackBlock.HAS_TURN))
|
||||
// return;
|
||||
// }
|
||||
BlockState blockState = getBlockState();
|
||||
if (blockState.hasProperty(TrackBlock.HAS_TURN))
|
||||
level.setBlockAndUpdate(worldPosition, blockState.setValue(TrackBlock.HAS_TURN, false));
|
||||
AllPackets.channel.send(packetTarget(), new RemoveTileEntityPacket(worldPosition));
|
||||
}
|
||||
|
||||
public void removeInboundConnections() {
|
||||
connections.forEach(map -> map.values()
|
||||
.forEach(bc -> {
|
||||
BlockEntity blockEntity = level.getBlockEntity(bc.getKey());
|
||||
if (!(blockEntity instanceof TrackTileEntity))
|
||||
return;
|
||||
TrackTileEntity other = (TrackTileEntity) blockEntity;
|
||||
other.removeConnection(bc.trackEnds.getSecond(), bc.tePositions.getFirst());
|
||||
}));
|
||||
for (BezierConnection bezierConnection : connections.values()) {
|
||||
BlockEntity blockEntity = level.getBlockEntity(bezierConnection.getKey());
|
||||
if (!(blockEntity instanceof TrackTileEntity))
|
||||
return;
|
||||
TrackTileEntity other = (TrackTileEntity) blockEntity;
|
||||
other.removeConnection(bezierConnection.tePositions.getFirst());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(CompoundTag tag, boolean clientPacket) {
|
||||
super.write(tag, clientPacket);
|
||||
|
||||
CompoundTag connectionsTag = new CompoundTag();
|
||||
connections.forEachWithContext((map, first) -> {
|
||||
ListTag listTag = new ListTag();
|
||||
map.values()
|
||||
.forEach(e -> listTag.add(e.write()));
|
||||
connectionsTag.put(first ? "Front" : "Back", listTag);
|
||||
});
|
||||
|
||||
tag.put("Connections", connectionsTag);
|
||||
ListTag listTag = new ListTag();
|
||||
for (BezierConnection bezierConnection : connections.values())
|
||||
listTag.add(bezierConnection.write(worldPosition));
|
||||
tag.put("Connections", listTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void read(CompoundTag tag, boolean clientPacket) {
|
||||
super.read(tag, clientPacket);
|
||||
|
||||
CompoundTag connectionsTag = tag.getCompound("Connections");
|
||||
connections.forEach(Map::clear);
|
||||
connections.forEachWithContext((map, first) -> connectionsTag.getList(first ? "Front" : "Back", 10)
|
||||
.forEach(t -> {
|
||||
if (!(t instanceof CompoundTag))
|
||||
return;
|
||||
BezierConnection connection = new BezierConnection((CompoundTag) t);
|
||||
map.put(connection.getKey(), connection);
|
||||
}));
|
||||
connections.clear();
|
||||
for (Tag t : tag.getList("Connections", Tag.TAG_COMPOUND)) {
|
||||
if (!(t instanceof CompoundTag))
|
||||
return;
|
||||
BezierConnection connection = new BezierConnection((CompoundTag) t, worldPosition);
|
||||
connections.put(connection.getKey(), connection);
|
||||
}
|
||||
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this));
|
||||
}
|
||||
|
@ -109,4 +125,49 @@ public class TrackTileEntity extends SmartTileEntity {
|
|||
@Override
|
||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
|
||||
|
||||
@Override
|
||||
public void accept(BlockEntity other) {
|
||||
if (other instanceof TrackTileEntity track)
|
||||
connections.putAll(track.connections);
|
||||
connectionsValidated = false;
|
||||
level.scheduleTick(worldPosition, getBlockState().getBlock(), 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(StructureTransform transform) {
|
||||
if (transform.rotationAxis != Axis.Y)
|
||||
return;
|
||||
|
||||
Map<BlockPos, BezierConnection> transformedConnections = new HashMap<>();
|
||||
for (Entry<BlockPos, BezierConnection> entry : connections.entrySet()) {
|
||||
BezierConnection newConnection = entry.getValue();
|
||||
newConnection.normals.replace(transform::applyWithoutOffsetUncentered);
|
||||
newConnection.axes.replace(transform::applyWithoutOffsetUncentered);
|
||||
|
||||
BlockPos diff = newConnection.tePositions.getSecond()
|
||||
.subtract(newConnection.tePositions.getFirst());
|
||||
newConnection.tePositions.setSecond(new BlockPos(Vec3.atCenterOf(newConnection.tePositions.getFirst())
|
||||
.add(transform.applyWithoutOffsetUncentered(Vec3.atLowerCornerOf(diff)))));
|
||||
|
||||
Vec3 teVec = Vec3.atLowerCornerOf(worldPosition);
|
||||
Vec3 teCenterVec = teVec.add(0.5, 0.5, 0.5);
|
||||
Vec3 start = newConnection.starts.getFirst();
|
||||
Vec3 startToTE = start.subtract(teCenterVec);
|
||||
Vec3 endToStart = newConnection.starts.getSecond()
|
||||
.subtract(start);
|
||||
startToTE = transform.applyWithoutOffsetUncentered(startToTE)
|
||||
.add(teCenterVec);
|
||||
endToStart = transform.applyWithoutOffsetUncentered(endToStart)
|
||||
.add(startToTE);
|
||||
|
||||
newConnection.starts.setFirst(new TrackNodeLocation(startToTE).getLocation());
|
||||
newConnection.starts.setSecond(new TrackNodeLocation(endToStart).getLocation());
|
||||
|
||||
BlockPos newTarget = newConnection.getKey();
|
||||
transformedConnections.put(newTarget, newConnection);
|
||||
}
|
||||
|
||||
connections = transformedConnections;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.simibubi.create.AllBlocks;
|
|||
import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
|
||||
import com.simibubi.create.content.schematics.item.SchematicItem;
|
||||
import com.simibubi.create.foundation.tileEntity.IMergeableTE;
|
||||
import com.simibubi.create.foundation.utility.BlockHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -190,7 +191,9 @@ public class SchematicPrinter {
|
|||
BlockEntity tileEntity = blockReader.getBlockEntity(pos);
|
||||
|
||||
BlockState toReplace = world.getBlockState(pos);
|
||||
BlockEntity toReplaceTE = world.getBlockEntity(pos);
|
||||
BlockState toReplaceOther = null;
|
||||
|
||||
if (state.hasProperty(BlockStateProperties.BED_PART) && state.hasProperty(BlockStateProperties.HORIZONTAL_FACING)
|
||||
&& state.getValue(BlockStateProperties.BED_PART) == BedPart.FOOT)
|
||||
toReplaceOther = world.getBlockState(pos.relative(state.getValue(BlockStateProperties.HORIZONTAL_FACING)));
|
||||
|
@ -198,11 +201,14 @@ public class SchematicPrinter {
|
|||
&& state.getValue(BlockStateProperties.DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER)
|
||||
toReplaceOther = world.getBlockState(pos.above());
|
||||
|
||||
boolean mergeTEs = tileEntity != null && toReplaceTE instanceof IMergeableTE mergeTE && toReplaceTE.getType()
|
||||
.equals(tileEntity.getType());
|
||||
|
||||
if (!world.isLoaded(pos))
|
||||
return false;
|
||||
if (!world.getWorldBorder().isWithinBounds(pos))
|
||||
return false;
|
||||
if (toReplace == state)
|
||||
if (toReplace == state && !mergeTEs)
|
||||
return false;
|
||||
if (toReplace.getDestroySpeed(world, pos) == -1
|
||||
|| (toReplaceOther != null && toReplaceOther.getDestroySpeed(world, pos) == -1))
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllKeys;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
|
||||
import com.simibubi.create.content.schematics.SchematicWorld;
|
||||
import com.simibubi.create.content.schematics.client.tools.Tools;
|
||||
import com.simibubi.create.content.schematics.filtering.SchematicInstances;
|
||||
|
@ -23,6 +24,7 @@ import com.simibubi.create.foundation.utility.outliner.AABBOutline;
|
|||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
|
@ -33,6 +35,8 @@ import net.minecraft.world.item.ItemStack;
|
|||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Mirror;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
||||
|
@ -137,16 +141,27 @@ public class SchematicHandler {
|
|||
SchematicWorld wMirroredFB = new SchematicWorld(clientWorld);
|
||||
SchematicWorld wMirroredLR = new SchematicWorld(clientWorld);
|
||||
StructurePlaceSettings placementSettings = new StructurePlaceSettings();
|
||||
StructureTransform transform;
|
||||
BlockPos pos;
|
||||
|
||||
pos = BlockPos.ZERO;
|
||||
schematic.placeInWorld(w, pos, pos, placementSettings, w.getRandom(), Block.UPDATE_CLIENTS);
|
||||
|
||||
placementSettings.setMirror(Mirror.FRONT_BACK);
|
||||
pos = BlockPos.ZERO.east(size.getX() - 1);
|
||||
schematic.placeInWorld(wMirroredFB, pos, pos, placementSettings, wMirroredFB.getRandom(), Block.UPDATE_CLIENTS);
|
||||
transform = new StructureTransform(placementSettings.getRotationPivot(), Axis.Y, Rotation.NONE,
|
||||
placementSettings.getMirror());
|
||||
for (BlockEntity te : wMirroredFB.getRenderedTileEntities())
|
||||
transform.apply(te);
|
||||
|
||||
placementSettings.setMirror(Mirror.LEFT_RIGHT);
|
||||
pos = BlockPos.ZERO.south(size.getZ() - 1);
|
||||
schematic.placeInWorld(wMirroredLR, pos, pos, placementSettings, wMirroredFB.getRandom(), Block.UPDATE_CLIENTS);
|
||||
transform = new StructureTransform(placementSettings.getRotationPivot(), Axis.Y, Rotation.NONE,
|
||||
placementSettings.getMirror());
|
||||
for (BlockEntity te : wMirroredLR.getRenderedTileEntities())
|
||||
transform.apply(te);
|
||||
|
||||
renderers.get(0)
|
||||
.display(w);
|
||||
|
@ -187,11 +202,11 @@ public class SchematicHandler {
|
|||
renderers.get(0)
|
||||
.render(ms, buffer);
|
||||
}
|
||||
|
||||
|
||||
if (active)
|
||||
currentTool.getTool()
|
||||
.renderOnSchematic(ms, buffer);
|
||||
|
||||
.renderOnSchematic(ms, buffer);
|
||||
|
||||
ms.popPose();
|
||||
|
||||
}
|
||||
|
@ -227,7 +242,7 @@ public class SchematicHandler {
|
|||
return;
|
||||
}
|
||||
currentTool.getTool()
|
||||
.handleRightClick();
|
||||
.handleRightClick();
|
||||
}
|
||||
|
||||
public void onKeyInput(int key, boolean pressed) {
|
||||
|
@ -272,10 +287,12 @@ public class SchematicHandler {
|
|||
|
||||
private boolean itemLost(Player player) {
|
||||
for (int i = 0; i < Inventory.getSelectionSize(); i++) {
|
||||
if (!player.getInventory().getItem(i)
|
||||
if (!player.getInventory()
|
||||
.getItem(i)
|
||||
.sameItem(activeSchematicItem))
|
||||
continue;
|
||||
if (!ItemStack.tagMatches(player.getInventory().getItem(i), activeSchematicItem))
|
||||
if (!ItemStack.tagMatches(player.getInventory()
|
||||
.getItem(i), activeSchematicItem))
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
|
@ -289,7 +306,8 @@ public class SchematicHandler {
|
|||
public void sync() {
|
||||
if (activeSchematicItem == null)
|
||||
return;
|
||||
AllPackets.channel.sendToServer(new SchematicSyncPacket(activeHotbarSlot, transformation.toSettings(), transformation.getAnchor(), deployed));
|
||||
AllPackets.channel.sendToServer(new SchematicSyncPacket(activeHotbarSlot, transformation.toSettings(),
|
||||
transformation.getAnchor(), deployed));
|
||||
}
|
||||
|
||||
public void equip(Tools tool) {
|
||||
|
|
|
@ -57,6 +57,7 @@ import com.simibubi.create.foundation.command.SConfigureConfigPacket;
|
|||
import com.simibubi.create.foundation.config.ui.CConfigureConfigPacket;
|
||||
import com.simibubi.create.foundation.gui.container.ClearContainerPacket;
|
||||
import com.simibubi.create.foundation.gui.container.GhostItemSubmitPacket;
|
||||
import com.simibubi.create.foundation.tileEntity.RemoveTileEntityPacket;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringCountUpdatePacket;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueUpdatePacket;
|
||||
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
|
||||
|
@ -132,6 +133,7 @@ public enum AllPackets {
|
|||
PERSISTENT_DATA(ISyncPersistentData.PersistentDataPacket.class, ISyncPersistentData.PersistentDataPacket::new, PLAY_TO_CLIENT),
|
||||
SYNC_POTATO_PROJECTILE_TYPES(PotatoProjectileTypeManager.SyncPacket.class, PotatoProjectileTypeManager.SyncPacket::new, PLAY_TO_CLIENT),
|
||||
SYNC_RAIL_GRAPH(RailGraphSyncPacket.class, RailGraphSyncPacket::new, PLAY_TO_CLIENT),
|
||||
REMOVE_TE(RemoveTileEntityPacket.class, RemoveTileEntityPacket::new, PLAY_TO_CLIENT),
|
||||
|
||||
;
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package com.simibubi.create.foundation.tileEntity;
|
||||
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
public interface IMergeableTE {
|
||||
|
||||
public void accept(BlockEntity other);
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.simibubi.create.foundation.tileEntity;
|
||||
|
||||
import com.simibubi.create.foundation.networking.TileEntityDataPacket;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
||||
public class RemoveTileEntityPacket extends TileEntityDataPacket<SyncedTileEntity> {
|
||||
|
||||
public RemoveTileEntityPacket(BlockPos pos) {
|
||||
super(pos);
|
||||
}
|
||||
|
||||
public RemoveTileEntityPacket(FriendlyByteBuf buffer) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeData(FriendlyByteBuf buffer) {}
|
||||
|
||||
@Override
|
||||
protected void handlePacket(SyncedTileEntity tile) {
|
||||
tile.setRemoved();
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ import javax.annotation.Nullable;
|
|||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.content.contraptions.components.actors.SeatBlock;
|
||||
import com.simibubi.create.foundation.tileEntity.IMergeableTE;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
|
@ -200,15 +201,12 @@ public class BlockHelper {
|
|||
int idx = chunk.getSectionIndex(target.getY());
|
||||
LevelChunkSection chunksection = chunk.getSection(idx);
|
||||
if (chunksection == null) {
|
||||
chunksection = new LevelChunkSection(chunk.getSectionYFromSectionIndex(idx),
|
||||
world.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY));
|
||||
chunksection = new LevelChunkSection(chunk.getSectionYFromSectionIndex(idx), world.registryAccess()
|
||||
.registryOrThrow(Registry.BIOME_REGISTRY));
|
||||
chunk.getSections()[idx] = chunksection;
|
||||
}
|
||||
BlockState old = chunksection.setBlockState(
|
||||
SectionPos.sectionRelative(target.getX()),
|
||||
SectionPos.sectionRelative(target.getY()),
|
||||
SectionPos.sectionRelative(target.getZ()),
|
||||
state);
|
||||
BlockState old = chunksection.setBlockState(SectionPos.sectionRelative(target.getX()),
|
||||
SectionPos.sectionRelative(target.getY()), SectionPos.sectionRelative(target.getZ()), state);
|
||||
chunk.setUnsaved(true);
|
||||
world.markAndNotifyBlock(target, chunk, old, state, 82, 512);
|
||||
|
||||
|
@ -219,6 +217,8 @@ public class BlockHelper {
|
|||
|
||||
public static void placeSchematicBlock(Level world, BlockState state, BlockPos target, ItemStack stack,
|
||||
@Nullable CompoundTag data) {
|
||||
BlockEntity existingTile = world.getBlockEntity(target);
|
||||
|
||||
// Piston
|
||||
if (state.hasProperty(BlockStateProperties.EXTENDED))
|
||||
state = state.setValue(BlockStateProperties.EXTENDED, Boolean.FALSE);
|
||||
|
@ -259,6 +259,14 @@ public class BlockHelper {
|
|||
}
|
||||
|
||||
if (data != null) {
|
||||
if (existingTile instanceof IMergeableTE mergeable) {
|
||||
BlockEntity loaded = BlockEntity.loadStatic(target, state, data);
|
||||
if (existingTile.getType()
|
||||
.equals(loaded.getType())) {
|
||||
mergeable.accept(loaded);
|
||||
return;
|
||||
}
|
||||
}
|
||||
BlockEntity tile = world.getBlockEntity(target);
|
||||
if (tile != null) {
|
||||
data.putInt("x", target.getX());
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"textures": {
|
||||
"0": "create:block/girder"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [-4, -1, 0],
|
||||
"to": [4, 1, 8],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [8, 13, 8]},
|
||||
"faces": {
|
||||
"north": {"uv": [12, 2, 16, 3], "texture": "#0"},
|
||||
"east": {"uv": [1, 5, 5, 4], "texture": "#0"},
|
||||
"south": {"uv": [12, 2, 16, 3], "texture": "#0"},
|
||||
"west": {"uv": [3, 5, 7, 4], "texture": "#0"},
|
||||
"up": {"uv": [12, 0, 16, 4], "rotation": 270, "texture": "#0"},
|
||||
"down": {"uv": [2, 0, 6, 4], "rotation": 270, "texture": "#0"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue