Beispiel #1
0
        /// <summary>
        /// Adds tags that can't be evaluated through a normal search
        /// </summary>
        /// <param name="segment">The segment to generate extended tags for</param>
        /// <returns>A list of tags generated from this segment</returns>
        public static List<OSMWayTag> AddExtendedWayTags(NetSegment segment)
        {
            List<OSMWayTag> returnList = new List<OSMWayTag>();

            ushort startNodeId = segment.m_endNode;
            ushort endNodeId = segment.m_startNode;

            NetManager netManager = Singleton<NetManager>.instance;
            NetNode startNode = netManager.m_nodes.m_buffer[startNodeId];
            NetNode endNode = netManager.m_nodes.m_buffer[endNodeId];

            byte wayElevation = (byte)(Mathf.Clamp((startNode.m_elevation + endNode.m_elevation) / 2, 0, 255));
            bool wayUnderground = startNode.m_flags.IsFlagSet(NetNode.Flags.Underground) || endNode.m_flags.IsFlagSet(NetNode.Flags.Underground);

            if (wayUnderground && MapperOptionsManager.OptionChecked("tunnels", MapperOptionsManager.exportOptions))
            {
                returnList.Add(new OSMWayTag { k = "tunnel", v = "yes" });
                returnList.Add(new OSMWayTag { k = "level", v = (-Mathf.FloorToInt(wayElevation / 12)).ToString() });
                returnList.Add(new OSMWayTag { k = "layer", v = (-Mathf.FloorToInt(wayElevation / 12)).ToString() });
            }
            else if (wayElevation != 0 && MapperOptionsManager.OptionChecked("bridges", MapperOptionsManager.exportOptions))
            {
                returnList.Add(new OSMWayTag { k = "bridge", v = "yes" });
                returnList.Add(new OSMWayTag { k = "level", v = Mathf.FloorToInt(wayElevation / 12).ToString() });
                returnList.Add(new OSMWayTag { k = "layer", v = Mathf.FloorToInt(wayElevation / 12).ToString() });
            }

            return returnList;
        }
		public override void SimulationStep(ushort segmentID, ref NetSegment data)
		{
			NetManager instance = Singleton<NetManager>.instance;
			if ((instance.m_nodes.m_buffer[(int)data.m_startNode].m_flags & NetNode.Flags.Temporary) == NetNode.Flags.None)
			{
				if (data.m_path == 0u || (ulong)(Singleton<SimulationManager>.instance.m_currentFrameIndex >> 8 & 15u) == (ulong)((long)(segmentID & 15)))
				{
					BusTransportLineAI.StartPathFind(segmentID, ref data, this.m_netService, this.m_vehicleType, false);
				}
				else
				{
					BusTransportLineAI.UpdatePath(segmentID, ref data, this.m_netService, this.m_vehicleType, false);
				}
			}
		}
        private void RenderManualSelectionOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (HoveredNodeId == 0)
            {
                return;
            }
            var segment = Singleton <NetManager> .instance.m_segments.m_buffer[Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_segment0];

            //if ((node.m_flags & NetNode.Flags.TrafficLights) == NetNode.Flags.None) return;
            Bezier3 bezier;

            bezier.a = Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position;
            bezier.d = Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position;

            var color = MainTool.GetToolColor(false, false);

            NetSegment.CalculateMiddlePoints(bezier.a, segment.m_startDirection, bezier.d,
                                             segment.m_endDirection, false, false, out bezier.b, out bezier.c);
            MainTool.DrawOverlayBezier(cameraInfo, bezier, color);
        }
Beispiel #4
0
        private void CalculateMatrix(float width, float height, out Matrix4x4 left, out Matrix4x4 right)
        {
            var bezierL = new Bezier3()
            {
                a = new Vector3(-width, 0f, -height),
                b = new Vector3(-width, 0f, -height / 3),
                c = new Vector3(-width, 0f, height / 3),
                d = new Vector3(-width, 0f, height),
            };
            var bezierR = new Bezier3()
            {
                a = new Vector3(width, 0f, -height),
                b = new Vector3(width, 0f, -height / 3),
                c = new Vector3(width, 0f, height / 3),
                d = new Vector3(width, 0f, height),
            };

            left  = NetSegment.CalculateControlMatrix(bezierL.a, bezierL.b, bezierL.c, bezierL.d, bezierR.a, bezierR.b, bezierR.c, bezierR.d, Vector3.zero, 0.05f);
            right = NetSegment.CalculateControlMatrix(bezierR.a, bezierR.b, bezierR.c, bezierR.d, bezierL.a, bezierL.b, bezierL.c, bezierL.d, Vector3.zero, 0.05f);
        }
Beispiel #5
0
 public static void BannAllCrossings()
 {
     Log.Info("BENCHMARK> BannAllCrossings started ... ");
     for (ushort segmentID = 0; segmentID < NetManager.MAX_SEGMENT_COUNT; ++segmentID)
     {
         foreach (bool bStartNode in new bool[] { false, true })
         {
             if (TMPEUTILS.HasCrossingBan(segmentID, bStartNode))
             {
                 NetSegment segment = segmentID.ToSegment();
                 ushort     nodeID  = bStartNode ? segment.m_startNode : segment.m_endNode;
                 var        flags   = nodeID.ToNode().m_flags;
                 //Ban:
                 TrafficManager.Manager.Impl.JunctionRestrictionsManager.Instance.
                 SetPedestrianCrossingAllowed(segmentID, bStartNode, false);
             }
         }
     }
     Log.Info("BENCHMARK> BannAllCrossings Done!");
 }
Beispiel #6
0
        private void CalculatePosition(NetSegment segment)
        {
            if (DriveLanes.FirstOrDefault() is DriveLane driveLane)
            {
                var position = driveLane.NetLane.CalculatePosition(T);
                var coef     = Mathf.Sin(CornerAndNormalAngle);

                RoadHalfWidth          = segment.Info.m_halfWidth - segment.Info.m_pavementWidth;
                RoadHalfWidthTransform = RoadHalfWidth / coef;

                Position       = position + (IsLaneInvert ? -CornerDir : CornerDir) * driveLane.Position / coef;
                FirstPointSide = Position.Value - RoadHalfWidthTransform * CornerDir;
                LastPointSide  = Position.Value + RoadHalfWidthTransform * CornerDir;
                Line           = new StraightTrajectory(FirstPointSide, LastPointSide);
            }
            else
            {
                Position = null;
            }
        }
Beispiel #7
0
        private void UpdateСontour()
        {
            BetweenEnters.Clear();

            for (var i = 0; i < EntersList.Count; i += 1)
            {
                var j    = i.NextIndex(EntersList.Count);
                var prev = EntersList[i];
                var next = EntersList[j];

                var betweenBezier = new Bezier3()
                {
                    a = prev.LastPointSide,
                    d = next.FirstPointSide
                };
                NetSegment.CalculateMiddlePoints(betweenBezier.a, prev.NormalDir, betweenBezier.d, next.NormalDir, true, true, out betweenBezier.b, out betweenBezier.c);

                BetweenEnters[i, j] = new BezierTrajectory(betweenBezier);
            }
        }
Beispiel #8
0
        internal ushort GetSegmentFromNode()
        {
            bool   considerSegmentLenght = true;
            ushort minSegId = 0;

            if (HoveredNodeId != 0)
            {
                NetNode node      = HoveredNodeId.ToNode();
                Vector3 dir0      = node.m_position - m_mousePosition;
                float   min_angle = float.MaxValue;
                for (int i = 0; i < 8; ++i)
                {
                    ushort segmentId = node.GetSegment(i);
                    if (segmentId == 0)
                    {
                        continue;
                    }
                    NetSegment segment = segmentId.ToSegment();
                    Vector3    dir;
                    if (segment.m_startNode == HoveredNodeId)
                    {
                        dir = segment.m_startDirection;
                    }
                    else
                    {
                        dir = segment.m_endDirection;
                    }
                    float angle = GetAgnele(-dir, dir0);
                    if (considerSegmentLenght)
                    {
                        angle *= segment.m_averageLength;
                    }
                    if (angle < min_angle)
                    {
                        min_angle = angle;
                        minSegId  = segmentId;
                    }
                }
            }
            return(minSegId);
        }
Beispiel #9
0
        void SetSegments(ushort segmentId, ushort infoIndex, ref Segment previousSeg)
        {
            NetSegment segment = NetManager.instance.m_segments.m_buffer[segmentId];

            if (segment.m_infoIndex != infoIndex || m_segments.ContainsKey(segmentId))
            {
                return;
            }

            Segment seg = default(Segment);

            seg.m_segmentId = segmentId;

            NetSegment previousSegment = NetManager.instance.m_segments.m_buffer[previousSeg.m_segmentId];
            ushort     nextNode;

            if ((segment.m_startNode == previousSegment.m_endNode) ||
                (segment.m_startNode == previousSegment.m_startNode))
            {
                nextNode         = segment.m_endNode;
                seg.m_targetNode = segment.m_startNode == previousSeg.m_targetNode
                    ? segment.m_endNode
                    : segment.m_startNode;
            }
            else
            {
                nextNode         = segment.m_startNode;
                seg.m_targetNode = segment.m_endNode == previousSeg.m_targetNode
                    ? segment.m_startNode
                    : segment.m_endNode;
            }

            m_segments[segmentId] = seg;

            NetNode node = NetManager.instance.m_nodes.m_buffer[nextNode];

            if (node.CountSegments() == 2)
            {
                SetSegments(node.m_segment0 == segmentId ? node.m_segment1 : node.m_segment0, infoIndex, ref seg);
            }
        }
Beispiel #10
0
        /// <summary>
        /// Adds tags that can't be evaluated through a normal search
        /// </summary>
        /// <param name="segment">The segment to generate extended tags for</param>
        /// <returns>A list of tags generated from this segment</returns>
        public static List <OSMWayTag> AddExtendedWayTags(NetSegment segment)
        {
            List <OSMWayTag> returnList = new List <OSMWayTag>();

            ushort startNodeId = segment.m_endNode;
            ushort endNodeId   = segment.m_startNode;

            NetManager netManager = Singleton <NetManager> .instance;
            NetNode    startNode  = netManager.m_nodes.m_buffer[startNodeId];
            NetNode    endNode    = netManager.m_nodes.m_buffer[endNodeId];

            byte wayElevation   = (byte)(Mathf.Clamp((startNode.m_elevation + endNode.m_elevation) / 2, 0, 255));
            bool wayUnderground = startNode.m_flags.IsFlagSet(NetNode.Flags.Underground) || endNode.m_flags.IsFlagSet(NetNode.Flags.Underground);

            if (wayUnderground && MapperOptionsManager.OptionChecked("tunnels", MapperOptionsManager.exportOptions))
            {
                returnList.Add(new OSMWayTag {
                    k = "tunnel", v = "yes"
                });
                returnList.Add(new OSMWayTag {
                    k = "level", v = (-Mathf.FloorToInt(wayElevation / 12)).ToString()
                });
                returnList.Add(new OSMWayTag {
                    k = "layer", v = (-Mathf.FloorToInt(wayElevation / 12)).ToString()
                });
            }
            else if (wayElevation != 0 && MapperOptionsManager.OptionChecked("bridges", MapperOptionsManager.exportOptions))
            {
                returnList.Add(new OSMWayTag {
                    k = "bridge", v = "yes"
                });
                returnList.Add(new OSMWayTag {
                    k = "level", v = Mathf.FloorToInt(wayElevation / 12).ToString()
                });
                returnList.Add(new OSMWayTag {
                    k = "layer", v = Mathf.FloorToInt(wayElevation / 12).ToString()
                });
            }

            return(returnList);
        }
        private static List <ushort> GetEdgeNodes(ref List <ushort> accessSegments, out bool nodeStartS, out bool nodeStartE, bool localAdjust)
        {
            if (accessSegments.Count > 1)
            {
                NetSegment seg0  = NetManager.instance.m_segments.m_buffer[accessSegments[0]];
                NetSegment seg1  = NetManager.instance.m_segments.m_buffer[accessSegments[1]];
                NetSegment segN2 = NetManager.instance.m_segments.m_buffer[accessSegments[accessSegments.Count - 2]];
                NetSegment segN1 = NetManager.instance.m_segments.m_buffer[accessSegments[accessSegments.Count - 1]];
                nodeStartS = seg1.m_startNode == seg0.m_endNode || seg1.m_endNode == seg0.m_endNode;
                nodeStartE = segN2.m_startNode == segN1.m_endNode || segN2.m_endNode == segN1.m_endNode;
                if (localAdjust)
                {
                    if (nodeStartS == ((NetManager.instance.m_segments.m_buffer[accessSegments[0]].m_flags & NetSegment.Flags.Invert) != 0))
                    {
                        accessSegments.Reverse();
                        bool temp = nodeStartS;
                        nodeStartS = nodeStartE;
                        nodeStartE = temp;
                    }
                }
                else
                {
                    ushort nodeF = nodeStartS ? seg0.m_startNode : seg0.m_endNode;
                    ushort nodeL = nodeStartE ? segN1.m_startNode : segN1.m_endNode;
                    if (VectorUtils.XZ(NetManager.instance.m_nodes.m_buffer[nodeF].m_position).GetAngleToPoint(VectorUtils.XZ(NetManager.instance.m_nodes.m_buffer[nodeL].m_position)) > 180)
                    {
                        accessSegments.Reverse();
                        bool temp = nodeStartS;
                        nodeStartS = nodeStartE;
                        nodeStartE = temp;
                    }
                }
            }
            else
            {
                nodeStartS = (NetManager.instance.m_segments.m_buffer[accessSegments[0]].m_flags & NetSegment.Flags.Invert) == 0;
                nodeStartE = (NetManager.instance.m_segments.m_buffer[accessSegments[0]].m_flags & NetSegment.Flags.Invert) != 0;
            }

            return(accessSegments);
        }
