The Client is always right

- Fixed edge points getting wiped near where two graphs just merged
- Fixed edge points not migrating to modified edges properly
- Graph edge points are now synched by netcode (signals, stations)
- Fixed incorrect stopping position when approaching station manually while the train is still moving backwards
- Fixed single-group edges not being deserialised correctly
- Edge data is now synched by netcode
- Signal edge groups are now synched by netcode
- Signal block indication can now get necessary information client-side
This commit is contained in:
simibubi 2022-03-04 18:30:18 +01:00
parent 3362e6a05e
commit 3c64ada850
23 changed files with 592 additions and 245 deletions

View file

@ -46,6 +46,7 @@ public class GlobalRailwayManager {
loadTrackData(serverPlayer.getServer()); loadTrackData(serverPlayer.getServer());
trackNetworks.values() trackNetworks.values()
.forEach(g -> sync.sendFullGraphTo(g, serverPlayer)); .forEach(g -> sync.sendFullGraphTo(g, serverPlayer));
sync.sendEdgeGroups(signalEdgeGroups.keySet(), serverPlayer);
} }
} }
@ -150,21 +151,21 @@ public class GlobalRailwayManager {
for (Train train : trains.values()) for (Train train : trains.values())
train.tick(level); train.tick(level);
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_H)) { if (AllKeys.isKeyDown(GLFW.GLFW_KEY_H) && AllKeys.altDown())
trackNetworks.values() trackNetworks.values()
.forEach(TrackGraph::debugViewSignalData); .forEach(TrackGraph::debugViewSignalData);
} if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown())
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown()) {
trackNetworks.values() trackNetworks.values()
.forEach(TrackGraph::debugViewNodes); .forEach(TrackGraph::debugViewNodes);
} }
}
public void clientTick() { public void clientTick() {
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && !AllKeys.altDown()) { if (AllKeys.isKeyDown(GLFW.GLFW_KEY_H) && !AllKeys.altDown())
trackNetworks.values()
.forEach(TrackGraph::debugViewSignalData);
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && !AllKeys.altDown())
trackNetworks.values() trackNetworks.values()
.forEach(TrackGraph::debugViewNodes); .forEach(TrackGraph::debugViewNodes);
} }
}
} }

View file

