mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-02-10 12:25:00 +01:00
Getting signals across
- Fixed signaling edge groups not being cleared when a signal migrates graphs - Graphs without any signals now create a fallback group - Fixed removed signals not clearing signal groups of previously affected edges - Signaling sections now use a fixed set of colours - Colours of signaling sections now try to be distinct from neighbouring sections - Colours of signal sections now get synched to the client - Edges now keep track of any intersections with bezier turns that cannot be part of the underlying graph structure - Signaling sections now consider all other intersecting sections when checking whether they are occupied - Holding a signal block now highlights nearby tracks with their respective section colour - Graphs now keep track of a boundary box - Track edges now carry back-references to their nodes - Graph debugger moved from keypress to f3
This commit is contained in:
parent
423bb407f7
commit
3848221712
30 changed files with 1198 additions and 508 deletions
|
@ -57,7 +57,7 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public BezierConnection secondary() {
|
public BezierConnection secondary() {
|
||||||
return new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), false, hasGirder);
|
return new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), !primary, hasGirder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BezierConnection(CompoundTag compound, BlockPos localTo) {
|
public BezierConnection(CompoundTag compound, BlockPos localTo) {
|
||||||
|
|
|
@ -13,23 +13,20 @@ import java.util.UUID;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.apache.commons.lang3.mutable.MutableObject;
|
import org.apache.commons.lang3.mutable.MutableObject;
|
||||||
import org.lwjgl.glfw.GLFW;
|
|
||||||
|
|
||||||
import com.simibubi.create.AllKeys;
|
|
||||||
import com.simibubi.create.CreateClient;
|
import com.simibubi.create.CreateClient;
|
||||||
|
import com.simibubi.create.content.contraptions.KineticDebugger;
|
||||||
import com.simibubi.create.content.logistics.trains.entity.Train;
|
import com.simibubi.create.content.logistics.trains.entity.Train;
|
||||||
import com.simibubi.create.content.logistics.trains.entity.TrainPacket;
|
import com.simibubi.create.content.logistics.trains.entity.TrainPacket;
|
||||||
import com.simibubi.create.content.logistics.trains.management.display.GlobalTrainDisplayData;
|
import com.simibubi.create.content.logistics.trains.management.display.GlobalTrainDisplayData;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
||||||
import com.simibubi.create.foundation.networking.AllPackets;
|
import com.simibubi.create.foundation.networking.AllPackets;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import net.minecraftforge.fml.DistExecutor;
|
import net.minecraftforge.fml.DistExecutor;
|
||||||
|
@ -56,7 +53,14 @@ public class GlobalRailwayManager {
|
||||||
loadTrackData(serverPlayer.getServer());
|
loadTrackData(serverPlayer.getServer());
|
||||||
trackNetworks.values()
|
trackNetworks.values()
|
||||||
.forEach(g -> sync.sendFullGraphTo(g, serverPlayer));
|
.forEach(g -> sync.sendFullGraphTo(g, serverPlayer));
|
||||||
sync.sendEdgeGroups(signalEdgeGroups.keySet(), serverPlayer);
|
ArrayList<SignalEdgeGroup> asList = new ArrayList<>(signalEdgeGroups.values());
|
||||||
|
sync.sendEdgeGroups(asList.stream()
|
||||||
|
.map(g -> g.id)
|
||||||
|
.toList(),
|
||||||
|
asList.stream()
|
||||||
|
.map(g -> g.color)
|
||||||
|
.toList(),
|
||||||
|
serverPlayer);
|
||||||
for (Train train : trains.values())
|
for (Train train : trains.values())
|
||||||
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> serverPlayer),
|
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> serverPlayer),
|
||||||
new TrainPacket(train, true));
|
new TrainPacket(train, true));
|
||||||
|
@ -119,19 +123,32 @@ public class GlobalRailwayManager {
|
||||||
return trackNetworks.computeIfAbsent(graphID, uid -> new TrackGraph(graphID));
|
return trackNetworks.computeIfAbsent(graphID, uid -> new TrackGraph(graphID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void putGraphWithDefaultGroup(TrackGraph graph) {
|
||||||
|
SignalEdgeGroup group = new SignalEdgeGroup(graph.id);
|
||||||
|
signalEdgeGroups.put(graph.id, group);
|
||||||
|
sync.edgeGroupCreated(graph.id, group.color);
|
||||||
|
putGraph(graph);
|
||||||
|
}
|
||||||
|
|
||||||
public void putGraph(TrackGraph graph) {
|
public void putGraph(TrackGraph graph) {
|
||||||
trackNetworks.put(graph.id, graph);
|
trackNetworks.put(graph.id, graph);
|
||||||
markTracksDirty();
|
markTracksDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeGraph(TrackGraph railGraph) {
|
public void removeGraphAndGroup(TrackGraph graph) {
|
||||||
trackNetworks.remove(railGraph.id);
|
signalEdgeGroups.remove(graph.id);
|
||||||
|
sync.edgeGroupRemoved(graph.id);
|
||||||
|
removeGraph(graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeGraph(TrackGraph graph) {
|
||||||
|
trackNetworks.remove(graph.id);
|
||||||
markTracksDirty();
|
markTracksDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSplitGraph(TrackGraph graph) {
|
public void updateSplitGraph(TrackGraph graph) {
|
||||||
Set<TrackGraph> disconnected = graph.findDisconnectedGraphs(null);
|
Set<TrackGraph> disconnected = graph.findDisconnectedGraphs(null);
|
||||||
disconnected.forEach(this::putGraph);
|
disconnected.forEach(this::putGraphWithDefaultGroup);
|
||||||
if (!disconnected.isEmpty()) {
|
if (!disconnected.isEmpty()) {
|
||||||
sync.graphSplit(graph, disconnected);
|
sync.graphSplit(graph, disconnected);
|
||||||
markTracksDirty();
|
markTracksDirty();
|
||||||
|
@ -159,10 +176,7 @@ public class GlobalRailwayManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick(Level level) {
|
public void tick(Level level) {
|
||||||
ResourceLocation location2 = DimensionType.OVERWORLD_LOCATION.location();
|
if (level.dimension() != Level.OVERWORLD)
|
||||||
ResourceLocation location = level.dimension()
|
|
||||||
.location();
|
|
||||||
if (!location.equals(location2))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (SignalEdgeGroup group : signalEdgeGroups.values()) {
|
for (SignalEdgeGroup group : signalEdgeGroups.values()) {
|
||||||
|
@ -170,8 +184,10 @@ public class GlobalRailwayManager {
|
||||||
group.reserved = null;
|
group.reserved = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TrackGraph graph : trackNetworks.values())
|
for (TrackGraph graph : trackNetworks.values()) {
|
||||||
graph.tickPoints(true);
|
graph.tickPoints(true);
|
||||||
|
graph.resolveIntersectingEdgeGroups(level);
|
||||||
|
}
|
||||||
|
|
||||||
tickTrains(level);
|
tickTrains(level);
|
||||||
|
|
||||||
|
@ -182,12 +198,12 @@ public class GlobalRailwayManager {
|
||||||
if (GlobalTrainDisplayData.updateTick)
|
if (GlobalTrainDisplayData.updateTick)
|
||||||
GlobalTrainDisplayData.refresh();
|
GlobalTrainDisplayData.refresh();
|
||||||
|
|
||||||
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_K))
|
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_H) && AllKeys.altDown())
|
||||||
// trackNetworks.values()
|
// for (TrackGraph trackGraph : trackNetworks.values())
|
||||||
// .forEach(TrackGraph::debugViewReserved);
|
// TrackGraphVisualizer.debugViewSignalData(trackGraph);
|
||||||
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown())
|
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown())
|
||||||
// trackNetworks.values()
|
// for (TrackGraph trackGraph : trackNetworks.values())
|
||||||
// .forEach(TrackGraph::debugViewNodes);
|
// TrackGraphVisualizer.debugViewNodes(trackGraph);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tickTrains(Level level) {
|
private void tickTrains(Level level) {
|
||||||
|
@ -218,13 +234,16 @@ public class GlobalRailwayManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void tickSignalOverlay() {
|
||||||
|
if (!KineticDebugger.isActive())
|
||||||
|
for (TrackGraph trackGraph : trackNetworks.values())
|
||||||
|
TrackGraphVisualizer.visualiseSignalEdgeGroups(trackGraph);
|
||||||
|
}
|
||||||
|
|
||||||
public void clientTick() {
|
public void clientTick() {
|
||||||
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_H) && !AllKeys.altDown())
|
if (KineticDebugger.isActive())
|
||||||
trackNetworks.values()
|
for (TrackGraph trackGraph : trackNetworks.values())
|
||||||
.forEach(TrackGraph::debugViewSignalData);
|
TrackGraphVisualizer.debugViewGraph(trackGraph);
|
||||||
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && !AllKeys.altDown())
|
|
||||||
trackNetworks.values()
|
|
||||||
.forEach(TrackGraph::debugViewNodes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlobalRailwayManager sided(LevelAccessor level) {
|
public GlobalRailwayManager sided(LevelAccessor level) {
|
||||||
|
|
|
@ -6,6 +6,8 @@ import java.util.UUID;
|
||||||
|
|
||||||
import com.simibubi.create.Create;
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.content.logistics.trains.entity.Train;
|
import com.simibubi.create.content.logistics.trains.entity.Train;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
||||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
|
|
||||||
|
@ -37,6 +39,7 @@ public class RailwaySavedData extends SavedData {
|
||||||
sd.signalEdgeGroups = new HashMap<>();
|
sd.signalEdgeGroups = new HashMap<>();
|
||||||
sd.trains = new HashMap<>();
|
sd.trains = new HashMap<>();
|
||||||
Create.LOGGER.info("Loading Railway Information...");
|
Create.LOGGER.info("Loading Railway Information...");
|
||||||
|
|
||||||
NBTHelper.iterateCompoundList(nbt.getList("RailGraphs", Tag.TAG_COMPOUND), c -> {
|
NBTHelper.iterateCompoundList(nbt.getList("RailGraphs", Tag.TAG_COMPOUND), c -> {
|
||||||
TrackGraph graph = TrackGraph.read(c);
|
TrackGraph graph = TrackGraph.read(c);
|
||||||
sd.trackNetworks.put(graph.id, graph);
|
sd.trackNetworks.put(graph.id, graph);
|
||||||
|
@ -49,6 +52,22 @@ public class RailwaySavedData extends SavedData {
|
||||||
SignalEdgeGroup group = SignalEdgeGroup.read(c);
|
SignalEdgeGroup group = SignalEdgeGroup.read(c);
|
||||||
sd.signalEdgeGroups.put(group.id, group);
|
sd.signalEdgeGroups.put(group.id, group);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (TrackGraph graph : sd.trackNetworks.values()) {
|
||||||
|
for (SignalBoundary signal : graph.getPoints(EdgePointType.SIGNAL)) {
|
||||||
|
UUID groupId = signal.groups.getFirst();
|
||||||
|
UUID otherGroupId = signal.groups.getSecond();
|
||||||
|
if (groupId == null || otherGroupId == null)
|
||||||
|
continue;
|
||||||
|
SignalEdgeGroup group = sd.signalEdgeGroups.get(groupId);
|
||||||
|
SignalEdgeGroup otherGroup = sd.signalEdgeGroups.get(otherGroupId);
|
||||||
|
if (group == null || otherGroup == null)
|
||||||
|
continue;
|
||||||
|
group.putAdjacent(otherGroupId);
|
||||||
|
otherGroup.putAdjacent(groupId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return sd;
|
return sd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,33 @@
|
||||||
package com.simibubi.create.content.logistics.trains;
|
package com.simibubi.create.content.logistics.trains;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData;
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction.Axis;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public class TrackEdge {
|
public class TrackEdge {
|
||||||
|
|
||||||
|
public TrackNode node1;
|
||||||
|
public TrackNode node2;
|
||||||
BezierConnection turn;
|
BezierConnection turn;
|
||||||
EdgeData edgeData;
|
EdgeData edgeData;
|
||||||
|
|
||||||
public TrackEdge(BezierConnection turn) {
|
public TrackEdge(TrackNode node1, TrackNode node2, BezierConnection turn) {
|
||||||
|
this.edgeData = new EdgeData(this);
|
||||||
|
this.node1 = node1;
|
||||||
|
this.node2 = node2;
|
||||||
this.turn = turn;
|
this.turn = turn;
|
||||||
this.edgeData = new EdgeData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTurn() {
|
public boolean isTurn() {
|
||||||
|
@ -31,29 +42,112 @@ public class TrackEdge {
|
||||||
return turn;
|
return turn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3 getDirection(TrackNode node1, TrackNode node2, boolean fromFirst) {
|
public Vec3 getDirection(boolean fromFirst) {
|
||||||
return getPosition(node1, node2, fromFirst ? 0.25f : 1)
|
return getPosition(fromFirst ? 0.25f : 1).subtract(getPosition(fromFirst ? 0 : 0.75f))
|
||||||
.subtract(getPosition(node1, node2, fromFirst ? 0 : 0.75f))
|
|
||||||
.normalize();
|
.normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getLength(TrackNode node1, TrackNode node2) {
|
public double getLength() {
|
||||||
return isTurn() ? turn.getLength()
|
return isTurn() ? turn.getLength()
|
||||||
: node1.location.getLocation()
|
: node1.location.getLocation()
|
||||||
.distanceTo(node2.location.getLocation());
|
.distanceTo(node2.location.getLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
public double incrementT(TrackNode node1, TrackNode node2, double currentT, double distance) {
|
public double incrementT(double currentT, double distance) {
|
||||||
boolean tooFar = Math.abs(distance) > 5;
|
boolean tooFar = Math.abs(distance) > 5;
|
||||||
distance = distance / getLength(node1, node2);
|
distance = distance / getLength();
|
||||||
return !tooFar && isTurn() ? turn.incrementT(currentT, distance) : currentT + distance;
|
return !tooFar && isTurn() ? turn.incrementT(currentT, distance) : currentT + distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3 getPosition(TrackNode node1, TrackNode node2, double t) {
|
public Vec3 getPosition(double t) {
|
||||||
return isTurn() ? turn.getPosition(Mth.clamp(t, 0, 1))
|
return isTurn() ? turn.getPosition(Mth.clamp(t, 0, 1))
|
||||||
: VecHelper.lerp((float) t, node1.location.getLocation(), node2.location.getLocation());
|
: VecHelper.lerp((float) t, node1.location.getLocation(), node2.location.getLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<double[]> getIntersection(TrackNode node1, TrackNode node2, TrackEdge other, TrackNode other1,
|
||||||
|
TrackNode other2) {
|
||||||
|
Vec3 v1 = node1.location.getLocation();
|
||||||
|
Vec3 v2 = node2.location.getLocation();
|
||||||
|
Vec3 w1 = other1.location.getLocation();
|
||||||
|
Vec3 w2 = other2.location.getLocation();
|
||||||
|
|
||||||
|
if (v1.y != v2.y || v1.y != w1.y || v1.y != w2.y)
|
||||||
|
return Collections.emptyList();
|
||||||
|
|
||||||
|
if (!isTurn()) {
|
||||||
|
if (!other.isTurn())
|
||||||
|
return ImmutableList.of(VecHelper.intersectRanged(v1, w1, v2, w2, Axis.Y));
|
||||||
|
return other.getIntersection(other1, other2, this, node1, node2)
|
||||||
|
.stream()
|
||||||
|
.map(a -> new double[] { a[1], a[0] })
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB bb = turn.getBounds();
|
||||||
|
|
||||||
|
if (!other.isTurn()) {
|
||||||
|
if (!bb.intersects(w1, w2))
|
||||||
|
return Collections.emptyList();
|
||||||
|
|
||||||
|
Vec3 seg1 = v1;
|
||||||
|
Vec3 seg2 = null;
|
||||||
|
double t = 0;
|
||||||
|
|
||||||
|
Collection<double[]> intersections = new ArrayList<>();
|
||||||
|
for (int i = 0; i < turn.getSegmentCount(); i++) {
|
||||||
|
double tOffset = t;
|
||||||
|
t += .5;
|
||||||
|
seg2 = getPosition(t / getLength());
|
||||||
|
double[] intersection = VecHelper.intersectRanged(seg1, w1, seg2, w2, Axis.Y);
|
||||||
|
seg1 = seg2;
|
||||||
|
if (intersection == null)
|
||||||
|
continue;
|
||||||
|
intersection[0] += tOffset;
|
||||||
|
intersections.add(intersection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersections;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bb.intersects(other.turn.getBounds()))
|
||||||
|
return Collections.emptyList();
|
||||||
|
|
||||||
|
Vec3 seg1 = v1;
|
||||||
|
Vec3 seg2 = null;
|
||||||
|
double t = 0;
|
||||||
|
|
||||||
|
Collection<double[]> intersections = new ArrayList<>();
|
||||||
|
for (int i = 0; i < turn.getSegmentCount(); i++) {
|
||||||
|
double tOffset = t;
|
||||||
|
t += .5;
|
||||||
|
seg2 = getPosition(t / getLength());
|
||||||
|
|
||||||
|
Vec3 otherSeg1 = w1;
|
||||||
|
Vec3 otherSeg2 = null;
|
||||||
|
double u = 0;
|
||||||
|
|
||||||
|
for (int j = 0; j < other.turn.getSegmentCount(); j++) {
|
||||||
|
double uOffset = u;
|
||||||
|
u += .5;
|
||||||
|
otherSeg2 = other.getPosition(u / other.getLength());
|
||||||
|
|
||||||
|
double[] intersection = VecHelper.intersectRanged(seg1, otherSeg1, seg2, otherSeg2, Axis.Y);
|
||||||
|
otherSeg1 = otherSeg2;
|
||||||
|
|
||||||
|
if (intersection == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
intersection[0] += tOffset;
|
||||||
|
intersection[1] += uOffset;
|
||||||
|
intersections.add(intersection);
|
||||||
|
}
|
||||||
|
|
||||||
|
seg1 = seg2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersections;
|
||||||
|
}
|
||||||
|
|
||||||
public Vec3 getNormal(TrackNode node1, TrackNode node2, double t) {
|
public Vec3 getNormal(TrackNode node1, TrackNode node2, double t) {
|
||||||
return isTurn() ? turn.getNormal(Mth.clamp(t, 0, 1)) : node1.getNormal();
|
return isTurn() ? turn.getNormal(Mth.clamp(t, 0, 1)) : node1.getNormal();
|
||||||
}
|
}
|
||||||
|
@ -65,7 +159,7 @@ public class TrackEdge {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TrackEdge read(FriendlyByteBuf buffer) {
|
public static TrackEdge read(FriendlyByteBuf buffer) {
|
||||||
return new TrackEdge(buffer.readBoolean() ? new BezierConnection(buffer) : null);
|
return new TrackEdge(null, null, buffer.readBoolean() ? new BezierConnection(buffer) : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompoundTag write() {
|
public CompoundTag write() {
|
||||||
|
@ -76,8 +170,8 @@ public class TrackEdge {
|
||||||
|
|
||||||
public static TrackEdge read(CompoundTag tag, TrackGraph graph) {
|
public static TrackEdge read(CompoundTag tag, TrackGraph graph) {
|
||||||
TrackEdge trackEdge =
|
TrackEdge trackEdge =
|
||||||
new TrackEdge(tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null);
|
new TrackEdge(null, null, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null);
|
||||||
trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), graph);
|
trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), trackEdge, graph);
|
||||||
return trackEdge;
|
return trackEdge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,34 +16,28 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
|
||||||
|
|
||||||
import com.simibubi.create.AllKeys;
|
|
||||||
import com.simibubi.create.Create;
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.CreateClient;
|
|
||||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation;
|
import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation;
|
||||||
import com.simibubi.create.content.logistics.trains.entity.Train;
|
import com.simibubi.create.content.logistics.trains.entity.Train;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointManager;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointManager;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointStorage;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointStorage;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackEdgeIntersection;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation;
|
|
||||||
import com.simibubi.create.foundation.utility.Color;
|
import com.simibubi.create.foundation.utility.Color;
|
||||||
import com.simibubi.create.foundation.utility.Couple;
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
import com.simibubi.create.foundation.utility.Pair;
|
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.ListTag;
|
import net.minecraft.nbt.ListTag;
|
||||||
import net.minecraft.nbt.NbtUtils;
|
import net.minecraft.nbt.NbtUtils;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
@ -58,6 +52,9 @@ public class TrackGraph {
|
||||||
Map<Integer, TrackNode> nodesById;
|
Map<Integer, TrackNode> nodesById;
|
||||||
Map<TrackNode, Map<TrackNode, TrackEdge>> connectionsByNode;
|
Map<TrackNode, Map<TrackNode, TrackEdge>> connectionsByNode;
|
||||||
EdgePointStorage edgePoints;
|
EdgePointStorage edgePoints;
|
||||||
|
Map<ResourceKey<Level>, TrackGraphBounds> bounds;
|
||||||
|
|
||||||
|
List<TrackEdge> deferredIntersectionUpdates;
|
||||||
|
|
||||||
public TrackGraph() {
|
public TrackGraph() {
|
||||||
this(UUID.randomUUID());
|
this(UUID.randomUUID());
|
||||||
|
@ -67,8 +64,10 @@ public class TrackGraph {
|
||||||
setId(graphID);
|
setId(graphID);
|
||||||
nodes = new HashMap<>();
|
nodes = new HashMap<>();
|
||||||
nodesById = new HashMap<>();
|
nodesById = new HashMap<>();
|
||||||
|
bounds = new HashMap<>();
|
||||||
connectionsByNode = new IdentityHashMap<>();
|
connectionsByNode = new IdentityHashMap<>();
|
||||||
edgePoints = new EdgePointStorage();
|
edgePoints = new EdgePointStorage();
|
||||||
|
deferredIntersectionUpdates = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -104,6 +103,16 @@ public class TrackGraph {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
public TrackGraphBounds getBounds(Level level) {
|
||||||
|
return bounds.computeIfAbsent(level.dimension(), dim -> new TrackGraphBounds(this, dim));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidateBounds() {
|
||||||
|
bounds.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
public Set<TrackNodeLocation> getNodes() {
|
public Set<TrackNodeLocation> getNodes() {
|
||||||
return nodes.keySet();
|
return nodes.keySet();
|
||||||
}
|
}
|
||||||
|
@ -125,6 +134,7 @@ public class TrackGraph {
|
||||||
return false;
|
return false;
|
||||||
TrackNode newNode = nodes.get(location);
|
TrackNode newNode = nodes.get(location);
|
||||||
Create.RAILWAYS.sync.nodeAdded(this, newNode);
|
Create.RAILWAYS.sync.nodeAdded(this, newNode);
|
||||||
|
invalidateBounds();
|
||||||
markDirty();
|
markDirty();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -165,17 +175,30 @@ public class TrackGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
nodesById.remove(removed.netId);
|
nodesById.remove(removed.netId);
|
||||||
|
invalidateBounds();
|
||||||
|
|
||||||
if (!connectionsByNode.containsKey(removed))
|
if (!connectionsByNode.containsKey(removed))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Map<TrackNode, TrackEdge> connections = connectionsByNode.remove(removed);
|
Map<TrackNode, TrackEdge> connections = connectionsByNode.remove(removed);
|
||||||
for (TrackEdge trackEdge : connections.values())
|
for (Entry<TrackNode, TrackEdge> entry : connections.entrySet()) {
|
||||||
for (TrackEdgePoint point : trackEdge.getEdgeData()
|
TrackEdge trackEdge = entry.getValue();
|
||||||
.getPoints()) {
|
EdgeData edgeData = trackEdge.getEdgeData();
|
||||||
|
for (TrackEdgePoint point : edgeData.getPoints()) {
|
||||||
if (level != null)
|
if (level != null)
|
||||||
point.invalidate(level);
|
point.invalidate(level);
|
||||||
edgePoints.remove(point.getType(), point.getId());
|
edgePoints.remove(point.getType(), point.getId());
|
||||||
}
|
}
|
||||||
|
if (level != null) {
|
||||||
|
TrackNode otherNode = entry.getKey();
|
||||||
|
for (TrackEdgeIntersection intersection : edgeData.getIntersections()) {
|
||||||
|
Couple<TrackNodeLocation> target = intersection.target;
|
||||||
|
TrackGraph graph = Create.RAILWAYS.getGraph(level, target.getFirst());
|
||||||
|
if (graph != null)
|
||||||
|
graph.removeIntersection(intersection, removed, otherNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (TrackNode railNode : connections.keySet())
|
for (TrackNode railNode : connections.keySet())
|
||||||
if (connectionsByNode.containsKey(railNode))
|
if (connectionsByNode.containsKey(railNode))
|
||||||
|
@ -185,6 +208,29 @@ public class TrackGraph {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeIntersection(TrackEdgeIntersection intersection, TrackNode targetNode1, TrackNode targetNode2) {
|
||||||
|
TrackNode node1 = locateNode(intersection.target.getFirst());
|
||||||
|
TrackNode node2 = locateNode(intersection.target.getSecond());
|
||||||
|
if (node1 == null || node2 == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Map<TrackNode, TrackEdge> from1 = getConnectionsFrom(node1);
|
||||||
|
if (from1 != null) {
|
||||||
|
TrackEdge edge = from1.get(node2);
|
||||||
|
if (edge != null)
|
||||||
|
edge.getEdgeData()
|
||||||
|
.removeIntersection(this, intersection.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<TrackNode, TrackEdge> from2 = getConnectionsFrom(node2);
|
||||||
|
if (from2 != null) {
|
||||||
|
TrackEdge edge = from2.get(node1);
|
||||||
|
if (edge != null)
|
||||||
|
edge.getEdgeData()
|
||||||
|
.removeIntersection(this, intersection.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static int nextNodeId() {
|
public static int nextNodeId() {
|
||||||
return netIdGenerator.incrementAndGet();
|
return netIdGenerator.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
@ -209,6 +255,7 @@ public class TrackGraph {
|
||||||
edgePoints.transferAll(toOther, toOther.edgePoints);
|
edgePoints.transferAll(toOther, toOther.edgePoints);
|
||||||
nodes.clear();
|
nodes.clear();
|
||||||
connectionsByNode.clear();
|
connectionsByNode.clear();
|
||||||
|
toOther.invalidateBounds();
|
||||||
|
|
||||||
Map<UUID, Train> trains = Create.RAILWAYS.trains;
|
Map<UUID, Train> trains = Create.RAILWAYS.trains;
|
||||||
for (Iterator<UUID> iterator = trains.keySet()
|
for (Iterator<UUID> iterator = trains.keySet()
|
||||||
|
@ -268,6 +315,7 @@ public class TrackGraph {
|
||||||
|
|
||||||
public void transfer(TrackNode node, TrackGraph target) {
|
public void transfer(TrackNode node, TrackGraph target) {
|
||||||
target.addNode(node);
|
target.addNode(node);
|
||||||
|
target.invalidateBounds();
|
||||||
|
|
||||||
TrackNodeLocation nodeLoc = node.getLocation();
|
TrackNodeLocation nodeLoc = node.getLocation();
|
||||||
Map<TrackNode, TrackEdge> connections = getConnectionsFrom(node);
|
Map<TrackNode, TrackEdge> connections = getConnectionsFrom(node);
|
||||||
|
@ -298,6 +346,7 @@ public class TrackGraph {
|
||||||
nodes.remove(nodeLoc);
|
nodes.remove(nodeLoc);
|
||||||
nodesById.remove(node.getNetId());
|
nodesById.remove(node.getNetId());
|
||||||
connectionsByNode.remove(node);
|
connectionsByNode.remove(node);
|
||||||
|
invalidateBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
|
@ -312,16 +361,66 @@ public class TrackGraph {
|
||||||
return getConnectionsFrom(nodes.getFirst()).get(nodes.getSecond());
|
return getConnectionsFrom(nodes.getFirst()).get(nodes.getSecond());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connectNodes(TrackNodeLocation location, TrackNodeLocation location2, TrackEdge edge) {
|
public void connectNodes(LevelAccessor reader, TrackNodeLocation location, TrackNodeLocation location2,
|
||||||
|
@Nullable BezierConnection turn) {
|
||||||
TrackNode node1 = nodes.get(location);
|
TrackNode node1 = nodes.get(location);
|
||||||
TrackNode node2 = nodes.get(location2);
|
TrackNode node2 = nodes.get(location2);
|
||||||
TrackEdge edge2 = new TrackEdge(edge.turn != null ? edge.turn.secondary() : null);
|
|
||||||
|
boolean bezier = turn != null;
|
||||||
|
TrackEdge edge = new TrackEdge(node1, node2, turn);
|
||||||
|
TrackEdge edge2 = new TrackEdge(node2, node1, bezier ? turn.secondary() : null);
|
||||||
|
|
||||||
|
if (reader instanceof Level level) {
|
||||||
|
for (TrackGraph graph : Create.RAILWAYS.trackNetworks.values()) {
|
||||||
|
if (graph != this
|
||||||
|
&& !graph.getBounds(level).box.intersects(location.getLocation(), location2.getLocation()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (TrackNode otherNode1 : graph.nodes.values()) {
|
||||||
|
Map<TrackNode, TrackEdge> connections = graph.connectionsByNode.get(otherNode1);
|
||||||
|
if (connections == null)
|
||||||
|
continue;
|
||||||
|
for (Entry<TrackNode, TrackEdge> entry : connections.entrySet()) {
|
||||||
|
TrackNode otherNode2 = entry.getKey();
|
||||||
|
TrackEdge otherEdge = entry.getValue();
|
||||||
|
|
||||||
|
if (graph == this)
|
||||||
|
if (otherNode1 == node1 || otherNode2 == node1 || otherNode1 == node2
|
||||||
|
|| otherNode2 == node2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (edge == otherEdge)
|
||||||
|
continue;
|
||||||
|
if (!bezier && !otherEdge.isTurn())
|
||||||
|
continue;
|
||||||
|
if (otherEdge.isTurn() && otherEdge.turn.isPrimary())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Collection<double[]> intersections =
|
||||||
|
edge.getIntersection(node1, node2, otherEdge, otherNode1, otherNode2);
|
||||||
|
|
||||||
|
UUID id = UUID.randomUUID();
|
||||||
|
for (double[] intersection : intersections) {
|
||||||
|
double s = intersection[0];
|
||||||
|
double t = intersection[1];
|
||||||
|
edge.edgeData.addIntersection(this, id, s, otherNode1, otherNode2, t);
|
||||||
|
edge2.edgeData.addIntersection(this, id, edge.getLength() - s, otherNode1, otherNode2, t);
|
||||||
|
otherEdge.edgeData.addIntersection(graph, id, t, node1, node2, s);
|
||||||
|
TrackEdge otherEdge2 = graph.getConnection(Couple.create(otherNode2, otherNode1));
|
||||||
|
if (otherEdge2 != null)
|
||||||
|
otherEdge2.edgeData.addIntersection(graph, id, otherEdge.getLength() - t, node1, node2,
|
||||||
|
s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
putConnection(node1, node2, edge);
|
putConnection(node1, node2, edge);
|
||||||
putConnection(node2, node1, edge2);
|
putConnection(node2, node1, edge2);
|
||||||
|
|
||||||
Create.RAILWAYS.sync.edgeAdded(this, node1, node2, edge);
|
Create.RAILWAYS.sync.edgeAdded(this, node1, node2, edge);
|
||||||
Create.RAILWAYS.sync.edgeAdded(this, node2, node1, edge2);
|
Create.RAILWAYS.sync.edgeAdded(this, node2, node1, edge2);
|
||||||
|
|
||||||
markDirty();
|
markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,6 +442,47 @@ public class TrackGraph {
|
||||||
return connections.put(node2, edge) == null;
|
return connections.put(node2, edge) == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deferIntersectionUpdate(TrackEdge edge) {
|
||||||
|
deferredIntersectionUpdates.add(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resolveIntersectingEdgeGroups(Level level) {
|
||||||
|
for (TrackEdge edge : deferredIntersectionUpdates) {
|
||||||
|
if (!connectionsByNode.containsKey(edge.node1) || edge != connectionsByNode.get(edge.node1)
|
||||||
|
.get(edge.node2))
|
||||||
|
continue;
|
||||||
|
EdgeData edgeData = edge.getEdgeData();
|
||||||
|
for (TrackEdgeIntersection intersection : edgeData.getIntersections()) {
|
||||||
|
UUID groupId = edgeData.getGroupAtPosition(this, intersection.location);
|
||||||
|
Couple<TrackNodeLocation> target = intersection.target;
|
||||||
|
TrackGraph graph = Create.RAILWAYS.getGraph(level, target.getFirst());
|
||||||
|
if (graph == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TrackNode node1 = graph.locateNode(target.getFirst());
|
||||||
|
TrackNode node2 = graph.locateNode(target.getSecond());
|
||||||
|
Map<TrackNode, TrackEdge> connectionsFrom = graph.getConnectionsFrom(node1);
|
||||||
|
if (connectionsFrom == null)
|
||||||
|
continue;
|
||||||
|
TrackEdge otherEdge = connectionsFrom.get(node2);
|
||||||
|
if (otherEdge == null)
|
||||||
|
continue;
|
||||||
|
UUID otherGroupId = otherEdge.getEdgeData()
|
||||||
|
.getGroupAtPosition(graph, intersection.targetLocation);
|
||||||
|
|
||||||
|
SignalEdgeGroup group = Create.RAILWAYS.signalEdgeGroups.get(groupId);
|
||||||
|
SignalEdgeGroup otherGroup = Create.RAILWAYS.signalEdgeGroups.get(otherGroupId);
|
||||||
|
if (group == null || otherGroup == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
intersection.groupId = groupId;
|
||||||
|
group.putIntersection(intersection.id, otherGroupId);
|
||||||
|
otherGroup.putIntersection(intersection.id, groupId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deferredIntersectionUpdates.clear();
|
||||||
|
}
|
||||||
|
|
||||||
public void markDirty() {
|
public void markDirty() {
|
||||||
Create.RAILWAYS.markTracksDirty();
|
Create.RAILWAYS.markTracksDirty();
|
||||||
}
|
}
|
||||||
|
@ -418,6 +558,8 @@ public class TrackGraph {
|
||||||
NBTHelper.iterateCompoundList(nodeTag.getList("Connections", Tag.TAG_COMPOUND), c -> {
|
NBTHelper.iterateCompoundList(nodeTag.getList("Connections", Tag.TAG_COMPOUND), c -> {
|
||||||
TrackNode node2 = indexTracker.get(c.getInt("To"));
|
TrackNode node2 = indexTracker.get(c.getInt("To"));
|
||||||
TrackEdge edge = TrackEdge.read(c.getCompound("EdgeData"), graph);
|
TrackEdge edge = TrackEdge.read(c.getCompound("EdgeData"), graph);
|
||||||
|
edge.node1 = node1;
|
||||||
|
edge.node2 = node2;
|
||||||
graph.putConnection(node1, node2, edge);
|
graph.putConnection(node1, node2, edge);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -425,300 +567,4 @@ public class TrackGraph {
|
||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void debugViewReserved() {
|
|
||||||
Entity cameraEntity = Minecraft.getInstance().cameraEntity;
|
|
||||||
if (cameraEntity == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Set<UUID> reserved = new HashSet<>();
|
|
||||||
Set<UUID> occupied = new HashSet<>();
|
|
||||||
|
|
||||||
for (Train train : Create.RAILWAYS.trains.values()) {
|
|
||||||
reserved.addAll(train.reservedSignalBlocks);
|
|
||||||
occupied.addAll(train.occupiedSignalBlocks.keySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
reserved.removeAll(occupied);
|
|
||||||
|
|
||||||
Vec3 camera = cameraEntity.getEyePosition();
|
|
||||||
for (Entry<TrackNodeLocation, TrackNode> nodeEntry : nodes.entrySet()) {
|
|
||||||
TrackNodeLocation nodeLocation = nodeEntry.getKey();
|
|
||||||
TrackNode node = nodeEntry.getValue();
|
|
||||||
if (nodeLocation == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Vec3 location = nodeLocation.getLocation();
|
|
||||||
if (location.distanceTo(camera) > 100)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Map<TrackNode, TrackEdge> map = connectionsByNode.get(node);
|
|
||||||
if (map == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int hashCode = node.hashCode();
|
|
||||||
for (Entry<TrackNode, TrackEdge> entry : map.entrySet()) {
|
|
||||||
TrackNode other = entry.getKey();
|
|
||||||
|
|
||||||
if (other.hashCode() > hashCode && !AllKeys.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL))
|
|
||||||
continue;
|
|
||||||
Vec3 yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0);
|
|
||||||
|
|
||||||
TrackEdge edge = entry.getValue();
|
|
||||||
EdgeData signalData = edge.getEdgeData();
|
|
||||||
UUID singleGroup = signalData.singleSignalGroup;
|
|
||||||
SignalEdgeGroup signalEdgeGroup =
|
|
||||||
singleGroup == null ? null : Create.RAILWAYS.sided(null).signalEdgeGroups.get(singleGroup);
|
|
||||||
|
|
||||||
if (!edge.isTurn()) {
|
|
||||||
Vec3 p1 = edge.getPosition(node, other, 0);
|
|
||||||
Vec3 p2 = edge.getPosition(node, other, 1);
|
|
||||||
|
|
||||||
if (signalData.hasPoints()) {
|
|
||||||
double prev = 0;
|
|
||||||
double length = edge.getLength(node, other);
|
|
||||||
SignalBoundary prevBoundary = null;
|
|
||||||
SignalEdgeGroup group = null;
|
|
||||||
|
|
||||||
for (TrackEdgePoint trackEdgePoint : signalData.getPoints()) {
|
|
||||||
if (!(trackEdgePoint instanceof SignalBoundary boundary))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
prevBoundary = boundary;
|
|
||||||
UUID groupId = boundary.getGroup(node);
|
|
||||||
group = Create.RAILWAYS.sided(null).signalEdgeGroups.get(groupId);
|
|
||||||
double start = prev + (prev == 0 ? 0 : 1 / 16f / length);
|
|
||||||
prev = (boundary.getLocationOn(node, other, edge) / length) - 1 / 16f / length;
|
|
||||||
|
|
||||||
if (group != null
|
|
||||||
&& (group.reserved != null || occupied.contains(groupId) || reserved.contains(groupId)))
|
|
||||||
CreateClient.OUTLINER
|
|
||||||
.showLine(Pair.of(boundary, edge), edge.getPosition(node, other, start)
|
|
||||||
.add(yOffset),
|
|
||||||
edge.getPosition(node, other, prev)
|
|
||||||
.add(yOffset))
|
|
||||||
.colored(occupied.contains(groupId) ? 0xF68989
|
|
||||||
: group.reserved != null ? 0xC5D8A4 : 0xF6E7D8)
|
|
||||||
.lineWidth(1 / 16f);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prevBoundary != null) {
|
|
||||||
UUID groupId = prevBoundary.getGroup(other);
|
|
||||||
SignalEdgeGroup lastGroup = Create.RAILWAYS.sided(null).signalEdgeGroups.get(groupId);
|
|
||||||
if (lastGroup != null && ((lastGroup.reserved != null || occupied.contains(groupId)
|
|
||||||
|| reserved.contains(groupId))))
|
|
||||||
CreateClient.OUTLINER
|
|
||||||
.showLine(edge, edge.getPosition(node, other, prev + 1 / 16f / length)
|
|
||||||
.add(yOffset), p2.add(yOffset))
|
|
||||||
.colored(occupied.contains(groupId) ? 0xF68989
|
|
||||||
: lastGroup.reserved != null ? 0xC5D8A4 : 0xF6E7D8)
|
|
||||||
.lineWidth(1 / 16f);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signalEdgeGroup == null || !(signalEdgeGroup.reserved != null || occupied.contains(singleGroup)
|
|
||||||
|| reserved.contains(singleGroup)))
|
|
||||||
continue;
|
|
||||||
CreateClient.OUTLINER.showLine(edge, p1.add(yOffset), p2.add(yOffset))
|
|
||||||
.colored(occupied.contains(singleGroup) ? 0xF68989
|
|
||||||
: signalEdgeGroup.reserved != null ? 0xC5D8A4 : 0xF6E7D8)
|
|
||||||
.lineWidth(1 / 16f);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signalEdgeGroup == null || !(signalEdgeGroup.reserved != null || occupied.contains(singleGroup)
|
|
||||||
|| reserved.contains(singleGroup)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int color =
|
|
||||||
occupied.contains(singleGroup) ? 0xF68989 : signalEdgeGroup.reserved != null ? 0xC5D8A4 : 0xF6E7D8;
|
|
||||||
Vec3 previous = null;
|
|
||||||
BezierConnection turn = edge.getTurn();
|
|
||||||
for (int i = 0; i <= turn.getSegmentCount(); i++) {
|
|
||||||
Vec3 current = edge.getPosition(node, other, i * 1f / turn.getSegmentCount());
|
|
||||||
if (previous != null)
|
|
||||||
CreateClient.OUTLINER
|
|
||||||
.showLine(Pair.of(edge, previous), previous.add(yOffset), current.add(yOffset))
|
|
||||||
.colored(color)
|
|
||||||
.lineWidth(1 / 16f);
|
|
||||||
previous = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void debugViewSignalData() {
|
|
||||||
Entity cameraEntity = Minecraft.getInstance().cameraEntity;
|
|
||||||
if (cameraEntity == null)
|
|
||||||
return;
|
|
||||||
Vec3 camera = cameraEntity.getEyePosition();
|
|
||||||
for (Entry<TrackNodeLocation, TrackNode> nodeEntry : nodes.entrySet()) {
|
|
||||||
TrackNodeLocation nodeLocation = nodeEntry.getKey();
|
|
||||||
TrackNode node = nodeEntry.getValue();
|
|
||||||
if (nodeLocation == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Vec3 location = nodeLocation.getLocation();
|
|
||||||
if (location.distanceTo(camera) > 50)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Map<TrackNode, TrackEdge> map = connectionsByNode.get(node);
|
|
||||||
if (map == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int hashCode = node.hashCode();
|
|
||||||
for (Entry<TrackNode, TrackEdge> entry : map.entrySet()) {
|
|
||||||
TrackNode other = entry.getKey();
|
|
||||||
|
|
||||||
if (other.hashCode() > hashCode && !AllKeys.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL))
|
|
||||||
continue;
|
|
||||||
Vec3 yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0);
|
|
||||||
|
|
||||||
TrackEdge edge = entry.getValue();
|
|
||||||
EdgeData signalData = edge.getEdgeData();
|
|
||||||
UUID singleGroup = signalData.singleSignalGroup;
|
|
||||||
SignalEdgeGroup signalEdgeGroup =
|
|
||||||
singleGroup == null ? null : Create.RAILWAYS.sided(null).signalEdgeGroups.get(singleGroup);
|
|
||||||
|
|
||||||
if (!edge.isTurn()) {
|
|
||||||
Vec3 p1 = edge.getPosition(node, other, 0);
|
|
||||||
Vec3 p2 = edge.getPosition(node, other, 1);
|
|
||||||
|
|
||||||
if (signalData.hasPoints()) {
|
|
||||||
double prev = 0;
|
|
||||||
double length = edge.getLength(node, other);
|
|
||||||
SignalBoundary prevBoundary = null;
|
|
||||||
SignalEdgeGroup group = null;
|
|
||||||
|
|
||||||
for (TrackEdgePoint trackEdgePoint : signalData.getPoints()) {
|
|
||||||
if (trackEdgePoint instanceof GlobalStation) {
|
|
||||||
Vec3 v1 = edge
|
|
||||||
.getPosition(node, other,
|
|
||||||
(trackEdgePoint.getLocationOn(node, other, edge) / length))
|
|
||||||
.add(yOffset);
|
|
||||||
Vec3 v2 = v1.add(node.normal.scale(3 / 16f));
|
|
||||||
CreateClient.OUTLINER.showLine(trackEdgePoint.id, v1, v2)
|
|
||||||
.colored(Color.mixColors(Color.WHITE, color, 1))
|
|
||||||
.lineWidth(1 / 8f);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!(trackEdgePoint instanceof SignalBoundary boundary))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
prevBoundary = boundary;
|
|
||||||
group = Create.RAILWAYS.sided(null).signalEdgeGroups.get(boundary.getGroup(node));
|
|
||||||
|
|
||||||
if (group != null)
|
|
||||||
CreateClient.OUTLINER
|
|
||||||
.showLine(Pair.of(boundary, edge),
|
|
||||||
edge.getPosition(node, other, prev + (prev == 0 ? 0 : 1 / 16f / length))
|
|
||||||
.add(yOffset),
|
|
||||||
edge.getPosition(node, other,
|
|
||||||
(prev = boundary.getLocationOn(node, other, edge) / length)
|
|
||||||
- 1 / 16f / length)
|
|
||||||
.add(yOffset))
|
|
||||||
.colored(group.color.getRGB())
|
|
||||||
.lineWidth(1 / 16f);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prevBoundary != null) {
|
|
||||||
group = Create.RAILWAYS.sided(null).signalEdgeGroups.get(prevBoundary.getGroup(other));
|
|
||||||
if (group != null)
|
|
||||||
CreateClient.OUTLINER
|
|
||||||
.showLine(edge, edge.getPosition(node, other, prev + 1 / 16f / length)
|
|
||||||
.add(yOffset), p2.add(yOffset))
|
|
||||||
.colored(group.color.getRGB())
|
|
||||||
.lineWidth(1 / 16f);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signalEdgeGroup == null)
|
|
||||||
continue;
|
|
||||||
CreateClient.OUTLINER.showLine(edge, p1.add(yOffset), p2.add(yOffset))
|
|
||||||
.colored(signalEdgeGroup.color.getRGB())
|
|
||||||
.lineWidth(1 / 16f);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signalEdgeGroup == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Vec3 previous = null;
|
|
||||||
BezierConnection turn = edge.getTurn();
|
|
||||||
for (int i = 0; i <= turn.getSegmentCount(); i++) {
|
|
||||||
Vec3 current = edge.getPosition(node, other, i * 1f / turn.getSegmentCount());
|
|
||||||
if (previous != null)
|
|
||||||
CreateClient.OUTLINER
|
|
||||||
.showLine(Pair.of(edge, previous), previous.add(yOffset), current.add(yOffset))
|
|
||||||
.colored(signalEdgeGroup.color.getRGB())
|
|
||||||
.lineWidth(1 / 16f);
|
|
||||||
previous = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void debugViewNodes() {
|
|
||||||
Entity cameraEntity = Minecraft.getInstance().cameraEntity;
|
|
||||||
if (cameraEntity == null)
|
|
||||||
return;
|
|
||||||
Vec3 camera = cameraEntity.getEyePosition();
|
|
||||||
for (Entry<TrackNodeLocation, TrackNode> nodeEntry : nodes.entrySet()) {
|
|
||||||
TrackNodeLocation nodeLocation = nodeEntry.getKey();
|
|
||||||
TrackNode node = nodeEntry.getValue();
|
|
||||||
if (nodeLocation == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Vec3 location = nodeLocation.getLocation();
|
|
||||||
if (location.distanceTo(camera) > 50)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Vec3 yOffset = new Vec3(0, 3 / 16f, 0);
|
|
||||||
Vec3 v1 = location.add(yOffset);
|
|
||||||
Vec3 v2 = v1.add(node.normal.scale(3 / 16f));
|
|
||||||
CreateClient.OUTLINER.showLine(Integer.valueOf(node.netId), v1, v2)
|
|
||||||
.colored(Color.mixColors(Color.WHITE, color, 1))
|
|
||||||
.lineWidth(1 / 8f);
|
|
||||||
|
|
||||||
Map<TrackNode, TrackEdge> map = connectionsByNode.get(node);
|
|
||||||
if (map == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int hashCode = node.hashCode();
|
|
||||||
for (Entry<TrackNode, TrackEdge> entry : map.entrySet()) {
|
|
||||||
TrackNode other = entry.getKey();
|
|
||||||
|
|
||||||
if (other.hashCode() > hashCode && !AllKeys.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL))
|
|
||||||
continue;
|
|
||||||
yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0);
|
|
||||||
|
|
||||||
TrackEdge edge = entry.getValue();
|
|
||||||
if (!edge.isTurn()) {
|
|
||||||
CreateClient.OUTLINER.showLine(edge, edge.getPosition(node, other, 0)
|
|
||||||
.add(yOffset),
|
|
||||||
edge.getPosition(node, other, 1)
|
|
||||||
.add(yOffset))
|
|
||||||
.colored(color)
|
|
||||||
.lineWidth(1 / 16f);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3 previous = null;
|
|
||||||
BezierConnection turn = edge.getTurn();
|
|
||||||
for (int i = 0; i <= turn.getSegmentCount(); i++) {
|
|
||||||
Vec3 current = edge.getPosition(node, other, i * 1f / turn.getSegmentCount());
|
|
||||||
if (previous != null)
|
|
||||||
CreateClient.OUTLINER
|
|
||||||
.showLine(Pair.of(edge, previous), previous.add(yOffset), current.add(yOffset))
|
|
||||||
.colored(color)
|
|
||||||
.lineWidth(1 / 16f);
|
|
||||||
previous = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.simibubi.create.content.logistics.trains;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public class TrackGraphBounds {
|
||||||
|
|
||||||
|
public AABB box;
|
||||||
|
public List<BezierConnection> beziers;
|
||||||
|
|
||||||
|
// TODO: filter nodes by dimensional coordinate
|
||||||
|
public TrackGraphBounds(TrackGraph graph, ResourceKey<Level> dimension) {
|
||||||
|
beziers = new ArrayList<>();
|
||||||
|
box = null;
|
||||||
|
|
||||||
|
for (TrackNode node : graph.nodes.values()) {
|
||||||
|
include(node);
|
||||||
|
Map<TrackNode, TrackEdge> connections = graph.getConnectionsFrom(node);
|
||||||
|
for (TrackEdge edge : connections.values())
|
||||||
|
if (edge.turn != null && edge.turn.isPrimary())
|
||||||
|
beziers.add(edge.turn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (box != null)
|
||||||
|
box = box.inflate(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void include(TrackNode node) {
|
||||||
|
Vec3 v = node.location.getLocation();
|
||||||
|
AABB aabb = new AABB(v, v);
|
||||||
|
box = box == null ? aabb : box.minmax(aabb);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ public class TrackGraphHelper {
|
||||||
public static GraphLocation getGraphLocationAt(Level level, BlockPos pos, AxisDirection targetDirection,
|
public static GraphLocation getGraphLocationAt(Level level, BlockPos pos, AxisDirection targetDirection,
|
||||||
Vec3 targetAxis) {
|
Vec3 targetAxis) {
|
||||||
BlockState trackBlockState = level.getBlockState(pos);
|
BlockState trackBlockState = level.getBlockState(pos);
|
||||||
if (!(trackBlockState.getBlock() instanceof ITrackBlock track))
|
if (!(trackBlockState.getBlock()instanceof ITrackBlock track))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
Vec3 axis = targetAxis.scale(targetDirection.getStep());
|
Vec3 axis = targetAxis.scale(targetDirection.getStep());
|
||||||
|
@ -44,7 +44,7 @@ public class TrackGraphHelper {
|
||||||
for (Entry<TrackNode, TrackEdge> entry : connectionsFrom.entrySet()) {
|
for (Entry<TrackNode, TrackEdge> entry : connectionsFrom.entrySet()) {
|
||||||
TrackNode backNode = entry.getKey();
|
TrackNode backNode = entry.getKey();
|
||||||
Vec3 direction = entry.getValue()
|
Vec3 direction = entry.getValue()
|
||||||
.getDirection(node, backNode, true);
|
.getDirection(true);
|
||||||
if (direction.scale(length)
|
if (direction.scale(length)
|
||||||
.distanceToSqr(axis.scale(-1)) > 1 / 4096f)
|
.distanceToSqr(axis.scale(-1)) > 1 / 4096f)
|
||||||
continue;
|
continue;
|
||||||
|
@ -133,9 +133,9 @@ public class TrackGraphHelper {
|
||||||
BezierTrackPointLocation targetBezier) {
|
BezierTrackPointLocation targetBezier) {
|
||||||
BlockState state = level.getBlockState(pos);
|
BlockState state = level.getBlockState(pos);
|
||||||
|
|
||||||
if (!(state.getBlock() instanceof ITrackBlock track))
|
if (!(state.getBlock()instanceof ITrackBlock track))
|
||||||
return null;
|
return null;
|
||||||
if (!(level.getBlockEntity(pos) instanceof TrackTileEntity trackTE))
|
if (!(level.getBlockEntity(pos)instanceof TrackTileEntity trackTE))
|
||||||
return null;
|
return null;
|
||||||
BezierConnection bc = trackTE.getConnections()
|
BezierConnection bc = trackTE.getConnections()
|
||||||
.get(targetBezier.curveTarget());
|
.get(targetBezier.curveTarget());
|
||||||
|
@ -163,7 +163,7 @@ public class TrackGraphHelper {
|
||||||
graphLocation.position = (targetBezier.segment() + 1) / 2f;
|
graphLocation.position = (targetBezier.segment() + 1) / 2f;
|
||||||
if (targetDirection == AxisDirection.POSITIVE) {
|
if (targetDirection == AxisDirection.POSITIVE) {
|
||||||
graphLocation.edge = graphLocation.edge.swap();
|
graphLocation.edge = graphLocation.edge.swap();
|
||||||
graphLocation.position = edge.getLength(node, targetNode) - graphLocation.position;
|
graphLocation.position = edge.getLength() - graphLocation.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
return graphLocation;
|
return graphLocation;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package com.simibubi.create.content.logistics.trains;
|
package com.simibubi.create.content.logistics.trains;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -11,6 +11,7 @@ import javax.annotation.Nullable;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.simibubi.create.Create;
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.EdgeGroupColor;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroupPacket;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroupPacket;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
||||||
import com.simibubi.create.foundation.networking.AllPackets;
|
import com.simibubi.create.foundation.networking.AllPackets;
|
||||||
|
@ -87,16 +88,18 @@ public class TrackGraphSync {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
public void sendEdgeGroups(Collection<UUID> ids, ServerPlayer player) {
|
public void sendEdgeGroups(List<UUID> ids, List<EdgeGroupColor> colors, ServerPlayer player) {
|
||||||
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), new SignalEdgeGroupPacket(ids, true));
|
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player),
|
||||||
|
new SignalEdgeGroupPacket(ids, colors, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void edgeGroupCreated(UUID id) {
|
public void edgeGroupCreated(UUID id, EdgeGroupColor color) {
|
||||||
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new SignalEdgeGroupPacket(ImmutableList.of(id), true));
|
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new SignalEdgeGroupPacket(id, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void edgeGroupRemoved(UUID id) {
|
public void edgeGroupRemoved(UUID id) {
|
||||||
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new SignalEdgeGroupPacket(ImmutableList.of(id), false));
|
AllPackets.channel.send(PacketDistributor.ALL.noArg(),
|
||||||
|
new SignalEdgeGroupPacket(ImmutableList.of(id), Collections.emptyList(), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -169,8 +169,14 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
||||||
for (Pair<Couple<Integer>, TrackEdge> pair : addedEdges) {
|
for (Pair<Couple<Integer>, TrackEdge> pair : addedEdges) {
|
||||||
Couple<TrackNode> nodes = pair.getFirst()
|
Couple<TrackNode> nodes = pair.getFirst()
|
||||||
.map(graph::getNode);
|
.map(graph::getNode);
|
||||||
if (nodes.getFirst() != null && nodes.getSecond() != null)
|
TrackNode node1 = nodes.getFirst();
|
||||||
graph.putConnection(nodes.getFirst(), nodes.getSecond(), pair.getSecond());
|
TrackNode node2 = nodes.getSecond();
|
||||||
|
if (node1 != null && node2 != null) {
|
||||||
|
TrackEdge edge = pair.getSecond();
|
||||||
|
edge.node1 = node1;
|
||||||
|
edge.node2 = node2;
|
||||||
|
graph.putConnection(node1, node2, edge);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TrackEdgePoint edgePoint : addedEdgePoints)
|
for (TrackEdgePoint edgePoint : addedEdgePoints)
|
||||||
|
@ -203,13 +209,13 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
||||||
if (edge == null)
|
if (edge == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
EdgeData edgeData = new EdgeData();
|
EdgeData edgeData = new EdgeData(edge);
|
||||||
if (groupType == NULL_GROUP)
|
if (groupType == NULL_GROUP)
|
||||||
edgeData.singleSignalGroup = null;
|
edgeData.setSingleSignalGroup(null, null);
|
||||||
else if (groupType == PASSIVE_GROUP)
|
else if (groupType == PASSIVE_GROUP)
|
||||||
edgeData.singleSignalGroup = EdgeData.passiveGroup;
|
edgeData.setSingleSignalGroup(null, EdgeData.passiveGroup);
|
||||||
else
|
else
|
||||||
edgeData.singleSignalGroup = idList.get(0);
|
edgeData.setSingleSignalGroup(null, idList.get(0));
|
||||||
|
|
||||||
List<TrackEdgePoint> points = edgeData.getPoints();
|
List<TrackEdgePoint> points = edgeData.getPoints();
|
||||||
edge.edgeData = edgeData;
|
edge.edgeData = edgeData;
|
||||||
|
@ -232,9 +238,9 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
||||||
List<UUID> list = new ArrayList<>();
|
List<UUID> list = new ArrayList<>();
|
||||||
EdgeData edgeData = edge.getEdgeData();
|
EdgeData edgeData = edge.getEdgeData();
|
||||||
int groupType = edgeData.hasSignalBoundaries() ? NULL_GROUP
|
int groupType = edgeData.hasSignalBoundaries() ? NULL_GROUP
|
||||||
: EdgeData.passiveGroup.equals(edgeData.singleSignalGroup) ? PASSIVE_GROUP : GROUP;
|
: EdgeData.passiveGroup.equals(edgeData.getSingleSignalGroup()) ? PASSIVE_GROUP : GROUP;
|
||||||
if (groupType == GROUP)
|
if (groupType == GROUP)
|
||||||
list.add(edgeData.singleSignalGroup);
|
list.add(edgeData.getSingleSignalGroup());
|
||||||
for (TrackEdgePoint point : edgeData.getPoints())
|
for (TrackEdgePoint point : edgeData.getPoints())
|
||||||
list.add(point.getId());
|
list.add(point.getId());
|
||||||
updatedEdgeData.put(key, Pair.of(groupType, list));
|
updatedEdgeData.put(key, Pair.of(groupType, list));
|
||||||
|
|
|
@ -0,0 +1,283 @@
|
||||||
|
package com.simibubi.create.content.logistics.trains;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import com.simibubi.create.AllKeys;
|
||||||
|
import com.simibubi.create.Create;
|
||||||
|
import com.simibubi.create.CreateClient;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackEdgeIntersection;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
||||||
|
import com.simibubi.create.foundation.utility.Color;
|
||||||
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
import com.simibubi.create.foundation.utility.outliner.Outliner;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public class TrackGraphVisualizer {
|
||||||
|
|
||||||
|
public static void visualiseSignalEdgeGroups(TrackGraph graph) {
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
Entity cameraEntity = mc.cameraEntity;
|
||||||
|
if (cameraEntity == null)
|
||||||
|
return;
|
||||||
|
AABB box = graph.getBounds(mc.level).box;
|
||||||
|
if (box == null || !box.intersects(cameraEntity.getBoundingBox()
|
||||||
|
.inflate(50)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vec3 camera = cameraEntity.getEyePosition();
|
||||||
|
Outliner outliner = CreateClient.OUTLINER;
|
||||||
|
boolean ctrl = AllKeys.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL);
|
||||||
|
Map<UUID, SignalEdgeGroup> allGroups = Create.RAILWAYS.sided(null).signalEdgeGroups;
|
||||||
|
float width = 1 / 8f;
|
||||||
|
|
||||||
|
for (Entry<TrackNodeLocation, TrackNode> nodeEntry : graph.nodes.entrySet()) {
|
||||||
|
TrackNodeLocation nodeLocation = nodeEntry.getKey();
|
||||||
|
TrackNode node = nodeEntry.getValue();
|
||||||
|
if (nodeLocation == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Vec3 location = nodeLocation.getLocation();
|
||||||
|
if (location.distanceTo(camera) > 50)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Map<TrackNode, TrackEdge> map = graph.connectionsByNode.get(node);
|
||||||
|
if (map == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int hashCode = node.hashCode();
|
||||||
|
for (Entry<TrackNode, TrackEdge> entry : map.entrySet()) {
|
||||||
|
TrackNode other = entry.getKey();
|
||||||
|
TrackEdge edge = entry.getValue();
|
||||||
|
EdgeData signalData = edge.getEdgeData();
|
||||||
|
|
||||||
|
// temporary
|
||||||
|
if (other.hashCode() > hashCode == ctrl)
|
||||||
|
for (TrackEdgeIntersection intersection : signalData.getIntersections()) {
|
||||||
|
Vec3 v1 = edge.getPosition(intersection.location / edge.getLength());
|
||||||
|
Vec3 v2 = v1.add(node.normal.scale(8 / 16f));
|
||||||
|
outliner.showLine(intersection, v1, v2)
|
||||||
|
.colored(Color.mixColors(Color.WHITE, graph.color, 1))
|
||||||
|
.lineWidth(width);
|
||||||
|
} //
|
||||||
|
|
||||||
|
if (other.hashCode() > hashCode && !ctrl)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Vec3 yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 5) / 64f, 0);
|
||||||
|
Vec3 startPoint = edge.getPosition(0);
|
||||||
|
Vec3 endPoint = edge.getPosition(1);
|
||||||
|
|
||||||
|
if (!edge.isTurn()) {
|
||||||
|
|
||||||
|
// Straight edge with signal boundaries
|
||||||
|
if (signalData.hasSignalBoundaries()) {
|
||||||
|
double prev = 0;
|
||||||
|
double length = edge.getLength();
|
||||||
|
SignalBoundary prevBoundary = null;
|
||||||
|
SignalEdgeGroup group = null;
|
||||||
|
|
||||||
|
for (TrackEdgePoint trackEdgePoint : signalData.getPoints()) {
|
||||||
|
if (!(trackEdgePoint instanceof SignalBoundary boundary))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
prevBoundary = boundary;
|
||||||
|
group = allGroups.get(boundary.getGroup(node));
|
||||||
|
|
||||||
|
if (group != null)
|
||||||
|
outliner.showLine(Pair.of(boundary, edge),
|
||||||
|
edge.getPosition(prev + (prev == 0 ? 0 : 1 / 16f / length))
|
||||||
|
.add(yOffset),
|
||||||
|
edge.getPosition((prev = boundary.getLocationOn(edge) / length) - 1 / 16f / length)
|
||||||
|
.add(yOffset))
|
||||||
|
.colored(group.color.get())
|
||||||
|
.lineWidth(width);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevBoundary != null) {
|
||||||
|
group = allGroups.get(prevBoundary.getGroup(other));
|
||||||
|
if (group != null)
|
||||||
|
outliner.showLine(edge, edge.getPosition(prev + 1 / 16f / length)
|
||||||
|
.add(yOffset), endPoint.add(yOffset))
|
||||||
|
.colored(group.color.get())
|
||||||
|
.lineWidth(width);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Straight edge, no signal boundaries
|
||||||
|
UUID singleGroup = signalData.getEffectiveEdgeGroupId(graph);
|
||||||
|
SignalEdgeGroup singleEdgeGroup = singleGroup == null ? null : allGroups.get(singleGroup);
|
||||||
|
if (singleEdgeGroup == null)
|
||||||
|
continue;
|
||||||
|
outliner.showLine(edge, startPoint.add(yOffset), endPoint.add(yOffset))
|
||||||
|
.colored(singleEdgeGroup.color.get())
|
||||||
|
.lineWidth(width);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Bezier edge with signal boundaries
|
||||||
|
if (signalData.hasSignalBoundaries()) {
|
||||||
|
Iterator<TrackEdgePoint> points = signalData.getPoints()
|
||||||
|
.iterator();
|
||||||
|
SignalBoundary currentBoundary = null;
|
||||||
|
double currentBoundaryPosition = 0;
|
||||||
|
while (points.hasNext()) {
|
||||||
|
TrackEdgePoint next = points.next();
|
||||||
|
if (!(next instanceof SignalBoundary signal))
|
||||||
|
continue;
|
||||||
|
currentBoundary = signal;
|
||||||
|
currentBoundaryPosition = signal.getLocationOn(edge);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentBoundary == null)
|
||||||
|
continue;
|
||||||
|
UUID initialGroupId = currentBoundary.getGroup(node);
|
||||||
|
if (initialGroupId == null)
|
||||||
|
continue;
|
||||||
|
SignalEdgeGroup initialGroup = allGroups.get(initialGroupId);
|
||||||
|
if (initialGroup == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Color currentColour = initialGroup.color.get();
|
||||||
|
Vec3 previous = null;
|
||||||
|
BezierConnection turn = edge.getTurn();
|
||||||
|
|
||||||
|
for (int i = 0; i <= turn.getSegmentCount(); i++) {
|
||||||
|
double f = i * 1f / turn.getSegmentCount();
|
||||||
|
double position = f * turn.getLength();
|
||||||
|
Vec3 current = edge.getPosition(f);
|
||||||
|
|
||||||
|
if (previous != null) {
|
||||||
|
if (currentBoundary != null && position > currentBoundaryPosition) {
|
||||||
|
current = edge.getPosition((currentBoundaryPosition - width) / turn.getLength());
|
||||||
|
outliner
|
||||||
|
.showLine(Pair.of(edge, previous), previous.add(yOffset), current.add(yOffset))
|
||||||
|
.colored(currentColour)
|
||||||
|
.lineWidth(width);
|
||||||
|
current = edge.getPosition((currentBoundaryPosition + width) / turn.getLength());
|
||||||
|
previous = current;
|
||||||
|
UUID newId = currentBoundary.getGroup(other);
|
||||||
|
if (newId != null && allGroups.containsKey(newId))
|
||||||
|
currentColour = allGroups.get(newId).color.get();
|
||||||
|
|
||||||
|
currentBoundary = null;
|
||||||
|
while (points.hasNext()) {
|
||||||
|
TrackEdgePoint next = points.next();
|
||||||
|
if (!(next instanceof SignalBoundary signal))
|
||||||
|
continue;
|
||||||
|
currentBoundary = signal;
|
||||||
|
currentBoundaryPosition = signal.getLocationOn(edge);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outliner.showLine(Pair.of(edge, previous), previous.add(yOffset), current.add(yOffset))
|
||||||
|
.colored(currentColour)
|
||||||
|
.lineWidth(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bezier edge, no signal boundaries
|
||||||
|
UUID singleGroup = signalData.getEffectiveEdgeGroupId(graph);
|
||||||
|
SignalEdgeGroup singleEdgeGroup = singleGroup == null ? null : allGroups.get(singleGroup);
|
||||||
|
if (singleEdgeGroup == null)
|
||||||
|
continue;
|
||||||
|
Vec3 previous = null;
|
||||||
|
BezierConnection turn = edge.getTurn();
|
||||||
|
for (int i = 0; i <= turn.getSegmentCount(); i++) {
|
||||||
|
Vec3 current = edge.getPosition(i * 1f / turn.getSegmentCount());
|
||||||
|
if (previous != null)
|
||||||
|
outliner.showLine(Pair.of(edge, previous), previous.add(yOffset), current.add(yOffset))
|
||||||
|
.colored(singleEdgeGroup.color.get())
|
||||||
|
.lineWidth(width);
|
||||||
|
previous = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void debugViewGraph(TrackGraph graph) {
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
Entity cameraEntity = mc.cameraEntity;
|
||||||
|
if (cameraEntity == null)
|
||||||
|
return;
|
||||||
|
AABB box = graph.getBounds(mc.level).box;
|
||||||
|
if (box == null || !box.intersects(cameraEntity.getBoundingBox()
|
||||||
|
.inflate(50)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vec3 camera = cameraEntity.getEyePosition();
|
||||||
|
for (Entry<TrackNodeLocation, TrackNode> nodeEntry : graph.nodes.entrySet()) {
|
||||||
|
TrackNodeLocation nodeLocation = nodeEntry.getKey();
|
||||||
|
TrackNode node = nodeEntry.getValue();
|
||||||
|
if (nodeLocation == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Vec3 location = nodeLocation.getLocation();
|
||||||
|
if (location.distanceTo(camera) > 50)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Vec3 yOffset = new Vec3(0, 3 / 16f, 0);
|
||||||
|
Vec3 v1 = location.add(yOffset);
|
||||||
|
Vec3 v2 = v1.add(node.normal.scale(3 / 16f));
|
||||||
|
CreateClient.OUTLINER.showLine(Integer.valueOf(node.netId), v1, v2)
|
||||||
|
.colored(Color.mixColors(Color.WHITE, graph.color, 1))
|
||||||
|
.lineWidth(1 / 8f);
|
||||||
|
|
||||||
|
Map<TrackNode, TrackEdge> map = graph.connectionsByNode.get(node);
|
||||||
|
if (map == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int hashCode = node.hashCode();
|
||||||
|
for (Entry<TrackNode, TrackEdge> entry : map.entrySet()) {
|
||||||
|
TrackNode other = entry.getKey();
|
||||||
|
|
||||||
|
if (other.hashCode() > hashCode && !AllKeys.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL))
|
||||||
|
continue;
|
||||||
|
yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0);
|
||||||
|
|
||||||
|
TrackEdge edge = entry.getValue();
|
||||||
|
if (!edge.isTurn()) {
|
||||||
|
CreateClient.OUTLINER.showLine(edge, edge.getPosition(0)
|
||||||
|
.add(yOffset),
|
||||||
|
edge.getPosition(1)
|
||||||
|
.add(yOffset))
|
||||||
|
.colored(graph.color)
|
||||||
|
.lineWidth(1 / 16f);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 previous = null;
|
||||||
|
BezierConnection turn = edge.getTurn();
|
||||||
|
for (int i = 0; i <= turn.getSegmentCount(); i++) {
|
||||||
|
Vec3 current = edge.getPosition(i * 1f / turn.getSegmentCount());
|
||||||
|
if (previous != null)
|
||||||
|
CreateClient.OUTLINER
|
||||||
|
.showLine(Pair.of(edge, previous), previous.add(yOffset), current.add(yOffset))
|
||||||
|
.colored(graph.color)
|
||||||
|
.lineWidth(1 / 16f);
|
||||||
|
previous = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ public class TrackPropagator {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onRailRemoved(LevelAccessor reader, BlockPos pos, BlockState state) {
|
public static void onRailRemoved(LevelAccessor reader, BlockPos pos, BlockState state) {
|
||||||
if (!(state.getBlock()instanceof ITrackBlock track))
|
if (!(state.getBlock() instanceof ITrackBlock track))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Collection<DiscoveredLocation> ends = track.getConnected(reader, pos, state, false, null);
|
Collection<DiscoveredLocation> ends = track.getConnected(reader, pos, state, false, null);
|
||||||
|
@ -51,7 +51,7 @@ public class TrackPropagator {
|
||||||
sync.nodeRemoved(foundGraph, removedNode);
|
sync.nodeRemoved(foundGraph, removedNode);
|
||||||
if (!foundGraph.isEmpty())
|
if (!foundGraph.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
manager.removeGraph(foundGraph);
|
manager.removeGraphAndGroup(foundGraph);
|
||||||
sync.graphRemoved(foundGraph);
|
sync.graphRemoved(foundGraph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ public class TrackPropagator {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TrackGraph onRailAdded(LevelAccessor reader, BlockPos pos, BlockState state) {
|
public static TrackGraph onRailAdded(LevelAccessor reader, BlockPos pos, BlockState state) {
|
||||||
if (!(state.getBlock()instanceof ITrackBlock track))
|
if (!(state.getBlock() instanceof ITrackBlock track))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// 1. Remove all immediately reachable node locations
|
// 1. Remove all immediately reachable node locations
|
||||||
|
@ -124,7 +124,7 @@ public class TrackPropagator {
|
||||||
TrackGraph railGraph = iterator.next();
|
TrackGraph railGraph = iterator.next();
|
||||||
if (!railGraph.isEmpty() || connectedGraphs.size() == 1)
|
if (!railGraph.isEmpty() || connectedGraphs.size() == 1)
|
||||||
continue;
|
continue;
|
||||||
manager.removeGraph(railGraph);
|
manager.removeGraphAndGroup(railGraph);
|
||||||
sync.graphRemoved(railGraph);
|
sync.graphRemoved(railGraph);
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ public class TrackPropagator {
|
||||||
graph = other;
|
graph = other;
|
||||||
else {
|
else {
|
||||||
other.transferAll(graph);
|
other.transferAll(graph);
|
||||||
manager.removeGraph(other);
|
manager.removeGraphAndGroup(other);
|
||||||
sync.graphRemoved(other);
|
sync.graphRemoved(other);
|
||||||
}
|
}
|
||||||
} else if (connectedGraphs.size() == 1) {
|
} else if (connectedGraphs.size() == 1) {
|
||||||
|
@ -144,7 +144,7 @@ public class TrackPropagator {
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.get();
|
.get();
|
||||||
} else
|
} else
|
||||||
manager.putGraph(graph = new TrackGraph());
|
manager.putGraphWithDefaultGroup(graph = new TrackGraph());
|
||||||
|
|
||||||
DiscoveredLocation startNode = null;
|
DiscoveredLocation startNode = null;
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ public class TrackPropagator {
|
||||||
|
|
||||||
if (isValidGraphNodeLocation(entry.currentNode, ends, first) && entry.currentNode != startNode) {
|
if (isValidGraphNodeLocation(entry.currentNode, ends, first) && entry.currentNode != startNode) {
|
||||||
boolean nodeIsNew = graph.createNodeIfAbsent(entry.currentNode);
|
boolean nodeIsNew = graph.createNodeIfAbsent(entry.currentNode);
|
||||||
graph.connectNodes(parentNode, entry.currentNode, new TrackEdge(entry.currentNode.getTurn()));
|
graph.connectNodes(reader, parentNode, entry.currentNode, entry.currentNode.getTurn());
|
||||||
addedNodes.add(graph.locateNode(entry.currentNode));
|
addedNodes.add(graph.locateNode(entry.currentNode));
|
||||||
parentNode = entry.currentNode;
|
parentNode = entry.currentNode;
|
||||||
if (!nodeIsNew)
|
if (!nodeIsNew)
|
||||||
|
|
|
@ -239,8 +239,8 @@ public class CarriageSyncData {
|
||||||
TravellingPoint toApproach = pointsToApproach[index];
|
TravellingPoint toApproach = pointsToApproach[index];
|
||||||
|
|
||||||
point.travel(graph, partial * f,
|
point.travel(graph, partial * f,
|
||||||
point.follow(toApproach, b -> success.setValue(success.booleanValue() && b)), point.ignoreEdgePoints(),
|
point.follow(toApproach, b -> success.setValue(success.booleanValue() && b)),
|
||||||
point.ignoreTurns());
|
point.ignoreEdgePoints(), point.ignoreTurns());
|
||||||
|
|
||||||
// could not pathfind to server location
|
// could not pathfind to server location
|
||||||
if (!success.booleanValue()) {
|
if (!success.booleanValue()) {
|
||||||
|
@ -284,8 +284,7 @@ public class CarriageSyncData {
|
||||||
TrackEdge targetEdge = graph.getConnectionsFrom(targetNode1)
|
TrackEdge targetEdge = graph.getConnectionsFrom(targetNode1)
|
||||||
.get(targetNode2);
|
.get(targetNode2);
|
||||||
|
|
||||||
double distanceToNode2 =
|
double distanceToNode2 = forward ? initialEdge.getLength() - current.position : current.position;
|
||||||
forward ? initialEdge.getLength(initialNode1, initialNode2) - current.position : current.position;
|
|
||||||
|
|
||||||
frontier.add(Pair.of(distanceToNode2, Pair.of(Couple.create(initialNode1, initialNode2), initialEdge)));
|
frontier.add(Pair.of(distanceToNode2, Pair.of(Couple.create(initialNode1, initialNode2), initialEdge)));
|
||||||
|
|
||||||
|
@ -294,15 +293,12 @@ public class CarriageSyncData {
|
||||||
double distance = poll.getFirst();
|
double distance = poll.getFirst();
|
||||||
|
|
||||||
Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond();
|
Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond();
|
||||||
TrackNode node1 = currentEntry.getFirst()
|
|
||||||
.getFirst();
|
|
||||||
TrackNode node2 = currentEntry.getFirst()
|
TrackNode node2 = currentEntry.getFirst()
|
||||||
.getSecond();
|
.getSecond();
|
||||||
TrackEdge edge = currentEntry.getSecond();
|
TrackEdge edge = currentEntry.getSecond();
|
||||||
|
|
||||||
if (edge == targetEdge)
|
if (edge == targetEdge)
|
||||||
return (float) (distance
|
return (float) (distance - (forward ? edge.getLength() - target.position : target.position));
|
||||||
- (forward ? edge.getLength(node1, node2) - target.position : target.position));
|
|
||||||
|
|
||||||
if (distance > maxDistance)
|
if (distance > maxDistance)
|
||||||
continue;
|
continue;
|
||||||
|
@ -310,10 +306,9 @@ public class CarriageSyncData {
|
||||||
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
||||||
Map<TrackNode, TrackEdge> connectionsFrom = graph.getConnectionsFrom(node2);
|
Map<TrackNode, TrackEdge> connectionsFrom = graph.getConnectionsFrom(node2);
|
||||||
for (Entry<TrackNode, TrackEdge> entry : connectionsFrom.entrySet()) {
|
for (Entry<TrackNode, TrackEdge> entry : connectionsFrom.entrySet()) {
|
||||||
TrackNode newNode = entry.getKey();
|
|
||||||
TrackEdge newEdge = entry.getValue();
|
TrackEdge newEdge = entry.getValue();
|
||||||
Vec3 currentDirection = edge.getDirection(node1, node2, false);
|
Vec3 currentDirection = edge.getDirection(false);
|
||||||
Vec3 newDirection = newEdge.getDirection(node2, newNode, true);
|
Vec3 newDirection = newEdge.getDirection(true);
|
||||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||||
continue;
|
continue;
|
||||||
if (!visited.add(entry.getValue()))
|
if (!visited.add(entry.getValue()))
|
||||||
|
@ -328,8 +323,7 @@ public class CarriageSyncData {
|
||||||
TrackNode newNode = entry.getKey();
|
TrackNode newNode = entry.getKey();
|
||||||
TrackEdge newEdge = entry.getValue();
|
TrackEdge newEdge = entry.getValue();
|
||||||
reachedVia.put(newEdge, Pair.of(validTargets.size() > 1, edge));
|
reachedVia.put(newEdge, Pair.of(validTargets.size() > 1, edge));
|
||||||
frontier.add(Pair.of(newEdge.getLength(node2, newNode) + distance,
|
frontier.add(Pair.of(newEdge.getLength() + distance, Pair.of(Couple.create(node2, newNode), newEdge)));
|
||||||
Pair.of(Couple.create(node2, newNode), newEdge)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -449,7 +449,7 @@ public class Navigation {
|
||||||
backTrack = reachedVia.get(edgeReached);
|
backTrack = reachedVia.get(edgeReached);
|
||||||
}
|
}
|
||||||
|
|
||||||
double position = edge.getLength(node1, node2) - destination.getLocationOn(node1, node2, edge);
|
double position = edge.getLength() - destination.getLocationOn(edge);
|
||||||
double distanceToDestination = distance - position;
|
double distanceToDestination = distance - position;
|
||||||
results.set(forward, new DiscoveredPath((forward ? 1 : -1) * distanceToDestination, cost, currentPath));
|
results.set(forward, new DiscoveredPath((forward ? 1 : -1) * distanceToDestination, cost, currentPath));
|
||||||
return true;
|
return true;
|
||||||
|
@ -510,12 +510,7 @@ public class Navigation {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
TrackEdge edge = currentEntry.getSecond();
|
TrackEdge edge = currentEntry.getSecond();
|
||||||
TrackNode node1 = currentEntry.getFirst()
|
double position = edge.getLength() - globalStation.getLocationOn(edge);
|
||||||
.getFirst();
|
|
||||||
TrackNode node2 = currentEntry.getFirst()
|
|
||||||
.getSecond();
|
|
||||||
|
|
||||||
double position = edge.getLength(node1, node2) - globalStation.getLocationOn(node1, node2, edge);
|
|
||||||
if (distance - position < minDistance)
|
if (distance - position < minDistance)
|
||||||
return false;
|
return false;
|
||||||
result.setValue(globalStation);
|
result.setValue(globalStation);
|
||||||
|
@ -571,8 +566,7 @@ public class Navigation {
|
||||||
TrackNode initialNode2 = forward ? startingPoint.node2 : startingPoint.node1;
|
TrackNode initialNode2 = forward ? startingPoint.node2 : startingPoint.node1;
|
||||||
TrackEdge initialEdge = graph.getConnectionsFrom(initialNode1)
|
TrackEdge initialEdge = graph.getConnectionsFrom(initialNode1)
|
||||||
.get(initialNode2);
|
.get(initialNode2);
|
||||||
double distanceToNode2 = forward ? initialEdge.getLength(initialNode1, initialNode2) - startingPoint.position
|
double distanceToNode2 = forward ? initialEdge.getLength() - startingPoint.position : startingPoint.position;
|
||||||
: startingPoint.position;
|
|
||||||
|
|
||||||
frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge));
|
frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge));
|
||||||
|
|
||||||
|
@ -597,8 +591,7 @@ public class Navigation {
|
||||||
EdgeData signalData = edge.getEdgeData();
|
EdgeData signalData = edge.getEdgeData();
|
||||||
if (signalData.hasPoints()) {
|
if (signalData.hasPoints()) {
|
||||||
for (TrackEdgePoint point : signalData.getPoints()) {
|
for (TrackEdgePoint point : signalData.getPoints()) {
|
||||||
if (node1 == initialNode1
|
if (node1 == initialNode1 && point.getLocationOn(edge) < edge.getLength() - distanceToNode2)
|
||||||
&& point.getLocationOn(node1, node2, edge) < edge.getLength(node1, node2) - distanceToNode2)
|
|
||||||
continue;
|
continue;
|
||||||
if (costRelevant && distance + penalty > maxCost)
|
if (costRelevant && distance + penalty > maxCost)
|
||||||
continue Search;
|
continue Search;
|
||||||
|
@ -624,10 +617,9 @@ public class Navigation {
|
||||||
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
||||||
Map<TrackNode, TrackEdge> connectionsFrom = graph.getConnectionsFrom(node2);
|
Map<TrackNode, TrackEdge> connectionsFrom = graph.getConnectionsFrom(node2);
|
||||||
for (Entry<TrackNode, TrackEdge> connection : connectionsFrom.entrySet()) {
|
for (Entry<TrackNode, TrackEdge> connection : connectionsFrom.entrySet()) {
|
||||||
TrackNode newNode = connection.getKey();
|
|
||||||
TrackEdge newEdge = connection.getValue();
|
TrackEdge newEdge = connection.getValue();
|
||||||
Vec3 currentDirection = edge.getDirection(node1, node2, false);
|
Vec3 currentDirection = edge.getDirection(false);
|
||||||
Vec3 newDirection = newEdge.getDirection(node2, newNode, true);
|
Vec3 newDirection = newEdge.getDirection(true);
|
||||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||||
continue;
|
continue;
|
||||||
validTargets.add(connection);
|
validTargets.add(connection);
|
||||||
|
@ -639,7 +631,7 @@ public class Navigation {
|
||||||
for (Entry<TrackNode, TrackEdge> target : validTargets) {
|
for (Entry<TrackNode, TrackEdge> target : validTargets) {
|
||||||
TrackNode newNode = target.getKey();
|
TrackNode newNode = target.getKey();
|
||||||
TrackEdge newEdge = target.getValue();
|
TrackEdge newEdge = target.getValue();
|
||||||
double newDistance = newEdge.getLength(node2, newNode) + distance;
|
double newDistance = newEdge.getLength() + distance;
|
||||||
int newPenalty = penalty;
|
int newPenalty = penalty;
|
||||||
reachedVia.putIfAbsent(newEdge, Pair.of(validTargets.size() > 1, Couple.create(node1, node2)));
|
reachedVia.putIfAbsent(newEdge, Pair.of(validTargets.size() > 1, Couple.create(node1, node2)));
|
||||||
frontier.add(new FrontierEntry(newDistance, newPenalty, node2, newNode, newEdge));
|
frontier.add(new FrontierEntry(newDistance, newPenalty, node2, newNode, newEdge));
|
||||||
|
|
|
@ -714,15 +714,15 @@ public class Train {
|
||||||
MutableObject<UUID> prevGroup = new MutableObject<>(null);
|
MutableObject<UUID> prevGroup = new MutableObject<>(null);
|
||||||
|
|
||||||
if (signalData.hasSignalBoundaries()) {
|
if (signalData.hasSignalBoundaries()) {
|
||||||
SignalBoundary nextBoundary = signalData.next(EdgePointType.SIGNAL, node1, node2, edge, position);
|
SignalBoundary nextBoundary = signalData.next(EdgePointType.SIGNAL, position);
|
||||||
if (nextBoundary == null) {
|
if (nextBoundary == null) {
|
||||||
double d = 0;
|
double d = 0;
|
||||||
SignalBoundary prev = null;
|
SignalBoundary prev = null;
|
||||||
SignalBoundary current = signalData.next(EdgePointType.SIGNAL, node1, node2, edge, 0);
|
SignalBoundary current = signalData.next(EdgePointType.SIGNAL, 0);
|
||||||
while (current != null) {
|
while (current != null) {
|
||||||
prev = current;
|
prev = current;
|
||||||
d = current.getLocationOn(node1, node2, edge);
|
d = current.getLocationOn(edge);
|
||||||
current = signalData.next(EdgePointType.SIGNAL, node1, node2, edge, d);
|
current = signalData.next(EdgePointType.SIGNAL, d);
|
||||||
}
|
}
|
||||||
if (prev != null) {
|
if (prev != null) {
|
||||||
UUID group = prev.getGroup(node2);
|
UUID group = prev.getGroup(node2);
|
||||||
|
@ -740,9 +740,12 @@ public class Train {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (signalData.singleSignalGroup != null && allGroups.containsKey(signalData.singleSignalGroup)) {
|
} else {
|
||||||
occupy(signalData.singleSignalGroup, null);
|
UUID groupId = signalData.getEffectiveEdgeGroupId(graph);
|
||||||
prevGroup.setValue(signalData.singleSignalGroup);
|
if (allGroups.containsKey(groupId)) {
|
||||||
|
occupy(groupId, null);
|
||||||
|
prevGroup.setValue(groupId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
forEachTravellingPointBackwards((tp, d) -> {
|
forEachTravellingPointBackwards((tp, d) -> {
|
||||||
|
|
|
@ -27,8 +27,8 @@ public class TrainMigration {
|
||||||
public TrainMigration() {}
|
public TrainMigration() {}
|
||||||
|
|
||||||
public TrainMigration(TravellingPoint point) {
|
public TrainMigration(TravellingPoint point) {
|
||||||
double t = point.position / point.edge.getLength(point.node1, point.node2);
|
double t = point.position / point.edge.getLength();
|
||||||
fallback = point.edge.getPosition(point.node1, point.node2, t);
|
fallback = point.edge.getPosition(t);
|
||||||
curve = point.edge.isTurn();
|
curve = point.edge.isTurn();
|
||||||
positionOnOldEdge = point.position;
|
positionOnOldEdge = point.position;
|
||||||
locations = Couple.create(point.node1.getLocation(), point.node2.getLocation());
|
locations = Couple.create(point.node1.getLocation(), point.node2.getLocation());
|
||||||
|
@ -71,7 +71,7 @@ public class TrainMigration {
|
||||||
continue;
|
continue;
|
||||||
TrackNode newNode2 = entry.getKey();
|
TrackNode newNode2 = entry.getKey();
|
||||||
float radius = 1 / 64f;
|
float radius = 1 / 64f;
|
||||||
Vec3 direction = edge.getDirection(newNode1, newNode2, true);
|
Vec3 direction = edge.getDirection(true);
|
||||||
if (!Mth.equal(direction.dot(prevDirection), 1))
|
if (!Mth.equal(direction.dot(prevDirection), 1))
|
||||||
continue;
|
continue;
|
||||||
Vec3 intersectSphere = VecHelper.intersectSphere(nodeVec, direction, fallback, radius);
|
Vec3 intersectSphere = VecHelper.intersectSphere(nodeVec, direction, fallback, radius);
|
||||||
|
@ -80,7 +80,7 @@ public class TrainMigration {
|
||||||
if (!Mth.equal(direction.dot(intersectSphere.subtract(nodeVec)
|
if (!Mth.equal(direction.dot(intersectSphere.subtract(nodeVec)
|
||||||
.normalize()), 1))
|
.normalize()), 1))
|
||||||
continue;
|
continue;
|
||||||
double edgeLength = edge.getLength(newNode1, newNode2);
|
double edgeLength = edge.getLength();
|
||||||
double position = intersectSphere.distanceTo(nodeVec) - radius;
|
double position = intersectSphere.distanceTo(nodeVec) - radius;
|
||||||
if (Double.isNaN(position))
|
if (Double.isNaN(position))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -153,9 +153,9 @@ public class TravellingPoint {
|
||||||
Entry<TrackNode, TrackEdge> best = null;
|
Entry<TrackNode, TrackEdge> best = null;
|
||||||
|
|
||||||
for (Entry<TrackNode, TrackEdge> entry : validTargets) {
|
for (Entry<TrackNode, TrackEdge> entry : validTargets) {
|
||||||
Vec3 trajectory = edge.getDirection(node1, node2, false);
|
Vec3 trajectory = edge.getDirection(false);
|
||||||
Vec3 entryTrajectory = entry.getValue()
|
Vec3 entryTrajectory = entry.getValue()
|
||||||
.getDirection(node2, entry.getKey(), true);
|
.getDirection(true);
|
||||||
Vec3 normal = trajectory.cross(upNormal);
|
Vec3 normal = trajectory.cross(upNormal);
|
||||||
double dot = normal.dot(entryTrajectory);
|
double dot = normal.dot(entryTrajectory);
|
||||||
double diff = Math.abs(direction.targetDot - dot);
|
double diff = Math.abs(direction.targetDot - dot);
|
||||||
|
@ -178,14 +178,14 @@ public class TravellingPoint {
|
||||||
public double travel(TrackGraph graph, double distance, ITrackSelector trackSelector,
|
public double travel(TrackGraph graph, double distance, ITrackSelector trackSelector,
|
||||||
IEdgePointListener signalListener, ITurnListener turnListener) {
|
IEdgePointListener signalListener, ITurnListener turnListener) {
|
||||||
blocked = false;
|
blocked = false;
|
||||||
double edgeLength = edge.getLength(node1, node2);
|
double edgeLength = edge.getLength();
|
||||||
if (distance == 0)
|
if (distance == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
double prevPos = position;
|
double prevPos = position;
|
||||||
double traveled = distance;
|
double traveled = distance;
|
||||||
double currentT = position / edgeLength;
|
double currentT = position / edgeLength;
|
||||||
double incrementT = edge.incrementT(node1, node2, currentT, distance);
|
double incrementT = edge.incrementT(currentT, distance);
|
||||||
position = incrementT * edgeLength;
|
position = incrementT * edgeLength;
|
||||||
|
|
||||||
// FIXME: using incrementT like this becomes inaccurate at medium-long distances
|
// FIXME: using incrementT like this becomes inaccurate at medium-long distances
|
||||||
|
@ -221,8 +221,8 @@ public class TravellingPoint {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
TrackEdge newEdge = entry.getValue();
|
TrackEdge newEdge = entry.getValue();
|
||||||
Vec3 currentDirection = edge.getDirection(node1, node2, false);
|
Vec3 currentDirection = edge.getDirection(false);
|
||||||
Vec3 newDirection = newEdge.getDirection(node2, newNode, true);
|
Vec3 newDirection = newEdge.getDirection(true);
|
||||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ public class TravellingPoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
prevPos = 0;
|
prevPos = 0;
|
||||||
edgeLength = edge.getLength(node1, node2);
|
edgeLength = edge.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -274,8 +274,8 @@ public class TravellingPoint {
|
||||||
|
|
||||||
TrackEdge newEdge = graph.getConnectionsFrom(newNode)
|
TrackEdge newEdge = graph.getConnectionsFrom(newNode)
|
||||||
.get(node1);
|
.get(node1);
|
||||||
Vec3 currentDirection = edge.getDirection(node1, node2, true);
|
Vec3 currentDirection = edge.getDirection(true);
|
||||||
Vec3 newDirection = newEdge.getDirection(newNode, node1, false);
|
Vec3 newDirection = newEdge.getDirection(false);
|
||||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ public class TravellingPoint {
|
||||||
edge = graph.getConnectionsFrom(node1)
|
edge = graph.getConnectionsFrom(node1)
|
||||||
.get(node2);
|
.get(node2);
|
||||||
collectedDistance += edgeLength;
|
collectedDistance += edgeLength;
|
||||||
edgeLength = edge.getLength(node1, node2);
|
edgeLength = edge.getLength();
|
||||||
position += edgeLength;
|
position += edgeLength;
|
||||||
|
|
||||||
blockedLocation =
|
blockedLocation =
|
||||||
|
@ -326,11 +326,11 @@ public class TravellingPoint {
|
||||||
double to = forward ? position : prevPos;
|
double to = forward ? position : prevPos;
|
||||||
List<TrackEdgePoint> edgePoints = edgeData.getPoints();
|
List<TrackEdgePoint> edgePoints = edgeData.getPoints();
|
||||||
|
|
||||||
double length = edge.getLength(node1, node2);
|
double length = edge.getLength();
|
||||||
for (int i = 0; i < edgePoints.size(); i++) {
|
for (int i = 0; i < edgePoints.size(); i++) {
|
||||||
int index = forward ? i : edgePoints.size() - i - 1;
|
int index = forward ? i : edgePoints.size() - i - 1;
|
||||||
TrackEdgePoint nextBoundary = edgePoints.get(index);
|
TrackEdgePoint nextBoundary = edgePoints.get(index);
|
||||||
double locationOn = nextBoundary.getLocationOn(node1, node2, edge);
|
double locationOn = nextBoundary.getLocationOn(edge);
|
||||||
double distance = forward ? locationOn : length - locationOn;
|
double distance = forward ? locationOn : length - locationOn;
|
||||||
if (forward ? (locationOn < from || locationOn >= to) : (locationOn <= from || locationOn > to))
|
if (forward ? (locationOn < from || locationOn >= to) : (locationOn <= from || locationOn > to))
|
||||||
continue;
|
continue;
|
||||||
|
@ -346,14 +346,14 @@ public class TravellingPoint {
|
||||||
TrackNode n = node1;
|
TrackNode n = node1;
|
||||||
node1 = node2;
|
node1 = node2;
|
||||||
node2 = n;
|
node2 = n;
|
||||||
position = edge.getLength(node1, node2) - position;
|
position = edge.getLength() - position;
|
||||||
edge = graph.getConnectionsFrom(node1)
|
edge = graph.getConnectionsFrom(node1)
|
||||||
.get(node2);
|
.get(node2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3 getPosition() {
|
public Vec3 getPosition() {
|
||||||
double t = position / edge.getLength(node1, node2);
|
double t = position / edge.getLength();
|
||||||
return edge.getPosition(node1, node2, t)
|
return edge.getPosition(t)
|
||||||
.add(edge.getNormal(node1, node2, t)
|
.add(edge.getNormal(node1, node2, t)
|
||||||
.scale(1));
|
.scale(1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,23 @@
|
||||||
package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||||
|
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
||||||
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
@ -21,11 +29,15 @@ public class EdgeData {
|
||||||
|
|
||||||
public static final UUID passiveGroup = UUID.fromString("00000000-0000-0000-0000-000000000000");
|
public static final UUID passiveGroup = UUID.fromString("00000000-0000-0000-0000-000000000000");
|
||||||
|
|
||||||
public UUID singleSignalGroup;
|
private UUID singleSignalGroup;
|
||||||
private List<TrackEdgePoint> points;
|
private List<TrackEdgePoint> points;
|
||||||
|
private List<TrackEdgeIntersection> intersections;
|
||||||
|
private TrackEdge edge;
|
||||||
|
|
||||||
public EdgeData() {
|
public EdgeData(TrackEdge edge) {
|
||||||
|
this.edge = edge;
|
||||||
points = new ArrayList<>();
|
points = new ArrayList<>();
|
||||||
|
intersections = new ArrayList<>();
|
||||||
singleSignalGroup = passiveGroup;
|
singleSignalGroup = passiveGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,56 +45,134 @@ public class EdgeData {
|
||||||
return singleSignalGroup == null;
|
return singleSignalGroup == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UUID getSingleSignalGroup() {
|
||||||
|
return singleSignalGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSingleSignalGroup(@Nullable TrackGraph graph, UUID singleSignalGroup) {
|
||||||
|
if (graph != null && !Objects.equal(singleSignalGroup, this.singleSignalGroup))
|
||||||
|
refreshIntersectingSignalGroups(graph);
|
||||||
|
this.singleSignalGroup = singleSignalGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshIntersectingSignalGroups(TrackGraph graph) {
|
||||||
|
Map<UUID, SignalEdgeGroup> groups = Create.RAILWAYS.signalEdgeGroups;
|
||||||
|
for (TrackEdgeIntersection intersection : intersections) {
|
||||||
|
if (intersection.groupId == null)
|
||||||
|
continue;
|
||||||
|
SignalEdgeGroup group = groups.get(intersection.groupId);
|
||||||
|
if (group != null)
|
||||||
|
group.removeIntersection(intersection.id);
|
||||||
|
}
|
||||||
|
if (hasIntersections())
|
||||||
|
graph.deferIntersectionUpdate(edge);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasPoints() {
|
public boolean hasPoints() {
|
||||||
return !points.isEmpty();
|
return !points.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasIntersections() {
|
||||||
|
return !intersections.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TrackEdgeIntersection> getIntersections() {
|
||||||
|
return intersections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addIntersection(TrackGraph graph, UUID id, double position, TrackNode target1, TrackNode target2,
|
||||||
|
double targetPosition) {
|
||||||
|
TrackNodeLocation loc1 = target1.getLocation();
|
||||||
|
TrackNodeLocation loc2 = target2.getLocation();
|
||||||
|
|
||||||
|
for (TrackEdgeIntersection existing : intersections)
|
||||||
|
if (existing.isNear(position) && existing.targets(loc1, loc2))
|
||||||
|
return;
|
||||||
|
|
||||||
|
TrackEdgeIntersection intersection = new TrackEdgeIntersection();
|
||||||
|
intersection.id = id;
|
||||||
|
intersection.location = position;
|
||||||
|
intersection.target = Couple.create(loc1, loc2);
|
||||||
|
intersection.targetLocation = targetPosition;
|
||||||
|
intersections.add(intersection);
|
||||||
|
graph.deferIntersectionUpdate(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeIntersection(TrackGraph graph, UUID id) {
|
||||||
|
refreshIntersectingSignalGroups(graph);
|
||||||
|
for (Iterator<TrackEdgeIntersection> iterator = intersections.iterator(); iterator.hasNext();) {
|
||||||
|
TrackEdgeIntersection existing = iterator.next();
|
||||||
|
if (existing.id.equals(id))
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getGroupAtPosition(TrackGraph graph, double position) {
|
||||||
|
if (!hasSignalBoundaries())
|
||||||
|
return getEffectiveEdgeGroupId(graph);
|
||||||
|
SignalBoundary firstSignal = next(EdgePointType.SIGNAL, 0);
|
||||||
|
UUID currentGroup = firstSignal.getGroup(edge.node1);
|
||||||
|
|
||||||
|
for (TrackEdgePoint trackEdgePoint : getPoints()) {
|
||||||
|
if (!(trackEdgePoint instanceof SignalBoundary sb))
|
||||||
|
continue;
|
||||||
|
if (sb.getLocationOn(edge) >= position)
|
||||||
|
return currentGroup;
|
||||||
|
currentGroup = sb.getGroup(edge.node2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentGroup;
|
||||||
|
}
|
||||||
|
|
||||||
public List<TrackEdgePoint> getPoints() {
|
public List<TrackEdgePoint> getPoints() {
|
||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removePoint(TrackNode node1, TrackNode node2, TrackEdge edge, TrackEdgePoint point) {
|
public UUID getEffectiveEdgeGroupId(TrackGraph graph) {
|
||||||
points.remove(point);
|
return singleSignalGroup == null ? null : singleSignalGroup.equals(passiveGroup) ? graph.id : singleSignalGroup;
|
||||||
if (point.getType() == EdgePointType.SIGNAL)
|
|
||||||
singleSignalGroup = next(point.getType(), node1, node2, edge, 0) == null ? passiveGroup : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends TrackEdgePoint> void addPoint(TrackNode node1, TrackNode node2, TrackEdge edge,
|
public void removePoint(TrackGraph graph, TrackEdgePoint point) {
|
||||||
TrackEdgePoint point) {
|
points.remove(point);
|
||||||
|
if (point.getType() == EdgePointType.SIGNAL) {
|
||||||
|
boolean noSignalsRemaining = next(point.getType(), 0) == null;
|
||||||
|
setSingleSignalGroup(graph, noSignalsRemaining ? passiveGroup : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends TrackEdgePoint> void addPoint(TrackGraph graph, TrackEdgePoint point) {
|
||||||
if (point.getType() == EdgePointType.SIGNAL)
|
if (point.getType() == EdgePointType.SIGNAL)
|
||||||
singleSignalGroup = null;
|
setSingleSignalGroup(graph, null);
|
||||||
double locationOn = point.getLocationOn(node1, node2, edge);
|
double locationOn = point.getLocationOn(edge);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < points.size(); i++)
|
for (; i < points.size(); i++)
|
||||||
if (points.get(i)
|
if (points.get(i)
|
||||||
.getLocationOn(node1, node2, edge) > locationOn)
|
.getLocationOn(edge) > locationOn)
|
||||||
break;
|
break;
|
||||||
points.add(i, point);
|
points.add(i, point);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T extends TrackEdgePoint> T next(EdgePointType<T> type, TrackNode node1, TrackNode node2, TrackEdge edge,
|
public <T extends TrackEdgePoint> T next(EdgePointType<T> type, double minPosition) {
|
||||||
double minPosition) {
|
|
||||||
for (TrackEdgePoint point : points)
|
for (TrackEdgePoint point : points)
|
||||||
if (point.getType() == type && point.getLocationOn(node1, node2, edge) > minPosition)
|
if (point.getType() == type && point.getLocationOn(edge) > minPosition)
|
||||||
return (T) point;
|
return (T) point;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public TrackEdgePoint next(TrackNode node1, TrackNode node2, TrackEdge edge, double minPosition) {
|
public TrackEdgePoint next(double minPosition) {
|
||||||
for (TrackEdgePoint point : points)
|
for (TrackEdgePoint point : points)
|
||||||
if (point.getLocationOn(node1, node2, edge) > minPosition)
|
if (point.getLocationOn(edge) > minPosition)
|
||||||
return point;
|
return point;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public <T extends TrackEdgePoint> T get(EdgePointType<T> type, TrackNode node1, TrackNode node2, TrackEdge edge,
|
public <T extends TrackEdgePoint> T get(EdgePointType<T> type, double exactPosition) {
|
||||||
double exactPosition) {
|
T next = next(type, exactPosition - .5f);
|
||||||
T next = next(type, node1, node2, edge, exactPosition - .5f);
|
if (next != null && Mth.equal(next.getLocationOn(edge), exactPosition))
|
||||||
if (next != null && Mth.equal(next.getLocationOn(node1, node2, edge), exactPosition))
|
|
||||||
return next;
|
return next;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -103,11 +193,13 @@ public class EdgeData {
|
||||||
.toString());
|
.toString());
|
||||||
return tag;
|
return tag;
|
||||||
}));
|
}));
|
||||||
|
if (hasIntersections())
|
||||||
|
nbt.put("Intersections", NBTHelper.writeCompoundList(intersections, TrackEdgeIntersection::write));
|
||||||
return nbt;
|
return nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EdgeData read(CompoundTag nbt, TrackGraph graph) {
|
public static EdgeData read(CompoundTag nbt, TrackEdge edge, TrackGraph graph) {
|
||||||
EdgeData data = new EdgeData();
|
EdgeData data = new EdgeData(edge);
|
||||||
if (nbt.contains("SignalGroup"))
|
if (nbt.contains("SignalGroup"))
|
||||||
data.singleSignalGroup = nbt.getUUID("SignalGroup");
|
data.singleSignalGroup = nbt.getUUID("SignalGroup");
|
||||||
else if (!nbt.contains("PassiveGroup"))
|
else if (!nbt.contains("PassiveGroup"))
|
||||||
|
@ -123,6 +215,9 @@ public class EdgeData {
|
||||||
if (point != null)
|
if (point != null)
|
||||||
data.points.add(point);
|
data.points.add(point);
|
||||||
});
|
});
|
||||||
|
if (nbt.contains("Intersections"))
|
||||||
|
data.intersections =
|
||||||
|
NBTHelper.readCompoundList(nbt.getList("Intersections", Tag.TAG_COMPOUND), TrackEdgeIntersection::read);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class EdgePointManager {
|
||||||
TrackNode node2 = startNodes.get(!front);
|
TrackNode node2 = startNodes.get(!front);
|
||||||
TrackEdge startEdge = startEdges.get(front);
|
TrackEdge startEdge = startEdges.get(front);
|
||||||
startEdge.getEdgeData()
|
startEdge.getEdgeData()
|
||||||
.addPoint(node1, node2, startEdge, point);
|
.addPoint(graph, point);
|
||||||
Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge);
|
Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ public class EdgePointManager {
|
||||||
if (trackEdge == null)
|
if (trackEdge == null)
|
||||||
return;
|
return;
|
||||||
trackEdge.getEdgeData()
|
trackEdge.getEdgeData()
|
||||||
.removePoint(l1, l2, trackEdge, point);
|
.removePoint(graph, point);
|
||||||
Create.RAILWAYS.sync.edgeDataChanged(graph, l1, l2, trackEdge);
|
Create.RAILWAYS.sync.edgeDataChanged(graph, l1, l2, trackEdge);
|
||||||
}, startNodes.swap());
|
}, startNodes.swap());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||||
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.NbtUtils;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
|
||||||
|
public class TrackEdgeIntersection {
|
||||||
|
|
||||||
|
public double location;
|
||||||
|
public Couple<TrackNodeLocation> target;
|
||||||
|
public double targetLocation;
|
||||||
|
public UUID groupId;
|
||||||
|
public UUID id;
|
||||||
|
|
||||||
|
public TrackEdgeIntersection() {
|
||||||
|
id = UUID.randomUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNear(double location) {
|
||||||
|
return Math.abs(location - this.location) < 1 / 32f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean targets(TrackNodeLocation target1, TrackNodeLocation target2) {
|
||||||
|
return target1.equals(target.getFirst()) && target2.equals(target.getSecond())
|
||||||
|
|| target1.equals(target.getSecond()) && target2.equals(target.getFirst());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag write() {
|
||||||
|
CompoundTag nbt = new CompoundTag();
|
||||||
|
nbt.putUUID("Id", id);
|
||||||
|
if (groupId != null)
|
||||||
|
nbt.putUUID("GroupId", groupId);
|
||||||
|
nbt.putDouble("Location", location);
|
||||||
|
nbt.putDouble("TargetLocation", targetLocation);
|
||||||
|
nbt.put("TargetEdge", target.serializeEach(loc -> NbtUtils.writeBlockPos(new BlockPos(loc))));
|
||||||
|
return nbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TrackEdgeIntersection read(CompoundTag nbt) {
|
||||||
|
TrackEdgeIntersection intersection = new TrackEdgeIntersection();
|
||||||
|
intersection.id = nbt.getUUID("Id");
|
||||||
|
if (nbt.contains("GroupId"))
|
||||||
|
intersection.groupId = nbt.getUUID("GroupId");
|
||||||
|
intersection.location = nbt.getDouble("Location");
|
||||||
|
intersection.targetLocation = nbt.getDouble("TargetLocation");
|
||||||
|
intersection.target = Couple.deserializeEach(nbt.getList("TargetEdge", Tag.TAG_COMPOUND),
|
||||||
|
tag -> TrackNodeLocation.fromPackedPos(NbtUtils.readBlockPos(tag)));
|
||||||
|
return intersection;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -149,13 +149,13 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
||||||
if (edge == null)
|
if (edge == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
double length = edge.getLength(node1, node2);
|
double length = edge.getLength();
|
||||||
CompoundTag data = migrationData;
|
CompoundTag data = migrationData;
|
||||||
migrationData = null;
|
migrationData = null;
|
||||||
|
|
||||||
{
|
{
|
||||||
orthogonal = targetBezier == null;
|
orthogonal = targetBezier == null;
|
||||||
Vec3 direction = edge.getDirection(node1, node2, true);
|
Vec3 direction = edge.getDirection(true);
|
||||||
int nonZeroComponents = 0;
|
int nonZeroComponents = 0;
|
||||||
for (Axis axis : Iterate.axes)
|
for (Axis axis : Iterate.axes)
|
||||||
nonZeroComponents += direction.get(axis) != 0 ? 1 : 0;
|
nonZeroComponents += direction.get(axis) != 0 ? 1 : 0;
|
||||||
|
@ -165,7 +165,7 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
||||||
EdgeData signalData = edge.getEdgeData();
|
EdgeData signalData = edge.getEdgeData();
|
||||||
if (signalData.hasPoints()) {
|
if (signalData.hasPoints()) {
|
||||||
for (EdgePointType<?> otherType : EdgePointType.TYPES.values()) {
|
for (EdgePointType<?> otherType : EdgePointType.TYPES.values()) {
|
||||||
TrackEdgePoint otherPoint = signalData.get(otherType, node1, node2, edge, loc.position);
|
TrackEdgePoint otherPoint = signalData.get(otherType, loc.position);
|
||||||
if (otherPoint == null)
|
if (otherPoint == null)
|
||||||
continue;
|
continue;
|
||||||
if (otherType != edgePointType) {
|
if (otherType != edgePointType) {
|
||||||
|
|
|
@ -202,7 +202,7 @@ public class TrackTargetingBlockItem extends BlockItem {
|
||||||
double edgePosition = location.position;
|
double edgePosition = location.position;
|
||||||
|
|
||||||
for (TrackEdgePoint edgePoint : edgeData.getPoints()) {
|
for (TrackEdgePoint edgePoint : edgeData.getPoints()) {
|
||||||
double otherEdgePosition = edgePoint.getLocationOn(nodes.getFirst(), nodes.getSecond(), edge);
|
double otherEdgePosition = edgePoint.getLocationOn(edge);
|
||||||
double distance = Math.abs(edgePosition - otherEdgePosition);
|
double distance = Math.abs(edgePosition - otherEdgePosition);
|
||||||
if (distance > .75)
|
if (distance > .75)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.content.logistics.trains.GraphLocation;
|
import com.simibubi.create.content.logistics.trains.GraphLocation;
|
||||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType;
|
||||||
|
@ -47,9 +48,13 @@ public class TrackTargetingClient {
|
||||||
BezierTrackPointLocation hoveredBezier = null;
|
BezierTrackPointLocation hoveredBezier = null;
|
||||||
|
|
||||||
ItemStack stack = player.getMainHandItem();
|
ItemStack stack = player.getMainHandItem();
|
||||||
if (stack.getItem() instanceof TrackTargetingBlockItem ttbi)
|
if (stack.getItem()instanceof TrackTargetingBlockItem ttbi)
|
||||||
type = ttbi.getType(stack);
|
type = ttbi.getType(stack);
|
||||||
|
|
||||||
|
if (type == EdgePointType.SIGNAL)
|
||||||
|
Create.RAILWAYS.sided(null)
|
||||||
|
.tickSignalOverlay();
|
||||||
|
|
||||||
boolean alreadySelected = stack.hasTag() && stack.getTag()
|
boolean alreadySelected = stack.hasTag() && stack.getTag()
|
||||||
.contains("SelectedPos");
|
.contains("SelectedPos");
|
||||||
|
|
||||||
|
@ -78,7 +83,7 @@ public class TrackTargetingClient {
|
||||||
BlockHitResult blockHitResult = (BlockHitResult) hitResult;
|
BlockHitResult blockHitResult = (BlockHitResult) hitResult;
|
||||||
BlockPos pos = blockHitResult.getBlockPos();
|
BlockPos pos = blockHitResult.getBlockPos();
|
||||||
BlockState blockState = mc.level.getBlockState(pos);
|
BlockState blockState = mc.level.getBlockState(pos);
|
||||||
if (blockState.getBlock() instanceof ITrackBlock track) {
|
if (blockState.getBlock()instanceof ITrackBlock track) {
|
||||||
direction = track.getNearestTrackAxis(mc.level, pos, blockState, lookAngle)
|
direction = track.getNearestTrackAxis(mc.level, pos, blockState, lookAngle)
|
||||||
.getSecond() == AxisDirection.POSITIVE;
|
.getSecond() == AxisDirection.POSITIVE;
|
||||||
hovered = pos;
|
hovered = pos;
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.simibubi.create.content.logistics.trains.management.edgePoint.signal;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.utility.Color;
|
||||||
|
|
||||||
|
public enum EdgeGroupColor {
|
||||||
|
|
||||||
|
YELLOW(0xEBC255),
|
||||||
|
GREEN(0x51C054),
|
||||||
|
BLUE(0x5391E1),
|
||||||
|
ORANGE(0xE36E36),
|
||||||
|
LAVENDER(0xCB92BA),
|
||||||
|
RED(0xA43538),
|
||||||
|
CYAN(0x6EDAD9),
|
||||||
|
BROWN(0xA17C58),
|
||||||
|
|
||||||
|
WHITE(0xE5E1DC)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private Color color;
|
||||||
|
private int mask;
|
||||||
|
|
||||||
|
private EdgeGroupColor(int color) {
|
||||||
|
this.color = new Color(color);
|
||||||
|
mask = 1 << ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int strikeFrom(int mask) {
|
||||||
|
if (this == WHITE)
|
||||||
|
return mask;
|
||||||
|
return mask | this.mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color get() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EdgeGroupColor getDefault() {
|
||||||
|
return values()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EdgeGroupColor findNextAvailable(int mask) {
|
||||||
|
EdgeGroupColor[] values = values();
|
||||||
|
for (int i = 0; i < values.length; i++) {
|
||||||
|
if ((mask & 1) == 0)
|
||||||
|
return values[i];
|
||||||
|
mask = mask >> 1;
|
||||||
|
}
|
||||||
|
return WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -45,9 +45,32 @@ public class SignalBoundary extends TrackEdgePoint {
|
||||||
cachedStates = Couple.create(() -> SignalState.INVALID);
|
cachedStates = Couple.create(() -> SignalState.INVALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGroup(TrackNode side, UUID groupId) {
|
public void setGroup(boolean primary, UUID groupId) {
|
||||||
boolean primary = isPrimary(side);
|
UUID previous = groups.get(primary);
|
||||||
|
|
||||||
groups.set(primary, groupId);
|
groups.set(primary, groupId);
|
||||||
|
|
||||||
|
UUID opposite = groups.get(!primary);
|
||||||
|
Map<UUID, SignalEdgeGroup> signalEdgeGroups = Create.RAILWAYS.signalEdgeGroups;
|
||||||
|
|
||||||
|
if (opposite != null && signalEdgeGroups.containsKey(opposite)) {
|
||||||
|
SignalEdgeGroup oppositeGroup = signalEdgeGroups.get(opposite);
|
||||||
|
if (previous != null)
|
||||||
|
oppositeGroup.removeAdjacent(previous);
|
||||||
|
if (groupId != null)
|
||||||
|
oppositeGroup.putAdjacent(groupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupId != null && signalEdgeGroups.containsKey(groupId)) {
|
||||||
|
SignalEdgeGroup group = signalEdgeGroups.get(groupId);
|
||||||
|
if (opposite != null)
|
||||||
|
group.putAdjacent(opposite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupAndUpdate(TrackNode side, UUID groupId) {
|
||||||
|
boolean primary = isPrimary(side);
|
||||||
|
setGroup(primary, groupId);
|
||||||
sidesToUpdate.set(primary, false);
|
sidesToUpdate.set(primary, false);
|
||||||
chainedSignals.set(primary, null);
|
chainedSignals.set(primary, null);
|
||||||
}
|
}
|
||||||
|
@ -60,6 +83,10 @@ public class SignalBoundary extends TrackEdgePoint {
|
||||||
@Override
|
@Override
|
||||||
public void invalidate(LevelAccessor level) {
|
public void invalidate(LevelAccessor level) {
|
||||||
blockEntities.forEach(s -> s.forEach(pos -> invalidateAt(level, pos)));
|
blockEntities.forEach(s -> s.forEach(pos -> invalidateAt(level, pos)));
|
||||||
|
groups.forEach(uuid -> {
|
||||||
|
if (Create.RAILWAYS.signalEdgeGroups.remove(uuid) != null)
|
||||||
|
Create.RAILWAYS.sync.edgeGroupRemoved(uuid);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,51 +1,147 @@
|
||||||
package com.simibubi.create.content.logistics.trains.management.edgePoint.signal;
|
package com.simibubi.create.content.logistics.trains.management.edgePoint.signal;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.mutable.MutableInt;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicates;
|
||||||
import com.simibubi.create.Create;
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.content.logistics.trains.entity.Train;
|
import com.simibubi.create.content.logistics.trains.entity.Train;
|
||||||
import com.simibubi.create.foundation.utility.Color;
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
|
||||||
public class SignalEdgeGroup {
|
public class SignalEdgeGroup {
|
||||||
|
|
||||||
public UUID id;
|
public UUID id;
|
||||||
public Color color;
|
public EdgeGroupColor color;
|
||||||
|
|
||||||
public Set<Train> trains;
|
public Set<Train> trains;
|
||||||
public SignalBoundary reserved;
|
public SignalBoundary reserved;
|
||||||
|
|
||||||
|
public Map<UUID, UUID> intersecting;
|
||||||
|
public Set<SignalEdgeGroup> intersectingResolved;
|
||||||
|
public Set<UUID> adjacent;
|
||||||
|
|
||||||
public SignalEdgeGroup(UUID id) {
|
public SignalEdgeGroup(UUID id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
color = Color.rainbowColor(Create.RANDOM.nextInt());
|
|
||||||
trains = new HashSet<>();
|
trains = new HashSet<>();
|
||||||
|
adjacent = new HashSet<>();
|
||||||
|
intersecting = new HashMap<>();
|
||||||
|
intersectingResolved = new HashSet<>();
|
||||||
|
color = EdgeGroupColor.getDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOccupiedUnless(Train train) {
|
public boolean isOccupiedUnless(Train train) {
|
||||||
|
if (intersectingResolved.isEmpty())
|
||||||
|
walkIntersecting(intersectingResolved::add);
|
||||||
|
for (SignalEdgeGroup group : intersectingResolved)
|
||||||
|
if (group.isThisOccupiedUnless(train))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isThisOccupiedUnless(Train train) {
|
||||||
return reserved != null || trains.size() > 1 || !trains.contains(train) && !trains.isEmpty();
|
return reserved != null || trains.size() > 1 || !trains.contains(train) && !trains.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOccupiedUnless(SignalBoundary boundary) {
|
public boolean isOccupiedUnless(SignalBoundary boundary) {
|
||||||
|
if (intersectingResolved.isEmpty())
|
||||||
|
walkIntersecting(intersectingResolved::add);
|
||||||
|
for (SignalEdgeGroup group : intersectingResolved)
|
||||||
|
if (group.isThisOccupiedUnless(boundary))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isThisOccupiedUnless(SignalBoundary boundary) {
|
||||||
return !trains.isEmpty() || reserved != null && reserved != boundary;
|
return !trains.isEmpty() || reserved != null && reserved != boundary;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOccupied() {
|
public void putIntersection(UUID intersectionId, UUID targetGroup) {
|
||||||
return !trains.isEmpty() || reserved != null;
|
intersecting.put(intersectionId, targetGroup);
|
||||||
|
walkIntersecting(g -> g.intersectingResolved.clear());
|
||||||
|
resolveColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeIntersection(UUID intersectionId) {
|
||||||
|
walkIntersecting(g -> g.intersectingResolved.clear());
|
||||||
|
|
||||||
|
UUID removed = intersecting.remove(intersectionId);
|
||||||
|
SignalEdgeGroup other = Create.RAILWAYS.signalEdgeGroups.get(removed);
|
||||||
|
if (other != null)
|
||||||
|
other.intersecting.remove(intersectionId);
|
||||||
|
|
||||||
|
resolveColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putAdjacent(UUID adjacent) {
|
||||||
|
this.adjacent.add(adjacent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAdjacent(UUID adjacent) {
|
||||||
|
this.adjacent.remove(adjacent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resolveColor() {
|
||||||
|
if (intersectingResolved.isEmpty())
|
||||||
|
walkIntersecting(intersectingResolved::add);
|
||||||
|
|
||||||
|
MutableInt mask = new MutableInt(0);
|
||||||
|
intersectingResolved.forEach(group -> group.adjacent.stream()
|
||||||
|
.map(Create.RAILWAYS.signalEdgeGroups::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(Predicates.not(intersectingResolved::contains))
|
||||||
|
.forEach(adjacent -> mask.setValue(adjacent.color.strikeFrom(mask.getValue()))));
|
||||||
|
|
||||||
|
EdgeGroupColor newColour = EdgeGroupColor.findNextAvailable(mask.getValue());
|
||||||
|
if (newColour == color)
|
||||||
|
return;
|
||||||
|
|
||||||
|
walkIntersecting(group -> Create.RAILWAYS.sync.edgeGroupCreated(group.id, group.color = newColour));
|
||||||
|
Create.RAILWAYS.markTracksDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void walkIntersecting(Consumer<SignalEdgeGroup> callback) {
|
||||||
|
walkIntersectingRec(new HashSet<>(), callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void walkIntersectingRec(Set<SignalEdgeGroup> visited, Consumer<SignalEdgeGroup> callback) {
|
||||||
|
if (!visited.add(this))
|
||||||
|
return;
|
||||||
|
callback.accept(this);
|
||||||
|
for (UUID uuid : intersecting.values()) {
|
||||||
|
SignalEdgeGroup group = Create.RAILWAYS.signalEdgeGroups.get(uuid);
|
||||||
|
if (group != null)
|
||||||
|
group.walkIntersectingRec(visited, callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SignalEdgeGroup read(CompoundTag tag) {
|
public static SignalEdgeGroup read(CompoundTag tag) {
|
||||||
SignalEdgeGroup group = new SignalEdgeGroup(tag.getUUID("Id"));
|
SignalEdgeGroup group = new SignalEdgeGroup(tag.getUUID("Id"));
|
||||||
group.color = new Color(tag.getInt("Color"));
|
group.color = NBTHelper.readEnum(tag, "Color", EdgeGroupColor.class);
|
||||||
|
NBTHelper.iterateCompoundList(tag.getList("Connected", Tag.TAG_COMPOUND),
|
||||||
|
nbt -> group.intersecting.put(nbt.getUUID("Key"), nbt.getUUID("Value")));
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompoundTag write() {
|
public CompoundTag write() {
|
||||||
CompoundTag tag = new CompoundTag();
|
CompoundTag tag = new CompoundTag();
|
||||||
tag.putUUID("Id", id);
|
tag.putUUID("Id", id);
|
||||||
tag.putInt("Color", color.getRGB());
|
NBTHelper.writeEnum(tag, "Color", color);
|
||||||
|
tag.put("Connected", NBTHelper.writeCompoundList(intersecting.entrySet(), e -> {
|
||||||
|
CompoundTag nbt = new CompoundTag();
|
||||||
|
nbt.putUUID("Key", e.getKey());
|
||||||
|
nbt.putUUID("Value", e.getValue());
|
||||||
|
return nbt;
|
||||||
|
}));
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package com.simibubi.create.content.logistics.trains.management.edgePoint.signal;
|
package com.simibubi.create.content.logistics.trains.management.edgePoint.signal;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.simibubi.create.CreateClient;
|
import com.simibubi.create.CreateClient;
|
||||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||||
|
|
||||||
|
@ -14,20 +15,30 @@ import net.minecraftforge.network.NetworkEvent.Context;
|
||||||
|
|
||||||
public class SignalEdgeGroupPacket extends SimplePacketBase {
|
public class SignalEdgeGroupPacket extends SimplePacketBase {
|
||||||
|
|
||||||
Collection<UUID> ids;
|
List<UUID> ids;
|
||||||
|
List<EdgeGroupColor> colors;
|
||||||
boolean add;
|
boolean add;
|
||||||
|
|
||||||
public SignalEdgeGroupPacket(Collection<UUID> ids, boolean add) {
|
public SignalEdgeGroupPacket(UUID id, EdgeGroupColor color) {
|
||||||
|
this(ImmutableList.of(id), ImmutableList.of(color), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SignalEdgeGroupPacket(List<UUID> ids, List<EdgeGroupColor> colors, boolean add) {
|
||||||
this.ids = ids;
|
this.ids = ids;
|
||||||
|
this.colors = colors;
|
||||||
this.add = add;
|
this.add = add;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SignalEdgeGroupPacket(FriendlyByteBuf buffer) {
|
public SignalEdgeGroupPacket(FriendlyByteBuf buffer) {
|
||||||
ids = new ArrayList<>();
|
ids = new ArrayList<>();
|
||||||
|
colors = new ArrayList<>();
|
||||||
add = buffer.readBoolean();
|
add = buffer.readBoolean();
|
||||||
int size = buffer.readVarInt();
|
int size = buffer.readVarInt();
|
||||||
for (int i = 0; i < size; i++)
|
for (int i = 0; i < size; i++)
|
||||||
ids.add(buffer.readUUID());
|
ids.add(buffer.readUUID());
|
||||||
|
size = buffer.readVarInt();
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
colors.add(EdgeGroupColor.values()[buffer.readVarInt()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -35,6 +46,8 @@ public class SignalEdgeGroupPacket extends SimplePacketBase {
|
||||||
buffer.writeBoolean(add);
|
buffer.writeBoolean(add);
|
||||||
buffer.writeVarInt(ids.size());
|
buffer.writeVarInt(ids.size());
|
||||||
ids.forEach(buffer::writeUUID);
|
ids.forEach(buffer::writeUUID);
|
||||||
|
buffer.writeVarInt(colors.size());
|
||||||
|
colors.forEach(c -> buffer.writeVarInt(c.ordinal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,11 +55,18 @@ public class SignalEdgeGroupPacket extends SimplePacketBase {
|
||||||
context.get()
|
context.get()
|
||||||
.enqueueWork(() -> {
|
.enqueueWork(() -> {
|
||||||
Map<UUID, SignalEdgeGroup> signalEdgeGroups = CreateClient.RAILWAYS.signalEdgeGroups;
|
Map<UUID, SignalEdgeGroup> signalEdgeGroups = CreateClient.RAILWAYS.signalEdgeGroups;
|
||||||
|
int i = 0;
|
||||||
for (UUID id : ids) {
|
for (UUID id : ids) {
|
||||||
if (add)
|
if (!add) {
|
||||||
signalEdgeGroups.put(id, new SignalEdgeGroup(id));
|
|
||||||
else
|
|
||||||
signalEdgeGroups.remove(id);
|
signalEdgeGroups.remove(id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SignalEdgeGroup group = new SignalEdgeGroup(id);
|
||||||
|
signalEdgeGroups.put(id, group);
|
||||||
|
if (colors.size() > i)
|
||||||
|
group.color = colors.get(i);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
context.get()
|
context.get()
|
||||||
|
|
|
@ -36,12 +36,21 @@ public class SignalPropagator {
|
||||||
UUID id = signal.groups.get(front);
|
UUID id = signal.groups.get(front);
|
||||||
if (Create.RAILWAYS.signalEdgeGroups.remove(id) != null)
|
if (Create.RAILWAYS.signalEdgeGroups.remove(id) != null)
|
||||||
Create.RAILWAYS.sync.edgeGroupRemoved(id);
|
Create.RAILWAYS.sync.edgeGroupRemoved(id);
|
||||||
|
|
||||||
walkSignals(graph, signal, front, pair -> {
|
walkSignals(graph, signal, front, pair -> {
|
||||||
TrackNode node1 = pair.getFirst();
|
TrackNode node1 = pair.getFirst();
|
||||||
SignalBoundary boundary = pair.getSecond();
|
SignalBoundary boundary = pair.getSecond();
|
||||||
boundary.queueUpdate(node1);
|
boundary.queueUpdate(node1);
|
||||||
return false;
|
return false;
|
||||||
}, Predicates.alwaysFalse(), false);
|
|
||||||
|
}, signalData -> {
|
||||||
|
if (!signalData.hasSignalBoundaries()) {
|
||||||
|
signalData.setSingleSignalGroup(graph, EdgeData.passiveGroup);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +62,15 @@ public class SignalPropagator {
|
||||||
SignalBoundary boundary = pair.getSecond();
|
SignalBoundary boundary = pair.getSecond();
|
||||||
boundary.queueUpdate(node1);
|
boundary.queueUpdate(node1);
|
||||||
return false;
|
return false;
|
||||||
}, Predicates.alwaysFalse(), false);
|
|
||||||
|
}, signalData -> {
|
||||||
|
if (!signalData.hasSignalBoundaries()) {
|
||||||
|
signalData.setSingleSignalGroup(graph, EdgeData.passiveGroup);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void propagateSignalGroup(TrackGraph graph, SignalBoundary signal, boolean front) {
|
public static void propagateSignalGroup(TrackGraph graph, SignalBoundary signal, boolean front) {
|
||||||
|
@ -63,8 +80,7 @@ public class SignalPropagator {
|
||||||
SignalEdgeGroup group = new SignalEdgeGroup(UUID.randomUUID());
|
SignalEdgeGroup group = new SignalEdgeGroup(UUID.randomUUID());
|
||||||
UUID groupId = group.id;
|
UUID groupId = group.id;
|
||||||
globalGroups.put(groupId, group);
|
globalGroups.put(groupId, group);
|
||||||
sync.edgeGroupCreated(groupId);
|
signal.setGroup(front, groupId);
|
||||||
signal.groups.set(front, groupId);
|
|
||||||
sync.pointAdded(graph, signal);
|
sync.pointAdded(graph, signal);
|
||||||
|
|
||||||
walkSignals(graph, signal, front, pair -> {
|
walkSignals(graph, signal, front, pair -> {
|
||||||
|
@ -74,18 +90,22 @@ public class SignalPropagator {
|
||||||
if (currentGroup != null)
|
if (currentGroup != null)
|
||||||
if (globalGroups.remove(currentGroup) != null)
|
if (globalGroups.remove(currentGroup) != null)
|
||||||
sync.edgeGroupRemoved(currentGroup);
|
sync.edgeGroupRemoved(currentGroup);
|
||||||
boundary.setGroup(node1, groupId);
|
boundary.setGroupAndUpdate(node1, groupId);
|
||||||
sync.pointAdded(graph, boundary);
|
sync.pointAdded(graph, boundary);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}, signalData -> {
|
}, signalData -> {
|
||||||
if (signalData.singleSignalGroup != null)
|
UUID singleSignalGroup = signalData.getSingleSignalGroup();
|
||||||
if (globalGroups.remove(signalData.singleSignalGroup) != null)
|
if (singleSignalGroup != null)
|
||||||
sync.edgeGroupRemoved(signalData.singleSignalGroup);
|
if (globalGroups.remove(singleSignalGroup) != null)
|
||||||
signalData.singleSignalGroup = groupId;
|
sync.edgeGroupRemoved(singleSignalGroup);
|
||||||
|
signalData.setSingleSignalGroup(graph, groupId);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
|
group.resolveColor();
|
||||||
|
sync.edgeGroupCreated(groupId, group.color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<UUID, Boolean> collectChainedSignals(TrackGraph graph, SignalBoundary signal, boolean front) {
|
public static Map<UUID, Boolean> collectChainedSignals(TrackGraph graph, SignalBoundary signal, boolean front) {
|
||||||
|
@ -117,14 +137,18 @@ public class SignalPropagator {
|
||||||
|
|
||||||
if (!forCollection) {
|
if (!forCollection) {
|
||||||
notifyTrains(graph, startEdge, oppositeEdge);
|
notifyTrains(graph, startEdge, oppositeEdge);
|
||||||
|
startEdge.getEdgeData()
|
||||||
|
.refreshIntersectingSignalGroups(graph);
|
||||||
Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge, oppositeEdge);
|
Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge, oppositeEdge);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for signal on the same edge
|
// Check for signal on the same edge
|
||||||
SignalBoundary immediateBoundary = startEdge.getEdgeData()
|
SignalBoundary immediateBoundary = startEdge.getEdgeData()
|
||||||
.next(EdgePointType.SIGNAL, node1, node2, startEdge, signal.getLocationOn(node1, node2, startEdge));
|
.next(EdgePointType.SIGNAL, signal.getLocationOn(startEdge));
|
||||||
if (immediateBoundary != null) {
|
if (immediateBoundary != null) {
|
||||||
boundaryCallback.test(Pair.of(node1, immediateBoundary));
|
if (boundaryCallback.test(Pair.of(node1, immediateBoundary)))
|
||||||
|
startEdge.getEdgeData()
|
||||||
|
.refreshIntersectingSignalGroups(graph);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,8 +183,8 @@ public class SignalPropagator {
|
||||||
if (forCollection) {
|
if (forCollection) {
|
||||||
Vec3 currentDirection = graph.getConnectionsFrom(prevNode)
|
Vec3 currentDirection = graph.getConnectionsFrom(prevNode)
|
||||||
.get(currentNode)
|
.get(currentNode)
|
||||||
.getDirection(prevNode, currentNode, false);
|
.getDirection(false);
|
||||||
Vec3 newDirection = edge.getDirection(currentNode, nextNode, true);
|
Vec3 newDirection = edge.getDirection(true);
|
||||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -175,20 +199,21 @@ public class SignalPropagator {
|
||||||
|
|
||||||
// no boundary- update group of edge
|
// no boundary- update group of edge
|
||||||
if (!signalData.hasSignalBoundaries()) {
|
if (!signalData.hasSignalBoundaries()) {
|
||||||
if (!nonBoundaryCallback.test(signalData))
|
if (nonBoundaryCallback.test(signalData)) {
|
||||||
continue;
|
|
||||||
notifyTrains(graph, currentEdge);
|
notifyTrains(graph, currentEdge);
|
||||||
Create.RAILWAYS.sync.edgeDataChanged(graph, currentNode, nextNode, edge, oppositeEdge);
|
Create.RAILWAYS.sync.edgeDataChanged(graph, currentNode, nextNode, edge, oppositeEdge);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// other/own boundary found
|
// other/own boundary found
|
||||||
SignalBoundary nextBoundary =
|
SignalBoundary nextBoundary = signalData.next(EdgePointType.SIGNAL, 0);
|
||||||
signalData.next(EdgePointType.SIGNAL, currentNode, nextNode, currentEdge, 0);
|
|
||||||
if (nextBoundary == null)
|
if (nextBoundary == null)
|
||||||
continue;
|
continue;
|
||||||
if (boundaryCallback.test(Pair.of(currentNode, nextBoundary))) {
|
if (boundaryCallback.test(Pair.of(currentNode, nextBoundary))) {
|
||||||
notifyTrains(graph, edge, oppositeEdge);
|
notifyTrains(graph, edge, oppositeEdge);
|
||||||
|
currentEdge.getEdgeData()
|
||||||
|
.refreshIntersectingSignalGroups(graph);
|
||||||
Create.RAILWAYS.sync.edgeDataChanged(graph, currentNode, nextNode, edge, oppositeEdge);
|
Create.RAILWAYS.sync.edgeDataChanged(graph, currentNode, nextNode, edge, oppositeEdge);
|
||||||
}
|
}
|
||||||
continue EdgeWalk;
|
continue EdgeWalk;
|
||||||
|
|
|
@ -71,8 +71,8 @@ public abstract class TrackEdgePoint {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getLocationOn(TrackNode node1, TrackNode node2, TrackEdge edge) {
|
public double getLocationOn(TrackEdge edge) {
|
||||||
return isPrimary(node1) ? edge.getLength(node1, node2) - position : position;
|
return isPrimary(edge.node1) ? edge.getLength() - position : position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canNavigateVia(TrackNode side) {
|
public boolean canNavigateVia(TrackNode side) {
|
||||||
|
|
|
@ -316,7 +316,7 @@ public class StationTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos));
|
BlockState potentialBogeyState = level.getBlockState(bogeyOffset.offset(currentPos));
|
||||||
if (potentialBogeyState.getBlock() instanceof IBogeyBlock bogey && bogeyIndex < bogeyLocations.length) {
|
if (potentialBogeyState.getBlock()instanceof IBogeyBlock bogey && bogeyIndex < bogeyLocations.length) {
|
||||||
bogeyTypes[bogeyIndex] = bogey;
|
bogeyTypes[bogeyIndex] = bogey;
|
||||||
bogeyLocations[bogeyIndex] = i;
|
bogeyLocations[bogeyIndex] = i;
|
||||||
bogeyIndex++;
|
bogeyIndex++;
|
||||||
|
@ -449,7 +449,7 @@ public class StationTileEntity extends SmartTileEntity {
|
||||||
TrackNode otherNode = entry.getKey();
|
TrackNode otherNode = entry.getKey();
|
||||||
if (edge.isTurn())
|
if (edge.isTurn())
|
||||||
continue;
|
continue;
|
||||||
Vec3 edgeDirection = edge.getDirection(node, otherNode, true);
|
Vec3 edgeDirection = edge.getDirection(true);
|
||||||
if (Mth.equal(edgeDirection.normalize()
|
if (Mth.equal(edgeDirection.normalize()
|
||||||
.dot(directionVec), -1d))
|
.dot(directionVec), -1d))
|
||||||
secondNode = otherNode;
|
secondNode = otherNode;
|
||||||
|
@ -638,7 +638,7 @@ public class StationTileEntity extends SmartTileEntity {
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
BlockState target = edgePoint.getTrackBlockState();
|
BlockState target = edgePoint.getTrackBlockState();
|
||||||
if (!(target.getBlock() instanceof ITrackBlock def))
|
if (!(target.getBlock()instanceof ITrackBlock def))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Vec3 axis = null;
|
Vec3 axis = null;
|
||||||
|
|
|
@ -302,6 +302,20 @@ public class VecHelper {
|
||||||
.add(p2.scale(3 * t * t));
|
.add(p2.scale(3 * t * t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static double[] intersectRanged(Vec3 p1, Vec3 q1, Vec3 p2, Vec3 q2, Axis plane) {
|
||||||
|
Vec3 pDiff = p2.subtract(p1);
|
||||||
|
Vec3 qDiff = q2.subtract(q1);
|
||||||
|
double[] intersect = intersect(p1, q1, pDiff.normalize(), qDiff.normalize(), plane);
|
||||||
|
if (intersect == null)
|
||||||
|
return null;
|
||||||
|
if (intersect[0] < 0 || intersect[1] < 0)
|
||||||
|
return null;
|
||||||
|
if (intersect[0] > pDiff.length() || intersect[1] > qDiff.length())
|
||||||
|
return null;
|
||||||
|
return intersect;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static double[] intersect(Vec3 p1, Vec3 p2, Vec3 r, Vec3 s, Axis plane) {
|
public static double[] intersect(Vec3 p1, Vec3 p2, Vec3 r, Vec3 s, Axis plane) {
|
||||||
if (plane == Axis.X) {
|
if (plane == Axis.X) {
|
||||||
|
|
Loading…
Reference in a new issue