mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-01-28 22:05:01 +01:00
Signal Station
- Refactored Stations and Signals into a more unified and expandable edge point abstraction - Trains no longer depart a station when a red signal is close by - Fixed inconsistent pathfinding when stations, signals and trains are sharing a graph edge
This commit is contained in:
parent
cf308cdc7f
commit
3362e6a05e
32 changed files with 884 additions and 659 deletions
|
@ -1,6 +1,9 @@
|
|||
package com.simibubi.create.content.logistics.trains;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
@ -118,6 +121,16 @@ public class GlobalRailwayManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
public List<TrackGraph> getGraphs(LevelAccessor level, TrackNodeLocation vertex) {
|
||||
if (trackNetworks == null)
|
||||
return Collections.emptyList();
|
||||
ArrayList<TrackGraph> intersecting = new ArrayList<>();
|
||||
for (TrackGraph railGraph : trackNetworks.values())
|
||||
if (railGraph.locateNode(vertex) != null)
|
||||
intersecting.add(railGraph);
|
||||
return intersecting;
|
||||
}
|
||||
|
||||
public void tick(Level level) {
|
||||
ResourceLocation location2 = DimensionType.OVERWORLD_LOCATION.location();
|
||||
ResourceLocation location = level.dimension()
|
||||
|
@ -131,10 +144,8 @@ public class GlobalRailwayManager {
|
|||
}
|
||||
|
||||
for (TrackGraph graph : trackNetworks.values())
|
||||
graph.getSignals()
|
||||
.forEach(sb -> sb.tick(graph));
|
||||
|
||||
for (Train train : trains.values())
|
||||
graph.tickPoints();
|
||||
for (Train train : trains.values())
|
||||
train.earlyTick(level);
|
||||
for (Train train : trains.values())
|
||||
train.tick(level);
|
||||
|
@ -143,10 +154,14 @@ public class GlobalRailwayManager {
|
|||
trackNetworks.values()
|
||||
.forEach(TrackGraph::debugViewSignalData);
|
||||
}
|
||||
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown()) {
|
||||
trackNetworks.values()
|
||||
.forEach(TrackGraph::debugViewNodes);
|
||||
}
|
||||
}
|
||||
|
||||
public void clientTick() {
|
||||
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J)) {
|
||||
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && !AllKeys.altDown()) {
|
||||
trackNetworks.values()
|
||||
.forEach(TrackGraph::debugViewNodes);
|
||||
}
|
||||
|
|
|
@ -24,12 +24,14 @@ 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.GlobalStation;
|
||||
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.signal.EdgeData;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalBoundary;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalEdgeGroup;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalPropagator;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.TrackEdgePoint;
|
||||
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;
|
||||
|
@ -54,67 +56,47 @@ public class TrackGraph {
|
|||
Map<TrackNodeLocation, TrackNode> nodes;
|
||||
Map<Integer, TrackNode> nodesById;
|
||||
Map<TrackNode, Map<TrackNode, TrackEdge>> connectionsByNode;
|
||||
|
||||
private Map<UUID, GlobalStation> stations;
|
||||
private Map<UUID, SignalBoundary> signals;
|
||||
EdgePointStorage edgePoints;
|
||||
|
||||
public TrackGraph() {
|
||||
this(UUID.randomUUID());
|
||||
}
|
||||
|
||||
public TrackGraph(UUID graphID) {
|
||||
id = graphID;
|
||||
setId(graphID);
|
||||
nodes = new HashMap<>();
|
||||
nodesById = new HashMap<>();
|
||||
connectionsByNode = new IdentityHashMap<>();
|
||||
color = Color.rainbowColor(new Random(graphID.getLeastSignificantBits()).nextInt());
|
||||
stations = new HashMap<>();
|
||||
signals = new HashMap<>();
|
||||
edgePoints = new EdgePointStorage();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Nullable
|
||||
public GlobalStation getStation(UUID id) {
|
||||
return stations.get(id);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SignalBoundary getSignal(UUID id) {
|
||||
return signals.get(id);
|
||||
}
|
||||
|
||||
public Collection<GlobalStation> getStations() {
|
||||
return stations.values();
|
||||
}
|
||||
|
||||
public Collection<SignalBoundary> getSignals() {
|
||||
return signals.values();
|
||||
}
|
||||
|
||||
public void addStation(GlobalStation station) {
|
||||
stations.put(station.id, station);
|
||||
SignalPropagator.onEdgePointAdded(this, station, GlobalStation.class);
|
||||
public <T extends TrackEdgePoint> void addPoint(EdgePointType<T> type, T point) {
|
||||
edgePoints.put(type, point);
|
||||
EdgePointManager.onEdgePointAdded(this, point, type);
|
||||
markDirty();
|
||||
}
|
||||
|
||||
public void addSignal(SignalBoundary signal) {
|
||||
signals.put(signal.id, signal);
|
||||
SignalPropagator.onEdgePointAdded(this, signal, SignalBoundary.class);
|
||||
markDirty();
|
||||
public <T extends TrackEdgePoint> T getPoint(EdgePointType<T> type, UUID id) {
|
||||
return edgePoints.get(type, id);
|
||||
}
|
||||
|
||||
public void removeStation(UUID id) {
|
||||
stations.remove(id);
|
||||
markDirty();
|
||||
public <T extends TrackEdgePoint> Collection<T> getPoints(EdgePointType<T> type) {
|
||||
return edgePoints.values(type);
|
||||
}
|
||||
|
||||
public void removeSignal(UUID id) {
|
||||
SignalBoundary signal = signals.remove(id);
|
||||
if (signal == null)
|
||||
return;
|
||||
SignalPropagator.onSignalRemoved(this, signal);
|
||||
public <T extends TrackEdgePoint> T removePoint(EdgePointType<T> type, UUID id) {
|
||||
T removed = edgePoints.remove(type, id);
|
||||
if (removed == null)
|
||||
return null;
|
||||
EdgePointManager.onEdgePointRemoved(this, removed, type);
|
||||
markDirty();
|
||||
return removed;
|
||||
}
|
||||
|
||||
public void tickPoints() {
|
||||
edgePoints.tick(this);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -135,8 +117,8 @@ public class TrackGraph {
|
|||
return nodesById.get(netId);
|
||||
}
|
||||
|
||||
public boolean createNode(DiscoveredLocation location) {
|
||||
if (!createSpecificNode(location, nextNodeId(), location.normal))
|
||||
public boolean createNodeIfAbsent(DiscoveredLocation location) {
|
||||
if (!addNodeIfAbsent(new TrackNode(location, nextNodeId(), location.normal)))
|
||||
return false;
|
||||
TrackNode newNode = nodes.get(location);
|
||||
Create.RAILWAYS.sync.nodeAdded(this, newNode);
|
||||
|
@ -144,11 +126,19 @@ public class TrackGraph {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean createSpecificNode(TrackNodeLocation location, int netId, Vec3 normal) {
|
||||
return addNode(new TrackNode(location, netId, normal));
|
||||
public void loadNode(TrackNodeLocation location, int netId, Vec3 normal) {
|
||||
addNode(new TrackNode(location, netId, normal));
|
||||
}
|
||||
|
||||
public boolean addNode(TrackNode node) {
|
||||
public void addNode(TrackNode node) {
|
||||
TrackNodeLocation location = node.getLocation();
|
||||
if (nodes.containsKey(location))
|
||||
removeNode(null, location);
|
||||
nodes.put(location, node);
|
||||
nodesById.put(node.getNetId(), node);
|
||||
}
|
||||
|
||||
public boolean addNodeIfAbsent(TrackNode node) {
|
||||
if (nodes.putIfAbsent(node.getLocation(), node) != null)
|
||||
return false;
|
||||
nodesById.put(node.getNetId(), node);
|
||||
|
@ -160,22 +150,6 @@ public class TrackGraph {
|
|||
if (removed == null)
|
||||
return false;
|
||||
|
||||
if (level != null) {
|
||||
for (Iterator<UUID> iterator = stations.keySet()
|
||||
.iterator(); iterator.hasNext();) {
|
||||
UUID uuid = iterator.next();
|
||||
GlobalStation globalStation = stations.get(uuid);
|
||||
Couple<TrackNodeLocation> loc = globalStation.edgeLocation;
|
||||
if (loc.getFirst()
|
||||
.equals(location)
|
||||
|| loc.getSecond()
|
||||
.equals(location)) {
|
||||
globalStation.migrate(level);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<UUID, Train> trains = Create.RAILWAYS.trains;
|
||||
for (Iterator<UUID> iterator = trains.keySet()
|
||||
.iterator(); iterator.hasNext();) {
|
||||
|
@ -193,13 +167,18 @@ public class TrackGraph {
|
|||
|
||||
Map<TrackNode, TrackEdge> connections = connectionsByNode.remove(removed);
|
||||
for (TrackEdge trackEdge : connections.values())
|
||||
for (SignalBoundary boundary : trackEdge.getEdgeData()
|
||||
.getBoundaries())
|
||||
signals.remove(boundary.id);
|
||||
for (TrackEdgePoint point : trackEdge.getEdgeData()
|
||||
.getPoints()) {
|
||||
if (level != null)
|
||||
point.invalidate(level);
|
||||
edgePoints.remove(point.getType(), point.getId());
|
||||
}
|
||||
|
||||
for (TrackNode railNode : connections.keySet())
|
||||
if (connectionsByNode.containsKey(railNode))
|
||||
connectionsByNode.get(railNode)
|
||||
.remove(removed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -208,20 +187,23 @@ public class TrackGraph {
|
|||
}
|
||||
|
||||
public void transferAll(TrackGraph toOther) {
|
||||
toOther.nodes.putAll(nodes);
|
||||
toOther.nodesById.putAll(nodesById);
|
||||
toOther.connectionsByNode.putAll(connectionsByNode);
|
||||
for (GlobalStation globalStation : stations.values())
|
||||
toOther.addStation(globalStation);
|
||||
nodes.forEach((loc, node) -> {
|
||||
if (toOther.addNodeIfAbsent(node))
|
||||
Create.RAILWAYS.sync.nodeAdded(toOther, node);
|
||||
});
|
||||
|
||||
nodesById.forEach((id, node) -> Create.RAILWAYS.sync.nodeAdded(toOther, node));
|
||||
connectionsByNode.forEach(
|
||||
(node1, map) -> map.forEach((node2, edge) -> Create.RAILWAYS.sync.edgeAdded(toOther, node1, node2, edge)));
|
||||
markDirty();
|
||||
connectionsByNode.forEach((node1, map) -> map.forEach((node2, edge) -> {
|
||||
TrackNode n1 = toOther.locateNode(node1.location);
|
||||
TrackNode n2 = toOther.locateNode(node2.location);
|
||||
if (n1 == null || n2 == null)
|
||||
return;
|
||||
toOther.putConnection(n1, n2, edge);
|
||||
Create.RAILWAYS.sync.edgeAdded(toOther, n1, n2, edge);
|
||||
}));
|
||||
|
||||
edgePoints.transferAll(toOther.edgePoints);
|
||||
|
||||
stations.clear();
|
||||
nodes.clear();
|
||||
nodesById.clear();
|
||||
connectionsByNode.clear();
|
||||
|
||||
Map<UUID, Train> trains = Create.RAILWAYS.trains;
|
||||
|
@ -263,7 +245,7 @@ public class TrackGraph {
|
|||
if (target != null) {
|
||||
transfer(currentNode, target);
|
||||
if (preAssignedIds != null && preAssignedIds.containsKey(currentNode.getNetId()))
|
||||
target.id = preAssignedIds.get(currentNode.getNetId());
|
||||
target.setId(preAssignedIds.get(currentNode.getNetId()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,31 +256,29 @@ public class TrackGraph {
|
|||
return dicovered;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
color = Color.rainbowColor(new Random(id.getLeastSignificantBits()).nextInt());
|
||||
}
|
||||
|
||||
public void transfer(TrackNode node, TrackGraph target) {
|
||||
target.addNode(node);
|
||||
TrackNodeLocation location1 = node.getLocation();
|
||||
|
||||
TrackNodeLocation nodeLoc = node.getLocation();
|
||||
Map<TrackNode, TrackEdge> connections = getConnectionsFrom(node);
|
||||
Map<UUID, Train> trains = Create.RAILWAYS.trains;
|
||||
|
||||
if (!connections.isEmpty()) {
|
||||
target.connectionsByNode.put(node, connections);
|
||||
for (TrackNode entry : connections.keySet()) {
|
||||
for (Iterator<UUID> iterator = stations.keySet()
|
||||
.iterator(); iterator.hasNext();) {
|
||||
UUID uuid = iterator.next();
|
||||
GlobalStation globalStation = stations.get(uuid);
|
||||
Couple<TrackNodeLocation> loc = globalStation.edgeLocation;
|
||||
if (loc.getFirst()
|
||||
.equals(location1)
|
||||
&& loc.getSecond()
|
||||
.equals(entry.getLocation())) {
|
||||
target.addStation(globalStation);
|
||||
iterator.remove();
|
||||
}
|
||||
for (TrackEdge entry : connections.values()) {
|
||||
EdgeData edgeData = entry.getEdgeData();
|
||||
for (TrackEdgePoint trackEdgePoint : edgeData.getPoints()) {
|
||||
target.edgePoints.put(trackEdgePoint.getType(), trackEdgePoint);
|
||||
edgePoints.remove(trackEdgePoint.getType(), trackEdgePoint.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<UUID, Train> trains = Create.RAILWAYS.trains;
|
||||
for (Iterator<UUID> iterator = trains.keySet()
|
||||
.iterator(); iterator.hasNext();) {
|
||||
UUID uuid = iterator.next();
|
||||
|
@ -310,7 +290,7 @@ public class TrackGraph {
|
|||
train.graph = target;
|
||||
}
|
||||
|
||||
nodes.remove(location1);
|
||||
nodes.remove(nodeLoc);
|
||||
nodesById.remove(node.getNetId());
|
||||
connectionsByNode.remove(node);
|
||||
}
|
||||
|
@ -391,19 +371,14 @@ public class TrackGraph {
|
|||
});
|
||||
|
||||
tag.put("Nodes", nodesList);
|
||||
tag.put("Stations", NBTHelper.writeCompoundList(getStations(), GlobalStation::write));
|
||||
tag.put("Signals", NBTHelper.writeCompoundList(getSignals(), SignalBoundary::write));
|
||||
tag.put("Points", edgePoints.write());
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static TrackGraph read(CompoundTag tag) {
|
||||
TrackGraph graph = new TrackGraph(tag.getUUID("Id"));
|
||||
graph.color = new Color(tag.getInt("Color"));
|
||||
|
||||
NBTHelper.readCompoundList(tag.getList("Signals", Tag.TAG_COMPOUND), SignalBoundary::new)
|
||||
.forEach(s -> graph.signals.put(s.id, s));
|
||||
NBTHelper.readCompoundList(tag.getList("Stations", Tag.TAG_COMPOUND), GlobalStation::new)
|
||||
.forEach(s -> graph.stations.put(s.id, s));
|
||||
graph.edgePoints.read(tag.getCompound("Points"));
|
||||
|
||||
Map<Integer, TrackNode> indexTracker = new HashMap<>();
|
||||
ListTag nodesList = tag.getList("Nodes", Tag.TAG_COMPOUND);
|
||||
|
@ -414,7 +389,7 @@ public class TrackGraph {
|
|||
TrackNodeLocation location =
|
||||
TrackNodeLocation.fromPackedPos(NbtUtils.readBlockPos(nodeTag.getCompound("Location")));
|
||||
Vec3 normal = VecHelper.readNBT(nodeTag.getList("Normal", Tag.TAG_DOUBLE));
|
||||
graph.createSpecificNode(location, nextNodeId(), normal);
|
||||
graph.loadNode(location, nextNodeId(), normal);
|
||||
indexTracker.put(i, graph.locateNode(location));
|
||||
i++;
|
||||
}
|
||||
|
@ -430,7 +405,6 @@ 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.edgeData.updateDelegates(node1, node2, edge);
|
||||
graph.putConnection(node1, node2, edge);
|
||||
});
|
||||
}
|
||||
|
@ -475,13 +449,30 @@ public class TrackGraph {
|
|||
Vec3 p1 = edge.getPosition(node, other, 0);
|
||||
Vec3 p2 = edge.getPosition(node, other, 1);
|
||||
|
||||
if (signalData.hasBoundaries()) {
|
||||
SignalBoundary boundary = signalData.nextBoundary(node, other, edge, 0);
|
||||
SignalBoundary prevBoundaryNonNull = boundary;
|
||||
if (signalData.hasPoints()) {
|
||||
double prev = 0;
|
||||
double length = edge.getLength(node, other);
|
||||
SignalEdgeGroup group = Create.RAILWAYS.signalEdgeGroups.get(boundary.getGroup(node));
|
||||
while (boundary != null) {
|
||||
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.signalEdgeGroups.get(boundary.getGroup(node));
|
||||
|
||||
if (group != null)
|
||||
CreateClient.OUTLINER
|
||||
.showLine(Pair.of(boundary, edge),
|
||||
|
@ -493,20 +484,19 @@ public class TrackGraph {
|
|||
.add(yOffset))
|
||||
.colored(group.color.getRGB())
|
||||
.lineWidth(1 / 16f);
|
||||
boundary =
|
||||
signalData.nextBoundary(node, other, edge, boundary.getLocationOn(node, other, edge));
|
||||
if (boundary != null) {
|
||||
group = Create.RAILWAYS.signalEdgeGroups.get(boundary.getGroup(node));
|
||||
prevBoundaryNonNull = boundary;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (prevBoundary != null) {
|
||||
group = Create.RAILWAYS.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;
|
||||
}
|
||||
group = Create.RAILWAYS.signalEdgeGroups.get(prevBoundaryNonNull.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)
|
||||
|
|
|
@ -56,8 +56,16 @@ public class TrackGraphSync {
|
|||
|
||||
public void nodeRemoved(TrackGraph graph, TrackNode node) {
|
||||
flushPacket(graph.id);
|
||||
if (currentPacket.addedNodes.remove(node.getNetId()) == null)
|
||||
currentPacket.removedNodes.add(node.getNetId());
|
||||
int nodeId = node.getNetId();
|
||||
if (currentPacket.addedNodes.remove(nodeId) == null)
|
||||
currentPacket.removedNodes.add(nodeId);
|
||||
currentPacket.addedEdges.removeIf(pair -> {
|
||||
Couple<Integer> ids = pair.getFirst();
|
||||
return ids.getFirst()
|
||||
.intValue() == nodeId
|
||||
|| ids.getSecond()
|
||||
.intValue() == nodeId;
|
||||
});
|
||||
}
|
||||
|
||||
public void graphSplit(TrackGraph graph, Set<TrackGraph> additional) {
|
||||
|
@ -80,19 +88,25 @@ public class TrackGraphSync {
|
|||
//
|
||||
|
||||
public void sendFullGraphTo(TrackGraph graph, ServerPlayer player) {
|
||||
// TODO ensure packet size limit
|
||||
|
||||
RailGraphSyncPacket packet = new RailGraphSyncPacket(graph.id);
|
||||
int sent = 0;
|
||||
for (TrackNode node : graph.nodes.values()) {
|
||||
packet.addedNodes.put(node.getNetId(), Pair.of(node.getLocation(), node.getNormal()));
|
||||
RailGraphSyncPacket currentPacket = packet;
|
||||
currentPacket.addedNodes.put(node.getNetId(), Pair.of(node.getLocation(), node.getNormal()));
|
||||
if (!graph.connectionsByNode.containsKey(node))
|
||||
continue;
|
||||
graph.connectionsByNode.get(node)
|
||||
.forEach((node2, edge) -> packet.addedEdges
|
||||
.forEach((node2, edge) -> currentPacket.addedEdges
|
||||
.add(Pair.of(Couple.create(node.getNetId(), node2.getNetId()), edge)));
|
||||
}
|
||||
|
||||
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), packet);
|
||||
if (sent++ > 1000) {
|
||||
sent = 0;
|
||||
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), packet);
|
||||
packet = new RailGraphSyncPacket(graph.id);
|
||||
}
|
||||
}
|
||||
if (sent > 0)
|
||||
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), packet);
|
||||
}
|
||||
|
||||
private RailGraphSyncPacket currentPacket;
|
||||
|
@ -161,6 +175,7 @@ public class TrackGraphSync {
|
|||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
|
||||
buffer.writeUUID(graphId);
|
||||
buffer.writeBoolean(delete);
|
||||
if (delete)
|
||||
|
@ -209,11 +224,11 @@ public class TrackGraphSync {
|
|||
railGraph.removeNode(null, node.getLocation());
|
||||
}
|
||||
|
||||
for (Entry<Integer, Pair<TrackNodeLocation, Vec3>> entry : addedNodes.entrySet())
|
||||
railGraph.createSpecificNode(entry.getValue()
|
||||
.getFirst(), entry.getKey(),
|
||||
entry.getValue()
|
||||
.getSecond());
|
||||
for (Entry<Integer, Pair<TrackNodeLocation, Vec3>> entry : addedNodes.entrySet()) {
|
||||
Integer nodeId = entry.getKey();
|
||||
Pair<TrackNodeLocation, Vec3> nodeLocation = entry.getValue();
|
||||
railGraph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond());
|
||||
}
|
||||
|
||||
for (Pair<Couple<Integer>, TrackEdge> pair : addedEdges) {
|
||||
Couple<TrackNode> nodes = pair.getFirst()
|
||||
|
|
|
@ -38,27 +38,24 @@ public class TrackPropagator {
|
|||
Collection<DiscoveredLocation> ends = track.getConnected(reader, pos, state, false, null);
|
||||
GlobalRailwayManager manager = Create.RAILWAYS;
|
||||
TrackGraphSync sync = manager.sync;
|
||||
TrackGraph foundGraph = null;
|
||||
|
||||
// 1. Remove any nodes this rail was part of
|
||||
|
||||
for (DiscoveredLocation removedLocation : ends) {
|
||||
if (foundGraph == null)
|
||||
foundGraph = manager.getGraph(reader, removedLocation);
|
||||
if (foundGraph == null)
|
||||
continue;
|
||||
TrackNode removedNode = foundGraph.locateNode(removedLocation);
|
||||
if (removedNode != null) {
|
||||
List<TrackGraph> intersecting = manager.getGraphs(reader, removedLocation);
|
||||
for (TrackGraph foundGraph : intersecting) {
|
||||
TrackNode removedNode = foundGraph.locateNode(removedLocation);
|
||||
if (removedNode == null)
|
||||
continue;
|
||||
foundGraph.removeNode(reader, removedLocation);
|
||||
sync.nodeRemoved(foundGraph, removedNode);
|
||||
if (!foundGraph.isEmpty())
|
||||
continue;
|
||||
manager.removeGraph(foundGraph);
|
||||
sync.graphRemoved(foundGraph);
|
||||
}
|
||||
}
|
||||
|
||||
if (foundGraph != null && foundGraph.isEmpty()) {
|
||||
manager.removeGraph(foundGraph);
|
||||
sync.graphRemoved(foundGraph);
|
||||
}
|
||||
|
||||
Set<BlockPos> positionsToUpdate = new HashSet<>();
|
||||
for (DiscoveredLocation removedEnd : ends)
|
||||
positionsToUpdate.addAll(removedEnd.allAdjacent());
|
||||
|
@ -100,8 +97,8 @@ public class TrackPropagator {
|
|||
break;
|
||||
|
||||
FrontierEntry entry = frontier.remove(0);
|
||||
TrackGraph graph = manager.getGraph(reader, entry.currentNode);
|
||||
if (graph != null) {
|
||||
List<TrackGraph> intersecting = manager.getGraphs(reader, entry.currentNode);
|
||||
for (TrackGraph graph : intersecting) {
|
||||
TrackNode node = graph.locateNode(entry.currentNode);
|
||||
graph.removeNode(reader, entry.currentNode);
|
||||
sync.nodeRemoved(graph, node);
|
||||
|
@ -109,6 +106,9 @@ public class TrackPropagator {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!intersecting.isEmpty())
|
||||
continue;
|
||||
|
||||
Collection<DiscoveredLocation> ends = ITrackBlock.walkConnectedTracks(reader, entry.currentNode, false);
|
||||
if (entry.prevNode != null)
|
||||
ends.remove(entry.prevNode);
|
||||
|
@ -117,7 +117,6 @@ public class TrackPropagator {
|
|||
|
||||
frontier.clear();
|
||||
visited.clear();
|
||||
|
||||
TrackGraph graph = null;
|
||||
|
||||
// Remove empty graphs
|
||||
|
@ -173,11 +172,7 @@ public class TrackPropagator {
|
|||
|
||||
frontier.clear();
|
||||
Set<TrackNode> addedNodes = new HashSet<>();
|
||||
if (graph.createNode(startNode)) {
|
||||
TrackNode node = graph.locateNode(startNode);
|
||||
sync.nodeAdded(graph, node);
|
||||
}
|
||||
|
||||
graph.createNodeIfAbsent(startNode);
|
||||
frontier.add(new FrontierEntry(startNode, null, startNode));
|
||||
|
||||
// 3. Build up the graph via all connected nodes
|
||||
|
@ -195,11 +190,7 @@ public class TrackPropagator {
|
|||
ends.remove(entry.prevNode);
|
||||
|
||||
if (isValidGraphNodeLocation(entry.currentNode, ends, first) && entry.currentNode != startNode) {
|
||||
boolean nodeIsNew = graph.createNode(entry.currentNode);
|
||||
if (nodeIsNew) {
|
||||
TrackNode node = graph.locateNode(entry.currentNode);
|
||||
sync.nodeAdded(graph, node);
|
||||
}
|
||||
boolean nodeIsNew = graph.createNodeIfAbsent(entry.currentNode);
|
||||
graph.connectNodes(parentNode, entry.currentNode, new TrackEdge(entry.currentNode.getTurn()));
|
||||
addedNodes.add(graph.locateNode(entry.currentNode));
|
||||
parentNode = entry.currentNode;
|
||||
|
|
|
@ -9,7 +9,6 @@ import java.util.Map.Entry;
|
|||
import java.util.PriorityQueue;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
|
||||
|
@ -17,12 +16,13 @@ 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.entity.TravellingPoint.ITrackSelector;
|
||||
import com.simibubi.create.content.logistics.trains.management.GlobalStation;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.EdgeData;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalBoundary;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalEdgeGroup;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.TrackEdgePoint;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
@ -79,13 +79,14 @@ public class Navigation {
|
|||
double acceleration = AllConfigs.SERVER.trains.getAccelerationMPTT();
|
||||
double brakingDistance = (train.speed * train.speed) / (2 * acceleration);
|
||||
double speedMod = destinationBehindTrain ? -1 : 1;
|
||||
double preDepartureLookAhead = train.getCurrentStation() != null ? 4.5 : 0;
|
||||
|
||||
// Signals
|
||||
if (train.graph != null) {
|
||||
if (waitingForSignal != null && checkBlockingSignal())
|
||||
waitingForSignal = null;
|
||||
|
||||
TravellingPoint leadingPoint = train.speed > 0 ? train.carriages.get(0)
|
||||
TravellingPoint leadingPoint = !destinationBehindTrain ? train.carriages.get(0)
|
||||
.getLeadingPoint()
|
||||
: train.carriages.get(train.carriages.size() - 1)
|
||||
.getTrailingPoint();
|
||||
|
@ -93,13 +94,19 @@ public class Navigation {
|
|||
if (waitingForSignal == null)
|
||||
distanceToSignal = Double.MAX_VALUE;
|
||||
|
||||
if (train.getCurrentStation() != null) {
|
||||
int i = 0;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (distanceToSignal > 1 / 16f) {
|
||||
signalScout.node1 = leadingPoint.node1;
|
||||
signalScout.node2 = leadingPoint.node2;
|
||||
signalScout.edge = leadingPoint.edge;
|
||||
signalScout.position = leadingPoint.position;
|
||||
|
||||
double brakingDistanceNoFlicker = brakingDistance + 3 - (brakingDistance % 3);
|
||||
double brakingDistanceNoFlicker =
|
||||
Math.max(preDepartureLookAhead, brakingDistance + 3 - (brakingDistance % 3));
|
||||
double scanDistance = Math.min(distanceToDestination - .5f, brakingDistanceNoFlicker);
|
||||
|
||||
signalScout.travel(train.graph, scanDistance * speedMod, controlSignalScout(), (distance, couple) -> {
|
||||
|
@ -133,6 +140,11 @@ public class Navigation {
|
|||
train.arriveAt(destination);
|
||||
destination = null;
|
||||
return;
|
||||
} else if (train.getCurrentStation() != null) {
|
||||
// dont leave until green light
|
||||
if (waitingForSignal != null && distanceToSignal < preDepartureLookAhead)
|
||||
return;
|
||||
train.leaveStation();
|
||||
}
|
||||
|
||||
train.currentlyBackwards = destinationBehindTrain;
|
||||
|
@ -158,7 +170,7 @@ public class Navigation {
|
|||
private boolean checkBlockingSignal() {
|
||||
if (distanceToDestination < .5f)
|
||||
return true;
|
||||
SignalBoundary signal = train.graph.getSignal(waitingForSignal.getFirst());
|
||||
SignalBoundary signal = train.graph.getPoint(EdgePointType.SIGNAL, waitingForSignal.getFirst());
|
||||
if (signal == null)
|
||||
return true;
|
||||
UUID groupId = signal.groups.get(waitingForSignal.getSecond());
|
||||
|
@ -167,11 +179,8 @@ public class Navigation {
|
|||
SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(groupId);
|
||||
if (signalEdgeGroup == null)
|
||||
return true;
|
||||
if (!signalEdgeGroup.isOccupiedUnless(train)) {
|
||||
if (train.currentStation != null)
|
||||
train.leaveStation();
|
||||
if (!signalEdgeGroup.isOccupiedUnless(train))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -272,20 +281,6 @@ public class Navigation {
|
|||
train.status.foundConductor();
|
||||
}
|
||||
|
||||
GlobalStation currentStation = train.getCurrentStation();
|
||||
if (currentStation != null) {
|
||||
SignalBoundary boundary = currentStation.boundary;
|
||||
if (boundary != null) {
|
||||
TrackNode node1 = train.graph.locateNode(currentStation.edgeLocation.getFirst());
|
||||
UUID group = boundary.getGroup(node1);
|
||||
if (group != null) {
|
||||
waitingForSignal = Pair.of(boundary.id, !boundary.isPrimary(node1));
|
||||
distanceToSignal = 0;
|
||||
}
|
||||
} else
|
||||
train.leaveStation();
|
||||
}
|
||||
|
||||
this.destination = destination;
|
||||
return distanceToDestination;
|
||||
}
|
||||
|
@ -297,7 +292,6 @@ public class Navigation {
|
|||
if (graph == null)
|
||||
return Pair.of(null, path);
|
||||
|
||||
Couple<TrackNodeLocation> target = destination.edgeLocation;
|
||||
MutableObject<Pair<Double, List<TrackEdge>>> frontResult = new MutableObject<>(Pair.of(null, path));
|
||||
MutableObject<Pair<Double, List<TrackEdge>>> backResult = new MutableObject<>(Pair.of(null, path));
|
||||
|
||||
|
@ -314,21 +308,16 @@ public class Navigation {
|
|||
: graph.getConnectionsFrom(initialPoint.node2)
|
||||
.get(initialPoint.node1);
|
||||
|
||||
search(Double.MAX_VALUE, forward, (reachedVia, poll) -> {
|
||||
search(Double.MAX_VALUE, forward, (distance, reachedVia, currentEntry, globalStation) -> {
|
||||
if (globalStation != destination)
|
||||
return false;
|
||||
|
||||
double distance = poll.getFirst();
|
||||
Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond();
|
||||
TrackEdge edge = currentEntry.getSecond();
|
||||
TrackNode node1 = currentEntry.getFirst()
|
||||
.getFirst();
|
||||
TrackNode node2 = currentEntry.getFirst()
|
||||
.getSecond();
|
||||
|
||||
TrackNodeLocation loc1 = node1.getLocation();
|
||||
TrackNodeLocation loc2 = node2.getLocation();
|
||||
if (!loc1.equals(target.getFirst()) || !loc2.equals(target.getSecond()))
|
||||
return false;
|
||||
|
||||
Pair<Boolean, TrackEdge> backTrack = reachedVia.get(edge);
|
||||
TrackEdge toReach = edge;
|
||||
while (backTrack != null && toReach != initialEdge) {
|
||||
|
@ -338,7 +327,7 @@ public class Navigation {
|
|||
backTrack = reachedVia.get(backTrack.getSecond());
|
||||
}
|
||||
|
||||
double position = edge.getLength(node1, node2) - destination.position;
|
||||
double position = edge.getLength(node1, node2) - destination.getLocationOn(node1, node2, edge);
|
||||
double distanceToDestination = distance - position;
|
||||
|
||||
if (forward)
|
||||
|
@ -383,40 +372,27 @@ public class Navigation {
|
|||
double minDistance = .75f * (train.speed * train.speed) / (2 * acceleration);
|
||||
double maxDistance = Math.max(32, 1.5f * (train.speed * train.speed) / (2 * acceleration));
|
||||
|
||||
search(maxDistance, forward, (reachedVia, poll) -> {
|
||||
double distance = poll.getFirst();
|
||||
search(maxDistance, forward, (distance, reachedVia, currentEntry, globalStation) -> {
|
||||
if (distance < minDistance)
|
||||
return false;
|
||||
|
||||
Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond();
|
||||
TrackEdge edge = currentEntry.getSecond();
|
||||
TrackNode node1 = currentEntry.getFirst()
|
||||
.getFirst();
|
||||
TrackNode node2 = currentEntry.getFirst()
|
||||
.getSecond();
|
||||
|
||||
for (GlobalStation globalStation : edge.getEdgeData()
|
||||
.getStations()) {
|
||||
Couple<TrackNodeLocation> target = globalStation.edgeLocation;
|
||||
TrackNodeLocation loc1 = node1.getLocation();
|
||||
TrackNodeLocation loc2 = node2.getLocation();
|
||||
if (!loc1.equals(target.getFirst()) || !loc2.equals(target.getSecond()))
|
||||
continue;
|
||||
double position = edge.getLength(node1, node2) - globalStation.position;
|
||||
if (distance - position < minDistance)
|
||||
continue;
|
||||
result.setValue(globalStation);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
double position = edge.getLength(node1, node2) - globalStation.getLocationOn(node1, node2, edge);
|
||||
if (distance - position < minDistance)
|
||||
return false;
|
||||
result.setValue(globalStation);
|
||||
return true;
|
||||
});
|
||||
|
||||
return result.getValue();
|
||||
}
|
||||
|
||||
public void search(double maxDistance, boolean forward,
|
||||
BiPredicate<Map<TrackEdge, Pair<Boolean, TrackEdge>>, Pair<Double, Pair<Couple<TrackNode>, TrackEdge>>> condition) {
|
||||
public void search(double maxDistance, boolean forward, StationTest stationTest) {
|
||||
TrackGraph graph = train.graph;
|
||||
if (graph == null)
|
||||
return;
|
||||
|
@ -440,7 +416,7 @@ public class Navigation {
|
|||
|
||||
frontier.add(Pair.of(distanceToNode2, Pair.of(Couple.create(initialNode1, initialNode2), initialEdge)));
|
||||
|
||||
while (!frontier.isEmpty()) {
|
||||
Search: while (!frontier.isEmpty()) {
|
||||
Pair<Double, Pair<Couple<TrackNode>, TrackEdge>> poll = frontier.poll();
|
||||
double distance = poll.getFirst();
|
||||
if (distance > maxDistance)
|
||||
|
@ -452,12 +428,24 @@ public class Navigation {
|
|||
.getFirst();
|
||||
TrackNode node2 = currentEntry.getFirst()
|
||||
.getSecond();
|
||||
if (condition.test(reachedVia, poll))
|
||||
return;
|
||||
|
||||
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)
|
||||
continue;
|
||||
if (!point.canNavigateVia(node2))
|
||||
continue Search;
|
||||
if (point instanceof GlobalStation station && station.canApproachFrom(node2)
|
||||
&& stationTest.test(distance, reachedVia, currentEntry, station))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
||||
EdgeWalk: for (Entry<TrackNode, TrackEdge> entry : graph.getConnectionsFrom(node2)
|
||||
.entrySet()) {
|
||||
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);
|
||||
|
@ -466,13 +454,6 @@ public class Navigation {
|
|||
continue;
|
||||
if (!visited.add(entry.getValue()))
|
||||
continue;
|
||||
|
||||
EdgeData signalData = newEdge.getEdgeData();
|
||||
if (signalData.hasBoundaries())
|
||||
for (SignalBoundary boundary : signalData.getBoundaries())
|
||||
if (!boundary.canNavigateVia(node2))
|
||||
continue EdgeWalk;
|
||||
|
||||
validTargets.add(entry);
|
||||
}
|
||||
|
||||
|
@ -489,4 +470,10 @@ public class Navigation {
|
|||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface StationTest {
|
||||
boolean test(double distance, Map<TrackEdge, Pair<Boolean, TrackEdge>> reachedVia,
|
||||
Pair<Couple<TrackNode>, TrackEdge> current, GlobalStation station);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.simibubi.create.content.logistics.trains.management.GlobalStation;
|
|||
import com.simibubi.create.content.logistics.trains.management.GraphLocation;
|
||||
import com.simibubi.create.content.logistics.trains.management.ScheduleRuntime;
|
||||
import com.simibubi.create.content.logistics.trains.management.ScheduleRuntime.State;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.EdgeData;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalBoundary;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalEdgeGroup;
|
||||
|
@ -556,7 +557,7 @@ public class Train {
|
|||
return null;
|
||||
if (graph == null)
|
||||
return null;
|
||||
return graph.getStation(currentStation);
|
||||
return graph.getPoint(EdgePointType.STATION, currentStation);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -596,16 +597,16 @@ public class Train {
|
|||
Map<UUID, SignalEdgeGroup> allGroups = Create.RAILWAYS.signalEdgeGroups;
|
||||
MutableObject<UUID> prevGroup = new MutableObject<>(null);
|
||||
|
||||
if (signalData.hasBoundaries()) {
|
||||
SignalBoundary nextBoundary = signalData.nextBoundary(node1, node2, edge, position);
|
||||
if (signalData.hasSignalBoundaries()) {
|
||||
SignalBoundary nextBoundary = signalData.next(EdgePointType.SIGNAL, node1, node2, edge, position);
|
||||
if (nextBoundary == null) {
|
||||
double d = 0;
|
||||
SignalBoundary prev = null;
|
||||
SignalBoundary current = signalData.nextBoundary(node1, node2, edge, 0);
|
||||
SignalBoundary current = signalData.next(EdgePointType.SIGNAL, node1, node2, edge, 0);
|
||||
while (current != null) {
|
||||
prev = current;
|
||||
d = current.getLocationOn(node1, node2, edge);
|
||||
current = signalData.nextBoundary(node1, node2, edge, d);
|
||||
current = signalData.next(EdgePointType.SIGNAL, node1, node2, edge, d);
|
||||
}
|
||||
if (prev != null) {
|
||||
UUID group = prev.getGroup(node2);
|
||||
|
|
|
@ -15,8 +15,9 @@ 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.management.GraphLocation;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalBoundary;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.EdgeData;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalBoundary;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
|
@ -258,12 +259,12 @@ public class TravellingPoint {
|
|||
private void edgeTraversedFrom(TrackGraph graph, boolean forward, ISignalBoundaryListener signalListener,
|
||||
double prevPos, double totalDistance) {
|
||||
EdgeData signalsOnEdge = edge.getEdgeData();
|
||||
if (!signalsOnEdge.hasBoundaries())
|
||||
if (!signalsOnEdge.hasSignalBoundaries())
|
||||
return;
|
||||
|
||||
double from = forward ? prevPos : position;
|
||||
double to = forward ? position : prevPos;
|
||||
SignalBoundary nextBoundary = signalsOnEdge.nextBoundary(node1, node2, edge, from);
|
||||
SignalBoundary nextBoundary = signalsOnEdge.next(EdgePointType.SIGNAL, node1, node2, edge, from);
|
||||
List<SignalBoundary> discoveredBoundaries = null;
|
||||
|
||||
while (nextBoundary != null) {
|
||||
|
@ -273,7 +274,7 @@ public class TravellingPoint {
|
|||
if (discoveredBoundaries == null)
|
||||
discoveredBoundaries = new ArrayList<>();
|
||||
discoveredBoundaries.add(nextBoundary);
|
||||
nextBoundary = signalsOnEdge.nextBoundary(node1, node2, edge, d);
|
||||
nextBoundary = signalsOnEdge.next(EdgePointType.SIGNAL, node1, node2, edge, d);
|
||||
}
|
||||
|
||||
if (discoveredBoundaries == null)
|
||||
|
|
|
@ -1,57 +1,40 @@
|
|||
package com.simibubi.create.content.logistics.trains.management;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Train;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalBoundary;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.TrackEdgePoint;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SingleTileEdgePoint;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
public class GlobalStation extends TrackEdgePoint {
|
||||
public class GlobalStation extends SingleTileEdgePoint {
|
||||
|
||||
public String name;
|
||||
public BlockPos stationPos;
|
||||
|
||||
public WeakReference<Train> nearestTrain;
|
||||
|
||||
@Nullable
|
||||
public SignalBoundary boundary;
|
||||
|
||||
public GlobalStation(UUID id, BlockPos stationPos) {
|
||||
super(id);
|
||||
this.stationPos = stationPos;
|
||||
public GlobalStation() {
|
||||
name = "Track Station";
|
||||
nearestTrain = new WeakReference<Train>(null);
|
||||
}
|
||||
|
||||
public GlobalStation(CompoundTag nbt) {
|
||||
super(nbt);
|
||||
@Override
|
||||
public void read(CompoundTag nbt, boolean migration) {
|
||||
super.read(nbt, migration);
|
||||
name = nbt.getString("Name");
|
||||
stationPos = NbtUtils.readBlockPos(nbt.getCompound("StationPos"));
|
||||
nearestTrain = new WeakReference<Train>(null);
|
||||
}
|
||||
|
||||
public void migrate(LevelAccessor level) {
|
||||
BlockEntity blockEntity = level.getBlockEntity(stationPos);
|
||||
if (blockEntity instanceof StationTileEntity station) {
|
||||
station.migrate(this);
|
||||
return;
|
||||
}
|
||||
@Override
|
||||
public void write(CompoundTag nbt) {
|
||||
super.write(nbt);
|
||||
nbt.putString("Name", name);
|
||||
}
|
||||
|
||||
public void setLocation(Couple<TrackNodeLocation> nodes, double position) {
|
||||
this.edgeLocation = nodes;
|
||||
this.position = position;
|
||||
|
||||
public boolean canApproachFrom(TrackNode side) {
|
||||
return isPrimary(side);
|
||||
}
|
||||
|
||||
public void reserveFor(Train train) {
|
||||
|
@ -97,14 +80,4 @@ public class GlobalStation extends TrackEdgePoint {
|
|||
return this.nearestTrain.get();
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
nbt.putUUID("Id", id);
|
||||
nbt.putString("Name", name);
|
||||
nbt.put("StationPos", NbtUtils.writeBlockPos(stationPos));
|
||||
nbt.putDouble("Position", position);
|
||||
nbt.put("Edge", edgeLocation.serializeEach(loc -> NbtUtils.writeBlockPos(new BlockPos(loc))));
|
||||
return nbt;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
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.schedule.FilteredDestination;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.Schedule;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleDestination;
|
||||
|
@ -128,7 +129,7 @@ public class ScheduleRuntime {
|
|||
String regex = filtered.nameFilter.replace("*", ".*");
|
||||
GlobalStation best = null;
|
||||
double bestCost = Double.MAX_VALUE;
|
||||
for (GlobalStation globalStation : train.graph.getStations()) {
|
||||
for (GlobalStation globalStation : train.graph.getPoints(EdgePointType.STATION)) {
|
||||
if (!globalStation.name.matches(regex))
|
||||
continue;
|
||||
boolean matchesCurrent = train.currentStation != null && train.currentStation.equals(globalStation.id);
|
||||
|
|
|
@ -75,10 +75,10 @@ public class StationBlock extends HorizontalDirectionalBlock implements ITE<Stat
|
|||
protected void displayScreen(StationTileEntity te, Player player) {
|
||||
if (!(player instanceof LocalPlayer))
|
||||
return;
|
||||
GlobalStation station = te.getOrCreateGlobalStation();
|
||||
if (station == null)
|
||||
return;
|
||||
GlobalStation station = te.getStation();
|
||||
BlockState blockState = te.getBlockState();
|
||||
if (station == null || blockState == null)
|
||||
return;
|
||||
boolean assembling = blockState.getBlock() == this && blockState.getValue(ASSEMBLING);
|
||||
ScreenOpener.open(assembling ? new AssemblyScreen(te, station) : new StationScreen(te, station));
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ public class StationEditPacket extends TileEntityConfigurationPacket<StationTile
|
|||
BlockState blockState = level.getBlockState(blockPos);
|
||||
|
||||
if (!name.isBlank()) {
|
||||
GlobalStation station = te.getOrCreateGlobalStation();
|
||||
GlobalStation station = te.getStation();
|
||||
if (station != null)
|
||||
station.name = name;
|
||||
Create.RAILWAYS.markTracksDirty();
|
||||
|
@ -113,12 +113,11 @@ public class StationEditPacket extends TileEntityConfigurationPacket<StationTile
|
|||
}
|
||||
|
||||
private boolean disassembleAndEnterMode(StationTileEntity te) {
|
||||
GlobalStation station = te.getOrCreateGlobalStation();
|
||||
GlobalStation station = te.getStation();
|
||||
if (station != null) {
|
||||
Train train = station.getPresentTrain();
|
||||
if (train != null && !train.disassemble(te.getAssemblyDirection(), te.getTarget()
|
||||
.getGlobalPosition()
|
||||
.above()))
|
||||
BlockPos trackPosition = te.edgePoint.getGlobalPosition();
|
||||
if (train != null && !train.disassemble(te.getAssemblyDirection(), trackPosition.above()))
|
||||
return false;
|
||||
}
|
||||
return te.tryEnterAssemblyMode();
|
||||
|
|
|
@ -29,7 +29,7 @@ public class StationRenderer extends SafeTileEntityRenderer<StationTileEntity> {
|
|||
int light, int overlay) {
|
||||
|
||||
BlockPos pos = te.getBlockPos();
|
||||
TrackTargetingBehaviour target = te.getTarget();
|
||||
TrackTargetingBehaviour<GlobalStation> target = te.edgePoint;
|
||||
BlockPos targetPosition = target.getGlobalPosition();
|
||||
Level level = te.getLevel();
|
||||
|
||||
|
@ -38,7 +38,7 @@ public class StationRenderer extends SafeTileEntityRenderer<StationTileEntity> {
|
|||
if (!(block instanceof ITrackBlock))
|
||||
return;
|
||||
|
||||
GlobalStation station = te.getOrCreateGlobalStation();
|
||||
GlobalStation station = te.getStation();
|
||||
|
||||
if (!te.getBlockState()
|
||||
.getValue(StationBlock.ASSEMBLING) || station == null || station.getPresentTrain() != null) {
|
||||
|
|
|
@ -9,6 +9,8 @@ import java.util.Map;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
|
@ -22,6 +24,7 @@ import com.simibubi.create.content.logistics.trains.entity.Carriage.CarriageBoge
|
|||
import com.simibubi.create.content.logistics.trains.entity.CarriageContraption;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Train;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
@ -46,91 +49,42 @@ import net.minecraftforge.api.distmarker.OnlyIn;
|
|||
|
||||
public class StationTileEntity extends SmartTileEntity {
|
||||
|
||||
UUID id;
|
||||
public TrackTargetingBehaviour<GlobalStation> edgePoint;
|
||||
|
||||
protected int failedCarriageIndex;
|
||||
protected AssemblyException lastException;
|
||||
protected CompoundTag toMigrate;
|
||||
|
||||
public StationTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
setLazyTickRate(20);
|
||||
id = UUID.randomUUID();
|
||||
lastException = null;
|
||||
toMigrate = null;
|
||||
failedCarriageIndex = -1;
|
||||
}
|
||||
|
||||
public void migrate(GlobalStation globalStation) {
|
||||
if (toMigrate != null)
|
||||
return;
|
||||
toMigrate = globalStation.write();
|
||||
setChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||
behaviours.add(new TrackTargetingBehaviour(this));
|
||||
}
|
||||
|
||||
public TrackTargetingBehaviour getTarget() {
|
||||
return getBehaviour(TrackTargetingBehaviour.TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (!level.isClientSide)
|
||||
getOrCreateGlobalStation();
|
||||
super.initialize();
|
||||
}
|
||||
|
||||
public GlobalStation getOrCreateGlobalStation() {
|
||||
for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values()) { // TODO thread breach
|
||||
GlobalStation station = trackGraph.getStation(id);
|
||||
if (station == null)
|
||||
continue;
|
||||
return station;
|
||||
}
|
||||
|
||||
if (level.isClientSide)
|
||||
return null;
|
||||
|
||||
TrackTargetingBehaviour target = getTarget();
|
||||
if (!target.hasValidTrack())
|
||||
return null;
|
||||
GraphLocation loc = target.determineGraphLocation();
|
||||
if (loc == null)
|
||||
return null;
|
||||
|
||||
GlobalStation globalStation =
|
||||
toMigrate != null ? new GlobalStation(toMigrate) : new GlobalStation(id, worldPosition);
|
||||
globalStation.setLocation(loc.edge, loc.position);
|
||||
loc.graph.addStation(globalStation);
|
||||
toMigrate = null;
|
||||
setChanged();
|
||||
|
||||
return globalStation;
|
||||
edgePoint = new TrackTargetingBehaviour<>(this, EdgePointType.STATION);
|
||||
behaviours.add(edgePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void read(CompoundTag tag, boolean clientPacket) {
|
||||
id = tag.getUUID("Id");
|
||||
lastException = AssemblyException.read(tag);
|
||||
failedCarriageIndex = tag.getInt("FailedCarriageIndex");
|
||||
super.read(tag, clientPacket);
|
||||
if (tag.contains("ToMigrate"))
|
||||
toMigrate = tag.getCompound("ToMigrate");
|
||||
invalidateRenderBoundingBox();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(CompoundTag tag, boolean clientPacket) {
|
||||
tag.putUUID("Id", id);
|
||||
AssemblyException.write(tag, lastException);
|
||||
tag.putInt("FailedCarriageIndex", failedCarriageIndex);
|
||||
super.write(tag, clientPacket);
|
||||
if (!clientPacket && toMigrate != null)
|
||||
tag.put("ToMigrate", toMigrate);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GlobalStation getStation() {
|
||||
return edgePoint.getEdgePoint();
|
||||
}
|
||||
|
||||
// Train Assembly
|
||||
|
@ -147,8 +101,6 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
public void lazyTick() {
|
||||
if (isAssembling() && !level.isClientSide)
|
||||
refreshAssemblyInfo();
|
||||
if (!level.isClientSide)
|
||||
getOrCreateGlobalStation();
|
||||
super.lazyTick();
|
||||
}
|
||||
|
||||
|
@ -157,12 +109,6 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
if (isAssembling() && level.isClientSide)
|
||||
refreshAssemblyInfo();
|
||||
super.tick();
|
||||
|
||||
if (level.isClientSide)
|
||||
return;
|
||||
if (toMigrate == null)
|
||||
return;
|
||||
getOrCreateGlobalStation();
|
||||
}
|
||||
|
||||
public void trackClicked(Player player, ITrackBlock track, BlockState state, BlockPos pos) {
|
||||
|
@ -172,7 +118,7 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
if (bb == null || !bb.isInside(pos))
|
||||
return;
|
||||
|
||||
int bogeyOffset = pos.distManhattan(getTarget().getGlobalPosition()) - 1;
|
||||
int bogeyOffset = pos.distManhattan(edgePoint.getGlobalPosition()) - 1;
|
||||
if (!isValidBogeyOffset(bogeyOffset))
|
||||
return;
|
||||
|
||||
|
@ -187,13 +133,12 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
}
|
||||
|
||||
public boolean tryEnterAssemblyMode() {
|
||||
TrackTargetingBehaviour target = getTarget();
|
||||
if (!target.hasValidTrack())
|
||||
if (!edgePoint.hasValidTrack())
|
||||
return false;
|
||||
|
||||
BlockPos targetPosition = target.getGlobalPosition();
|
||||
BlockState trackState = target.getTrackBlockState();
|
||||
ITrackBlock track = target.getTrack();
|
||||
BlockPos targetPosition = edgePoint.getGlobalPosition();
|
||||
BlockState trackState = edgePoint.getTrackBlockState();
|
||||
ITrackBlock track = edgePoint.getTrack();
|
||||
Vec3 trackAxis = track.getTrackAxes(level, targetPosition, trackState)
|
||||
.get(0);
|
||||
|
||||
|
@ -210,18 +155,17 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
}
|
||||
|
||||
public void refreshAssemblyInfo() {
|
||||
TrackTargetingBehaviour target = getTarget();
|
||||
if (!target.hasValidTrack())
|
||||
if (!edgePoint.hasValidTrack())
|
||||
return;
|
||||
|
||||
GlobalStation station = getOrCreateGlobalStation();
|
||||
GlobalStation station = getStation();
|
||||
if (station == null || station.getPresentTrain() != null)
|
||||
return;
|
||||
|
||||
int prevLength = assemblyLength;
|
||||
BlockPos targetPosition = target.getGlobalPosition();
|
||||
BlockState trackState = target.getTrackBlockState();
|
||||
ITrackBlock track = target.getTrack();
|
||||
BlockPos targetPosition = edgePoint.getGlobalPosition();
|
||||
BlockState trackState = edgePoint.getTrackBlockState();
|
||||
ITrackBlock track = edgePoint.getTrack();
|
||||
getAssemblyDirection();
|
||||
|
||||
MutableBlockPos currentPos = targetPosition.mutable();
|
||||
|
@ -248,7 +192,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++;
|
||||
|
@ -285,13 +229,12 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
public Direction getAssemblyDirection() {
|
||||
if (assemblyDirection != null)
|
||||
return assemblyDirection;
|
||||
TrackTargetingBehaviour target = getTarget();
|
||||
if (!target.hasValidTrack())
|
||||
if (!edgePoint.hasValidTrack())
|
||||
return null;
|
||||
BlockPos targetPosition = target.getGlobalPosition();
|
||||
BlockState trackState = target.getTrackBlockState();
|
||||
ITrackBlock track = target.getTrack();
|
||||
AxisDirection axisDirection = target.getTargetDirection();
|
||||
BlockPos targetPosition = edgePoint.getGlobalPosition();
|
||||
BlockState trackState = edgePoint.getTrackBlockState();
|
||||
ITrackBlock track = edgePoint.getTrack();
|
||||
AxisDirection axisDirection = edgePoint.getTargetDirection();
|
||||
Vec3 axis = track.getTrackAxes(level, targetPosition, trackState)
|
||||
.get(0)
|
||||
.normalize()
|
||||
|
@ -303,8 +246,7 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
protected void setRemovedNotDueToChunkUnload() {
|
||||
assemblyAreas.get(level)
|
||||
.remove(worldPosition);
|
||||
for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values())
|
||||
trackGraph.removeStation(id);
|
||||
|
||||
super.setRemovedNotDueToChunkUnload();
|
||||
}
|
||||
|
||||
|
@ -316,13 +258,12 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
return;
|
||||
}
|
||||
|
||||
TrackTargetingBehaviour target = getTarget();
|
||||
if (!target.hasValidTrack())
|
||||
if (!edgePoint.hasValidTrack())
|
||||
return;
|
||||
|
||||
BlockPos trackPosition = target.getGlobalPosition();
|
||||
BlockState trackState = target.getTrackBlockState();
|
||||
ITrackBlock track = target.getTrack();
|
||||
BlockPos trackPosition = edgePoint.getGlobalPosition();
|
||||
BlockState trackState = edgePoint.getTrackBlockState();
|
||||
ITrackBlock track = edgePoint.getTrack();
|
||||
BlockPos bogeyOffset = new BlockPos(track.getUpNormal(level, trackPosition, trackState));
|
||||
|
||||
DiscoveredLocation location = null;
|
||||
|
@ -487,11 +428,13 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
}
|
||||
|
||||
Train train = new Train(UUID.randomUUID(), playerUUID, graph, carriages, spacing);
|
||||
GlobalStation station = getOrCreateGlobalStation();
|
||||
train.setCurrentStation(station);
|
||||
station.reserveFor(train);
|
||||
GlobalStation station = getStation();
|
||||
if (station != null) {
|
||||
train.setCurrentStation(station);
|
||||
station.reserveFor(train);
|
||||
}
|
||||
|
||||
train.collectInitiallyOccupiedSignalBlocks();
|
||||
|
||||
Create.RAILWAYS.trains.put(train.id, train);
|
||||
clearException();
|
||||
}
|
||||
|
@ -523,7 +466,7 @@ public class StationTileEntity extends SmartTileEntity {
|
|||
|
||||
@Override
|
||||
protected AABB createRenderBoundingBox() {
|
||||
return new AABB(worldPosition, getTarget().getGlobalPosition()).inflate(2);
|
||||
return new AABB(worldPosition, edgePoint.getGlobalPosition()).inflate(2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,20 @@
|
|||
package com.simibubi.create.content.logistics.trains.management;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraphHelper;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.EdgeData;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SingleTileEdgePoint;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.TrackEdgePoint;
|
||||
import com.simibubi.create.foundation.render.CachedBufferer;
|
||||
import com.simibubi.create.foundation.render.SuperByteBuffer;
|
||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||
|
@ -23,33 +35,143 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
public class TrackTargetingBehaviour extends TileEntityBehaviour {
|
||||
public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntityBehaviour {
|
||||
|
||||
public static final BehaviourType<TrackTargetingBehaviour> TYPE = new BehaviourType<>();
|
||||
public static final BehaviourType<TrackTargetingBehaviour<?>> TYPE = new BehaviourType<>();
|
||||
|
||||
private BlockPos targetTrack;
|
||||
private AxisDirection targetDirection;
|
||||
private UUID id;
|
||||
|
||||
public TrackTargetingBehaviour(SmartTileEntity te) {
|
||||
private CompoundTag migrationData;
|
||||
private EdgePointType<T> edgePointType;
|
||||
private T edgePoint;
|
||||
|
||||
public TrackTargetingBehaviour(SmartTileEntity te, EdgePointType<T> edgePointType) {
|
||||
super(te);
|
||||
this.edgePointType = edgePointType;
|
||||
targetDirection = AxisDirection.POSITIVE;
|
||||
targetTrack = BlockPos.ZERO;
|
||||
id = UUID.randomUUID();
|
||||
migrationData = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(CompoundTag nbt, boolean clientPacket) {
|
||||
nbt.putUUID("Id", id);
|
||||
nbt.put("TargetTrack", NbtUtils.writeBlockPos(targetTrack));
|
||||
nbt.putBoolean("TargetDirection", targetDirection == AxisDirection.POSITIVE);
|
||||
if (migrationData != null && !clientPacket)
|
||||
nbt.put("Migrate", migrationData);
|
||||
super.write(nbt, clientPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(CompoundTag nbt, boolean clientPacket) {
|
||||
UUID prevId = id;
|
||||
id = nbt.getUUID("Id");
|
||||
targetTrack = NbtUtils.readBlockPos(nbt.getCompound("TargetTrack"));
|
||||
targetDirection = nbt.getBoolean("TargetDirection") ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE;
|
||||
if (nbt.contains("Migrate"))
|
||||
migrationData = nbt.getCompound("Migrate");
|
||||
if (clientPacket && !prevId.equals(id))
|
||||
edgePoint = null;
|
||||
super.read(nbt, clientPacket);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T getEdgePoint() {
|
||||
return edgePoint;
|
||||
}
|
||||
|
||||
public void invalidateEdgePoint(CompoundTag migrationData) {
|
||||
this.migrationData = migrationData;
|
||||
id = UUID.randomUUID();
|
||||
edgePoint = null;
|
||||
tileEntity.sendData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if (edgePoint == null)
|
||||
edgePoint = createEdgePoint();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T createEdgePoint() {
|
||||
for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values()) { // TODO thread breach
|
||||
T point = trackGraph.getPoint(edgePointType, id);
|
||||
if (point == null)
|
||||
continue;
|
||||
return point;
|
||||
}
|
||||
|
||||
if (getWorld().isClientSide)
|
||||
return null;
|
||||
if (!hasValidTrack())
|
||||
return null;
|
||||
GraphLocation loc = determineGraphLocation();
|
||||
if (loc == null)
|
||||
return null;
|
||||
|
||||
TrackGraph graph = loc.graph;
|
||||
TrackNode node1 = graph.locateNode(loc.edge.getFirst());
|
||||
TrackNode node2 = graph.locateNode(loc.edge.getSecond());
|
||||
TrackEdge edge = graph.getConnectionsFrom(node1)
|
||||
.get(node2);
|
||||
|
||||
boolean front = getTargetDirection() == AxisDirection.POSITIVE;
|
||||
|
||||
if (edge == null)
|
||||
return null;
|
||||
|
||||
EdgeData signalData = edge.getEdgeData();
|
||||
if (signalData.hasPoints()) {
|
||||
for (EdgePointType<?> otherType : EdgePointType.TYPES.values()) {
|
||||
TrackEdgePoint otherPoint = signalData.get(otherType, node1, node2, edge, loc.position);
|
||||
if (otherPoint == null)
|
||||
continue;
|
||||
if (otherType != edgePointType) {
|
||||
if (!otherPoint.canCoexistWith(edgePointType, front))
|
||||
return null;
|
||||
continue;
|
||||
}
|
||||
if (!otherPoint.canMerge())
|
||||
return null;
|
||||
otherPoint.tileAdded(getPos(), front);
|
||||
id = otherPoint.getId();
|
||||
tileEntity.setChanged();
|
||||
return (T) otherPoint;
|
||||
}
|
||||
}
|
||||
|
||||
T point = edgePointType.create();
|
||||
point.setId(id);
|
||||
|
||||
if (point instanceof SingleTileEdgePoint step) {
|
||||
point.setLocation(loc.edge, loc.position);
|
||||
if (migrationData != null) {
|
||||
step.read(migrationData, true);
|
||||
migrationData = null;
|
||||
tileEntity.setChanged();
|
||||
}
|
||||
} else
|
||||
point.setLocation(front ? loc.edge : loc.edge.swap(),
|
||||
front ? loc.position : edge.getLength(node1, node2) - loc.position);
|
||||
|
||||
point.tileAdded(getPos(), front);
|
||||
loc.graph.addPoint(edgePointType, point);
|
||||
return point;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (edgePoint != null && !getWorld().isClientSide)
|
||||
edgePoint.tileRemoved(getPos(), getTargetDirection() == AxisDirection.POSITIVE);
|
||||
super.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BehaviourType<?> getType() {
|
||||
return TYPE;
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
||||
|
||||
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.signal.TrackEdgePoint;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
public class EdgePointManager {
|
||||
|
||||
public static <T extends TrackEdgePoint> void onEdgePointAdded(TrackGraph graph, T point, EdgePointType<T> type) {
|
||||
Couple<TrackNodeLocation> edgeLocation = point.edgeLocation;
|
||||
Couple<TrackNode> startNodes = edgeLocation.map(graph::locateNode);
|
||||
Couple<TrackEdge> startEdges = startNodes.mapWithParams((l1, l2) -> graph.getConnectionsFrom(l1)
|
||||
.get(l2), startNodes.swap());
|
||||
|
||||
for (boolean front : Iterate.trueAndFalse) {
|
||||
TrackNode node1 = startNodes.get(front);
|
||||
TrackNode node2 = startNodes.get(!front);
|
||||
TrackEdge startEdge = startEdges.get(front);
|
||||
startEdge.getEdgeData()
|
||||
.addPoint(node1, node2, startEdge, point);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T extends TrackEdgePoint> void onEdgePointRemoved(TrackGraph graph, T point, EdgePointType<T> type) {
|
||||
point.onRemoved(graph);
|
||||
Couple<TrackNodeLocation> edgeLocation = point.edgeLocation;
|
||||
Couple<TrackNode> startNodes = edgeLocation.map(graph::locateNode);
|
||||
startNodes.forEachWithParams((l1, l2) -> {
|
||||
TrackEdge trackEdge = graph.getConnectionsFrom(l1)
|
||||
.get(l2);
|
||||
trackEdge.getEdgeData()
|
||||
.removePoint(l1, l2, trackEdge, point);
|
||||
}, startNodes.swap());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.TrackEdgePoint;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
|
||||
public class EdgePointStorage {
|
||||
|
||||
private Map<EdgePointType<?>, Map<UUID, TrackEdgePoint>> pointsByType;
|
||||
|
||||
public EdgePointStorage() {
|
||||
pointsByType = new HashMap<>();
|
||||
}
|
||||
|
||||
public <T extends TrackEdgePoint> void put(EdgePointType<T> type, TrackEdgePoint point) {
|
||||
getMap(type).put(point.getId(), point);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends TrackEdgePoint> T get(EdgePointType<T> type, UUID id) {
|
||||
return (T) getMap(type).get(id);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends TrackEdgePoint> T remove(EdgePointType<T> type, UUID id) {
|
||||
return (T) getMap(type).remove(id);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends TrackEdgePoint> Collection<T> values(EdgePointType<T> type) {
|
||||
return getMap(type).values()
|
||||
.stream()
|
||||
.map(e -> (T) e)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public Map<UUID, TrackEdgePoint> getMap(EdgePointType<? extends TrackEdgePoint> type) {
|
||||
return pointsByType.computeIfAbsent(type, t -> new HashMap<>());
|
||||
}
|
||||
|
||||
public void tick(TrackGraph graph) {
|
||||
pointsByType.values()
|
||||
.forEach(map -> map.values()
|
||||
.forEach(p -> p.tick(graph)));
|
||||
}
|
||||
|
||||
public void transferAll(EdgePointStorage other) {
|
||||
pointsByType.forEach((type, map) -> other.getMap(type)
|
||||
.putAll(map));
|
||||
pointsByType.clear();
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
for (Entry<EdgePointType<?>, Map<UUID, TrackEdgePoint>> entry : pointsByType.entrySet()) {
|
||||
EdgePointType<?> type = entry.getKey();
|
||||
ListTag list = NBTHelper.writeCompoundList(entry.getValue()
|
||||
.values(), edgePoint -> {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
edgePoint.write(tag);
|
||||
return tag;
|
||||
});
|
||||
nbt.put(type.getId()
|
||||
.toString(), list);
|
||||
}
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public void read(CompoundTag nbt) {
|
||||
for (EdgePointType<?> type : EdgePointType.TYPES.values()) {
|
||||
ListTag list = nbt.getList(type.getId()
|
||||
.toString(), Tag.TAG_COMPOUND);
|
||||
Map<UUID, TrackEdgePoint> map = getMap(type);
|
||||
NBTHelper.iterateCompoundList(list, tag -> {
|
||||
TrackEdgePoint edgePoint = type.create();
|
||||
edgePoint.read(tag);
|
||||
map.put(edgePoint.getId(), edgePoint);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.simibubi.create.content.logistics.trains.management.edgePoint;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.management.GlobalStation;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalBoundary;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.TrackEdgePoint;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class EdgePointType<T extends TrackEdgePoint> {
|
||||
|
||||
public static final Map<ResourceLocation, EdgePointType<?>> TYPES = new HashMap<>();
|
||||
private ResourceLocation id;
|
||||
private Supplier<T> factory;
|
||||
|
||||
public static final EdgePointType<SignalBoundary> SIGNAL =
|
||||
register(Create.asResource("signal"), SignalBoundary::new);
|
||||
public static final EdgePointType<GlobalStation> STATION =
|
||||
register(Create.asResource("station"), GlobalStation::new);
|
||||
|
||||
public static <T extends TrackEdgePoint> EdgePointType<T> register(ResourceLocation id, Supplier<T> factory) {
|
||||
EdgePointType<T> type = new EdgePointType<>(id, factory);
|
||||
TYPES.put(id, type);
|
||||
return type;
|
||||
}
|
||||
|
||||
public EdgePointType(ResourceLocation id, Supplier<T> factory) {
|
||||
this.id = id;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public T create() {
|
||||
T t = factory.get();
|
||||
t.setType(this);
|
||||
return t;
|
||||
}
|
||||
|
||||
public ResourceLocation getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
|
@ -19,7 +19,7 @@ public class ScheduledDelay extends TimedWaitCondition {
|
|||
|
||||
@Override
|
||||
public boolean tickCompletion(Level level, Train train, CompoundTag context) {
|
||||
int time = context.getInt("Time") + 1900;
|
||||
int time = context.getInt("Time");
|
||||
if (time >= value * timeUnit.ticksPer)
|
||||
return true;
|
||||
context.putInt("Time", time + 1);
|
||||
|
|
|
@ -24,7 +24,7 @@ public class StationPoweredCondition extends ScheduleWaitCondition {
|
|||
GlobalStation currentStation = train.getCurrentStation();
|
||||
if (currentStation == null)
|
||||
return false;
|
||||
BlockPos stationPos = currentStation.stationPos;
|
||||
BlockPos stationPos = currentStation.getTilePos();
|
||||
if (!level.isLoaded(stationPos))
|
||||
return false;
|
||||
return level.hasNeighborSignal(stationPos);
|
||||
|
|
|
@ -25,7 +25,7 @@ public class StationUnloadedCondition extends ScheduleWaitCondition {
|
|||
if (currentStation == null)
|
||||
return false;
|
||||
if (level instanceof ServerLevel serverLevel)
|
||||
return !serverLevel.isPositionEntityTicking(currentStation.stationPos);
|
||||
return !serverLevel.isPositionEntityTicking(currentStation.getTilePos());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,109 +1,77 @@
|
|||
package com.simibubi.create.content.logistics.trains.management.signal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
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.management.GlobalStation;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public class EdgeData {
|
||||
|
||||
public static final UUID passiveGroup = UUID.fromString("00000000-0000-0000-0000-000000000000");
|
||||
|
||||
public UUID singleSignalGroup;
|
||||
private List<SignalBoundary> boundaries;
|
||||
private List<GlobalStation> stations;
|
||||
private List<TrackEdgePoint> points;
|
||||
|
||||
public EdgeData() {
|
||||
boundaries = new ArrayList<>();
|
||||
stations = new ArrayList<>();
|
||||
singleSignalGroup = null;
|
||||
points = new ArrayList<>();
|
||||
singleSignalGroup = passiveGroup;
|
||||
}
|
||||
|
||||
public boolean hasBoundaries() {
|
||||
return !boundaries.isEmpty();
|
||||
public boolean hasSignalBoundaries() {
|
||||
return singleSignalGroup == null;
|
||||
}
|
||||
|
||||
public boolean hasStations() {
|
||||
return !stations.isEmpty();
|
||||
public boolean hasPoints() {
|
||||
return !points.isEmpty();
|
||||
}
|
||||
|
||||
public List<SignalBoundary> getBoundaries() {
|
||||
return boundaries;
|
||||
}
|
||||
|
||||
public List<GlobalStation> getStations() {
|
||||
return stations;
|
||||
public List<TrackEdgePoint> getPoints() {
|
||||
return points;
|
||||
}
|
||||
|
||||
public void removePoint(TrackNode node1, TrackNode node2, TrackEdge edge, TrackEdgePoint point) {
|
||||
if (point instanceof GlobalStation gs)
|
||||
stations.remove(gs);
|
||||
if (point instanceof SignalBoundary sb)
|
||||
boundaries.remove(sb);
|
||||
updateDelegates(node1, node2, edge);
|
||||
points.remove(point);
|
||||
if (point.getType() == EdgePointType.SIGNAL)
|
||||
singleSignalGroup = next(point.getType(), node1, node2, edge, 0) == null ? passiveGroup : null;
|
||||
}
|
||||
|
||||
public <T extends TrackEdgePoint> void addPoint(TrackNode node1, TrackNode node2, TrackEdge edge, T boundary,
|
||||
Class<T> type) {
|
||||
T next = next(type, node1, node2, edge, boundary.getLocationOn(node1, node2, edge));
|
||||
if (boundary instanceof GlobalStation gs)
|
||||
stations.add(next == null ? stations.size() : stations.indexOf(next), gs);
|
||||
if (boundary instanceof SignalBoundary sb)
|
||||
boundaries.add(next == null ? boundaries.size() : boundaries.indexOf(next), sb);
|
||||
updateDelegates(node1, node2, edge);
|
||||
}
|
||||
|
||||
public void updateDelegates(TrackNode node1, TrackNode node2, TrackEdge edge) {
|
||||
for (GlobalStation globalStation : stations)
|
||||
globalStation.boundary = getBoundary(node1, node2, edge, globalStation.getLocationOn(node1, node2, edge));
|
||||
for (SignalBoundary boundary : boundaries)
|
||||
boundary.station = getStation(node1, node2, edge, boundary.getLocationOn(node1, node2, edge));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SignalBoundary nextBoundary(TrackNode node1, TrackNode node2, TrackEdge edge, double minPosition) {
|
||||
return next(SignalBoundary.class, node1, node2, edge, minPosition);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GlobalStation nextStation(TrackNode node1, TrackNode node2, TrackEdge edge, double minPosition) {
|
||||
return next(GlobalStation.class, node1, node2, edge, minPosition);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SignalBoundary getBoundary(TrackNode node1, TrackNode node2, TrackEdge edge, double exactPosition) {
|
||||
return get(SignalBoundary.class, node1, node2, edge, exactPosition);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GlobalStation getStation(TrackNode node1, TrackNode node2, TrackEdge edge, double exactPosition) {
|
||||
return get(GlobalStation.class, node1, node2, edge, exactPosition);
|
||||
public <T extends TrackEdgePoint> void addPoint(TrackNode node1, TrackNode node2, TrackEdge edge,
|
||||
TrackEdgePoint point) {
|
||||
if (point.getType() == EdgePointType.SIGNAL)
|
||||
singleSignalGroup = null;
|
||||
double locationOn = point.getLocationOn(node1, node2, edge);
|
||||
int i = 0;
|
||||
for (; i < points.size(); i++)
|
||||
if (points.get(i)
|
||||
.getLocationOn(node1, node2, edge) > locationOn)
|
||||
break;
|
||||
points.add(i, point);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends TrackEdgePoint> T next(Class<T> type, TrackNode node1, TrackNode node2, TrackEdge edge,
|
||||
public <T extends TrackEdgePoint> T next(EdgePointType<T> type, TrackNode node1, TrackNode node2, TrackEdge edge,
|
||||
double minPosition) {
|
||||
for (TrackEdgePoint point : type == GlobalStation.class ? stations : boundaries)
|
||||
if (point.getLocationOn(node1, node2, edge) > minPosition)
|
||||
for (TrackEdgePoint point : points)
|
||||
if (point.getType() == type && point.getLocationOn(node1, node2, edge) > minPosition)
|
||||
return (T) point;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T extends TrackEdgePoint> T get(Class<T> type, TrackNode node1, TrackNode node2, TrackEdge edge,
|
||||
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))
|
||||
|
@ -112,43 +80,42 @@ public class EdgeData {
|
|||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag signalCompound = new CompoundTag();
|
||||
if (hasBoundaries()) {
|
||||
signalCompound.put("Boundaries", NBTHelper.writeCompoundList(boundaries, this::writePoint));
|
||||
} else if (singleSignalGroup != null)
|
||||
signalCompound.putUUID("Group", singleSignalGroup);
|
||||
if (hasStations())
|
||||
signalCompound.put("Stations", NBTHelper.writeCompoundList(stations, this::writePoint));
|
||||
return signalCompound;
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
if (singleSignalGroup == passiveGroup)
|
||||
NBTHelper.putMarker(nbt, "PassiveGroup");
|
||||
else if (singleSignalGroup != null)
|
||||
nbt.putUUID("SignalGroup", singleSignalGroup);
|
||||
|
||||
if (hasPoints())
|
||||
nbt.put("Points", NBTHelper.writeCompoundList(points, point -> {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putUUID("Id", point.id);
|
||||
tag.putString("Type", point.getType()
|
||||
.getId()
|
||||
.toString());
|
||||
return tag;
|
||||
}));
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static EdgeData read(CompoundTag tag, TrackGraph graph) {
|
||||
EdgeData signalEdgeData = new EdgeData();
|
||||
if (tag.contains("Group"))
|
||||
signalEdgeData.singleSignalGroup = tag.getUUID("Group");
|
||||
if (tag.contains("Boundaries"))
|
||||
NBTHelper.iterateCompoundList(tag.getList("Boundaries", Tag.TAG_COMPOUND),
|
||||
readPoint(graph::getSignal, signalEdgeData.boundaries));
|
||||
if (tag.contains("Stations"))
|
||||
NBTHelper.iterateCompoundList(tag.getList("Stations", Tag.TAG_COMPOUND),
|
||||
readPoint(graph::getStation, signalEdgeData.stations));
|
||||
return signalEdgeData;
|
||||
}
|
||||
public static EdgeData read(CompoundTag nbt, TrackGraph graph) {
|
||||
EdgeData data = new EdgeData();
|
||||
if (nbt.contains("SignalGroup"))
|
||||
data.singleSignalGroup = nbt.getUUID("Group");
|
||||
else if (!nbt.contains("PassiveGroup"))
|
||||
data.singleSignalGroup = null;
|
||||
|
||||
private <T extends TrackEdgePoint> CompoundTag writePoint(T point) {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
compoundTag.putUUID("Id", point.id);
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
private static <T extends TrackEdgePoint> Consumer<CompoundTag> readPoint(Function<UUID, T> lookup,
|
||||
Collection<T> target) {
|
||||
return tag -> {
|
||||
UUID id = tag.getUUID("Id");
|
||||
T signal = lookup.apply(id);
|
||||
if (signal != null)
|
||||
target.add(signal);
|
||||
};
|
||||
if (nbt.contains("Points"))
|
||||
NBTHelper.iterateCompoundList(nbt.getList("Points", Tag.TAG_COMPOUND), tag -> {
|
||||
ResourceLocation location = new ResourceLocation(tag.getString("Type"));
|
||||
EdgePointType<?> type = EdgePointType.TYPES.get(location);
|
||||
if (type == null || !tag.contains("Id"))
|
||||
return;
|
||||
TrackEdgePoint point = graph.getPoint(type, tag.getUUID("Id"));
|
||||
if (point != null)
|
||||
data.points.add(point);
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,13 +5,10 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
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.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.management.GlobalStation;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalTileEntity.OverlayState;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalTileEntity.SignalState;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
|
@ -22,6 +19,7 @@ import net.minecraft.core.BlockPos;
|
|||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
|
||||
public class SignalBoundary extends TrackEdgePoint {
|
||||
|
||||
|
@ -29,16 +27,10 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
public Couple<UUID> groups;
|
||||
public Couple<Boolean> sidesToUpdate;
|
||||
|
||||
@Nullable
|
||||
public GlobalStation station;
|
||||
|
||||
public SignalBoundary(UUID id, BlockPos tilePosition, boolean front) {
|
||||
super(id);
|
||||
public SignalBoundary() {
|
||||
signals = Couple.create(HashSet::new);
|
||||
groups = Couple.create(null, null);
|
||||
sidesToUpdate = Couple.create(true, true);
|
||||
this.signals.get(front)
|
||||
.add(tilePosition);
|
||||
}
|
||||
|
||||
public void setGroup(TrackNode side, UUID groupId) {
|
||||
|
@ -47,6 +39,35 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
sidesToUpdate.set(primary, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMerge() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate(LevelAccessor level) {
|
||||
signals.forEach(s -> s.forEach(pos -> invalidateAt(level, pos)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tileAdded(BlockPos tilePos, boolean front) {
|
||||
signals.get(front)
|
||||
.add(tilePos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tileRemoved(BlockPos tilePos, boolean front) {
|
||||
signals.forEach(s -> s.remove(tilePos));
|
||||
if (signals.both(Set::isEmpty))
|
||||
removeFromAllGraphs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(TrackGraph graph) {
|
||||
super.onRemoved(graph);
|
||||
SignalPropagator.onSignalRemoved(graph, this);
|
||||
}
|
||||
|
||||
public void queueUpdate(TrackNode side) {
|
||||
sidesToUpdate.set(isPrimary(side), true);
|
||||
}
|
||||
|
@ -55,14 +76,13 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
return groups.get(isPrimary(side));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigateVia(TrackNode side) {
|
||||
return !signals.get(!isPrimary(side))
|
||||
return !signals.get(isPrimary(side))
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
public OverlayState getOverlayFor(BlockPos tile) {
|
||||
if (station != null)
|
||||
return OverlayState.SKIP;
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
Set<BlockPos> set = signals.get(first);
|
||||
for (BlockPos blockPos : set) {
|
||||
|
@ -92,7 +112,9 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
return SignalState.INVALID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(TrackGraph graph) {
|
||||
super.tick(graph);
|
||||
for (boolean front : Iterate.trueAndFalse) {
|
||||
if (!sidesToUpdate.get(front))
|
||||
continue;
|
||||
|
@ -101,12 +123,13 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
}
|
||||
}
|
||||
|
||||
public SignalBoundary(CompoundTag nbt) {
|
||||
super(nbt);
|
||||
@Override
|
||||
public void read(CompoundTag nbt) {
|
||||
super.read(nbt);
|
||||
|
||||
sidesToUpdate = Couple.create(true, true);
|
||||
signals = Couple.create(HashSet::new);
|
||||
groups = Couple.create(null, null);
|
||||
sidesToUpdate = Couple.create(true, true);
|
||||
|
||||
for (int i = 1; i <= 2; i++)
|
||||
if (nbt.contains("Tiles" + i)) {
|
||||
|
@ -121,12 +144,9 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
sidesToUpdate.set(i == 1, nbt.contains("Update" + i));
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
nbt.putUUID("Id", id);
|
||||
nbt.putDouble("Position", position);
|
||||
nbt.put("Edge", edgeLocation.serializeEach(loc -> NbtUtils.writeBlockPos(new BlockPos(loc))));
|
||||
|
||||
@Override
|
||||
public void write(CompoundTag nbt) {
|
||||
super.write(nbt);
|
||||
for (int i = 1; i <= 2; i++)
|
||||
if (!signals.get(i == 1)
|
||||
.isEmpty())
|
||||
|
@ -137,7 +157,6 @@ public class SignalBoundary extends TrackEdgePoint {
|
|||
for (int i = 1; i <= 2; i++)
|
||||
if (sidesToUpdate.get(i == 1))
|
||||
nbt.putBoolean("Update" + i, true);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,38 +16,13 @@ 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.entity.Train;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
public class SignalPropagator {
|
||||
|
||||
public static <T extends TrackEdgePoint> void onEdgePointAdded(TrackGraph graph, T point, Class<T> type) {
|
||||
Couple<TrackNodeLocation> edgeLocation = point.edgeLocation;
|
||||
Couple<TrackNode> startNodes = edgeLocation.map(graph::locateNode);
|
||||
Couple<TrackEdge> startEdges = startNodes.mapWithParams((l1, l2) -> graph.getConnectionsFrom(l1)
|
||||
.get(l2), startNodes.swap());
|
||||
|
||||
for (boolean front : Iterate.trueAndFalse) {
|
||||
TrackNode node1 = startNodes.get(front);
|
||||
TrackNode node2 = startNodes.get(!front);
|
||||
TrackEdge startEdge = startEdges.get(front);
|
||||
startEdge.getEdgeData()
|
||||
.addPoint(node1, node2, startEdge, point, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T extends TrackEdgePoint> void onEdgePointRemoved(TrackGraph graph, T point, Class<T> type) {
|
||||
Couple<TrackNodeLocation> edgeLocation = point.edgeLocation;
|
||||
Couple<TrackNode> startNodes = edgeLocation.map(graph::locateNode);
|
||||
startNodes.forEachWithParams((l1, l2) -> {
|
||||
TrackEdge trackEdge = graph.getConnectionsFrom(l1)
|
||||
.get(l2);
|
||||
trackEdge.getEdgeData()
|
||||
.removePoint(l1, l2, trackEdge, point);
|
||||
}, startNodes.swap());
|
||||
}
|
||||
|
||||
public static void onSignalRemoved(TrackGraph graph, SignalBoundary signal) {
|
||||
signal.sidesToUpdate.map($ -> false);
|
||||
for (boolean front : Iterate.trueAndFalse) {
|
||||
|
@ -61,8 +36,6 @@ public class SignalPropagator {
|
|||
return false;
|
||||
}, Predicates.alwaysFalse());
|
||||
}
|
||||
|
||||
onEdgePointRemoved(graph, signal, SignalBoundary.class);
|
||||
}
|
||||
|
||||
public static void notifySignalsOfNewNode(TrackGraph graph, TrackNode node) {
|
||||
|
@ -118,7 +91,7 @@ public class SignalPropagator {
|
|||
|
||||
// Check for signal on the same edge
|
||||
SignalBoundary immediateBoundary = startEdge.getEdgeData()
|
||||
.nextBoundary(node1, node2, startEdge, signal.getLocationOn(node1, node2, startEdge));
|
||||
.next(EdgePointType.SIGNAL, node1, node2, startEdge, signal.getLocationOn(node1, node2, startEdge));
|
||||
if (immediateBoundary != null) {
|
||||
if (boundaryCallback.test(Pair.of(node1, immediateBoundary)))
|
||||
notifyTrains(graph, startEdge, startEdges.get(!front));
|
||||
|
@ -160,14 +133,15 @@ public class SignalPropagator {
|
|||
EdgeData signalData = currentEdge.getEdgeData();
|
||||
|
||||
// no boundary- update group of edge
|
||||
if (!signalData.hasBoundaries()) {
|
||||
if (!signalData.hasSignalBoundaries()) {
|
||||
if (nonBoundaryCallback.test(signalData))
|
||||
notifyTrains(graph, currentEdge);
|
||||
continue;
|
||||
}
|
||||
|
||||
// other/own boundary found
|
||||
SignalBoundary nextBoundary = signalData.nextBoundary(currentNode, nextNode, currentEdge, 0);
|
||||
SignalBoundary nextBoundary =
|
||||
signalData.next(EdgePointType.SIGNAL, currentNode, nextNode, currentEdge, 0);
|
||||
if (boundaryCallback.test(Pair.of(currentNode, nextBoundary)))
|
||||
notifyTrains(graph, edge, oppositeEdge);
|
||||
continue EdgeWalk;
|
||||
|
|
|
@ -39,7 +39,7 @@ public class SignalRenderer extends SafeTileEntityRenderer<SignalTileEntity> {
|
|||
.renderInto(ms, buffer.getBuffer(RenderType.solid()));
|
||||
|
||||
BlockPos pos = te.getBlockPos();
|
||||
TrackTargetingBehaviour target = te.getTarget();
|
||||
TrackTargetingBehaviour<SignalBoundary> target = te.edgePoint;
|
||||
BlockPos targetPosition = target.getGlobalPosition();
|
||||
Level level = te.getLevel();
|
||||
BlockState trackState = level.getBlockState(targetPosition);
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
package com.simibubi.create.content.logistics.trains.management.signal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
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.management.GraphLocation;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.content.logistics.trains.management.TrackTargetingBehaviour;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction.AxisDirection;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
@ -37,20 +31,19 @@ public class SignalTileEntity extends SmartTileEntity {
|
|||
return this == RED || this == INVALID && renderTime % 40 < 3;
|
||||
}
|
||||
|
||||
public boolean isGreenLight(float renderTime) {
|
||||
public boolean isGreenLight(float renderTime) {
|
||||
return this == GREEN || this == TRAIN_ENTERING;
|
||||
}
|
||||
}
|
||||
|
||||
public UUID id;
|
||||
|
||||
public TrackTargetingBehaviour<SignalBoundary> edgePoint;
|
||||
|
||||
private SignalState state;
|
||||
private OverlayState overlay;
|
||||
private int switchToRedAfterTrainEntered;
|
||||
|
||||
public SignalTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
id = UUID.randomUUID();
|
||||
this.state = SignalState.INVALID;
|
||||
this.overlay = OverlayState.SKIP;
|
||||
}
|
||||
|
@ -58,7 +51,6 @@ public class SignalTileEntity extends SmartTileEntity {
|
|||
@Override
|
||||
protected void write(CompoundTag tag, boolean clientPacket) {
|
||||
super.write(tag, clientPacket);
|
||||
tag.putUUID("Id", id);
|
||||
NBTHelper.writeEnum(tag, "State", state);
|
||||
NBTHelper.writeEnum(tag, "Overlay", overlay);
|
||||
}
|
||||
|
@ -66,12 +58,16 @@ public class SignalTileEntity extends SmartTileEntity {
|
|||
@Override
|
||||
protected void read(CompoundTag tag, boolean clientPacket) {
|
||||
super.read(tag, clientPacket);
|
||||
id = tag.getUUID("Id");
|
||||
state = NBTHelper.readEnum(tag, "State", SignalState.class);
|
||||
overlay = NBTHelper.readEnum(tag, "Overlay", OverlayState.class);
|
||||
invalidateRenderBoundingBox();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SignalBoundary getSignal() {
|
||||
return edgePoint.getEdgePoint();
|
||||
}
|
||||
|
||||
public boolean isPowered() {
|
||||
return state == SignalState.RED;
|
||||
}
|
||||
|
@ -89,7 +85,8 @@ public class SignalTileEntity extends SmartTileEntity {
|
|||
|
||||
@Override
|
||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||
behaviours.add(new TrackTargetingBehaviour(this));
|
||||
edgePoint = new TrackTargetingBehaviour<>(this, EdgePointType.SIGNAL);
|
||||
behaviours.add(edgePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -97,7 +94,7 @@ public class SignalTileEntity extends SmartTileEntity {
|
|||
super.tick();
|
||||
if (level.isClientSide)
|
||||
return;
|
||||
SignalBoundary boundary = getOrCreateSignalBoundary();
|
||||
SignalBoundary boundary = getSignal();
|
||||
if (boundary == null) {
|
||||
enterState(SignalState.INVALID);
|
||||
setOverlay(OverlayState.RENDER);
|
||||
|
@ -107,86 +104,10 @@ public class SignalTileEntity extends SmartTileEntity {
|
|||
setOverlay(boundary.getOverlayFor(worldPosition));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setRemovedNotDueToChunkUnload() {
|
||||
if (!getTarget().hasValidTrack() || level.isClientSide) {
|
||||
super.setRemovedNotDueToChunkUnload();
|
||||
return;
|
||||
}
|
||||
|
||||
for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values()) {
|
||||
SignalBoundary signal = trackGraph.getSignal(id);
|
||||
if (signal == null)
|
||||
continue;
|
||||
for (boolean front : Iterate.trueAndFalse)
|
||||
signal.signals.get(front)
|
||||
.remove(worldPosition);
|
||||
if (signal.signals.getFirst()
|
||||
.isEmpty()
|
||||
&& signal.signals.getSecond()
|
||||
.isEmpty())
|
||||
trackGraph.removeSignal(id);
|
||||
}
|
||||
|
||||
super.setRemovedNotDueToChunkUnload();
|
||||
}
|
||||
|
||||
public SignalBoundary getOrCreateSignalBoundary() {
|
||||
for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values()) {
|
||||
SignalBoundary signal = trackGraph.getSignal(id);
|
||||
if (signal == null)
|
||||
continue;
|
||||
return signal;
|
||||
}
|
||||
|
||||
if (level.isClientSide)
|
||||
return null;
|
||||
|
||||
TrackTargetingBehaviour target = getTarget();
|
||||
if (!target.hasValidTrack())
|
||||
return null;
|
||||
GraphLocation loc = target.determineGraphLocation();
|
||||
if (loc == null)
|
||||
return null;
|
||||
|
||||
TrackGraph graph = loc.graph;
|
||||
TrackNode node1 = graph.locateNode(loc.edge.getFirst());
|
||||
TrackNode node2 = graph.locateNode(loc.edge.getSecond());
|
||||
TrackEdge edge = graph.getConnectionsFrom(node1)
|
||||
.get(node2);
|
||||
boolean positive = target.getTargetDirection() == AxisDirection.POSITIVE;
|
||||
|
||||
if (edge == null)
|
||||
return null;
|
||||
|
||||
EdgeData signalData = edge.getEdgeData();
|
||||
if (signalData.hasBoundaries()) {
|
||||
SignalBoundary nextBoundary = signalData.nextBoundary(node1, node2, edge, loc.position - .25f);
|
||||
if (nextBoundary != null && Mth.equal(nextBoundary.getLocationOn(node1, node2, edge), loc.position)) {
|
||||
nextBoundary.signals.get(positive)
|
||||
.add(worldPosition);
|
||||
id = nextBoundary.id;
|
||||
setChanged();
|
||||
return nextBoundary;
|
||||
}
|
||||
}
|
||||
|
||||
SignalBoundary signal = new SignalBoundary(id, worldPosition, positive);
|
||||
signal.setLocation(positive ? loc.edge : loc.edge.swap(),
|
||||
positive ? loc.position : edge.getLength(node1, node2) - loc.position);
|
||||
graph.addSignal(signal);
|
||||
setChanged();
|
||||
return signal;
|
||||
}
|
||||
|
||||
public TrackTargetingBehaviour getTarget() {
|
||||
return getBehaviour(TrackTargetingBehaviour.TYPE);
|
||||
}
|
||||
|
||||
public SignalState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
public OverlayState getOverlay() {
|
||||
return overlay;
|
||||
}
|
||||
|
@ -199,7 +120,7 @@ public class SignalTileEntity extends SmartTileEntity {
|
|||
}
|
||||
|
||||
public void enterState(SignalState state) {
|
||||
if (switchToRedAfterTrainEntered > 0)
|
||||
if (switchToRedAfterTrainEntered > 0)
|
||||
switchToRedAfterTrainEntered--;
|
||||
if (this.state == state)
|
||||
return;
|
||||
|
@ -213,7 +134,7 @@ public class SignalTileEntity extends SmartTileEntity {
|
|||
|
||||
@Override
|
||||
protected AABB createRenderBoundingBox() {
|
||||
return new AABB(worldPosition, getTarget().getGlobalPosition()).inflate(2);
|
||||
return new AABB(worldPosition, edgePoint.getGlobalPosition()).inflate(2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package com.simibubi.create.content.logistics.trains.management.signal;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
|
||||
public abstract class SingleTileEdgePoint extends TrackEdgePoint {
|
||||
|
||||
public BlockPos tilePos;
|
||||
|
||||
public BlockPos getTilePos() {
|
||||
return tilePos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tileAdded(BlockPos tilePos, boolean front) {
|
||||
this.tilePos = tilePos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tileRemoved(BlockPos tilePos, boolean front) {
|
||||
removeFromAllGraphs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate(LevelAccessor level) {
|
||||
invalidateAt(level, tilePos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMerge() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void read(CompoundTag nbt) {
|
||||
read(nbt, false);
|
||||
}
|
||||
|
||||
public void read(CompoundTag nbt, boolean migration) {
|
||||
if (migration)
|
||||
return;
|
||||
|
||||
super.read(nbt);
|
||||
tilePos = NbtUtils.readBlockPos(nbt.getCompound("TilePos"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(CompoundTag nbt) {
|
||||
super.write(nbt);
|
||||
nbt.put("TilePos", NbtUtils.writeBlockPos(tilePos));
|
||||
}
|
||||
|
||||
}
|
|
@ -2,32 +2,68 @@ package com.simibubi.create.content.logistics.trains.management.signal;
|
|||
|
||||
import java.util.UUID;
|
||||
|
||||
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.TrackTargetingBehaviour;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
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;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
|
||||
public class TrackEdgePoint {
|
||||
public abstract class TrackEdgePoint {
|
||||
|
||||
public UUID id;
|
||||
public Couple<TrackNodeLocation> edgeLocation;
|
||||
public double position;
|
||||
private EdgePointType<?> type;
|
||||
|
||||
public TrackEdgePoint(UUID id) {
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public TrackEdgePoint(CompoundTag nbt) {
|
||||
id = nbt.getUUID("Id");
|
||||
position = nbt.getDouble("Position");
|
||||
edgeLocation = Couple.deserializeEach(nbt.getList("Edge", Tag.TAG_COMPOUND),
|
||||
tag -> TrackNodeLocation.fromPackedPos(NbtUtils.readBlockPos(tag)));
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setType(EdgePointType<?> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public EdgePointType<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public abstract boolean canMerge();
|
||||
|
||||
public boolean canCoexistWith(EdgePointType<?> otherType, boolean front) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract void invalidate(LevelAccessor level);
|
||||
|
||||
protected void invalidateAt(LevelAccessor level, BlockPos tilePos) {
|
||||
TrackTargetingBehaviour<?> behaviour = TileEntityBehaviour.get(level, tilePos, TrackTargetingBehaviour.TYPE);
|
||||
if (behaviour == null)
|
||||
return;
|
||||
CompoundTag migrationData = new CompoundTag();
|
||||
write(migrationData);
|
||||
behaviour.invalidateEdgePoint(migrationData);
|
||||
}
|
||||
|
||||
public abstract void tileAdded(BlockPos tilePos, boolean front);
|
||||
|
||||
public abstract void tileRemoved(BlockPos tilePos, boolean front);
|
||||
|
||||
public void onRemoved(TrackGraph graph) {}
|
||||
|
||||
public void setLocation(Couple<TrackNodeLocation> nodes, double position) {
|
||||
this.edgeLocation = nodes;
|
||||
this.position = position;
|
||||
|
@ -37,9 +73,34 @@ public class TrackEdgePoint {
|
|||
return isPrimary(node1) ? edge.getLength(node1, node2) - position : position;
|
||||
}
|
||||
|
||||
public boolean canNavigateVia(TrackNode side) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isPrimary(TrackNode node1) {
|
||||
return edgeLocation.getSecond()
|
||||
.equals(node1.getLocation());
|
||||
}
|
||||
|
||||
public void read(CompoundTag nbt) {
|
||||
id = nbt.getUUID("Id");
|
||||
position = nbt.getDouble("Position");
|
||||
edgeLocation = Couple.deserializeEach(nbt.getList("Edge", Tag.TAG_COMPOUND),
|
||||
tag -> TrackNodeLocation.fromPackedPos(NbtUtils.readBlockPos(tag)));
|
||||
}
|
||||
|
||||
public void write(CompoundTag nbt) {
|
||||
nbt.putUUID("Id", id);
|
||||
nbt.putDouble("Position", position);
|
||||
nbt.put("Edge", edgeLocation.serializeEach(loc -> NbtUtils.writeBlockPos(new BlockPos(loc))));
|
||||
}
|
||||
|
||||
public void tick(TrackGraph graph) {}
|
||||
|
||||
protected void removeFromAllGraphs() {
|
||||
for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values())
|
||||
if (trackGraph.removePoint(getType(), id) != null)
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -228,7 +228,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
if (!entry.getValue()
|
||||
.isInside(pos))
|
||||
continue;
|
||||
if (world.getBlockEntity(entry.getKey())instanceof StationTileEntity station)
|
||||
if (world.getBlockEntity(entry.getKey()) instanceof StationTileEntity station)
|
||||
station.trackClicked(player, this, state, pos);
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
|
@ -245,7 +245,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
BlockPos girderPos = pPos.below()
|
||||
.offset(vec3.z * side, 0, vec3.x * side);
|
||||
BlockState girderState = pLevel.getBlockState(girderPos);
|
||||
if (girderState.getBlock()instanceof GirderBlock girderBlock
|
||||
if (girderState.getBlock() instanceof GirderBlock girderBlock
|
||||
&& !blockTicks.hasScheduledTick(girderPos, girderBlock))
|
||||
pLevel.scheduleTick(girderPos, girderBlock, 1);
|
||||
}
|
||||
|
@ -348,8 +348,8 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
@OnlyIn(Dist.CLIENT)
|
||||
public PartialModel prepareAssemblyOverlay(BlockGetter world, BlockPos pos, BlockState state, Direction direction,
|
||||
PoseStack ms) {
|
||||
TransformStack.cast(ms).rotateCentered(Direction.UP,
|
||||
AngleHelper.rad(AngleHelper.horizontalAngle(direction)));
|
||||
TransformStack.cast(ms)
|
||||
.rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(direction)));
|
||||
return AllBlockPartials.TRACK_ASSEMBLING_OVERLAY;
|
||||
}
|
||||
|
||||
|
@ -365,11 +365,13 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
Vec3 normal = getUpNormal(world, pos, state);
|
||||
Vec3 angles = TrackRenderer.getModelAngles(normal, directionVec);
|
||||
|
||||
TransformStack.cast(ms).centre()
|
||||
TransformStack.cast(ms)
|
||||
.centre()
|
||||
.rotateYRadians(angles.y)
|
||||
.rotateXRadians(angles.x)
|
||||
.unCentre()
|
||||
.translate(0, axis.y != 0 ? 7 / 16f : 0, axis.y != 0 ? direction.getStep() * 2.5f / 16f : 0);
|
||||
.translate(0, axis.y != 0 ? 7 / 16f : 0, axis.y != 0 ? direction.getStep() * 2.5f / 16f : 0)
|
||||
.scale(type == RenderedTrackOverlayType.STATION ? 1 + 1 / 512f : 1);
|
||||
|
||||
return type == RenderedTrackOverlayType.STATION ? AllBlockPartials.TRACK_STATION_OVERLAY
|
||||
: type == RenderedTrackOverlayType.SIGNAL ? AllBlockPartials.TRACK_SIGNAL_OVERLAY
|
||||
|
|
|
@ -93,6 +93,7 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE
|
|||
TrackTileEntity other = (TrackTileEntity) blockEntity;
|
||||
other.removeConnection(bezierConnection.tePositions.getFirst());
|
||||
}
|
||||
AllPackets.channel.send(packetTarget(), new RemoveTileEntityPacket(worldPosition));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.simibubi.create.content.logistics.trains.entity.Train;
|
|||
import com.simibubi.create.content.logistics.trains.management.GlobalStation;
|
||||
import com.simibubi.create.content.logistics.trains.management.ScheduleRuntime;
|
||||
import com.simibubi.create.content.logistics.trains.management.ScheduleRuntime.State;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.content.logistics.trains.management.signal.SignalBoundary;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
|
@ -62,11 +63,11 @@ public class DumpRailwaysCommand {
|
|||
+ graph.getNodes()
|
||||
.size()
|
||||
+ " Nodes", graph.color.getRGB());
|
||||
Collection<SignalBoundary> signals = graph.getSignals();
|
||||
Collection<SignalBoundary> signals = graph.getPoints(EdgePointType.SIGNAL);
|
||||
if (!signals.isEmpty())
|
||||
chat.accept(" -> " + signals.size() + " registered Signals", blue);
|
||||
for (GlobalStation globalStation : graph.getStations()) {
|
||||
BlockPos pos = globalStation.stationPos;
|
||||
for (GlobalStation globalStation : graph.getPoints(EdgePointType.STATION)) {
|
||||
BlockPos pos = globalStation.getTilePos();
|
||||
chat.accept(" -> " + globalStation.name + " (" + globalStation.id.toString()
|
||||
.substring(0, 5) + ") [" + pos.getX() + "," + pos.getY() + "," + pos.getZ() + "]", darkBlue);
|
||||
if (globalStation.getPresentTrain() != null) {
|
||||
|
|
|
@ -129,12 +129,11 @@ public abstract class SmartTileEntity extends CachedRenderBBTileEntity implement
|
|||
}
|
||||
|
||||
protected void setRemovedNotDueToChunkUnload() {
|
||||
|
||||
forEachBehaviour(TileEntityBehaviour::remove);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoved() {
|
||||
forEachBehaviour(TileEntityBehaviour::remove);
|
||||
super.setRemoved();
|
||||
|
||||
if (!unloaded) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.function.BiConsumer;
|
|||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
@ -62,6 +63,14 @@ public class Couple<T> extends Pair<T, T> implements Iterable<T> {
|
|||
return Couple.create(function.apply(first, values.first), function.apply(second, values.second));
|
||||
}
|
||||
|
||||
public boolean both(Predicate<T> test) {
|
||||
return test.test(getFirst()) && test.test(getSecond());
|
||||
}
|
||||
|
||||
public boolean either(Predicate<T> test) {
|
||||
return test.test(getFirst()) || test.test(getSecond());
|
||||
}
|
||||
|
||||
public void replace(Function<T, T> function) {
|
||||
setFirst(function.apply(getFirst()));
|
||||
setSecond(function.apply(getSecond()));
|
||||
|
|
Loading…
Reference in a new issue