@ -75,6 +75,7 @@ public class TrackGraph {
public <T extends TrackEdgePoint> void addPoint(EdgePointType<T> type, T point) { public <T extends TrackEdgePoint> void addPoint(EdgePointType<T> type, T point) {
edgePoints.put(type, point); edgePoints.put(type, point);
EdgePointManager.onEdgePointAdded(this, point, type); EdgePointManager.onEdgePointAdded(this, point, type);
Create.RAILWAYS.sync.pointAdded(this, point);
markDirty(); markDirty();
} }
@ -91,6 +92,7 @@ public class TrackGraph {
if (removed == null) if (removed == null)
return null; return null;
EdgePointManager.onEdgePointRemoved(this, removed, type); EdgePointManager.onEdgePointRemoved(this, removed, type);
Create.RAILWAYS.sync.pointRemoved(this, removed);
markDirty(); markDirty();
return removed; return removed;
} }
@ -197,12 +199,13 @@ public class TrackGraph {
TrackNode n2 = toOther.locateNode(node2.location); TrackNode n2 = toOther.locateNode(node2.location);
if (n1 == null || n2 == null) if (n1 == null || n2 == null)
return; return;
toOther.putConnection(n1, n2, edge); if (toOther.putConnection(n1, n2, edge)) {
Create.RAILWAYS.sync.edgeAdded(toOther, n1, n2, edge); Create.RAILWAYS.sync.edgeAdded(toOther, n1, n2, edge);
Create.RAILWAYS.sync.edgeDataChanged(toOther, n1, n2, edge);
}
})); }));
edgePoints.transferAll(toOther.edgePoints); edgePoints.transferAll(toOther, toOther.edgePoints);
nodes.clear(); nodes.clear();
connectionsByNode.clear(); connectionsByNode.clear();
@ -325,9 +328,13 @@ public class TrackGraph {
map2.remove(node1); map2.remove(node1);
} }
public void putConnection(TrackNode node1, TrackNode node2, TrackEdge edge) { public boolean putConnection(TrackNode node1, TrackNode node2, TrackEdge edge) {
connectionsByNode.computeIfAbsent(node1, n -> new IdentityHashMap<>()) Map<TrackNode, TrackEdge> connections = connectionsByNode.computeIfAbsent(node1, n -> new IdentityHashMap<>());
.put(node2, edge); if (connections.containsKey(node2) && connections.get(node2)
.getEdgeData()
.hasPoints())
return false;
return connections.put(node2, edge) == null;
} }
public void markDirty() { public void markDirty() {

View file

@ -0,0 +1,26 @@
package com.simibubi.create.content.logistics.trains;
import java.util.UUID;
import java.util.function.Supplier;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.networking.SimplePacketBase;
import net.minecraftforge.network.NetworkEvent.Context;
public abstract class TrackGraphPacket extends SimplePacketBase {
public UUID graphId;
public boolean packetDeletesGraph;
@Override
public void handle(Supplier<Context> context) {
context.get()
.enqueueWork(() -> handle(CreateClient.RAILWAYS, CreateClient.RAILWAYS.getOrCreateGraph(graphId)));
context.get()
.setPacketHandled(true);
}
protected abstract void handle(GlobalRailwayManager manager, TrackGraph graph);
}

View file

@ -1,65 +1,69 @@
package com.simibubi.create.content.logistics.trains; package com.simibubi.create.content.logistics.trains;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.function.Supplier;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.CreateClient; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
import com.simibubi.create.content.logistics.trains.management.signal.SignalEdgeGroupPacket;
import com.simibubi.create.content.logistics.trains.management.signal.TrackEdgePoint;
import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.networking.SimplePacketBase;
import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.Pair;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.network.NetworkEvent.Context;
import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.network.PacketDistributor;
public class TrackGraphSync { public class TrackGraphSync {
List<RailGraphSyncPacket> queuedPackets = new ArrayList<>(); List<TrackGraphPacket> queuedPackets = new ArrayList<>();
public void serverTick() { public void serverTick() {
finish(); flushGraphPacket(null);
if (queuedPackets.isEmpty()) if (queuedPackets.isEmpty())
return; return;
for (RailGraphSyncPacket packet : queuedPackets) { for (TrackGraphPacket packet : queuedPackets) {
if (packet.delete || Create.RAILWAYS.trackNetworks.containsKey(packet.graphId)) { if (!packet.packetDeletesGraph && !Create.RAILWAYS.trackNetworks.containsKey(packet.graphId))
continue;
AllPackets.channel.send(PacketDistributor.ALL.noArg(), packet); AllPackets.channel.send(PacketDistributor.ALL.noArg(), packet);
} }
}
queuedPackets.clear(); queuedPackets.clear();
} }
// //
public void nodeAdded(TrackGraph graph, TrackNode node) { public void nodeAdded(TrackGraph graph, TrackNode node) {
flushPacket(graph.id); flushGraphPacket(graph.id);
currentPacket.addedNodes.put(node.getNetId(), Pair.of(node.getLocation(), node.getNormal())); currentGraphSyncPacket.addedNodes.put(node.getNetId(), Pair.of(node.getLocation(), node.getNormal()));
} }
public void edgeAdded(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) { public void edgeAdded(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) {
flushPacket(graph.id); flushGraphPacket(graph.id);
currentPacket.addedEdges.add(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge)); currentGraphSyncPacket.addedEdges.add(Pair.of(Couple.create(node1.getNetId(), node2.getNetId()), edge));
}
public void pointAdded(TrackGraph graph, TrackEdgePoint point) {
flushGraphPacket(graph.id);
currentGraphSyncPacket.addedEdgePoints.add(point);
}
public void pointRemoved(TrackGraph graph, TrackEdgePoint point) {
flushGraphPacket(graph.id);
currentGraphSyncPacket.removedEdgePoints.add(point.getId());
} }
public void nodeRemoved(TrackGraph graph, TrackNode node) { public void nodeRemoved(TrackGraph graph, TrackNode node) {
flushPacket(graph.id); flushGraphPacket(graph.id);
int nodeId = node.getNetId(); int nodeId = node.getNetId();
if (currentPacket.addedNodes.remove(nodeId) == null) if (currentGraphSyncPacket.addedNodes.remove(nodeId) == null)
currentPacket.removedNodes.add(nodeId); currentGraphSyncPacket.removedNodes.add(nodeId);
currentPacket.addedEdges.removeIf(pair -> { currentGraphSyncPacket.addedEdges.removeIf(pair -> {
Couple<Integer> ids = pair.getFirst(); Couple<Integer> ids = pair.getFirst();
return ids.getFirst() return ids.getFirst()
.intValue() == nodeId .intValue() == nodeId
@ -69,183 +73,104 @@ public class TrackGraphSync {
} }
public void graphSplit(TrackGraph graph, Set<TrackGraph> additional) { public void graphSplit(TrackGraph graph, Set<TrackGraph> additional) {
flushPacket(graph.id); flushGraphPacket(graph.id);
additional.forEach(rg -> currentPacket.splitSubGraphs.put(rg.nodesById.keySet() additional.forEach(rg -> currentGraphSyncPacket.splitSubGraphs.put(rg.nodesById.keySet()
.stream() .stream()
.findFirst() .findFirst()
.get(), rg.id)); .get(), rg.id));
} }
public void graphRemoved(TrackGraph graph) { public void graphRemoved(TrackGraph graph) {
flushPacket(graph.id); flushGraphPacket(graph.id);
currentPacket.delete = true; currentGraphSyncPacket.packetDeletesGraph = true;
}
public void finish() {
flushPacket(null);
} }
// //
public void sendEdgeGroups(Collection<UUID> ids, ServerPlayer player) {
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), new SignalEdgeGroupPacket(ids, true));
}
public void edgeGroupCreated(UUID id) {
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new SignalEdgeGroupPacket(ImmutableList.of(id), true));
}
public void edgeGroupRemoved(UUID id) {
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new SignalEdgeGroupPacket(ImmutableList.of(id), false));
}
//
public void edgeDataChanged(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge) {
flushGraphPacket(graph.id);
currentGraphSyncPacket.syncEdgeData(node1, node2, edge);
}
public void edgeDataChanged(TrackGraph graph, TrackNode node1, TrackNode node2, TrackEdge edge, TrackEdge edge2) {
flushGraphPacket(graph.id);
currentGraphSyncPacket.syncEdgeData(node1, node2, edge);
currentGraphSyncPacket.syncEdgeData(node2, node1, edge2);
}
public void sendFullGraphTo(TrackGraph graph, ServerPlayer player) { public void sendFullGraphTo(TrackGraph graph, ServerPlayer player) {
RailGraphSyncPacket packet = new RailGraphSyncPacket(graph.id); TrackGraphSyncPacket packet = new TrackGraphSyncPacket(graph.id);
int sent = 0; int sent = 0;
for (TrackNode node : graph.nodes.values()) { for (TrackNode node : graph.nodes.values()) {
RailGraphSyncPacket currentPacket = packet; TrackGraphSyncPacket currentPacket = packet;
currentPacket.addedNodes.put(node.getNetId(), Pair.of(node.getLocation(), node.getNormal())); currentPacket.addedNodes.put(node.getNetId(), Pair.of(node.getLocation(), node.getNormal()));
if (!graph.connectionsByNode.containsKey(node)) if (!graph.connectionsByNode.containsKey(node))
continue; continue;
graph.connectionsByNode.get(node) graph.connectionsByNode.get(node)
.forEach((node2, edge) -> currentPacket.addedEdges .forEach((node2, edge) -> {
.add(Pair.of(Couple.create(node.getNetId(), node2.getNetId()), edge))); Couple<Integer> key = Couple.create(node.getNetId(), node2.getNetId());
currentPacket.addedEdges.add(Pair.of(key, edge));
currentPacket.syncEdgeData(node, node2, edge);
});
if (sent++ < 1000)
continue;
if (sent++ > 1000) {
sent = 0; sent = 0;
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), packet); packet = flushAndCreateNew(graph, player, packet);
packet = new RailGraphSyncPacket(graph.id); }
for (EdgePointType<?> type : EdgePointType.TYPES.values()) {
for (TrackEdgePoint point : graph.getPoints(type)) {
packet.addedEdgePoints.add(point);
if (sent++ < 1000)
continue;
sent = 0;
packet = flushAndCreateNew(graph, player, packet);
} }
} }
if (sent > 0) if (sent > 0)
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), packet); flushAndCreateNew(graph, player, packet);
} }
private RailGraphSyncPacket currentPacket; private TrackGraphSyncPacket flushAndCreateNew(TrackGraph graph, ServerPlayer player, TrackGraphSyncPacket packet) {
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), packet);
packet = new TrackGraphSyncPacket(graph.id);
return packet;
}
private void flushPacket(@Nullable UUID graphId) { //
if (currentPacket != null) {
if (currentPacket.graphId.equals(graphId)) private TrackGraphSyncPacket currentGraphSyncPacket;
private void flushGraphPacket(@Nullable UUID graphId) {
if (currentGraphSyncPacket != null) {
if (currentGraphSyncPacket.graphId.equals(graphId))
return; return;
queuedPackets.add(currentPacket); queuedPackets.add(currentGraphSyncPacket);
currentPacket = null; currentGraphSyncPacket = null;
} }
if (graphId != null) if (graphId != null)
currentPacket = new RailGraphSyncPacket(graphId); currentGraphSyncPacket = new TrackGraphSyncPacket(graphId);
}
public static class RailGraphSyncPacket extends SimplePacketBase {
UUID graphId;
Map<Integer, Pair<TrackNodeLocation, Vec3>> addedNodes;
List<Pair<Couple<Integer>, TrackEdge>> addedEdges;
List<Integer> removedNodes;
Map<Integer, UUID> splitSubGraphs;
boolean delete;
public RailGraphSyncPacket(UUID graphId) {
this.graphId = graphId;
addedNodes = new HashMap<>();
addedEdges = new ArrayList<>();
removedNodes = new ArrayList<>();
splitSubGraphs = new HashMap<>();
delete = false;
}
public RailGraphSyncPacket(FriendlyByteBuf buffer) {
int size;
graphId = buffer.readUUID();
delete = buffer.readBoolean();
if (delete)
return;
addedNodes = new HashMap<>();
addedEdges = new ArrayList<>();
removedNodes = new ArrayList<>();
splitSubGraphs = new HashMap<>();
size = buffer.readVarInt();
for (int i = 0; i < size; i++)
removedNodes.add(buffer.readVarInt());
size = buffer.readVarInt();
for (int i = 0; i < size; i++)
addedNodes.put(buffer.readVarInt(),
Pair.of(TrackNodeLocation.fromPackedPos(buffer.readBlockPos()), VecHelper.read(buffer)));
size = buffer.readVarInt();
for (int i = 0; i < size; i++)
addedEdges.add(Pair.of(Couple.create(buffer::readVarInt), TrackEdge.read(buffer)));
size = buffer.readVarInt();
for (int i = 0; i < size; i++)
splitSubGraphs.put(buffer.readVarInt(), buffer.readUUID());
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeUUID(graphId);
buffer.writeBoolean(delete);
if (delete)
return;
buffer.writeVarInt(removedNodes.size());
removedNodes.forEach(buffer::writeVarInt);
buffer.writeVarInt(addedNodes.size());
addedNodes.forEach((node, loc) -> {
buffer.writeVarInt(node);
buffer.writeBlockPos(new BlockPos(loc.getFirst()));
VecHelper.write(loc.getSecond(), buffer);
});
buffer.writeVarInt(addedEdges.size());
addedEdges.forEach(pair -> {
pair.getFirst()
.forEach(buffer::writeVarInt);
pair.getSecond()
.write(buffer);
});
buffer.writeVarInt(splitSubGraphs.size());
splitSubGraphs.forEach((node, uuid) -> {
buffer.writeVarInt(node);
buffer.writeUUID(uuid);
});
}
@Override
public void handle(Supplier<Context> context) {
context.get()
.enqueueWork(() -> {
GlobalRailwayManager manager = CreateClient.RAILWAYS;
TrackGraph railGraph = manager.getOrCreateGraph(graphId);
if (delete) {
manager.removeGraph(railGraph);
return;
}
for (int nodeId : removedNodes) {
TrackNode node = railGraph.getNode(nodeId);
if (node != null)
railGraph.removeNode(null, node.getLocation());
}
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()
.map(railGraph::getNode);
if (nodes.getFirst() != null && nodes.getSecond() != null)
railGraph.putConnection(nodes.getFirst(), nodes.getSecond(), pair.getSecond());
}
if (!splitSubGraphs.isEmpty())
railGraph.findDisconnectedGraphs(splitSubGraphs)
.forEach(manager::putGraph);
});
context.get()
.setPacketHandled(true);
}
} }
} }

