From 033e7e1a0d33ccbf335f71210002c1e14e144928 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Fri, 11 Feb 2022 00:20:58 +0100 Subject: [PATCH] Proper Propa - Improvements to graph building - Fixed a number of issues caused by junctions and inconsistent track propagation - Trains no longer disassemble with reversed carriage spacing - Trains can no longer jump to perpendicular tracks on an intersection --- .../content/logistics/trains/ITrackBlock.java | 72 ++++- .../content/logistics/trains/TrackGraph.java | 15 +- .../logistics/trains/TrackGraphHelper.java | 89 ++++-- .../logistics/trains/TrackNodeLocation.java | 31 +- .../logistics/trains/TrackPropagator.java | 280 +++++------------- .../logistics/trains/entity/Train.java | 2 +- .../trains/entity/TravellingPoint.java | 4 +- .../trains/management/StationTileEntity.java | 23 +- .../trains/track/StandardBogeyBlock.java | 2 +- .../logistics/trains/track/TrackBlock.java | 43 ++- 10 files changed, 301 insertions(+), 260 deletions(-) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java index ace7b5084..27aa7a436 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java @@ -1,9 +1,18 @@ package com.simibubi.create.content.logistics.trains; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +import javax.annotation.Nullable; import com.jozufozu.flywheel.core.PartialModel; import com.mojang.blaze3d.vertex.PoseStack; +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.TrackShape; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Pair; @@ -27,11 +36,72 @@ public interface ITrackBlock { public BlockState getBogeyAnchor(BlockGetter world, BlockPos pos, BlockState state); // should be on bogey side public boolean trackEquals(BlockState state1, BlockState state2); - + public default BlockState overlay(BlockGetter world, BlockPos pos, BlockState existing, BlockState placed) { return existing; } + public default double getElevationAtCenter(BlockGetter world, BlockPos pos, BlockState state) { + return isSlope(world, pos, state) ? .5 : 0; + } + + public static Collection walkConnectedTracks(BlockGetter world, TrackNodeLocation location, + boolean linear) { + List list = new ArrayList<>(); + for (BlockPos blockPos : location.allAdjacent()) { + BlockState blockState = world.getBlockState(blockPos); + if (blockState.getBlock()instanceof ITrackBlock track) + list.addAll(track.getConnected(world, blockPos, blockState, linear, location)); + } + return list; + } + + public default Collection getConnected(BlockGetter world, BlockPos pos, BlockState state, + boolean linear, @Nullable TrackNodeLocation connectedTo) { + Vec3 center = Vec3.atBottomCenterOf(pos) + .add(0, getElevationAtCenter(world, pos, state), 0); + List 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(), null); + }); + + return list; + } + + public static void addToListIfConnected(@Nullable TrackNodeLocation fromEnd, Collection list, + BiFunction offsetFactory, Function normalFactory, + BezierConnection viaTurn) { + + DiscoveredLocation firstLocation = new DiscoveredLocation(offsetFactory.apply(0.5d, true)).viaTurn(viaTurn) + .withNormal(normalFactory.apply(true)); + DiscoveredLocation secondLocation = new DiscoveredLocation(offsetFactory.apply(0.5d, false)).viaTurn(viaTurn) + .withNormal(normalFactory.apply(false)); + + boolean skipFirst = false; + boolean skipSecond = false; + + if (fromEnd != null) { + boolean equalsFirst = firstLocation.equals(fromEnd); + boolean equalsSecond = secondLocation.equals(fromEnd); + + // not reachable from this end + if (!equalsFirst && !equalsSecond) + return; + + if (equalsFirst) + skipFirst = true; + if (equalsSecond) + skipSecond = true; + } + + if (!skipFirst) + list.add(firstLocation); + if (!skipSecond) + list.add(secondLocation); + } + @OnlyIn(Dist.CLIENT) public PartialModel prepareStationOverlay(BlockGetter world, BlockPos pos, BlockState state, AxisDirection direction, PoseStack transform); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java index 8fc03f02f..5736c3192 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java @@ -409,11 +409,12 @@ public class TrackGraph { if (location.distanceTo(camera) > 50) continue; - Vec3 v1 = location.add(0, 3 / 16f, 0); - Vec3 v2 = v1.add(node.normal.scale(0.75f)); + Vec3 yOffset = new Vec3(0, 3 / 16f, 0); + Vec3 v1 = location.add(yOffset); + Vec3 v2 = v1.add(node.normal.scale(0.125f)); CreateClient.OUTLINER.showLine(Integer.valueOf(node.netId), v1, v2) .colored(Color.mixColors(Color.WHITE, color, 1)) - .lineWidth(1 / 8f); + .lineWidth(1 / 4f); Map map = connectionsByNode.get(node); if (map == null) @@ -428,8 +429,10 @@ public class TrackGraph { TrackEdge edge = entry.getValue(); if (!edge.isTurn()) { - CreateClient.OUTLINER - .showLine(edge, edge.getPosition(node, other, 0), edge.getPosition(node, other, 1)) + CreateClient.OUTLINER.showLine(edge, edge.getPosition(node, other, 0) + .add(yOffset), + edge.getPosition(node, other, 1) + .add(yOffset)) .colored(color) .lineWidth(1 / 16f); continue; @@ -440,7 +443,7 @@ public class TrackGraph { for (int i = 0; i <= turn.getSegmentCount(); i++) { Vec3 current = edge.getPosition(node, other, i * 1f / turn.getSegmentCount()); if (previous != null) - CreateClient.OUTLINER.showLine(previous, previous, current) + CreateClient.OUTLINER.showLine(previous, previous.add(yOffset), current.add(yOffset)) .colored(color) .lineWidth(1 / 16f); previous = current; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphHelper.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphHelper.java index c17283c52..fddc93cff 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphHelper.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphHelper.java @@ -1,12 +1,13 @@ package com.simibubi.create.content.logistics.trains; -import java.util.List; +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; import com.simibubi.create.Create; import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; import com.simibubi.create.content.logistics.trains.management.GraphLocation; import com.simibubi.create.foundation.utility.Couple; -import com.simibubi.create.foundation.utility.Pair; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction.AxisDirection; @@ -24,48 +25,88 @@ public class TrackGraphHelper { Vec3 axis = targetAxis.scale(targetDirection.getStep()); double length = axis.length(); - - List> ends = - TrackPropagator.getEnds(level, pos, trackBlockState, true, null, null); - TrackGraph graph = null; + + // Case 1: Centre of block lies on a node + + TrackNodeLocation location = new TrackNodeLocation(Vec3.atBottomCenterOf(pos) + .add(0, track.getElevationAtCenter(level, pos, trackBlockState), 0)); + graph = Create.RAILWAYS.getGraph(level, location); + if (graph != null) { + TrackNode node = graph.locateNode(location); + if (node != null) { + Map connectionsFrom = graph.getConnectionsFrom(node); + for (Entry entry : connectionsFrom.entrySet()) { + TrackNode backNode = entry.getKey(); + Vec3 direction = entry.getValue() + .getDirection(node, backNode, true); + if (direction.scale(length) + .distanceToSqr(axis.scale(-1)) > 1 / 4096f) + continue; + + GraphLocation graphLocation = new GraphLocation(); + graphLocation.edge = Couple.create(node.getLocation(), backNode.getLocation()); + graphLocation.position = 0; + graphLocation.graph = graph; + return graphLocation; + } + } + } + + // Case 2: Center of block is between two nodes + + Collection ends = track.getConnected(level, pos, trackBlockState, true, null); + Vec3 start = Vec3.atBottomCenterOf(pos) + .add(0, track.getElevationAtCenter(level, pos, trackBlockState), 0); + TrackNode frontNode = null; TrackNode backNode = null; double position = 0; - for (Pair pair : ends) { - DiscoveredLocation current = pair.getSecond(); - BlockPos currentPos = pair.getFirst(); - Vec3 offset = Vec3.atLowerCornerOf(currentPos.subtract(pos)); + for (DiscoveredLocation current : ends) { + Vec3 offset = current.getLocation() + .subtract(start) + .normalize() + .scale(length); + boolean forward = offset.distanceToSqr(axis.scale(-1)) < 1 / 4096f; boolean backwards = offset.distanceToSqr(axis) < 1 / 4096f; if (!forward && !backwards) continue; - for (int i = 0; i < 32; i++) { + DiscoveredLocation previous = null; + double distance = 0; + for (int i = 0; i < 100 && distance < 32; i++) { DiscoveredLocation loc = current; - List> list = - TrackPropagator.getEnds(level, currentPos, level.getBlockState(currentPos), true, current, null); - if (!list.isEmpty()) { - currentPos = list.get(0) - .getFirst(); - current = list.get(0) - .getSecond(); - } - if (graph == null) graph = Create.RAILWAYS.getGraph(level, loc); - if (graph == null) + + if (graph == null || graph.locateNode(loc) == null) { + Collection list = ITrackBlock.walkConnectedTracks(level, loc, true); + for (DiscoveredLocation discoveredLocation : list) { + if (discoveredLocation == previous) + continue; + Vec3 diff = discoveredLocation.getLocation() + .subtract(loc.getLocation()); + if ((forward ? axis.scale(-1) : axis).distanceToSqr(diff.normalize() + .scale(length)) > 1 / 4096f) + continue; + + previous = current; + current = discoveredLocation; + distance += diff.length(); + break; + } continue; + } + TrackNode node = graph.locateNode(loc); - if (node == null) - continue; if (forward) frontNode = node; if (backwards) { backNode = node; - position = (i + .5) * length; + position = distance + .5; } break; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java index a23dbdc32..2ccd1d573 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java @@ -1,5 +1,11 @@ package com.simibubi.create.content.logistics.trains; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import com.simibubi.create.foundation.utility.Iterate; + import net.minecraft.core.BlockPos; import net.minecraft.core.Vec3i; import net.minecraft.world.phys.Vec3; @@ -17,7 +23,7 @@ public class TrackNodeLocation extends Vec3i { public static TrackNodeLocation fromPackedPos(BlockPos bufferPos) { return new TrackNodeLocation(bufferPos); } - + private TrackNodeLocation(BlockPos readBlockPos) { super(readBlockPos.getX(), readBlockPos.getY(), readBlockPos.getZ()); } @@ -36,9 +42,21 @@ public class TrackNodeLocation extends Vec3i { return (this.getY() + this.getZ() * 31) * 31 + this.getX(); } + public Collection allAdjacent() { + Set set = new HashSet<>(); + Vec3 vec3 = getLocation(); + double step = 1 / 8f; + for (int x : Iterate.positiveAndNegative) + for (int y : Iterate.positiveAndNegative) + for (int z : Iterate.positiveAndNegative) + set.add(new BlockPos(vec3.add(x * step, y * step, z * step))); + return set; + } + public static class DiscoveredLocation extends TrackNodeLocation { BezierConnection turn = null; + boolean forceNode = false; Vec3 normal; public DiscoveredLocation(double p_121865_, double p_121866_, double p_121867_) { @@ -51,6 +69,13 @@ public class TrackNodeLocation extends Vec3i { public DiscoveredLocation viaTurn(BezierConnection turn) { this.turn = turn; + if (turn != null) + forceNode(); + return this; + } + + public DiscoveredLocation forceNode() { + forceNode = true; return this; } @@ -66,6 +91,10 @@ public class TrackNodeLocation extends Vec3i { public BezierConnection getTurn() { return turn; } + + public boolean shouldForceNode() { + return forceNode; + } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java index 95804463c..a15b40dc5 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java @@ -1,70 +1,55 @@ package com.simibubi.create.content.logistics.trains; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; -import java.util.function.BiFunction; -import java.util.function.Function; - -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.TrackShape; -import com.simibubi.create.content.logistics.trains.track.TrackTileEntity; -import com.simibubi.create.foundation.utility.Pair; -import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; public class TrackPropagator { static class FrontierEntry { - BlockPos prevPos; DiscoveredLocation prevNode; - BlockPos currentPos; DiscoveredLocation currentNode; DiscoveredLocation parentNode; - public FrontierEntry(BlockPos previousPos, BlockPos pos, DiscoveredLocation location) { - this(null, previousPos, null, pos, location); - } - - public FrontierEntry(DiscoveredLocation parent, BlockPos previousPos, DiscoveredLocation previousNode, - BlockPos pos, DiscoveredLocation location) { + public FrontierEntry(DiscoveredLocation parent, DiscoveredLocation previousNode, DiscoveredLocation location) { parentNode = parent; - prevPos = previousPos; prevNode = previousNode; - currentPos = pos; currentNode = location; } } public static void onRailRemoved(LevelAccessor reader, BlockPos pos, BlockState state) { - List> ends = getEnds(reader, pos, state, false, null, null); - TrackGraph foundGraph = null; + if (!(state.getBlock()instanceof ITrackBlock track)) + return; + + Collection ends = track.getConnected(reader, pos, state, false, null); GlobalRailwayManager manager = Create.RAILWAYS; TrackGraphSync sync = manager.sync; + TrackGraph foundGraph = null; - for (Pair removedEnd : ends) { - DiscoveredLocation removedLocation = removedEnd.getSecond(); + // 1. Remove any nodes this rail was part of + + for (DiscoveredLocation removedLocation : ends) { if (foundGraph == null) foundGraph = manager.getGraph(reader, removedLocation); - if (foundGraph != null) { - TrackNode removedNode = foundGraph.locateNode(removedLocation); - if (removedNode != null) { - foundGraph.removeNode(reader, removedLocation); - sync.nodeRemoved(foundGraph, removedNode); - } + if (foundGraph == null) + continue; + TrackNode removedNode = foundGraph.locateNode(removedLocation); + if (removedNode != null) { + foundGraph.removeNode(reader, removedLocation); + sync.nodeRemoved(foundGraph, removedNode); } } @@ -73,21 +58,21 @@ public class TrackPropagator { sync.graphRemoved(foundGraph); } + Set positionsToUpdate = new HashSet<>(); + for (DiscoveredLocation removedEnd : ends) + positionsToUpdate.addAll(removedEnd.allAdjacent()); + + // 2. Re-run railAdded for any track that was disconnected from this track + Set toUpdate = new HashSet<>(); - for (Pair removedEnd : ends) { - BlockPos adjPos = removedEnd.getFirst(); - BlockState adjState = reader.getBlockState(adjPos); - List> 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 (BlockPos blockPos : positionsToUpdate) + if (!blockPos.equals(pos)) { + TrackGraph onRailAdded = onRailAdded(reader, blockPos, reader.getBlockState(blockPos)); + if (onRailAdded != null) + toUpdate.add(onRailAdded); + } + + // 3. Ensure any affected graph gets checked for segmentation for (TrackGraph railGraph : toUpdate) manager.updateSplitGraph(railGraph); @@ -95,7 +80,10 @@ public class TrackPropagator { manager.markTracksDirty(); } - public static TrackGraph onRailAdded(LevelAccessor reader, BlockPos pos, BlockState state, Vec3 axisFilter) { + public static TrackGraph onRailAdded(LevelAccessor reader, BlockPos pos, BlockState state) { + if (!(state.getBlock()instanceof ITrackBlock track)) + return null; + // 1. Remove all immediately reachable node locations GlobalRailwayManager manager = Create.RAILWAYS; @@ -103,7 +91,7 @@ public class TrackPropagator { List frontier = new ArrayList<>(); Set visited = new HashSet<>(); Set connectedGraphs = new HashSet<>(); - addInitialEndsOf(reader, pos, state, frontier, false, axisFilter); + addInitialEndsOf(reader, pos, state, track, frontier, false); int emergencyExit = 1000; while (!frontier.isEmpty()) { @@ -111,7 +99,6 @@ public class TrackPropagator { break; FrontierEntry entry = frontier.remove(0); - List> ends = findReachableEnds(reader, entry); TrackGraph graph = manager.getGraph(reader, entry.currentNode); if (graph != null) { TrackNode node = graph.locateNode(entry.currentNode); @@ -121,6 +108,9 @@ public class TrackPropagator { continue; } + Collection ends = ITrackBlock.walkConnectedTracks(reader, entry.currentNode, false); + if (entry.prevNode != null) + ends.remove(entry.prevNode); continueSearch(frontier, visited, entry, ends); } @@ -157,11 +147,10 @@ public class TrackPropagator { manager.putGraph(graph = new TrackGraph()); DiscoveredLocation startNode = null; - List startPositions = new ArrayList<>(); // 2. Find the first graph node candidate nearby - addInitialEndsOf(reader, pos, state, frontier, true, axisFilter); + addInitialEndsOf(reader, pos, state, track, frontier, true); emergencyExit = 1000; while (!frontier.isEmpty()) { @@ -169,26 +158,12 @@ public class TrackPropagator { break; FrontierEntry entry = frontier.remove(0); - -// CreateClient.OUTLINER -// .showAABB(entry.currentNode, new AABB(entry.currentNode.getLocation(), entry.currentNode.getLocation() -// .add(0, 2, 0)), 120) -// .colored(Color.GREEN) -// .lineWidth(1 / 16f); -// CreateClient.OUTLINER.showAABB(entry.currentPos, new AABB(entry.currentPos).contract(0, 1, 0), 120) -// .colored(0x7777ff) -// .lineWidth(1 / 16f); -// if (entry.prevPos != null) { -// CreateClient.OUTLINER.showAABB(entry.prevPos, new AABB(entry.prevPos).contract(0, 1, 0), 120) -// .colored(0x3333aa) -// .lineWidth(1 / 16f); -// } - - List> ends = findReachableEnds(reader, entry); - if (isValidGraphNodeLocation(entry.currentNode, ends)) { + Collection ends = ITrackBlock.walkConnectedTracks(reader, entry.currentNode, false); + boolean first = entry.prevNode == null; + if (!first) + ends.remove(entry.prevNode); + if (isValidGraphNodeLocation(entry.currentNode, ends, first)) { startNode = entry.currentNode; - startPositions.add(entry.prevPos); - startPositions.add(entry.currentPos); break; } @@ -199,12 +174,7 @@ public class TrackPropagator { if (graph.createNode(startNode)) sync.nodeAdded(graph, graph.locateNode(startNode)); -// CreateClient.OUTLINER.showAABB(graph, new AABB(startNode.getLocation(), startNode.getLocation() -// .add(0, 2, 0)), 20) -// .lineWidth(1 / 32f); - - for (BlockPos position : startPositions) - frontier.add(new FrontierEntry(startNode, null, null, position, startNode)); + frontier.add(new FrontierEntry(startNode, null, startNode)); // 3. Build up the graph via all connected nodes @@ -215,9 +185,12 @@ public class TrackPropagator { FrontierEntry entry = frontier.remove(0); DiscoveredLocation parentNode = entry.parentNode; - List> ends = findReachableEnds(reader, entry); + Collection ends = ITrackBlock.walkConnectedTracks(reader, entry.currentNode, false); + boolean first = entry.prevNode == null; + if (!first) + ends.remove(entry.prevNode); - if (isValidGraphNodeLocation(entry.currentNode, ends) && entry.currentNode != startNode) { + if (isValidGraphNodeLocation(entry.currentNode, ends, first) && entry.currentNode != startNode) { boolean nodeIsNew = graph.createNode(entry.currentNode); if (nodeIsNew) sync.nodeAdded(graph, graph.locateNode(entry.currentNode)); @@ -234,70 +207,35 @@ public class TrackPropagator { return graph; } - private static void addInitialEndsOf(LevelAccessor reader, BlockPos pos, BlockState state, - List frontier, boolean ignoreTurns, Vec3 axisFilter) { - for (Pair initial : getEnds(reader, pos, state, ignoreTurns, null, axisFilter)) - frontier.add(new FrontierEntry(initial.getFirst(), pos, initial.getSecond())); - } - - private static List> findReachableEnds(LevelAccessor reader, - FrontierEntry entry) { - BlockState currentState = reader.getBlockState(entry.currentPos); - List> ends = new ArrayList<>(); - - if (entry.prevNode != null) { - BlockPos prevPos = entry.prevPos; - - // PrevPos correction after a turn - if (entry.currentNode.connectedViaTurn()) { - boolean slope = false; - if (currentState.getBlock()instanceof ITrackBlock track) - slope = track.isSlope(reader, entry.currentPos, currentState); - BlockPos offset = new BlockPos(VecHelper.getCenterOf(entry.currentPos) - .subtract(entry.currentNode.getLocation() - .add(0, slope ? 0 : .5f, 0)) - .scale(-2)); - prevPos = entry.currentPos.offset(offset); - } - - for (Pair pair : getEnds(reader, prevPos, reader.getBlockState(prevPos), - false, entry.currentNode, null)) - if (!pair.getSecond() - .equals(entry.prevNode)) - ends.add(pair); + private static void addInitialEndsOf(LevelAccessor reader, BlockPos pos, BlockState state, ITrackBlock track, + List frontier, boolean ignoreTurns) { + for (DiscoveredLocation initial : track.getConnected(reader, pos, state, ignoreTurns, null)) { + frontier.add(new FrontierEntry(null, null, initial)); } - - ends.addAll(getEnds(reader, entry.currentPos, currentState, false, entry.currentNode, null)); - return ends; } private static void continueSearch(List frontier, Set visited, - FrontierEntry entry, List> ends) { - for (Pair pair : ends) - if (visited.add(pair.getSecond())) - frontier.add( - new FrontierEntry(null, entry.currentPos, entry.currentNode, pair.getFirst(), pair.getSecond())); + FrontierEntry entry, Collection ends) { + for (DiscoveredLocation location : ends) + if (visited.add(location)) + frontier.add(new FrontierEntry(null, entry.currentNode, location)); } private static void continueSearchWithParent(List frontier, FrontierEntry entry, - DiscoveredLocation parentNode, List> ends) { - for (Pair pair : ends) - frontier.add( - new FrontierEntry(parentNode, entry.currentPos, entry.currentNode, pair.getFirst(), pair.getSecond())); + DiscoveredLocation parentNode, Collection ends) { + for (DiscoveredLocation location : ends) + frontier.add(new FrontierEntry(parentNode, entry.currentNode, location)); } - public static boolean isValidGraphNodeLocation(DiscoveredLocation location, - List> next) { - if (next.size() != 1) + public static boolean isValidGraphNodeLocation(DiscoveredLocation location, Collection next, + boolean first) { + int size = next.size() - (first ? 1 : 0); + if (size != 1) return true; - if (location.connectedViaTurn()) + if (location.shouldForceNode()) return true; - - DiscoveredLocation nextLocation = next.iterator() - .next() - .getSecond(); - - if (nextLocation.connectedViaTurn()) + if (next.stream() + .anyMatch(DiscoveredLocation::connectedViaTurn)) return true; Vec3 vec = location.getLocation(); @@ -308,86 +246,4 @@ public class TrackPropagator { return ((int) Math.round(vec.x)) % 16 == 0; } - // TODO ITrackBlock - public static List> getEnds(LevelReader reader, BlockPos pos, BlockState state, - boolean ignoreTurns, @Nullable DiscoveredLocation fromEnd, @Nullable Vec3 axisFilter) { - Vec3 center = VecHelper.getCenterOf(pos); - List> list = new ArrayList<>(); - - if (!(state.getBlock() instanceof TrackBlock)) - return list; - - BlockEntity blockEntity = reader.getBlockEntity(pos); - if (state.getValue(TrackBlock.HAS_TURN) && blockEntity instanceof TrackTileEntity && !ignoreTurns) { - TrackTileEntity trackTileEntity = (TrackTileEntity) blockEntity; - trackTileEntity.getConnections() - .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) - 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); - }); - - 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> list, - BiFunction offsetFactory, Function normalFactory, - BezierConnection viaTurn) { - - DiscoveredLocation firstLocation = new DiscoveredLocation(offsetFactory.apply(0.5d, true)); - DiscoveredLocation secondLocation = new DiscoveredLocation(offsetFactory.apply(0.5d, false)); - - Pair firstNode = - Pair.of(new BlockPos(offsetFactory.apply(1.0d, true)), firstLocation.viaTurn(viaTurn) - .withNormal(normalFactory.apply(true))); - Pair secondNode = - Pair.of(new BlockPos(offsetFactory.apply(1.0d, false)), secondLocation.viaTurn(viaTurn) - .withNormal(normalFactory.apply(false))); - - boolean skipFirst = false; - boolean skipSecond = false; - - if (fromEnd != null) { - boolean equalsFirst = firstNode.getSecond() - .equals(fromEnd); - boolean equalsSecond = secondNode.getSecond() - .equals(fromEnd); - - // not reachable from this end, crossover rail - if (!equalsFirst && !equalsSecond) - return; - - if (equalsFirst) - skipFirst = true; - if (equalsSecond) - skipSecond = true; - } - - if (!skipFirst) - list.add(firstNode); - if (!skipSecond) - list.add(secondNode); - } - } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java index 70e380afb..642150435 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java @@ -338,7 +338,7 @@ public class Train { offset += carriage.bogeySpacing; if (i < carriageSpacing.size()) - offset += carriageSpacing.get(carriageSpacing.size() - i - 1); + offset += carriageSpacing.get(backwards ? carriageSpacing.size() - i - 1 : i); } GlobalStation currentStation = getCurrentStation(); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java index 582910e24..aba766f94 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java @@ -159,7 +159,7 @@ public class TravellingPoint { TrackEdge newEdge = entry.getValue(); Vec3 currentDirection = edge.getDirection(node1, node2, false); Vec3 newDirection = newEdge.getDirection(node2, newNode, true); - if (currentDirection.dot(newDirection) < 0) + if (currentDirection.dot(newDirection) < 3 / 4f) continue; validTargets.add(entry); @@ -197,7 +197,7 @@ public class TravellingPoint { .get(node1); Vec3 currentDirection = edge.getDirection(node1, node2, true); Vec3 newDirection = newEdge.getDirection(newNode, node1, false); - if (currentDirection.dot(newDirection) < 0) + if (currentDirection.dot(newDirection) < 3 / 4f) continue; validTargets.add(entry); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/StationTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/StationTileEntity.java index 23001e88c..5a8492429 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/StationTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/StationTileEntity.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains.management; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -16,7 +17,6 @@ import com.simibubi.create.content.logistics.trains.TrackEdge; import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackNode; import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; -import com.simibubi.create.content.logistics.trains.TrackPropagator; import com.simibubi.create.content.logistics.trains.entity.Carriage; import com.simibubi.create.content.logistics.trains.entity.Carriage.CarriageBogey; import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; @@ -26,7 +26,6 @@ import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Lang; -import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.WorldAttached; import net.minecraft.core.BlockPos; @@ -325,12 +324,15 @@ public class StationTileEntity extends SmartTileEntity { BlockPos bogeyOffset = new BlockPos(track.getUpNormal(level, trackPosition, trackState)); DiscoveredLocation location = null; - List> ends = - TrackPropagator.getEnds(level, trackPosition, trackState, true, null, null); - for (Pair pair : ends) - if (trackPosition.relative(assemblyDirection) - .equals(pair.getFirst())) - location = pair.getSecond(); + Vec3 centre = Vec3.atBottomCenterOf(trackPosition) + .add(0, track.getElevationAtCenter(level, trackPosition, trackState), 0); + Collection ends = track.getConnected(level, trackPosition, trackState, true, null); + Vec3 targetOffset = Vec3.atLowerCornerOf(assemblyDirection.getNormal()); + for (DiscoveredLocation end : ends) + if (Mth.equal(0, targetOffset.distanceToSqr(end.getLocation() + .subtract(centre) + .normalize()))) + location = end; if (location == null) return; @@ -349,13 +351,14 @@ public class StationTileEntity extends SmartTileEntity { TrackGraph graph = null; TrackNode secondNode = null; - for (int i = 0; i < assemblyLength + 20; i++) { + for (int j = 0; j < assemblyLength * 2 + 40; j++) { + double i = j / 2d; if (points.size() == pointOffsets.size()) break; DiscoveredLocation currentLocation = location; location = new DiscoveredLocation(location.getLocation() - .add(directionVec)); + .add(directionVec.scale(.5))); if (graph == null) graph = Create.RAILWAYS.getGraph(level, currentLocation); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java index 3f69c2f8f..72064ea39 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java @@ -99,7 +99,7 @@ public class StandardBogeyBlock extends Block implements IBogeyBlock, ITE getConnected(BlockGetter world, BlockPos pos, BlockState state, + boolean linear, TrackNodeLocation connectedTo) { + Collection list; + + if (getTrackAxes(world, pos, state).size() > 1) { + Vec3 center = Vec3.atBottomCenterOf(pos) + .add(0, getElevationAtCenter(world, pos, state), 0); + TrackShape shape = state.getValue(TrackBlock.SHAPE); + list = new ArrayList<>(); + for (Vec3 axis : getTrackAxes(world, pos, state)) + for (boolean fromCenter : Iterate.trueAndFalse) + ITrackBlock.addToListIfConnected(connectedTo, list, + (d, b) -> axis.scale(b ? 0 : fromCenter ? -d : d) + .add(center), + b -> shape.getNormal(), null); + } else + list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo); + + if (!state.getValue(HAS_TURN)) + return list; + if (linear) + return list; + + BlockEntity blockEntity = world.getBlockEntity(pos); + if (!(blockEntity instanceof TrackTileEntity trackTE)) + return list; + + Map 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, bc)); + return list; } @Override