protected void CustomUpdatePathTargetPositions(ushort vehicleID, ref Vehicle vehicleData, Vector3 refPos, ref int index, int max, float minSqrDistanceA, float minSqrDistanceB)
        {
            PathManager pathMan    = Singleton <PathManager> .instance;
            NetManager  netManager = Singleton <NetManager> .instance;
            Vector4     targetPos0 = vehicleData.m_targetPos0;

            targetPos0.w = 1000f;
            float minSqrDistA    = minSqrDistanceA;
            uint  pathId         = vehicleData.m_path;
            byte  pathPosIndex   = vehicleData.m_pathPositionIndex;
            byte  lastPathOffset = vehicleData.m_lastPathOffset;

            if (pathPosIndex == 255)
            {
                pathPosIndex = 0;
                if (index <= 0)
                {
                    vehicleData.m_pathPositionIndex = 0;
                }
                if (!Singleton <PathManager> .instance.m_pathUnits.m_buffer[pathId].CalculatePathPositionOffset(pathPosIndex >> 1, targetPos0, out lastPathOffset))
                {
                    this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }
            }

            PathUnit.Position position;
            if (!pathMan.m_pathUnits.m_buffer[pathId].GetPosition(pathPosIndex >> 1, out position))
            {
                this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                return;
            }

            NetInfo curSegmentInfo = netManager.m_segments.m_buffer[(int)position.m_segment].Info;

            if (curSegmentInfo.m_lanes.Length <= (int)position.m_lane)
            {
                this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                return;
            }

            uint curLaneId = PathManager.GetLaneID(position);

            NetInfo.Lane laneInfo = curSegmentInfo.m_lanes[(int)position.m_lane];
            Bezier3      bezier;
            bool         firstIter = true;     // NON-STOCK CODE

            while (true)
            {
                if ((pathPosIndex & 1) == 0)
                {
                    if (laneInfo.m_laneType != NetInfo.LaneType.CargoVehicle)
                    {
                        bool first = true;
                        while (lastPathOffset != position.m_offset)
                        {
                            if (first)
                            {
                                first = false;
                            }
                            else
                            {
                                float distDiff = Mathf.Sqrt(minSqrDistA) - Vector3.Distance(targetPos0, refPos);
                                int   pathOffsetDelta;
                                if (distDiff < 0f)
                                {
                                    pathOffsetDelta = 4;
                                }
                                else
                                {
                                    pathOffsetDelta = 4 + Mathf.Max(0, Mathf.CeilToInt(distDiff * 256f / (netManager.m_lanes.m_buffer[curLaneId].m_length + 1f)));
                                }
                                if (lastPathOffset > position.m_offset)
                                {
                                    lastPathOffset = (byte)Mathf.Max((int)lastPathOffset - pathOffsetDelta, (int)position.m_offset);
                                }
                                else if (lastPathOffset < position.m_offset)
                                {
                                    lastPathOffset = (byte)Mathf.Min((int)lastPathOffset + pathOffsetDelta, (int)position.m_offset);
                                }
                            }
                            Vector3 curSegPos;
                            Vector3 curSegDir;
                            float   curSegOffset;
                            this.CalculateSegmentPosition(vehicleID, ref vehicleData, position, curLaneId, lastPathOffset, out curSegPos, out curSegDir, out curSegOffset);
                            targetPos0.Set(curSegPos.x, curSegPos.y, curSegPos.z, Mathf.Min(targetPos0.w, curSegOffset));
                            float refPosSqrDist = (curSegPos - refPos).sqrMagnitude;
                            if (refPosSqrDist >= minSqrDistA)
                            {
                                if (index <= 0)
                                {
                                    vehicleData.m_lastPathOffset = lastPathOffset;
                                }
                                vehicleData.SetTargetPos(index++, targetPos0);
                                minSqrDistA  = minSqrDistanceB;
                                refPos       = targetPos0;
                                targetPos0.w = 1000f;
                                if (index == max)
                                {
                                    return;
                                }
                            }
                        }
                    }
                    pathPosIndex  += 1;
                    lastPathOffset = 0;
                    if (index <= 0)
                    {
                        vehicleData.m_pathPositionIndex = pathPosIndex;
                        vehicleData.m_lastPathOffset    = lastPathOffset;
                    }
                }

                int  nextPathPosIndex = (pathPosIndex >> 1) + 1;
                uint nextPathId       = pathId;
                if (nextPathPosIndex >= (int)pathMan.m_pathUnits.m_buffer[pathId].m_positionCount)
                {
                    nextPathPosIndex = 0;
                    nextPathId       = pathMan.m_pathUnits.m_buffer[pathId].m_nextPathUnit;
                    if (nextPathId == 0u)
                    {
                        if (index <= 0)
                        {
                            Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path);

                            vehicleData.m_path = 0u;
                        }
                        targetPos0.w = 1f;
                        vehicleData.SetTargetPos(index++, targetPos0);
                        return;
                    }
                }

                PathUnit.Position nextPathPos;
                if (!pathMan.m_pathUnits.m_buffer[nextPathId].GetPosition(nextPathPosIndex, out nextPathPos))
                {
                    this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }

                NetInfo nextSegmentInfo = netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].Info;
                if (nextSegmentInfo.m_lanes.Length <= (int)nextPathPos.m_lane)
                {
                    this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }

                int bestLaneIndex = nextPathPos.m_lane;
                if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) != (Vehicle.Flags) 0)
                {
                    bestLaneIndex = FindBestLane(vehicleID, ref vehicleData, nextPathPos);
                }
                else
                {
                    // NON-STOCK CODE START
                    if (firstIter &&
                        this.m_info.m_vehicleType == VehicleInfo.VehicleType.Car &&
                        !this.m_info.m_isLargeVehicle
                        )
                    {
                        bool mayFindBestLane = false;
#if BENCHMARK
                        using (var bm = new Benchmark(null, "MayFindBestLane")) {
#endif
                        mayFindBestLane = VehicleBehaviorManager.Instance.MayFindBestLane(vehicleID, ref vehicleData, ref VehicleStateManager.Instance.VehicleStates[vehicleID]);
#if BENCHMARK
                    }
#endif

                        if (mayFindBestLane)
                        {
                            uint next2PathId       = nextPathId;
                            int  next2PathPosIndex = nextPathPosIndex;
                            bool next2Invalid;
                            PathUnit.Position next2PathPos;
                            NetInfo           next2SegmentInfo = null;
                            PathUnit.Position next3PathPos;
                            NetInfo           next3SegmentInfo = null;
                            PathUnit.Position next4PathPos;
                            if (PathUnit.GetNextPosition(ref next2PathId, ref next2PathPosIndex, out next2PathPos, out next2Invalid))
                            {
                                next2SegmentInfo = netManager.m_segments.m_buffer[(int)next2PathPos.m_segment].Info;

                                uint next3PathId       = next2PathId;
                                int  next3PathPosIndex = next2PathPosIndex;
                                bool next3Invalid;
                                if (PathUnit.GetNextPosition(ref next3PathId, ref next3PathPosIndex, out next3PathPos, out next3Invalid))
                                {
                                    next3SegmentInfo = netManager.m_segments.m_buffer[(int)next3PathPos.m_segment].Info;

                                    uint next4PathId       = next3PathId;
                                    int  next4PathPosIndex = next3PathPosIndex;
                                    bool next4Invalid;
                                    if (!PathUnit.GetNextPosition(ref next4PathId, ref next4PathPosIndex, out next4PathPos, out next4Invalid))
                                    {
                                        next4PathPos = default(PathUnit.Position);
                                    }
                                }
                                else
                                {
                                    next3PathPos = default(PathUnit.Position);
                                    next4PathPos = default(PathUnit.Position);
                                }
                            }
                            else
                            {
                                next2PathPos = default(PathUnit.Position);
                                next3PathPos = default(PathUnit.Position);
                                next4PathPos = default(PathUnit.Position);
                            }

#if BENCHMARK
                            using (var bm = new Benchmark(null, "FindBestLane")) {
#endif
                            bestLaneIndex = VehicleBehaviorManager.Instance.FindBestLane(vehicleID, ref vehicleData, ref VehicleStateManager.Instance.VehicleStates[vehicleID], curLaneId, position, curSegmentInfo, nextPathPos, nextSegmentInfo, next2PathPos, next2SegmentInfo, next3PathPos, next3SegmentInfo, next4PathPos);
#if BENCHMARK
                        }
#endif
                        }
                        // NON-STOCK CODE END
                    }
                }

                if (bestLaneIndex != (int)nextPathPos.m_lane)
                {
                    nextPathPos.m_lane = (byte)bestLaneIndex;
                    pathMan.m_pathUnits.m_buffer[nextPathId].SetPosition(nextPathPosIndex, nextPathPos);
#if BENCHMARK
                    using (var bm = new Benchmark(null, "AddTraffic")) {
#endif
                    // prevent multiple lane changes to the same lane from happening at the same time
                    TrafficMeasurementManager.Instance.AddTraffic(nextPathPos.m_segment, nextPathPos.m_lane
#if MEASUREDENSITY
                                                                  , VehicleStateManager.Instance.VehicleStates[vehicleID].totalLength
#endif
                                                                  , 0); // NON-STOCK CODE
#if BENCHMARK
                }
#endif
                }

                uint nextLaneId           = PathManager.GetLaneID(nextPathPos);
                NetInfo.Lane nextLaneInfo = nextSegmentInfo.m_lanes[(int)nextPathPos.m_lane];
                ushort curSegStartNodeId  = netManager.m_segments.m_buffer[(int)position.m_segment].m_startNode;
                ushort curSegEndNodeId    = netManager.m_segments.m_buffer[(int)position.m_segment].m_endNode;
                ushort nextSegStartNodeId = netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].m_startNode;
                ushort nextSegEndNodeId   = netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].m_endNode;
                if (nextSegStartNodeId != curSegStartNodeId &&
                    nextSegStartNodeId != curSegEndNodeId &&
                    nextSegEndNodeId != curSegStartNodeId &&
                    nextSegEndNodeId != curSegEndNodeId &&
                    ((netManager.m_nodes.m_buffer[(int)curSegStartNodeId].m_flags | netManager.m_nodes.m_buffer[(int)curSegEndNodeId].m_flags) & NetNode.Flags.Disabled) == NetNode.Flags.None &&
                    ((netManager.m_nodes.m_buffer[(int)nextSegStartNodeId].m_flags | netManager.m_nodes.m_buffer[(int)nextSegEndNodeId].m_flags) & NetNode.Flags.Disabled) != NetNode.Flags.None)
                {
                    this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }

                if (nextLaneInfo.m_laneType == NetInfo.LaneType.Pedestrian)
                {
                    if (vehicleID != 0 && (vehicleData.m_flags & Vehicle.Flags.Parking) == (Vehicle.Flags) 0)
                    {
                        byte inOffset  = position.m_offset;
                        byte outOffset = position.m_offset;
                        if (this.ParkVehicle(vehicleID, ref vehicleData, position, nextPathId, nextPathPosIndex << 1, out outOffset))
                        {
                            if (outOffset != inOffset)
                            {
                                if (index <= 0)
                                {
                                    vehicleData.m_pathPositionIndex = (byte)((int)vehicleData.m_pathPositionIndex & -2);
                                    vehicleData.m_lastPathOffset    = inOffset;
                                }
                                position.m_offset = outOffset;
                                pathMan.m_pathUnits.m_buffer[(int)((UIntPtr)pathId)].SetPosition(pathPosIndex >> 1, position);
                            }
                            vehicleData.m_flags |= Vehicle.Flags.Parking;
                        }
                        else
                        {
                            this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                        }
                    }
                    return;
                }

                if ((byte)(nextLaneInfo.m_laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.CargoVehicle | NetInfo.LaneType.TransportVehicle)) == 0)
                {
                    this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }

                if (nextLaneInfo.m_vehicleType != this.m_info.m_vehicleType &&
                    this.NeedChangeVehicleType(vehicleID, ref vehicleData, nextPathPos, nextLaneId, nextLaneInfo.m_vehicleType, ref targetPos0)
                    )
                {
                    float targetPos0ToRefPosSqrDist = ((Vector3)targetPos0 - refPos).sqrMagnitude;
                    if (targetPos0ToRefPosSqrDist >= minSqrDistA)
                    {
                        vehicleData.SetTargetPos(index++, targetPos0);
                    }
                    if (index <= 0)
                    {
                        while (index < max)
                        {
                            vehicleData.SetTargetPos(index++, targetPos0);
                        }
                        if (nextPathId != vehicleData.m_path)
                        {
                            Singleton <PathManager> .instance.ReleaseFirstUnit(ref vehicleData.m_path);
                        }
                        vehicleData.m_pathPositionIndex = (byte)(nextPathPosIndex << 1);
                        PathUnit.CalculatePathPositionOffset(nextLaneId, targetPos0, out vehicleData.m_lastPathOffset);
                        if (vehicleID != 0 && !this.ChangeVehicleType(vehicleID, ref vehicleData, nextPathPos, nextLaneId))
                        {
                            this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                        }
                    }
                    else
                    {
                        while (index < max)
                        {
                            vehicleData.SetTargetPos(index++, targetPos0);
                        }
                    }
                    return;
                }

                if (nextPathPos.m_segment != position.m_segment && vehicleID != 0)
                {
                    vehicleData.m_flags &= ~Vehicle.Flags.Leaving;
                }

                byte nextSegOffset = 0;
                if ((vehicleData.m_flags & Vehicle.Flags.Flying) != (Vehicle.Flags) 0)
                {
                    nextSegOffset = (byte)((nextPathPos.m_offset < 128) ? 255 : 0);
                }
                else if (curLaneId != nextLaneId && laneInfo.m_laneType != NetInfo.LaneType.CargoVehicle)
                {
                    PathUnit.CalculatePathPositionOffset(nextLaneId, targetPos0, out nextSegOffset);
                    bezier = default(Bezier3);
                    Vector3 curSegDir;
                    float   maxSpeed;
                    this.CalculateSegmentPosition(vehicleID, ref vehicleData, position, curLaneId, position.m_offset, out bezier.a, out curSegDir, out maxSpeed);
                    bool calculateNextNextPos = lastPathOffset == 0;
                    if (calculateNextNextPos)
                    {
                        if ((vehicleData.m_flags & Vehicle.Flags.Reversed) != (Vehicle.Flags) 0)
                        {
                            calculateNextNextPos = (vehicleData.m_trailingVehicle == 0);
                        }
                        else
                        {
                            calculateNextNextPos = (vehicleData.m_leadingVehicle == 0);
                        }
                    }
                    Vector3 nextSegDir;
                    float   nextMaxSpeed;
                    if (calculateNextNextPos)
                    {
                        PathUnit.Position nextNextPathPos;
                        if (!pathMan.m_pathUnits.m_buffer[nextPathId].GetNextPosition(nextPathPosIndex, out nextNextPathPos))
                        {
                            nextNextPathPos = default(PathUnit.Position);
                        }
                        this.CalculateSegmentPosition(vehicleID, ref vehicleData, nextNextPathPos, nextPathPos, nextLaneId, nextSegOffset, position, curLaneId, position.m_offset, index, out bezier.d, out nextSegDir, out nextMaxSpeed);
                    }
                    else
                    {
                        this.CalculateSegmentPosition(vehicleID, ref vehicleData, nextPathPos, nextLaneId, nextSegOffset, out bezier.d, out nextSegDir, out nextMaxSpeed);
                    }
                    if (nextMaxSpeed < 0.01f || (netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].m_flags & (NetSegment.Flags.Collapsed | NetSegment.Flags.Flooded)) != NetSegment.Flags.None)
                    {
                        if (index <= 0)
                        {
                            vehicleData.m_lastPathOffset = lastPathOffset;
                        }
                        targetPos0   = bezier.a;
                        targetPos0.w = 0f;
                        while (index < max)
                        {
                            vehicleData.SetTargetPos(index++, targetPos0);
                        }
                        return;
                    }
                    if (position.m_offset == 0)
                    {
                        curSegDir = -curSegDir;
                    }
                    if (nextSegOffset < nextPathPos.m_offset)
                    {
                        nextSegDir = -nextSegDir;
                    }
                    curSegDir.Normalize();
                    nextSegDir.Normalize();
                    float dist;
                    NetSegment.CalculateMiddlePoints(bezier.a, curSegDir, bezier.d, nextSegDir, true, true, out bezier.b, out bezier.c, out dist);
                    if (dist > 1f)
                    {
                        ushort nextNodeId;
                        if (nextSegOffset == 0)
                        {
                            nextNodeId = netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].m_startNode;
                        }
                        else if (nextSegOffset == 255)
                        {
                            nextNodeId = netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].m_endNode;
                        }
                        else
                        {
                            nextNodeId = 0;
                        }
                        float curve = 1.57079637f * (1f + Vector3.Dot(curSegDir, nextSegDir));
                        if (dist > 1f)
                        {
                            curve /= dist;
                        }
                        nextMaxSpeed = Mathf.Min(nextMaxSpeed, this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1000f, curve));
                        while (lastPathOffset < 255)
                        {
                            float distDiff = Mathf.Sqrt(minSqrDistA) - Vector3.Distance(targetPos0, refPos);
                            int   pathOffsetDelta;
                            if (distDiff < 0f)
                            {
                                pathOffsetDelta = 8;
                            }
                            else
                            {
                                pathOffsetDelta = 8 + Mathf.Max(0, Mathf.CeilToInt(distDiff * 256f / (dist + 1f)));
                            }
                            lastPathOffset = (byte)Mathf.Min((int)lastPathOffset + pathOffsetDelta, 255);
                            Vector3 bezierPos = bezier.Position((float)lastPathOffset * 0.003921569f);
                            targetPos0.Set(bezierPos.x, bezierPos.y, bezierPos.z, Mathf.Min(targetPos0.w, nextMaxSpeed));
                            float sqrMagnitude2 = (bezierPos - refPos).sqrMagnitude;
                            if (sqrMagnitude2 >= minSqrDistA)
                            {
                                if (index <= 0)
                                {
                                    vehicleData.m_lastPathOffset = lastPathOffset;
                                }
                                if (nextNodeId != 0)
                                {
                                    this.UpdateNodeTargetPos(vehicleID, ref vehicleData, nextNodeId, ref netManager.m_nodes.m_buffer[(int)nextNodeId], ref targetPos0, index);
                                }
                                vehicleData.SetTargetPos(index++, targetPos0);
                                minSqrDistA  = minSqrDistanceB;
                                refPos       = targetPos0;
                                targetPos0.w = 1000f;
                                if (index == max)
                                {
                                    return;
                                }
                            }
                        }
                    }
                }
                else
                {
                    PathUnit.CalculatePathPositionOffset(nextLaneId, targetPos0, out nextSegOffset);
                }

                if (index <= 0)
                {
                    if (nextPathPosIndex == 0)
                    {
                        Singleton <PathManager> .instance.ReleaseFirstUnit(ref vehicleData.m_path);
                    }
                    if (nextPathPosIndex >= (int)(pathMan.m_pathUnits.m_buffer[(int)((UIntPtr)nextPathId)].m_positionCount - 1) && pathMan.m_pathUnits.m_buffer[(int)((UIntPtr)nextPathId)].m_nextPathUnit == 0u && vehicleID != 0)
                    {
                        this.ArrivingToDestination(vehicleID, ref vehicleData);
                    }
                }

                pathId         = nextPathId;
                pathPosIndex   = (byte)(nextPathPosIndex << 1);
                lastPathOffset = nextSegOffset;
                if (index <= 0)
                {
                    vehicleData.m_pathPositionIndex = pathPosIndex;
                    vehicleData.m_lastPathOffset    = lastPathOffset;
                    vehicleData.m_flags             = ((vehicleData.m_flags & ~(Vehicle.Flags.OnGravel | Vehicle.Flags.Underground | Vehicle.Flags.Transition)) | nextSegmentInfo.m_setVehicleFlags);
                    if (this.LeftHandDrive(nextLaneInfo))
                    {
                        vehicleData.m_flags |= Vehicle.Flags.LeftHandDrive;
                    }
                    else
                    {
                        vehicleData.m_flags &= (Vehicle.Flags.Created | Vehicle.Flags.Deleted | Vehicle.Flags.Spawned | Vehicle.Flags.Inverted | Vehicle.Flags.TransferToTarget | Vehicle.Flags.TransferToSource | Vehicle.Flags.Emergency1 | Vehicle.Flags.Emergency2 | Vehicle.Flags.WaitingPath | Vehicle.Flags.Stopped | Vehicle.Flags.Leaving | Vehicle.Flags.Arriving | Vehicle.Flags.Reversed | Vehicle.Flags.TakingOff | Vehicle.Flags.Flying | Vehicle.Flags.Landing | Vehicle.Flags.WaitingSpace | Vehicle.Flags.WaitingCargo | Vehicle.Flags.GoingBack | Vehicle.Flags.WaitingTarget | Vehicle.Flags.Importing | Vehicle.Flags.Exporting | Vehicle.Flags.Parking | Vehicle.Flags.CustomName | Vehicle.Flags.OnGravel | Vehicle.Flags.WaitingLoading | Vehicle.Flags.Congestion | Vehicle.Flags.DummyTraffic | Vehicle.Flags.Underground | Vehicle.Flags.Transition | Vehicle.Flags.InsideBuilding);
                    }
                }
                position  = nextPathPos;
                curLaneId = nextLaneId;
                laneInfo  = nextLaneInfo;
                firstIter = false;                 // NON-STOCK CODE
            }
        }