View file

@ -0,0 +1,243 @@
package com.simibubi.create.content.logistics.trains;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.UUID;
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.TrackEdgePoint;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Pair;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.phys.Vec3;
public class TrackGraphSyncPacket extends TrackGraphPacket {
Map<Integer, Pair<TrackNodeLocation, Vec3>> addedNodes;
List<Pair<Couple<Integer>, TrackEdge>> addedEdges;
List<Integer> removedNodes;
List<TrackEdgePoint> addedEdgePoints;
List<UUID> removedEdgePoints;
Map<Integer, UUID> splitSubGraphs;
Map<Couple<Integer>, Pair<Integer, List<UUID>>> updatedEdgeData;
static final int NULL_GROUP = 0, PASSIVE_GROUP = 1, GROUP = 2;
public TrackGraphSyncPacket(UUID graphId) {
this.graphId = graphId;
addedNodes = new HashMap<>();
addedEdges = new ArrayList<>();
removedNodes = new ArrayList<>();
addedEdgePoints = new ArrayList<>();
removedEdgePoints = new ArrayList<>();
updatedEdgeData = new HashMap<>();
splitSubGraphs = new HashMap<>();
packetDeletesGraph = false;
}
public TrackGraphSyncPacket(FriendlyByteBuf buffer) {
int size;
graphId = buffer.readUUID();
packetDeletesGraph = buffer.readBoolean();
if (packetDeletesGraph)
return;
addedNodes = new HashMap<>();
addedEdges = new ArrayList<>();
addedEdgePoints = new ArrayList<>();
removedEdgePoints = new ArrayList<>();
removedNodes = new ArrayList<>();
splitSubGraphs = new HashMap<>();
updatedEdgeData = new HashMap<>();
size = buffer.readVarInt();
for (int i = 0; i < size; i++)
removedNodes.add(buffer.readVarInt());
size = buffer.readVarInt();
for (int i = 0; i < size; i++)
addedNodes.put(buffer.readVarInt(),
Pair.of(TrackNodeLocation.fromPackedPos(buffer.readBlockPos()), VecHelper.read(buffer)));
size = buffer.readVarInt();
for (int i = 0; i < size; i++)
addedEdges.add(Pair.of(Couple.create(buffer::readVarInt), TrackEdge.read(buffer)));
size = buffer.readVarInt();
for (int i = 0; i < size; i++)
addedEdgePoints.add(EdgePointType.read(buffer));
size = buffer.readVarInt();
for (int i = 0; i < size; i++)
removedEdgePoints.add(buffer.readUUID());
size = buffer.readVarInt();
for (int i = 0; i < size; i++) {
ArrayList<UUID> list = new ArrayList<>();
Couple<Integer> key = Couple.create(buffer::readInt);
Pair<Integer, List<UUID>> entry = Pair.of(buffer.readVarInt(), list);
int size2 = buffer.readVarInt();
for (int j = 0; j < size2; j++)
list.add(buffer.readUUID());
updatedEdgeData.put(key, entry);
}
size = buffer.readVarInt();
for (int i = 0; i < size; i++)
splitSubGraphs.put(buffer.readVarInt(), buffer.readUUID());
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeUUID(graphId);
buffer.writeBoolean(packetDeletesGraph);
if (packetDeletesGraph)
return;
buffer.writeVarInt(removedNodes.size());
removedNodes.forEach(buffer::writeVarInt);
buffer.writeVarInt(addedNodes.size());
addedNodes.forEach((node, loc) -> {
buffer.writeVarInt(node);
buffer.writeBlockPos(new BlockPos(loc.getFirst()));
VecHelper.write(loc.getSecond(), buffer);
});
buffer.writeVarInt(addedEdges.size());
addedEdges.forEach(pair -> {
pair.getFirst()
.forEach(buffer::writeVarInt);
pair.getSecond()
.write(buffer);
});
buffer.writeVarInt(addedEdgePoints.size());
addedEdgePoints.forEach(ep -> ep.write(buffer));
buffer.writeVarInt(removedEdgePoints.size());
removedEdgePoints.forEach(buffer::writeUUID);
buffer.writeVarInt(updatedEdgeData.size());
for (Entry<Couple<Integer>, Pair<Integer, List<UUID>>> entry : updatedEdgeData.entrySet()) {
entry.getKey()
.forEach(buffer::writeInt);
Pair<Integer, List<UUID>> pair = entry.getValue();
buffer.writeVarInt(pair.getFirst());
List<UUID> list = pair.getSecond();
buffer.writeVarInt(list.size());
list.forEach(buffer::writeUUID);
}
buffer.writeVarInt(splitSubGraphs.size());
splitSubGraphs.forEach((node, uuid) -> {
buffer.writeVarInt(node);
buffer.writeUUID(uuid);
});
}
@Override
protected void handle(GlobalRailwayManager manager, TrackGraph graph) {
if (packetDeletesGraph) {
manager.removeGraph(graph);
return;
}
for (int nodeId : removedNodes) {
TrackNode node = graph.getNode(nodeId);
if (node != null)
graph.removeNode(null, node.getLocation());
}
for (Entry<Integer, Pair<TrackNodeLocation, Vec3>> entry : addedNodes.entrySet()) {
Integer nodeId = entry.getKey();
Pair<TrackNodeLocation, Vec3> nodeLocation = entry.getValue();
graph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond());
}
for (Pair<Couple<Integer>, TrackEdge> pair : addedEdges) {
Couple<TrackNode> nodes = pair.getFirst()
.map(graph::getNode);
if (nodes.getFirst() != null && nodes.getSecond() != null)
graph.putConnection(nodes.getFirst(), nodes.getSecond(), pair.getSecond());
}
for (TrackEdgePoint edgePoint : addedEdgePoints)
graph.edgePoints.put(edgePoint.getType(), edgePoint);
for (UUID uuid : removedEdgePoints)
for (EdgePointType<?> type : EdgePointType.TYPES.values())
graph.edgePoints.remove(type, uuid);
handleEdgeData(manager, graph);
if (!splitSubGraphs.isEmpty())
graph.findDisconnectedGraphs(splitSubGraphs)
.forEach(manager::putGraph);
}
protected void handleEdgeData(GlobalRailwayManager manager, TrackGraph graph) {
for (Entry<Couple<Integer>, Pair<Integer, List<UUID>>> entry : updatedEdgeData.entrySet()) {
List<UUID> idList = entry.getValue()
.getSecond();
int groupType = entry.getValue()
.getFirst();
Couple<TrackNode> nodes = entry.getKey()
.map(graph::getNode);
if (nodes.either(Objects::isNull))
continue;
TrackEdge edge = graph.getConnectionsFrom(nodes.getFirst())
.get(nodes.getSecond());
if (edge == null)
continue;
EdgeData edgeData = new EdgeData();
if (groupType == NULL_GROUP)
edgeData.singleSignalGroup = null;
else if (groupType == PASSIVE_GROUP)
edgeData.singleSignalGroup = EdgeData.passiveGroup;
else
edgeData.singleSignalGroup = idList.get(0);
List<TrackEdgePoint> points = edgeData.getPoints();
edge.edgeData = edgeData;
for (int i = groupType == GROUP ? 1 : 0; i < idList.size(); i++) {
UUID uuid = idList.get(i);
for (EdgePointType<?> type : EdgePointType.TYPES.values()) {
TrackEdgePoint point = graph.edgePoints.get(type, uuid);
if (point == null)
continue;
points.add(point);
break;
}
}
}
}
public void syncEdgeData(TrackNode node1, TrackNode node2, TrackEdge edge) {
Couple<Integer> key = Couple.create(node1.getNetId(), node2.getNetId());
List<UUID> list = new ArrayList<>();
EdgeData edgeData = edge.getEdgeData();
int groupType = edgeData.hasSignalBoundaries() ? NULL_GROUP
: EdgeData.passiveGroup.equals(edgeData.singleSignalGroup) ? PASSIVE_GROUP : GROUP;
if (groupType == GROUP)
list.add(edgeData.singleSignalGroup);
for (TrackEdgePoint point : edgeData.getPoints())
list.add(point.getId());
updatedEdgeData.put(key, Pair.of(groupType, list));
}
}