Beispiel #12
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo, Color toolColor, Color despawnColor)
        {
            if (!isValid)
            {
                return;
            }

            ushort  segment = id.NetSegment;
            NetInfo netInfo = segmentBuffer[segment].Info;

            ushort startNode = segmentBuffer[segment].m_startNode;
            ushort endNode   = segmentBuffer[segment].m_endNode;

            bool smoothStart = ((nodeBuffer[startNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None);
            bool smoothEnd   = ((nodeBuffer[endNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None);

            Bezier3 bezier;

            bezier.a = nodeBuffer[startNode].m_position;
            bezier.d = nodeBuffer[endNode].m_position;

            NetSegment.CalculateMiddlePoints(
                bezier.a, segmentBuffer[segment].m_startDirection,
                bezier.d, segmentBuffer[segment].m_endDirection,
                smoothStart, smoothEnd, out bezier.b, out bezier.c);

            RenderManager.instance.OverlayEffect.DrawBezier(cameraInfo, toolColor, bezier, netInfo.m_halfWidth * 4f / 3f, 100000f, -100000f, -1f, 1280f, false, true);

            Segment3 segment1, segment2;

            segment1.a = nodeBuffer[startNode].m_position;
            segment2.a = nodeBuffer[endNode].m_position;

            segment1.b = GetControlPoint(segment);
            segment2.b = segment1.b;

            toolColor.a = toolColor.a / 2;

            RenderManager.instance.OverlayEffect.DrawSegment(cameraInfo, toolColor, segment1, segment2, 0, 10f, -1f, 1280f, false, true);
            RenderManager.instance.OverlayEffect.DrawCircle(cameraInfo, toolColor, segment1.b, netInfo.m_halfWidth / 2f, -1f, 1280f, false, true);
        }
Beispiel #13
0
        public static void CachePrefabs()
        {
            Log.Info("CachePrefabs() called ...");
            TMPEUTILS.Init();
            NS2Utils.Init();
#if !DEBUG
            if (Extensions.InAssetEditor)
            {
                Log.Info("skipped caching prefabs in asset editor release build");
                return;
            }
#endif
            NetInfoExt.InitNetInfoExtArray();
            TextureUtils.Init();
            MaterialUtils.Init();
            for (ushort segmentID = 0; segmentID < NetManager.MAX_SEGMENT_COUNT; ++segmentID)
            {
                foreach (bool bStartNode in new bool[] { false, true })
                {
                    if (TMPEUTILS.HasCrossingBan(segmentID, bStartNode))
                    {
                        NetSegment segment = segmentID.ToSegment();
                        ushort     nodeID  = bStartNode ? segment.m_startNode : segment.m_endNode;
                        foreach (var node in segment.Info.m_nodes)
                        {
                            if (node.m_directConnect)
                            {
                                continue;
                            }
                            var flags = nodeID.ToNode().m_flags;

                            //cache:
                            Log.Info("Caching " + segment.Info.name);
                            CalculateMaterialCommons.CalculateMaterial(node.m_nodeMaterial, nodeID, segmentID);
                        }
                    }
                }
            }
            PrefabsLoaded = true;
            Log.Info("all prefabs cached");
        }
Beispiel #14
0
        public static void Prefix(RoadBaseAI __instance, ushort segmentID, ref NetSegment data)
        {
            // TODO check if this is required *START*
            uint curLaneId = data.m_lanes;
            int  numLanes  = data.Info.m_lanes.Length;
            uint laneIndex = 0;

            while (laneIndex < numLanes && curLaneId != 0u)
            {
                Flags.ApplyLaneArrowFlags(curLaneId);

                laneIndex++;
                curLaneId = Singleton <NetManager> .instance.m_lanes.m_buffer[curLaneId].m_nextLane;
            }

            // ↑↑↑↑
            // TODO check if this is required *END*
            Constants.ManagerFactory.TrafficMeasurementManager.OnBeforeSimulationStep(
                segmentID,
                ref data);
        }
        public void IterateSegmentLanes(ushort segmentId, ref NetSegment segment, NetSegmentLaneHandler handler)
        {
            NetInfo segmentInfo = segment.Info;

            if (segmentInfo == null)
            {
                return;
            }

            byte laneIndex = 0;
            uint curLaneId = segment.m_lanes;

            while (laneIndex < segmentInfo.m_lanes.Length && curLaneId != 0u)
            {
                NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex];
                handler(curLaneId, ref Singleton <NetManager> .instance.m_lanes.m_buffer[curLaneId], laneInfo, segmentId, ref segment, laneIndex);

                curLaneId = Singleton <NetManager> .instance.m_lanes.m_buffer[curLaneId].m_nextLane;
                ++laneIndex;
            }
        }
        private Vector3 CalculateNodePositionForSegment(NetNode node, ref NetSegment segment)
        {
            Vector3 position = node.m_position;

            const float offset = 25f;

            if (segment.m_startNode == SelectedNodeId)
            {
                position.x += segment.m_startDirection.x * offset;
                position.y += segment.m_startDirection.y * offset;
                position.z += segment.m_startDirection.z * offset;
            }
            else
            {
                position.x += segment.m_endDirection.x * offset;
                position.y += segment.m_endDirection.y * offset;
                position.z += segment.m_endDirection.z * offset;
            }

            return(position);
        }
        internal static bool Prefix(ushort segmentID, ref NetSegment data, int index, ref TerrainModify.Surface surface, ref TerrainModify.Heights heights, ref TerrainModify.Edges edges, ref float left, ref float right, ref float leftStartY, ref float rightStartY, ref float leftEndY, ref float rightEndY, ref bool __result, NetAI __instance)
        {
            var net = __instance.m_info.GetMetaData();

            if (net is null)
            {
#if DEBUGQUAYROADS
                Log.Debug("No AR data found for: \n segmentId: " + segmentID + "name: " + data.Info.name);
#endif
                return(true);
            }

            ProfileSection[] profile = net.QuayRoadsProfile;
            if (profile is null)
            {
                return(true);
            }
            Log.Debug("modifying mask for segment " + segmentID.ToString() + ", section " + index);
            bool invert = (data.m_flags & NetSegment.Flags.Invert) != 0;
            return(ModifyMaskCommon.ModifyMask(profile, invert, index, ref surface, ref heights, ref edges, ref left, ref right, ref leftStartY, ref rightStartY, ref leftEndY, ref rightEndY, ref __result));
        }
Beispiel #18
0
        private void ExportWays()
        {
            NetManager netManager = Singleton <NetManager> .instance;

            NetSegment[] netSegments = netManager.m_segments.m_buffer;
            for (int segmentId = 0; segmentId < netSegments.Length; segmentId++)
            {
                NetSegment       netSegment   = netSegments[segmentId];
                NetSegment.Flags segmentFlags = netSegment.m_flags;

                if (segmentFlags.IsFlagSet(NetSegment.Flags.Created))
                {
                    OSMWay generatedWay = CreateWay(unindexedWayOffset++, netSegment, (ushort)segmentId);

                    if (generatedWay != null)
                    {
                        osmWays.Add(generatedWay);
                    }
                }
            }
        }
        private Vector3 CalculateNodePositionForSegment(NetNode node, int segmentId)
        {
            Vector3 position = node.m_position;

            NetSegment segment = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId];

            if (segment.m_startNode == SelectedNodeId)
            {
                position.x += segment.m_startDirection.x * 10f;
                position.y += segment.m_startDirection.y * 10f;
                position.z += segment.m_startDirection.z * 10f;
            }
            else
            {
                position.x += segment.m_endDirection.x * 10f;
                position.y += segment.m_endDirection.y * 10f;
                position.z += segment.m_endDirection.z * 10f;
            }

            return(position);
        }
Beispiel #20
0
        private bool CheckSegmentsTurningAngle(ushort sourceSegmentId, ref NetSegment sourceSegment, bool sourceStartNode, ushort targetSegmentId, ref NetSegment targetSegment, bool targetStartNode)
        {
            NetManager netManager = Singleton <NetManager> .instance;

            NetInfo sourceSegmentInfo = netManager.m_segments.m_buffer[sourceSegmentId].Info;
            NetInfo targetSegmentInfo = netManager.m_segments.m_buffer[targetSegmentId].Info;

            if (IsCSUR(sourceSegmentInfo) || IsCSUR(targetSegmentInfo))
            {
                return(true);
            }

            float turningAngle = 0.01f - Mathf.Min(sourceSegmentInfo.m_maxTurnAngleCos, targetSegmentInfo.m_maxTurnAngleCos);

            if (turningAngle < 1f)
            {
                Vector3 sourceDirection;
                if (sourceStartNode)
                {
                    sourceDirection = sourceSegment.m_startDirection;
                }
                else
                {
                    sourceDirection = sourceSegment.m_endDirection;
                }

                Vector3 targetDirection;
                if (targetStartNode)
                {
                    targetDirection = targetSegment.m_startDirection;
                }
                else
                {
                    targetDirection = targetSegment.m_endDirection;
                }
                float dirDotProd = sourceDirection.x * targetDirection.x + sourceDirection.z * targetDirection.z;
                return(dirDotProd < turningAngle);
            }
            return(true);
        }
Beispiel #21
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            base.RenderOverlay(cameraInfo);
            if (!enabled)
            {
                return;
            }

            if (hoveredId.NetSegment != 0)
            {
                NetSegment hoveredSegment = hoveredId.NetSegment.S();
                NetTool.RenderOverlay(cameraInfo, ref hoveredSegment, hoverColor, hoverColor);
            }
            //else if (hoveredObject.NetNode != 0 && hoveredObject.NetNode < 32768)
            //{
            //    NetNode hoveredNode = hoveredObject.NetNode.N();
            //    RenderManager.instance.OverlayEffect.DrawCircle(cameraInfo, hoverColor, hoveredNode.m_position, Mathf.Max(6f, hoveredNode.Info.m_halfWidth * 2f), -1f, 1280f, false, true);
            //}
            else if (hoveredId.Building != 0)
            {
                Building hoveredBuilding = hoveredId.Building.B();
                BuildingTool.RenderOverlay(cameraInfo, ref hoveredBuilding, hoverColor, hoverColor);

                while (hoveredBuilding.m_subBuilding > 0)
                {
                    hoveredBuilding = BuildingManager.instance.m_buildings.m_buffer[hoveredBuilding.m_subBuilding];
                    BuildingTool.RenderOverlay(cameraInfo, ref hoveredBuilding, hoverColor, hoverColor);
                }
            }
            else if (hoveredId.Tree != 0)
            {
                TreeInstance hoveredTree = hoveredId.Tree.T();
                TreeTool.RenderOverlay(cameraInfo, hoveredTree.Info, hoveredTree.Position, hoveredTree.Info.m_minScale, hoverColor);
            }
            else if (hoveredId.Prop != 0)
            {
                PropInstance hoveredProp = hoveredId.Prop.P();
                PropTool.RenderOverlay(cameraInfo, hoveredProp.Info, hoveredProp.Position, hoveredProp.Info.m_minScale, hoveredProp.Angle, hoverColor);
            }
        }
        public static void GetNearestSegment(Vector3 sidewalk, out Vector3 targetPosition, out float targetLength, out ushort targetSegmentId)
        {
            NetManager.instance.GetClosestSegments(sidewalk, m_closestSegsFind, out int found);
            targetPosition  = default;
            targetLength    = 0;
            targetSegmentId = 0;
            if (found == 0)
            {
                return;
            }
            else if (found > 1)
            {
                float minSqrDist = float.MaxValue;
                for (int i = 0; i < found; i++)
                {
                    ushort     segId = m_closestSegsFind[i];
                    NetSegment seg   = NetManager.instance.m_segments.m_buffer[segId];
                    if (!(seg.Info.GetAI() is RoadBaseAI))
                    {
                        continue;
                    }

                    GetClosestPositionAndDirectionAndPoint(seg, sidewalk, out Vector3 position, out _, out float length);
                    float sqrDist = Vector3.SqrMagnitude(sidewalk - position);
                    if (i == 0 || sqrDist < minSqrDist)
                    {
                        minSqrDist      = sqrDist;
                        targetPosition  = position;
                        targetLength    = length;
                        targetSegmentId = segId;
                    }
                }
            }
            else
            {
                targetSegmentId = m_closestSegsFind[0];
                GetClosestPositionAndDirectionAndPoint(NetManager.instance.m_segments.m_buffer[targetSegmentId], sidewalk, out targetPosition, out _, out targetLength);
            }
        }
 private void CreateZoneBlocks(ushort segment, ref NetSegment data)
 {
     try
     {
         if (RoadZoneBlocksCreationManager.HasCustomCreator(this.m_info.name))
         {
             RoadZoneBlocksCreationManager
                 .GetCustomCreator(this.m_info.name)
                 .CreateZoneBlocks(this.m_info, segment, ref data);
         }
         else
         {
             CreateZoneBlocksVanilla(this.m_info, segment, ref data);
         }
     }
     catch (Exception ex)
     {
         Debug.Log("TAM: Crashed-CreateZoneBlocks");
         Debug.Log("TAM: " + ex.Message);
         Debug.Log("TAM: " + ex.ToString());
     }
 }
Beispiel #24
0
        public static Lane CreateLane(uint laneId)
        {
            Lane lane = new Lane()
            {
                m_laneId = laneId
            };

            NetSegment segment   = NetManager.instance.m_segments.m_buffer[NetManager.instance.m_lanes.m_buffer[laneId].m_segment];
            NetInfo    netInfo   = segment.Info;
            int        laneCount = netInfo.m_lanes.Length;
            int        laneIndex = 0;

            for (uint l = segment.m_lanes; laneIndex < laneCount && l != 0; laneIndex++)
            {
                if (l == laneId)
                {
                    break;
                }

                l = NetManager.instance.m_lanes.m_buffer[l].m_nextLane;
            }

            if (laneIndex < laneCount)
            {
                NetInfoLane netInfoLane = netInfo.m_lanes[laneIndex] as NetInfoLane;
                if (netInfoLane != null)
                {
                    lane.m_vehicleTypes = netInfoLane.m_allowedVehicleTypes;
                }

                lane.m_speed = netInfo.m_lanes[laneIndex].m_speedLimit;
            }

            NetManager.instance.m_lanes.m_buffer[laneId].m_flags |= Lane.CONTROL_BIT;

            sm_lanes[laneId] = lane;

            return(lane);
        }
 private void CreateZoneBlocks(ushort segment, ref NetSegment data)
 {
     try
     {
         if (RoadZoneBlocksCreationManager.HasCustomCreator(this.m_info.name))
         {
             RoadZoneBlocksCreationManager
             .GetCustomCreator(this.m_info.name)
             .CreateZoneBlocks(this.m_info, segment, ref data);
         }
         else
         {
             CreateZoneBlocksVanilla(this.m_info, segment, ref data);
         }
     }
     catch (Exception ex)
     {
         Debug.Log("TAM: Crashed-CreateZoneBlocks");
         Debug.Log("TAM: " + ex.Message);
         Debug.Log("TAM: " + ex.ToString());
     }
 }
Beispiel #26
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 void RepairShortSegment(ref Vector3 direction, ref ushort node)
        {
            //Debug.Log("Repairing short segment...");

            NetNode netNode = NetUtil.Node(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  = NetUtil.GetFirstSegment(netNode);
            NetSegment netSegment = NetUtil.Segment(segmentId);

            WrappedNode nodeW = _networkDictionary.RegisterNode(node);

            if (node == netSegment.m_startNode)
            {
                direction = netSegment.m_endDirection;
                node      = netSegment.m_endNode;
            }
            else
            {
                direction = netSegment.m_startDirection;
                node      = netSegment.m_startNode;
            }

            WrappedSegment segmentW = _networkDictionary.RegisterSegment(segmentId);

            _actionGroup.Actions.Add(segmentW);
            _actionGroup.Actions.Add(nodeW);
            segmentW.Release();
            nodeW.Release();
            segmentW.IsBuildAction = false;
            nodeW.IsBuildAction    = false;

            //NetUtil.ReleaseSegment(segmentId, true);
        }
Beispiel #27
0
        public void DirectionSelectButtons(NetSegment currentSegment, NetInfo.Direction dir, float y)
        {
            float columnOffset = 0f;
            uint  currentLane  = currentSegment.m_lanes;

            for (int i = 0; i < currentSegment.Info.m_lanes.Length; i++)
            {
                if (currentSegment.Info.m_lanes[i].m_laneType == NetInfo.LaneType.Vehicle && currentSegment.Info.m_lanes[i].m_direction == dir)
                {
                    LaneDirectionToggleButton leftToggleButton = this.AddUIComponent <LaneDirectionToggleButton>();
                    leftToggleButton.DrawButton(currentLane, NetLane.Flags.Left, new Vector3(5f + columnOffset, 5f + y));

                    LaneDirectionToggleButton forwardToggleButton = this.AddUIComponent <LaneDirectionToggleButton>();
                    forwardToggleButton.DrawButton(currentLane, NetLane.Flags.Forward, new Vector3(40f + columnOffset, 5f + y));

                    LaneDirectionToggleButton rightToggleButton = this.AddUIComponent <LaneDirectionToggleButton>();
                    rightToggleButton.DrawButton(currentLane, NetLane.Flags.Right, new Vector3(75f + columnOffset, 5f + y));
                    columnOffset += 120f;
                }
                currentLane = NetManager.instance.m_lanes.m_buffer[currentLane].m_nextLane;
            }
        }
Beispiel #28
0
        private void RenderConnectLineOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (!IsSelectPoint)
            {
                return;
            }

            var   bezier = new Bezier3();
            Color color;

            if (IsHoverPoint)
            {
                var pointPair = new MarkupPointPair(SelectPoint, HoverPoint);
                color = EditMarkup.ExistConnection(pointPair) ? Color.red : Color.green;

                bezier.a = SelectPoint.Position;
                bezier.b = HoverPoint.Enter == SelectPoint.Enter ? HoverPoint.Position - SelectPoint.Position : SelectPoint.Direction;
                bezier.c = HoverPoint.Enter == SelectPoint.Enter ? SelectPoint.Position - HoverPoint.Position : HoverPoint.Direction;
                bezier.d = HoverPoint.Position;
            }
            else
            {
                color = Color.white;

                RaycastInput input = new RaycastInput(MouseRay, MouseRayLength);
                RayCast(input, out RaycastOutput output);

                bezier.a = SelectPoint.Position;
                bezier.b = SelectPoint.Direction;
                bezier.c = SelectPoint.Direction.Turn90(true);
                bezier.d = output.m_hitPos;

                Line2.Intersect(VectorUtils.XZ(bezier.a), VectorUtils.XZ(bezier.a + bezier.b), VectorUtils.XZ(bezier.d), VectorUtils.XZ(bezier.d + bezier.c), out _, out float v);
                bezier.c = v >= 0 ? bezier.c : -bezier.c;
            }

            NetSegment.CalculateMiddlePoints(bezier.a, bezier.b, bezier.d, bezier.c, true, true, out bezier.b, out bezier.c);
            RenderManager.OverlayEffect.DrawBezier(cameraInfo, color, bezier, 0.5f, 0f, 0f, -1f, 1280f, false, true);
        }
Beispiel #29
0
        protected void CalculateMatrix(ITrajectory trajectory, float halfWidth, Vector3 position, out Matrix4x4 left, out Matrix4x4 right)
        {
            var startNormal = trajectory.StartDirection.Turn90(true).MakeFlatNormalized();
            var endNormal   = trajectory.EndDirection.Turn90(false).MakeFlatNormalized();

            var bezierL = new Bezier3()
            {
                a = trajectory.StartPosition - startNormal * halfWidth,
                d = trajectory.EndPosition - endNormal * halfWidth,
            };
            var bezierR = new Bezier3()
            {
                a = trajectory.StartPosition + startNormal * halfWidth,
                d = trajectory.EndPosition + endNormal * halfWidth,
            };

            NetSegment.CalculateMiddlePoints(bezierL.a, trajectory.StartDirection, bezierL.d, trajectory.EndDirection, true, true, out bezierL.b, out bezierL.c);
            NetSegment.CalculateMiddlePoints(bezierR.a, trajectory.StartDirection, bezierR.d, trajectory.EndDirection, true, true, out bezierR.b, out bezierR.c);

            left  = NetSegment.CalculateControlMatrix(bezierL.a, bezierL.b, bezierL.c, bezierL.d, bezierR.a, bezierR.b, bezierR.c, bezierR.d, position, 0.05f);
            right = NetSegment.CalculateControlMatrix(bezierR.a, bezierR.b, bezierR.c, bezierR.d, bezierL.a, bezierL.b, bezierL.c, bezierL.d, position, 0.05f);
        }
Beispiel #30
0
        public bool NodeInsertion(ushort segment, float time)  // time is in the range (0, 1) inclusive
        {
            Bezier3    bezier = new Bezier3();
            NetSegment s1     = GetSegment(segment);

            bezier.a = NetManager.instance.m_nodes.m_buffer[s1.m_startNode].m_position;
            bezier.d = NetManager.instance.m_nodes.m_buffer[s1.m_endNode].m_position;

            bool smoothStart = (Singleton <NetManager> .instance.m_nodes.m_buffer[s1.m_startNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None;
            bool smoothEnd   = (Singleton <NetManager> .instance.m_nodes.m_buffer[s1.m_endNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None;

            NetSegment.CalculateMiddlePoints(bezier.a, s1.m_startDirection, bezier.d, s1.m_endDirection, smoothStart, smoothEnd, out Vector3 b, out Vector3 c);

            bezier.b = b;
            bezier.c = c;

            Vector3 timePoint = bezier.Position(time);

            ushort  seg1ls  = s1.m_startNode;
            Vector3 seg1lsd = s1.m_startDirection;
            Vector3 seg1led = -bezier.Tangent(time).normalized;

            ushort  seg1rs  = s1.m_endNode;
            Vector3 seg1rsd = s1.m_endDirection;
            Vector3 seg1red = bezier.Tangent(time).normalized;

            Manager.CreateNode(out ushort timePointNode, ref SimulationManager.instance.m_randomizer, s1.Info, timePoint, SimulationManager.instance.m_currentBuildIndex++);
            Manager.CreateSegment(out ushort seg1, ref SimulationManager.instance.m_randomizer, s1.Info, timePointNode, seg1ls, seg1led, seg1lsd, SimulationManager.instance.m_currentBuildIndex++, SimulationManager.instance.m_currentBuildIndex - 1, false);
            Manager.CreateSegment(out ushort seg2, ref SimulationManager.instance.m_randomizer, s1.Info, seg1rs, timePointNode, seg1rsd, seg1red, SimulationManager.instance.m_currentBuildIndex++, SimulationManager.instance.m_currentBuildIndex - 1, false);

            Manager.UpdateNode(timePointNode);
            Manager.UpdateSegment(seg1);
            Manager.UpdateSegment(seg2);

            Manager.ReleaseSegment(segment, true);
            m_newSeg1 = seg1;
            m_newSeg2 = seg2;
            return(true);
        }
Beispiel #31
0
        private static void HoverBuilding(RenderManager.CameraInfo cameraInfo, Color toolColor, ushort buildingId)
        {
            BuildingBuffer[buildingId].GetTotalPosition(out Vector3 pos, out Quaternion rot, out Vector3 size);
            var quad = new Quad3(
                (rot * new Vector3(-size.x, 0, size.z) / 2) + pos,
                (rot * new Vector3(-size.x, 0, -size.z) / 2) + pos,
                (rot * new Vector3(size.x, 0, -size.z) / 2) + pos,
                (rot * new Vector3(size.x, 0, size.z) / 2) + pos
                );

            Singleton <RenderManager> .instance.OverlayEffect.DrawQuad(cameraInfo, toolColor, quad, -1f, 1280f, false, true);

            var nets               = BuildingBuffer[buildingId].m_netNode;
            var drawnSegments      = new HashSet <ushort>();
            var netManagerInstance = NetManager.instance;

            while (nets > 0)
            {
                ref NetNode currNode = ref netManagerInstance.m_nodes.m_buffer[nets];
                for (int i = 0; i < 8; i++)
                {
                    var segmentId = currNode.GetSegment(i);
                    if (segmentId == 0)
                    {
                        break;
                    }
                    if (drawnSegments.Contains(segmentId))
                    {
                        continue;
                    }
                    ref NetSegment nextSegment = ref netManagerInstance.m_segments.m_buffer[segmentId];
                    if (netManagerInstance.m_nodes.m_buffer[nextSegment.GetOtherNode(nets)].m_building != buildingId)
                    {
                        continue;
                    }
                    drawnSegments.Add(segmentId);
                    RenderOverlayUtils.RenderNetSegmentOverlay(cameraInfo, toolColor, segmentId);
                }
Beispiel #32
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            // no highlight for existing priority node in sign mode
            if (TrafficPriority.IsPriorityNode(HoveredNodeId))
            {
                return;
            }

            if (HoveredNodeId == 0)
            {
                return;
            }

            if (!Flags.mayHaveTrafficLight(HoveredNodeId))
            {
                return;
            }

            var segment = Singleton <NetManager> .instance.m_segments.m_buffer[Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_segment0];

            Bezier3 bezier;

            bezier.a = Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position;
            bezier.d = Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position;

            var color = MainTool.GetToolColor(Input.GetMouseButton(0), false);

            NetSegment.CalculateMiddlePoints(bezier.a, segment.m_startDirection, bezier.d,
                                             segment.m_endDirection,
                                             false, false, out bezier.b, out bezier.c);

            MainTool.DrawOverlayBezier(cameraInfo, bezier, color);
        }
        internal bool GetTags(byte elevation, NetSegment netSegment, List <osmWayTag> tags)
        {
            if (elevation > 0)
            {
                tags.Add(new osmWayTag {
                    k = "bridge", v = "yes"
                });
                tags.Add(new osmWayTag {
                    k = "level", v = Mathf.FloorToInt(elevation / 12).ToString()
                });
            }
            var name = netSegment.Info.name.Replace(" ", "");

            if (name.ToLower().Contains("oneway") || name.ToLower().Contains("highway"))
            {
                tags.Add(new osmWayTag {
                    k = "oneway", v = "yes"
                });
            }
            var roadType = RoadTypes.None;

            try
            {
                roadType = (RoadTypes)Enum.Parse(typeof(RoadTypes), name);
            }
            catch
            {
                return(false);
            }
            if (reverseMapping.ContainsKey(roadType))
            {
                tags.Add(new osmWayTag {
                    k = reverseMapping[roadType].Key, v = reverseMapping[roadType].Value
                });
                return(true);
            }
            return(false);
        }
        public void CreateZoneBlocks(NetInfo info, ushort segmentId, ref NetSegment segment)
        {
            var netManager = Singleton<NetManager>.instance;
            var randomizer = new Randomizer((int)segmentId);

            var startNode = netManager.m_nodes.m_buffer[(int)segment.m_startNode];
            var endNode = netManager.m_nodes.m_buffer[(int)segment.m_endNode];

            var startPosition = startNode.m_position;
            var endPosition = endNode.m_position;
            var startDirection = segment.m_startDirection;
            var endDirection = segment.m_endDirection;
            var isCurve = !NetSegment.IsStraight(startPosition, startDirection, endPosition, endDirection);

            if (isCurve)
            {
                CreateZoneBlocksTiny_Curve(info, randomizer, ref segment);
            }
            else
            {
                CreateZoneBlocksTiny_Straight(info, randomizer, ref segment, startNode, endNode);
            }
        }
 public static new bool UpdatePath(ushort segmentID, ref NetSegment data, ItemClass.Service netService, VehicleInfo.VehicleType vehicleType, bool skipQueue)
 {
     if (data.m_path == 0u)
     {
         return BusTransportLineAI.StartPathFind(segmentID, ref data, netService, vehicleType, skipQueue);
     }
     if ((data.m_flags & NetSegment.Flags.WaitingPath) == NetSegment.Flags.None)
     {
         return true;
     }
     PathManager instance = Singleton<PathManager>.instance;
     NetManager instance2 = Singleton<NetManager>.instance;
     byte pathFindFlags = instance.m_pathUnits.m_buffer[(int)((UIntPtr)data.m_path)].m_pathFindFlags;
     if ((pathFindFlags & 4) != 0)
     {
         bool flag = false;
         PathUnit.Position pathPos;
         if (instance.m_pathUnits.m_buffer[(int)((UIntPtr)data.m_path)].GetPosition(0, out pathPos))
         {
             flag = TransportLineAI.CheckNodePosition(data.m_startNode, pathPos);
         }
         if (instance.m_pathUnits.m_buffer[(int)((UIntPtr)data.m_path)].GetLastPosition(out pathPos))
         {
             TransportLineAI.CheckNodePosition(data.m_endNode, pathPos);
         }
         float length = instance.m_pathUnits.m_buffer[(int)((UIntPtr)data.m_path)].m_length;
         if (length != data.m_averageLength)
         {
             data.m_averageLength = length;
             ushort transportLine = instance2.m_nodes.m_buffer[(int)data.m_startNode].m_transportLine;
             if (transportLine != 0)
             {
                 Singleton<TransportManager>.instance.UpdateLine(transportLine);
             }
         }
         if (data.m_lanes != 0u)
         {
             instance2.m_lanes.m_buffer[(int)((UIntPtr)data.m_lanes)].m_length = data.m_averageLength * ((!flag) ? 1f : 0.75f);
         }
         data.m_flags &= ~NetSegment.Flags.WaitingPath;
         data.m_flags &= ~NetSegment.Flags.PathFailed;
         return true;
     }
     if ((pathFindFlags & 8) != 0)
     {
         if (data.m_averageLength == 0f)
         {
             Vector3 position = instance2.m_nodes.m_buffer[(int)data.m_startNode].m_position;
             Vector3 position2 = instance2.m_nodes.m_buffer[(int)data.m_endNode].m_position;
             data.m_averageLength = Vector3.Distance(position, position2);
         }
         data.m_flags &= ~NetSegment.Flags.WaitingPath;
         data.m_flags |= NetSegment.Flags.PathFailed;
         return true;
     }
     return false;
 }
        private float CalculateLaneSpeed(byte startOffset, byte endOffset, ref NetSegment segment, NetInfo.Lane laneInfo, uint laneId)
        {
            float speedLimit = (CSLTraffic.Options & OptionsManager.ModOptions.BetaTestRoadCustomizerTool) == OptionsManager.ModOptions.BetaTestRoadCustomizerTool ? RoadManager.GetLaneSpeed(laneId) : laneInfo.m_speedLimit;
            //float speedLimit = laneInfo.m_speedLimit;

            NetInfo.Direction direction = ((segment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? laneInfo.m_finalDirection : NetInfo.InvertDirection(laneInfo.m_finalDirection);
            if ((byte)(direction & NetInfo.Direction.Avoid) == 0)
            {
                //return laneInfo.m_speedLimit;
                return speedLimit;
            }
            if (endOffset > startOffset && direction == NetInfo.Direction.AvoidForward)
            {
                //return laneInfo.m_speedLimit * 0.1f;
                return speedLimit * 0.1f;
            }
            if (endOffset < startOffset && direction == NetInfo.Direction.AvoidBackward)
            {
                //return laneInfo.m_speedLimit * 0.1f;
                return speedLimit * 0.1f;
            }
            //return laneInfo.m_speedLimit * 0.2f;
            return speedLimit * 0.2f;
        }
        private static Vector3 CalculateNodePositionForSegment(NetNode node, NetSegment segment)
        {
            var position = node.m_position;

            const float offset = 25f;

            if (segment.m_startNode == SelectedNode)
            {
                position.x += segment.m_startDirection.x*offset;
                position.y += segment.m_startDirection.y*offset;
                position.z += segment.m_startDirection.z*offset;
            }
            else
            {
                position.x += segment.m_endDirection.x*offset;
                position.y += segment.m_endDirection.y*offset;
                position.z += segment.m_endDirection.z*offset;
            }
            return position;
        }
		public static bool CustomStartPathFind(ushort segmentID, ref NetSegment data, ItemClass.Service netService, VehicleInfo.VehicleType vehicleType, bool skipQueue) {
			if (data.m_path != 0u) {
				Singleton<PathManager>.instance.ReleasePath(data.m_path);
				data.m_path = 0u;
			}
			NetManager instance = Singleton<NetManager>.instance;
			if ((instance.m_nodes.m_buffer[(int)data.m_startNode].m_flags & NetNode.Flags.Ambiguous) != NetNode.Flags.None) {
				for (int i = 0; i < 8; i++) {
					ushort segment = instance.m_nodes.m_buffer[(int)data.m_startNode].GetSegment(i);
					if (segment != 0 && segment != segmentID && instance.m_segments.m_buffer[(int)segment].m_path != 0u) {
						return true;
					}
				}
			}
			if ((instance.m_nodes.m_buffer[(int)data.m_endNode].m_flags & NetNode.Flags.Ambiguous) != NetNode.Flags.None) {
				for (int j = 0; j < 8; j++) {
					ushort segment2 = instance.m_nodes.m_buffer[(int)data.m_endNode].GetSegment(j);
					if (segment2 != 0 && segment2 != segmentID && instance.m_segments.m_buffer[(int)segment2].m_path != 0u) {
						return true;
					}
				}
			}
			Vector3 position = instance.m_nodes.m_buffer[(int)data.m_startNode].m_position;
			Vector3 position2 = instance.m_nodes.m_buffer[(int)data.m_endNode].m_position;
			PathUnit.Position startPosA;
			PathUnit.Position startPosB;
			float num;
			float num2;
			if (!PathManager.FindPathPosition(position, netService, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, vehicleType, true, false, 32f, out startPosA, out startPosB, out num, out num2)) {
				CustomTransportLineAI.CheckSegmentProblems(segmentID, ref data);
				return true;
			}
			PathUnit.Position endPosA;
			PathUnit.Position endPosB;
			float num3;
			float num4;
			if (!PathManager.FindPathPosition(position2, netService, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, vehicleType, true, false, 32f, out endPosA, out endPosB, out num3, out num4)) {
				CustomTransportLineAI.CheckSegmentProblems(segmentID, ref data);
				return true;
			}
			if ((instance.m_nodes.m_buffer[(int)data.m_startNode].m_flags & NetNode.Flags.Fixed) != NetNode.Flags.None) {
				startPosB = default(PathUnit.Position);
			}
			if ((instance.m_nodes.m_buffer[(int)data.m_endNode].m_flags & NetNode.Flags.Fixed) != NetNode.Flags.None) {
				endPosB = default(PathUnit.Position);
			}
			startPosA.m_offset = 128;
			startPosB.m_offset = 128;
			endPosA.m_offset = 128;
			endPosB.m_offset = 128;
			bool stopLane = CustomTransportLineAI.GetStopLane(ref startPosA, vehicleType);
			bool stopLane2 = CustomTransportLineAI.GetStopLane(ref startPosB, vehicleType);
			bool stopLane3 = CustomTransportLineAI.GetStopLane(ref endPosA, vehicleType);
			bool stopLane4 = CustomTransportLineAI.GetStopLane(ref endPosB, vehicleType);
			if ((!stopLane && !stopLane2) || (!stopLane3 && !stopLane4)) {
				CustomTransportLineAI.CheckSegmentProblems(segmentID, ref data);
				return true;
			}
			uint path;
			ExtVehicleType extVehicleType = ExtVehicleType.Bus;
			if ((vehicleType & (VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Metro)) != VehicleInfo.VehicleType.None)
				extVehicleType = ExtVehicleType.PassengerTrain;
			if ((vehicleType & VehicleInfo.VehicleType.Tram) != VehicleInfo.VehicleType.None)
				extVehicleType = ExtVehicleType.Tram;
			if ((vehicleType & VehicleInfo.VehicleType.Ship) != VehicleInfo.VehicleType.None)
				extVehicleType = ExtVehicleType.PassengerShip;
			if ((vehicleType & VehicleInfo.VehicleType.Plane) != VehicleInfo.VehicleType.None)
				extVehicleType = ExtVehicleType.PassengerPlane;
			//Log._Debug($"Transport line. extVehicleType={extVehicleType}");

			if (Singleton<CustomPathManager>.instance.CreatePath(extVehicleType, out path, ref Singleton<SimulationManager>.instance.m_randomizer, Singleton<SimulationManager>.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, vehicleType, 20000f, false, true, true, skipQueue)) {
				if (startPosA.m_segment != 0 && startPosB.m_segment != 0) {
					NetNode[] expr_2F5_cp_0 = instance.m_nodes.m_buffer;
					ushort expr_2F5_cp_1 = data.m_startNode;
					expr_2F5_cp_0[(int)expr_2F5_cp_1].m_flags = (expr_2F5_cp_0[(int)expr_2F5_cp_1].m_flags | NetNode.Flags.Ambiguous);
				} else {
					NetNode[] expr_321_cp_0 = instance.m_nodes.m_buffer;
					ushort expr_321_cp_1 = data.m_startNode;
					expr_321_cp_0[(int)expr_321_cp_1].m_flags = (expr_321_cp_0[(int)expr_321_cp_1].m_flags & ~NetNode.Flags.Ambiguous);
				}
				if (endPosA.m_segment != 0 && endPosB.m_segment != 0) {
					NetNode[] expr_360_cp_0 = instance.m_nodes.m_buffer;
					ushort expr_360_cp_1 = data.m_endNode;
					expr_360_cp_0[(int)expr_360_cp_1].m_flags = (expr_360_cp_0[(int)expr_360_cp_1].m_flags | NetNode.Flags.Ambiguous);
				} else {
					NetNode[] expr_38C_cp_0 = instance.m_nodes.m_buffer;
					ushort expr_38C_cp_1 = data.m_endNode;
					expr_38C_cp_0[(int)expr_38C_cp_1].m_flags = (expr_38C_cp_0[(int)expr_38C_cp_1].m_flags & ~NetNode.Flags.Ambiguous);
				}
				data.m_path = path;
				data.m_flags |= NetSegment.Flags.WaitingPath;
				return false;
			}
			CustomTransportLineAI.CheckSegmentProblems(segmentID, ref data);
			return true;
		}
 protected static bool StartPathFind(ushort segmentId, ref NetSegment data, ItemClass.Service netService, VehicleInfo.VehicleType vehicleType, bool skipQueue)
 {
     if (data.m_path != 0u)
     {
         Singleton<PathManager>.instance.ReleasePath(data.m_path);
         data.m_path = 0u;
     }
     NetManager instance = Singleton<NetManager>.instance;
     if ((instance.m_nodes.m_buffer[data.m_startNode].m_flags & NetNode.Flags.Ambiguous) != NetNode.Flags.None)
     {
         for (int i = 0; i < 8; i++)
         {
             ushort segment = instance.m_nodes.m_buffer[data.m_startNode].GetSegment(i);
             if (segment != 0 && segment != segmentId && instance.m_segments.m_buffer[segment].m_path != 0u)
             {
                 return true;
             }
         }
     }
     if ((instance.m_nodes.m_buffer[data.m_endNode].m_flags & NetNode.Flags.Ambiguous) != NetNode.Flags.None)
     {
         for (int j = 0; j < 8; j++)
         {
             ushort segment2 = instance.m_nodes.m_buffer[data.m_endNode].GetSegment(j);
             if (segment2 != 0 && segment2 != segmentId && instance.m_segments.m_buffer[segment2].m_path != 0u)
             {
                 return true;
             }
         }
     }
     var position = instance.m_nodes.m_buffer[data.m_startNode].m_position;
     var position2 = instance.m_nodes.m_buffer[data.m_endNode].m_position;
     PathUnit.Position startPosA;
     PathUnit.Position startPosB;
     float num;
     float num2;
     if (!PathManager.FindPathPosition(position, netService, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, true, true, 32f, out startPosA, out startPosB, out num, out num2))
     {
         return true;
     }
     PathUnit.Position endPosA;
     PathUnit.Position endPosB;
     float num3;
     float num4;
     if (!PathManager.FindPathPosition(position2, netService, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, true, true, 32f, out endPosA, out endPosB, out num3, out num4))
     {
         return true;
     }
     if ((instance.m_nodes.m_buffer[data.m_startNode].m_flags & NetNode.Flags.Fixed) != NetNode.Flags.None)
     {
         startPosB = default(PathUnit.Position);
     }
     if ((instance.m_nodes.m_buffer[data.m_endNode].m_flags & NetNode.Flags.Fixed) != NetNode.Flags.None)
     {
         endPosB = default(PathUnit.Position);
     }
     startPosA.m_offset = 128;
     startPosB.m_offset = 128;
     endPosA.m_offset = 128;
     endPosB.m_offset = 128;
     bool stopLane = GetStopLane(ref startPosA, vehicleType);
     bool stopLane2 = GetStopLane(ref startPosB, vehicleType);
     bool stopLane3 = GetStopLane(ref endPosA, vehicleType);
     bool stopLane4 = GetStopLane(ref endPosB, vehicleType);
     if ((!stopLane && !stopLane2) || (!stopLane3 && !stopLane4))
     {
         return true;
     }
     uint path;
     if (Singleton<CustomPathManager>.instance.CreatePath(out path, ref Singleton<SimulationManager>.instance.m_randomizer, Singleton<SimulationManager>.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle, vehicleType, 20000f, false, true, true, skipQueue, ItemClass.Service.PublicTransport))
     {
         if (startPosA.m_segment != 0 && startPosB.m_segment != 0)
         {
             var expr_2D9Cp0 = instance.m_nodes.m_buffer;
             var expr_2D9Cp1 = data.m_startNode;
             expr_2D9Cp0[expr_2D9Cp1].m_flags = (expr_2D9Cp0[expr_2D9Cp1].m_flags | NetNode.Flags.Ambiguous);
         }
         else
         {
             var expr305Cp0 = instance.m_nodes.m_buffer;
             var expr305Cp1 = data.m_startNode;
             expr305Cp0[expr305Cp1].m_flags = (expr305Cp0[expr305Cp1].m_flags & ~NetNode.Flags.Ambiguous);
         }
         if (endPosA.m_segment != 0 && endPosB.m_segment != 0)
         {
             var expr344Cp0 = instance.m_nodes.m_buffer;
             var expr344Cp1 = data.m_endNode;
             expr344Cp0[expr344Cp1].m_flags = (expr344Cp0[expr344Cp1].m_flags | NetNode.Flags.Ambiguous);
         }
         else
         {
             var expr370Cp0 = instance.m_nodes.m_buffer;
             var expr370Cp1 = data.m_endNode;
             expr370Cp0[expr370Cp1].m_flags = (expr370Cp0[expr370Cp1].m_flags & ~NetNode.Flags.Ambiguous);
         }
         data.m_path = path;
         data.m_flags |= NetSegment.Flags.WaitingPath;
         return false;
     }
     return true;
 }
            bool FindNode(NetSegment segment)
            {
                uint laneId = segment.m_lanes;
                NetInfo info = segment.Info;
                int laneCount = info.m_lanes.Length;
                int laneIndex = 0;
                for (; laneIndex < laneCount && laneId != 0; laneIndex++)
                {
                    if (laneId == m_laneId)
                        break;
                    laneId = NetManager.instance.m_lanes.m_buffer[laneId].m_nextLane;
                }

                if (laneIndex < laneCount)
                {
                    NetInfo.Direction laneDir = ((segment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? info.m_lanes[laneIndex].m_finalDirection : NetInfo.InvertDirection(info.m_lanes[laneIndex].m_finalDirection);

                    if ((laneDir & (NetInfo.Direction.Forward | NetInfo.Direction.Avoid)) == NetInfo.Direction.Forward)
                        m_nodeId = segment.m_endNode;
                    else if ((laneDir & (NetInfo.Direction.Backward | NetInfo.Direction.Avoid)) == NetInfo.Direction.Backward)
                        m_nodeId = segment.m_startNode;

                    return true;
                }

                return false;
            }
 // NetSegment.GetClosestLane -- it's only called by the PathManager
 public static bool GetClosestLanePosition(NetSegment seg, Vector3 point, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, bool requireConnect, out Vector3 positionA, out int laneIndexA, out float laneOffsetA, out Vector3 positionB, out int laneIndexB, out float laneOffsetB, RoadManager.VehicleType vehicleType)
 {
     positionA = point;
     laneIndexA = -1;
     laneOffsetA = 0f;
     positionB = point;
     laneIndexB = -1;
     laneOffsetB = 0f;
     if (seg.m_flags != NetSegment.Flags.None && seg.m_lanes != 0u)
     {
         NetInfo info = seg.Info;
         if (info.m_lanes != null)
         {
             float num = 1E+09f;
             float num2 = 1E+09f;
             uint num3 = seg.m_lanes;
             int num4 = 0;
             while (num4 < info.m_lanes.Length && num3 != 0u)
             {
                 NetInfo.Lane lane = info.m_lanes[num4];
                 if (lane.CheckType(laneTypes, vehicleTypes) && (lane.m_allowConnect || !requireConnect) && RoadManager.CanUseLane(vehicleType, num3))
                 {
                     Vector3 vector;
                     float num5;
                     Singleton<NetManager>.instance.m_lanes.m_buffer[(int)((UIntPtr)num3)].GetClosestPosition(point, out vector, out num5);
                     float num6 = Vector3.SqrMagnitude(point - vector);
                     if (lane.m_finalDirection == NetInfo.Direction.Backward || lane.m_finalDirection == NetInfo.Direction.AvoidForward)
                     {
                         if (num6 < num2)
                         {
                             num2 = num6;
                             positionB = vector;
                             laneIndexB = num4;
                             laneOffsetB = num5;
                         }
                     }
                     else if (num6 < num)
                     {
                         num = num6;
                         positionA = vector;
                         laneIndexA = num4;
                         laneOffsetA = num5;
                     }
                 }
                 num3 = Singleton<NetManager>.instance.m_lanes.m_buffer[(int)((UIntPtr)num3)].m_nextLane;
                 num4++;
             }
             if (num2 < num)
             {
                 Vector3 vector2 = positionA;
                 int num7 = laneIndexA;
                 float num8 = laneOffsetA;
                 positionA = positionB;
                 laneIndexA = laneIndexB;
                 laneOffsetA = laneOffsetB;
                 positionB = vector2;
                 laneIndexB = num7;
                 laneOffsetB = num8;
             }
             if (!info.m_canCrossLanes)
             {
                 positionB = point;
                 laneIndexB = -1;
                 laneOffsetB = 0f;
             }
         }
     }
     return laneIndexA != -1;
 }
 protected virtual void ProcessItem(BufferItem item, ushort targetNode, ushort segmentID, ref NetSegment segment, byte connectOffset, int laneIndex, uint lane)
 {
     if ((segment.m_flags & (NetSegment.Flags.PathFailed | NetSegment.Flags.Flooded)) != NetSegment.Flags.None)
     {
         return;
     }
     NetManager instance = Singleton<NetManager>.instance;
     NetInfo info = segment.Info;
     NetInfo info2 = instance.m_segments.m_buffer[(int)item.m_position.m_segment].Info;
     int num = info.m_lanes.Length;
     float num2;
     byte offset;
     if (segmentID == item.m_position.m_segment)
     {
         Vector3 b = instance.m_lanes.m_buffer[(int)((UIntPtr)item.m_laneID)].CalculatePosition((float)connectOffset * 0.003921569f);
         Vector3 a = instance.m_lanes.m_buffer[(int)((UIntPtr)lane)].CalculatePosition((float)connectOffset * 0.003921569f);
         num2 = Vector3.Distance(a, b);
         offset = connectOffset;
     }
     else
     {
         NetInfo.Direction direction = (targetNode != segment.m_startNode) ? NetInfo.Direction.Forward : NetInfo.Direction.Backward;
         Vector3 b2 = instance.m_lanes.m_buffer[(int)((UIntPtr)item.m_laneID)].CalculatePosition((float)connectOffset * 0.003921569f);
         Vector3 a2;
         if ((byte)(direction & NetInfo.Direction.Forward) != 0)
         {
             a2 = instance.m_lanes.m_buffer[(int)((UIntPtr)lane)].m_bezier.d;
         }
         else
         {
             a2 = instance.m_lanes.m_buffer[(int)((UIntPtr)lane)].m_bezier.a;
         }
         num2 = Vector3.Distance(a2, b2);
         offset = (byte)(((direction & NetInfo.Direction.Forward) == 0) ? 0 : 255);
     }
     float num3 = 1f;
     float num4 = 1f;
     NetInfo.LaneType laneType = NetInfo.LaneType.None;
     if ((int)item.m_position.m_lane < info2.m_lanes.Length)
     {
         NetInfo.Lane lane2 = info2.m_lanes[(int)item.m_position.m_lane];
         num3 = lane2.m_speedLimit;
         laneType = lane2.m_laneType;
         if ((byte)(laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0)
         {
             laneType = (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle);
         }
         num4 = this.CalculateLaneSpeed(connectOffset, item.m_position.m_offset, ref instance.m_segments.m_buffer[(int)item.m_position.m_segment], lane2);
     }
     float averageLength = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_averageLength;
     float num5 = (float)Mathf.Abs((int)(connectOffset - item.m_position.m_offset)) * 0.003921569f * averageLength;
     float num6 = item.m_methodDistance + num5;
     float num7 = item.m_comparisonValue + num5 / (num4 * this.m_maxLength);
     if (laneIndex < num)
     {
         NetInfo.Lane lane3 = info.m_lanes[laneIndex];
         BufferItem item2;
         item2.m_position.m_segment = segmentID;
         item2.m_position.m_lane = (byte)laneIndex;
         item2.m_position.m_offset = offset;
         if ((byte)(lane3.m_laneType & laneType) == 0)
         {
             item2.m_methodDistance = 0f;
         }
         else
         {
             if (item.m_methodDistance == 0f)
             {
                 num7 += 100f / (0.25f * this.m_maxLength);
             }
             item2.m_methodDistance = num6 + num2;
         }
         if (lane3.m_laneType != NetInfo.LaneType.Pedestrian || item2.m_methodDistance < 1000f)
         {
             item2.m_comparisonValue = num7 + num2 / ((num3 + lane3.m_speedLimit) * 0.25f * this.m_maxLength);
             if ((segment.m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None)
             {
                 item2.m_direction = NetInfo.InvertDirection(lane3.m_finalDirection);
             }
             else
             {
                 item2.m_direction = lane3.m_finalDirection;
             }
             if (lane == this.m_startLaneA)
             {
                 if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this.m_startOffsetA) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this.m_startOffsetA))
                 {
                     return;
                 }
                 float num8 = this.CalculateLaneSpeed(this.m_startOffsetA, item2.m_position.m_offset, ref segment, lane3);
                 float num9 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this.m_startOffsetA)) * 0.003921569f;
                 item2.m_comparisonValue += num9 * segment.m_averageLength / (num8 * this.m_maxLength);
             }
             if (lane == this.m_startLaneB)
             {
                 if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this.m_startOffsetB) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this.m_startOffsetB))
                 {
                     return;
                 }
                 float num10 = this.CalculateLaneSpeed(this.m_startOffsetB, item2.m_position.m_offset, ref segment, lane3);
                 float num11 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this.m_startOffsetB)) * 0.003921569f;
                 item2.m_comparisonValue += num11 * segment.m_averageLength / (num10 * this.m_maxLength);
             }
             item2.m_laneID = lane;
             item2.m_lanesUsed = (item.m_lanesUsed | lane3.m_laneType);
             this.AddBufferItem(item2, item.m_position);
         }
     }
 }
        protected bool ValidateSelectedArea(NetSegment segment)
        {
            var minX = this.m_startPosition.x < this.m_mousePosition.x ? this.m_startPosition.x : this.m_mousePosition.x;
            var minZ = this.m_startPosition.z < this.m_mousePosition.z ? this.m_startPosition.z : this.m_mousePosition.z;
            var maxX = this.m_startPosition.x > this.m_mousePosition.x ? this.m_startPosition.x : this.m_mousePosition.x;
            var maxZ = this.m_startPosition.z > this.m_mousePosition.z ? this.m_startPosition.z : this.m_mousePosition.z;

            Vector3 position = segment.m_middlePosition;
            float positionDiff = Mathf.Max(Mathf.Max(minX - 16f - position.x, minZ - 16f - position.z), Mathf.Max(position.x - maxX - 16f, position.z - maxZ - 16f));

            if (positionDiff < 0f)
            {
                return true;
            }
            return false;
        }
		// 3
		private bool ProcessItemCosts(bool allowCustomLaneChanging, bool debug, BufferItem item, ushort targetNodeId, ushort nextSegmentId, ref NetSegment nextSegment, ref int laneIndexFromLeft, byte connectOffset, bool enableVehicle, bool enablePedestrian, int? forceLaneIndex, uint? forceLaneId, out bool foundForced) {
			//sCurrentState = 0;
#if DEBUGPF
			/*if (Options.disableSomething1)
				Log._Debug($"THREAD #{Thread.CurrentThread.ManagedThreadId} PF {this._pathFindIndex}: ProcessItemSub item {item.m_position.m_segment} {item.m_position.m_lane}, targetNodeId {targetNodeId}");*/
#endif

			//debug = targetNodeId == 6900;
			foundForced = false;
			bool result = false;
			if ((nextSegment.m_flags & (NetSegment.Flags.PathFailed | NetSegment.Flags.Flooded)) != NetSegment.Flags.None) {
				return result;
			}
			NetManager instance = Singleton<NetManager>.instance;
			NetInfo nextSegmentInfo = nextSegment.Info;
			NetInfo prevSegmentInfo = instance.m_segments.m_buffer[(int)item.m_position.m_segment].Info;
			int nextNumLanes = nextSegmentInfo.m_lanes.Length;
			NetInfo.Direction nextDir = (targetNodeId != nextSegment.m_startNode) ? NetInfo.Direction.Forward : NetInfo.Direction.Backward;
			NetInfo.Direction nextDir2 = ((nextSegment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? nextDir : NetInfo.InvertDirection(nextDir);
			float num3 = 0.01f - Mathf.Min(nextSegmentInfo.m_maxTurnAngleCos, prevSegmentInfo.m_maxTurnAngleCos);
			//sCurrentState = 1;
			if (num3 < 1f) {
				Vector3 vector;
				if (targetNodeId == instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_startNode) {
					vector = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_startDirection;
				} else {
					vector = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_endDirection;
				}
				Vector3 vector2;
				if ((byte)(nextDir & NetInfo.Direction.Forward) != 0) {
					vector2 = nextSegment.m_endDirection;
				} else {
					vector2 = nextSegment.m_startDirection;
				}
				float num4 = vector.x * vector2.x + vector.z * vector2.z;
				if (num4 >= num3) {
					return result;
				}
			}
			//sCurrentState = 2;
			float prevMaxSpeed = 1f;
			float prevLaneSpeed = 1f;
			NetInfo.LaneType laneType = NetInfo.LaneType.None;
			VehicleInfo.VehicleType vehicleType = VehicleInfo.VehicleType.None;
			// NON-STOCK CODE START //
			bool prevIsHighway = false;
			if (prevSegmentInfo.m_netAI is RoadBaseAI)
				prevIsHighway = ((RoadBaseAI)prevSegmentInfo.m_netAI).m_highwayRules;
			float nextSpeed = 1f;
			float nextDensity = 0f;
			int prevRightSimilarLaneIndex = -1;
			NetInfo.Direction normDirection = TrafficPriority.IsLeftHandDrive() ? NetInfo.Direction.Forward : NetInfo.Direction.Backward; // direction to normalize indices to
			int prevNumLanes = 1;
			float prevSpeed = 0f;
			bool isMiddle = connectOffset != 0 && connectOffset != 255;
			NetInfo.Lane lane = null;
			//sCurrentState = 3;
			// NON-STOCK CODE END //
			if ((int)item.m_position.m_lane < prevSegmentInfo.m_lanes.Length) {
				lane = prevSegmentInfo.m_lanes[(int)item.m_position.m_lane];
				laneType = lane.m_laneType;
				vehicleType = lane.m_vehicleType;
				prevMaxSpeed = GetLaneSpeedLimit(item.m_position.m_segment, item.m_position.m_lane, item.m_laneID, lane); // SpeedLimitManager.GetLockFreeGameSpeedLimit(item.m_position.m_segment, item.m_position.m_lane, item.m_laneID, ref lane); // NON-STOCK CODE
				prevLaneSpeed = this.CalculateLaneSpeed(prevMaxSpeed, connectOffset, item.m_position.m_offset, ref instance.m_segments.m_buffer[(int)item.m_position.m_segment], lane); // NON-STOCK CODE
				// NON-STOCK CODE START //
				prevNumLanes = lane.m_similarLaneCount;
				if ((byte)(lane.m_direction & normDirection) != 0) {
					prevRightSimilarLaneIndex = lane.m_similarLaneIndex;
				} else {
					prevRightSimilarLaneIndex = lane.m_similarLaneCount - lane.m_similarLaneIndex - 1;
				}
				prevSpeed = CustomRoadAI.laneMeanSpeeds[item.m_laneID];
				prevSpeed = (float)Math.Max(0.1f, Math.Round(prevSpeed * 0.01f * 4f) / 4f); // 0.01, 0.25, 0.5, 0.75, 1
				// NON-STOCK CODE END //
			}
			//sCurrentState = 4;
			bool useAdvancedAI = !Options.isStockLaneChangerUsed() &&
				(_extVehicleType != null &&
				(_extVehicleType & (ExtVehicleType.RoadVehicle & ~ExtVehicleType.RoadPublicTransport)) != ExtVehicleType.None) &&
				allowCustomLaneChanging &&
				!_transportVehicle &&
				!_stablePath &&
				enableVehicle &&
				(vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None &&
				(laneType & (NetInfo.LaneType.PublicTransport | NetInfo.LaneType.Pedestrian | NetInfo.LaneType.Parking)) == NetInfo.LaneType.None; // NON-STOCK CODE
			float cost = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_averageLength;
			if (!useAdvancedAI && !this._stablePath) { // NON-STOCK CODE
				Randomizer randomizer = new Randomizer(this._pathFindIndex << 16 | (uint)item.m_position.m_segment);
				cost *= (float)(randomizer.Int32(900, 1000 + (int)(instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_trafficDensity * 10)) + this._pathRandomizer.Int32(20u)) * 0.001f;
			}
			if (!useAdvancedAI) {
				if (this._isHeavyVehicle && (instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_flags & NetSegment.Flags.HeavyBan) != NetSegment.Flags.None) {
					cost *= 10f;
				} else if (laneType == NetInfo.LaneType.Vehicle && (vehicleType & _vehicleTypes) == VehicleInfo.VehicleType.Car && (instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_flags & NetSegment.Flags.CarBan) != NetSegment.Flags.None) {
					cost *= 5f;
				}
			}
			if (this._transportVehicle && laneType == NetInfo.LaneType.TransportVehicle) {
				cost *= 0.95f;
				//cost *= Options.someValue2;
			}
			bool avoidLane = false;
			bool strictlyAvoidLane = false;
			if (
					(this._isHeavyVehicle && (nextSegment.m_flags & NetSegment.Flags.HeavyBan) != NetSegment.Flags.None) ||
					(laneType == NetInfo.LaneType.Vehicle && (vehicleType & _vehicleTypes) == VehicleInfo.VehicleType.Car && (instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_flags & NetSegment.Flags.CarBan) != NetSegment.Flags.None)
					) {
				if (Options.disableSomething1 && debug) {
					Log._Debug($"Vehicle {_extVehicleType} should not use lane {item.m_position.m_lane} @ seg. {item.m_position.m_segment}, null? {lane == null}");
				}
				avoidLane = true;
			}
			if (!CanUseLane(debug, item.m_position.m_segment, item.m_position.m_lane, item.m_laneID, lane)) {
				if (Options.disableSomething1 && debug) {
					Log._Debug($"Vehicle {_extVehicleType} must not use lane {item.m_position.m_lane} @ seg. {item.m_position.m_segment}, null? {lane== null}");
				}
				strictlyAvoidLane = true;
			}
			if (!useAdvancedAI) {
				if (strictlyAvoidLane)
					cost *= Options.someValue4;
			}
			if ((byte)(laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0) {
				laneType = (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle);
			}
			float prevOffsetCost = (float)Mathf.Abs((int)(connectOffset - item.m_position.m_offset)) * 0.003921569f * cost;
			float prevMethodDist = item.m_methodDistance + prevOffsetCost;
			float prevComparisonPlusOffsetCostOverSpeed = item.m_comparisonValue + prevOffsetCost / (prevLaneSpeed * this._maxLength);
			Vector3 prevLanePosition = instance.m_lanes.m_buffer[(int)((UIntPtr)item.m_laneID)].CalculatePosition((float)connectOffset * 0.003921569f);
			int newLaneIndexFromLeft = laneIndexFromLeft;
			bool transitionNode = (instance.m_nodes.m_buffer[(int)targetNodeId].m_flags & NetNode.Flags.Transition) != NetNode.Flags.None;
			NetInfo.LaneType laneType2 = this._laneTypes;
			VehicleInfo.VehicleType vehicleType2 = this._vehicleTypes;
			if (!enableVehicle) {
				vehicleType2 &= VehicleInfo.VehicleType.Bicycle;
				if (vehicleType2 == VehicleInfo.VehicleType.None) {
					laneType2 &= ~(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle);
				}
			}
			if (!enablePedestrian) {
				laneType2 &= ~NetInfo.LaneType.Pedestrian;
			}
			// NON-STOCK CODE START //
			//NetNode targetNode = instance.m_nodes.m_buffer[targetNodeId];
			//float segmentDensity = (float)(instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_trafficDensity + nextSegment.m_trafficDensity) / 2f;
			bool nextIsRealJunction = instance.m_nodes.m_buffer[targetNodeId].CountSegments() > 2;
			ushort sourceNodeId = (targetNodeId == instance.m_segments.m_buffer[item.m_position.m_segment].m_startNode) ? instance.m_segments.m_buffer[item.m_position.m_segment].m_endNode : instance.m_segments.m_buffer[item.m_position.m_segment].m_startNode; // no lane changing directly in front of a junction
			bool prevIsRealJunction = instance.m_nodes.m_buffer[sourceNodeId].CountSegments() > 2;
			//sCurrentState = 9;
			bool nextIsHighway = false;
			if (nextSegmentInfo.m_netAI is RoadBaseAI)
				nextIsHighway = ((RoadBaseAI)nextSegmentInfo.m_netAI).m_highwayRules;
			bool wantToChangeLane = false;
			if (useAdvancedAI)
				wantToChangeLane = _pathRandomizer.Int32(1, Options.getLaneChangingRandomizationTargetValue()) == 1;

			float nextDensitySum = 0f;
			if (useAdvancedAI) {
				// measure speed variance
				uint lIndex = 0;
				uint currentLaneId = nextSegment.m_lanes;
				uint nextCompatibleLanes = 0;
				while (lIndex < nextNumLanes && currentLaneId != 0u) {
					NetInfo.Lane nextLane = nextSegmentInfo.m_lanes[lIndex];
					if (nextLane.CheckType(laneType2, vehicleType2) && (nextSegmentId != item.m_position.m_segment || lIndex != (int)item.m_position.m_lane) && (byte)(nextLane.m_finalDirection & nextDir2) != 0) {
						++nextCompatibleLanes;
						nextDensitySum += CustomRoadAI.currentLaneDensities[currentLaneId];
					}

					lIndex++;
					currentLaneId = instance.m_lanes.m_buffer[currentLaneId].m_nextLane;
				}
			}
			// NON-STOCK CODE END //

			uint laneIndex = forceLaneIndex != null ? (uint)forceLaneIndex : 0u;
			uint curLaneId = (uint)(forceLaneId != null ? forceLaneId : nextSegment.m_lanes); // NON-STOCK CODE
																							  //sCurrentState = 10;
			while (laneIndex < nextNumLanes && curLaneId != 0u) {
				//sCurrentState = 11;

				//Log.Message($"PF {this._pathFindIndex} -- CustomPathfind (3): Iter #{laneIndex}, curLaneId={curLaneId}, prevSegment={item.m_position.m_segment}, targetNodeId={targetNodeId}");

				// NON-STOCK CODE START //
				if (forceLaneIndex != null && laneIndex != forceLaneIndex)
					break;
				// NON-STOCK CODE END //
				NetInfo.Lane nextLane = nextSegmentInfo.m_lanes[laneIndex];

#if DEBUGCOSTS
				bool costDebug = debug;
				//bool costDebug = Options.disableSomething1 && (nextSegmentId == 9649 || nextSegmentId == 1043);
				List<String> logBuf = null;
				if (costDebug) {
					logBuf = new List<String>();
					logBuf.Add($"Path from {nextSegmentId} (idx {laneIndex}, id {curLaneId}) to {item.m_position.m_segment} (lane {prevRightSimilarLaneIndex} from right, idx {item.m_position.m_lane}): costDebug=TRUE, explore? {nextLane.CheckType(laneType2, vehicleType2)} && {(nextSegmentId != item.m_position.m_segment || laneIndex != (int)item.m_position.m_lane)} && {(byte)(nextLane.m_finalDirection & nextDir2) != 0 && CanLanesConnect(curLaneId, item.m_laneID)}");
				}
#endif

				if ((byte)(nextLane.m_finalDirection & nextDir2) != 0 && CanLanesConnect(curLaneId, item.m_laneID)) {
					//sCurrentState = 12;
					if (nextLane.CheckType(laneType2, vehicleType2) && (nextSegmentId != item.m_position.m_segment || laneIndex != (int)item.m_position.m_lane) && (byte)(nextLane.m_finalDirection & nextDir2) != 0) {
						// NON-STOCK CODE START //
						float nextMaxSpeed = GetLaneSpeedLimit(nextSegmentId, laneIndex, curLaneId, nextLane);// SpeedLimitManager.GetLockFreeGameSpeedLimit(segmentID, laneIndex, curLaneId, ref nextLane);
						bool addCustomTrafficCosts = useAdvancedAI && curLaneId != this._startLaneA && curLaneId != this._startLaneB && curLaneId != this._endLaneA && curLaneId != this._endLaneB && (byte)(nextLane.m_laneType & laneType) != 0 && (nextLane.m_vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None && (nextLane.m_laneType & NetInfo.LaneType.PublicTransport) == NetInfo.LaneType.None;

						if (addCustomTrafficCosts) {
							nextSpeed = CustomRoadAI.laneMeanSpeeds[curLaneId];
							nextSpeed = (float)Math.Max(0.1f, Math.Round(nextSpeed * 0.01f * 4f) / 4f); // 0.01, 0.25, 0.5, 0.75, 1
							if (nextDensitySum <= 0f)
								nextDensity = 0.01f;
							else {
								nextDensity = Math.Min(1f, (float)CustomRoadAI.currentLaneDensities[curLaneId] / nextDensitySum);
								nextDensity = (float)Math.Max(0.01f, Math.Round(nextDensity * 4f) / 4f); // 0.01, 0.25, 0.5, 0.75, 1
							}

							/*if (Options.disableSomething4) {
								Log._Debug($"nextSegment={nextSegmentId} laneIndex={laneIndex} nextDensitySum={nextDensitySum} nextDensity={(float)CustomRoadAI.currentLaneDensities[curLaneId]} / {nextDensitySum} = {nextDensity}");
							}*/
						}
						// NON-STOCK CODE END //

						//sCurrentState = 13;
						float distanceOnBezier = 0f;

						Vector3 a;
						Vector3 b;

						// NON-STOCK CODE START //
						/*if (customLaneChanging) {
							a = instance.m_nodes.m_buffer[targetNodeId].m_position;
							b = meanPrevLanePosition;
							distanceOnBezier = Vector3.Distance(a, b);
						} else {*/
							// NON-STOCK CODE END //
							if ((byte)(nextDir & NetInfo.Direction.Forward) != 0) {
								a = instance.m_lanes.m_buffer[(int)((UIntPtr)curLaneId)].m_bezier.d;
							} else {
								a = instance.m_lanes.m_buffer[(int)((UIntPtr)curLaneId)].m_bezier.a;
							}
							b = prevLanePosition;
							distanceOnBezier = Vector3.Distance(a, b);

						// NON-STOCK CODE START //
						//}
						// NON-STOCK CODE END //

						//sCurrentState = 14;
						//sCurrentState = 15;
						/*if (targetNodeId == 17415) {*/
						//Log.Message($">> PF {this._pathFindIndex} -- Calculated distance: " + distanceOnBezier + " Original distance: " + Vector3.Distance(a1, b1) + " New distance: " + Vector3.Distance(a2, b2) + " next segment: " + segmentID + " from segment: " + item.m_position.m_segment + " a1: " + a1.ToString() + " b1: " + b1.ToString() + " a2: " + a2.ToString() + " b2: " + b2.ToString());
						/*}*/

#if DEBUGCOSTS
						if (costDebug)
							logBuf.Add($"ProcessItemCosts: costs from {nextSegmentId} (off {(byte)(((nextDir & NetInfo.Direction.Forward) == 0) ? 0 : 255)}) to {item.m_position.m_segment} (off {item.m_position.m_offset}), connectOffset={connectOffset}: distanceOnBezier={distanceOnBezier}");
#endif

						if (transitionNode) {
							distanceOnBezier *= 2f;
						}

						//sCurrentState = 16;
						float distanceOverMeanMaxSpeed = distanceOnBezier / ((prevMaxSpeed + nextMaxSpeed) * 0.5f * this._maxLength);
						BufferItem nextItem;
						nextItem.m_position.m_segment = nextSegmentId;
						nextItem.m_position.m_lane = (byte)laneIndex;
						nextItem.m_position.m_offset = (byte)(((nextDir & NetInfo.Direction.Forward) == 0) ? 0 : 255);
						if ((byte)(nextLane.m_laneType & laneType) == 0) {
							nextItem.m_methodDistance = 0f;
						} else {
							nextItem.m_methodDistance = prevMethodDist + distanceOnBezier;
						}

						if (nextLane.m_laneType != NetInfo.LaneType.Pedestrian || nextItem.m_methodDistance < 1000f) {
							//sCurrentState = 17;
							// NON-STOCK CODE START //
							// apply vehicle restrictions
							if (!addCustomTrafficCosts) {
								nextItem.m_comparisonValue = prevComparisonPlusOffsetCostOverSpeed + distanceOverMeanMaxSpeed;
							} else {
								nextItem.m_comparisonValue = item.m_comparisonValue;
								distanceOnBezier += prevOffsetCost;

								if (strictlyAvoidLane) {
									distanceOnBezier *= Options.someValue4;
								} else if (avoidLane && (_extVehicleType == null || (_extVehicleType & (ExtVehicleType.CargoTruck | ExtVehicleType.PassengerCar)) != ExtVehicleType.None)) {
									distanceOnBezier *= Options.someValue3;
								}

#if DEBUGCOSTS
								if (costDebug) {
									logBuf.Add($"Path from {nextSegmentId} (idx {laneIndex}, id {curLaneId}) to {item.m_position.m_segment} (lane {prevRightSimilarLaneIndex} from right, idx {item.m_position.m_lane}): useAdvancedAI={useAdvancedAI}, addCustomTrafficCosts={addCustomTrafficCosts}, distanceOnBezier={distanceOnBezier} avoidLane={avoidLane} strictlyAvoidLane={strictlyAvoidLane}");
								}
#endif
							}
							// NON-STOCK CODE END //
							nextItem.m_direction = nextDir;
							if (curLaneId == this._startLaneA) {
								if (((byte)(nextItem.m_direction & NetInfo.Direction.Forward) == 0 || nextItem.m_position.m_offset < this._startOffsetA) && ((byte)(nextItem.m_direction & NetInfo.Direction.Backward) == 0 || nextItem.m_position.m_offset > this._startOffsetA)) {
									curLaneId = instance.m_lanes.m_buffer[(int)((UIntPtr)curLaneId)].m_nextLane;
									//sCurrentState = 18;
									goto IL_90F;
								}
								float num15 = this.CalculateLaneSpeed(nextMaxSpeed, this._startOffsetA, nextItem.m_position.m_offset, ref nextSegment, nextLane); // NON-STOCK CODE
								float num16 = (float)Mathf.Abs((int)(nextItem.m_position.m_offset - this._startOffsetA)) * 0.003921569f;
								nextItem.m_comparisonValue += num16 * nextSegment.m_averageLength / (num15 * this._maxLength);
							}
							if (curLaneId == this._startLaneB) {
								if (((byte)(nextItem.m_direction & NetInfo.Direction.Forward) == 0 || nextItem.m_position.m_offset < this._startOffsetB) && ((byte)(nextItem.m_direction & NetInfo.Direction.Backward) == 0 || nextItem.m_position.m_offset > this._startOffsetB)) {
									curLaneId = instance.m_lanes.m_buffer[(int)((UIntPtr)curLaneId)].m_nextLane;
									//sCurrentState = 19;
									goto IL_90F;
								}
								float num17 = this.CalculateLaneSpeed(nextMaxSpeed, this._startOffsetB, nextItem.m_position.m_offset, ref nextSegment, nextLane); // NON-STOCK CODE
								float num18 = (float)Mathf.Abs((int)(nextItem.m_position.m_offset - this._startOffsetB)) * 0.003921569f;
								nextItem.m_comparisonValue += num18 * nextSegment.m_averageLength / (num17 * this._maxLength);
							}
							if (!this._ignoreBlocked && (nextSegment.m_flags & NetSegment.Flags.Blocked) != NetSegment.Flags.None && (byte)(nextLane.m_laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0) {
								if (addCustomTrafficCosts)
									distanceOnBezier *= 2f;
								else
									nextItem.m_comparisonValue += 0.1f;
								result = true;
							}
							//sCurrentState = 20;
							nextItem.m_lanesUsed = (item.m_lanesUsed | nextLane.m_laneType);
							nextItem.m_laneID = curLaneId;
							if ((byte)(nextLane.m_laneType & laneType) != 0 && nextLane.m_vehicleType == vehicleType) {
								// NON-STOCK CODE START //
								if (!addCustomTrafficCosts) {
									// NON-STOCK CODE END //
									int firstTarget = (int)instance.m_lanes.m_buffer[(int)((UIntPtr)curLaneId)].m_firstTarget;
									int lastTarget = (int)instance.m_lanes.m_buffer[(int)((UIntPtr)curLaneId)].m_lastTarget;
									if (laneIndexFromLeft < firstTarget || laneIndexFromLeft >= lastTarget) {
										nextItem.m_comparisonValue += Mathf.Max(1f, distanceOnBezier * 3f - 3f) / ((prevMaxSpeed + nextMaxSpeed) * 0.5f * this._maxLength);
									}
									if (!this._transportVehicle && nextLane.m_laneType == NetInfo.LaneType.TransportVehicle) {
										nextItem.m_comparisonValue += 20f / ((prevMaxSpeed + nextMaxSpeed) * 0.5f * this._maxLength);
									}
									// NON-STOCK CODE START //
								}
								// NON-STOCK CODE END //
							}
							//sCurrentState = 21;

							// NON-STOCK CODE START //
							bool addItem = true;
							if (addCustomTrafficCosts) {
								//sCurrentState = 22;
								int nextRightSimilarLaneIndex;
								if ((byte)(nextLane.m_direction & normDirection) != 0) {
									nextRightSimilarLaneIndex = nextLane.m_similarLaneIndex;
								} else {
									nextRightSimilarLaneIndex = nextLane.m_similarLaneCount - nextLane.m_similarLaneIndex - 1;
								}

								float laneDist = !isMiddle && nextSegmentId == item.m_position.m_segment ? Options.someValue2 : Convert.ToSingle(Math.Abs(nextRightSimilarLaneIndex - prevRightSimilarLaneIndex));

								if (forceLaneIndex == null && prevIsHighway && nextIsHighway && laneDist > 1) {
									goto IL_8F5;
								}

								if (strictlyAvoidLane) {
									nextSpeed = 0;
									nextDensity = 1;
								}

								float metric = 1f;
								float multMetric = 1f;
								float divMetric = nextMaxSpeed;
								float metricBeforeLanes = 1f;
								
								// vehicles should choose lanes with low traffic volume, but should neither change lanes too frequently nor change to too distant lanes.

								// calculate speed metric
								divMetric = nextSpeed * nextMaxSpeed; // 0 .. nextMaxSpeed

								// calculate density metric
								multMetric = Options.pathCostMultiplicator * nextDensity; // 1 .. pathCostMultiplicator

								// calculate metric
								metric = Math.Max(0.01f, multMetric) / Math.Max(0.1f, divMetric);
								metricBeforeLanes = metric;

								// multiply with lane distance
								float laneMetric = 1f;
								if ((forceLaneIndex == null || !isMiddle && nextSegmentId == item.m_position.m_segment) && _extVehicleType != ExtVehicleType.Emergency && (!wantToChangeLane || laneDist > 1)) {
									laneMetric = (float)Math.Pow(Options.someValue, laneDist);
									metric *= laneMetric;
								}
								
#if DEBUGCOSTS
								if (costDebug) {
									logBuf.Add($"Path from {nextSegmentId} (lane {nextRightSimilarLaneIndex} from right, idx {laneIndex}, id {curLaneId}) to {item.m_position.m_segment} (lane {prevRightSimilarLaneIndex} from right, idx {item.m_position.m_lane}): nextMaxSpeed={nextMaxSpeed} prevMaxSpeed={prevMaxSpeed} nextMaxSpeed={nextMaxSpeed} divMetric={divMetric} nextDensity={nextDensity} multMetric={multMetric} laneDist={laneDist} laneMetric={laneMetric} metric={metric} metricBeforeLanes={metricBeforeLanes} isMiddle={isMiddle}");
                                }
#endif

								//sCurrentState = 24;

								float oldDistanceOverMaxSpeed = distanceOverMeanMaxSpeed;
								distanceOverMeanMaxSpeed = (metric * distanceOnBezier) / this._maxLength;

#if DEBUG
								/*if ((segmentID == 25320 || segmentID == 31177) && Options.disableSomething1)
									Log._Debug($"Costs for lane {curLaneId} @ {segmentID}: prevSpeed={prevSpeed} nextSpeed={nextSpeed} prevDensity={prevDensity} nextDensity={nextDensity} divMetric={divMetric}, multMetric={multMetric} laneDist={laneDist} metric={metric} distanceOnBezier={distanceOnBezier} prevCost={item2.m_comparisonValue} newCost={distanceOnBezier+item2.m_comparisonValue}");*/
#endif

									if (distanceOverMeanMaxSpeed < 0f) {
#if DEBUG
									Log.Error($"THREAD #{Thread.CurrentThread.ManagedThreadId}, PF {this._pathFindIndex}: distanceOverMeanMaxSpeed < 0! seg. {nextSegmentId}, lane {laneIndex}, off {nextItem.m_position.m_offset} -> {item.m_position.m_segment}, lane {item.m_position.m_lane}, off {item.m_position.m_offset}. distanceOverMeanMaxSpeed={distanceOverMeanMaxSpeed}, nextSpeed={nextSpeed}, prevSpeed={prevSpeed}");
#endif
									distanceOverMeanMaxSpeed = 0f;
								} else if (Single.IsNaN(distanceOverMeanMaxSpeed) || Single.IsInfinity(distanceOverMeanMaxSpeed)) {
#if DEBUG
									//if (costDebug)
										Log.Error($"Pathfinder ({this._pathFindIndex}): distanceOverMeanMaxSpeed is NaN or Infinity: seg. {nextSegmentId}, lane {laneIndex}, off {nextItem.m_position.m_offset} -> {item.m_position.m_segment}, lane {item.m_position.m_lane}, off {item.m_position.m_offset}. {distanceOverMeanMaxSpeed} // nextMaxSpeed={nextMaxSpeed} prevMaxSpeed={prevMaxSpeed} nextMaxSpeed={nextMaxSpeed} divMetric={divMetric} nextDensity={nextDensity} multMetric={multMetric} laneDist={laneDist} laneMetric={laneMetric} metric={metric} metricBeforeLanes={metricBeforeLanes}");
#endif
#if DEBUGPF
									//Log.Error($"THREAD #{Thread.CurrentThread.ManagedThreadId}, PF {this._pathFindIndex}: distanceOverMeanMaxSpeed is NaN! distanceOverMeanMaxSpeed={distanceOverMeanMaxSpeed}, nextSpeed={nextSpeed}, prevSpeed={prevSpeed}");
#endif
									distanceOverMeanMaxSpeed = oldDistanceOverMaxSpeed;
								}
								//sCurrentState = 25;

#if DEBUGCOSTS
								if (costDebug) {
									logBuf.Add($"Path from {nextSegmentId} (lane {nextRightSimilarLaneIndex} from right, idx {laneIndex}) to {item.m_position.m_segment} (lane {prevRightSimilarLaneIndex} from right, idx {item.m_position.m_lane}.");
									//logBuf.Add($"distanceOverMeanMaxSpeed = {distanceOverMeanMaxSpeed} oldDistanceOverMaxSpeed = {oldDistanceOverMaxSpeed}, prevMaxSpeed={prevMaxSpeed}, nextMaxSpeed={nextMaxSpeed}, prevSpeed={prevSpeed}, nextSpeed={nextSpeed}");
									logBuf.Add($"distanceOverMeanMaxSpeed = {distanceOverMeanMaxSpeed} oldDistanceOverMaxSpeed = {oldDistanceOverMaxSpeed}, prevMaxSpeed={prevMaxSpeed}, nextMaxSpeed={nextMaxSpeed}, nextSpeed={nextSpeed} nextDensity={nextDensity}");
                                }
#endif

								nextItem.m_comparisonValue += distanceOverMeanMaxSpeed;
#if DEBUGCOSTS
								if (costDebug) {
									logBuf.Add($"Total cost = {distanceOverMeanMaxSpeed}, comparison value = {nextItem.m_comparisonValue}");
								}
#endif
#if DEBUGCOSTS
								if (costDebug) {
									foreach (String toLog in logBuf) {
										Log._Debug($"Pathfinder ({this._pathFindIndex}): " + toLog);
									}
								}
#endif

								//sCurrentState = 26;
								if (nextItem.m_comparisonValue < 0f) {
#if DEBUG
									Log.Error($"THREAD #{Thread.CurrentThread.ManagedThreadId}, PF {this._pathFindIndex}: Comparison value < 0! seg. {nextSegmentId}, lane {laneIndex}, off {nextItem.m_position.m_offset} -> {item.m_position.m_segment}, lane {item.m_position.m_lane}, off {item.m_position.m_offset}. distanceOverMeanMaxSpeed={distanceOverMeanMaxSpeed}, nextSpeed={nextSpeed}");
#endif
									nextItem.m_comparisonValue = 0f;
								} else if (nextItem.m_comparisonValue > 1f || Single.IsNaN(nextItem.m_comparisonValue) || Single.IsInfinity(nextItem.m_comparisonValue)) {
#if DEBUGPF
									if (debug)
										Log._Debug($"Pathfinder ({this._pathFindIndex}): comparisonValue is >1, NaN or Infinity: {nextItem.m_comparisonValue}. seg. {nextSegmentId}, lane {laneIndex}, off {nextItem.m_position.m_offset} -> {item.m_position.m_segment}, lane {item.m_position.m_lane}, off {item.m_position.m_offset}.");
#endif
#if DEBUG
									//Log.Error($"THREAD #{Thread.CurrentThread.ManagedThreadId}, PF {this._pathFindIndex}: Comparison value > 1, NaN or infinity! distanceOverMeanMaxSpeed={distanceOverMeanMaxSpeed}, nextSpeed={nextSpeed}, prevSpeed={prevSpeed}");
#endif
									addItem = false;
								}
								//sCurrentState = 27;
#if DEBUGPF
								if (debug) {
									//Log.Message($">> PF {this._pathFindIndex} -- seg {item2.m_position.m_segment}, lane {item2.m_position.m_lane} (idx {item2.m_laneID}), off {item2.m_position.m_offset}, cost {item2.m_comparisonValue}, totalCost {totalCost} = traffic={trafficCost}, junction={junctionCost}, lane={laneChangeCost}");
								}
#endif
							}
							//sCurrentState = 28;

							if (forceLaneIndex != null && laneIndex == forceLaneIndex && addItem) {
								foundForced = true;
							}

							/*if (addCustomCosts && ((item.m_position.m_segment == 2062 && item2.m_position.m_segment == 23640) || (item.m_position.m_segment == 23640 && item2.m_position.m_segment == 29505) || (item.m_position.m_segment == 29505 && item2.m_position.m_segment == 24975) || (item.m_position.m_segment == 24975 && item2.m_position.m_segment == 9535) || (item.m_position.m_segment == 9535 && item2.m_position.m_segment == 20914) || (item.m_position.m_segment == 20914 && item2.m_position.m_segment == 21545))) {
								Log.Message($">> PF {this._pathFindIndex} -- Adding item: seg {item2.m_position.m_segment}, lane {item2.m_position.m_lane} (idx {item2.m_laneID}), off {item2.m_position.m_offset} -> seg {item.m_position.m_segment}, lane {item.m_position.m_lane} (idx {item.m_laneID}), off {item.m_position.m_offset}, cost {item2.m_comparisonValue}, methodDist {item2.m_methodDistance}");
							}*/

							// NON-STOCK CODE END //

							if (addItem) {
#if DEBUGPF
								if (debug)
									Log._Debug($">> PF {this._pathFindIndex} -- Adding item: seg {nextItem.m_position.m_segment}, lane {nextItem.m_position.m_lane} (idx {nextItem.m_laneID}), off {nextItem.m_position.m_offset} -> seg {item.m_position.m_segment}, lane {item.m_position.m_lane} (idx {item.m_laneID}), off {item.m_position.m_offset}, cost {nextItem.m_comparisonValue}, previous cost {item.m_comparisonValue}, methodDist {nextItem.m_methodDistance}");
#endif
								//sCurrentState = 29;
								this.AddBufferItem(nextItem, item.m_position);
								//sCurrentState = 30;
							} else {
								//sCurrentState = 31;
#if DEBUGPF
								if (debug)
									Log._Debug($">> PF {this._pathFindIndex} -- NOT adding item");
#endif
							}
							//sCurrentState = 32;
						}
						//sCurrentState = 33;
					}
					//sCurrentState = 34;
					goto IL_8F5;
				}
				//sCurrentState = 35;
				if ((byte)(nextLane.m_laneType & laneType) != 0 && (nextLane.m_vehicleType & vehicleType) != VehicleInfo.VehicleType.None) {
					newLaneIndexFromLeft++;
					goto IL_8F5;
				}
				//sCurrentState = 36;
				goto IL_8F5;
				IL_90F:
				//sCurrentState = 37;
				laneIndex++;
				continue;
				IL_8F5:
				//sCurrentState = 38;
				curLaneId = instance.m_lanes.m_buffer[(int)((UIntPtr)curLaneId)].m_nextLane;
				goto IL_90F;
			} // foreach lane
			//sCurrentState = 39;
			laneIndexFromLeft = newLaneIndexFromLeft;
			return result;
		}
        private osmWay AddWay(int i, NetSegment netSegment)
        {
            var nm = Singleton<NetManager>.instance;
            if (netSegment.m_startNode == 0 || netSegment.m_endNode == 0)
            {
                return null;
            }
            var startNode = netSegment.m_startNode;
            var endNode = netSegment.m_endNode;
            var startDirection = netSegment.m_startDirection;
            var endDirection = netSegment.m_endDirection;

            if ((netSegment.m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None)
            {
                startNode = netSegment.m_endNode;
                endNode = netSegment.m_startNode;
                startDirection = netSegment.m_endDirection;
                endDirection = netSegment.m_startDirection;
            }
            osmWayND[] nd;
            if (Vector3.Angle(startDirection, -endDirection) > 3f)
            {
                var start = nm.m_nodes.m_buffer[startNode].m_position;
                var end = nm.m_nodes.m_buffer[endNode].m_position;
                Vector3 a = Vector3.zero;
                Vector3 b = Vector3.zero;
                NetSegment.CalculateMiddlePoints(start, startDirection, end, endDirection, false, false, out a, out b);

                var bezier = new Bezier3(start, a, b, end);

                nd = new osmWayND[5];
                nd[0] = new osmWayND { @ref = startNode };
                nd[1] = new osmWayND { @ref = AddNode(bezier.Position(0.25f)) };
                nd[2] = new osmWayND { @ref = AddNode(bezier.Position(0.5f)) };
                nd[3] = new osmWayND { @ref = AddNode(bezier.Position(0.75f)) };
                nd[4] = new osmWayND { @ref = endNode };
            }
            else
            {
                nd = new osmWayND[2];
                nd[0] = new osmWayND { @ref = startNode };
                nd[1] = new osmWayND { @ref = endNode };
            }

            byte elevation = (byte)(Mathf.Clamp((nm.m_nodes.m_buffer[startNode].m_elevation + nm.m_nodes.m_buffer[endNode].m_elevation) / 2, 0, 255));
            var tags = new List<osmWayTag>();
            if (!mapping.GetTags(elevation, netSegment, tags))
            {
                return null;
            }
            return new osmWay { changeset = 50000000, id = (uint)i, timestamp = DateTime.Now, user = "******", version = 1, nd = nd, tag = tags.ToArray() };
        }
		// 4
		private void ProcessItemPedBicycle(BufferItem item, ushort targetNodeId, ushort segmentID, ref NetSegment segment, byte connectOffset, int laneIndex, uint lane) {
			if ((segment.m_flags & (NetSegment.Flags.PathFailed | NetSegment.Flags.Flooded)) != NetSegment.Flags.None) {
				return;
			}
			NetManager instance = Singleton<NetManager>.instance;
			NetInfo info = segment.Info;
			NetInfo info2 = instance.m_segments.m_buffer[(int)item.m_position.m_segment].Info;
			int num = info.m_lanes.Length;
			float num2;
			byte offset;
			if (segmentID == item.m_position.m_segment) {
				Vector3 b = instance.m_lanes.m_buffer[(int)((UIntPtr)item.m_laneID)].CalculatePosition((float)connectOffset * 0.003921569f);
				Vector3 a = instance.m_lanes.m_buffer[(int)((UIntPtr)lane)].CalculatePosition((float)connectOffset * 0.003921569f);
				num2 = Vector3.Distance(a, b);
				offset = connectOffset;
			} else {
				NetInfo.Direction direction = (targetNodeId != segment.m_startNode) ? NetInfo.Direction.Forward : NetInfo.Direction.Backward;
				Vector3 b2 = instance.m_lanes.m_buffer[(int)((UIntPtr)item.m_laneID)].CalculatePosition((float)connectOffset * 0.003921569f);
				Vector3 a2;
				if ((byte)(direction & NetInfo.Direction.Forward) != 0) {
					a2 = instance.m_lanes.m_buffer[(int)((UIntPtr)lane)].m_bezier.d;
				} else {
					a2 = instance.m_lanes.m_buffer[(int)((UIntPtr)lane)].m_bezier.a;
				}
				num2 = Vector3.Distance(a2, b2);
				offset = (byte)(((direction & NetInfo.Direction.Forward) == 0) ? 0 : 255);
			}
			float prevMaxSpeed = 1f;
			float num4 = 1f;
			NetInfo.LaneType laneType = NetInfo.LaneType.None;
			if ((int)item.m_position.m_lane < info2.m_lanes.Length) {
				NetInfo.Lane lane2 = info2.m_lanes[(int)item.m_position.m_lane];
				prevMaxSpeed = GetLaneSpeedLimit(item.m_position.m_segment, item.m_position.m_lane, item.m_laneID, lane2); // SpeedLimitManager.GetLockFreeGameSpeedLimit(item.m_position.m_segment, item.m_position.m_lane, item.m_laneID, ref lane2); // NON-STOCK CODE
				laneType = lane2.m_laneType;
				if ((byte)(laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0) {
					laneType = (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle);
				}
				num4 = this.CalculateLaneSpeed(prevMaxSpeed, connectOffset, item.m_position.m_offset, ref instance.m_segments.m_buffer[(int)item.m_position.m_segment], lane2); // NON-STOCK CODE
			}
			float averageLength = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_averageLength;
			float num5 = (float)Mathf.Abs((int)(connectOffset - item.m_position.m_offset)) * 0.003921569f * averageLength;
			float num6 = item.m_methodDistance + num5;
			float num7 = item.m_comparisonValue + num5 / (num4 * this._maxLength);
			// NON-STOCK CODE START //
			bool nextIsJunction = instance.m_nodes.m_buffer[targetNodeId].CountSegments() > 2;
			ushort sourceNodeId = (targetNodeId == instance.m_segments.m_buffer[item.m_position.m_segment].m_startNode) ? instance.m_segments.m_buffer[item.m_position.m_segment].m_endNode : instance.m_segments.m_buffer[item.m_position.m_segment].m_startNode; // no lane changing directly in front of a junction
			bool prevIsJunction = instance.m_nodes.m_buffer[sourceNodeId].CountSegments() > 2;
			// NON-STOCK CODE END //
			if (laneIndex < num) {
				NetInfo.Lane lane3 = info.m_lanes[laneIndex];
				BufferItem item2;
				item2.m_position.m_segment = segmentID;
				item2.m_position.m_lane = (byte)laneIndex;
				item2.m_position.m_offset = offset;
				if ((byte)(lane3.m_laneType & laneType) == 0) {
					item2.m_methodDistance = 0f;
				} else {
					if (item.m_methodDistance == 0f) {
						num7 += 100f / (0.25f * this._maxLength);
					}
					item2.m_methodDistance = num6 + num2;
				}
				float nextMaxSpeed = GetLaneSpeedLimit(segmentID, (uint)laneIndex, lane, lane3); // SpeedLimitManager.GetLockFreeGameSpeedLimit(segmentID, (uint)laneIndex, lane, ref lane3); // NON-STOCK CODE
				if (lane3.m_laneType != NetInfo.LaneType.Pedestrian || item2.m_methodDistance < 1000f) {
					item2.m_comparisonValue = num7 + num2 / ((prevMaxSpeed + nextMaxSpeed) * 0.25f * this._maxLength); // NON-STOCK CODE
					if ((segment.m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) {
						item2.m_direction = NetInfo.InvertDirection(lane3.m_finalDirection);
					} else {
						item2.m_direction = lane3.m_finalDirection;
					}
					if (lane == this._startLaneA) {
						if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this._startOffsetA) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this._startOffsetA)) {
							return;
						}
						float num8 = this.CalculateLaneSpeed(nextMaxSpeed, this._startOffsetA, item2.m_position.m_offset, ref segment, lane3); // NON-STOCK CODE
						float num9 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this._startOffsetA)) * 0.003921569f;
						item2.m_comparisonValue += num9 * segment.m_averageLength / (num8 * this._maxLength);
					}
					if (lane == this._startLaneB) {
						if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this._startOffsetB) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this._startOffsetB)) {
							return;
						}
						float num10 = this.CalculateLaneSpeed(nextMaxSpeed, this._startOffsetB, item2.m_position.m_offset, ref segment, lane3); // NON-STOCK CODE
						float num11 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this._startOffsetB)) * 0.003921569f;
						item2.m_comparisonValue += num11 * segment.m_averageLength / (num10 * this._maxLength);
					}
					item2.m_laneID = lane;
					item2.m_lanesUsed = (item.m_lanesUsed | lane3.m_laneType);
					this.AddBufferItem(item2, item.m_position);
				}
			}
		}
Beispiel #47
0
		private bool ProcessItem(CustomPathFind.BufferItem item, ushort targetNode, ushort segmentID, ref NetSegment segment, ref int currentTargetIndex, byte connectOffset, bool enableVehicle, bool enablePedestrian)
		{
			bool result = false;
			if ((segment.m_flags & (NetSegment.Flags.PathFailed | NetSegment.Flags.Flooded)) != NetSegment.Flags.None)
			{
				return result;
			}
			NetManager instance = Singleton<NetManager>.instance;
			NetInfo info = segment.Info;
			NetInfo info2 = instance.m_segments.m_buffer[(int)item.m_position.m_segment].Info;
			int num = info.m_lanes.Length;
			uint num2 = segment.m_lanes;
			NetInfo.Direction direction = (targetNode != segment.m_startNode) ? NetInfo.Direction.Forward : NetInfo.Direction.Backward;
			NetInfo.Direction direction2 = ((segment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? direction : NetInfo.InvertDirection(direction);
			float num3 = 0.01f - Mathf.Min(info.m_maxTurnAngleCos, info2.m_maxTurnAngleCos);
			if (num3 < 1f)
			{
				Vector3 vector;
				if (targetNode == instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_startNode)
				{
					vector = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_startDirection;
				}
				else
				{
					vector = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_endDirection;
				}
				Vector3 vector2;
				if ((byte)(direction & NetInfo.Direction.Forward) != 0)
				{
					vector2 = segment.m_endDirection;
				}
				else
				{
					vector2 = segment.m_startDirection;
				}
				float num4 = vector.x * vector2.x + vector.z * vector2.z;
				if (num4 >= num3)
				{
					return result;
				}
			}
			float num5 = 1f;
			float num6 = 1f;
			NetInfo.LaneType laneType = NetInfo.LaneType.None;
			VehicleInfo.VehicleType vehicleType = VehicleInfo.VehicleType.None;
			if ((int)item.m_position.m_lane < info2.m_lanes.Length)
			{
				uint l = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_lanes;
				for (int n = 0; l != 0 && n < (int)item.m_position.m_lane; ++n)
					l = instance.m_lanes.m_buffer[l].m_nextLane;

				NetInfo.Lane lane = info2.m_lanes[(int)item.m_position.m_lane];
				laneType = lane.m_laneType;
				vehicleType = lane.m_vehicleType;
				//num5 = lane.m_speedLimit;
				//num6 = this.CalculateLaneSpeed(connectOffset, item.m_position.m_offset, ref instance.m_segments.m_buffer[(int)item.m_position.m_segment], lane, 0);
				num5 = RoadManager.GetLaneSpeed(l);
				num6 = this.CalculateLaneSpeed(connectOffset, item.m_position.m_offset, ref instance.m_segments.m_buffer[(int)item.m_position.m_segment], lane, l);
			}
			float num7 = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_averageLength;
			if (!this.m_stablePath)
			{
				Randomizer randomizer = new Randomizer(this.m_pathFindIndex << 16 | (uint)item.m_position.m_segment);
				num7 *= (float)(randomizer.Int32(900, 1000 + (int)(instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_trafficDensity * 10)) + this.m_pathRandomizer.Int32(20u)) * 0.001f;
			}
			if (this.m_isHeavyVehicle && (instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_flags & NetSegment.Flags.HeavyBan) != NetSegment.Flags.None)
			{
				num7 *= 10f;
			}
            else if (laneType == NetInfo.LaneType.Vehicle && vehicleType == VehicleInfo.VehicleType.Car && (instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_flags & NetSegment.Flags.CarBan) != NetSegment.Flags.None)
            {
                num7 *= 5f;
            }
            if (this.m_transportVehicle && laneType == NetInfo.LaneType.TransportVehicle)
            {
                num7 *= 0.95f;
            }
            if ((byte)(laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0)
            {
                laneType = (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle);
            }
			float num8 = (float)Mathf.Abs((int)(connectOffset - item.m_position.m_offset)) * 0.003921569f * num7;
			float num9 = item.m_methodDistance + num8;
			float num10 = item.m_comparisonValue + num8 / (num6 * this.m_maxLength);
			Vector3 b = instance.m_lanes.m_buffer[(int)((UIntPtr)item.m_laneID)].CalculatePosition((float)connectOffset * 0.003921569f);
			int num11 = currentTargetIndex;
			bool flag = (instance.m_nodes.m_buffer[(int)targetNode].m_flags & NetNode.Flags.Transition) != NetNode.Flags.None;
			NetInfo.LaneType laneType2 = this.m_laneTypes;
			VehicleInfo.VehicleType vehicleType2 = this.m_vehicleTypes;
			if (!enableVehicle)
			{
				vehicleType2 &= VehicleInfo.VehicleType.Bicycle;
				if (vehicleType2 == VehicleInfo.VehicleType.None)
				{
                    laneType2 &= ~(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle);
				}
			}
			if (!enablePedestrian)
			{
				laneType2 &= ~NetInfo.LaneType.Pedestrian;
			}
			int num12 = 0;
			while (num12 < num && num2 != 0u)
			{
				NetInfo.Lane lane2 = info.m_lanes[num12];
				if ((byte)(lane2.m_finalDirection & direction2) != 0 && RoadManager.CheckLaneConnection(num2, item.m_laneID) && RoadManager.CanUseLane(this.m_vehicleType, num2) && RoadManager.CanUseLane(this.m_vehicleType, item.m_laneID))
				{
					if (lane2.CheckType(laneType2, vehicleType2) && (segmentID != item.m_position.m_segment || num12 != (int)item.m_position.m_lane) && (byte)(lane2.m_finalDirection & direction2) != 0)
					{
						Vector3 a;
						if ((byte)(direction & NetInfo.Direction.Forward) != 0)
						{
							a = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_bezier.d;
						}
						else
						{
							a = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_bezier.a;
						}
						float num13 = Vector3.Distance(a, b);
						if (flag)
						{
							num13 *= 2f;
						}
                        if ((CSLTraffic.Options & OptionsManager.ModOptions.ImprovedAI) == OptionsManager.ModOptions.ImprovedAI)
                        {
                            /* ----- Congestion Changes ----- */
                            // Checks if the lane has space for a vehicle of length 5. If not, increase its cost to avoid it. 
                            if (!instance.m_lanes.m_buffer[num2].CheckSpace(5)) // the length used here can be tweaked for different results. Haven't had time to test it yet
                            {
                                num13 *= 3f; // the factor of cost increase can also be tweaked to achieve different results
                            }
                        }
                        /* ------------------------------ */
                        if (this.m_prioritizeBusLanes)
						{
							NetInfoLane customLane2 = lane2 as NetInfoLane;
							if (customLane2 != null && customLane2.m_specialLaneType == NetInfoLane.SpecialLaneType.BusLane)
							{
								num13 /= 10f;
							}
						}
						float num14 = num13 / ((num5 + RoadManager.GetLaneSpeed(num2) /*lane2.m_speedLimit*/) * 0.5f * this.m_maxLength);
						CustomPathFind.BufferItem item2;
						item2.m_position.m_segment = segmentID;
						item2.m_position.m_lane = (byte)num12;
						item2.m_position.m_offset = (byte)(((direction & NetInfo.Direction.Forward) == 0) ? 0 : 255);
                        if ((byte)(lane2.m_laneType & laneType) == 0)
						{
							item2.m_methodDistance = 0f;
						}
						else
						{
							item2.m_methodDistance = num9 + num13;
						}
						if (lane2.m_laneType != NetInfo.LaneType.Pedestrian || item2.m_methodDistance < 1000f)
						{
							item2.m_comparisonValue = num10 + num14;
                            item2.m_direction = direction;
                            if (num2 == this.m_startLaneA)
							{
                                if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this.m_startOffsetA) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this.m_startOffsetA))
                                {
                                    num2 = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_nextLane;
                                    num12++;
                                    continue;
                                }
                                float num15 = this.CalculateLaneSpeed(this.m_startOffsetA, item2.m_position.m_offset, ref segment, lane2, num2);
								float num16 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this.m_startOffsetA)) * 0.003921569f;
								item2.m_comparisonValue += num16 * segment.m_averageLength / (num15 * this.m_maxLength);
							}
							if (num2 == this.m_startLaneB)
							{
                                if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this.m_startOffsetB) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this.m_startOffsetB))
                                {
                                    num2 = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_nextLane;
                                    num12++;
                                    continue;
                                }
                                float num17 = this.CalculateLaneSpeed(this.m_startOffsetB, item2.m_position.m_offset, ref segment, lane2, num2);
								float num18 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this.m_startOffsetB)) * 0.003921569f;
								item2.m_comparisonValue += num18 * segment.m_averageLength / (num17 * this.m_maxLength);
							}
                            if (!this.m_ignoreBlocked && (segment.m_flags & NetSegment.Flags.Blocked) != NetSegment.Flags.None && (byte)(lane2.m_laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0)
							{
								item2.m_comparisonValue += 0.1f;
								result = true;
							}
							item2.m_lanesUsed = (item.m_lanesUsed | lane2.m_laneType);
							item2.m_laneID = num2;
                            if ((byte)(lane2.m_laneType & laneType) != 0 && lane2.m_vehicleType == vehicleType)
							{
								int firstTarget = (int)instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_firstTarget;
								int lastTarget = (int)instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_lastTarget;
								if (currentTargetIndex < firstTarget || currentTargetIndex >= lastTarget)
								{
									item2.m_comparisonValue += Mathf.Max(1f, num13 * 3f - 3f) / ((num5 + RoadManager.GetLaneSpeed(num2)/* lane2.m_speedLimit*/) * 0.5f * this.m_maxLength);
								}
                                if (!this.m_transportVehicle && lane2.m_laneType == NetInfo.LaneType.TransportVehicle)
                                {
                                    item2.m_comparisonValue += 20f / ((num5 + lane2.m_speedLimit) * 0.5f * this.m_maxLength);
                                }
							}
							this.AddBufferItem(item2, item.m_position);
						}
					}
                    num2 = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_nextLane;
                    num12++;
                    continue;
                }
                if ((byte)(lane2.m_laneType & laneType) != 0 && lane2.m_vehicleType == vehicleType)
                {
                    num11++;
                }
                num2 = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_nextLane;
                num12++;
			}
			currentTargetIndex = num11;
			return result;
		}
