/*public static void Apply(HarmonyInstance harmony) * { * var fix = typeof(BuildingDecorationDetour).GetMethod("LoadPaths"); * harmony.Patch(OriginalMethod, new HarmonyMethod(fix), null, null); * * }*/ /*public static void Revert(HarmonyInstance harmony) * { * harmony.Unpatch(OriginalMethod, HarmonyPatchType.Prefix); * }*/ /*private static MethodInfo OriginalMethod => typeof(BuildingDecoration).GetMethod("LoadPaths");*/ #endregion DETOUR private static HashSet <ConnectionPoint> ReleaseCollidingSegments() { // We obtain a list of nodes adjacent to the deleted segment to know where to reconnect HashSet <ConnectionPoint> borderNodes = new HashSet <ConnectionPoint>(); if (ToolControllerDetour.CollidingSegmentsCache2 == null) { return(null); } foreach (ushort segment in ToolControllerDetour.CollidingSegmentsCache2) { //Debug.Log("Releasing segment " + segment); NetSegment netSegment = NetAccess.GetSegment(segment); // We keep untouchable segments if ((netSegment.m_flags & NetSegment.Flags.Untouchable) != NetSegment.Flags.None) { continue; } bool inverted = ((netSegment.m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None); borderNodes.Add(new ConnectionPoint(netSegment.m_startNode, netSegment.m_startDirection, netSegment.Info, inverted)); borderNodes.Add(new ConnectionPoint(netSegment.m_endNode, netSegment.m_endDirection, netSegment.Info, !inverted)); NetAccess.ReleaseSegment(segment, true); } borderNodes.RemoveWhere(n => !NetAccess.ExistsNode(n.Node)); ToolControllerDetour.CollidingSegmentsCache2 = null; //Debug.Log("Border nodes (1): " + borderNodes.Count); return(borderNodes); }
/* If node distance is too short, we travel one segment up from the border node and set the new node as the one to connect to */ private static void RepairShortSegment(ref Vector3 direction, ref ushort node) { //Debug.Log("Repairing short segment..."); NetNode netNode = NetAccess.GetNode(node); // If there is more than one segment we cannot safely delete it (we don't even know from which segment we should pick) if (netNode.CountSegments() != 1) { return; } ushort segmentId = NetAccess.GetFirstSegment(netNode); NetSegment netSegment = NetAccess.GetSegment(segmentId); if (node == netSegment.m_startNode) { direction = netSegment.m_endDirection; node = netSegment.m_endNode; } else { direction = netSegment.m_startDirection; node = netSegment.m_startNode; } NetAccess.ReleaseSegment(segmentId, true); }
// Solved by ReleaseQuestionableSegments /*private static void CheckSplitSegmentAngle(ref NetTool.ControlPoint point, FastList<ushort> createdSegments, HashSet<ConnectionPoint> borderNodes) * { * if(point.m_segment != 0) * { * if (createdSegments.Contains(point.m_segment)) * return; * * if (point.m_node != 0) * return; * * Debug.Log("CheckSplitSegmentAngle: Snapping detected"); * NetSegment netSegment = NetAccess.GetSegment(point.m_segment); * netSegment.GetClosestPositionAndDirection(point.m_position, out Vector3 pos, out Vector3 dir); * float angle = Vector3.Angle(point.m_direction, dir); * if(angle < 5 || 180 - angle < 5) * { * Debug.Log("CheckSplitSegmentAngle: Releasing (" + angle + " deg)"); * bool inverted = ((netSegment.m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None); * ConnectionPoint p1 = new ConnectionPoint(netSegment.m_startNode, netSegment.m_startDirection, netSegment.Info, inverted); * ConnectionPoint p2 = new ConnectionPoint(netSegment.m_endNode, netSegment.m_endDirection, netSegment.Info, !inverted); * NetAccess.ReleaseSegment(point.m_segment, true); * if(NetAccess.ExistsNode(p1.Node) && NetAccess.ExistsNode(p2.Node)) * { * borderNodes.Add(p1); * borderNodes.Add(p2); * } * } * } * }*/ /* Sometimes the intersection end snaps to an existing road. But it can happen that the intersection road and the road it snaps to are (more or * less) parallel. Then we are left with a piece of old road overlapping the new road because the old segment for some reason doesn't show up as * colliding. We have to find it and release it. I think that it shouldn't happen more than once per intersection tho. */ private static void ReleaseQuestionableSegments(FastList <ushort> newNodes, FastList <ushort> newSegments) { foreach (ushort node in newNodes) { NetNode netNode = NetAccess.GetNode(node); ushort foundSegment = 0; for (int i = 0; i < 8; i++) { ushort segment = netNode.GetSegment(i); if (segment != 0 && newSegments.Contains(segment)) { if (foundSegment != 0) { goto continueOuterLoop; } else { foundSegment = segment; } } } Vector3 direction = NetAccess.GetSegment(foundSegment).GetDirection(node); for (int i = 0; i < 8; i++) { ushort segment = netNode.GetSegment(i); if (segment != 0 && segment != foundSegment) { float angle = Vector3.Angle(direction, NetAccess.GetSegment(segment).GetDirection(node)); if (angle < 10) { //Debug.Log("Releasing questionable segment " + segment); NetAccess.ReleaseSegment(segment); goto breakOuterLoop; } } } continueOuterLoop :; } breakOuterLoop :; }
private static bool TryConnect(ushort node1, ConnectionPoint cpoint) { NetNode netNode1 = NetAccess.GetNode(node1); NetNode netNode2 = NetAccess.GetNode(cpoint.Node); Vector3 differenceVector = netNode2.m_position - netNode1.m_position; //Debug.Log("TryConnect: " + node1 + ", " + cpoint.Node + ", dist: " + differenceVector.magnitude); // 1) Check max distance if (differenceVector.magnitude > MAX_NODE_DISTANCE) { return(false); } ushort segment1 = NetAccess.GetFirstSegment(netNode1); //ushort segment2 = NetAccess.GetFirstSegment(netNode2); NetSegment netSegment1 = NetAccess.GetSegment(segment1); //NetSegment netSegment2 = NetAccess.GetSegment(segment2); // 2) Check if both segments are roads if (!((netSegment1.Info.m_hasForwardVehicleLanes || netSegment1.Info.m_hasBackwardVehicleLanes) && (cpoint.NetInfo.m_hasForwardVehicleLanes || cpoint.NetInfo.m_hasBackwardVehicleLanes))) { //Debug.Log("Not roads!"); return(false); } // 3) Check max angle (if segments are too close we skip this as it won't give good data) Vector3 direction1 = netSegment1.GetDirection(node1); Vector3 direction2 = cpoint.Direction; float angle1 = Vector3.Angle(direction1, -differenceVector); float angle2 = Vector3.Angle(direction2, -differenceVector); if (differenceVector.magnitude > MIN_SEGMENT_LENGTH) { if (angle1 > MAX_ANGLE || angle2 > MAX_ANGLE) { //Debug.Log("Angle too big: " + angle1 + " " + angle2); return(false); } } // 4) Check if directions of one-way roads match (if so connect) if (NetAccess.IsOneWay(netSegment1.Info) && cpoint.NetInfo) { if (SegmentDirectionBool(netSegment1, node1) ^ cpoint.DirectionBool) { Connect(node1, cpoint.Node, -netSegment1.GetDirection(node1), cpoint.Direction, cpoint.NetInfo, !cpoint.DirectionBool); return(true); } else { return(false); // We won't connect one-way roads whose directions don't match } } // 5) We will favor roads with same NetIfno (if so connect) if (netSegment1.Info == cpoint.NetInfo) { Connect(node1, cpoint.Node, -netSegment1.GetDirection(node1), cpoint.Direction, cpoint.NetInfo, !cpoint.DirectionBool); return(true); } // 6) Lastly we set smaller max distance and angle and try again if (differenceVector.magnitude < (MAX_NODE_DISTANCE * 3 / 4) && angle1 < MAX_ANGLE / 2 && angle2 < MAX_ANGLE / 2) { Connect(node1, cpoint.Node, -netSegment1.GetDirection(node1), cpoint.Direction, cpoint.NetInfo, !cpoint.DirectionBool); return(true); } return(false); }