Exemple #2
0
        public static void UpdatePathTargetPositions(VehicleAI vehicleAI, ushort vehicleID, ref Vehicle vehicleData, Vector3 refPos, ref int index, int max, float minSqrDistanceA, float minSqrDistanceB)
        {
            PathManager instance  = Singleton <PathManager> .instance;
            NetManager  instance2 = Singleton <NetManager> .instance;
            Vector4     vector    = vehicleData.m_targetPos0;

            vector.w = 1000f;
            float num  = minSqrDistanceA;
            uint  num2 = vehicleData.m_path;
            byte  b    = vehicleData.m_pathPositionIndex;
            byte  b2   = vehicleData.m_lastPathOffset;

            if (b == 255)
            {
                b = 0;
                if (index <= 0)
                {
                    vehicleData.m_pathPositionIndex = 0;
                }
                if (!Singleton <PathManager> .instance.m_pathUnits.m_buffer[(int)((UIntPtr)num2)].CalculatePathPositionOffset(b >> 1, vector, out b2))
                {
                    (vehicleAI as IVehicle).InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }
            }
            PathUnit.Position position;
            if (!instance.m_pathUnits.m_buffer[(int)((UIntPtr)num2)].GetPosition(b >> 1, out position))
            {
                (vehicleAI as IVehicle).InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                return;
            }
            NetInfo info = instance2.m_segments.m_buffer[(int)position.m_segment].Info;

            if (info.m_lanes.Length <= (int)position.m_lane)
            {
                (vehicleAI as IVehicle).InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                return;
            }
            uint num3 = PathManager.GetLaneID(position);

            NetInfo.Lane lane = info.m_lanes[(int)position.m_lane];
            Bezier3      bezier;

            while (true)
            {
                if ((b & 1) == 0)
                {
                    if (lane.m_laneType != NetInfo.LaneType.CargoVehicle)
                    {
                        bool flag = true;
                        while (b2 != position.m_offset)
                        {
                            if (flag)
                            {
                                flag = false;
                            }
                            else
                            {
                                float num4 = Mathf.Sqrt(num) - Vector3.Distance(vector, refPos);
                                int   num5;
                                if (num4 < 0f)
                                {
                                    num5 = 4;
                                }
                                else
                                {
                                    num5 = 4 + Mathf.Max(0, Mathf.CeilToInt(num4 * 256f / (instance2.m_lanes.m_buffer[(int)((UIntPtr)num3)].m_length + 1f)));
                                }
                                if (b2 > position.m_offset)
                                {
                                    b2 = (byte)Mathf.Max((int)b2 - num5, (int)position.m_offset);
                                }
                                else
                                {
                                    if (b2 < position.m_offset)
                                    {
                                        b2 = (byte)Mathf.Min((int)b2 + num5, (int)position.m_offset);
                                    }
                                }
                            }
                            Vector3 a;
                            Vector3 vector2;
                            float   b3;
                            (vehicleAI as IVehicle).CalculateSegmentPosition(vehicleID, ref vehicleData, position, num3, b2, out a, out vector2, out b3);
                            b3 = RestrictSpeed(b3, num3, vehicleData.Info);
                            vector.Set(a.x, a.y, a.z, Mathf.Min(vector.w, b3));
                            float sqrMagnitude = (a - refPos).sqrMagnitude;
                            if (sqrMagnitude >= num)
                            {
                                if (index <= 0)
                                {
                                    vehicleData.m_lastPathOffset = b2;
                                }
                                vehicleData.SetTargetPos(index++, vector);
                                num      = minSqrDistanceB;
                                refPos   = vector;
                                vector.w = 1000f;
                                if (index == max)
                                {
                                    return;
                                }
                            }
                        }
                    }
                    b += 1;
                    b2 = 0;
                    if (index <= 0)
                    {
                        vehicleData.m_pathPositionIndex = b;
                        vehicleData.m_lastPathOffset    = b2;
                    }
                }
                int  num6 = (b >> 1) + 1;
                uint num7 = num2;
                if (num6 >= (int)instance.m_pathUnits.m_buffer[(int)((UIntPtr)num2)].m_positionCount)
                {
                    num6 = 0;
                    num7 = instance.m_pathUnits.m_buffer[(int)((UIntPtr)num2)].m_nextPathUnit;
                    if (num7 == 0u)
                    {
                        if (index <= 0)
                        {
                            Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path);

                            vehicleData.m_path = 0u;
                        }
                        vector.w = 1f;
                        vehicleData.SetTargetPos(index++, vector);
                        return;
                    }
                }
                PathUnit.Position position2;
                if (!instance.m_pathUnits.m_buffer[(int)((UIntPtr)num7)].GetPosition(num6, out position2))
                {
                    (vehicleAI as IVehicle).InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }
                NetInfo info2 = instance2.m_segments.m_buffer[(int)position2.m_segment].Info;
                if (info2.m_lanes.Length <= (int)position2.m_lane)
                {
                    (vehicleAI as IVehicle).InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }
                uint         laneID     = PathManager.GetLaneID(position2);
                NetInfo.Lane lane2      = info2.m_lanes[(int)position2.m_lane];
                ushort       startNode  = instance2.m_segments.m_buffer[(int)position.m_segment].m_startNode;
                ushort       endNode    = instance2.m_segments.m_buffer[(int)position.m_segment].m_endNode;
                ushort       startNode2 = instance2.m_segments.m_buffer[(int)position2.m_segment].m_startNode;
                ushort       endNode2   = instance2.m_segments.m_buffer[(int)position2.m_segment].m_endNode;
                if (startNode2 != startNode && startNode2 != endNode && endNode2 != startNode && endNode2 != endNode && ((instance2.m_nodes.m_buffer[(int)startNode].m_flags | instance2.m_nodes.m_buffer[(int)endNode].m_flags) & NetNode.Flags.Disabled) == NetNode.Flags.None && ((instance2.m_nodes.m_buffer[(int)startNode2].m_flags | instance2.m_nodes.m_buffer[(int)endNode2].m_flags) & NetNode.Flags.Disabled) != NetNode.Flags.None)
                {
                    (vehicleAI as IVehicle).InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }
                if (lane2.m_laneType == NetInfo.LaneType.Pedestrian)
                {
                    if (vehicleID != 0 && (vehicleData.m_flags & Vehicle.Flags.Parking) == Vehicle.Flags.None)
                    {
                        byte offset  = position.m_offset;
                        byte offset2 = position.m_offset;
                        if ((vehicleAI as IVehicle).ParkVehicle(vehicleID, ref vehicleData, position, num7, num6 << 1, out offset2))
                        {
                            if (offset2 != offset)
                            {
                                if (index <= 0)
                                {
                                    vehicleData.m_pathPositionIndex = (byte)((int)vehicleData.m_pathPositionIndex & -2);
                                    vehicleData.m_lastPathOffset    = offset;
                                }
                                position.m_offset = offset2;
                                instance.m_pathUnits.m_buffer[(int)((UIntPtr)num2)].SetPosition(b >> 1, position);
                            }
                            vehicleData.m_flags |= Vehicle.Flags.Parking;
                        }
                        else
                        {
                            (vehicleAI as IVehicle).InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                        }
                    }
                    return;
                }
                if ((byte)(lane2.m_laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.CargoVehicle | NetInfo.LaneType.TransportVehicle)) == 0)
                {
                    (vehicleAI as IVehicle).InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }
                if (lane2.m_vehicleType != vehicleAI.m_info.m_vehicleType && (vehicleAI as IVehicle).NeedChangeVehicleType(vehicleID, ref vehicleData, position2, laneID, lane2.m_vehicleType, ref vector))
                {
                    float sqrMagnitude3 = (vector - (Vector4)refPos).sqrMagnitude;
                    if (sqrMagnitude3 >= num)
                    {
                        vehicleData.SetTargetPos(index++, vector);
                    }
                    if (index <= 0)
                    {
                        if (num6 == 0)
                        {
                            Singleton <PathManager> .instance.ReleaseFirstUnit(ref vehicleData.m_path);
                        }
                        vehicleData.m_pathPositionIndex = (byte)(num6 << 1);
                        PathUnit.CalculatePathPositionOffset(laneID, vector, out vehicleData.m_lastPathOffset);
                        if (vehicleID != 0 && !(vehicleAI as IVehicle).ChangeVehicleType(vehicleID, ref vehicleData, position2, laneID))
                        {
                            (vehicleAI as IVehicle).InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                        }
                    }
                    return;
                }
                if (position2.m_segment != position.m_segment && vehicleID != 0)
                {
                    vehicleData.m_flags &= ~Vehicle.Flags.Leaving;
                }
                byte b4 = 0;
                if ((vehicleData.m_flags & Vehicle.Flags.Flying) != Vehicle.Flags.None)
                {
                    b4 = (byte)((position2.m_offset < 128) ? 255 : 0);
                }
                else
                {
                    if (num3 != laneID && lane.m_laneType != NetInfo.LaneType.CargoVehicle)
                    {
                        PathUnit.CalculatePathPositionOffset(laneID, vector, out b4);
                        bezier = default(Bezier3);
                        Vector3 vector3;
                        float   num8;
                        (vehicleAI as IVehicle).CalculateSegmentPosition(vehicleID, ref vehicleData, position, num3, position.m_offset, out bezier.a, out vector3, out num8);
                        num8 = RestrictSpeed(num8, num3, vehicleData.Info);
                        bool flag2 = b2 == 0;
                        if (flag2)
                        {
                            if ((vehicleData.m_flags & Vehicle.Flags.Reversed) != Vehicle.Flags.None)
                            {
                                flag2 = (vehicleData.m_trailingVehicle == 0);
                            }
                            else
                            {
                                flag2 = (vehicleData.m_leadingVehicle == 0);
                            }
                        }
                        Vector3 vector4;
                        float   num9;
                        if (flag2)
                        {
                            PathUnit.Position nextPosition;
                            if (!instance.m_pathUnits.m_buffer[(int)((UIntPtr)num7)].GetNextPosition(num6, out nextPosition))
                            {
                                nextPosition = default(PathUnit.Position);
                            }
                            (vehicleAI as IVehicle).CalculateSegmentPosition(vehicleID, ref vehicleData, nextPosition, position2, laneID, b4, position, num3, position.m_offset, out bezier.d, out vector4, out num9);
                            num9 = RestrictSpeed(num9, laneID, vehicleData.Info);
                        }
                        else
                        {
                            (vehicleAI as IVehicle).CalculateSegmentPosition(vehicleID, ref vehicleData, position2, laneID, b4, out bezier.d, out vector4, out num9);
                            num9 = RestrictSpeed(num9, laneID, vehicleData.Info);
                        }
                        if (num9 < 0.01f || (instance2.m_segments.m_buffer[(int)position2.m_segment].m_flags & NetSegment.Flags.Flooded) != NetSegment.Flags.None)
                        {
                            if (index <= 0)
                            {
                                vehicleData.m_lastPathOffset = b2;
                            }
                            vector   = bezier.a;
                            vector.w = 0f;
                            while (index < max)
                            {
                                vehicleData.SetTargetPos(index++, vector);
                            }
                        }
                        if (position.m_offset == 0)
                        {
                            vector3 = -vector3;
                        }
                        if (b4 < position2.m_offset)
                        {
                            vector4 = -vector4;
                        }
                        vector3.Normalize();
                        vector4.Normalize();
                        float num10;
                        NetSegment.CalculateMiddlePoints(bezier.a, vector3, bezier.d, vector4, true, true, out bezier.b, out bezier.c, out num10);
                        if (num10 > 1f)
                        {
                            ushort num11;
                            if (b4 == 0)
                            {
                                num11 = instance2.m_segments.m_buffer[(int)position2.m_segment].m_startNode;
                            }
                            else
                            {
                                if (b4 == 255)
                                {
                                    num11 = instance2.m_segments.m_buffer[(int)position2.m_segment].m_endNode;
                                }
                                else
                                {
                                    num11 = 0;
                                }
                            }
                            float num12 = 1.57079637f * (1f + Vector3.Dot(vector3, vector4));
                            if (num10 > 1f)
                            {
                                num12 /= num10;
                            }
                            num9 = Mathf.Min(num9, (vehicleAI as IVehicle).CalculateTargetSpeed(vehicleID, ref vehicleData, 1000f, num12));
                            while (b2 < 255)
                            {
                                float num13 = Mathf.Sqrt(num) - Vector3.Distance(vector, refPos);
                                int   num14;
                                if (num13 < 0f)
                                {
                                    num14 = 8;
                                }
                                else
                                {
                                    num14 = 8 + Mathf.Max(0, Mathf.CeilToInt(num13 * 256f / (num10 + 1f)));
                                }
                                b2 = (byte)Mathf.Min((int)b2 + num14, 255);
                                Vector3 a2 = bezier.Position((float)b2 * 0.003921569f);
                                vector.Set(a2.x, a2.y, a2.z, Mathf.Min(vector.w, num9));
                                float sqrMagnitude2 = (a2 - refPos).sqrMagnitude;
                                if (sqrMagnitude2 >= num)
                                {
                                    if (index <= 0)
                                    {
                                        vehicleData.m_lastPathOffset = b2;
                                    }
                                    if (num11 != 0)
                                    {
                                        (vehicleAI as IVehicle).UpdateNodeTargetPos(vehicleID, ref vehicleData, num11, ref instance2.m_nodes.m_buffer[(int)num11], ref vector, index);
                                    }
                                    vehicleData.SetTargetPos(index++, vector);
                                    num      = minSqrDistanceB;
                                    refPos   = vector;
                                    vector.w = 1000f;
                                    if (index == max)
                                    {
                                        return;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        PathUnit.CalculatePathPositionOffset(laneID, vector, out b4);
                    }
                }
                if (index <= 0)
                {
                    if (num6 == 0)
                    {
                        Singleton <PathManager> .instance.ReleaseFirstUnit(ref vehicleData.m_path);
                    }
                    if (num6 >= (int)(instance.m_pathUnits.m_buffer[(int)((UIntPtr)num7)].m_positionCount - 1) && instance.m_pathUnits.m_buffer[(int)((UIntPtr)num7)].m_nextPathUnit == 0u && vehicleID != 0)
                    {
                        (vehicleAI as IVehicle).ArrivingToDestination(vehicleID, ref vehicleData);
                    }
                }
                num2 = num7;
                b    = (byte)(num6 << 1);
                b2   = b4;
                if (index <= 0)
                {
                    vehicleData.m_pathPositionIndex = b;
                    vehicleData.m_lastPathOffset    = b2;
                    vehicleData.m_flags             = ((vehicleData.m_flags & ~(Vehicle.Flags.OnGravel | Vehicle.Flags.Underground | Vehicle.Flags.Transition)) | info2.m_setVehicleFlags);
                }
                position = position2;
                num3     = laneID;
                lane     = lane2;
            }
        }
        private static void ResetTargets(ushort vehicleID, ref Vehicle vehicleData, ushort leaderID, ref Vehicle leaderData, bool pushPathPos)
        {
            Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData();
            VehicleInfo   info          = vehicleData.Info;
            TrainAI       trainAI       = info.m_vehicleAI as TrainAI;
            Vector3       vector        = lastFrameData.m_position;
            Vector3       vector2       = lastFrameData.m_position;
            Vector3       b             = lastFrameData.m_rotation * new Vector3(0f, 0f, info.m_generatedInfo.m_wheelBase * 0.5f);

            if ((leaderData.m_flags & Vehicle.Flags.Reversed) != Vehicle.Flags.None)
            {
                vector  -= b;
                vector2 += b;
            }
            else
            {
                vector  += b;
                vector2 -= b;
            }
            vehicleData.m_targetPos0   = vector2;
            vehicleData.m_targetPos0.w = 2f;
            vehicleData.m_targetPos1   = vector;
            vehicleData.m_targetPos1.w = 2f;
            vehicleData.m_targetPos2   = vehicleData.m_targetPos1;
            vehicleData.m_targetPos3   = vehicleData.m_targetPos1;
            if (vehicleData.m_path != 0u)
            {
                PathManager instance = Singleton <PathManager> .instance;
                int         num      = (vehicleData.m_pathPositionIndex >> 1) + 1;
                uint        num2     = vehicleData.m_path;
                if (num >= (int)instance.m_pathUnits.m_buffer [(int)((UIntPtr)num2)].m_positionCount)
                {
                    num  = 0;
                    num2 = instance.m_pathUnits.m_buffer [(int)((UIntPtr)num2)].m_nextPathUnit;
                }
                PathUnit.Position pathPos;
                if (instance.m_pathUnits.m_buffer [(int)((UIntPtr)vehicleData.m_path)].GetPosition(vehicleData.m_pathPositionIndex >> 1, out pathPos))
                {
                    uint laneID = PathManager.GetLaneID(pathPos);
                    PathUnit.Position pathPos2;
                    if (num2 != 0u && instance.m_pathUnits.m_buffer [(int)((UIntPtr)num2)].GetPosition(num, out pathPos2))
                    {
                        uint laneID2 = PathManager.GetLaneID(pathPos2);
                        if (laneID2 == laneID)
                        {
                            if (num2 != vehicleData.m_path)
                            {
                                instance.ReleaseFirstUnit(ref vehicleData.m_path);
                            }
                            vehicleData.m_pathPositionIndex = (byte)(num << 1);
                        }
                    }
                    PathUnit.CalculatePathPositionOffset(laneID, vector2, out vehicleData.m_lastPathOffset);
                }
            }
            if (vehicleData.m_path != 0u)
            {
                int num3 = 0;
                ((FakeTrainAI)trainAI).UpdatePathTargetPositions(vehicleID, ref vehicleData, vector2, vector, 0, ref leaderData, ref num3, 1, 4, 4f, 1f);
            }
        }
        //from source code
        protected void UpdatePathTargetPositions(ushort vehicleID, ref Vehicle vehicleData, Vector3 refPos1, Vector3 refPos2, ushort leaderID, ref Vehicle leaderData, ref int index, int max1, int max2, float minSqrDistanceA, float minSqrDistanceB)
        {
            PathManager instance  = Singleton <PathManager> .instance;
            NetManager  instance2 = Singleton <NetManager> .instance;

            Vector4 vector = vehicleData.m_targetPos0;

            vector.w = 1000f;
            float num  = minSqrDistanceA;
            float num2 = 0f;
            uint  num3 = vehicleData.m_path;
            byte  b    = vehicleData.m_pathPositionIndex;
            byte  b2   = vehicleData.m_lastPathOffset;

            if (b == 255)
            {
                b = 0;
                if (index <= 0)
                {
                    vehicleData.m_pathPositionIndex = 0;
                }
                if (!Singleton <PathManager> .instance.m_pathUnits.m_buffer[(int)((UIntPtr)num3)].CalculatePathPositionOffset(b >> 1, vector, out b2))
                {
                    this.InvalidPath(vehicleID, ref vehicleData, leaderID, ref leaderData);
                    return;
                }
            }
            PathUnit.Position position;
            if (!instance.m_pathUnits.m_buffer[(int)((UIntPtr)num3)].GetPosition(b >> 1, out position))
            {
                this.InvalidPath(vehicleID, ref vehicleData, leaderID, ref leaderData);
                return;
            }
            uint num4 = PathManager.GetLaneID(position);
            //try to notify for all vehicles composing the train. however, UpdatePathTargetPositions is not called when train is stopped
            //this.NotifySingleTrack2Ways(vehicleID, vehicleData, num4);
            Bezier3 bezier;

            while (true)
            {
                if ((b & 1) == 0) //is pathPositionIndex even?
                {
                    bool flag = true;
                    while (b2 != position.m_offset)
                    {
                        if (flag)
                        {
                            flag = false;
                        }
                        else
                        {
                            float num5 = Mathf.Max(Mathf.Sqrt(num) - Vector3.Distance(vector, refPos1), Mathf.Sqrt(num2) - Vector3.Distance(vector, refPos2));
                            int   num6;
                            if (num5 < 0f)
                            {
                                num6 = 4;
                            }
                            else
                            {
                                num6 = 4 + Mathf.CeilToInt(num5 * 256f / (instance2.m_lanes.m_buffer[(int)((UIntPtr)num4)].m_length + 1f));
                            }
                            if (b2 > position.m_offset)
                            {
                                b2 = (byte)Mathf.Max((int)b2 - num6, (int)position.m_offset);
                            }
                            else if (b2 < position.m_offset)
                            {
                                b2 = (byte)Mathf.Min((int)b2 + num6, (int)position.m_offset);
                            }
                        }
                        Vector3 a;
                        Vector3 vector2;
                        float   b3;
                        this.CalculateSegmentPosition(vehicleID, ref vehicleData, position, num4, b2, out a, out vector2, out b3);
                        vector.Set(a.x, a.y, a.z, Mathf.Min(vector.w, b3));
                        float sqrMagnitude  = (a - refPos1).sqrMagnitude;
                        float sqrMagnitude2 = (a - refPos2).sqrMagnitude;
                        if (sqrMagnitude >= num && sqrMagnitude2 >= num2)
                        {
                            if (index <= 0)
                            {
                                vehicleData.m_lastPathOffset = b2;
                            }
                            vehicleData.SetTargetPos(index++, vector);
                            if (index < max1)
                            {
                                num     = minSqrDistanceB;
                                refPos1 = vector;
                            }
                            else if (index == max1)
                            {
                                num  = (refPos2 - refPos1).sqrMagnitude;
                                num2 = minSqrDistanceA;
                            }
                            else
                            {
                                num2    = minSqrDistanceB;
                                refPos2 = vector;
                            }
                            vector.w = 1000f;
                            if (index == max2)
                            {
                                return;
                            }
                        }
                    }
                    b += 1;
                    b2 = 0;
                    if (index <= 0)
                    {
                        vehicleData.m_pathPositionIndex = b;
                        vehicleData.m_lastPathOffset    = b2;
                    }
                }
                int  num7 = (b >> 1) + 1; //pathPositionIndex is divided by 2 to get the final position index
                uint num8 = num3;
                if (num7 >= (int)instance.m_pathUnits.m_buffer[(int)((UIntPtr)num3)].m_positionCount)
                {
                    num7 = 0;
                    num8 = instance.m_pathUnits.m_buffer[(int)((UIntPtr)num3)].m_nextPathUnit;
                    if (num8 == 0u)
                    {
                        goto Block_19;
                    }
                }
                PathUnit.Position position2;
                if (!instance.m_pathUnits.m_buffer[(int)((UIntPtr)num8)].GetPosition(num7, out position2))
                {
                    goto Block_21;
                }
                NetInfo info = instance2.m_segments.m_buffer[(int)position2.m_segment].Info;
                if (info.m_lanes.Length <= (int)position2.m_lane)
                {
                    goto Block_22;
                }
                uint         laneID = PathManager.GetLaneID(position2);
                NetInfo.Lane lane   = info.m_lanes[(int)position2.m_lane];
                if (lane.m_laneType != NetInfo.LaneType.Vehicle)
                {
                    goto Block_23;
                }
                if (position2.m_segment != position.m_segment && leaderID != 0)
                {
                    leaderData.m_flags &= ~Vehicle.Flags.Leaving;
                }
                byte b4 = 0;

                if (num4 != laneID) //num4 is last path lane, laneID is the new one. This triggers checkNextLane.
                {
                    PathUnit.CalculatePathPositionOffset(laneID, vector, out b4);
                    bezier = default(Bezier3);
                    Vector3 vector3;
                    float   num9;
                    this.CalculateSegmentPosition(vehicleID, ref vehicleData, position, num4, position.m_offset, out bezier.a, out vector3, out num9);
                    bool flag2;
                    //checkNextLane only for the vehicle in front of the train
                    if ((leaderData.m_flags & Vehicle.Flags.Reversed) != (Vehicle.Flags) 0)
                    {
                        flag2 = (vehicleData.m_trailingVehicle == 0);
                    }
                    else
                    {
                        flag2 = (vehicleData.m_leadingVehicle == 0);
                    }

                    bool    flag3 = flag2 && b2 == 0;
                    Vector3 vector4;
                    float   num10;
                    this.CalculateSegmentPosition(vehicleID, ref vehicleData, position2, laneID, b4, out bezier.d, out vector4, out num10);
                    if (position.m_offset == 0)
                    {
                        vector3 = -vector3;
                    }
                    if (b4 < position2.m_offset)
                    {
                        vector4 = -vector4;
                    }
                    vector3.Normalize();
                    vector4.Normalize();
                    float num11;
                    NetSegment.CalculateMiddlePoints(bezier.a, vector3, bezier.d, vector4, true, true, out bezier.b, out bezier.c, out num11);

                    if (flag3)
                    {
                        bool mayNeedFix = false;
                        if (!this.CheckSingleTrack2Ways(vehicleID, vehicleData, ref num10, laneID, num4, ref mayNeedFix))
                        {
                            float savedMaxSpeed = num10;
                            this.CheckNextLane(vehicleID, ref vehicleData, ref num10, position2, laneID, b4, position, num4, position.m_offset, bezier);

                            //address bug where some train are blocked after reversing at a single train track station
                            if (Mod.fixReverseTrainSingleTrackStation && mayNeedFix && num10 < 0.01f)
                            {
                                ushort vehiclePreviouslyReservingSpace = leaderID;
                                if ((leaderData.m_flags & Vehicle.Flags.Reversed) != (Vehicle.Flags) 0)
                                {
                                    //vehiclePreviouslyReservingSpace = vehicleData.GetFirstVehicle(vehicleID);
                                    //CODebug.Log(LogChannel.Modding, Mod.modName + " - attempt fix(1) " + instance2.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CheckSpace(1000f, vehiclePreviouslyReservingSpace));

                                    //try checkspace again with carriage at the other end of the train (the one who has, by supposition, reserved the space previously)
                                    if (instance2.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CheckSpace(1000f, vehiclePreviouslyReservingSpace))
                                    {
                                        num10 = savedMaxSpeed;
                                    }
                                    else
                                    {
                                        Segment3 segment = new Segment3(bezier.Position(0.5f), bezier.d);
                                        //CODebug.Log(LogChannel.Modding, Mod.modName + " - attempt fix(2) " + CheckOverlap(vehicleID, ref vehicleData, segment, vehiclePreviouslyReservingSpace));

                                        if (CheckOverlap(vehicleID, ref vehicleData, segment, vehiclePreviouslyReservingSpace))
                                        {
                                            num10 = savedMaxSpeed;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (flag2 && (num10 < 0.01f || (instance2.m_segments.m_buffer[(int)position2.m_segment].m_flags & (NetSegment.Flags.Collapsed | NetSegment.Flags.Flooded)) != NetSegment.Flags.None))
                    {
                        goto IL_595;
                    }
                    if (num11 > 1f)
                    {
                        ushort num12;
                        if (b4 == 0)
                        {
                            num12 = instance2.m_segments.m_buffer[(int)position2.m_segment].m_startNode;
                        }
                        else if (b4 == 255)
                        {
                            num12 = instance2.m_segments.m_buffer[(int)position2.m_segment].m_endNode;
                        }
                        else
                        {
                            num12 = 0;
                        }
                        float num13 = 1.57079637f * (1f + Vector3.Dot(vector3, vector4));
                        if (num11 > 1f)
                        {
                            num13 /= num11;
                        }
                        num10 = Mathf.Min(num10, this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1000f, num13));

                        while (b2 < 255)
                        {
                            float num14 = Mathf.Max(Mathf.Sqrt(num) - Vector3.Distance(vector, refPos1), Mathf.Sqrt(num2) - Vector3.Distance(vector, refPos2));
                            int   num15;
                            if (num14 < 0f)
                            {
                                num15 = 8;
                            }
                            else
                            {
                                num15 = 8 + Mathf.CeilToInt(num14 * 256f / (num11 + 1f));
                            }
                            b2 = (byte)Mathf.Min((int)b2 + num15, 255);
                            Vector3 a2 = bezier.Position((float)b2 * 0.003921569f);
                            vector.Set(a2.x, a2.y, a2.z, Mathf.Min(vector.w, num10));
                            float sqrMagnitude3 = (a2 - refPos1).sqrMagnitude;
                            float sqrMagnitude4 = (a2 - refPos2).sqrMagnitude;
                            if (sqrMagnitude3 >= num && sqrMagnitude4 >= num2)
                            {
                                if (index <= 0)
                                {
                                    vehicleData.m_lastPathOffset = b2;
                                }
                                if (num12 != 0)
                                {
                                    this.UpdateNodeTargetPos(vehicleID, ref vehicleData, num12, ref instance2.m_nodes.m_buffer[(int)num12], ref vector, index);
                                }
                                vehicleData.SetTargetPos(index++, vector);
                                if (index < max1)
                                {
                                    num     = minSqrDistanceB;
                                    refPos1 = vector;
                                }
                                else if (index == max1)
                                {
                                    num  = (refPos2 - refPos1).sqrMagnitude;
                                    num2 = minSqrDistanceA;
                                }
                                else
                                {
                                    num2    = minSqrDistanceB;
                                    refPos2 = vector;
                                }
                                vector.w = 1000f;
                                if (index == max2)
                                {
                                    return;
                                }
                            }
                        }
                    }
                }
                else
                {
                    PathUnit.CalculatePathPositionOffset(laneID, vector, out b4);
                }
                if (index <= 0)
                {
                    if (num7 == 0)
                    {
                        Singleton <PathManager> .instance.ReleaseFirstUnit(ref vehicleData.m_path);
                    }
                    if (num7 >= (int)(instance.m_pathUnits.m_buffer[(int)((UIntPtr)num8)].m_positionCount - 1) && instance.m_pathUnits.m_buffer[(int)((UIntPtr)num8)].m_nextPathUnit == 0u && leaderID != 0)
                    {
                        this.ArrivingToDestination(leaderID, ref leaderData);
                    }
                }
                num3 = num8;
                b    = (byte)(num7 << 1);
                b2   = b4;
                if (index <= 0)
                {
                    vehicleData.m_pathPositionIndex = b;
                    vehicleData.m_lastPathOffset    = b2;
                    vehicleData.m_flags             = ((vehicleData.m_flags & ~(Vehicle.Flags.OnGravel | Vehicle.Flags.Underground | Vehicle.Flags.Transition)) | info.m_setVehicleFlags);
                    if ((vehicleData.m_flags2 & Vehicle.Flags2.Yielding) != (Vehicle.Flags2) 0)
                    {
                        vehicleData.m_flags2     &= ~Vehicle.Flags2.Yielding;
                        vehicleData.m_waitCounter = 0;
                    }
                }
                position = position2;
                num4     = laneID;
            }
            return;

Block_19:
            if (index <= 0)
            {
                Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path);

                vehicleData.m_path = 0u;
            }
            vector.w = 1f;
            vehicleData.SetTargetPos(index++, vector);
            return;

Block_21:
            this.InvalidPath(vehicleID, ref vehicleData, leaderID, ref leaderData);
            return;

Block_22:
            this.InvalidPath(vehicleID, ref vehicleData, leaderID, ref leaderData);
            return;

Block_23:
            this.InvalidPath(vehicleID, ref vehicleData, leaderID, ref leaderData);
            return;

IL_595:
            if (index <= 0)
            {
                vehicleData.m_lastPathOffset = b2;
            }
            vector   = bezier.a;
            vector.w = 0f;
            while (index < max2)
            {
                vehicleData.SetTargetPos(index++, vector);
            }
        }
        protected void CustomUpdatePathTargetPositions(ushort vehicleID, ref Vehicle vehicleData, Vector3 refPos, ref int targetPosIndex, int maxTargetPosIndex, float minSqrDistanceA, float minSqrDistanceB)
        {
            PathManager pathMan    = Singleton <PathManager> .instance;
            NetManager  netManager = Singleton <NetManager> .instance;

            Vector4 targetPos = vehicleData.m_targetPos0;

            targetPos.w = 1000f;
            float minSqrDistA      = minSqrDistanceA;
            uint  pathId           = vehicleData.m_path;
            byte  finePathPosIndex = vehicleData.m_pathPositionIndex;
            byte  lastPathOffset   = vehicleData.m_lastPathOffset;

            // initial position
            if (finePathPosIndex == 255)
            {
                finePathPosIndex = 0;
                if (targetPosIndex <= 0)
                {
                    vehicleData.m_pathPositionIndex = 0;
                }

                if (!Singleton <PathManager> .instance.m_pathUnits.m_buffer[pathId].CalculatePathPositionOffset(finePathPosIndex >> 1, targetPos, out lastPathOffset))
                {
                    this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }
            }

            // get current path position, check for errors
            PathUnit.Position currentPosition;
            if (!pathMan.m_pathUnits.m_buffer[pathId].GetPosition(finePathPosIndex >> 1, out currentPosition))
            {
                this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                return;
            }

            // get current segment info, check for errors
            NetInfo curSegmentInfo = netManager.m_segments.m_buffer[(int)currentPosition.m_segment].Info;

            if (curSegmentInfo.m_lanes.Length <= (int)currentPosition.m_lane)
            {
                this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                return;
            }

            // main loop
            uint curLaneId = PathManager.GetLaneID(currentPosition);

            NetInfo.Lane laneInfo = curSegmentInfo.m_lanes[(int)currentPosition.m_lane];
            Bezier3      bezier;
            bool         firstIter = true;     // NON-STOCK CODE

            while (true)
            {
                if ((finePathPosIndex & 1) == 0)
                {
                    // vehicle is not in transition
                    if (laneInfo.m_laneType != NetInfo.LaneType.CargoVehicle)
                    {
                        bool first = true;
                        while (lastPathOffset != currentPosition.m_offset)
                        {
                            // catch up and update target position until we get to the current segment offset
                            if (first)
                            {
                                first = false;
                            }
                            else
                            {
                                float distDiff = Mathf.Sqrt(minSqrDistA) - Vector3.Distance(targetPos, refPos);
                                int   pathOffsetDelta;
                                if (distDiff < 0f)
                                {
                                    pathOffsetDelta = 4;
                                }
                                else
                                {
                                    pathOffsetDelta = 4 + Mathf.Max(0, Mathf.CeilToInt(distDiff * 256f / (netManager.m_lanes.m_buffer[curLaneId].m_length + 1f)));
                                }
                                if (lastPathOffset > currentPosition.m_offset)
                                {
                                    lastPathOffset = (byte)Mathf.Max((int)lastPathOffset - pathOffsetDelta, (int)currentPosition.m_offset);
                                }
                                else if (lastPathOffset < currentPosition.m_offset)
                                {
                                    lastPathOffset = (byte)Mathf.Min((int)lastPathOffset + pathOffsetDelta, (int)currentPosition.m_offset);
                                }
                            }

                            Vector3 curSegPos;
                            Vector3 curSegDir;
                            float   curSegOffset;
                            this.CalculateSegmentPosition(vehicleID, ref vehicleData, currentPosition, curLaneId, lastPathOffset, out curSegPos, out curSegDir, out curSegOffset);
                            targetPos.Set(curSegPos.x, curSegPos.y, curSegPos.z, Mathf.Min(targetPos.w, curSegOffset));
                            float refPosSqrDist = (curSegPos - refPos).sqrMagnitude;
                            if (refPosSqrDist >= minSqrDistA)
                            {
                                if (targetPosIndex <= 0)
                                {
                                    vehicleData.m_lastPathOffset = lastPathOffset;
                                }
                                vehicleData.SetTargetPos(targetPosIndex++, targetPos);
                                minSqrDistA = minSqrDistanceB;
                                refPos      = targetPos;
                                targetPos.w = 1000f;
                                if (targetPosIndex == maxTargetPosIndex)
                                {
                                    // maximum target position index reached
                                    return;
                                }
                            }
                        }
                    }

                    // set vehicle in transition
                    finePathPosIndex += 1;
                    lastPathOffset    = 0;
                    if (targetPosIndex <= 0)
                    {
                        vehicleData.m_pathPositionIndex = finePathPosIndex;
                        vehicleData.m_lastPathOffset    = lastPathOffset;
                    }
                }

                if ((vehicleData.m_flags2 & Vehicle.Flags2.EndStop) != 0)
                {
                    if (targetPosIndex <= 0)
                    {
                        targetPos.w = 0f;
                        if (VectorUtils.LengthSqrXZ(vehicleData.GetLastFrameVelocity()) < 0.01f)
                        {
                            vehicleData.m_flags2 &= ~Vehicle.Flags2.EndStop;
                        }
                    }
                    else
                    {
                        targetPos.w = 1f;
                    }
                    while (targetPosIndex < maxTargetPosIndex)
                    {
                        vehicleData.SetTargetPos(targetPosIndex++, targetPos);
                    }
                    return;
                }

                // vehicle is in transition now

                /*
                 * coarse path position format: 0..11 (always equals 'fine path position' / 2 == 'fine path position' >> 1)
                 * fine path position format: 0..23
                 */

                // find next path unit (or abort if at path end)
                int  nextCoarsePathPosIndex = (finePathPosIndex >> 1) + 1;
                uint nextPathId             = pathId;
                if (nextCoarsePathPosIndex >= (int)pathMan.m_pathUnits.m_buffer[pathId].m_positionCount)
                {
                    nextCoarsePathPosIndex = 0;
                    nextPathId             = pathMan.m_pathUnits.m_buffer[pathId].m_nextPathUnit;
                    if (nextPathId == 0u)
                    {
                        if (targetPosIndex <= 0)
                        {
                            Singleton <PathManager> .instance.ReleasePath(vehicleData.m_path);

                            vehicleData.m_path = 0u;
                        }
                        targetPos.w = 1f;
                        vehicleData.SetTargetPos(targetPosIndex++, targetPos);
                        return;
                    }
                }

                // check for errors
                PathUnit.Position nextPathPos;
                if (!pathMan.m_pathUnits.m_buffer[nextPathId].GetPosition(nextCoarsePathPosIndex, out nextPathPos))
                {
                    this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }

                // check for errors
                NetInfo nextSegmentInfo = netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].Info;
                if (nextSegmentInfo.m_lanes.Length <= (int)nextPathPos.m_lane)
                {
                    this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }

                // find next lane (emergency vehicles / dynamic lane selection)
                int bestLaneIndex = nextPathPos.m_lane;
                if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) != (Vehicle.Flags) 0)
                {
#if ROUTING
                    bestLaneIndex = VehicleBehaviorManager.Instance.FindBestEmergencyLane(vehicleID, ref vehicleData, ref VehicleStateManager.Instance.VehicleStates[vehicleID], curLaneId, currentPosition, curSegmentInfo, nextPathPos, nextSegmentInfo);
#else
                    // stock procedure for emergency vehicles on duty
                    bestLaneIndex = FindBestLane(vehicleID, ref vehicleData, nextPathPos);
#endif
                }
                else if (VehicleBehaviorManager.Instance.MayFindBestLane(vehicleID, ref vehicleData, ref VehicleStateManager.Instance.VehicleStates[vehicleID]))
                {
                    // NON-STOCK CODE START
                    if (firstIter &&
                        this.m_info.m_vehicleType == VehicleInfo.VehicleType.Car &&
                        !this.m_info.m_isLargeVehicle
                        )
                    {
                        uint next2PathId       = nextPathId;
                        int  next2PathPosIndex = nextCoarsePathPosIndex;
                        bool next2Invalid;
                        PathUnit.Position next2PathPos;
                        NetInfo           next2SegmentInfo = null;
                        PathUnit.Position next3PathPos;
                        NetInfo           next3SegmentInfo = null;
                        PathUnit.Position next4PathPos;
                        if (PathUnit.GetNextPosition(ref next2PathId, ref next2PathPosIndex, out next2PathPos, out next2Invalid))
                        {
                            next2SegmentInfo = netManager.m_segments.m_buffer[(int)next2PathPos.m_segment].Info;

                            uint next3PathId       = next2PathId;
                            int  next3PathPosIndex = next2PathPosIndex;
                            bool next3Invalid;
                            if (PathUnit.GetNextPosition(ref next3PathId, ref next3PathPosIndex, out next3PathPos, out next3Invalid))
                            {
                                next3SegmentInfo = netManager.m_segments.m_buffer[(int)next3PathPos.m_segment].Info;

                                uint next4PathId       = next3PathId;
                                int  next4PathPosIndex = next3PathPosIndex;
                                bool next4Invalid;
                                if (!PathUnit.GetNextPosition(ref next4PathId, ref next4PathPosIndex, out next4PathPos, out next4Invalid))
                                {
                                    next4PathPos = default(PathUnit.Position);
                                }
                            }
                            else
                            {
                                next3PathPos = default(PathUnit.Position);
                                next4PathPos = default(PathUnit.Position);
                            }
                        }
                        else
                        {
                            next2PathPos = default(PathUnit.Position);
                            next3PathPos = default(PathUnit.Position);
                            next4PathPos = default(PathUnit.Position);
                        }

                        bestLaneIndex = VehicleBehaviorManager.Instance.FindBestLane(vehicleID, ref vehicleData, ref VehicleStateManager.Instance.VehicleStates[vehicleID], curLaneId, currentPosition, curSegmentInfo, nextPathPos, nextSegmentInfo, next2PathPos, next2SegmentInfo, next3PathPos, next3SegmentInfo, next4PathPos);
                    }
                    // NON-STOCK CODE END
                }

                // update lane index
                if (bestLaneIndex != (int)nextPathPos.m_lane)
                {
                    nextPathPos.m_lane = (byte)bestLaneIndex;
                    pathMan.m_pathUnits.m_buffer[nextPathId].SetPosition(nextCoarsePathPosIndex, nextPathPos);
#if BENCHMARK
                    using (var bm = new Benchmark(null, "AddTraffic")) {
#endif
                    // prevent multiple lane changes to the same lane from happening at the same time
                    TrafficMeasurementManager.Instance.AddTraffic(nextPathPos.m_segment, nextPathPos.m_lane
#if MEASUREDENSITY
                                                                  , VehicleStateManager.Instance.VehicleStates[vehicleID].totalLength
#endif
                                                                  , 0); // NON-STOCK CODE
#if BENCHMARK
                }
#endif
                }

                // check for errors
                uint nextLaneId           = PathManager.GetLaneID(nextPathPos);
                NetInfo.Lane nextLaneInfo = nextSegmentInfo.m_lanes[(int)nextPathPos.m_lane];
                ushort curSegStartNodeId  = netManager.m_segments.m_buffer[(int)currentPosition.m_segment].m_startNode;
                ushort curSegEndNodeId    = netManager.m_segments.m_buffer[(int)currentPosition.m_segment].m_endNode;
                ushort nextSegStartNodeId = netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].m_startNode;
                ushort nextSegEndNodeId   = netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].m_endNode;
                if (nextSegStartNodeId != curSegStartNodeId &&
                    nextSegStartNodeId != curSegEndNodeId &&
                    nextSegEndNodeId != curSegStartNodeId &&
                    nextSegEndNodeId != curSegEndNodeId &&
                    ((netManager.m_nodes.m_buffer[(int)curSegStartNodeId].m_flags | netManager.m_nodes.m_buffer[(int)curSegEndNodeId].m_flags) & NetNode.Flags.Disabled) == NetNode.Flags.None &&
                    ((netManager.m_nodes.m_buffer[(int)nextSegStartNodeId].m_flags | netManager.m_nodes.m_buffer[(int)nextSegEndNodeId].m_flags) & NetNode.Flags.Disabled) != NetNode.Flags.None)
                {
                    this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }

                // park vehicle
                if (nextLaneInfo.m_laneType == NetInfo.LaneType.Pedestrian)
                {
                    if (vehicleID != 0 && (vehicleData.m_flags & Vehicle.Flags.Parking) == (Vehicle.Flags) 0)
                    {
                        byte inOffset  = currentPosition.m_offset;
                        byte outOffset = currentPosition.m_offset;
                        if (this.ParkVehicle(vehicleID, ref vehicleData, currentPosition, nextPathId, nextCoarsePathPosIndex << 1, out outOffset))
                        {
                            if (outOffset != inOffset)
                            {
                                if (targetPosIndex <= 0)
                                {
                                    vehicleData.m_pathPositionIndex = (byte)((int)vehicleData.m_pathPositionIndex & -2);
                                    vehicleData.m_lastPathOffset    = inOffset;
                                }
                                currentPosition.m_offset = outOffset;
                                pathMan.m_pathUnits.m_buffer[(int)((UIntPtr)pathId)].SetPosition(finePathPosIndex >> 1, currentPosition);
                            }
                            vehicleData.m_flags |= Vehicle.Flags.Parking;
                        }
                        else
                        {
                            this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                        }
                    }
                    return;
                }

                // check for errors
                if ((byte)(nextLaneInfo.m_laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.CargoVehicle | NetInfo.LaneType.TransportVehicle)) == 0)
                {
                    this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                    return;
                }

                // change vehicle
                if (nextLaneInfo.m_vehicleType != this.m_info.m_vehicleType &&
                    this.NeedChangeVehicleType(vehicleID, ref vehicleData, nextPathPos, nextLaneId, nextLaneInfo.m_vehicleType, ref targetPos)
                    )
                {
                    float targetPos0ToRefPosSqrDist = ((Vector3)targetPos - refPos).sqrMagnitude;
                    if (targetPos0ToRefPosSqrDist >= minSqrDistA)
                    {
                        vehicleData.SetTargetPos(targetPosIndex++, targetPos);
                    }
                    if (targetPosIndex <= 0)
                    {
                        while (targetPosIndex < maxTargetPosIndex)
                        {
                            vehicleData.SetTargetPos(targetPosIndex++, targetPos);
                        }
                        if (nextPathId != vehicleData.m_path)
                        {
                            Singleton <PathManager> .instance.ReleaseFirstUnit(ref vehicleData.m_path);
                        }
                        vehicleData.m_pathPositionIndex = (byte)(nextCoarsePathPosIndex << 1);
                        PathUnit.CalculatePathPositionOffset(nextLaneId, targetPos, out vehicleData.m_lastPathOffset);
                        if (vehicleID != 0 && !this.ChangeVehicleType(vehicleID, ref vehicleData, nextPathPos, nextLaneId))
                        {
                            this.InvalidPath(vehicleID, ref vehicleData, vehicleID, ref vehicleData);
                        }
                    }
                    else
                    {
                        while (targetPosIndex < maxTargetPosIndex)
                        {
                            vehicleData.SetTargetPos(targetPosIndex++, targetPos);
                        }
                    }
                    return;
                }

                // unset leaving flag
                if (nextPathPos.m_segment != currentPosition.m_segment && vehicleID != 0)
                {
                    vehicleData.m_flags &= ~Vehicle.Flags.Leaving;
                }

                // calculate next segment offset
                byte nextSegOffset = 0;
                if ((vehicleData.m_flags & Vehicle.Flags.Flying) != (Vehicle.Flags) 0)
                {
                    nextSegOffset = (byte)((nextPathPos.m_offset < 128) ? 255 : 0);
                }
                else if (curLaneId != nextLaneId && laneInfo.m_laneType != NetInfo.LaneType.CargoVehicle)
                {
                    PathUnit.CalculatePathPositionOffset(nextLaneId, targetPos, out nextSegOffset);
                    bezier = default(Bezier3);
                    Vector3 curSegDir;
                    float   maxSpeed;
                    this.CalculateSegmentPosition(vehicleID, ref vehicleData, currentPosition, curLaneId, currentPosition.m_offset, out bezier.a, out curSegDir, out maxSpeed);
                    bool calculateNextNextPos = lastPathOffset == 0;
                    if (calculateNextNextPos)
                    {
                        if ((vehicleData.m_flags & Vehicle.Flags.Reversed) != (Vehicle.Flags) 0)
                        {
                            calculateNextNextPos = (vehicleData.m_trailingVehicle == 0);
                        }
                        else
                        {
                            calculateNextNextPos = (vehicleData.m_leadingVehicle == 0);
                        }
                    }
                    Vector3 nextSegDir;
                    float   nextMaxSpeed;
                    if (calculateNextNextPos)
                    {
                        PathUnit.Position nextNextPathPos;
                        if (!pathMan.m_pathUnits.m_buffer[nextPathId].GetNextPosition(nextCoarsePathPosIndex, out nextNextPathPos))
                        {
                            nextNextPathPos = default(PathUnit.Position);
                        }
                        this.CalculateSegmentPosition(vehicleID, ref vehicleData, nextNextPathPos, nextPathPos, nextLaneId, nextSegOffset, currentPosition, curLaneId, currentPosition.m_offset, targetPosIndex, out bezier.d, out nextSegDir, out nextMaxSpeed);
                    }
                    else
                    {
                        this.CalculateSegmentPosition(vehicleID, ref vehicleData, nextPathPos, nextLaneId, nextSegOffset, out bezier.d, out nextSegDir, out nextMaxSpeed);
                    }
                    if (nextMaxSpeed < 0.01f || (netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].m_flags & (NetSegment.Flags.Collapsed | NetSegment.Flags.Flooded)) != NetSegment.Flags.None)
                    {
                        if (targetPosIndex <= 0)
                        {
                            vehicleData.m_lastPathOffset = lastPathOffset;
                        }
                        targetPos   = bezier.a;
                        targetPos.w = 0f;
                        while (targetPosIndex < maxTargetPosIndex)
                        {
                            vehicleData.SetTargetPos(targetPosIndex++, targetPos);
                        }
                        return;
                    }
                    if (currentPosition.m_offset == 0)
                    {
                        curSegDir = -curSegDir;
                    }
                    if (nextSegOffset < nextPathPos.m_offset)
                    {
                        nextSegDir = -nextSegDir;
                    }
                    curSegDir.Normalize();
                    nextSegDir.Normalize();
                    float dist;
                    NetSegment.CalculateMiddlePoints(bezier.a, curSegDir, bezier.d, nextSegDir, true, true, out bezier.b, out bezier.c, out dist);
                    if (dist > 1f)
                    {
                        ushort nextNodeId;
                        if (nextSegOffset == 0)
                        {
                            nextNodeId = netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].m_startNode;
                        }
                        else if (nextSegOffset == 255)
                        {
                            nextNodeId = netManager.m_segments.m_buffer[(int)nextPathPos.m_segment].m_endNode;
                        }
                        else
                        {
                            nextNodeId = 0;
                        }
                        float curve = 1.57079637f * (1f + Vector3.Dot(curSegDir, nextSegDir));
                        if (dist > 1f)
                        {
                            curve /= dist;
                        }
                        nextMaxSpeed = Mathf.Min(nextMaxSpeed, this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1000f, curve));
                        while (lastPathOffset < 255)
                        {
                            float distDiff = Mathf.Sqrt(minSqrDistA) - Vector3.Distance(targetPos, refPos);
                            int   pathOffsetDelta;
                            if (distDiff < 0f)
                            {
                                pathOffsetDelta = 8;
                            }
                            else
                            {
                                pathOffsetDelta = 8 + Mathf.Max(0, Mathf.CeilToInt(distDiff * 256f / (dist + 1f)));
                            }
                            lastPathOffset = (byte)Mathf.Min((int)lastPathOffset + pathOffsetDelta, 255);
                            Vector3 bezierPos = bezier.Position((float)lastPathOffset * 0.003921569f);
                            targetPos.Set(bezierPos.x, bezierPos.y, bezierPos.z, Mathf.Min(targetPos.w, nextMaxSpeed));
                            float sqrMagnitude2 = (bezierPos - refPos).sqrMagnitude;
                            if (sqrMagnitude2 >= minSqrDistA)
                            {
                                if (targetPosIndex <= 0)
                                {
                                    vehicleData.m_lastPathOffset = lastPathOffset;
                                }
                                if (nextNodeId != 0)
                                {
                                    this.UpdateNodeTargetPos(vehicleID, ref vehicleData, nextNodeId, ref netManager.m_nodes.m_buffer[(int)nextNodeId], ref targetPos, targetPosIndex);
                                }
                                vehicleData.SetTargetPos(targetPosIndex++, targetPos);
                                minSqrDistA = minSqrDistanceB;
                                refPos      = targetPos;
                                targetPos.w = 1000f;
                                if (targetPosIndex == maxTargetPosIndex)
                                {
                                    return;
                                }
                            }
                        }
                    }
                }
                else
                {
                    PathUnit.CalculatePathPositionOffset(nextLaneId, targetPos, out nextSegOffset);
                }

                // check for arrival
                if (targetPosIndex <= 0)
                {
                    if ((netManager.m_segments.m_buffer[nextPathPos.m_segment].m_flags & NetSegment.Flags.Untouchable) != 0 && (netManager.m_segments.m_buffer[currentPosition.m_segment].m_flags & NetSegment.Flags.Untouchable) == NetSegment.Flags.None)
                    {
                        ushort ownerBuildingId = NetSegment.FindOwnerBuilding(nextPathPos.m_segment, 363f);
                        if (ownerBuildingId != 0)
                        {
                            BuildingManager buildingMan       = Singleton <BuildingManager> .instance;
                            BuildingInfo    ownerBuildingInfo = buildingMan.m_buildings.m_buffer[ownerBuildingId].Info;
                            InstanceID      itemID            = default(InstanceID);
                            itemID.Vehicle = vehicleID;
                            ownerBuildingInfo.m_buildingAI.EnterBuildingSegment(ownerBuildingId, ref buildingMan.m_buildings.m_buffer[ownerBuildingId], nextPathPos.m_segment, nextPathPos.m_offset, itemID);
                        }
                    }

                    if (nextCoarsePathPosIndex == 0)
                    {
                        Singleton <PathManager> .instance.ReleaseFirstUnit(ref vehicleData.m_path);
                    }
                    if (nextCoarsePathPosIndex >= (int)(pathMan.m_pathUnits.m_buffer[(int)((UIntPtr)nextPathId)].m_positionCount - 1) && pathMan.m_pathUnits.m_buffer[(int)((UIntPtr)nextPathId)].m_nextPathUnit == 0u && vehicleID != 0)
                    {
                        this.ArrivingToDestination(vehicleID, ref vehicleData);
                    }
                }

                // prepare next loop iteration: go to next path position
                pathId           = nextPathId;
                finePathPosIndex = (byte)(nextCoarsePathPosIndex << 1);
                lastPathOffset   = nextSegOffset;
                if (targetPosIndex <= 0)
                {
                    vehicleData.m_pathPositionIndex = finePathPosIndex;
                    vehicleData.m_lastPathOffset    = lastPathOffset;
                    vehicleData.m_flags             = ((vehicleData.m_flags & ~(Vehicle.Flags.OnGravel | Vehicle.Flags.Underground | Vehicle.Flags.Transition)) | nextSegmentInfo.m_setVehicleFlags);
                    if (this.LeftHandDrive(nextLaneInfo))
                    {
                        vehicleData.m_flags |= Vehicle.Flags.LeftHandDrive;
                    }
                    else
                    {
                        vehicleData.m_flags &= (Vehicle.Flags.Created | Vehicle.Flags.Deleted | Vehicle.Flags.Spawned | Vehicle.Flags.Inverted | Vehicle.Flags.TransferToTarget | Vehicle.Flags.TransferToSource | Vehicle.Flags.Emergency1 | Vehicle.Flags.Emergency2 | Vehicle.Flags.WaitingPath | Vehicle.Flags.Stopped | Vehicle.Flags.Leaving | Vehicle.Flags.Arriving | Vehicle.Flags.Reversed | Vehicle.Flags.TakingOff | Vehicle.Flags.Flying | Vehicle.Flags.Landing | Vehicle.Flags.WaitingSpace | Vehicle.Flags.WaitingCargo | Vehicle.Flags.GoingBack | Vehicle.Flags.WaitingTarget | Vehicle.Flags.Importing | Vehicle.Flags.Exporting | Vehicle.Flags.Parking | Vehicle.Flags.CustomName | Vehicle.Flags.OnGravel | Vehicle.Flags.WaitingLoading | Vehicle.Flags.Congestion | Vehicle.Flags.DummyTraffic | Vehicle.Flags.Underground | Vehicle.Flags.Transition | Vehicle.Flags.InsideBuilding);
                    }
                }
                currentPosition = nextPathPos;
                curLaneId       = nextLaneId;
                laneInfo        = nextLaneInfo;
                firstIter       = false;           // NON-STOCK CODE
            }
        }