public static NetInfo.Lane Clone(this NetInfo.Lane templateLane, string newName) { var newLane = new NetInfo.Lane(); newLane.m_direction = templateLane.m_direction; newLane.m_finalDirection = templateLane.m_finalDirection; newLane.m_allowConnect = templateLane.m_allowConnect; newLane.m_allowStop = false; newLane.m_stopOffset = 0; newLane.m_laneType = templateLane.m_laneType; newLane.m_speedLimit = templateLane.m_speedLimit; newLane.m_vehicleType = templateLane.m_vehicleType; newLane.m_verticalOffset = templateLane.m_verticalOffset; newLane.m_width = templateLane.m_width; var templateLaneProps = templateLane.m_laneProps ?? ScriptableObject.CreateInstance<NetLaneProps>(); if (templateLaneProps.m_props == null) { templateLaneProps.m_props = new NetLaneProps.Prop[0]; } newLane.m_laneProps = ScriptableObject.CreateInstance<NetLaneProps>(); newLane.m_laneProps.name = newName; newLane.m_laneProps.m_props = templateLaneProps .m_props .Select(p => p.ShallowClone()) .ToArray(); return newLane; }
public static NetInfo.Lane CloneWithoutStops(this NetInfo.Lane templateLane, string newName = null) { var newLane = new NetInfo.Lane(); newLane.m_direction = templateLane.m_direction; newLane.m_finalDirection = templateLane.m_finalDirection; newLane.m_allowConnect = templateLane.m_allowConnect; newLane.m_stopType = VehicleInfo.VehicleType.None; newLane.m_stopOffset = 0; newLane.m_laneType = templateLane.m_laneType; newLane.m_speedLimit = templateLane.m_speedLimit; newLane.m_vehicleType = templateLane.m_vehicleType; newLane.m_verticalOffset = templateLane.m_verticalOffset; newLane.m_width = templateLane.m_width; newLane.m_laneProps = templateLane.m_laneProps.Clone(newName); return newLane; }
/// <summary> /// Displays segment ids over segments /// </summary> private void _guiSegments() { GUIStyle _counterStyle = new GUIStyle(); Array16 <NetSegment> segments = Singleton <NetManager> .instance.m_segments; for (int i = 1; i < segments.m_size; ++i) { if (segments.m_buffer[i].m_flags == NetSegment.Flags.None) // segment is unused { continue; } #if !DEBUG if ((segments.m_buffer[i].m_flags & NetSegment.Flags.Untouchable) != NetSegment.Flags.None) { continue; } #endif var segmentInfo = segments.m_buffer[i].Info; Vector3 centerPos = segments.m_buffer[i].m_bounds.center; var screenPos = Camera.main.WorldToScreenPoint(centerPos); screenPos.y = Screen.height - screenPos.y; if (screenPos.z < 0) { continue; } var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; var diff = centerPos - camPos; if (diff.magnitude > DebugCloseLod) { continue; // do not draw if too distant } if (Options.nodesOverlay) { var zoom = 1.0f / diff.magnitude * 150f; _counterStyle.fontSize = (int)(12f * zoom); _counterStyle.normal.textColor = new Color(1f, 0f, 0f); String labelStr = "Segment " + i; #if DEBUGx labelStr += ", flags: " + segments.m_buffer[i].m_flags.ToString() + ", condition: " + segments.m_buffer[i].m_condition; #endif #if DEBUG SegmentEnd startEnd = TrafficPriority.GetPrioritySegment(segments.m_buffer[i].m_startNode, (ushort)i); SegmentEnd endEnd = TrafficPriority.GetPrioritySegment(segments.m_buffer[i].m_endNode, (ushort)i); labelStr += "\nstart? " + (startEnd != null) + " veh.: " + startEnd?.GetRegisteredVehicleCount() + ", end? " + (endEnd != null) + " veh.: " + endEnd?.GetRegisteredVehicleCount(); #endif labelStr += "\nTraffic: " + segments.m_buffer[i].m_trafficDensity + " %"; #if MARKCONGESTEDSEGMENTS if (CustomRoadAI.initDone && CustomRoadAI.segmentCongestion[i]) { labelStr += " congested!"; } #endif float meanLaneSpeed = 0f; int lIndex = 0; uint laneId = segments.m_buffer[i].m_lanes; int validLanes = 0; while (lIndex < segmentInfo.m_lanes.Length && laneId != 0u) { NetInfo.Lane lane = segmentInfo.m_lanes[lIndex]; if (lane.CheckType(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car)) { if (CustomRoadAI.laneMeanSpeeds[i] != null && lIndex < CustomRoadAI.laneMeanSpeeds[i].Length) { if (CustomRoadAI.laneMeanSpeeds[i][lIndex] >= 0) { meanLaneSpeed += (float)CustomRoadAI.laneMeanSpeeds[i][lIndex]; ++validLanes; } } } lIndex++; laneId = Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_nextLane; } if (validLanes > 0) { meanLaneSpeed /= Convert.ToSingle(validLanes); } /*if (CustomRoadAI.InStartupPhase) * labelStr += " (in start-up phase)"; * else*/ labelStr += " (avg. speed: " + String.Format("{0:0.##}", meanLaneSpeed) + " %)"; #if DEBUG labelStr += "\nstart: " + segments.m_buffer[i].m_startNode + ", end: " + segments.m_buffer[i].m_endNode; #endif Vector2 dim = _counterStyle.CalcSize(new GUIContent(labelStr)); Rect labelRect = new Rect(screenPos.x - dim.x / 2f, screenPos.y, dim.x, dim.y); GUI.Label(labelRect, labelStr, _counterStyle); if (Options.showLanes) { _guiLanes((ushort)i, ref segments.m_buffer[i], ref segmentInfo); } } } }
private static void SetupTurningLaneProps(NetInfo.Lane lane) { var isLeftDriving = Singleton <SimulationManager> .instance.m_metaData.m_invertTraffic == SimulationMetaData.MetaBool.True; if (lane.m_laneProps == null) { return; } if (lane.m_laneProps.m_props == null) { return; } var fwd = lane.m_laneProps.m_props.FirstOrDefault(p => p.m_flagsRequired == NetLane.Flags.Forward); var left = lane.m_laneProps.m_props.FirstOrDefault(p => p.m_flagsRequired == NetLane.Flags.Left); var right = lane.m_laneProps.m_props.FirstOrDefault(p => p.m_flagsRequired == NetLane.Flags.Right); if (fwd == null) { return; } if (left == null) { return; } if (right == null) { return; } // Existing props //var r0 = NetLane.Flags.Forward; //var r1 = NetLane.Flags.ForwardRight; //var r2 = NetLane.Flags.Left; //var r3 = NetLane.Flags.LeftForward; //var r4 = NetLane.Flags.LeftForwardRight; //var r5 = NetLane.Flags.LeftRight; //var r6 = NetLane.Flags.Right; //var f0 = NetLane.Flags.LeftRight; //var f1 = NetLane.Flags.Left; //var f2 = NetLane.Flags.ForwardRight; //var f3 = NetLane.Flags.Right; //var f4 = NetLane.Flags.None; //var f5 = NetLane.Flags.Forward; //var f6 = NetLane.Flags.LeftForward; var newProps = new FastList <NetLaneProps.Prop>(); newProps.Add(fwd); newProps.Add(left); newProps.Add(right); var fl = left.ShallowClone(); fl.m_flagsRequired = NetLane.Flags.LeftForward; fl.m_flagsForbidden = NetLane.Flags.Right; newProps.Add(fl); var fr = right.ShallowClone(); fr.m_flagsRequired = NetLane.Flags.ForwardRight; fr.m_flagsForbidden = NetLane.Flags.Left; newProps.Add(fr); var flr = isLeftDriving ? right.ShallowClone() : left.ShallowClone(); flr.m_flagsRequired = NetLane.Flags.LeftForwardRight; flr.m_flagsForbidden = NetLane.Flags.None; newProps.Add(flr); var lr = isLeftDriving ? right.ShallowClone() : left.ShallowClone(); lr.m_flagsRequired = NetLane.Flags.LeftRight; lr.m_flagsForbidden = NetLane.Flags.Forward; newProps.Add(lr); lane.m_laneProps = new NetLaneProps { name = "TurningLane", m_props = newProps.ToArray() }; }
internal bool GetLaneEndPoint(ushort segmentId, bool startNode, byte laneIndex, uint?laneId, NetInfo.Lane laneInfo, out bool outgoing, out bool incoming, out Vector3?pos) { NetManager netManager = Singleton <NetManager> .instance; pos = null; outgoing = false; incoming = false; if ((netManager.m_segments.m_buffer[segmentId].m_flags & (NetSegment.Flags.Created | NetSegment.Flags.Deleted)) != NetSegment.Flags.Created) { return(false); } if (laneId == null) { laneId = FindLaneId(segmentId, laneIndex); if (laneId == null) { return(false); } } if ((netManager.m_lanes.m_buffer[(uint)laneId].m_flags & ((ushort)NetLane.Flags.Created | (ushort)NetLane.Flags.Deleted)) != (ushort)NetLane.Flags.Created) { return(false); } if (laneInfo == null) { if (laneIndex < netManager.m_segments.m_buffer[segmentId].Info.m_lanes.Length) { laneInfo = netManager.m_segments.m_buffer[segmentId].Info.m_lanes[laneIndex]; } else { return(false); } } NetInfo.Direction laneDir = ((NetManager.instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? laneInfo.m_finalDirection : NetInfo.InvertDirection(laneInfo.m_finalDirection); if (startNode) { if ((laneDir & NetInfo.Direction.Backward) != NetInfo.Direction.None) { outgoing = true; } if ((laneDir & NetInfo.Direction.Forward) != NetInfo.Direction.None) { incoming = true; } pos = NetManager.instance.m_lanes.m_buffer[(uint)laneId].m_bezier.a; } else { if ((laneDir & NetInfo.Direction.Forward) != NetInfo.Direction.None) { outgoing = true; } if ((laneDir & NetInfo.Direction.Backward) != NetInfo.Direction.None) { incoming = true; } pos = NetManager.instance.m_lanes.m_buffer[(uint)laneId].m_bezier.d; } return(true); }
/// <summary> /// Determines the allowed vehicle types that may approach the given node from the given segment (lane-wise). /// </summary> /// <param name="segmentId"></param> /// <param name="nodeId"></param> /// <returns></returns> public IDictionary <byte, ExtVehicleType> GetAllowedVehicleTypesAsDict( ushort segmentId, ushort nodeId, VehicleRestrictionsMode busLaneMode) { IDictionary <byte, ExtVehicleType> ret = new TinyDictionary <byte, ExtVehicleType>(); NetManager netManager = Singleton <NetManager> .instance; if (segmentId == 0 || (netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None || nodeId == 0 || (netManager.m_nodes.m_buffer[nodeId].m_flags & NetNode.Flags.Created) == NetNode.Flags.None) { return(ret); } const NetInfo.Direction DIR = NetInfo.Direction.Forward; NetInfo.Direction dir2 = ((netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? DIR : NetInfo.InvertDirection(DIR); NetInfo segmentInfo = netManager.m_segments.m_buffer[segmentId].Info; uint curLaneId = netManager.m_segments.m_buffer[segmentId].m_lanes; int numLanes = segmentInfo.m_lanes.Length; uint laneIndex = 0; while (laneIndex < numLanes && curLaneId != 0u) { NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; if (laneInfo.m_laneType == NetInfo.LaneType.Vehicle || laneInfo.m_laneType == NetInfo.LaneType.TransportVehicle) { if ((laneInfo.m_vehicleType & VEHICLE_TYPES) != VehicleInfo.VehicleType.None) { ushort toNodeId = (laneInfo.m_finalDirection & dir2) != NetInfo.Direction.None ? netManager.m_segments.m_buffer[segmentId].m_endNode : netManager.m_segments.m_buffer[segmentId].m_startNode; if ((laneInfo.m_finalDirection & NetInfo.Direction.Both) == NetInfo.Direction.Both || toNodeId == nodeId) { ExtVehicleType vehicleTypes = GetAllowedVehicleTypes( segmentId, segmentInfo, laneIndex, laneInfo, busLaneMode); ret[(byte)laneIndex] = vehicleTypes; } } } curLaneId = netManager.m_lanes.m_buffer[curLaneId].m_nextLane; ++laneIndex; } return(ret); }
public bool IsRoadLane(NetInfo.Lane laneInfo) { return((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None); }
public ExtVehicleType GetDefaultAllowedVehicleTypes(NetInfo.Lane laneInfo, VehicleRestrictionsMode busLaneMode) { var ret = ExtVehicleType.None; if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Bicycle) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Bicycle; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Tram) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Tram; } switch (busLaneMode) { case VehicleRestrictionsMode.Restricted: case VehicleRestrictionsMode.Configured when Options.banRegularTrafficOnBusLanes: { if ((laneInfo.m_laneType & NetInfo.LaneType.TransportVehicle) != NetInfo.LaneType.None) { ret |= ExtVehicleType.RoadPublicTransport | ExtVehicleType.Service | ExtVehicleType.Emergency; } else if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.RoadVehicle; } break; } default: { if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.RoadVehicle; } break; } } // TODO: Mapping from VehicleInfo.VehicleType to bit flags can be improved by a lookup table if ((laneInfo.m_vehicleType & (VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Metro | VehicleInfo.VehicleType.Monorail)) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.RailVehicle; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Ship) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Ship; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Plane) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Plane; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Ferry) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Ferry; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Blimp) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Blimp; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.CableCar) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.CableCar; } return(ret); }
/// <summary> /// Determines if custom speed limits may be assigned to the given lane info /// </summary> /// <param name="laneInfo"></param> /// <returns></returns> public bool MayHaveCustomSpeedLimits(NetInfo.Lane laneInfo) { return((laneInfo.m_laneType & LANE_TYPES) != NetInfo.LaneType.None && (laneInfo.m_vehicleType & VEHICLE_TYPES) != VehicleInfo.VehicleType.None); }
/// <summary> /// Determines the default set of allowed vehicle types for a given segment and lane. /// </summary> /// <param name="segmentId"></param> /// <param name="segmentInfo"></param> /// <param name="laneIndex"></param> /// <param name="laneInfo"></param> /// <returns></returns> public ExtVehicleType GetDefaultAllowedVehicleTypes(ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo) { // manage cached default vehicle types if (defaultVehicleTypeCache == null) { defaultVehicleTypeCache = new ExtVehicleType?[NetManager.MAX_SEGMENT_COUNT][]; } ExtVehicleType?[] cachedDefaultTypes = defaultVehicleTypeCache[segmentId]; if (cachedDefaultTypes == null || cachedDefaultTypes.Length != segmentInfo.m_lanes.Length) { defaultVehicleTypeCache[segmentId] = cachedDefaultTypes = new ExtVehicleType?[segmentInfo.m_lanes.Length]; } ExtVehicleType?defaultVehicleType = cachedDefaultTypes[laneIndex]; if (defaultVehicleType == null) { ExtVehicleType ret = ExtVehicleType.None; if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Bicycle) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Bicycle; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Tram) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Tram; } if ((laneInfo.m_laneType & NetInfo.LaneType.TransportVehicle) != NetInfo.LaneType.None) { ret |= ExtVehicleType.RoadPublicTransport | ExtVehicleType.Service | ExtVehicleType.Emergency; } else if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.RoadVehicle; } if ((laneInfo.m_vehicleType & (VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Metro)) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.RailVehicle; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Ship) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Ship; } if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Plane) != VehicleInfo.VehicleType.None) { ret |= ExtVehicleType.Plane; } cachedDefaultTypes[laneIndex] = ret; return(ret); } else { return((ExtVehicleType)defaultVehicleType); } }
/// <summary> /// Determines the allowed vehicle types for the given segment and lane. /// </summary> /// <param name="segmentId"></param> /// <param name="laneIndex"></param> /// <param name="segmetnInfo"></param> /// <param name="laneInfo"></param> /// <returns></returns> internal ExtVehicleType GetAllowedVehicleTypes(ushort segmentId, NetInfo segmentInfo, uint laneIndex, NetInfo.Lane laneInfo) { ExtVehicleType?[] fastArray = Flags.laneAllowedVehicleTypesArray[segmentId]; if (fastArray != null && fastArray.Length > laneIndex && fastArray[laneIndex] != null) { return((ExtVehicleType)fastArray[laneIndex]); } return(GetDefaultAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo)); }
private static NetInfo.Lane FindNearestVehicleStopLane(NetInfo.Lane[] laneGroup, NetInfo.Lane refLane, out ushort laneId) { NetInfo.Lane nearestLane = null; float nearestDist = float.MaxValue; laneId = 0xffff; for (ushort i = 0; i < laneGroup.Length; i++) { NetInfo.Lane lane = laneGroup[i]; if ((lane.m_vehicleType & refLane.m_stopType) != VehicleInfo.VehicleType.None) { float dist = Mathf.Abs(lane.m_position - refLane.m_position); if (dist < nearestDist) { nearestDist = dist; nearestLane = lane; laneId = i; } } } return(nearestLane); }
public static StopPointDescriptorLanes[] MapStopPoints(BuildingInfo buildingInfo, float thresold) { var result = new List <StopPointDescriptorLanes>(); if (buildingInfo?.m_paths != null) { foreach (BuildingInfo.PathInfo path in buildingInfo.m_paths) { if (path.m_nodes.Length < 2) { continue; } Vector3 position = path.m_nodes[0]; Vector3 position2 = path.m_nodes[1]; position.z *= -1; position2.z *= -1; Vector3 directionPath = Quaternion.AngleAxis(90, Vector3.up) * (position2 - position).normalized; foreach (NetInfo.Lane refLane in path.m_netInfo.m_lanes) { if (refLane.m_stopType == VehicleInfo.VehicleType.None) { continue; } NetInfo.Lane lane = FindNearestVehicleStopLane(path.m_netInfo.m_lanes, refLane, out ushort laneId); if (lane == null) { continue; } LogUtils.DoLog($"[{buildingInfo}] pos + dir = ({position} {position2} + {directionPath})"); Vector3 lanePos = position + (lane.m_position / 2 * directionPath) + new Vector3(0, lane.m_verticalOffset); Vector3 lanePos2 = position2 + (lane.m_position / 2 * directionPath) + new Vector3(0, lane.m_verticalOffset); Vector3 b3, c; if (path.m_curveTargets == null || path.m_curveTargets.Length == 0) { NetSegment.CalculateMiddlePoints(lanePos, Vector3.zero, lanePos2, Vector3.zero, true, true, out b3, out c); } else { GetMiddlePointsFor(path, out b3, out c); LogUtils.DoLog($"[{buildingInfo}] GetMiddlePointsFor path = ({b3} {c})"); b3 += (lane.m_position * directionPath) + new Vector3(0, lane.m_verticalOffset); c += (lane.m_position * directionPath) + new Vector3(0, lane.m_verticalOffset); b3.y = c.y = (lanePos.y + lanePos2.y) / 2; } var refBezier = new Bezier3(lanePos, b3, c, lanePos2); LogUtils.DoLog($"[{buildingInfo}]refBezier = {refBezier} ({lanePos} {b3} {c} {lanePos2})"); Vector3 positionR = refBezier.Position(m_defaultStopOffset); Vector3 direction = refBezier.Tangent(m_defaultStopOffset); LogUtils.DoLog($"[{buildingInfo}]1positionR = {positionR}; direction = {direction}"); Vector3 normalized = Vector3.Cross(Vector3.up, direction).normalized; positionR += normalized * (MathUtils.SmootherStep(0.5f, 0f, Mathf.Abs(m_defaultStopOffset - 0.5f)) * lane.m_stopOffset); LogUtils.DoLog($"[{buildingInfo}]2positionR = {positionR}; direction = {direction}; {normalized}"); result.Add(new StopPointDescriptorLanes { platformLine = refBezier, width = lane.m_width, vehicleType = refLane.m_stopType, laneId = laneId, subbuildingId = -1, directionPath = directionPath * (path.m_invertSegments == (refLane.m_finalDirection == NetInfo.Direction.AvoidForward || refLane.m_finalDirection == NetInfo.Direction.Backward) ? 1 : -1) }); } } } for (int i = 0; i < (buildingInfo.m_subBuildings?.Length ?? 0); i++) { StopPointDescriptorLanes[] subPlats = MapStopPoints(buildingInfo.m_subBuildings[i].m_buildingInfo, thresold); if (subPlats != null) { var rotationToApply = Quaternion.AngleAxis(buildingInfo.m_subBuildings[i].m_angle, Vector3.up); result.AddRange(subPlats.Select(x => { x.platformLine.a = (rotationToApply * x.platformLine.a) + buildingInfo.m_subBuildings[i].m_position; x.platformLine.b = (rotationToApply * x.platformLine.b) + buildingInfo.m_subBuildings[i].m_position; x.platformLine.c = (rotationToApply * x.platformLine.c) + buildingInfo.m_subBuildings[i].m_position; x.platformLine.d = (rotationToApply * x.platformLine.d) + buildingInfo.m_subBuildings[i].m_position; x.subbuildingId = (sbyte)i; x.directionPath = (rotationToApply * x.directionPath).normalized; return(x); })); } } result.Sort((x, y) => { int priorityX = VehicleToPriority(x.vehicleType); int priorityY = VehicleToPriority(y.vehicleType); if (priorityX != priorityY) { return(priorityX.CompareTo(priorityY)); } Vector3 centerX = (x.platformLine.Position(0.5f)); Vector3 centerY = (y.platformLine.Position(0.5f)); if (Mathf.Abs(centerX.y - centerY.y) >= thresold) { return(-centerX.y.CompareTo(centerY.y)); } if (Mathf.Abs(centerX.z - centerY.z) >= thresold) { return(-centerX.z.CompareTo(centerY.z)); } return(-centerX.x.CompareTo(centerY.x)); }); if (CommonProperties.DebugMode) { LogUtils.DoLog($"{buildingInfo.name} PLAT ORDER:\n{string.Join("\n", result.Select((x, y) => $"{y}=> {x.ToString()}").ToArray())}"); } return(result.ToArray()); }
private static List <NodeLaneMarker> GetNodeMarkers(ushort nodeId, ref NetNode node) { if (nodeId == 0) { return(null); } if ((node.m_flags & NetNode.Flags.Created) == NetNode.Flags.None) { return(null); } List <NodeLaneMarker> nodeMarkers = new List <NodeLaneMarker>(); int nodeMarkerColorIndex = 0; LaneConnectionManager connManager = LaneConnectionManager.Instance; int offsetMultiplier = node.CountSegments() <= 2 ? 3 : 1; for (int i = 0; i < 8; i++) { ushort segmentId = node.GetSegment(i); if (segmentId == 0) { continue; } NetSegment[] segmentsBuffer = NetManager.instance.m_segments.m_buffer; bool startNode = segmentsBuffer[segmentId].m_startNode == nodeId; Vector3 offset = segmentsBuffer[segmentId] .FindDirection(segmentId, nodeId) * offsetMultiplier; NetInfo.Lane[] lanes = segmentsBuffer[segmentId].Info.m_lanes; uint laneId = segmentsBuffer[segmentId].m_lanes; for (byte laneIndex = 0; (laneIndex < lanes.Length) && (laneId != 0); laneIndex++) { NetInfo.Lane laneInfo = lanes[laneIndex]; if (((laneInfo.m_laneType & LaneConnectionManager.LANE_TYPES) != NetInfo.LaneType.None) && ((laneInfo.m_vehicleType & LaneConnectionManager.VEHICLE_TYPES) != VehicleInfo.VehicleType.None)) { if (connManager.GetLaneEndPoint( segmentId, startNode, laneIndex, laneId, laneInfo, out bool isSource, out bool isTarget, out Vector3? pos)) { pos = pos.Value + offset; float terrainY = Singleton <TerrainManager> .instance.SampleDetailHeightSmooth(pos.Value); var finalPos = new Vector3(pos.Value.x, terrainY, pos.Value.z); Color32 nodeMarkerColor = isSource ? COLOR_CHOICES[nodeMarkerColorIndex % COLOR_CHOICES.Length] : default; // or black (not used while rendering) NetLane lane = NetManager.instance.m_lanes.m_buffer[laneId]; Bezier3 bezier = lane.m_bezier; if (startNode) { bezier.a = (Vector3)pos; } else { bezier.d = (Vector3)pos; } SegmentLaneMarker segmentLaneMarker = new SegmentLaneMarker { renderBezier = bezier, raycastBezier = bezier, laneID = laneId, laneIndex = laneIndex, }; nodeMarkers.Add( new NodeLaneMarker { SegmentId = segmentId, LaneId = laneId, NodeId = nodeId, StartNode = startNode, Position = finalPos, SecondaryPosition = (Vector3)pos, Color = nodeMarkerColor, IsSource = isSource, IsTarget = isTarget, LaneType = laneInfo.m_laneType, VehicleType = laneInfo.m_vehicleType, InnerSimilarLaneIndex = ((byte)(laneInfo.m_direction & NetInfo.Direction.Forward) != 0) ? laneInfo.m_similarLaneIndex : laneInfo.m_similarLaneCount - laneInfo.m_similarLaneIndex - 1, SegmentIndex = i, segmentLaneMarker = segmentLaneMarker, }); if (isSource) { nodeMarkerColorIndex++; } } } laneId = NetManager.instance.m_lanes.m_buffer[laneId].m_nextLane; } } if (nodeMarkers.Count == 0) { return(null); } foreach (NodeLaneMarker laneMarker1 in nodeMarkers) { if (!laneMarker1.IsSource) { continue; } uint[] connections = LaneConnectionManager.Instance.GetLaneConnections( laneMarker1.LaneId, laneMarker1.StartNode); if ((connections == null) || (connections.Length == 0)) { continue; } foreach (NodeLaneMarker laneMarker2 in nodeMarkers) { if (!laneMarker2.IsTarget) { continue; } if (connections.Contains(laneMarker2.LaneId)) { laneMarker1.ConnectedMarkers.Add(laneMarker2); } } } return(nodeMarkers); }
private List <NodeLaneMarker> GetNodeMarkers(ushort nodeId, ref NetNode node) { if (nodeId == 0) { return(null); } if ((node.m_flags & NetNode.Flags.Created) == NetNode.Flags.None) { return(null); } List <NodeLaneMarker> nodeMarkers = new List <NodeLaneMarker>(); LaneConnectionManager connManager = LaneConnectionManager.Instance; int offsetMultiplier = node.CountSegments() <= 2 ? 3 : 1; for (int i = 0; i < 8; i++) { ushort segmentId = node.GetSegment(i); if (segmentId == 0) { continue; } bool isEndNode = NetManager.instance.m_segments.m_buffer[segmentId].m_endNode == nodeId; Vector3 offset = NetManager.instance.m_segments.m_buffer[segmentId].FindDirection(segmentId, nodeId) * offsetMultiplier; NetInfo.Lane[] lanes = NetManager.instance.m_segments.m_buffer[segmentId].Info.m_lanes; uint laneId = NetManager.instance.m_segments.m_buffer[segmentId].m_lanes; for (byte laneIndex = 0; laneIndex < lanes.Length && laneId != 0; laneIndex++) { NetInfo.Lane laneInfo = lanes[laneIndex]; if ((laneInfo.m_laneType & LaneConnectionManager.LANE_TYPES) != NetInfo.LaneType.None && (laneInfo.m_vehicleType & LaneConnectionManager.VEHICLE_TYPES) != VehicleInfo.VehicleType.None) { Vector3?pos = null; bool isSource = false; bool isTarget = false; if (connManager.GetLaneEndPoint(segmentId, !isEndNode, laneIndex, laneId, laneInfo, out isSource, out isTarget, out pos)) { pos = (Vector3)pos + offset; float terrainY = Singleton <TerrainManager> .instance.SampleDetailHeightSmooth(((Vector3)pos)); Vector3 finalPos = new Vector3(((Vector3)pos).x, terrainY, ((Vector3)pos).z); nodeMarkers.Add(new NodeLaneMarker() { segmentId = segmentId, laneId = laneId, nodeId = nodeId, startNode = !isEndNode, position = finalPos, secondaryPosition = (Vector3)pos, color = colors[nodeMarkers.Count % colors.Length], isSource = isSource, isTarget = isTarget, laneType = laneInfo.m_laneType, vehicleType = laneInfo.m_vehicleType, innerSimilarLaneIndex = ((byte)(laneInfo.m_direction & NetInfo.Direction.Forward) != 0) ? laneInfo.m_similarLaneIndex : laneInfo.m_similarLaneCount - laneInfo.m_similarLaneIndex - 1, segmentIndex = i }); } } laneId = NetManager.instance.m_lanes.m_buffer[laneId].m_nextLane; } } if (nodeMarkers.Count == 0) { return(null); } foreach (NodeLaneMarker laneMarker1 in nodeMarkers) { if (!laneMarker1.isSource) { continue; } uint[] connections = LaneConnectionManager.Instance.GetLaneConnections(laneMarker1.laneId, laneMarker1.startNode); if (connections == null || connections.Length == 0) { continue; } foreach (NodeLaneMarker laneMarker2 in nodeMarkers) { if (!laneMarker2.isTarget) { continue; } if (connections.Contains(laneMarker2.laneId)) { laneMarker1.connectedMarkers.Add(laneMarker2); } } } return(nodeMarkers); }
public static bool IsDriveLane(this NetInfo.Lane info) => (info.m_vehicleType & DriveType) != VehicleInfo.VehicleType.None;
internal float GetLockFreeGameSpeedLimit(ushort segmentId, uint laneIndex, uint laneId, NetInfo.Lane laneInfo) { #if TRACE Singleton <CodeProfiler> .instance.Start("SpeedLimitManager.GetLockFreeGameSpeedLimit"); #endif if (Flags.IsInitDone()) { if (Flags.laneSpeedLimitArray.Length <= segmentId) { Log.Error($"laneSpeedLimitArray.Length = {Flags.laneSpeedLimitArray.Length}, segmentId={segmentId}. Out of range!"); #if TRACE Singleton <CodeProfiler> .instance.Stop("SpeedLimitManager.GetLockFreeGameSpeedLimit"); #endif return(laneInfo.m_speedLimit); } float speedLimit = 0; ushort?[] fastArray = Flags.laneSpeedLimitArray[segmentId]; if (fastArray != null && fastArray.Length > laneIndex && fastArray[laneIndex] != null) { speedLimit = ToGameSpeedLimit((ushort)fastArray[laneIndex]); } else { speedLimit = laneInfo.m_speedLimit; } #if TRACE Singleton <CodeProfiler> .instance.Stop("SpeedLimitManager.GetLockFreeGameSpeedLimit"); #endif return(speedLimit); } else { float ret = GetGameSpeedLimit(laneId); #if TRACE Singleton <CodeProfiler> .instance.Stop("SpeedLimitManager.GetLockFreeGameSpeedLimit"); #endif return(ret); } }
/// <summary> /// Removes the given vehicle type from the set of allowed vehicles at the specified lane /// </summary> /// <param name="segmentId"></param> /// <param name="laneIndex"></param> /// <param name="laneId"></param> /// <param name="laneInfo"></param> /// <param name="road"></param> /// <param name="vehicleType"></param> public void RemoveAllowedType(ushort segmentId, NetInfo segmentInfo, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType) { if (segmentId == 0 || (Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None || ((NetLane.Flags)Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_flags & NetLane.Flags.Created) == NetLane.Flags.None) { return; } ExtVehicleType allowedTypes = GetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo); allowedTypes &= ~vehicleType; allowedTypes &= GetBaseMask(segmentInfo.m_lanes[laneIndex]); // ensure default base mask Flags.setLaneAllowedVehicleTypes(segmentId, laneIndex, laneId, allowedTypes); SubscribeToSegmentGeometry(segmentId); NotifyStartEndNode(segmentId); }
// NetSegment.GetClosestLane -- it's only called by the PathManager public static bool GetClosestLanePosition(NetSegment seg, Vector3 point, NetInfo.LaneType laneTypes, VehicleInfo.VehicleType vehicleTypes, out Vector3 positionA, out int laneIndexA, out float laneOffsetA, out Vector3 positionB, out int laneIndexB, out float laneOffsetB, RoadManager.VehicleType vehicleType) { positionA = point; laneIndexA = -1; laneOffsetA = 0f; positionB = point; laneIndexB = -1; laneOffsetB = 0f; if (seg.m_flags != NetSegment.Flags.None && seg.m_lanes != 0u) { NetInfo info = seg.Info; if (info.m_lanes != null) { float num = 1E+09f; float num2 = 1E+09f; uint num3 = seg.m_lanes; int num4 = 0; while (num4 < info.m_lanes.Length && num3 != 0u) { NetInfo.Lane lane = info.m_lanes[num4]; if (lane.CheckType(laneTypes, vehicleTypes) && RoadManager.CanUseLane(vehicleType, num3)) { Vector3 vector; float num5; Singleton <NetManager> .instance.m_lanes.m_buffer[(int)((UIntPtr)num3)].GetClosestPosition(point, out vector, out num5); float num6 = Vector3.SqrMagnitude(point - vector); if (lane.m_finalDirection == NetInfo.Direction.Backward || lane.m_finalDirection == NetInfo.Direction.AvoidForward) { if (num6 < num2) { num2 = num6; positionB = vector; laneIndexB = num4; laneOffsetB = num5; } } else if (num6 < num) { num = num6; positionA = vector; laneIndexA = num4; laneOffsetA = num5; } } num3 = Singleton <NetManager> .instance.m_lanes.m_buffer[(int)((UIntPtr)num3)].m_nextLane; num4++; } if (num2 < num) { Vector3 vector2 = positionA; int num7 = laneIndexA; float num8 = laneOffsetA; positionA = positionB; laneIndexA = laneIndexB; laneOffsetA = laneOffsetB; positionB = vector2; laneIndexB = num7; laneOffsetB = num8; } if (!info.m_canCrossLanes) { positionB = point; laneIndexB = -1; laneOffsetB = 0f; } } } return(laneIndexA != -1); }
public void ToggleAllowedType(ushort segmentId, NetInfo segmentInfo, uint laneIndex, uint laneId, NetInfo.Lane laneInfo, ExtVehicleType vehicleType, bool add) { if (add) { AddAllowedType(segmentId, segmentInfo, laneIndex, laneId, laneInfo, vehicleType); } else { RemoveAllowedType(segmentId, segmentInfo, laneIndex, laneId, laneInfo, vehicleType); } }
/// <summary> /// Determines the maximum allowed set of vehicles (the base mask) for a given lane /// </summary> /// <param name="laneInfo"></param> /// <returns></returns> public ExtVehicleType GetBaseMask(NetInfo.Lane laneInfo, VehicleRestrictionsMode includeBusLanes) { return(GetDefaultAllowedVehicleTypes(laneInfo, includeBusLanes)); }
public void OnBeforeSimulationStep(ushort segmentId, ref NetSegment segment) { GlobalConfig conf = GlobalConfig.Instance; // calculate traffic density NetInfo segmentInfo = segment.Info; int numLanes = segmentInfo.m_lanes.Length; if (LaneTrafficData[segmentId] == null || LaneTrafficData[segmentId].Length < numLanes) { LaneTrafficData[segmentId] = new LaneTrafficData[numLanes]; for (int i = 0; i < numLanes; ++i) { // laneTrafficData[segmentId][i] = new LaneTrafficData(); LaneTrafficData[segmentId][i].meanSpeed = REF_REL_SPEED; } } // calculate max./min. lane speed for (var i = 0; i < 2; ++i) { meanSpeeds[i] = 0; meanSpeedLanes[i] = 0; } uint curLaneId = segment.m_lanes; byte laneIndex = 0; while (laneIndex < numLanes && curLaneId != 0u) { NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; if ((laneInfo.m_laneType & LANE_TYPES) != NetInfo.LaneType.None && (laneInfo.m_vehicleType & VEHICLE_TYPES) != VehicleInfo.VehicleType.None) { int dirIndex = GetDirIndex(laneInfo.m_finalDirection); // calculate reported mean speed ushort newRelSpeed = CalcLaneRelativeMeanSpeed( segmentId, laneIndex, curLaneId, segment.Info.m_lanes[laneIndex]); meanSpeeds[dirIndex] += newRelSpeed; ++meanSpeedLanes[dirIndex]; LaneTrafficData[segmentId][laneIndex].meanSpeed = newRelSpeed; ushort trafficBuffer = LaneTrafficData[segmentId][laneIndex].trafficBuffer; // remember historic data LaneTrafficData[segmentId][laneIndex].lastTrafficBuffer = trafficBuffer; if (trafficBuffer > LaneTrafficData[segmentId][laneIndex].maxTrafficBuffer) { LaneTrafficData[segmentId][laneIndex].maxTrafficBuffer = trafficBuffer; } // reset buffers if (conf.AdvancedVehicleAI.MaxTrafficBuffer > 0) { if (LaneTrafficData[segmentId][laneIndex].trafficBuffer > conf.AdvancedVehicleAI.MaxTrafficBuffer) { LaneTrafficData[segmentId][laneIndex].accumulatedSpeeds /= LaneTrafficData[segmentId][laneIndex].trafficBuffer / conf.AdvancedVehicleAI.MaxTrafficBuffer; LaneTrafficData[segmentId][laneIndex].trafficBuffer = (ushort)conf.AdvancedVehicleAI.MaxTrafficBuffer; } else if (LaneTrafficData[segmentId][laneIndex].trafficBuffer == conf.AdvancedVehicleAI.MaxTrafficBuffer) { LaneTrafficData[segmentId][laneIndex].accumulatedSpeeds = 0; LaneTrafficData[segmentId][laneIndex].trafficBuffer = 0; } } else { LaneTrafficData[segmentId][laneIndex].accumulatedSpeeds = 0; LaneTrafficData[segmentId][laneIndex].trafficBuffer = 0; } } laneIndex++; curLaneId = curLaneId.ToLane().m_nextLane; } for (int i = 0; i < 2; ++i) { int segDirIndex = i == 0 ? GetDirIndex(segmentId, NetInfo.Direction.Forward) : GetDirIndex(segmentId, NetInfo.Direction.Backward); if (meanSpeedLanes[i] > 0) { SegmentDirTrafficData[segDirIndex].meanSpeed = (ushort)Math.Min( REF_REL_SPEED, meanSpeeds[i] / meanSpeedLanes[i]); } else { SegmentDirTrafficData[segDirIndex].meanSpeed = REF_REL_SPEED; } } }
public bool IsTramLane(NetInfo.Lane laneInfo) { return((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Tram) != VehicleInfo.VehicleType.None); }
public void BuildUp(NetInfo info, NetInfoVersion version) { /////////////////////////// // Template // /////////////////////////// if (version == NetInfoVersion.GroundGrass || version == NetInfoVersion.GroundTrees) { var roadInfo = Prefabs.Find <NetInfo>(NetInfos.Vanilla.ROAD_2L); info.m_segments = roadInfo.m_segments.Select(x => x.ShallowClone()).ToArray(); info.m_nodes = roadInfo.m_nodes.Select(x => x.ShallowClone()).ToArray(); info.m_lanes = roadInfo.m_lanes.Select(x => x.ShallowClone()).ToArray(); } /////////////////////////// // 3DModeling // /////////////////////////// info.Setup16m3mSW3mMdnMesh(version); /////////////////////////// // Texturing // /////////////////////////// SetupTextures(info, version); /////////////////////////// // Set up // /////////////////////////// info.m_hasParkingSpaces = false; info.m_pavementWidth = (version != NetInfoVersion.Slope && version != NetInfoVersion.Tunnel ? 3 : 6); info.m_halfWidth = (version != NetInfoVersion.Slope && version != NetInfoVersion.Tunnel ? 8 : 11); info.m_canCrossLanes = false; if (version == NetInfoVersion.Tunnel) { info.m_setVehicleFlags = Vehicle.Flags.Transition | Vehicle.Flags.Underground; info.m_setCitizenFlags = CitizenInstance.Flags.Transition | CitizenInstance.Flags.Underground; info.m_class = info.m_class.Clone("NEXTbasicroadmedian" + version.ToString()); } else { info.m_class = info.m_class.Clone("NEXTbasicroadmedian" + version.ToString()); } // Setting up lanes info.SetRoadLanes(version, new LanesConfiguration { IsTwoWay = true, LaneWidth = 3.3f, SpeedLimit = 0.8f, CenterLane = CenterLaneType.Median, CenterLaneWidth = 3.3f }); var leftPedLane = info.GetLeftRoadShoulder(); var rightPedLane = info.GetRightRoadShoulder(); //Setting Up Props var leftRoadProps = leftPedLane.m_laneProps.m_props.ToList(); var rightRoadProps = rightPedLane.m_laneProps.m_props.ToList(); var centerLane = new NetInfo.Lane(); centerLane.m_position = 0; centerLane.m_laneProps = ScriptableObject.CreateInstance <NetLaneProps>(); centerLane.m_laneProps.name = "Center Lane Props"; centerLane.m_vehicleType = VehicleInfo.VehicleType.None; var centerLaneProps = new List <NetLaneProps.Prop>(); if (version == NetInfoVersion.GroundTrees) { var treeProp = new NetLaneProps.Prop() { m_tree = Prefabs.Find <TreeInfo>("Tree2variant"), m_repeatDistance = 20, m_probability = 100, }; treeProp.m_position.x = 0; centerLaneProps.Add(treeProp); } else if (version == NetInfoVersion.Slope) { leftRoadProps.AddLeftWallLights(info.m_pavementWidth); rightRoadProps.AddRightWallLights(info.m_pavementWidth); } centerLane.m_laneProps.m_props = centerLaneProps.ToArray(); leftPedLane.m_laneProps.m_props = leftRoadProps.ToArray(); rightPedLane.m_laneProps.m_props = rightRoadProps.ToArray(); var lanes = info.m_lanes.ToList(); lanes.Add(centerLane); info.m_lanes = lanes.ToArray(); //info.TrimAboveGroundProps(version); //info.SetupNewSpeedLimitProps(50, 40); // AI //var owPlayerNetAI = roadInfo.GetComponent<PlayerNetAI>(); //var playerNetAI = info.GetComponent<PlayerNetAI>(); //if (owPlayerNetAI != null && playerNetAI != null) //{ // playerNetAI.m_constructionCost = owPlayerNetAI.m_constructionCost ; // Charge by the lane? // playerNetAI.m_maintenanceCost = owPlayerNetAI.m_maintenanceCost; // Charge by the lane? //} var roadBaseAI = info.GetComponent <RoadBaseAI>(); if (roadBaseAI != null) { roadBaseAI.m_trafficLights = false; } }
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 } }
/// <summary> /// coppies vehicle restrictions of the current segment /// and applies them to all segments until the next junction. /// </summary> /// <param name="sortedLaneIndex">if provided only current lane is considered</param> /// <param name="vehicleTypes"> /// if provided only bits for which vehicleTypes is set are considered. /// </param> private void ApplyRestrictionsToAllSegments( int?sortedLaneIndex = null, ExtVehicleType?vehicleTypes = null) { NetManager netManager = Singleton <NetManager> .instance; NetInfo selectedSegmentInfo = netManager.m_segments.m_buffer[SelectedSegmentId].Info; bool LaneVisitorFun(SegmentLaneVisitData data) { if (data.SegVisitData.Initial) { return(true); } if (sortedLaneIndex != null && data.SortedLaneIndex != sortedLaneIndex) { return(true); } ushort segmentId = data.SegVisitData.CurSeg.segmentId; NetInfo segmentInfo = netManager.m_segments.m_buffer[segmentId].Info; byte selectedLaneIndex = data.InitLanePos.laneIndex; NetInfo.Lane selectedLaneInfo = selectedSegmentInfo.m_lanes[selectedLaneIndex]; uint laneId = data.CurLanePos.laneId; byte laneIndex = data.CurLanePos.laneIndex; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; // apply restrictions of selected segment & lane ExtVehicleType mask = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes( SelectedSegmentId, selectedSegmentInfo, selectedLaneIndex, selectedLaneInfo, VehicleRestrictionsMode.Configured);; if (vehicleTypes != null) { ExtVehicleType currentMask = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes( segmentId, segmentInfo, laneIndex, laneInfo, VehicleRestrictionsMode.Configured); // only apply changes where types is 1. that means: // for bits where types is 0, use currentMask, // for bits where types is 1, use initial mask. ExtVehicleType types2 = (ExtVehicleType)vehicleTypes; //cast mask = (types2 & mask) | (~types2 & currentMask); } VehicleRestrictionsManager.Instance.SetAllowedVehicleTypes( segmentId, segmentInfo, laneIndex, laneInfo, laneId, mask); RefreshCurrentRestrictedSegmentIds(segmentId); return(true); } SegmentLaneTraverser.Traverse( SelectedSegmentId, SegmentTraverser.TraverseDirection.AnyDirection, SegmentTraverser.TraverseSide.AnySide, SegmentLaneTraverser.LaneStopCriterion.LaneCount, SegmentTraverser.SegmentStopCriterion.Junction, VehicleRestrictionsManager.LANE_TYPES, VehicleRestrictionsManager.VEHICLE_TYPES, LaneVisitorFun); }
private NetInfo.Direction DrawParkingRestrictionHandles(ushort segmentId, bool clicked, ref NetSegment segment, bool viewOnly, ref Vector3 camPos) { if (viewOnly && !Options.parkingRestrictionsOverlay && !MassEditOverlay.IsActive) { return(NetInfo.Direction.None); } NetManager netManager = Singleton <NetManager> .instance; ParkingRestrictionsManager parkingManager = ParkingRestrictionsManager.Instance; NetInfo.Direction hoveredDirection = NetInfo.Direction.None; // draw parking restriction signs over mean middle points of lane beziers if (!segmentCenterByDir.TryGetValue( segmentId, out Dictionary <NetInfo.Direction, Vector3> segCenter)) { segCenter = new Dictionary <NetInfo.Direction, Vector3>(); segmentCenterByDir.Add(segmentId, segCenter); GeometryUtil.CalculateSegmentCenterByDir( segmentId, segCenter, SIGN_SIZE * TrafficManagerTool.MAX_ZOOM); } foreach (KeyValuePair <NetInfo.Direction, Vector3> e in segCenter) { bool allowed = parkingManager.IsParkingAllowed(segmentId, e.Key); if (allowed && viewOnly) { continue; } bool visible = GeometryUtil.WorldToScreenPoint(e.Value, out Vector3 screenPos); if (!visible) { continue; } float zoom = (1.0f / (e.Value - camPos).magnitude) * 100f * MainTool.GetBaseZoom(); float size = (viewOnly ? 0.8f : 1f) * SIGN_SIZE * zoom; Color guiColor = GUI.color; Rect boundingBox = new Rect( screenPos.x - (size / 2), screenPos.y - (size / 2), size, size); if (Options.speedLimitsOverlay || MassEditOverlay.IsActive) { boundingBox.y -= size + 10f; } bool hoveredHandle = !viewOnly && TrafficManagerTool.IsMouseOver(boundingBox); guiColor.a = TrafficManagerTool.GetHandleAlpha(hoveredHandle); if (hoveredHandle) { // mouse hovering over sign hoveredDirection = e.Key; } GUI.color = GUI.color.WithAlpha(TrafficManagerTool.OverlayAlpha); GUI.DrawTexture(boundingBox, RoadUI.ParkingRestrictionTextures[allowed]); GUI.color = guiColor; if (hoveredHandle && clicked && !IsCursorInPanel() && parkingManager.ToggleParkingAllowed(segmentId, hoveredDirection)) { allowed = !allowed; if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) { NetInfo.Direction normDir = e.Key; if ((netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) { normDir = NetInfo.InvertDirection(normDir); } bool LaneVisitor(SegmentLaneVisitData data) { if (data.SegVisitData.Initial) { return(true); } bool reverse = data.SegVisitData.ViaStartNode == data.SegVisitData.ViaInitialStartNode; ushort otherSegmentId = data.SegVisitData.CurSeg.segmentId; NetInfo otherSegmentInfo = netManager.m_segments.m_buffer[otherSegmentId].Info; byte laneIndex = data.CurLanePos.laneIndex; NetInfo.Lane laneInfo = otherSegmentInfo.m_lanes[laneIndex]; NetInfo.Direction otherNormDir = laneInfo.m_finalDirection; if (((netManager.m_segments.m_buffer[otherSegmentId].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) ^ reverse) { otherNormDir = NetInfo.InvertDirection(otherNormDir); } if (otherNormDir == normDir) { parkingManager.SetParkingAllowed( otherSegmentId, laneInfo.m_finalDirection, allowed); } return(true); } SegmentLaneTraverser.Traverse( segmentId, SegmentTraverser.TraverseDirection.AnyDirection, SegmentTraverser.TraverseSide.AnySide, SegmentLaneTraverser.LaneStopCriterion.LaneCount, SegmentTraverser.SegmentStopCriterion.Junction, ParkingRestrictionsManager.LANE_TYPES, ParkingRestrictionsManager.VEHICLE_TYPES, LaneVisitor); } } guiColor.a = 1f; GUI.color = guiColor; } return(hoveredDirection); }
private bool DrawVehicleRestrictionHandles(ushort segmentId, ref NetSegment segment, bool viewOnly, out bool stateUpdated) { stateUpdated = false; if (viewOnly && !Options.vehicleRestrictionsOverlay && MainTool.GetToolMode() != ToolMode.VehicleRestrictions) { return(false); } Vector3 center = segment.m_bounds.center; bool visible = GeometryUtil.WorldToScreenPoint(center, out Vector3 _); if (!visible) { return(false); } Vector3 camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; Vector3 diff = center - camPos; if (diff.sqrMagnitude > TrafficManagerTool.MAX_OVERLAY_DISTANCE_SQR) { return(false); // do not draw if too distant } int numLanes = GeometryUtil.GetSegmentNumVehicleLanes( segmentId, null, out int numDirections, VehicleRestrictionsManager.VEHICLE_TYPES); // draw vehicle restrictions over each lane NetInfo segmentInfo = segment.Info; Vector3 yu = (segment.m_endDirection - segment.m_startDirection).normalized; // if ((segment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) // yu = -yu; Vector3 xu = Vector3.Cross(yu, new Vector3(0, 1f, 0)).normalized; float f = viewOnly ? 4f : 7f; // reserved sign size in game coordinates int maxNumSigns = 0; if (VehicleRestrictionsManager.Instance.IsRoadSegment(segmentInfo)) { maxNumSigns = RoadVehicleTypes.Length; } else if (VehicleRestrictionsManager.Instance.IsRailSegment(segmentInfo)) { maxNumSigns = RailVehicleTypes.Length; } // Vector3 zero = center - 0.5f * (float)(numLanes + numDirections - 1) * f * (xu + yu); // "bottom left" Vector3 zero = center - (0.5f * (numLanes - 1 + numDirections - 1) * f * xu) - (0.5f * maxNumSigns * f * yu); // "bottom left" // if (!viewOnly) // Log._Debug($"xu: {xu.ToString()} yu: {yu.ToString()} center: {center.ToString()} // zero: {zero.ToString()} numLanes: {numLanes} numDirections: {numDirections}");*/ uint x = 0; Color guiColor = GUI.color; IList <LanePos> sortedLanes = Constants.ServiceFactory.NetService.GetSortedLanes( segmentId, ref segment, null, VehicleRestrictionsManager.LANE_TYPES, VehicleRestrictionsManager.VEHICLE_TYPES); bool hovered = false; HashSet <NetInfo.Direction> directions = new HashSet <NetInfo.Direction>(); int sortedLaneIndex = -1; foreach (LanePos laneData in sortedLanes) { ++sortedLaneIndex; uint laneId = laneData.laneId; byte laneIndex = laneData.laneIndex; NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; if (!directions.Contains(laneInfo.m_finalDirection)) { if (directions.Count > 0) { ++x; // space between different directions } directions.Add(laneInfo.m_finalDirection); } ExtVehicleType[] possibleVehicleTypes; if (VehicleRestrictionsManager.Instance.IsRoadLane(laneInfo)) { possibleVehicleTypes = RoadVehicleTypes; } else if (VehicleRestrictionsManager.Instance.IsRailLane(laneInfo)) { possibleVehicleTypes = RailVehicleTypes; } else { ++x; continue; } ExtVehicleType allowedTypes = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes( segmentId, segmentInfo, laneIndex, laneInfo, VehicleRestrictionsMode.Configured); uint y = 0; #if DEBUG_disabled_xxx Vector3 labelCenter = zero + f * (float)x * xu + f * (float)y * yu; // in game coordinates Vector3 labelScreenPos; bool visible = GeometryUtil.WorldToScreenPoint(labelCenter, out labelScreenPos); // BUGBUG: Using screen.height might be wrong, consider U.UIScaler.ScreenHeight (from UIView.fixedHeight) labelScreenPos.y = Screen.height - labelScreenPos.y; diff = labelCenter - camPos; var labelZoom = 1.0f / diff.magnitude * 100f; _counterStyle.fontSize = (int)(11f * labelZoom); _counterStyle.normal.textColor = new Color(1f, 1f, 0f); string labelStr = $"Idx {laneIndex}"; Vector2 dim = _counterStyle.CalcSize(new GUIContent(labelStr)); Rect labelRect = new Rect(labelScreenPos.x - dim.x / 2f, labelScreenPos.y, dim.x, dim.y); GUI.Label(labelRect, labelStr, _counterStyle); ++y; #endif Color guiColor2 = GUI.color; GUI.color = GUI.color.WithAlpha(TrafficManagerTool.OverlayAlpha); foreach (ExtVehicleType vehicleType in possibleVehicleTypes) { bool allowed = VehicleRestrictionsManager.Instance.IsAllowed(allowedTypes, vehicleType); if (allowed && viewOnly) { continue; // do not draw allowed vehicles in view-only mode } bool hoveredHandle = MainTool.DrawGenericSquareOverlayGridTexture( RoadUI.VehicleRestrictionTextures[vehicleType][allowed], camPos, zero, f, xu, yu, x, y, vehicleRestrictionsSignSize, !viewOnly); if (hoveredHandle) { hovered = true; renderData_.segmentId = segmentId; renderData_.laneId = laneId; renderData_.laneIndex = laneIndex; renderData_.laneInfo = laneInfo; renderData_.SortedLaneIndex = sortedLaneIndex; } if (hoveredHandle && MainTool.CheckClicked()) { // toggle vehicle restrictions // Log._Debug($"Setting vehicle restrictions of segment {segmentId}, lane // idx {laneIndex}, {vehicleType.ToString()} to {!allowed}"); VehicleRestrictionsManager.Instance.ToggleAllowedType( segmentId, segmentInfo, laneIndex, laneId, laneInfo, vehicleType, !allowed); stateUpdated = true; RefreshCurrentRestrictedSegmentIds(segmentId); if (RoadMode) { ApplyRestrictionsToAllSegments(sortedLaneIndex, vehicleType); } } ++y; } GUI.color = guiColor2; ++x; } guiColor.a = 1f; GUI.color = guiColor; return(hovered); }
/// <summary> /// Displays lane ids over lanes /// </summary> private void _guiLanes(ushort segmentId, ref NetSegment segment, ref NetInfo segmentInfo) { GUIStyle _counterStyle = new GUIStyle(); Vector3 centerPos = segment.m_bounds.center; var screenPos = Camera.main.WorldToScreenPoint(centerPos); screenPos.y = Screen.height - screenPos.y - 200; if (screenPos.z < 0) { return; } var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; var diff = centerPos - camPos; if (diff.magnitude > DebugCloseLod) { return; // do not draw if too distant } var zoom = 1.0f / diff.magnitude * 150f; _counterStyle.fontSize = (int)(11f * zoom); _counterStyle.normal.textColor = new Color(1f, 1f, 0f); uint totalDensity = 0u; uint curLaneId = segment.m_lanes; for (int i = 0; i < segmentInfo.m_lanes.Length; ++i) { if (curLaneId == 0) { break; } if (CustomRoadAI.currentLaneDensities[segmentId] != null && i < CustomRoadAI.currentLaneDensities[segmentId].Length) { totalDensity += CustomRoadAI.currentLaneDensities[segmentId][i]; } curLaneId = Singleton <NetManager> .instance.m_lanes.m_buffer[curLaneId].m_nextLane; } curLaneId = segment.m_lanes; String labelStr = ""; for (int i = 0; i < segmentInfo.m_lanes.Length; ++i) { if (curLaneId == 0) { break; } NetInfo.Lane laneInfo = segmentInfo.m_lanes[i]; labelStr += "Lane idx " + i + ", id " + curLaneId; #if DEBUG labelStr += ", flags: " + ((NetLane.Flags)Singleton <NetManager> .instance.m_lanes.m_buffer[curLaneId].m_flags).ToString() + ", limit: " + SpeedLimitManager.GetCustomSpeedLimit(curLaneId) + " km/h, dir: " + laneInfo.m_direction + ", final: " + laneInfo.m_finalDirection + ", pos: " + String.Format("{0:0.##}", laneInfo.m_position) + ", sim. idx: " + laneInfo.m_similarLaneIndex + " for " + laneInfo.m_vehicleType + "/" + laneInfo.m_laneType; #endif /*if (CustomRoadAI.InStartupPhase) * labelStr += ", in start-up phase"; * else*/ labelStr += ", avg. speed: " + (CustomRoadAI.laneMeanSpeeds[segmentId] != null && i < CustomRoadAI.laneMeanSpeeds[segmentId].Length ? "" + CustomRoadAI.laneMeanSpeeds[segmentId][i] : "?") + " %"; labelStr += ", rel. density: " + (CustomRoadAI.laneMeanRelDensities[segmentId] != null && i < CustomRoadAI.laneMeanRelDensities[segmentId].Length ? "" + CustomRoadAI.laneMeanRelDensities[segmentId][i] : "?") + " %"; #if ABSDENSITY labelStr += ", abs. density: " + (CustomRoadAI.laneMeanAbsDensities[segmentId] != null && i < CustomRoadAI.laneMeanAbsDensities[segmentId].Length ? "" + CustomRoadAI.laneMeanAbsDensities[segmentId][i] : "?") + " %"; #endif #if DEBUG labelStr += " (" + (CustomRoadAI.currentLaneDensities[segmentId] != null && i < CustomRoadAI.currentLaneDensities[segmentId].Length ? "" + CustomRoadAI.currentLaneDensities[segmentId][i] : "?") + "/" + totalDensity + ")"; #endif labelStr += "\n"; curLaneId = Singleton <NetManager> .instance.m_lanes.m_buffer[curLaneId].m_nextLane; } Vector2 dim = _counterStyle.CalcSize(new GUIContent(labelStr)); Rect labelRect = new Rect(screenPos.x - dim.x / 2f, screenPos.y, dim.x, dim.y); GUI.Label(labelRect, labelStr, _counterStyle); }
public override void SimulationStep(ushort segmentID, ref NetSegment data) { //Start PlayerNEtAI.SimulationStep if (this.HasMaintenanceCost(segmentID, ref data)) { NetManager playerNetAIinstance = Singleton <NetManager> .instance; Vector3 playerNetAIposition = playerNetAIinstance.m_nodes.m_buffer[(int)data.m_startNode].m_position; Vector3 playerNetAIposition2 = playerNetAIinstance.m_nodes.m_buffer[(int)data.m_endNode].m_position; int playerNetAInum = this.GetMaintenanceCost(playerNetAIposition, playerNetAIposition2); bool playerNetAIflag = (ulong)(Singleton <SimulationManager> .instance.m_currentFrameIndex >> 8 & 15u) == (ulong)((long)(segmentID & 15)); if (playerNetAInum != 0) { if (playerNetAIflag) { playerNetAInum = playerNetAInum * 16 / 100 - playerNetAInum / 100 * 15; } else { playerNetAInum /= 100; } Singleton <EconomyManager> .instance.FetchResource(EconomyManager.Resource.Maintenance, playerNetAInum, this.m_info.m_class); } if (playerNetAIflag) { float playerNetAInum2 = (float)playerNetAIinstance.m_nodes.m_buffer[(int)data.m_startNode].m_elevation; float playerNetAInum3 = (float)playerNetAIinstance.m_nodes.m_buffer[(int)data.m_endNode].m_elevation; if (this.IsUnderground()) { playerNetAInum2 = -playerNetAInum2; playerNetAInum3 = -playerNetAInum3; } int constructionCost = this.GetConstructionCost(playerNetAIposition, playerNetAIposition2, playerNetAInum2, playerNetAInum3); if (constructionCost != 0) { StatisticBase statisticBase = Singleton <StatisticsManager> .instance.Acquire <StatisticInt64>(StatisticType.CityValue); if (statisticBase != null) { statisticBase.Add(constructionCost); } } } } //End PlayerNEtAI.SimulationStep SimulationManager instance = Singleton <SimulationManager> .instance; NetManager instance2 = Singleton <NetManager> .instance; Notification.Problem problem = Notification.RemoveProblems(data.m_problems, Notification.Problem.Flood | Notification.Problem.Snow); if ((data.m_flags & NetSegment.Flags.AccessFailed) != NetSegment.Flags.None && Singleton <SimulationManager> .instance.m_randomizer.Int32(16u) == 0) { data.m_flags &= ~NetSegment.Flags.AccessFailed; } float num = 0f; uint num2 = data.m_lanes; int num3 = 0; while (num3 < this.m_info.m_lanes.Length && num2 != 0u) { NetInfo.Lane lane = this.m_info.m_lanes[num3]; if ((byte)(lane.m_laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0 && (lane.m_vehicleType & ~VehicleInfo.VehicleType.Bicycle) != VehicleInfo.VehicleType.None) { num += instance2.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_length; } num2 = instance2.m_lanes.m_buffer[(int)((UIntPtr)num2)].m_nextLane; num3++; } int num4 = 0; if (data.m_trafficBuffer == 65535) { if ((data.m_flags & NetSegment.Flags.Blocked) == NetSegment.Flags.None) { data.m_flags |= NetSegment.Flags.Blocked; data.m_modifiedIndex = instance.m_currentBuildIndex++; } } else { data.m_flags &= ~NetSegment.Flags.Blocked; int num5 = Mathf.RoundToInt(num) << 4; if (num5 != 0) { num4 = (int)((byte)Mathf.Min((int)(data.m_trafficBuffer * 100) / num5, 100)); } } data.m_trafficBuffer = 0; if (num4 > (int)data.m_trafficDensity) { data.m_trafficDensity = (byte)Mathf.Min((int)(data.m_trafficDensity + 5), num4); } else if (num4 < (int)data.m_trafficDensity) { data.m_trafficDensity = (byte)Mathf.Max((int)(data.m_trafficDensity - 5), num4); } Vector3 position = instance2.m_nodes.m_buffer[(int)data.m_startNode].m_position; Vector3 position2 = instance2.m_nodes.m_buffer[(int)data.m_endNode].m_position; Vector3 vector = (position + position2) * 0.5f; bool flag = false; if ((this.m_info.m_setVehicleFlags & Vehicle.Flags.Underground) == (Vehicle.Flags) 0) { float num6 = Singleton <TerrainManager> .instance.WaterLevel(VectorUtils.XZ(vector)); // NON-STOCK CODE START if (num6 > vector.y + (float)ModSettings.RoadwayFloodedTolerance / 100) { flag = true; data.m_flags |= NetSegment.Flags.Flooded; //Debug.Log("[RF] Successfully detoured roadway flooded tolerance"); problem = Notification.AddProblems(problem, Notification.Problem.Flood | Notification.Problem.MajorProblem); /*DisasterData floodedSinkHoleData = new DisasterData(); * floodedSinkHoleData.m_targetPosition = data.m_middlePosition; * floodedSinkHoleData.m_intensity = (byte)instance.m_randomizer.Int32(100u); */ Vector3 min = data.m_bounds.min; Vector3 max = data.m_bounds.max; RoadBaseAI.FloodParkedCars(min.x, min.z, max.x, max.z); } else { data.m_flags &= ~NetSegment.Flags.Flooded; // Rainfall compatibility float add = (float)ModSettings.RoadwayFloodingTolerance / 100; //Debug.Log("[RF] Successfully detoured roadway flooding tolerance"); if (num6 > vector.y + add) { flag = true; problem = Notification.AddProblems(problem, Notification.Problem.Flood); } } //Debug.Log("[RF] Successfully detoured roadway flooding tolerance: not flooding"); // NON-STOCK CODE END } DistrictManager instance3 = Singleton <DistrictManager> .instance; byte district = instance3.GetDistrict(vector); DistrictPolicies.CityPlanning cityPlanningPolicies = instance3.m_districts.m_buffer[(int)district].m_cityPlanningPolicies; int num7 = (int)(100 - (data.m_trafficDensity - 100) * (data.m_trafficDensity - 100) / 100); if ((this.m_info.m_vehicleTypes & VehicleInfo.VehicleType.Car) != VehicleInfo.VehicleType.None) { if ((this.m_info.m_setVehicleFlags & Vehicle.Flags.Underground) == (Vehicle.Flags) 0) { if (flag && (data.m_flags & (NetSegment.Flags.AccessFailed | NetSegment.Flags.Blocked)) == NetSegment.Flags.None && instance.m_randomizer.Int32(10u) == 0) { TransferManager.TransferOffer offer = default(TransferManager.TransferOffer); offer.Priority = 4; offer.NetSegment = segmentID; offer.Position = vector; offer.Amount = 1; Singleton <TransferManager> .instance.AddOutgoingOffer(TransferManager.TransferReason.FloodWater, offer); } int num8 = (int)data.m_wetness; if (!instance2.m_treatWetAsSnow) { if (flag) { num8 = 255; } else { int num9 = -(num8 + 63 >> 5); float num10 = Singleton <WeatherManager> .instance.SampleRainIntensity(vector, false); if (num10 != 0f) { int num11 = Mathf.RoundToInt(Mathf.Min(num10 * 4000f, 1000f)); num9 += instance.m_randomizer.Int32(num11, num11 + 99) / 100; } num8 = Mathf.Clamp(num8 + num9, 0, 255); } } else if (this.m_accumulateSnow) { if (flag) { num8 = 128; } else { float num12 = Singleton <WeatherManager> .instance.SampleRainIntensity(vector, false); if (num12 != 0f) { int num13 = Mathf.RoundToInt(num12 * 400f); int num14 = instance.m_randomizer.Int32(num13, num13 + 99) / 100; if (Singleton <UnlockManager> .instance.Unlocked(UnlockManager.Feature.Snowplow)) { num8 = Mathf.Min(num8 + num14, 255); } else { num8 = Mathf.Min(num8 + num14, 128); } } else if (Singleton <SimulationManager> .instance.m_randomizer.Int32(4u) == 0) { num8 = Mathf.Max(num8 - 1, 0); } if (num8 >= 64 && (data.m_flags & (NetSegment.Flags.AccessFailed | NetSegment.Flags.Blocked | NetSegment.Flags.Flooded)) == NetSegment.Flags.None && instance.m_randomizer.Int32(10u) == 0) { TransferManager.TransferOffer offer2 = default(TransferManager.TransferOffer); offer2.Priority = num8 / 50; offer2.NetSegment = segmentID; offer2.Position = vector; offer2.Amount = 1; Singleton <TransferManager> .instance.AddOutgoingOffer(TransferManager.TransferReason.Snow, offer2); } if (num8 >= 192) { problem = Notification.AddProblems(problem, Notification.Problem.Snow); } District[] expr_5B7_cp_0_cp_0 = instance3.m_districts.m_buffer; byte expr_5B7_cp_0_cp_1 = district; expr_5B7_cp_0_cp_0[(int)expr_5B7_cp_0_cp_1].m_productionData.m_tempSnowCover = expr_5B7_cp_0_cp_0[(int)expr_5B7_cp_0_cp_1].m_productionData.m_tempSnowCover + (uint)num8; } } if (num8 != (int)data.m_wetness) { if (Mathf.Abs((int)data.m_wetness - num8) > 10) { data.m_wetness = (byte)num8; InstanceID empty = InstanceID.Empty; empty.NetSegment = segmentID; instance2.AddSmoothColor(empty); empty.NetNode = data.m_startNode; instance2.AddSmoothColor(empty); empty.NetNode = data.m_endNode; instance2.AddSmoothColor(empty); } else { data.m_wetness = (byte)num8; instance2.m_wetnessChanged = 256; } } } int num15; if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.StuddedTires) != DistrictPolicies.CityPlanning.None) { num7 = num7 * 3 + 1 >> 1; num15 = Mathf.Min(700, (int)(50 + data.m_trafficDensity * 6)); } else { num15 = Mathf.Min(500, (int)(50 + data.m_trafficDensity * 4)); } if (!this.m_highwayRules) { int num16 = instance.m_randomizer.Int32(num15, num15 + 99) / 100; data.m_condition = (byte)Mathf.Max((int)data.m_condition - num16, 0); if (data.m_condition < 192 && (data.m_flags & (NetSegment.Flags.AccessFailed | NetSegment.Flags.Blocked | NetSegment.Flags.Flooded)) == NetSegment.Flags.None && instance.m_randomizer.Int32(20u) == 0) { TransferManager.TransferOffer offer3 = default(TransferManager.TransferOffer); offer3.Priority = (int)((255 - data.m_condition) / 50); offer3.NetSegment = segmentID; offer3.Position = vector; offer3.Amount = 1; Singleton <TransferManager> .instance.AddIncomingOffer(TransferManager.TransferReason.RoadMaintenance, offer3); } } } if (!this.m_highwayRules) { if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.HeavyTrafficBan) != DistrictPolicies.CityPlanning.None) { data.m_flags |= NetSegment.Flags.HeavyBan; } else { data.m_flags &= ~NetSegment.Flags.HeavyBan; } if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.BikeBan) != DistrictPolicies.CityPlanning.None) { data.m_flags |= NetSegment.Flags.BikeBan; } else { data.m_flags &= ~NetSegment.Flags.BikeBan; } if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.OldTown) != DistrictPolicies.CityPlanning.None) { data.m_flags |= NetSegment.Flags.CarBan; } else { data.m_flags &= ~NetSegment.Flags.CarBan; } } int num17 = this.m_noiseAccumulation * num7 / 100; if (num17 != 0) { float num18 = Vector3.Distance(position, position2); int num19 = Mathf.FloorToInt(num18 / this.m_noiseRadius); for (int i = 0; i < num19; i++) { Vector3 position3 = Vector3.Lerp(position, position2, (float)(i + 1) / (float)(num19 + 1)); Singleton <ImmaterialResourceManager> .instance.AddResource(ImmaterialResourceManager.Resource.NoisePollution, num17, position3, this.m_noiseRadius); } } if (data.m_trafficDensity >= 50 && data.m_averageLength < 25f && (instance2.m_nodes.m_buffer[(int)data.m_startNode].m_flags & (NetNode.Flags.LevelCrossing | NetNode.Flags.TrafficLights)) == NetNode.Flags.TrafficLights && (instance2.m_nodes.m_buffer[(int)data.m_endNode].m_flags & (NetNode.Flags.LevelCrossing | NetNode.Flags.TrafficLights)) == NetNode.Flags.TrafficLights) { GuideController properties = Singleton <GuideManager> .instance.m_properties; if (properties != null) { Singleton <NetManager> .instance.m_shortRoadTraffic.Activate(properties.m_shortRoadTraffic, segmentID); } } if ((data.m_flags & NetSegment.Flags.Collapsed) != NetSegment.Flags.None) { GuideController properties2 = Singleton <GuideManager> .instance.m_properties; if (properties2 != null) { Singleton <NetManager> .instance.m_roadDestroyed.Activate(properties2.m_roadDestroyed, segmentID); Singleton <NetManager> .instance.m_roadDestroyed2.Activate(properties2.m_roadDestroyed2, this.m_info.m_class.m_service); } if ((ulong)(instance.m_currentFrameIndex >> 8 & 15u) == (ulong)((long)(segmentID & 15))) { int delta = Mathf.RoundToInt(data.m_averageLength); StatisticBase statisticBase = Singleton <StatisticsManager> .instance.Acquire <StatisticInt32>(StatisticType.DestroyedLength); statisticBase.Add(delta); } } data.m_problems = problem; }
internal float GetLockFreeGameSpeedLimit(ushort segmentId, uint laneIndex, uint laneId, NetInfo.Lane laneInfo) { float speedLimit = 0; ushort?[] fastArray = Flags.laneSpeedLimitArray[segmentId]; if (fastArray != null && fastArray.Length > laneIndex && fastArray[laneIndex] != null) { speedLimit = ToGameSpeedLimit((ushort)fastArray[laneIndex]); } else { speedLimit = laneInfo.m_speedLimit; } return(speedLimit); }
private bool GetStopPosition(TransportInfo info, ushort segment, ushort building, ushort firstStop, ref Vector3 hitPos, out bool fixedPlatform) { bool alternateMode = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift); fixedPlatform = false; if (segment != 0) { NetManager instance = Singleton <NetManager> .instance; if (!alternateMode && (instance.m_segments.m_buffer [(int)segment].m_flags & NetSegment.Flags.Untouchable) != NetSegment.Flags.None) { building = NetSegment.FindOwnerBuilding(segment, 363f); if (building != 0) { BuildingManager instance3 = Singleton <BuildingManager> .instance; BuildingInfo info3 = instance3.m_buildings.m_buffer[(int)building].Info; TransportInfo transportLineInfo = info3.m_buildingAI.GetTransportLineInfo(); if (transportLineInfo != null && transportLineInfo.m_transportType == info.m_transportType) { segment = 0; } else { building = 0; } } } Vector3 point; int num; float num2; Vector3 vector; int num3; float num4; if (segment != 0 && instance.m_segments.m_buffer[(int)segment].GetClosestLanePosition(hitPos, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, out point, out num, out num2) && instance.m_segments.m_buffer[(int)segment].GetClosestLanePosition(point, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, out vector, out num3, out num4)) { PathUnit.Position pathPos; pathPos.m_segment = segment; pathPos.m_lane = (byte)num3; pathPos.m_offset = 128; NetInfo.Lane lane = instance.m_segments.m_buffer[(int)segment].Info.m_lanes[num3]; if (!lane.m_allowStop) { return(false); } float num5 = lane.m_stopOffset; if ((instance.m_segments.m_buffer[(int)segment].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) { num5 = -num5; } uint laneID = PathManager.GetLaneID(pathPos); Vector3 vector2; instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CalculateStopPositionAndDirection((float)pathPos.m_offset * 0.003921569f, num5, out hitPos, out vector2); fixedPlatform = true; return(true); } } if (!alternateMode && building != 0) { VehicleInfo randomVehicleInfo = Singleton <VehicleManager> .instance.GetRandomVehicleInfo(ref Singleton <SimulationManager> .instance.m_randomizer, info.m_class.m_service, info.m_class.m_subService, info.m_class.m_level); if (randomVehicleInfo != null) { BuildingManager instance2 = Singleton <BuildingManager> .instance; BuildingInfo info2 = instance2.m_buildings.m_buffer[(int)building].Info; if (info2.m_buildingAI.GetTransportLineInfo() != null) { Vector3 vector3 = Vector3.zero; int num6 = 1000000; for (int i = 0; i < 12; i++) { Randomizer randomizer = new Randomizer(i); Vector3 vector4; Vector3 a; info2.m_buildingAI.CalculateSpawnPosition(building, ref instance2.m_buildings.m_buffer[(int)building], ref randomizer, randomVehicleInfo, out vector4, out a); int lineCount = this.GetLineCount(vector4, a - vector4, info.m_transportType); if (lineCount < num6) { vector3 = vector4; num6 = lineCount; } } if (firstStop != 0) { Vector3 position = Singleton <NetManager> .instance.m_nodes.m_buffer[(int)firstStop].m_position; if (Vector3.SqrMagnitude(position - vector3) < 16384f && instance2.FindBuilding(vector3, 128f, info.m_class.m_service, info.m_class.m_subService, Building.Flags.None, Building.Flags.None) == building) { hitPos = position; return(true); } } hitPos = vector3; return(true); } } } return(false); }