/*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);
        }
Beispiel #2
0
        /* 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 :;
        }
Beispiel #4
0
        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);
        }