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.Create; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; import com.simibubi.create.content.logistics.trains.management.edgePoint.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.network.FriendlyByteBuf; import net.minecraft.world.phys.Vec3; public class TrackGraphSyncPacket extends TrackGraphPacket { Map> addedNodes; List, TrackMaterial>, BezierConnection>> addedEdges; List removedNodes; List addedEdgePoints; List removedEdgePoints; Map> splitSubGraphs; Map, Pair>> updatedEdgeData; boolean fullWipe; static final int NULL_GROUP = 0, PASSIVE_GROUP = 1, GROUP = 2; public TrackGraphSyncPacket(UUID graphId, int netId) { this.graphId = graphId; this.netId = netId; 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(); netId = buffer.readInt(); packetDeletesGraph = buffer.readBoolean(); fullWipe = buffer.readBoolean(); if (packetDeletesGraph) return; DimensionPalette dimensions = DimensionPalette.receive(buffer); 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.receive(buffer, dimensions), VecHelper.read(buffer))); size = buffer.readVarInt(); for (int i = 0; i < size; i++) addedEdges.add( Pair.of(Pair.of(Couple.create(buffer::readVarInt), TrackMaterial.deserialize(buffer.readUtf())), buffer.readBoolean() ? new BezierConnection(buffer) : null)); size = buffer.readVarInt(); for (int i = 0; i < size; i++) addedEdgePoints.add(EdgePointType.read(buffer, dimensions)); 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 list = new ArrayList<>(); Couple key = Couple.create(buffer::readInt); Pair> 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(), Pair.of(buffer.readInt(), buffer.readUUID())); } @Override public void write(FriendlyByteBuf buffer) { buffer.writeUUID(graphId); buffer.writeInt(netId); buffer.writeBoolean(packetDeletesGraph); buffer.writeBoolean(fullWipe); if (packetDeletesGraph) return; // Populate and send palette ahead of time DimensionPalette dimensions = new DimensionPalette(); addedNodes.forEach((node, loc) -> dimensions.encode(loc.getFirst().dimension)); addedEdgePoints.forEach(ep -> ep.edgeLocation.forEach(loc -> dimensions.encode(loc.dimension))); dimensions.send(buffer); buffer.writeVarInt(removedNodes.size()); removedNodes.forEach(buffer::writeVarInt); buffer.writeVarInt(addedNodes.size()); addedNodes.forEach((node, loc) -> { buffer.writeVarInt(node); loc.getFirst() .send(buffer, dimensions); VecHelper.write(loc.getSecond(), buffer); }); buffer.writeVarInt(addedEdges.size()); addedEdges.forEach(pair -> { pair.getFirst().getFirst() .forEach(buffer::writeVarInt); buffer.writeUtf(pair.getFirst().getSecond().id.toString()); BezierConnection turn = pair.getSecond(); buffer.writeBoolean(turn != null); if (turn != null) turn.write(buffer); }); buffer.writeVarInt(addedEdgePoints.size()); addedEdgePoints.forEach(ep -> ep.write(buffer, dimensions)); buffer.writeVarInt(removedEdgePoints.size()); removedEdgePoints.forEach(buffer::writeUUID); buffer.writeVarInt(updatedEdgeData.size()); for (Entry, Pair>> entry : updatedEdgeData.entrySet()) { entry.getKey() .forEach(buffer::writeInt); Pair> pair = entry.getValue(); buffer.writeVarInt(pair.getFirst()); List list = pair.getSecond(); buffer.writeVarInt(list.size()); list.forEach(buffer::writeUUID); } buffer.writeVarInt(splitSubGraphs.size()); splitSubGraphs.forEach((node, p) -> { buffer.writeVarInt(node); buffer.writeInt(p.getFirst()); buffer.writeUUID(p.getSecond()); }); } @Override protected void handle(GlobalRailwayManager manager, TrackGraph graph) { if (packetDeletesGraph) { manager.removeGraph(graph); return; } if (fullWipe) { manager.removeGraph(graph); graph = Create.RAILWAYS.sided(null) .getOrCreateGraph(graphId, netId); } for (int nodeId : removedNodes) { TrackNode node = graph.getNode(nodeId); if (node != null) graph.removeNode(null, node.getLocation()); } for (Entry> entry : addedNodes.entrySet()) { Integer nodeId = entry.getKey(); Pair nodeLocation = entry.getValue(); graph.loadNode(nodeLocation.getFirst(), nodeId, nodeLocation.getSecond()); } for (Pair, TrackMaterial>, BezierConnection> pair : addedEdges) { Couple nodes = pair.getFirst().getFirst() .map(graph::getNode); TrackNode node1 = nodes.getFirst(); TrackNode node2 = nodes.getSecond(); if (node1 != null && node2 != null) graph.putConnection(node1, node2, new TrackEdge(node1, node2, pair.getSecond(), pair.getFirst().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(null, splitSubGraphs) .forEach(manager::putGraph); } protected void handleEdgeData(GlobalRailwayManager manager, TrackGraph graph) { for (Entry, Pair>> entry : updatedEdgeData.entrySet()) { List idList = entry.getValue() .getSecond(); int groupType = entry.getValue() .getFirst(); Couple 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(edge); if (groupType == NULL_GROUP) edgeData.setSingleSignalGroup(null, null); else if (groupType == PASSIVE_GROUP) edgeData.setSingleSignalGroup(null, EdgeData.passiveGroup); else edgeData.setSingleSignalGroup(null, idList.get(0)); List 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 key = Couple.create(node1.getNetId(), node2.getNetId()); List list = new ArrayList<>(); EdgeData edgeData = edge.getEdgeData(); int groupType = edgeData.hasSignalBoundaries() ? NULL_GROUP : EdgeData.passiveGroup.equals(edgeData.getSingleSignalGroup()) ? PASSIVE_GROUP : GROUP; if (groupType == GROUP) list.add(edgeData.getSingleSignalGroup()); for (TrackEdgePoint point : edgeData.getPoints()) list.add(point.getId()); updatedEdgeData.put(key, Pair.of(groupType, list)); } }