Beispiel #48
0
        /// <summary>
        /// Returns a list of tags associated with the NetSegment passed in
        /// </summary>
        /// <param name="segment">The segment to generate tags for</param>
        /// <param name="wayTags">The tags associated with the segment</param>
        /// <returns>Whether any tags were found</returns>
        public static bool CreateWayTags(NetSegment segment, out List<OSMWayTag> wayTags)
        {
            wayTags = new List<OSMWayTag>();

            bool success = false;
            string segmentName = segment.Info.name;

            foreach(RoadContainer road in RoadManager.GetAllRoadTypes())
            {
                if(road.RoadNameMatches(segmentName))
                {
                    wayTags.AddRange(road.tags);
                    success = true;
                }
            }

            if(success)
            {
                wayTags.AddRange(AddExtendedWayTags(segment));
            }

            return success;
        }
 public static new bool StartPathFind(ushort segmentID, ref NetSegment data, ItemClass.Service netService, VehicleInfo.VehicleType vehicleType, bool skipQueue)
 {
     if (data.m_path != 0u)
     {
         Singleton<PathManager>.instance.ReleasePath(data.m_path);
         data.m_path = 0u;
     }
     NetManager instance = Singleton<NetManager>.instance;
     if ((instance.m_nodes.m_buffer[(int)data.m_startNode].m_flags & NetNode.Flags.Ambiguous) != NetNode.Flags.None)
     {
         for (int i = 0; i < 8; i++)
         {
             ushort segment = instance.m_nodes.m_buffer[(int)data.m_startNode].GetSegment(i);
             if (segment != 0 && segment != segmentID && instance.m_segments.m_buffer[(int)segment].m_path != 0u)
             {
                 return true;
             }
         }
     }
     if ((instance.m_nodes.m_buffer[(int)data.m_endNode].m_flags & NetNode.Flags.Ambiguous) != NetNode.Flags.None)
     {
         for (int j = 0; j < 8; j++)
         {
             ushort segment2 = instance.m_nodes.m_buffer[(int)data.m_endNode].GetSegment(j);
             if (segment2 != 0 && segment2 != segmentID && instance.m_segments.m_buffer[(int)segment2].m_path != 0u)
             {
                 return true;
             }
         }
     }
     Vector3 position = instance.m_nodes.m_buffer[(int)data.m_startNode].m_position;
     Vector3 position2 = instance.m_nodes.m_buffer[(int)data.m_endNode].m_position;
     PathUnit.Position startPosA;
     PathUnit.Position startPosB;
     float num;
     float num2;
     if (!PathManager.FindPathPosition(position, netService, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, true, false, 32f, out startPosA, out startPosB, out num, out num2))
     {
         return true;
     }
     PathUnit.Position endPosA;
     PathUnit.Position endPosB;
     float num3;
     float num4;
     if (!PathManager.FindPathPosition(position2, netService, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, true, false, 32f, out endPosA, out endPosB, out num3, out num4))
     {
         return true;
     }
     if ((instance.m_nodes.m_buffer[(int)data.m_startNode].m_flags & NetNode.Flags.Fixed) != NetNode.Flags.None)
     {
         startPosB = default(PathUnit.Position);
     }
     if ((instance.m_nodes.m_buffer[(int)data.m_endNode].m_flags & NetNode.Flags.Fixed) != NetNode.Flags.None)
     {
         endPosB = default(PathUnit.Position);
     }
     startPosA.m_offset = 128;
     startPosB.m_offset = 128;
     endPosA.m_offset = 128;
     endPosB.m_offset = 128;
     bool stopLane = BusTransportLineAI.GetStopLane(ref startPosA, vehicleType);
     bool stopLane2 = BusTransportLineAI.GetStopLane(ref startPosB, vehicleType);
     bool stopLane3 = BusTransportLineAI.GetStopLane(ref endPosA, vehicleType);
     bool stopLane4 = BusTransportLineAI.GetStopLane(ref endPosB, vehicleType);
     if ((!stopLane && !stopLane2) || (!stopLane3 && !stopLane4))
     {
         return true;
     }
     uint path;
     bool createPathResult;
     CustomPathManager customPathManager = Singleton<PathManager>.instance as CustomPathManager;
     if (customPathManager != null)
         createPathResult = customPathManager.CreatePath(out path, ref Singleton<SimulationManager>.instance.m_randomizer, Singleton<SimulationManager>.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, vehicleType, 20000f, false, true, true, skipQueue, RoadManager.VehicleType.Bus);
     else
         createPathResult = Singleton<PathManager>.instance.CreatePath(out path, ref Singleton<SimulationManager>.instance.m_randomizer, Singleton<SimulationManager>.instance.m_currentBuildIndex, startPosA, startPosB, endPosA, endPosB, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, vehicleType, 20000f, false, true, true, skipQueue);
     if (createPathResult)
     {
         if (startPosA.m_segment != 0 && startPosB.m_segment != 0)
         {
             NetNode[] expr_2D9_cp_0 = instance.m_nodes.m_buffer;
             ushort expr_2D9_cp_1 = data.m_startNode;
             expr_2D9_cp_0[(int)expr_2D9_cp_1].m_flags = (expr_2D9_cp_0[(int)expr_2D9_cp_1].m_flags | NetNode.Flags.Ambiguous);
         }
         else
         {
             NetNode[] expr_305_cp_0 = instance.m_nodes.m_buffer;
             ushort expr_305_cp_1 = data.m_startNode;
             expr_305_cp_0[(int)expr_305_cp_1].m_flags = (expr_305_cp_0[(int)expr_305_cp_1].m_flags & ~NetNode.Flags.Ambiguous);
         }
         if (endPosA.m_segment != 0 && endPosB.m_segment != 0)
         {
             NetNode[] expr_344_cp_0 = instance.m_nodes.m_buffer;
             ushort expr_344_cp_1 = data.m_endNode;
             expr_344_cp_0[(int)expr_344_cp_1].m_flags = (expr_344_cp_0[(int)expr_344_cp_1].m_flags | NetNode.Flags.Ambiguous);
         }
         else
         {
             NetNode[] expr_370_cp_0 = instance.m_nodes.m_buffer;
             ushort expr_370_cp_1 = data.m_endNode;
             expr_370_cp_0[(int)expr_370_cp_1].m_flags = (expr_370_cp_0[(int)expr_370_cp_1].m_flags & ~NetNode.Flags.Ambiguous);
         }
         data.m_path = path;
         data.m_flags |= NetSegment.Flags.WaitingPath;
         return false;
     }
     return true;
 }
 protected virtual float CalculateLaneSpeed(byte startOffset, byte endOffset, ref NetSegment segment, NetInfo.Lane laneInfo)
 {
     NetInfo.Direction direction = ((segment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? laneInfo.m_finalDirection : NetInfo.InvertDirection(laneInfo.m_finalDirection);
     if ((byte)(direction & NetInfo.Direction.Avoid) == 0)
     {
         return laneInfo.m_speedLimit;
     }
     if (endOffset > startOffset && direction == NetInfo.Direction.AvoidForward)
     {
         return laneInfo.m_speedLimit * 0.1f;
     }
     if (endOffset < startOffset && direction == NetInfo.Direction.AvoidBackward)
     {
         return laneInfo.m_speedLimit * 0.1f;
     }
     return laneInfo.m_speedLimit * 0.2f;
 }
            void SetDefaultArrows(ushort seg, ref NetSegment segment)
            {
                NetInfo info = segment.Info;
                info.m_netAI.UpdateLanes(seg, ref segment, false);

                uint laneId = segment.m_lanes;
                int laneCount = info.m_lanes.Length;
                for (int laneIndex = 0; laneIndex < laneCount && laneId != 0; laneIndex++)
                {
                    if (laneId != m_laneId && RoadManager.sm_lanes[laneId] != null && RoadManager.sm_lanes[laneId].ConnectionCount() > 0)
                        RoadManager.sm_lanes[laneId].UpdateArrows();

                    laneId = NetManager.instance.m_lanes.m_buffer[laneId].m_nextLane;
                }
            }
 protected virtual void ProcessItem(BufferItem item, ushort targetNode, bool targetDisabled, ushort segmentID, ref NetSegment segment, uint lane, byte offset, byte connectOffset)
 {
     if ((segment.m_flags & (NetSegment.Flags.PathFailed | NetSegment.Flags.Flooded)) != NetSegment.Flags.None)
     {
         return;
     }
     NetManager instance = Singleton<NetManager>.instance;
     if (targetDisabled && ((instance.m_nodes.m_buffer[(int)segment.m_startNode].m_flags | instance.m_nodes.m_buffer[(int)segment.m_endNode].m_flags) & NetNode.Flags.Disabled) == NetNode.Flags.None)
     {
         return;
     }
     NetInfo info = segment.Info;
     NetInfo info2 = instance.m_segments.m_buffer[(int)item.m_position.m_segment].Info;
     int num = info.m_lanes.Length;
     uint num2 = segment.m_lanes;
     float num3 = 1f;
     float num4 = 1f;
     NetInfo.LaneType laneType = NetInfo.LaneType.None;
     if ((int)item.m_position.m_lane < info2.m_lanes.Length)
     {
         NetInfo.Lane lane2 = info2.m_lanes[(int)item.m_position.m_lane];
         num3 = lane2.m_speedLimit;
         laneType = lane2.m_laneType;
         if ((byte)(laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0)
         {
             laneType = (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle);
         }
         num4 = this.CalculateLaneSpeed(connectOffset, item.m_position.m_offset, ref instance.m_segments.m_buffer[(int)item.m_position.m_segment], lane2);
     }
     float averageLength = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_averageLength;
     float num5 = (float)Mathf.Abs((int)(connectOffset - item.m_position.m_offset)) * 0.003921569f * averageLength;
     float num6 = item.m_methodDistance + num5;
     float num7 = item.m_comparisonValue + num5 / (num4 * this.m_maxLength);
     Vector3 b = instance.m_lanes.m_buffer[(int)((UIntPtr)item.m_laneID)].CalculatePosition((float)connectOffset * 0.003921569f);
     int num8 = 0;
     while (num8 < num && num2 != 0u)
     {
         if (lane == num2)
         {
             NetInfo.Lane lane3 = info.m_lanes[num8];
             if (lane3.CheckType(this.m_laneTypes, this.m_vehicleTypes))
             {
                 Vector3 a = instance.m_lanes.m_buffer[(int)((UIntPtr)lane)].CalculatePosition((float)offset * 0.003921569f);
                 float num9 = Vector3.Distance(a, b);
                 BufferItem item2;
                 item2.m_position.m_segment = segmentID;
                 item2.m_position.m_lane = (byte)num8;
                 item2.m_position.m_offset = offset;
                 if ((byte)(lane3.m_laneType & laneType) == 0)
                 {
                     item2.m_methodDistance = 0f;
                 }
                 else
                 {
                     item2.m_methodDistance = num6 + num9;
                 }
                 if (lane3.m_laneType != NetInfo.LaneType.Pedestrian || item2.m_methodDistance < 1000f)
                 {
                     item2.m_comparisonValue = num7 + num9 / ((num3 + lane3.m_speedLimit) * 0.5f * this.m_maxLength);
                     if ((segment.m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None)
                     {
                         item2.m_direction = NetInfo.InvertDirection(lane3.m_finalDirection);
                     }
                     else
                     {
                         item2.m_direction = lane3.m_finalDirection;
                     }
                     if (lane == this.m_startLaneA)
                     {
                         if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this.m_startOffsetA) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this.m_startOffsetA))
                         {
                             return;
                         }
                         float num10 = this.CalculateLaneSpeed(this.m_startOffsetA, item2.m_position.m_offset, ref segment, lane3);
                         float num11 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this.m_startOffsetA)) * 0.003921569f;
                         item2.m_comparisonValue += num11 * segment.m_averageLength / (num10 * this.m_maxLength);
                     }
                     if (lane == this.m_startLaneB)
                     {
                         if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this.m_startOffsetB) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this.m_startOffsetB))
                         {
                             return;
                         }
                         float num12 = this.CalculateLaneSpeed(this.m_startOffsetB, item2.m_position.m_offset, ref segment, lane3);
                         float num13 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this.m_startOffsetB)) * 0.003921569f;
                         item2.m_comparisonValue += num13 * segment.m_averageLength / (num12 * this.m_maxLength);
                     }
                     item2.m_laneID = lane;
                     item2.m_lanesUsed = (item.m_lanesUsed | lane3.m_laneType);
                     this.AddBufferItem(item2, item.m_position);
                 }
             }
             return;
         }
         num2 = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_nextLane;
         num8++;
     }
 }
 protected virtual bool ProcessItem(BufferItem item, ushort targetNode, ushort segmentID, ref NetSegment segment, ref int currentTargetIndex, byte connectOffset, bool enableVehicle, bool enablePedestrian)
 {
     bool result = false;
     if ((segment.m_flags & (NetSegment.Flags.PathFailed | NetSegment.Flags.Flooded)) != NetSegment.Flags.None)
     {
         return result;
     }
     NetManager instance = Singleton<NetManager>.instance;
     NetInfo info = segment.Info;
     NetInfo info2 = instance.m_segments.m_buffer[(int)item.m_position.m_segment].Info;
     int num = info.m_lanes.Length;
     uint num2 = segment.m_lanes;
     NetInfo.Direction direction = (targetNode != segment.m_startNode) ? NetInfo.Direction.Forward : NetInfo.Direction.Backward;
     NetInfo.Direction direction2 = ((segment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? direction : NetInfo.InvertDirection(direction);
     float num3 = 0.01f - Mathf.Min(info.m_maxTurnAngleCos, info2.m_maxTurnAngleCos);
     if (num3 < 1f)
     {
         Vector3 vector;
         if (targetNode == instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_startNode)
         {
             vector = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_startDirection;
         }
         else
         {
             vector = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_endDirection;
         }
         Vector3 vector2;
         if ((byte)(direction & NetInfo.Direction.Forward) != 0)
         {
             vector2 = segment.m_endDirection;
         }
         else
         {
             vector2 = segment.m_startDirection;
         }
         float num4 = vector.x * vector2.x + vector.z * vector2.z;
         if (num4 >= num3)
         {
             return result;
         }
     }
     float num5 = 1f;
     float num6 = 1f;
     NetInfo.LaneType laneType = NetInfo.LaneType.None;
     VehicleInfo.VehicleType vehicleType = VehicleInfo.VehicleType.None;
     if ((int)item.m_position.m_lane < info2.m_lanes.Length)
     {
         NetInfo.Lane lane = info2.m_lanes[(int)item.m_position.m_lane];
         laneType = lane.m_laneType;
         vehicleType = lane.m_vehicleType;
         num5 = lane.m_speedLimit;
         num6 = this.CalculateLaneSpeed(connectOffset, item.m_position.m_offset, ref instance.m_segments.m_buffer[(int)item.m_position.m_segment], lane);
     }
     float num7 = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_averageLength;
     if (!this.m_stablePath)
     {
         Randomizer randomizer = new Randomizer(this.m_pathFindIndex << 16 | (uint)item.m_position.m_segment);
         num7 *= (float)(randomizer.Int32(900, 1000 + (int)(instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_trafficDensity * 10)) + this.m_pathRandomizer.Int32(20u)) * 0.001f;
     }
     if (this.m_isHeavyVehicle && (instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_flags & NetSegment.Flags.HeavyBan) != NetSegment.Flags.None)
     {
         num7 *= 10f;
     }
     else if (laneType == NetInfo.LaneType.Vehicle && (vehicleType & this.m_vehicleTypes) == VehicleInfo.VehicleType.Car && (instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_flags & NetSegment.Flags.CarBan) != NetSegment.Flags.None)
     {
         num7 *= 5f;
     }
     if (this.m_transportVehicle && laneType == NetInfo.LaneType.TransportVehicle)
     {
         num7 *= 0.95f;
     }
     if ((byte)(laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0)
     {
         laneType = (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle);
     }
     float num8 = (float)Mathf.Abs((int)(connectOffset - item.m_position.m_offset)) * 0.003921569f * num7;
     float num9 = item.m_methodDistance + num8;
     float num10 = item.m_comparisonValue + num8 / (num6 * this.m_maxLength);
     Vector3 b = instance.m_lanes.m_buffer[(int)((UIntPtr)item.m_laneID)].CalculatePosition((float)connectOffset * 0.003921569f);
     int num11 = currentTargetIndex;
     bool flag = (instance.m_nodes.m_buffer[(int)targetNode].m_flags & NetNode.Flags.Transition) != NetNode.Flags.None;
     NetInfo.LaneType laneType2 = this.m_laneTypes;
     VehicleInfo.VehicleType vehicleType2 = this.m_vehicleTypes;
     if (!enableVehicle)
     {
         vehicleType2 &= VehicleInfo.VehicleType.Bicycle;
         if (vehicleType2 == VehicleInfo.VehicleType.None)
         {
             laneType2 &= ~(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle);
         }
     }
     if (!enablePedestrian)
     {
         laneType2 &= ~NetInfo.LaneType.Pedestrian;
     }
     int num12 = 0;
     while (num12 < num && num2 != 0u)
     {
         NetInfo.Lane lane2 = info.m_lanes[num12];
         if ((byte)(lane2.m_finalDirection & direction2) != 0)
         {
             if (lane2.CheckType(laneType2, vehicleType2) && (segmentID != item.m_position.m_segment || num12 != (int)item.m_position.m_lane) && (byte)(lane2.m_finalDirection & direction2) != 0)
             {
                 Vector3 a;
                 if ((byte)(direction & NetInfo.Direction.Forward) != 0)
                 {
                     a = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_bezier.d;
                 }
                 else
                 {
                     a = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_bezier.a;
                 }
                 float num13 = Vector3.Distance(a, b);
                 if (flag)
                 {
                     num13 *= 2f;
                 }
                 float num14 = num13 / ((num5 + lane2.m_speedLimit) * 0.5f * this.m_maxLength);
                 BufferItem item2;
                 item2.m_position.m_segment = segmentID;
                 item2.m_position.m_lane = (byte)num12;
                 item2.m_position.m_offset = (byte)(((direction & NetInfo.Direction.Forward) == 0) ? 0 : 255);
                 if ((byte)(lane2.m_laneType & laneType) == 0)
                 {
                     item2.m_methodDistance = 0f;
                 }
                 else
                 {
                     item2.m_methodDistance = num9 + num13;
                 }
                 if (lane2.m_laneType != NetInfo.LaneType.Pedestrian || item2.m_methodDistance < 1000f)
                 {
                     item2.m_comparisonValue = num10 + num14;
                     item2.m_direction = direction;
                     if (num2 == this.m_startLaneA)
                     {
                         if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this.m_startOffsetA) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this.m_startOffsetA))
                         {
                             num2 = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_nextLane;
                             num12++;
                             continue;
                         }
                         float num15 = this.CalculateLaneSpeed(this.m_startOffsetA, item2.m_position.m_offset, ref segment, lane2);
                         float num16 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this.m_startOffsetA)) * 0.003921569f;
                         item2.m_comparisonValue += num16 * segment.m_averageLength / (num15 * this.m_maxLength);
                     }
                     if (num2 == this.m_startLaneB)
                     {
                         if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this.m_startOffsetB) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this.m_startOffsetB))
                         {
                             num2 = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_nextLane;
                             num12++;
                             continue;
                         }
                         float num17 = this.CalculateLaneSpeed(this.m_startOffsetB, item2.m_position.m_offset, ref segment, lane2);
                         float num18 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this.m_startOffsetB)) * 0.003921569f;
                         item2.m_comparisonValue += num18 * segment.m_averageLength / (num17 * this.m_maxLength);
                     }
                     if (!this.m_ignoreBlocked && (segment.m_flags & NetSegment.Flags.Blocked) != NetSegment.Flags.None && (byte)(lane2.m_laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0)
                     {
                         item2.m_comparisonValue += 0.1f;
                         result = true;
                     }
                     item2.m_lanesUsed = (item.m_lanesUsed | lane2.m_laneType);
                     item2.m_laneID = num2;
                     if ((byte)(lane2.m_laneType & laneType) != 0 && (lane2.m_vehicleType & this.m_vehicleTypes) != VehicleInfo.VehicleType.None)
                     {
                         int firstTarget = (int)instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_firstTarget;
                         int lastTarget = (int)instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_lastTarget;
                         if (currentTargetIndex < firstTarget || currentTargetIndex >= lastTarget)
                         {
                             item2.m_comparisonValue += Mathf.Max(1f, num13 * 3f - 3f) / ((num5 + lane2.m_speedLimit) * 0.5f * this.m_maxLength);
                         }
                         if (!this.m_transportVehicle && lane2.m_laneType == NetInfo.LaneType.TransportVehicle)
                         {
                             item2.m_comparisonValue += 20f / ((num5 + lane2.m_speedLimit) * 0.5f * this.m_maxLength);
                         }
                     }
                     this.AddBufferItem(item2, item.m_position);
                 }
             }
             num2 = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_nextLane;
             num12++;
             continue;
         }
         if ((byte)(lane2.m_laneType & laneType) != 0 && (lane2.m_vehicleType & vehicleType) != VehicleInfo.VehicleType.None)
         {
             num11++;
         }
         num2 = instance.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_nextLane;
         num12++;
     }
     currentTargetIndex = num11;
     return result;
 }
        /// <summary>
        /// This method marks zone cells overlapped by network segments as invalid. Called by CalculateBlock1.
        /// </summary>
        /// <param name="_this"></param>
        /// <param name="blockID"></param>
        /// <param name="segmentID"></param>
        /// <param name="data"></param>
        /// <param name="valid"></param>
        /// <param name="minX"></param>
        /// <param name="minZ"></param>
        /// <param name="maxX"></param>
        /// <param name="maxZ"></param>
        private static void CalculateImplementation1(ref ZoneBlock _this, ushort blockID, ushort segmentID, ref NetSegment data, ref ulong valid, float minX, float minZ, float maxX, float maxZ)
        {
            // do nothing if the block belongs to the network segment
            if ((int)data.m_blockStartLeft == (int)blockID || (int)data.m_blockStartRight == (int)blockID ||
                ((int)data.m_blockEndLeft == (int)blockID || (int)data.m_blockEndRight == (int)blockID))
            {
                return;
            }

            NetInfo info = data.Info;
            if (!info.m_canCollide) return; // water pipes etc.

            float collisionHalfWidth = info.m_netAI.GetCollisionHalfWidth();

            NetNode[] netNodeArray = Singleton<NetManager>.instance.m_nodes.m_buffer;

            // calculate network bezier curve
            Bezier3 bezier = new Bezier3();
            bezier.a = netNodeArray[(int)data.m_startNode].m_position;
            bezier.d = netNodeArray[(int)data.m_endNode].m_position;
            NetSegment.CalculateMiddlePoints(bezier.a, data.m_startDirection, bezier.d, data.m_endDirection, true, true, out bezier.b, out bezier.c);

            // remove vertical component
            Bezier2 bezierXZ = Bezier2.XZ(bezier);

            // do nothing if the collision hitbox is outside of the hitbox of the zone block
            Vector2 collisionAreaMin = bezierXZ.Min() + new Vector2(-collisionHalfWidth, -collisionHalfWidth);
            Vector2 collisionAreaMax = bezierXZ.Max() + new Vector2(collisionHalfWidth, collisionHalfWidth);
            if ((double)collisionAreaMin.x > (double)maxX || (double)collisionAreaMin.y > (double)maxZ
                || ((double)minX > (double)collisionAreaMax.x || (double)minZ > (double)collisionAreaMax.y))
            {
                return;
            }

            // width of the zone block
            int rowCount = _this.RowCount;

            // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size)
            Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f;
            Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x);

            // origin of the zone block
            // this position is in the center of the 8x8 zone block (4 columns and 4 rows away from the lower corner)
            Vector2 positionXZ = VectorUtils.XZ(_this.m_position);

            // area of the zone block (8x8 cells)
            Quad2 zoneBlockQuad = new Quad2
            {
                a = positionXZ - 4f * columnDirection - 4f * rowDirection,
                b = positionXZ + 4f * columnDirection - 4f * rowDirection,
                c = positionXZ + 4f * columnDirection + (float)(rowCount - 4) * rowDirection,
                d = positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection
            };

            // Calculate the bounds of the network segment at the start node
            float start;
            float end;
            info.m_netAI.GetTerrainModifyRange(out start, out end);
            float halfStart = start * 0.5f; // e.g. 0.25f ---> 0.125f
            float halfEnd = (float)(1.0 - (1.0 - (double)end) * 0.5); // e.g. 0.75f --> 0.875f
            float t = halfStart;
            Vector2 startBezierPos = bezierXZ.Position(halfStart);
            Vector2 startBezierTan = bezierXZ.Tangent(halfStart);
            Vector2 startOrthogonalNormalized = new Vector2(-startBezierTan.y, startBezierTan.x).normalized; // tangent rotated by -90 deg = orthogonal

            Quad2 bezierQuad = new Quad2();

            // set the initial a/b bounds
            if ((double)t < 0.00999999977648258 && (info.m_clipSegmentEnds || (netNodeArray[(int)data.m_startNode].m_flags & NetNode.Flags.Bend) != NetNode.Flags.None))
            {
                Vector2 ortho4m = startOrthogonalNormalized * 4f;
                bezierQuad.a = startBezierPos + ortho4m - VectorUtils.XZ(data.m_startDirection) * 4f;
                bezierQuad.d = startBezierPos - ortho4m - VectorUtils.XZ(data.m_startDirection) * 4f;
            }
            else
            {
                Vector2 orthoHalfWidth = startOrthogonalNormalized * collisionHalfWidth;
                bezierQuad.a = startBezierPos + orthoHalfWidth;
                bezierQuad.d = startBezierPos - orthoHalfWidth;
            }

            // overlap 8 quads describing the position
            int steps = 8;
            for (int step = 1; step <= steps; ++step)
            {
                float interp = halfStart + (halfEnd - halfStart) * (float)step / (float)steps;
                Vector2 interpBezierPos = bezierXZ.Position(interp);
                Vector2 interpBezierTangent = bezierXZ.Tangent(interp);
                interpBezierTangent = new Vector2(-interpBezierTangent.y, interpBezierTangent.x).normalized;

                // set the c/d bounds
                if ((double)interp > 0.990000009536743 && (info.m_clipSegmentEnds || (netNodeArray[(int)data.m_endNode].m_flags & NetNode.Flags.Bend) != NetNode.Flags.None))
                {
                    interpBezierTangent *= 4f;
                    bezierQuad.b = interpBezierPos + interpBezierTangent - VectorUtils.XZ(data.m_endDirection) * 4f;
                    bezierQuad.c = interpBezierPos - interpBezierTangent - VectorUtils.XZ(data.m_endDirection) * 4f;
                }
                else
                {
                    interpBezierTangent *= collisionHalfWidth;
                    bezierQuad.b = interpBezierPos + interpBezierTangent;
                    bezierQuad.c = interpBezierPos - interpBezierTangent;
                }
                Vector2 quadMin = bezierQuad.Min();
                Vector2 quadMax = bezierQuad.Max();

                // Overlap the quad with the zone block quad
                if ((double)quadMin.x <= (double)maxX && (double)quadMin.y <= (double)maxZ && ((double)minX <= (double)quadMax.x && (double)minZ <= (double)quadMax.y) && zoneBlockQuad.Intersect(bezierQuad))
                {
                    // mark colliding cells as invalid
                    valid = valid & ~OverlapQuad(ref _this, bezierQuad);
                }

                // set the a/b bounds for the next quad
                bezierQuad.a = bezierQuad.b;
                bezierQuad.d = bezierQuad.c;
            }
        }
        private OSMWay CreateWay(int index, NetSegment segment, ushort segmentId)
        {
            OSMWay returnWay = null;
            NetSegment.Flags segmentFlags = segment.m_flags;
            NetManager netManager = Singleton<NetManager>.instance;
            List<OSMWayND> wayPaths = new List<OSMWayND>();
            List<OSMWayTag> wayTags;
            ushort startNodeId = segment.m_startNode, endNodeId = segment.m_endNode;

            if(startNodeId != 0 && endNodeId != 0)
            {
                Vector3 startNodeDirection = segment.m_startDirection;
                Vector3 endNodeDirection = segment.m_endDirection;

                if(segmentFlags.IsFlagSet(NetSegment.Flags.Invert))
                {
                    startNodeId = segment.m_endNode;
                    endNodeId = segment.m_startNode;
                    startNodeDirection = segment.m_endDirection;
                    endNodeDirection = segment.m_startDirection;
                }

                NetNode startNode = netManager.m_nodes.m_buffer[startNodeId];
                NetNode endNode = netManager.m_nodes.m_buffer[endNodeId];
                Vector3 startNodePosition = startNode.m_position;
                Vector3 endNodePosition = endNode.m_position;

                wayPaths.Add(new OSMWayND { @ref = startNodeId });

                if (Vector3.Angle(startNodeDirection, -endNodeDirection) > 3f)
                {
                    Vector3 midPointA = Vector3.zero, midPointB = Vector3.zero;
                    NetSegment.CalculateMiddlePoints(startNodePosition, startNodeDirection, endNodePosition, endNodeDirection, false, false, out midPointA, out midPointB);
                    Bezier3 bezier = new Bezier3(startNodePosition, midPointA, midPointB, endNodePosition);

                    osmNodes.Add(CreateNode(unindexedNodeOffset++, bezier.Position(0.25f)));
                    osmNodes.Add(CreateNode(unindexedNodeOffset++, bezier.Position(0.5f)));
                    osmNodes.Add(CreateNode(unindexedNodeOffset++, bezier.Position(0.75f)));

                    wayPaths.Add(new OSMWayND { @ref = (uint)unindexedNodeOffset - 3 });
                    wayPaths.Add(new OSMWayND { @ref = (uint)unindexedNodeOffset - 2 });
                    wayPaths.Add(new OSMWayND { @ref = (uint)unindexedNodeOffset - 1 });
                }

                wayPaths.Add(new OSMWayND { @ref = endNodeId });

                if(Tagger.CreateWayTags(segment, out wayTags))
                {
                    if (haveRoadNamerMod)
                    {
                        // If road namer mod is available, then attempt to get the name asscociated with the segment, if any
                        string roadName = RoadNamerManager.Instance().getSegmentName((ushort)(segmentId));
                        if (roadName != null)
                        {
                            //If a name is available, add a name tag
                            wayTags.Add(new OSMWayTag { k = "name", v = StringUtilities.RemoveTags(roadName) });
                        }
                    }
                    returnWay = new OSMWay { changeset = 50000000, id = (uint)index, timestamp = DateTime.Now, user = "******", nd = wayPaths.ToArray(), tag = wayTags.ToArray(), version = 1 };
                }
                else
                {
                    UniqueLogger.AddLog("Road names missing from search", segment.Info.name, "");
                }
            }

            return returnWay;
        }
		private bool ProcessItemCosts(bool allowCustomLaneChanging, bool debug, BufferItem item, ushort targetNode, ushort segmentID, ref NetSegment segment, ref int laneIndexFromLeft, byte connectOffset, bool enableVehicle, bool enablePedestrian) {
			bool foundForced = false;
			return ProcessItemCosts(allowCustomLaneChanging, debug, item, targetNode, segmentID, ref segment, ref laneIndexFromLeft, connectOffset, enableVehicle, enablePedestrian, null, null, out foundForced);
		}
		internal static void CheckSegmentProblems(ushort segmentID, ref NetSegment data) {
			NetManager instance = Singleton<NetManager>.instance;
			Notification.Problem problems = instance.m_nodes.m_buffer[(int)data.m_startNode].m_problems;
			CheckNodeProblems(data.m_startNode, ref instance.m_nodes.m_buffer[(int)data.m_startNode]);
			Notification.Problem problems2 = instance.m_nodes.m_buffer[(int)data.m_startNode].m_problems;
			if (problems != problems2) {
				instance.UpdateNodeNotifications(data.m_startNode, problems, problems2);
			}
			Notification.Problem problems3 = instance.m_nodes.m_buffer[(int)data.m_endNode].m_problems;
			CheckNodeProblems(data.m_endNode, ref instance.m_nodes.m_buffer[(int)data.m_endNode]);
			Notification.Problem problems4 = instance.m_nodes.m_buffer[(int)data.m_endNode].m_problems;
			if (problems3 != problems4) {
				instance.UpdateNodeNotifications(data.m_endNode, problems3, problems4);
			}
		}
		// 2
		private void ProcessItem2(BufferItem item, ushort targetNodeId, bool targetDisabled, ushort nextSegmentId, ref NetSegment nextSegment, uint lane, byte offset, byte connectOffset) {
			if ((nextSegment.m_flags & (NetSegment.Flags.PathFailed | NetSegment.Flags.Flooded)) != NetSegment.Flags.None) {
				return;
			}
			NetManager instance = Singleton<NetManager>.instance;
			if (targetDisabled && ((instance.m_nodes.m_buffer[(int)nextSegment.m_startNode].m_flags | instance.m_nodes.m_buffer[(int)nextSegment.m_endNode].m_flags) & NetNode.Flags.Disabled) == NetNode.Flags.None) {
				return;
			}
			NetInfo nextSegmentInfo = nextSegment.Info;
			NetInfo prevSegmentInfo = instance.m_segments.m_buffer[(int)item.m_position.m_segment].Info;
			int nextNumLanes = nextSegmentInfo.m_lanes.Length;
			uint curLaneId = nextSegment.m_lanes;
			float prevMaxSpeed = 1f;
			float num4 = 1f;
			NetInfo.LaneType laneType = NetInfo.LaneType.None;
			// NON-STOCK CODE START //
			bool nextIsJunction = instance.m_nodes.m_buffer[targetNodeId].CountSegments() > 2;
			ushort sourceNodeId = (targetNodeId == instance.m_segments.m_buffer[item.m_position.m_segment].m_startNode) ? instance.m_segments.m_buffer[item.m_position.m_segment].m_endNode : instance.m_segments.m_buffer[item.m_position.m_segment].m_startNode; // no lane changing directly in front of a junction
			bool prevIsJunction = instance.m_nodes.m_buffer[sourceNodeId].CountSegments() > 2;
			// NON-STOCK CODE END //
			if ((int)item.m_position.m_lane < prevSegmentInfo.m_lanes.Length) {
				NetInfo.Lane lane2 = prevSegmentInfo.m_lanes[(int)item.m_position.m_lane];
				prevMaxSpeed = GetLaneSpeedLimit(item.m_position.m_segment, item.m_position.m_lane, item.m_laneID, lane2); // SpeedLimitManager.GetLockFreeGameSpeedLimit(item.m_position.m_segment, item.m_position.m_lane, item.m_laneID, ref lane2); // NON-STOCK CODE
				laneType = lane2.m_laneType;
				if ((byte)(laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0) {
					laneType = (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle);
				}
				num4 = this.CalculateLaneSpeed(prevMaxSpeed, connectOffset, item.m_position.m_offset, ref instance.m_segments.m_buffer[(int)item.m_position.m_segment], lane2); // NON-STOCK CODE
			}
			float averageLength = instance.m_segments.m_buffer[(int)item.m_position.m_segment].m_averageLength;
			float num5 = (float)Mathf.Abs((int)(connectOffset - item.m_position.m_offset)) * 0.003921569f * averageLength;
			float num6 = item.m_methodDistance + num5;
			float num7 = item.m_comparisonValue + num5 / (num4 * this._maxLength);
			Vector3 b = instance.m_lanes.m_buffer[(int)((UIntPtr)item.m_laneID)].CalculatePosition((float)connectOffset * 0.003921569f);
			uint laneIndex = 0;
#if DEBUG
			int wIter = 0;
#endif
			while (laneIndex < nextNumLanes && curLaneId != 0u) {
#if DEBUG
				++wIter;
				if (wIter >= 20) {
					Log.Error("Too many iterations in ProcessItem2!");
					break;
				}
#endif

				if (lane == curLaneId) {
					NetInfo.Lane lane3 = nextSegmentInfo.m_lanes[laneIndex];
					if (lane3.CheckType(this._laneTypes, this._vehicleTypes)) {
						Vector3 a = instance.m_lanes.m_buffer[(int)((UIntPtr)lane)].CalculatePosition((float)offset * 0.003921569f);
						float num9 = Vector3.Distance(a, b);
						BufferItem item2;
						item2.m_position.m_segment = nextSegmentId;
						item2.m_position.m_lane = (byte)laneIndex;
						item2.m_position.m_offset = offset;
						if ((byte)(lane3.m_laneType & laneType) == 0) {
							item2.m_methodDistance = 0f;
						} else {
							item2.m_methodDistance = num6 + num9;
						}
						float nextMaxSpeed = GetLaneSpeedLimit(nextSegmentId, laneIndex, curLaneId, lane3); // SpeedLimitManager.GetLockFreeGameSpeedLimit(nextSegmentId, laneIndex, curLaneId, ref lane3); // NON-STOCK CODE
						if (lane3.m_laneType != NetInfo.LaneType.Pedestrian || item2.m_methodDistance < 1000f) {
							item2.m_comparisonValue = num7 + num9 / ((prevMaxSpeed + nextMaxSpeed) * 0.5f * this._maxLength); // NON-STOCK CODE
							if ((nextSegment.m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) {
								item2.m_direction = NetInfo.InvertDirection(lane3.m_finalDirection);
							} else {
								item2.m_direction = lane3.m_finalDirection;
							}
							if (lane == this._startLaneA) {
								if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this._startOffsetA) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this._startOffsetA)) {
									return;
								}
								float num10 = this.CalculateLaneSpeed(nextMaxSpeed, this._startOffsetA, item2.m_position.m_offset, ref nextSegment, lane3); // NON-STOCK CODE
								float num11 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this._startOffsetA)) * 0.003921569f;
								item2.m_comparisonValue += num11 * nextSegment.m_averageLength / (num10 * this._maxLength);
							}
							if (lane == this._startLaneB) {
								if (((byte)(item2.m_direction & NetInfo.Direction.Forward) == 0 || item2.m_position.m_offset < this._startOffsetB) && ((byte)(item2.m_direction & NetInfo.Direction.Backward) == 0 || item2.m_position.m_offset > this._startOffsetB)) {
									return;
								}
								float num12 = this.CalculateLaneSpeed(nextMaxSpeed, this._startOffsetB, item2.m_position.m_offset, ref nextSegment, lane3); // NON-STOCK CODE
								float num13 = (float)Mathf.Abs((int)(item2.m_position.m_offset - this._startOffsetB)) * 0.003921569f;
								item2.m_comparisonValue += num13 * nextSegment.m_averageLength / (num12 * this._maxLength);
							}
							item2.m_laneID = lane;
							item2.m_lanesUsed = (item.m_lanesUsed | lane3.m_laneType);
							this.AddBufferItem(item2, item.m_position);
						}
					}
					return;
				}
				curLaneId = instance.m_lanes.m_buffer[(int)((UIntPtr)curLaneId)].m_nextLane;
				laneIndex++;
			}
		}
        private void CreateZoneBlocks(int segment, ref NetSegment data, NetInfo info)
        {
            var instance = Singleton<NetManager>.instance;
            var randomizer = new Randomizer(segment);
            var position = instance.m_nodes.m_buffer[data.m_startNode].m_position;
            var position2 = instance.m_nodes.m_buffer[data.m_endNode].m_position;
            var startDirection = data.m_startDirection;
            var endDirection = data.m_endDirection;
            var num = startDirection.x * endDirection.x + startDirection.z * endDirection.z;
            var flag = !NetSegment.IsStraight(position, startDirection, position2, endDirection);
            var num2 = Mathf.Max(8f, info.m_halfWidth);
            var num3 = 32f;
            if (flag)
            {
                var num4 = VectorUtils.LengthXZ(position2 - position);
                var flag2 = startDirection.x * endDirection.z - startDirection.z * endDirection.x > 0f;
                var flag3 = num < -0.8f || num4 > 50f;
                if (flag2)
                {
                    num2 = -num2;
                    num3 = -num3;
                }
                var vector = position - new Vector3(startDirection.z, 0f, -startDirection.x) * num2;
                var vector2 = position2 + new Vector3(endDirection.z, 0f, -endDirection.x) * num2;
                Vector3 vector3;
                Vector3 vector4;
                NetSegment.CalculateMiddlePoints(vector, startDirection, vector2, endDirection, true, true, out vector3, out vector4);
                if (flag3)
                {
                    var num5 = num * 0.025f + 0.04f;
                    var num6 = num * 0.025f + 0.06f;
                    if (num < -0.9f)
                    {
                        num6 = num5;
                    }
                    var bezier = new Bezier3(vector, vector3, vector4, vector2);
                    vector = bezier.Position(num5);
                    vector3 = bezier.Position(0.5f - num6);
                    vector4 = bezier.Position(0.5f + num6);
                    vector2 = bezier.Position(1f - num5);
                }
                else
                {
                    var bezier2 = new Bezier3(vector, vector3, vector4, vector2);
                    vector3 = bezier2.Position(0.86f);
                    vector = bezier2.Position(0.14f);
                }
                float num7;
                var vector5 = VectorUtils.NormalizeXZ(vector3 - vector, out num7);
                var num8 = Mathf.FloorToInt(num7 / 8f + 0.01f);
                var num9 = num7 * 0.5f + (num8 - 8) * ((!flag2) ? -4f : 4f);
                if (num8 != 0)
                {
                    var angle = (!flag2) ? Mathf.Atan2(vector5.x, -vector5.z) : Mathf.Atan2(-vector5.x, vector5.z);
                    var position3 = vector + new Vector3(vector5.x * num9 - vector5.z * num3, 0f, vector5.z * num9 + vector5.x * num3);
                    if (flag2)
                    {
                        Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockStartRight, ref randomizer, position3, angle, num8, data.m_buildIndex);
                    }
                    else
                    {
                        Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockStartLeft, ref randomizer, position3, angle, num8, data.m_buildIndex);
                    }
                }
                if (flag3)
                {
                    vector5 = VectorUtils.NormalizeXZ(vector2 - vector4, out num7);
                    num8 = Mathf.FloorToInt(num7 / 8f + 0.01f);
                    num9 = num7 * 0.5f + (num8 - 8) * ((!flag2) ? -4f : 4f);
                    if (num8 != 0)
                    {
                        var angle2 = (!flag2) ? Mathf.Atan2(vector5.x, -vector5.z) : Mathf.Atan2(-vector5.x, vector5.z);
                        var position4 = vector4 + new Vector3(vector5.x * num9 - vector5.z * num3, 0f, vector5.z * num9 + vector5.x * num3);
                        if (flag2)
                        {
                            Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockEndRight, ref randomizer, position4, angle2, num8, data.m_buildIndex + 1u);
                        }
                        else
                        {
                            Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockEndLeft, ref randomizer, position4, angle2, num8, data.m_buildIndex + 1u);
                        }
                    }
                }
                var vector6 = position + new Vector3(startDirection.z, 0f, -startDirection.x) * num2;
                var vector7 = position2 - new Vector3(endDirection.z, 0f, -endDirection.x) * num2;
                Vector3 b;
                Vector3 c;
                NetSegment.CalculateMiddlePoints(vector6, startDirection, vector7, endDirection, true, true, out b, out c);
                var bezier3 = new Bezier3(vector6, b, c, vector7);
                var vector8 = bezier3.Position(0.5f);
                var vector9 = bezier3.Position(0.25f);
                vector9 = Line2.Offset(VectorUtils.XZ(vector6), VectorUtils.XZ(vector8), VectorUtils.XZ(vector9));
                var vector10 = bezier3.Position(0.75f);
                vector10 = Line2.Offset(VectorUtils.XZ(vector7), VectorUtils.XZ(vector8), VectorUtils.XZ(vector10));
                var vector11 = vector6;
                var a = vector7;
                float d;
                float num10;
                if (Line2.Intersect(VectorUtils.XZ(position), VectorUtils.XZ(vector6), VectorUtils.XZ(vector11 - vector9), VectorUtils.XZ(vector8 - vector9), out d, out num10))
                {
                    vector6 = position + (vector6 - position) * d;
                }
                if (Line2.Intersect(VectorUtils.XZ(position2), VectorUtils.XZ(vector7), VectorUtils.XZ(a - vector10), VectorUtils.XZ(vector8 - vector10), out d, out num10))
                {
                    vector7 = position2 + (vector7 - position2) * d;
                }
                if (Line2.Intersect(VectorUtils.XZ(vector11 - vector9), VectorUtils.XZ(vector8 - vector9), VectorUtils.XZ(a - vector10), VectorUtils.XZ(vector8 - vector10), out d, out num10))
                {
                    vector8 = vector11 - vector9 + (vector8 - vector11) * d;
                }
                float num11;
                var vector12 = VectorUtils.NormalizeXZ(vector8 - vector6, out num11);
                var num12 = Mathf.FloorToInt(num11 / 8f + 0.01f);
                var num13 = num11 * 0.5f + (num12 - 8) * ((!flag2) ? 4f : -4f);
                if (num12 != 0)
                {
                    var angle3 = (!flag2) ? Mathf.Atan2(-vector12.x, vector12.z) : Mathf.Atan2(vector12.x, -vector12.z);
                    var position5 = vector6 + new Vector3(vector12.x * num13 + vector12.z * num3, 0f, vector12.z * num13 - vector12.x * num3);
                    if (flag2)
                    {
                        Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockStartLeft, ref randomizer, position5, angle3, num12, data.m_buildIndex);
                    }
                    else
                    {
                        Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockStartRight, ref randomizer, position5, angle3, num12, data.m_buildIndex);
                    }
                }
                vector12 = VectorUtils.NormalizeXZ(vector7 - vector8, out num11);
                num12 = Mathf.FloorToInt(num11 / 8f + 0.01f);
                num13 = num11 * 0.5f + (num12 - 8) * ((!flag2) ? 4f : -4f);

                if (num12 == 0) return;

                var angle4 = (!flag2) ? Mathf.Atan2(-vector12.x, vector12.z) : Mathf.Atan2(vector12.x, -vector12.z);
                var position6 = vector8 + new Vector3(vector12.x * num13 + vector12.z * num3, 0f, vector12.z * num13 - vector12.x * num3);
                if (flag2)
                {
                    Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockEndLeft, ref randomizer, position6, angle4, num12, data.m_buildIndex + 1u);
                }
                else
                {
                    Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockEndRight, ref randomizer, position6, angle4, num12, data.m_buildIndex + 1u);
                }
            }
            else
            {
                num2 += num3;
                var vector13 = new Vector2(position2.x - position.x, position2.z - position.z);
                var magnitude = vector13.magnitude;
                var num14 = Mathf.FloorToInt(magnitude / 8f + 0.1f);
                var num15 = (num14 <= 8) ? num14 : (num14 + 1 >> 1);
                var num16 = (num14 <= 8) ? 0 : (num14 >> 1);
                if (num15 > 0)
                {
                    var num17 = Mathf.Atan2(startDirection.x, -startDirection.z);
                    var position7 = position + new Vector3(startDirection.x * 32f - startDirection.z * num2, 0f, startDirection.z * 32f + startDirection.x * num2);
                    Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockStartLeft, ref randomizer, position7, num17, num15, data.m_buildIndex);
                    position7 = position + new Vector3(startDirection.x * (num15 - 4) * 8f + startDirection.z * num2, 0f, startDirection.z * (num15 - 4) * 8f - startDirection.x * num2);
                    Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockStartRight, ref randomizer, position7, num17 + 3.14159274f, num15, data.m_buildIndex);
                }

                if (num16 <= 0) return;

                var num18 = magnitude - num14 * 8f;
                var num19 = Mathf.Atan2(endDirection.x, -endDirection.z);
                var position8 = position2 + new Vector3(endDirection.x * (32f + num18) - endDirection.z * num2, 0f, endDirection.z * (32f + num18) + endDirection.x * num2);
                Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockEndLeft, ref randomizer, position8, num19, num16, data.m_buildIndex + 1u);
                position8 = position2 + new Vector3(endDirection.x * ((num16 - 4) * 8f + num18) + endDirection.z * num2, 0f, endDirection.z * ((num16 - 4) * 8f + num18) - endDirection.x * num2);
                Singleton<ZoneManager>.instance.CreateBlock(out data.m_blockEndRight, ref randomizer, position8, num19 + 3.14159274f, num16, data.m_buildIndex + 1u);
            }
        }
		/*private void _guiManualTrafficLightsCrosswalk(ref NetNode node) {
			var hoveredSegment = false;

			ushort segment1 = 0;
			ushort segment2 = 0;

			for (var i = 0; i < 8; i++) {
				var segmentId = node.GetSegment(i);

				if (segmentId == 0) continue;

				if (segment1 == 0) {
					segment1 = segmentId;
				} else {
					segment2 = segmentId;
				}
			}

			var segmentDict1 = CustomTrafficLights.GetSegmentLights(SelectedNode, segment1);
			var segmentDict2 = CustomTrafficLights.GetSegmentLights(SelectedNode, segment2);
			var position = node.m_position;

			const float offset = 0f;

			if (Singleton<NetManager>.instance.m_segments.m_buffer[segment1].m_startNode == SelectedNode) {
				position.x += Singleton<NetManager>.instance.m_segments.m_buffer[segment1].m_startDirection.x * offset;
				position.y += Singleton<NetManager>.instance.m_segments.m_buffer[segment1].m_startDirection.y * offset;
				position.z += Singleton<NetManager>.instance.m_segments.m_buffer[segment1].m_startDirection.z * offset;
			} else {
				position.x += Singleton<NetManager>.instance.m_segments.m_buffer[segment1].m_endDirection.x * offset;
				position.y += Singleton<NetManager>.instance.m_segments.m_buffer[segment1].m_endDirection.y * offset;
				position.z += Singleton<NetManager>.instance.m_segments.m_buffer[segment1].m_endDirection.z * offset;
			}

			var guiColor = GUI.color;

			var screenPos = Camera.main.WorldToScreenPoint(position);
			screenPos.y = Screen.height - screenPos.y;

			if (screenPos.z < 0)
				return;

			var diff = position - Camera.main.transform.position;
			var zoom = 1.0f / diff.magnitude * 100f;

			// original / 2.5
			var lightWidth = 41f * zoom;
			var lightHeight = 97f * zoom;

			// SWITCH PEDESTRIAN LIGHT
			var pedestrianWidth = 36f * zoom;
			var pedestrianHeight = 61f * zoom;

			guiColor.a = _hoveredButton[0] == segment1 && _hoveredButton[1] == 0 ? 0.92f : 0.6f;

			GUI.color = guiColor;

			var myRect3 = new Rect(screenPos.x - pedestrianWidth / 2 - lightWidth + 5f * zoom, screenPos.y - pedestrianHeight / 2 + 22f * zoom, pedestrianWidth, pedestrianHeight);

			switch (segmentDict1.LightPedestrian) {
				case RoadBaseAI.TrafficLightState.Green:
					GUI.DrawTexture(myRect3, TrafficLightToolTextureResources.PedestrianGreenLightTexture2D);
					break;
				case RoadBaseAI.TrafficLightState.Red:
				default:
					GUI.DrawTexture(myRect3, TrafficLightToolTextureResources.PedestrianRedLightTexture2D);
					break;
			}

			if (myRect3.Contains(Event.current.mousePosition)) {
				_hoveredButton[0] = segment1;
				_hoveredButton[1] = 0;
				hoveredSegment = true;

				checkClicked();
			}

			// no arrow light
			guiColor.a = _hoveredButton[0] == segment1 && _hoveredButton[1] == 1 ? 0.92f : 0.6f;

			GUI.color = guiColor;

			var myRect4 =
				new Rect(screenPos.x - lightWidth / 2 - lightWidth - pedestrianWidth + 5f * zoom,
					screenPos.y - lightHeight / 2, lightWidth, lightHeight);

			switch (segmentDict1.LightMain) {
				case RoadBaseAI.TrafficLightState.Green:
					GUI.DrawTexture(myRect4, TrafficLightToolTextureResources.GreenLightTexture2D);
					break;
				case RoadBaseAI.TrafficLightState.Red:
					GUI.DrawTexture(myRect4, TrafficLightToolTextureResources.RedLightTexture2D);
					break;
			}

			if (myRect4.Contains(Event.current.mousePosition)) {
				_hoveredButton[0] = segment1;
				_hoveredButton[1] = 1;
				hoveredSegment = true;

				if (checkClicked()) {
					segmentDict1.ChangeLightMain();
					segmentDict2.ChangeLightMain();
				}
			}

			if (hoveredSegment) return;

			_hoveredButton[0] = 0;
			_hoveredButton[1] = 0;
		}*/

		/// <summary>
		/// Displays lane ids over lanes
		/// </summary>
		private void _guiLanes(ref NetSegment segment, ref NetInfo segmentInfo) {
			Vector3 centerPos = segment.m_bounds.center;
			var screenPos = Camera.main.WorldToScreenPoint(centerPos);
			screenPos.y = Screen.height - screenPos.y - 200;

			if (screenPos.z < 0)
				return;

			var camPos = Singleton<SimulationManager>.instance.m_simulationView.m_position;
			var diff = centerPos - camPos;
			if (diff.magnitude > DebugCloseLod)
				return; // do not draw if too distant

			var zoom = 1.0f / diff.magnitude * 150f;

			_counterStyle.fontSize = (int)(11f * zoom);
			_counterStyle.normal.textColor = new Color(1f, 1f, 0f);

			uint totalDensity = 0u;
			uint curLaneId = segment.m_lanes;
			for (int i = 0; i < segmentInfo.m_lanes.Length; ++i) {
				if (curLaneId == 0)
					break;

				totalDensity += CustomRoadAI.currentLaneDensities[curLaneId];

				curLaneId = Singleton<NetManager>.instance.m_lanes.m_buffer[curLaneId].m_nextLane;
			}


			curLaneId = segment.m_lanes;
			String labelStr = "";
			for (int i = 0; i < segmentInfo.m_lanes.Length; ++i) {
				if (curLaneId == 0)
					break;

				NetInfo.Lane laneInfo = segmentInfo.m_lanes[i];

				labelStr += "Lane idx " + i + ", id " + curLaneId;
#if DEBUG
				labelStr += ", flags: " + ((NetLane.Flags)Singleton<NetManager>.instance.m_lanes.m_buffer[curLaneId].m_flags).ToString() + ", limit: " + SpeedLimitManager.GetCustomSpeedLimit(curLaneId) + " km/h, dir: " + laneInfo.m_direction + ", final: " + laneInfo.m_finalDirection + ", pos: " + String.Format("{0:0.##}", laneInfo.m_position) + ", sim. idx: " + laneInfo.m_similarLaneIndex + " for " + laneInfo.m_vehicleType;
#endif
				if (CustomRoadAI.InStartupPhase)
					labelStr += ", in start-up phase";
				else
					labelStr += ", avg. speed: " + CustomRoadAI.laneMeanSpeeds[curLaneId] + " %";
				labelStr += ", avg. density: " + (totalDensity > 0 ? Math.Min(100f, ((float)CustomRoadAI.currentLaneDensities[curLaneId] * 100f) / (float)totalDensity) : 0f) + " %";
#if DEBUG
				labelStr += " (" + CustomRoadAI.currentLaneDensities[curLaneId] + "/" + totalDensity + ")";
#endif
				labelStr += "\n";

				curLaneId = Singleton<NetManager>.instance.m_lanes.m_buffer[curLaneId].m_nextLane;
			}
			
			Vector2 dim = _counterStyle.CalcSize(new GUIContent(labelStr));
			Rect labelRect = new Rect(screenPos.x - dim.x / 2f, screenPos.y, dim.x, dim.y);

			GUI.Label(labelRect, labelStr, _counterStyle);
		}