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() {
|
||||
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) {
|
||||
|
|
|
@ -13,23 +13,20 @@ import java.util.UUID;
|
|||
import javax.annotation.Nullable;
|
||||
|
||||
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.content.contraptions.KineticDebugger;
|
||||
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.management.display.GlobalTrainDisplayData;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
@ -56,7 +53,14 @@ public class GlobalRailwayManager {
|
|||
loadTrackData(serverPlayer.getServer());
|
||||
trackNetworks.values()
|
||||
.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())
|
||||
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> serverPlayer),
|
||||
new TrainPacket(train, true));
|
||||
|
@ -119,19 +123,32 @@ public class GlobalRailwayManager {
|
|||
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) {
|
||||
trackNetworks.put(graph.id, graph);
|
||||
markTracksDirty();
|
||||
}
|
||||
|
||||
public void removeGraph(TrackGraph railGraph) {
|
||||
trackNetworks.remove(railGraph.id);
|
||||
public void removeGraphAndGroup(TrackGraph graph) {
|
||||
signalEdgeGroups.remove(graph.id);
|
||||
sync.edgeGroupRemoved(graph.id);
|
||||
removeGraph(graph);
|
||||
}
|
||||
|
||||
public void removeGraph(TrackGraph graph) {
|
||||
trackNetworks.remove(graph.id);
|
||||
markTracksDirty();
|
||||
}
|
||||
|
||||
public void updateSplitGraph(TrackGraph graph) {
|
||||
Set<TrackGraph> disconnected = graph.findDisconnectedGraphs(null);
|
||||
disconnected.forEach(this::putGraph);
|
||||
disconnected.forEach(this::putGraphWithDefaultGroup);
|
||||
if (!disconnected.isEmpty()) {
|
||||
sync.graphSplit(graph, disconnected);
|
||||
markTracksDirty();
|
||||
|
@ -159,10 +176,7 @@ public class GlobalRailwayManager {
|
|||
}
|
||||
|
||||
public void tick(Level level) {
|
||||
ResourceLocation location2 = DimensionType.OVERWORLD_LOCATION.location();
|
||||
ResourceLocation location = level.dimension()
|
||||
.location();
|
||||
if (!location.equals(location2))
|
||||
if (level.dimension() != Level.OVERWORLD)
|
||||
return;
|
||||
|
||||
for (SignalEdgeGroup group : signalEdgeGroups.values()) {
|
||||
|
@ -170,8 +184,10 @@ public class GlobalRailwayManager {
|
|||
group.reserved = null;
|
||||
}
|
||||
|
||||
for (TrackGraph graph : trackNetworks.values())
|
||||
for (TrackGraph graph : trackNetworks.values()) {
|
||||
graph.tickPoints(true);
|
||||
graph.resolveIntersectingEdgeGroups(level);
|
||||
}
|
||||
|
||||
tickTrains(level);
|
||||
|
||||
|
@ -182,12 +198,12 @@ public class GlobalRailwayManager {
|
|||
if (GlobalTrainDisplayData.updateTick)
|
||||
GlobalTrainDisplayData.refresh();
|
||||
|
||||
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_K))
|
||||
// trackNetworks.values()
|
||||
// .forEach(TrackGraph::debugViewReserved);
|
||||
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_H) && AllKeys.altDown())
|
||||
// for (TrackGraph trackGraph : trackNetworks.values())
|
||||
// TrackGraphVisualizer.debugViewSignalData(trackGraph);
|
||||
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown())
|
||||
// trackNetworks.values()
|
||||
// .forEach(TrackGraph::debugViewNodes);
|
||||
// for (TrackGraph trackGraph : trackNetworks.values())
|
||||
// TrackGraphVisualizer.debugViewNodes(trackGraph);
|
||||
}
|
||||
|
||||
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() {
|
||||
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_H) && !AllKeys.altDown())
|
||||
trackNetworks.values()
|
||||
.forEach(TrackGraph::debugViewSignalData);
|
||||
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && !AllKeys.altDown())
|
||||
trackNetworks.values()
|
||||
.forEach(TrackGraph::debugViewNodes);
|
||||
if (KineticDebugger.isActive())
|
||||
for (TrackGraph trackGraph : trackNetworks.values())
|
||||
TrackGraphVisualizer.debugViewGraph(trackGraph);
|
||||
}
|
||||
|
||||
public GlobalRailwayManager sided(LevelAccessor level) {
|
||||
|
|
|
@ -6,6 +6,8 @@ import java.util.UUID;
|
|||
|
||||
import com.simibubi.create.Create;
|
||||
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.foundation.utility.NBTHelper;
|
||||
|
||||
|
@ -37,6 +39,7 @@ public class RailwaySavedData extends SavedData {
|
|||
sd.signalEdgeGroups = new HashMap<>();
|
||||
sd.trains = new HashMap<>();
|
||||
Create.LOGGER.info("Loading Railway Information...");
|
||||
|
||||
NBTHelper.iterateCompoundList(nbt.getList("RailGraphs", Tag.TAG_COMPOUND), c -> {
|
||||
TrackGraph graph = TrackGraph.read(c);
|
||||
sd.trackNetworks.put(graph.id, graph);
|
||||
|
@ -49,13 +52,29 @@ public class RailwaySavedData extends SavedData {
|
|||
SignalEdgeGroup group = SignalEdgeGroup.read(c);
|
||||
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;
|
||||
}
|
||||
|
||||
public Map<UUID, TrackGraph> getTrackNetworks() {
|
||||
return trackNetworks;
|
||||
}
|
||||
|
||||
|
||||
public Map<UUID, Train> getTrains() {
|
||||
return trains;
|
||||
}
|
||||
|
|
|
@ -1,22 +1,33 @@
|
|||
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.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class TrackEdge {
|
||||
|
||||
public TrackNode node1;
|
||||
public TrackNode node2;
|
||||
BezierConnection turn;
|
||||
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.edgeData = new EdgeData();
|
||||
}
|
||||
|
||||
public boolean isTurn() {
|
||||
|
@ -31,29 +42,112 @@ public class TrackEdge {
|
|||
return turn;
|
||||
}
|
||||
|
||||
public Vec3 getDirection(TrackNode node1, TrackNode node2, boolean fromFirst) {
|
||||
return getPosition(node1, node2, fromFirst ? 0.25f : 1)
|
||||
.subtract(getPosition(node1, node2, fromFirst ? 0 : 0.75f))
|
||||
public Vec3 getDirection(boolean fromFirst) {
|
||||
return getPosition(fromFirst ? 0.25f : 1).subtract(getPosition(fromFirst ? 0 : 0.75f))
|
||||
.normalize();
|
||||
}
|
||||
|
||||
public double getLength(TrackNode node1, TrackNode node2) {
|
||||
public double getLength() {
|
||||
return isTurn() ? turn.getLength()
|
||||
: node1.location.getLocation()
|
||||
.distanceTo(node2.location.getLocation());
|
||||
}
|
||||
|
||||
public double incrementT(TrackNode node1, TrackNode node2, double currentT, double distance) {
|
||||
boolean tooFar = Math.abs(distance) > 5;
|
||||
distance = distance / getLength(node1, node2);
|
||||
public double incrementT(double currentT, double distance) {
|
||||
boolean tooFar = Math.abs(distance) > 5;
|
||||
distance = distance / getLength();
|
||||
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))
|
||||
: 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) {
|
||||
return isTurn() ? turn.getNormal(Mth.clamp(t, 0, 1)) : node1.getNormal();
|
||||
}
|
||||
|
@ -65,7 +159,7 @@ public class TrackEdge {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
@ -76,8 +170,8 @@ public class TrackEdge {
|
|||
|
||||
public static TrackEdge read(CompoundTag tag, TrackGraph graph) {
|
||||
TrackEdge trackEdge =
|
||||
new TrackEdge(tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null);
|
||||
trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), graph);
|
||||
new TrackEdge(null, null, tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null);
|
||||
trackEdge.edgeData = EdgeData.read(tag.getCompound("Signals"), trackEdge, graph);
|
||||
return trackEdge;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,34 +16,28 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
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.TrackNodeLocation.DiscoveredLocation;
|
||||
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.EdgePointManager;
|
||||
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.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.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.Couple;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
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.phys.Vec3;
|
||||
|
||||
|
@ -58,6 +52,9 @@ public class TrackGraph {
|
|||
Map<Integer, TrackNode> nodesById;
|
||||
Map<TrackNode, Map<TrackNode, TrackEdge>> connectionsByNode;
|
||||
EdgePointStorage edgePoints;
|
||||
Map<ResourceKey<Level>, TrackGraphBounds> bounds;
|
||||
|
||||
List<TrackEdge> deferredIntersectionUpdates;
|
||||
|
||||
public TrackGraph() {
|
||||
this(UUID.randomUUID());
|
||||
|
@ -67,8 +64,10 @@ public class TrackGraph {
|
|||
setId(graphID);
|
||||
nodes = new HashMap<>();
|
||||
nodesById = new HashMap<>();
|
||||
bounds = new HashMap<>();
|
||||
connectionsByNode = new IdentityHashMap<>();
|
||||
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() {
|
||||
return nodes.keySet();
|
||||
}
|
||||
|
@ -125,6 +134,7 @@ public class TrackGraph {
|
|||
return false;
|
||||
TrackNode newNode = nodes.get(location);
|
||||
Create.RAILWAYS.sync.nodeAdded(this, newNode);
|
||||
invalidateBounds();
|
||||
markDirty();
|
||||
return true;
|
||||
}
|
||||
|
@ -165,17 +175,30 @@ public class TrackGraph {
|
|||
}
|
||||
|
||||
nodesById.remove(removed.netId);
|
||||
invalidateBounds();
|
||||
|
||||
if (!connectionsByNode.containsKey(removed))
|
||||
return true;
|
||||
|
||||
Map<TrackNode, TrackEdge> connections = connectionsByNode.remove(removed);
|
||||
for (TrackEdge trackEdge : connections.values())
|
||||
for (TrackEdgePoint point : trackEdge.getEdgeData()
|
||||
.getPoints()) {
|
||||
for (Entry<TrackNode, TrackEdge> entry : connections.entrySet()) {
|
||||
TrackEdge trackEdge = entry.getValue();
|
||||
EdgeData edgeData = trackEdge.getEdgeData();
|
||||
for (TrackEdgePoint point : edgeData.getPoints()) {
|
||||
if (level != null)
|
||||
point.invalidate(level);
|
||||
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())
|
||||
if (connectionsByNode.containsKey(railNode))
|
||||
|
@ -185,6 +208,29 @@ public class TrackGraph {
|
|||
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() {
|
||||
return netIdGenerator.incrementAndGet();
|
||||
}
|
||||
|
@ -209,6 +255,7 @@ public class TrackGraph {
|
|||
edgePoints.transferAll(toOther, toOther.edgePoints);
|
||||
nodes.clear();
|
||||
connectionsByNode.clear();
|
||||
toOther.invalidateBounds();
|
||||
|
||||
Map<UUID, Train> trains = Create.RAILWAYS.trains;
|
||||
for (Iterator<UUID> iterator = trains.keySet()
|
||||
|
@ -268,6 +315,7 @@ public class TrackGraph {
|
|||
|
||||
public void transfer(TrackNode node, TrackGraph target) {
|
||||
target.addNode(node);
|
||||
target.invalidateBounds();
|
||||
|
||||
TrackNodeLocation nodeLoc = node.getLocation();
|
||||
Map<TrackNode, TrackEdge> connections = getConnectionsFrom(node);
|
||||
|
@ -298,6 +346,7 @@ public class TrackGraph {
|
|||
nodes.remove(nodeLoc);
|
||||
nodesById.remove(node.getNetId());
|
||||
connectionsByNode.remove(node);
|
||||
invalidateBounds();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
|
@ -312,16 +361,66 @@ public class TrackGraph {
|
|||
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 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(node2, node1, edge2);
|
||||
|
||||
Create.RAILWAYS.sync.edgeAdded(this, node1, node2, edge);
|
||||
Create.RAILWAYS.sync.edgeAdded(this, node2, node1, edge2);
|
||||
|
||||
markDirty();
|
||||
}
|
||||
|
||||
|
@ -343,6 +442,47 @@ public class TrackGraph {
|
|||
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() {
|
||||
Create.RAILWAYS.markTracksDirty();
|
||||
}
|
||||
|
@ -418,6 +558,8 @@ public class TrackGraph {
|
|||
NBTHelper.iterateCompoundList(nodeTag.getList("Connections", Tag.TAG_COMPOUND), c -> {
|
||||
TrackNode node2 = indexTracker.get(c.getInt("To"));
|
||||
TrackEdge edge = TrackEdge.read(c.getCompound("EdgeData"), graph);
|
||||
edge.node1 = node1;
|
||||
edge.node2 = node2;
|
||||
graph.putConnection(node1, node2, edge);
|
||||
});
|
||||
}
|
||||
|
@ -425,300 +567,4 @@ public class TrackGraph {
|
|||
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,
|
||||
Vec3 targetAxis) {
|
||||
BlockState trackBlockState = level.getBlockState(pos);
|
||||
if (!(trackBlockState.getBlock() instanceof ITrackBlock track))
|
||||
if (!(trackBlockState.getBlock()instanceof ITrackBlock track))
|
||||
return null;
|
||||
|
||||
Vec3 axis = targetAxis.scale(targetDirection.getStep());
|
||||
|
@ -44,7 +44,7 @@ public class TrackGraphHelper {
|
|||
for (Entry<TrackNode, TrackEdge> entry : connectionsFrom.entrySet()) {
|
||||
TrackNode backNode = entry.getKey();
|
||||
Vec3 direction = entry.getValue()
|
||||
.getDirection(node, backNode, true);
|
||||
.getDirection(true);
|
||||
if (direction.scale(length)
|
||||
.distanceToSqr(axis.scale(-1)) > 1 / 4096f)
|
||||
continue;
|
||||
|
@ -133,9 +133,9 @@ public class TrackGraphHelper {
|
|||
BezierTrackPointLocation targetBezier) {
|
||||
BlockState state = level.getBlockState(pos);
|
||||
|
||||
if (!(state.getBlock() instanceof ITrackBlock track))
|
||||
if (!(state.getBlock()instanceof ITrackBlock track))
|
||||
return null;
|
||||
if (!(level.getBlockEntity(pos) instanceof TrackTileEntity trackTE))
|
||||
if (!(level.getBlockEntity(pos)instanceof TrackTileEntity trackTE))
|
||||
return null;
|
||||
BezierConnection bc = trackTE.getConnections()
|
||||
.get(targetBezier.curveTarget());
|
||||
|
@ -163,7 +163,7 @@ public class TrackGraphHelper {
|
|||
graphLocation.position = (targetBezier.segment() + 1) / 2f;
|
||||
if (targetDirection == AxisDirection.POSITIVE) {
|
||||
graphLocation.edge = graphLocation.edge.swap();
|
||||
graphLocation.position = edge.getLength(node, targetNode) - graphLocation.position;
|
||||
graphLocation.position = edge.getLength() - graphLocation.position;
|
||||
}
|
||||
|
||||
return graphLocation;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.simibubi.create.content.logistics.trains;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
@ -11,6 +11,7 @@ import javax.annotation.Nullable;
|
|||
import com.google.common.collect.ImmutableList;
|
||||
import com.simibubi.create.Create;
|
||||
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.TrackEdgePoint;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
|
@ -87,16 +88,18 @@ public class TrackGraphSync {
|
|||
|
||||
//
|
||||
|
||||
public void sendEdgeGroups(Collection<UUID> ids, ServerPlayer player) {
|
||||
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), new SignalEdgeGroupPacket(ids, true));
|
||||
public void sendEdgeGroups(List<UUID> ids, List<EdgeGroupColor> colors, ServerPlayer player) {
|
||||
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player),
|
||||
new SignalEdgeGroupPacket(ids, colors, true));
|
||||
}
|
||||
|
||||
public void edgeGroupCreated(UUID id) {
|
||||
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new SignalEdgeGroupPacket(ImmutableList.of(id), true));
|
||||
public void edgeGroupCreated(UUID id, EdgeGroupColor color) {
|
||||
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new SignalEdgeGroupPacket(id, color));
|
||||
}
|
||||
|
||||
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) {
|
||||
Couple<TrackNode> nodes = pair.getFirst()
|
||||
.map(graph::getNode);
|
||||
if (nodes.getFirst() != null && nodes.getSecond() != null)
|
||||
graph.putConnection(nodes.getFirst(), nodes.getSecond(), pair.getSecond());
|
||||
TrackNode node1 = nodes.getFirst();
|
||||
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)
|
||||
|
@ -203,13 +209,13 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
|||
if (edge == null)
|
||||
continue;
|
||||
|
||||
EdgeData edgeData = new EdgeData();
|
||||
EdgeData edgeData = new EdgeData(edge);
|
||||
if (groupType == NULL_GROUP)
|
||||
edgeData.singleSignalGroup = null;
|
||||
edgeData.setSingleSignalGroup(null, null);
|
||||
else if (groupType == PASSIVE_GROUP)
|
||||
edgeData.singleSignalGroup = EdgeData.passiveGroup;
|
||||
edgeData.setSingleSignalGroup(null, EdgeData.passiveGroup);
|
||||
else
|
||||
edgeData.singleSignalGroup = idList.get(0);
|
||||
edgeData.setSingleSignalGroup(null, idList.get(0));
|
||||
|
||||
List<TrackEdgePoint> points = edgeData.getPoints();
|
||||
edge.edgeData = edgeData;
|
||||
|
@ -232,9 +238,9 @@ public class TrackGraphSyncPacket extends TrackGraphPacket {
|
|||
List<UUID> list = new ArrayList<>();
|
||||
EdgeData edgeData = edge.getEdgeData();
|
||||
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)
|
||||
list.add(edgeData.singleSignalGroup);
|
||||
list.add(edgeData.getSingleSignalGroup());
|
||||
for (TrackEdgePoint point : edgeData.getPoints())
|
||||
list.add(point.getId());
|
||||
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) {
|
||||
if (!(state.getBlock()instanceof ITrackBlock track))
|
||||
if (!(state.getBlock() instanceof ITrackBlock track))
|
||||
return;
|
||||
|
||||
Collection<DiscoveredLocation> ends = track.getConnected(reader, pos, state, false, null);
|
||||
|
@ -51,7 +51,7 @@ public class TrackPropagator {
|
|||
sync.nodeRemoved(foundGraph, removedNode);
|
||||
if (!foundGraph.isEmpty())
|
||||
continue;
|
||||
manager.removeGraph(foundGraph);
|
||||
manager.removeGraphAndGroup(foundGraph);
|
||||
sync.graphRemoved(foundGraph);
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class TrackPropagator {
|
|||
}
|
||||
|
||||
public static TrackGraph onRailAdded(LevelAccessor reader, BlockPos pos, BlockState state) {
|
||||
if (!(state.getBlock()instanceof ITrackBlock track))
|
||||
if (!(state.getBlock() instanceof ITrackBlock track))
|
||||
return null;
|
||||
|
||||
// 1. Remove all immediately reachable node locations
|
||||
|
@ -124,7 +124,7 @@ public class TrackPropagator {
|
|||
TrackGraph railGraph = iterator.next();
|
||||
if (!railGraph.isEmpty() || connectedGraphs.size() == 1)
|
||||
continue;
|
||||
manager.removeGraph(railGraph);
|
||||
manager.removeGraphAndGroup(railGraph);
|
||||
sync.graphRemoved(railGraph);
|
||||
iterator.remove();
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ public class TrackPropagator {
|
|||
graph = other;
|
||||
else {
|
||||
other.transferAll(graph);
|
||||
manager.removeGraph(other);
|
||||
manager.removeGraphAndGroup(other);
|
||||
sync.graphRemoved(other);
|
||||
}
|
||||
} else if (connectedGraphs.size() == 1) {
|
||||
|
@ -144,7 +144,7 @@ public class TrackPropagator {
|
|||
.findFirst()
|
||||
.get();
|
||||
} else
|
||||
manager.putGraph(graph = new TrackGraph());
|
||||
manager.putGraphWithDefaultGroup(graph = new TrackGraph());
|
||||
|
||||
DiscoveredLocation startNode = null;
|
||||
|
||||
|
@ -191,7 +191,7 @@ public class TrackPropagator {
|
|||
|
||||
if (isValidGraphNodeLocation(entry.currentNode, ends, first) && entry.currentNode != startNode) {
|
||||
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));
|
||||
parentNode = entry.currentNode;
|
||||
if (!nodeIsNew)
|
||||
|
|
|
@ -239,8 +239,8 @@ public class CarriageSyncData {
|
|||
TravellingPoint toApproach = pointsToApproach[index];
|
||||
|
||||
point.travel(graph, partial * f,
|
||||
point.follow(toApproach, b -> success.setValue(success.booleanValue() && b)), point.ignoreEdgePoints(),
|
||||
point.ignoreTurns());
|
||||
point.follow(toApproach, b -> success.setValue(success.booleanValue() && b)),
|
||||
point.ignoreEdgePoints(), point.ignoreTurns());
|
||||
|
||||
// could not pathfind to server location
|
||||
if (!success.booleanValue()) {
|
||||
|
@ -284,8 +284,7 @@ public class CarriageSyncData {
|
|||
TrackEdge targetEdge = graph.getConnectionsFrom(targetNode1)
|
||||
.get(targetNode2);
|
||||
|
||||
double distanceToNode2 =
|
||||
forward ? initialEdge.getLength(initialNode1, initialNode2) - current.position : current.position;
|
||||
double distanceToNode2 = forward ? initialEdge.getLength() - current.position : current.position;
|
||||
|
||||
frontier.add(Pair.of(distanceToNode2, Pair.of(Couple.create(initialNode1, initialNode2), initialEdge)));
|
||||
|
||||
|
@ -294,15 +293,12 @@ public class CarriageSyncData {
|
|||
double distance = poll.getFirst();
|
||||
|
||||
Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond();
|
||||
TrackNode node1 = currentEntry.getFirst()
|
||||
.getFirst();
|
||||
TrackNode node2 = currentEntry.getFirst()
|
||||
.getSecond();
|
||||
TrackEdge edge = currentEntry.getSecond();
|
||||
|
||||
if (edge == targetEdge)
|
||||
return (float) (distance
|
||||
- (forward ? edge.getLength(node1, node2) - target.position : target.position));
|
||||
return (float) (distance - (forward ? edge.getLength() - target.position : target.position));
|
||||
|
||||
if (distance > maxDistance)
|
||||
continue;
|
||||
|
@ -310,10 +306,9 @@ public class CarriageSyncData {
|
|||
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
||||
Map<TrackNode, TrackEdge> connectionsFrom = graph.getConnectionsFrom(node2);
|
||||
for (Entry<TrackNode, TrackEdge> entry : connectionsFrom.entrySet()) {
|
||||
TrackNode newNode = entry.getKey();
|
||||
TrackEdge newEdge = entry.getValue();
|
||||
Vec3 currentDirection = edge.getDirection(node1, node2, false);
|
||||
Vec3 newDirection = newEdge.getDirection(node2, newNode, true);
|
||||
Vec3 currentDirection = edge.getDirection(false);
|
||||
Vec3 newDirection = newEdge.getDirection(true);
|
||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||
continue;
|
||||
if (!visited.add(entry.getValue()))
|
||||
|
@ -328,8 +323,7 @@ public class CarriageSyncData {
|
|||
TrackNode newNode = entry.getKey();
|
||||
TrackEdge newEdge = entry.getValue();
|
||||
reachedVia.put(newEdge, Pair.of(validTargets.size() > 1, edge));
|
||||
frontier.add(Pair.of(newEdge.getLength(node2, newNode) + distance,
|
||||
Pair.of(Couple.create(node2, newNode), newEdge)));
|
||||
frontier.add(Pair.of(newEdge.getLength() + distance, Pair.of(Couple.create(node2, newNode), newEdge)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -449,7 +449,7 @@ public class Navigation {
|
|||
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;
|
||||
results.set(forward, new DiscoveredPath((forward ? 1 : -1) * distanceToDestination, cost, currentPath));
|
||||
return true;
|
||||
|
@ -510,12 +510,7 @@ public class Navigation {
|
|||
return false;
|
||||
|
||||
TrackEdge edge = currentEntry.getSecond();
|
||||
TrackNode node1 = currentEntry.getFirst()
|
||||
.getFirst();
|
||||
TrackNode node2 = currentEntry.getFirst()
|
||||
.getSecond();
|
||||
|
||||
double position = edge.getLength(node1, node2) - globalStation.getLocationOn(node1, node2, edge);
|
||||
double position = edge.getLength() - globalStation.getLocationOn(edge);
|
||||
if (distance - position < minDistance)
|
||||
return false;
|
||||
result.setValue(globalStation);
|
||||
|
@ -571,8 +566,7 @@ public class Navigation {
|
|||
TrackNode initialNode2 = forward ? startingPoint.node2 : startingPoint.node1;
|
||||
TrackEdge initialEdge = graph.getConnectionsFrom(initialNode1)
|
||||
.get(initialNode2);
|
||||
double distanceToNode2 = forward ? initialEdge.getLength(initialNode1, initialNode2) - startingPoint.position
|
||||
: startingPoint.position;
|
||||
double distanceToNode2 = forward ? initialEdge.getLength() - startingPoint.position : startingPoint.position;
|
||||
|
||||
frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge));
|
||||
|
||||
|
@ -597,8 +591,7 @@ public class Navigation {
|
|||
EdgeData signalData = edge.getEdgeData();
|
||||
if (signalData.hasPoints()) {
|
||||
for (TrackEdgePoint point : signalData.getPoints()) {
|
||||
if (node1 == initialNode1
|
||||
&& point.getLocationOn(node1, node2, edge) < edge.getLength(node1, node2) - distanceToNode2)
|
||||
if (node1 == initialNode1 && point.getLocationOn(edge) < edge.getLength() - distanceToNode2)
|
||||
continue;
|
||||
if (costRelevant && distance + penalty > maxCost)
|
||||
continue Search;
|
||||
|
@ -624,10 +617,9 @@ public class Navigation {
|
|||
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
||||
Map<TrackNode, TrackEdge> connectionsFrom = graph.getConnectionsFrom(node2);
|
||||
for (Entry<TrackNode, TrackEdge> connection : connectionsFrom.entrySet()) {
|
||||
TrackNode newNode = connection.getKey();
|
||||
TrackEdge newEdge = connection.getValue();
|
||||
Vec3 currentDirection = edge.getDirection(node1, node2, false);
|
||||
Vec3 newDirection = newEdge.getDirection(node2, newNode, true);
|
||||
Vec3 currentDirection = edge.getDirection(false);
|
||||
Vec3 newDirection = newEdge.getDirection(true);
|
||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||
continue;
|
||||
validTargets.add(connection);
|
||||
|
@ -639,7 +631,7 @@ public class Navigation {
|
|||
for (Entry<TrackNode, TrackEdge> target : validTargets) {
|
||||
TrackNode newNode = target.getKey();
|
||||
TrackEdge newEdge = target.getValue();
|
||||
double newDistance = newEdge.getLength(node2, newNode) + distance;
|
||||
double newDistance = newEdge.getLength() + distance;
|
||||
int newPenalty = penalty;
|
||||
reachedVia.putIfAbsent(newEdge, Pair.of(validTargets.size() > 1, Couple.create(node1, node2)));
|
||||
frontier.add(new FrontierEntry(newDistance, newPenalty, node2, newNode, newEdge));
|
||||
|
@ -704,10 +696,10 @@ public class Navigation {
|
|||
destination = graph != null && tag.contains("Destination")
|
||||
? graph.getPoint(EdgePointType.STATION, tag.getUUID("Destination"))
|
||||
: null;
|
||||
|
||||
|
||||
if (destination == null)
|
||||
return;
|
||||
|
||||
|
||||
distanceToDestination = tag.getDouble("DistanceToDestination");
|
||||
distanceStartedAt = tag.getDouble("DistanceStartedAt");
|
||||
destinationBehindTrain = tag.getBoolean("BehindTrain");
|
||||
|
|
|
@ -129,7 +129,7 @@ public class Train {
|
|||
addToSignalGroups(occupiedSignalBlocks.keySet());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (updateSignalBlocks) {
|
||||
updateSignalBlocks = false;
|
||||
collectInitiallyOccupiedSignalBlocks();
|
||||
|
@ -714,15 +714,15 @@ public class Train {
|
|||
MutableObject<UUID> prevGroup = new MutableObject<>(null);
|
||||
|
||||
if (signalData.hasSignalBoundaries()) {
|
||||
SignalBoundary nextBoundary = signalData.next(EdgePointType.SIGNAL, node1, node2, edge, position);
|
||||
SignalBoundary nextBoundary = signalData.next(EdgePointType.SIGNAL, position);
|
||||
if (nextBoundary == null) {
|
||||
double d = 0;
|
||||
SignalBoundary prev = null;
|
||||
SignalBoundary current = signalData.next(EdgePointType.SIGNAL, node1, node2, edge, 0);
|
||||
SignalBoundary current = signalData.next(EdgePointType.SIGNAL, 0);
|
||||
while (current != null) {
|
||||
prev = current;
|
||||
d = current.getLocationOn(node1, node2, edge);
|
||||
current = signalData.next(EdgePointType.SIGNAL, node1, node2, edge, d);
|
||||
d = current.getLocationOn(edge);
|
||||
current = signalData.next(EdgePointType.SIGNAL, d);
|
||||
}
|
||||
if (prev != null) {
|
||||
UUID group = prev.getGroup(node2);
|
||||
|
@ -740,9 +740,12 @@ public class Train {
|
|||
}
|
||||
}
|
||||
|
||||
} else if (signalData.singleSignalGroup != null && allGroups.containsKey(signalData.singleSignalGroup)) {
|
||||
occupy(signalData.singleSignalGroup, null);
|
||||
prevGroup.setValue(signalData.singleSignalGroup);
|
||||
} else {
|
||||
UUID groupId = signalData.getEffectiveEdgeGroupId(graph);
|
||||
if (allGroups.containsKey(groupId)) {
|
||||
occupy(groupId, null);
|
||||
prevGroup.setValue(groupId);
|
||||
}
|
||||
}
|
||||
|
||||
forEachTravellingPointBackwards((tp, d) -> {
|
||||
|
@ -764,9 +767,9 @@ public class Train {
|
|||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
public boolean shouldCarriageSyncThisTick(long gameTicks, int updateInterval) {
|
||||
return (gameTicks + tickOffset) % updateInterval == 0;
|
||||
return (gameTicks + tickOffset) % updateInterval == 0;
|
||||
}
|
||||
|
||||
public Couple<Couple<TrackNode>> getEndpointEdges() {
|
||||
|
|
|
@ -27,8 +27,8 @@ public class TrainMigration {
|
|||
public TrainMigration() {}
|
||||
|
||||
public TrainMigration(TravellingPoint point) {
|
||||
double t = point.position / point.edge.getLength(point.node1, point.node2);
|
||||
fallback = point.edge.getPosition(point.node1, point.node2, t);
|
||||
double t = point.position / point.edge.getLength();
|
||||
fallback = point.edge.getPosition(t);
|
||||
curve = point.edge.isTurn();
|
||||
positionOnOldEdge = point.position;
|
||||
locations = Couple.create(point.node1.getLocation(), point.node2.getLocation());
|
||||
|
@ -71,7 +71,7 @@ public class TrainMigration {
|
|||
continue;
|
||||
TrackNode newNode2 = entry.getKey();
|
||||
float radius = 1 / 64f;
|
||||
Vec3 direction = edge.getDirection(newNode1, newNode2, true);
|
||||
Vec3 direction = edge.getDirection(true);
|
||||
if (!Mth.equal(direction.dot(prevDirection), 1))
|
||||
continue;
|
||||
Vec3 intersectSphere = VecHelper.intersectSphere(nodeVec, direction, fallback, radius);
|
||||
|
@ -80,7 +80,7 @@ public class TrainMigration {
|
|||
if (!Mth.equal(direction.dot(intersectSphere.subtract(nodeVec)
|
||||
.normalize()), 1))
|
||||
continue;
|
||||
double edgeLength = edge.getLength(newNode1, newNode2);
|
||||
double edgeLength = edge.getLength();
|
||||
double position = intersectSphere.distanceTo(nodeVec) - radius;
|
||||
if (Double.isNaN(position))
|
||||
continue;
|
||||
|
|
|
@ -153,9 +153,9 @@ public class TravellingPoint {
|
|||
Entry<TrackNode, TrackEdge> best = null;
|
||||
|
||||
for (Entry<TrackNode, TrackEdge> entry : validTargets) {
|
||||
Vec3 trajectory = edge.getDirection(node1, node2, false);
|
||||
Vec3 trajectory = edge.getDirection(false);
|
||||
Vec3 entryTrajectory = entry.getValue()
|
||||
.getDirection(node2, entry.getKey(), true);
|
||||
.getDirection(true);
|
||||
Vec3 normal = trajectory.cross(upNormal);
|
||||
double dot = normal.dot(entryTrajectory);
|
||||
double diff = Math.abs(direction.targetDot - dot);
|
||||
|
@ -178,14 +178,14 @@ public class TravellingPoint {
|
|||
public double travel(TrackGraph graph, double distance, ITrackSelector trackSelector,
|
||||
IEdgePointListener signalListener, ITurnListener turnListener) {
|
||||
blocked = false;
|
||||
double edgeLength = edge.getLength(node1, node2);
|
||||
double edgeLength = edge.getLength();
|
||||
if (distance == 0)
|
||||
return 0;
|
||||
|
||||
double prevPos = position;
|
||||
double traveled = distance;
|
||||
double currentT = position / edgeLength;
|
||||
double incrementT = edge.incrementT(node1, node2, currentT, distance);
|
||||
double incrementT = edge.incrementT(currentT, distance);
|
||||
position = incrementT * edgeLength;
|
||||
|
||||
// FIXME: using incrementT like this becomes inaccurate at medium-long distances
|
||||
|
@ -193,7 +193,7 @@ public class TravellingPoint {
|
|||
// incrementT at their starting position (e.g. bezier turn)
|
||||
// In an ideal scenario the amount added to position would iterate the traversed
|
||||
// edges for context first
|
||||
|
||||
|
||||
// A workaround was added in TrackEdge::incrementT
|
||||
|
||||
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
||||
|
@ -221,8 +221,8 @@ public class TravellingPoint {
|
|||
continue;
|
||||
|
||||
TrackEdge newEdge = entry.getValue();
|
||||
Vec3 currentDirection = edge.getDirection(node1, node2, false);
|
||||
Vec3 newDirection = newEdge.getDirection(node2, newNode, true);
|
||||
Vec3 currentDirection = edge.getDirection(false);
|
||||
Vec3 newDirection = newEdge.getDirection(true);
|
||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||
continue;
|
||||
|
||||
|
@ -258,7 +258,7 @@ public class TravellingPoint {
|
|||
}
|
||||
|
||||
prevPos = 0;
|
||||
edgeLength = edge.getLength(node1, node2);
|
||||
edgeLength = edge.getLength();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -274,8 +274,8 @@ public class TravellingPoint {
|
|||
|
||||
TrackEdge newEdge = graph.getConnectionsFrom(newNode)
|
||||
.get(node1);
|
||||
Vec3 currentDirection = edge.getDirection(node1, node2, true);
|
||||
Vec3 newDirection = newEdge.getDirection(newNode, node1, false);
|
||||
Vec3 currentDirection = edge.getDirection(true);
|
||||
Vec3 newDirection = newEdge.getDirection(false);
|
||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||
continue;
|
||||
|
||||
|
@ -297,7 +297,7 @@ public class TravellingPoint {
|
|||
edge = graph.getConnectionsFrom(node1)
|
||||
.get(node2);
|
||||
collectedDistance += edgeLength;
|
||||
edgeLength = edge.getLength(node1, node2);
|
||||
edgeLength = edge.getLength();
|
||||
position += edgeLength;
|
||||
|
||||
blockedLocation =
|
||||
|
@ -326,11 +326,11 @@ public class TravellingPoint {
|
|||
double to = forward ? position : prevPos;
|
||||
List<TrackEdgePoint> edgePoints = edgeData.getPoints();
|
||||
|
||||
double length = edge.getLength(node1, node2);
|
||||
double length = edge.getLength();
|
||||
for (int i = 0; i < edgePoints.size(); i++) {
|
||||
int index = forward ? i : edgePoints.size() - i - 1;
|
||||
TrackEdgePoint nextBoundary = edgePoints.get(index);
|
||||
double locationOn = nextBoundary.getLocationOn(node1, node2, edge);
|
||||
double locationOn = nextBoundary.getLocationOn(edge);
|
||||
double distance = forward ? locationOn : length - locationOn;
|
||||
if (forward ? (locationOn < from || locationOn >= to) : (locationOn <= from || locationOn > to))
|
||||
continue;
|
||||
|
@ -346,14 +346,14 @@ public class TravellingPoint {
|
|||
TrackNode n = node1;
|
||||
node1 = node2;
|
||||
node2 = n;
|
||||
position = edge.getLength(node1, node2) - position;
|
||||
position = edge.getLength() - position;
|
||||
edge = graph.getConnectionsFrom(node1)
|
||||
.get(node2);
|
||||
}
|
||||
|
||||
public Vec3 getPosition() {
|
||||
double t = position / edge.getLength(node1, node2);
|
||||
return edge.getPosition(node1, node2, t)
|
||||
double t = position / edge.getLength();
|
||||
return edge.getPosition(t)
|
||||
.add(edge.getNormal(node1, node2, t)
|
||||
.scale(1));
|
||||
}
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
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.TrackGraph;
|
||||
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.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
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 UUID singleSignalGroup;
|
||||
private UUID singleSignalGroup;
|
||||
private List<TrackEdgePoint> points;
|
||||
private List<TrackEdgeIntersection> intersections;
|
||||
private TrackEdge edge;
|
||||
|
||||
public EdgeData() {
|
||||
public EdgeData(TrackEdge edge) {
|
||||
this.edge = edge;
|
||||
points = new ArrayList<>();
|
||||
intersections = new ArrayList<>();
|
||||
singleSignalGroup = passiveGroup;
|
||||
}
|
||||
|
||||
|
@ -33,56 +45,134 @@ public class EdgeData {
|
|||
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() {
|
||||
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() {
|
||||
return points;
|
||||
}
|
||||
|
||||
public void removePoint(TrackNode node1, TrackNode node2, TrackEdge edge, TrackEdgePoint point) {
|
||||
points.remove(point);
|
||||
if (point.getType() == EdgePointType.SIGNAL)
|
||||
singleSignalGroup = next(point.getType(), node1, node2, edge, 0) == null ? passiveGroup : null;
|
||||
public UUID getEffectiveEdgeGroupId(TrackGraph graph) {
|
||||
return singleSignalGroup == null ? null : singleSignalGroup.equals(passiveGroup) ? graph.id : singleSignalGroup;
|
||||
}
|
||||
|
||||
public <T extends TrackEdgePoint> void addPoint(TrackNode node1, TrackNode node2, TrackEdge edge,
|
||||
TrackEdgePoint point) {
|
||||
public void removePoint(TrackGraph graph, 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)
|
||||
singleSignalGroup = null;
|
||||
double locationOn = point.getLocationOn(node1, node2, edge);
|
||||
setSingleSignalGroup(graph, null);
|
||||
double locationOn = point.getLocationOn(edge);
|
||||
int i = 0;
|
||||
for (; i < points.size(); i++)
|
||||
if (points.get(i)
|
||||
.getLocationOn(node1, node2, edge) > locationOn)
|
||||
.getLocationOn(edge) > locationOn)
|
||||
break;
|
||||
points.add(i, point);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends TrackEdgePoint> T next(EdgePointType<T> type, TrackNode node1, TrackNode node2, TrackEdge edge,
|
||||
double minPosition) {
|
||||
public <T extends TrackEdgePoint> T next(EdgePointType<T> type, double minPosition) {
|
||||
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 null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TrackEdgePoint next(TrackNode node1, TrackNode node2, TrackEdge edge, double minPosition) {
|
||||
public TrackEdgePoint next(double minPosition) {
|
||||
for (TrackEdgePoint point : points)
|
||||
if (point.getLocationOn(node1, node2, edge) > minPosition)
|
||||
if (point.getLocationOn(edge) > minPosition)
|
||||
return point;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T extends TrackEdgePoint> T get(EdgePointType<T> type, TrackNode node1, TrackNode node2, TrackEdge edge,
|
||||
double exactPosition) {
|
||||
T next = next(type, node1, node2, edge, exactPosition - .5f);
|
||||
if (next != null && Mth.equal(next.getLocationOn(node1, node2, edge), exactPosition))
|
||||
public <T extends TrackEdgePoint> T get(EdgePointType<T> type, double exactPosition) {
|
||||
T next = next(type, exactPosition - .5f);
|
||||
if (next != null && Mth.equal(next.getLocationOn(edge), exactPosition))
|
||||
return next;
|
||||
return null;
|
||||
}
|
||||
|
@ -103,11 +193,13 @@ public class EdgeData {
|
|||
.toString());
|
||||
return tag;
|
||||
}));
|
||||
if (hasIntersections())
|
||||
nbt.put("Intersections", NBTHelper.writeCompoundList(intersections, TrackEdgeIntersection::write));
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static EdgeData read(CompoundTag nbt, TrackGraph graph) {
|
||||
EdgeData data = new EdgeData();
|
||||
public static EdgeData read(CompoundTag nbt, TrackEdge edge, TrackGraph graph) {
|
||||
EdgeData data = new EdgeData(edge);
|
||||
if (nbt.contains("SignalGroup"))
|
||||
data.singleSignalGroup = nbt.getUUID("SignalGroup");
|
||||
else if (!nbt.contains("PassiveGroup"))
|
||||
|
@ -123,6 +215,9 @@ public class EdgeData {
|
|||
if (point != null)
|
||||
data.points.add(point);
|
||||
});
|
||||
if (nbt.contains("Intersections"))
|
||||
data.intersections =
|
||||
NBTHelper.readCompoundList(nbt.getList("Intersections", Tag.TAG_COMPOUND), TrackEdgeIntersection::read);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ public class EdgePointManager {
|
|||
TrackNode node2 = startNodes.get(!front);
|
||||
TrackEdge startEdge = startEdges.get(front);
|
||||
startEdge.getEdgeData()
|
||||
.addPoint(node1, node2, startEdge, point);
|
||||
.addPoint(graph, point);
|
||||
Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ public class EdgePointManager {
|
|||
if (trackEdge == null)
|
||||
return;
|
||||
trackEdge.getEdgeData()
|
||||
.removePoint(l1, l2, trackEdge, point);
|
||||
.removePoint(graph, point);
|
||||
Create.RAILWAYS.sync.edgeDataChanged(graph, l1, l2, trackEdge);
|
||||
}, 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)
|
||||
return null;
|
||||
|
||||
double length = edge.getLength(node1, node2);
|
||||
double length = edge.getLength();
|
||||
CompoundTag data = migrationData;
|
||||
migrationData = null;
|
||||
|
||||
{
|
||||
orthogonal = targetBezier == null;
|
||||
Vec3 direction = edge.getDirection(node1, node2, true);
|
||||
Vec3 direction = edge.getDirection(true);
|
||||
int nonZeroComponents = 0;
|
||||
for (Axis axis : Iterate.axes)
|
||||
nonZeroComponents += direction.get(axis) != 0 ? 1 : 0;
|
||||
|
@ -165,7 +165,7 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
|||
EdgeData signalData = edge.getEdgeData();
|
||||
if (signalData.hasPoints()) {
|
||||
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)
|
||||
continue;
|
||||
if (otherType != edgePointType) {
|
||||
|
|
|
@ -202,7 +202,7 @@ public class TrackTargetingBlockItem extends BlockItem {
|
|||
double edgePosition = location.position;
|
||||
|
||||
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);
|
||||
if (distance > .75)
|
||||
continue;
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
|||
|
||||
import com.google.common.base.Objects;
|
||||
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.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType;
|
||||
|
@ -47,9 +48,13 @@ public class TrackTargetingClient {
|
|||
BezierTrackPointLocation hoveredBezier = null;
|
||||
|
||||
ItemStack stack = player.getMainHandItem();
|
||||
if (stack.getItem() instanceof TrackTargetingBlockItem ttbi)
|
||||
if (stack.getItem()instanceof TrackTargetingBlockItem ttbi)
|
||||
type = ttbi.getType(stack);
|
||||
|
||||
if (type == EdgePointType.SIGNAL)
|
||||
Create.RAILWAYS.sided(null)
|
||||
.tickSignalOverlay();
|
||||
|
||||
boolean alreadySelected = stack.hasTag() && stack.getTag()
|
||||
.contains("SelectedPos");
|
||||
|
||||
|
@ -78,7 +83,7 @@ public class TrackTargetingClient {
|
|||
BlockHitResult blockHitResult = (BlockHitResult) hitResult;
|
||||
BlockPos pos = blockHitResult.getBlockPos();
|
||||
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)
|
||||
.getSecond() == AxisDirection.POSITIVE;
|
||||
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);
|
||||
}
|
||||
|
||||
public void setGroup(TrackNode side, UUID groupId) {
|
||||
boolean primary = isPrimary(side);
|
||||
public void setGroup(boolean primary, UUID groupId) {
|
||||
UUID previous = groups.get(primary);
|
||||
|
||||
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);
|
||||
chainedSignals.set(primary, null);
|
||||
}
|
||||
|
@ -60,8 +83,12 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
@Override
|
||||
public void invalidate(LevelAccessor level) {
|
||||
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
|
||||
public boolean canCoexistWith(EdgePointType<?> otherType, boolean front) {
|
||||
return otherType == getType();
|
||||
|
|
|
@ -1,51 +1,147 @@
|
|||
package com.simibubi.create.content.logistics.trains.management.edgePoint.signal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
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.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.Tag;
|
||||
|
||||
public class SignalEdgeGroup {
|
||||
|
||||
public UUID id;
|
||||
public Color color;
|
||||
public EdgeGroupColor color;
|
||||
|
||||
public Set<Train> trains;
|
||||
public SignalBoundary reserved;
|
||||
|
||||
public Map<UUID, UUID> intersecting;
|
||||
public Set<SignalEdgeGroup> intersectingResolved;
|
||||
public Set<UUID> adjacent;
|
||||
|
||||
public SignalEdgeGroup(UUID id) {
|
||||
this.id = id;
|
||||
color = Color.rainbowColor(Create.RANDOM.nextInt());
|
||||
trains = new HashSet<>();
|
||||
adjacent = new HashSet<>();
|
||||
intersecting = new HashMap<>();
|
||||
intersectingResolved = new HashSet<>();
|
||||
color = EdgeGroupColor.getDefault();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public boolean isOccupied() {
|
||||
return !trains.isEmpty() || reserved != null;
|
||||
public void putIntersection(UUID intersectionId, UUID targetGroup) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package com.simibubi.create.content.logistics.trains.management.edgePoint.signal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
|
@ -14,20 +15,30 @@ import net.minecraftforge.network.NetworkEvent.Context;
|
|||
|
||||
public class SignalEdgeGroupPacket extends SimplePacketBase {
|
||||
|
||||
Collection<UUID> ids;
|
||||
List<UUID> ids;
|
||||
List<EdgeGroupColor> colors;
|
||||
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.colors = colors;
|
||||
this.add = add;
|
||||
}
|
||||
|
||||
public SignalEdgeGroupPacket(FriendlyByteBuf buffer) {
|
||||
ids = new ArrayList<>();
|
||||
colors = new ArrayList<>();
|
||||
add = buffer.readBoolean();
|
||||
int size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++)
|
||||
ids.add(buffer.readUUID());
|
||||
size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++)
|
||||
colors.add(EdgeGroupColor.values()[buffer.readVarInt()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,6 +46,8 @@ public class SignalEdgeGroupPacket extends SimplePacketBase {
|
|||
buffer.writeBoolean(add);
|
||||
buffer.writeVarInt(ids.size());
|
||||
ids.forEach(buffer::writeUUID);
|
||||
buffer.writeVarInt(colors.size());
|
||||
colors.forEach(c -> buffer.writeVarInt(c.ordinal()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,11 +55,18 @@ public class SignalEdgeGroupPacket extends SimplePacketBase {
|
|||
context.get()
|
||||
.enqueueWork(() -> {
|
||||
Map<UUID, SignalEdgeGroup> signalEdgeGroups = CreateClient.RAILWAYS.signalEdgeGroups;
|
||||
int i = 0;
|
||||
for (UUID id : ids) {
|
||||
if (add)
|
||||
signalEdgeGroups.put(id, new SignalEdgeGroup(id));
|
||||
else
|
||||
if (!add) {
|
||||
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()
|
||||
|
|
|
@ -36,12 +36,21 @@ public class SignalPropagator {
|
|||
UUID id = signal.groups.get(front);
|
||||
if (Create.RAILWAYS.signalEdgeGroups.remove(id) != null)
|
||||
Create.RAILWAYS.sync.edgeGroupRemoved(id);
|
||||
|
||||
walkSignals(graph, signal, front, pair -> {
|
||||
TrackNode node1 = pair.getFirst();
|
||||
SignalBoundary boundary = pair.getSecond();
|
||||
boundary.queueUpdate(node1);
|
||||
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();
|
||||
boundary.queueUpdate(node1);
|
||||
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) {
|
||||
|
@ -63,8 +80,7 @@ public class SignalPropagator {
|
|||
SignalEdgeGroup group = new SignalEdgeGroup(UUID.randomUUID());
|
||||
UUID groupId = group.id;
|
||||
globalGroups.put(groupId, group);
|
||||
sync.edgeGroupCreated(groupId);
|
||||
signal.groups.set(front, groupId);
|
||||
signal.setGroup(front, groupId);
|
||||
sync.pointAdded(graph, signal);
|
||||
|
||||
walkSignals(graph, signal, front, pair -> {
|
||||
|
@ -74,18 +90,22 @@ public class SignalPropagator {
|
|||
if (currentGroup != null)
|
||||
if (globalGroups.remove(currentGroup) != null)
|
||||
sync.edgeGroupRemoved(currentGroup);
|
||||
boundary.setGroup(node1, groupId);
|
||||
boundary.setGroupAndUpdate(node1, groupId);
|
||||
sync.pointAdded(graph, boundary);
|
||||
return true;
|
||||
|
||||
}, signalData -> {
|
||||
if (signalData.singleSignalGroup != null)
|
||||
if (globalGroups.remove(signalData.singleSignalGroup) != null)
|
||||
sync.edgeGroupRemoved(signalData.singleSignalGroup);
|
||||
signalData.singleSignalGroup = groupId;
|
||||
UUID singleSignalGroup = signalData.getSingleSignalGroup();
|
||||
if (singleSignalGroup != null)
|
||||
if (globalGroups.remove(singleSignalGroup) != null)
|
||||
sync.edgeGroupRemoved(singleSignalGroup);
|
||||
signalData.setSingleSignalGroup(graph, groupId);
|
||||
return true;
|
||||
|
||||
}, false);
|
||||
|
||||
group.resolveColor();
|
||||
sync.edgeGroupCreated(groupId, group.color);
|
||||
}
|
||||
|
||||
public static Map<UUID, Boolean> collectChainedSignals(TrackGraph graph, SignalBoundary signal, boolean front) {
|
||||
|
@ -117,14 +137,18 @@ public class SignalPropagator {
|
|||
|
||||
if (!forCollection) {
|
||||
notifyTrains(graph, startEdge, oppositeEdge);
|
||||
startEdge.getEdgeData()
|
||||
.refreshIntersectingSignalGroups(graph);
|
||||
Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge, oppositeEdge);
|
||||
}
|
||||
|
||||
// Check for signal on the same edge
|
||||
SignalBoundary immediateBoundary = startEdge.getEdgeData()
|
||||
.next(EdgePointType.SIGNAL, node1, node2, startEdge, signal.getLocationOn(node1, node2, startEdge));
|
||||
.next(EdgePointType.SIGNAL, signal.getLocationOn(startEdge));
|
||||
if (immediateBoundary != null) {
|
||||
boundaryCallback.test(Pair.of(node1, immediateBoundary));
|
||||
if (boundaryCallback.test(Pair.of(node1, immediateBoundary)))
|
||||
startEdge.getEdgeData()
|
||||
.refreshIntersectingSignalGroups(graph);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -159,8 +183,8 @@ public class SignalPropagator {
|
|||
if (forCollection) {
|
||||
Vec3 currentDirection = graph.getConnectionsFrom(prevNode)
|
||||
.get(currentNode)
|
||||
.getDirection(prevNode, currentNode, false);
|
||||
Vec3 newDirection = edge.getDirection(currentNode, nextNode, true);
|
||||
.getDirection(false);
|
||||
Vec3 newDirection = edge.getDirection(true);
|
||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||
continue;
|
||||
}
|
||||
|
@ -175,20 +199,21 @@ public class SignalPropagator {
|
|||
|
||||
// no boundary- update group of edge
|
||||
if (!signalData.hasSignalBoundaries()) {
|
||||
if (!nonBoundaryCallback.test(signalData))
|
||||
continue;
|
||||
notifyTrains(graph, currentEdge);
|
||||
Create.RAILWAYS.sync.edgeDataChanged(graph, currentNode, nextNode, edge, oppositeEdge);
|
||||
if (nonBoundaryCallback.test(signalData)) {
|
||||
notifyTrains(graph, currentEdge);
|
||||
Create.RAILWAYS.sync.edgeDataChanged(graph, currentNode, nextNode, edge, oppositeEdge);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// other/own boundary found
|
||||
SignalBoundary nextBoundary =
|
||||
signalData.next(EdgePointType.SIGNAL, currentNode, nextNode, currentEdge, 0);
|
||||
SignalBoundary nextBoundary = signalData.next(EdgePointType.SIGNAL, 0);
|
||||
if (nextBoundary == null)
|
||||
continue;
|
||||
if (boundaryCallback.test(Pair.of(currentNode, nextBoundary))) {
|
||||
notifyTrains(graph, edge, oppositeEdge);
|
||||
currentEdge.getEdgeData()
|
||||
.refreshIntersectingSignalGroups(graph);
|
||||
Create.RAILWAYS.sync.edgeDataChanged(graph, currentNode, nextNode, edge, oppositeEdge);
|
||||
}
|
||||
continue EdgeWalk;
|
||||
|
|
|
@ -71,8 +71,8 @@ public abstract class TrackEdgePoint {
|
|||
this.position = position;
|
||||
}
|
||||
|
||||
public double getLocationOn(TrackNode node1, TrackNode node2, TrackEdge edge) {
|
||||
return isPrimary(node1) ? edge.getLength(node1, node2) - position : position;
|
||||
public double getLocationOn(TrackEdge edge) {
|
||||
return isPrimary(edge.node1) ? edge.getLength() - position : position;
|
||||
}
|
||||
|
||||
public boolean canNavigateVia(TrackNode side) {
|
||||
|
|
|
@ -316,7 +316,7 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
}
|
||||
|
||||
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;
|
||||
bogeyLocations[bogeyIndex] = i;
|
||||
bogeyIndex++;
|
||||
|
@ -449,7 +449,7 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
TrackNode otherNode = entry.getKey();
|
||||
if (edge.isTurn())
|
||||
continue;
|
||||
Vec3 edgeDirection = edge.getDirection(node, otherNode, true);
|
||||
Vec3 edgeDirection = edge.getDirection(true);
|
||||
if (Mth.equal(edgeDirection.normalize()
|
||||
.dot(directionVec), -1d))
|
||||
secondNode = otherNode;
|
||||
|
@ -638,7 +638,7 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
return true;
|
||||
|
||||
BlockState target = edgePoint.getTrackBlockState();
|
||||
if (!(target.getBlock() instanceof ITrackBlock def))
|
||||
if (!(target.getBlock()instanceof ITrackBlock def))
|
||||
return false;
|
||||
|
||||
Vec3 axis = null;
|
||||
|
|
|
@ -302,6 +302,20 @@ public class VecHelper {
|
|||
.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
|
||||
public static double[] intersect(Vec3 p1, Vec3 p2, Vec3 r, Vec3 s, Axis plane) {
|
||||
if (plane == Axis.X) {
|
||||
|
@ -310,14 +324,14 @@ public class VecHelper {
|
|||
r = new Vec3(r.y, 0, r.z);
|
||||
s = new Vec3(s.y, 0, s.z);
|
||||
}
|
||||
|
||||
|
||||
if (plane == Axis.Z) {
|
||||
p1 = new Vec3(p1.x, 0, p1.y);
|
||||
p2 = new Vec3(p2.x, 0, p2.y);
|
||||
r = new Vec3(r.x, 0, r.y);
|
||||
s = new Vec3(s.x, 0, s.y);
|
||||
}
|
||||
|
||||
|
||||
Vec3 qminusp = p2.subtract(p1);
|
||||
double rcs = r.x * s.z - r.z * s.x;
|
||||
if (Mth.equal(rcs, 0))
|
||||
|
|
Loading…
Reference in a new issue