View file

@ -27,7 +27,7 @@ public class TrackSavedData extends SavedData {
} }
private static TrackSavedData load(CompoundTag nbt) { private static TrackSavedData load(CompoundTag nbt) {
TrackSavedData sd = new TrackSavedData(); TrackSavedData sd = new TrackSavedData();//TODO load trains before everything else
sd.trackNetworks = new HashMap<>(); sd.trackNetworks = new HashMap<>();
sd.signalEdgeGroups = new HashMap<>(); sd.signalEdgeGroups = new HashMap<>();
NBTHelper.iterateCompoundList(nbt.getList("RailGraphs", Tag.TAG_COMPOUND), c -> { NBTHelper.iterateCompoundList(nbt.getList("RailGraphs", Tag.TAG_COMPOUND), c -> {

View file

@ -94,11 +94,6 @@ public class Navigation {
if (waitingForSignal == null) if (waitingForSignal == null)
distanceToSignal = Double.MAX_VALUE; distanceToSignal = Double.MAX_VALUE;
if (train.getCurrentStation() != null) {
int i = 0;
i++;
}
if (distanceToSignal > 1 / 16f) { if (distanceToSignal > 1 / 16f) {
signalScout.node1 = leadingPoint.node1; signalScout.node1 = leadingPoint.node1;
signalScout.node2 = leadingPoint.node2; signalScout.node2 = leadingPoint.node2;

View file

@ -241,10 +241,11 @@ public class Train {
if (navigation.destination != null) { if (navigation.destination != null) {
boolean recalculate = navigation.distanceToDestination % 100 > 20; boolean recalculate = navigation.distanceToDestination % 100 > 20;
boolean imminentRecalculate = navigation.distanceToDestination > 5; boolean imminentRecalculate = navigation.distanceToDestination > 5;
navigation.distanceToDestination -= Math.abs(distance); double toSubstract = navigation.destinationBehindTrain ? -distance : distance;
navigation.distanceToDestination -= toSubstract;
boolean signalMode = navigation.waitingForSignal != null; boolean signalMode = navigation.waitingForSignal != null;
if (signalMode) { if (signalMode) {
navigation.distanceToSignal -= Math.abs(distance); navigation.distanceToSignal -= toSubstract;
recalculate = navigation.distanceToSignal % 100 > 20; recalculate = navigation.distanceToSignal % 100 > 20;
} }
if (recalculate && (signalMode ? navigation.distanceToSignal : navigation.distanceToDestination) % 100 <= 20 if (recalculate && (signalMode ? navigation.distanceToSignal : navigation.distanceToDestination) % 100 <= 20

View file

@ -9,6 +9,7 @@ import com.simibubi.create.content.logistics.trains.entity.Train;
import com.simibubi.create.content.logistics.trains.management.signal.SingleTileEdgePoint; import com.simibubi.create.content.logistics.trains.management.signal.SingleTileEdgePoint;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
public class GlobalStation extends SingleTileEdgePoint { public class GlobalStation extends SingleTileEdgePoint {
@ -27,12 +28,24 @@ public class GlobalStation extends SingleTileEdgePoint {
nearestTrain = new WeakReference<Train>(null); nearestTrain = new WeakReference<Train>(null);
} }
@Override
public void read(FriendlyByteBuf buffer) {
super.read(buffer);
name = buffer.readUtf();
}
@Override @Override
public void write(CompoundTag nbt) { public void write(CompoundTag nbt) {
super.write(nbt); super.write(nbt);
nbt.putString("Name", name); nbt.putString("Name", name);
} }
@Override
public void write(FriendlyByteBuf buffer) {
super.write(buffer);
buffer.writeUtf(name);
}
public boolean canApproachFrom(TrackNode side) { public boolean canApproachFrom(TrackNode side) {
return isPrimary(side); return isPrimary(side);
} }

View file

@ -74,8 +74,11 @@ public class StationEditPacket extends TileEntityConfigurationPacket<StationTile
if (!name.isBlank()) { if (!name.isBlank()) {
GlobalStation station = te.getStation(); GlobalStation station = te.getStation();
if (station != null) GraphLocation graphLocation = te.edgePoint.determineGraphLocation();
if (station != null && graphLocation != null) {
station.name = name; station.name = name;
Create.RAILWAYS.sync.pointAdded(graphLocation.graph, station);
}
Create.RAILWAYS.markTracksDirty(); Create.RAILWAYS.markTracksDirty();
} }

View file

@ -144,6 +144,8 @@ public class StationScreen extends AbstractStationScreen {
int trainIconWidth = getTrainIconWidth(imminentTrain); int trainIconWidth = getTrainIconWidth(imminentTrain);
int targetPos = background.width / 2 - trainIconWidth / 2; int targetPos = background.width / 2 - trainIconWidth / 2;
float f = (float) (imminentTrain.navigation.distanceToDestination / 15f); float f = (float) (imminentTrain.navigation.distanceToDestination / 15f);
if (imminentTrain.currentStation.equals(station.getId()))
f = 0;
trainPosition.startWithValue(targetPos - (targetPos + 5) * f); trainPosition.startWithValue(targetPos - (targetPos + 5) * f);
} }
return; return;
@ -167,15 +169,16 @@ public class StationScreen extends AbstractStationScreen {
return; return;
} }
if (train.navigation.destination != station && train.getCurrentStation() != station) { boolean trainAtStation = train.currentStation != null && train.currentStation.equals(station.getId());
if (train.navigation.destination != station && !trainAtStation) {
leavingAnimation = 80; leavingAnimation = 80;
return; return;
} }
disassembleTrainButton.active = train.getCurrentStation() == station; // TODO te.canAssemble disassembleTrainButton.active = trainAtStation; // TODO te.canAssemble
openScheduleButton.active = train.runtime.schedule != null; openScheduleButton.active = train.runtime.schedule != null;
float f = (float) (train.navigation.distanceToDestination / 30f); float f = trainAtStation ? 0 : (float) (train.navigation.distanceToDestination / 30f);
trainPosition.setValue(targetPos - (targetPos + trainIconWidth) * f); trainPosition.setValue(targetPos - (targetPos + trainIconWidth) * f);
} }

View file

@ -68,13 +68,12 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
@Override @Override
public void read(CompoundTag nbt, boolean clientPacket) { public void read(CompoundTag nbt, boolean clientPacket) {
UUID prevId = id;
id = nbt.getUUID("Id"); id = nbt.getUUID("Id");
targetTrack = NbtUtils.readBlockPos(nbt.getCompound("TargetTrack")); targetTrack = NbtUtils.readBlockPos(nbt.getCompound("TargetTrack"));
targetDirection = nbt.getBoolean("TargetDirection") ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE; targetDirection = nbt.getBoolean("TargetDirection") ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE;
if (nbt.contains("Migrate")) if (nbt.contains("Migrate"))
migrationData = nbt.getCompound("Migrate"); migrationData = nbt.getCompound("Migrate");
if (clientPacket && !prevId.equals(id)) if (clientPacket)
edgePoint = null; edgePoint = null;
super.read(nbt, clientPacket); super.read(nbt, clientPacket);
} }
@ -86,7 +85,6 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
public void invalidateEdgePoint(CompoundTag migrationData) { public void invalidateEdgePoint(CompoundTag migrationData) {
this.migrationData = migrationData; this.migrationData = migrationData;
id = UUID.randomUUID();
edgePoint = null; edgePoint = null;
tileEntity.sendData(); tileEntity.sendData();
} }
@ -100,6 +98,8 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public T createEdgePoint() { public T createEdgePoint() {
boolean isClientSide = getWorld().isClientSide;
if (migrationData == null || isClientSide)
for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values()) { // TODO thread breach for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values()) { // TODO thread breach
T point = trackGraph.getPoint(edgePointType, id); T point = trackGraph.getPoint(edgePointType, id);
if (point == null) if (point == null)
@ -107,7 +107,7 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
return point; return point;
} }
if (getWorld().isClientSide) if (isClientSide)
return null; return null;
if (!hasValidTrack()) if (!hasValidTrack())
return null; return null;
@ -126,6 +126,10 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
if (edge == null) if (edge == null)
return null; return null;
double length = edge.getLength(node1, node2);
CompoundTag data = migrationData;
migrationData = null;
EdgeData signalData = edge.getEdgeData(); EdgeData signalData = edge.getEdgeData();
if (signalData.hasPoints()) { if (signalData.hasPoints()) {
for (EdgePointType<?> otherType : EdgePointType.TYPES.values()) { for (EdgePointType<?> otherType : EdgePointType.TYPES.values()) {
@ -147,19 +151,13 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
} }
T point = edgePointType.create(); T point = edgePointType.create();
boolean reverseEdge = front || point instanceof SingleTileEdgePoint;
if (data != null)
point.read(data, true);
point.setId(id); point.setId(id);
point.setLocation(reverseEdge ? loc.edge : loc.edge.swap(), reverseEdge ? loc.position : length - loc.position);
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); point.tileAdded(getPos(), front);
loc.graph.addPoint(edgePointType, point); loc.graph.addPoint(edgePointType, point);
return point; return point;

View file

@ -1,5 +1,6 @@
package com.simibubi.create.content.logistics.trains.management.edgePoint; package com.simibubi.create.content.logistics.trains.management.edgePoint;
import com.simibubi.create.Create;
import com.simibubi.create.content.logistics.trains.TrackEdge; import com.simibubi.create.content.logistics.trains.TrackEdge;
import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackGraph;
import com.simibubi.create.content.logistics.trains.TrackNode; import com.simibubi.create.content.logistics.trains.TrackNode;
@ -22,6 +23,7 @@ public class EdgePointManager {
TrackEdge startEdge = startEdges.get(front); TrackEdge startEdge = startEdges.get(front);
startEdge.getEdgeData() startEdge.getEdgeData()
.addPoint(node1, node2, startEdge, point); .addPoint(node1, node2, startEdge, point);
Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge);
} }
} }
@ -32,8 +34,11 @@ public class EdgePointManager {
startNodes.forEachWithParams((l1, l2) -> { startNodes.forEachWithParams((l1, l2) -> {
TrackEdge trackEdge = graph.getConnectionsFrom(l1) TrackEdge trackEdge = graph.getConnectionsFrom(l1)
.get(l2); .get(l2);
if (trackEdge == null)
return;
trackEdge.getEdgeData() trackEdge.getEdgeData()
.removePoint(l1, l2, trackEdge, point); .removePoint(l1, l2, trackEdge, point);
Create.RAILWAYS.sync.edgeDataChanged(graph, l1, l2, trackEdge);
}, startNodes.swap()); }, startNodes.swap());
} }

View file

@ -6,6 +6,7 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.UUID; import java.util.UUID;
import com.simibubi.create.Create;
import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackGraph;
import com.simibubi.create.content.logistics.trains.management.signal.TrackEdgePoint; import com.simibubi.create.content.logistics.trains.management.signal.TrackEdgePoint;
import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.NBTHelper;
@ -54,9 +55,13 @@ public class EdgePointStorage {
.forEach(p -> p.tick(graph))); .forEach(p -> p.tick(graph)));
} }
public void transferAll(EdgePointStorage other) { public void transferAll(TrackGraph target, EdgePointStorage other) {
pointsByType.forEach((type, map) -> other.getMap(type) pointsByType.forEach((type, map) -> {
.putAll(map)); other.getMap(type)
.putAll(map);
map.values()
.forEach(ep -> Create.RAILWAYS.sync.pointAdded(target, ep));
});
pointsByType.clear(); pointsByType.clear();
} }
@ -83,7 +88,7 @@ public class EdgePointStorage {
Map<UUID, TrackEdgePoint> map = getMap(type); Map<UUID, TrackEdgePoint> map = getMap(type);
NBTHelper.iterateCompoundList(list, tag -> { NBTHelper.iterateCompoundList(list, tag -> {
TrackEdgePoint edgePoint = type.create(); TrackEdgePoint edgePoint = type.create();
edgePoint.read(tag); edgePoint.read(tag, false);
map.put(edgePoint.getId(), edgePoint); map.put(edgePoint.getId(), edgePoint);
}); });
} }

View file

@ -9,6 +9,7 @@ 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.SignalBoundary;
import com.simibubi.create.content.logistics.trains.management.signal.TrackEdgePoint; import com.simibubi.create.content.logistics.trains.management.signal.TrackEdgePoint;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public class EdgePointType<T extends TrackEdgePoint> { public class EdgePointType<T extends TrackEdgePoint> {
@ -43,4 +44,12 @@ public class EdgePointType<T extends TrackEdgePoint> {
return id; return id;
} }
public static TrackEdgePoint read(FriendlyByteBuf buffer) {
ResourceLocation type = buffer.readResourceLocation();
EdgePointType<?> edgePointType = TYPES.get(type);
TrackEdgePoint point = edgePointType.create();
point.read(buffer);
return point;
}
} }

View file

@ -101,7 +101,7 @@ public class EdgeData {
public static EdgeData read(CompoundTag nbt, TrackGraph graph) { public static EdgeData read(CompoundTag nbt, TrackGraph graph) {
EdgeData data = new EdgeData(); EdgeData data = new EdgeData();
if (nbt.contains("SignalGroup")) if (nbt.contains("SignalGroup"))
data.singleSignalGroup = nbt.getUUID("Group"); data.singleSignalGroup = nbt.getUUID("SignalGroup");
else if (!nbt.contains("PassiveGroup")) else if (!nbt.contains("PassiveGroup"))
data.singleSignalGroup = null; data.singleSignalGroup = null;

View file

@ -19,6 +19,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
public class SignalBoundary extends TrackEdgePoint { public class SignalBoundary extends TrackEdgePoint {
@ -124,8 +125,11 @@ public class SignalBoundary extends TrackEdgePoint {
} }
@Override @Override
public void read(CompoundTag nbt) { public void read(CompoundTag nbt, boolean migration) {
super.read(nbt); super.read(nbt, migration);
if (migration)
return;
sidesToUpdate = Couple.create(true, true); sidesToUpdate = Couple.create(true, true);
signals = Couple.create(HashSet::new); signals = Couple.create(HashSet::new);
@ -144,6 +148,15 @@ public class SignalBoundary extends TrackEdgePoint {
sidesToUpdate.set(i == 1, nbt.contains("Update" + i)); sidesToUpdate.set(i == 1, nbt.contains("Update" + i));
} }
@Override
public void read(FriendlyByteBuf buffer) {
super.read(buffer);
for (int i = 1; i <= 2; i++) {
if (buffer.readBoolean())
groups.set(i == 1, buffer.readUUID());
}
}
@Override @Override
public void write(CompoundTag nbt) { public void write(CompoundTag nbt) {
super.write(nbt); super.write(nbt);
@ -159,4 +172,15 @@ public class SignalBoundary extends TrackEdgePoint {
nbt.putBoolean("Update" + i, true); nbt.putBoolean("Update" + i, true);
} }
@Override
public void write(FriendlyByteBuf buffer) {
super.write(buffer);
for (int i = 1; i <= 2; i++) {
boolean hasGroup = groups.get(i == 1) != null;
buffer.writeBoolean(hasGroup);
if (hasGroup)
buffer.writeUUID(groups.get(i == 1));
}
}
} }

View file

@ -0,0 +1,56 @@
package com.simibubi.create.content.logistics.trains.management.signal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
import java.util.function.Supplier;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.networking.SimplePacketBase;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.network.NetworkEvent.Context;
public class SignalEdgeGroupPacket extends SimplePacketBase {
Collection<UUID> ids;
boolean add;
public SignalEdgeGroupPacket(Collection<UUID> ids, boolean add) {
this.ids = ids;
this.add = add;
}
public SignalEdgeGroupPacket(FriendlyByteBuf buffer) {
ids = new ArrayList<>();
add = buffer.readBoolean();
int size = buffer.readVarInt();
for (int i = 0; i < size; i++)
ids.add(buffer.readUUID());
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeBoolean(add);
buffer.writeVarInt(ids.size());
ids.forEach(buffer::writeUUID);
}
@Override
public void handle(Supplier<Context> context) {
context.get()
.enqueueWork(() -> {
Map<UUID, SignalEdgeGroup> signalEdgeGroups = CreateClient.RAILWAYS.signalEdgeGroups;
for (UUID id : ids) {
if (add)
signalEdgeGroups.put(id, new SignalEdgeGroup(id));
else
signalEdgeGroups.remove(id);
}
});
context.get()
.setPacketHandled(true);
}
}

View file

@ -13,6 +13,7 @@ import com.google.common.base.Predicates;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.logistics.trains.TrackEdge; import com.simibubi.create.content.logistics.trains.TrackEdge;
import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackGraph;
import com.simibubi.create.content.logistics.trains.TrackGraphSync;
import com.simibubi.create.content.logistics.trains.TrackNode; import com.simibubi.create.content.logistics.trains.TrackNode;
import com.simibubi.create.content.logistics.trains.TrackNodeLocation; import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
import com.simibubi.create.content.logistics.trains.entity.Train; import com.simibubi.create.content.logistics.trains.entity.Train;
@ -28,7 +29,9 @@ public class SignalPropagator {
for (boolean front : Iterate.trueAndFalse) { for (boolean front : Iterate.trueAndFalse) {
if (signal.sidesToUpdate.get(front)) if (signal.sidesToUpdate.get(front))
continue; continue;
Create.RAILWAYS.signalEdgeGroups.remove(signal.groups.get(front)); UUID id = signal.groups.get(front);
if (Create.RAILWAYS.signalEdgeGroups.remove(id) != null)
Create.RAILWAYS.sync.edgeGroupRemoved(id);
walkSignals(graph, signal, front, pair -> { walkSignals(graph, signal, front, pair -> {
TrackNode node1 = pair.getFirst(); TrackNode node1 = pair.getFirst();
SignalBoundary boundary = pair.getSecond(); SignalBoundary boundary = pair.getSecond();
@ -51,23 +54,30 @@ public class SignalPropagator {
public static void propagateSignalGroup(TrackGraph graph, SignalBoundary signal, boolean front) { public static void propagateSignalGroup(TrackGraph graph, SignalBoundary signal, boolean front) {
Map<UUID, SignalEdgeGroup> globalGroups = Create.RAILWAYS.signalEdgeGroups; Map<UUID, SignalEdgeGroup> globalGroups = Create.RAILWAYS.signalEdgeGroups;
TrackGraphSync sync = Create.RAILWAYS.sync;
SignalEdgeGroup group = new SignalEdgeGroup(UUID.randomUUID()); SignalEdgeGroup group = new SignalEdgeGroup(UUID.randomUUID());
UUID groupId = group.id; UUID groupId = group.id;
globalGroups.put(groupId, group); globalGroups.put(groupId, group);
sync.edgeGroupCreated(groupId);
signal.groups.set(front, groupId); signal.groups.set(front, groupId);
sync.pointAdded(graph, signal);
walkSignals(graph, signal, front, pair -> { walkSignals(graph, signal, front, pair -> {
TrackNode node1 = pair.getFirst(); TrackNode node1 = pair.getFirst();
SignalBoundary boundary = pair.getSecond(); SignalBoundary boundary = pair.getSecond();
UUID currentGroup = boundary.getGroup(node1); UUID currentGroup = boundary.getGroup(node1);
if (currentGroup != null) if (currentGroup != null)
globalGroups.remove(currentGroup); if (globalGroups.remove(currentGroup) != null)
sync.edgeGroupRemoved(currentGroup);
boundary.setGroup(node1, groupId); boundary.setGroup(node1, groupId);
sync.pointAdded(graph, boundary);
return true; return true;
}, signalData -> { }, signalData -> {
if (signalData.singleSignalGroup != null) if (signalData.singleSignalGroup != null)
globalGroups.remove(signalData.singleSignalGroup); if (globalGroups.remove(signalData.singleSignalGroup) != null)
sync.edgeGroupRemoved(signalData.singleSignalGroup);
signalData.singleSignalGroup = groupId; signalData.singleSignalGroup = groupId;
return true; return true;
@ -85,16 +95,19 @@ public class SignalPropagator {
TrackNode node1 = startNodes.get(front); TrackNode node1 = startNodes.get(front);
TrackNode node2 = startNodes.get(!front); TrackNode node2 = startNodes.get(!front);
TrackEdge startEdge = startEdges.get(front); TrackEdge startEdge = startEdges.get(front);
TrackEdge oppositeEdge = startEdges.get(!front);
if (startEdge == null) if (startEdge == null)
return; return;
Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge, oppositeEdge);
// Check for signal on the same edge // Check for signal on the same edge
SignalBoundary immediateBoundary = startEdge.getEdgeData() SignalBoundary immediateBoundary = startEdge.getEdgeData()
.next(EdgePointType.SIGNAL, node1, node2, startEdge, signal.getLocationOn(node1, node2, startEdge)); .next(EdgePointType.SIGNAL, node1, node2, startEdge, signal.getLocationOn(node1, node2, startEdge));
if (immediateBoundary != null) { if (immediateBoundary != null) {
if (boundaryCallback.test(Pair.of(node1, immediateBoundary))) if (boundaryCallback.test(Pair.of(node1, immediateBoundary)))
notifyTrains(graph, startEdge, startEdges.get(!front)); notifyTrains(graph, startEdge, oppositeEdge);
return; return;
} }
@ -134,16 +147,20 @@ public class SignalPropagator {
// no boundary- update group of edge // no boundary- update group of edge
if (!signalData.hasSignalBoundaries()) { if (!signalData.hasSignalBoundaries()) {
if (nonBoundaryCallback.test(signalData)) if (!nonBoundaryCallback.test(signalData))
continue;
notifyTrains(graph, currentEdge); notifyTrains(graph, currentEdge);
Create.RAILWAYS.sync.edgeDataChanged(graph, currentNode, nextNode, edge, oppositeEdge);
continue; continue;
} }
// other/own boundary found // other/own boundary found
SignalBoundary nextBoundary = SignalBoundary nextBoundary =
signalData.next(EdgePointType.SIGNAL, currentNode, nextNode, currentEdge, 0); signalData.next(EdgePointType.SIGNAL, currentNode, nextNode, currentEdge, 0);
if (boundaryCallback.test(Pair.of(currentNode, nextBoundary))) if (boundaryCallback.test(Pair.of(currentNode, nextBoundary))) {
notifyTrains(graph, edge, oppositeEdge); notifyTrains(graph, edge, oppositeEdge);
Create.RAILWAYS.sync.edgeDataChanged(graph, currentNode, nextNode, edge, oppositeEdge);
}
continue EdgeWalk; continue EdgeWalk;
} }

View file

@ -34,15 +34,10 @@ public abstract class SingleTileEdgePoint extends TrackEdgePoint {
} }
@Override @Override
public final void read(CompoundTag nbt) {
read(nbt, false);
}
public void read(CompoundTag nbt, boolean migration) { public void read(CompoundTag nbt, boolean migration) {
super.read(nbt, migration);
if (migration) if (migration)
return; return;
super.read(nbt);
tilePos = NbtUtils.readBlockPos(nbt.getCompound("TilePos")); tilePos = NbtUtils.readBlockPos(nbt.getCompound("TilePos"));
} }

View file

@ -16,6 +16,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
public abstract class TrackEdgePoint { public abstract class TrackEdgePoint {
@ -82,19 +83,35 @@ public abstract class TrackEdgePoint {
.equals(node1.getLocation()); .equals(node1.getLocation());
} }
public void read(CompoundTag nbt) { public void read(CompoundTag nbt, boolean migration) {
if (migration)
return;
id = nbt.getUUID("Id"); id = nbt.getUUID("Id");
position = nbt.getDouble("Position"); position = nbt.getDouble("Position");
edgeLocation = Couple.deserializeEach(nbt.getList("Edge", Tag.TAG_COMPOUND), edgeLocation = Couple.deserializeEach(nbt.getList("Edge", Tag.TAG_COMPOUND),
tag -> TrackNodeLocation.fromPackedPos(NbtUtils.readBlockPos(tag))); tag -> TrackNodeLocation.fromPackedPos(NbtUtils.readBlockPos(tag)));
} }
public void read(FriendlyByteBuf buffer) {
id = buffer.readUUID();
edgeLocation = Couple.create(() -> TrackNodeLocation.fromPackedPos(buffer.readBlockPos()));
position = buffer.readDouble();
}
public void write(CompoundTag nbt) { public void write(CompoundTag nbt) {
nbt.putUUID("Id", id); nbt.putUUID("Id", id);
nbt.putDouble("Position", position); nbt.putDouble("Position", position);
nbt.put("Edge", edgeLocation.serializeEach(loc -> NbtUtils.writeBlockPos(new BlockPos(loc)))); nbt.put("Edge", edgeLocation.serializeEach(loc -> NbtUtils.writeBlockPos(new BlockPos(loc))));
} }
public void write(FriendlyByteBuf buffer) {
buffer.writeResourceLocation(type.getId());
buffer.writeUUID(id);
edgeLocation.forEach(loc -> buffer.writeBlockPos(new BlockPos(loc)));
buffer.writeDouble(position);
}
public void tick(TrackGraph graph) {} public void tick(TrackGraph graph) {}
protected void removeFromAllGraphs() { protected void removeFromAllGraphs() {

View file

@ -6,7 +6,7 @@ import java.util.UUID;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.ArgumentBuilder;
import com.simibubi.create.Create; import com.simibubi.create.CreateClient;
import com.simibubi.create.content.logistics.trains.GlobalRailwayManager; import com.simibubi.create.content.logistics.trains.GlobalRailwayManager;
import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackGraph;
import com.simibubi.create.content.logistics.trains.entity.Train; import com.simibubi.create.content.logistics.trains.entity.Train;
@ -40,7 +40,7 @@ public class DumpRailwaysCommand {
} }
static void fillReport(ServerLevel level, BiConsumer<String, Integer> chat) { static void fillReport(ServerLevel level, BiConsumer<String, Integer> chat) {
GlobalRailwayManager railways = Create.RAILWAYS; GlobalRailwayManager railways = CreateClient.RAILWAYS;
int white = ChatFormatting.WHITE.getColor(); int white = ChatFormatting.WHITE.getColor();
int blue = 0xD3DEDC; int blue = 0xD3DEDC;
int darkBlue = 0x92A9BD; int darkBlue = 0x92A9BD;
@ -68,6 +68,8 @@ public class DumpRailwaysCommand {
chat.accept(" -> " + signals.size() + " registered Signals", blue); chat.accept(" -> " + signals.size() + " registered Signals", blue);
for (GlobalStation globalStation : graph.getPoints(EdgePointType.STATION)) { for (GlobalStation globalStation : graph.getPoints(EdgePointType.STATION)) {
BlockPos pos = globalStation.getTilePos(); BlockPos pos = globalStation.getTilePos();
if (pos == null)
pos = BlockPos.ZERO;
chat.accept(" -> " + globalStation.name + " (" + globalStation.id.toString() chat.accept(" -> " + globalStation.name + " (" + globalStation.id.toString()
.substring(0, 5) + ") [" + pos.getX() + "," + pos.getY() + "," + pos.getZ() + "]", darkBlue); .substring(0, 5) + ") [" + pos.getX() + "," + pos.getY() + "," + pos.getZ() + "]", darkBlue);
if (globalStation.getPresentTrain() != null) { if (globalStation.getPresentTrain() != null) {

View file

@ -43,10 +43,11 @@ import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket;
import com.simibubi.create.content.logistics.packet.ConfigureStockswitchPacket; import com.simibubi.create.content.logistics.packet.ConfigureStockswitchPacket;
import com.simibubi.create.content.logistics.packet.FunnelFlapPacket; import com.simibubi.create.content.logistics.packet.FunnelFlapPacket;
import com.simibubi.create.content.logistics.packet.TunnelFlapPacket; import com.simibubi.create.content.logistics.packet.TunnelFlapPacket;
import com.simibubi.create.content.logistics.trains.TrackGraphSync.RailGraphSyncPacket; import com.simibubi.create.content.logistics.trains.TrackGraphSyncPacket;
import com.simibubi.create.content.logistics.trains.management.StationEditPacket; import com.simibubi.create.content.logistics.trains.management.StationEditPacket;
import com.simibubi.create.content.logistics.trains.management.TrainEditPacket; import com.simibubi.create.content.logistics.trains.management.TrainEditPacket;
import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleEditPacket; import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleEditPacket;
import com.simibubi.create.content.logistics.trains.management.signal.SignalEdgeGroupPacket;
import com.simibubi.create.content.schematics.packet.ConfigureSchematicannonPacket; import com.simibubi.create.content.schematics.packet.ConfigureSchematicannonPacket;
import com.simibubi.create.content.schematics.packet.InstantSchematicPacket; import com.simibubi.create.content.schematics.packet.InstantSchematicPacket;
import com.simibubi.create.content.schematics.packet.SchematicPlacePacket; import com.simibubi.create.content.schematics.packet.SchematicPlacePacket;
@ -132,7 +133,8 @@ public enum AllPackets {
SOUL_PULSE(SoulPulseEffectPacket.class, SoulPulseEffectPacket::new, PLAY_TO_CLIENT), SOUL_PULSE(SoulPulseEffectPacket.class, SoulPulseEffectPacket::new, PLAY_TO_CLIENT),
PERSISTENT_DATA(ISyncPersistentData.PersistentDataPacket.class, ISyncPersistentData.PersistentDataPacket::new, PLAY_TO_CLIENT), PERSISTENT_DATA(ISyncPersistentData.PersistentDataPacket.class, ISyncPersistentData.PersistentDataPacket::new, PLAY_TO_CLIENT),
SYNC_POTATO_PROJECTILE_TYPES(PotatoProjectileTypeManager.SyncPacket.class, PotatoProjectileTypeManager.SyncPacket::new, PLAY_TO_CLIENT), SYNC_POTATO_PROJECTILE_TYPES(PotatoProjectileTypeManager.SyncPacket.class, PotatoProjectileTypeManager.SyncPacket::new, PLAY_TO_CLIENT),
SYNC_RAIL_GRAPH(RailGraphSyncPacket.class, RailGraphSyncPacket::new, PLAY_TO_CLIENT), SYNC_RAIL_GRAPH(TrackGraphSyncPacket.class, TrackGraphSyncPacket::new, PLAY_TO_CLIENT),
SYNC_EDGE_GROUP(SignalEdgeGroupPacket.class, SignalEdgeGroupPacket::new, PLAY_TO_CLIENT),
REMOVE_TE(RemoveTileEntityPacket.class, RemoveTileEntityPacket::new, PLAY_TO_CLIENT), REMOVE_TE(RemoveTileEntityPacket.class, RemoveTileEntityPacket::new, PLAY_TO_CLIENT),
; ;