private static void AddLaneData(int i, Configuration configuration) { try { NetLane lane = Singleton <NetManager> .instance.m_lanes.m_buffer[i]; NetLane.Flags flags = (NetLane.Flags)lane.m_flags; if ((flags & NetLane.Flags.LeftForwardRight) == NetLane.Flags.None) // only save lanes with explicit lane arrows { return; } var laneSegmentId = lane.m_segment; if (laneSegmentId <= 0) { return; } NetSegment segment = Singleton <NetManager> .instance.m_segments.m_buffer[laneSegmentId]; if (segment.m_flags == NetSegment.Flags.None) { return; } //if (TrafficPriority.PrioritySegments.ContainsKey(laneSegmentId)) { Log.Message($"Saving lane data for lane {i}, segment {laneSegmentId}"); configuration.LaneFlags += $"{i}:{Singleton<NetManager>.instance.m_lanes.m_buffer[i].m_flags},"; //} } catch (Exception e) { Log.Error($"Error saving NodeLaneData {e.Message}"); } }
static bool Prefix(NetLane.Flags ___m_stopFlag, VehicleInfo.VehicleType ___m_vehicleType, ushort nodeID, ref NetNode data, uint laneID, byte offset) { if (nodeID == 0 || !___m_vehicleType.IsValidTransport()) { return(true); } var segment = Singleton <NetManager> .instance.m_lanes.m_buffer[laneID].m_segment; Log.Debug($"AddLaneConn on segment {segment}"); var roadAi = Singleton <NetManager> .instance.m_segments.m_buffer[segment].Info.m_netAI; if (roadAi is not RoadBridgeAI) { return(true); } var flags = (NetLane.Flags)Singleton <NetManager> .instance.m_lanes.m_buffer[laneID].m_flags; flags |= ___m_stopFlag; Singleton <NetManager> .instance.m_lanes.m_buffer[laneID].m_flags = (ushort)flags; Log.Debug($"lane flags updated {(NetLane.Flags)Singleton<NetManager>.instance.m_lanes.m_buffer[laneID].m_flags}"); if (roadAi is RoadBridgeAI roadBridgeAI) { roadBridgeAI.UpdateSegmentStopFlags(segment, ref Singleton <NetManager> .instance.m_segments.m_buffer[segment]); } Log.Debug($"segment flags updated {Singleton<NetManager>.instance.m_segments.m_buffer[segment].m_flags}"); return(true); }
static bool Prefix(NetLane.Flags ___m_stopFlag, VehicleInfo.VehicleType ___m_vehicleType, ushort nodeID, ref NetNode data) { if (nodeID == 0 || !___m_vehicleType.IsValidTransport()) { return(true); } ushort segment = Singleton <NetManager> .instance.m_lanes.m_buffer[data.m_lane].m_segment; Log.Debug($"RemoveLaneConn on segment {segment}"); NetAI roadAi = Singleton <NetManager> .instance.m_segments.m_buffer[segment].Info.m_netAI; if (!(roadAi is RoadBridgeAI)) { return(true); } NetLane.Flags flags = (NetLane.Flags)Singleton <NetManager> .instance.m_lanes.m_buffer[data.m_lane].m_flags; flags &= ~___m_stopFlag; Singleton <NetManager> .instance.m_lanes.m_buffer[data.m_lane].m_flags = (ushort)flags; Log.Debug($"lane flags updated {(NetLane.Flags)Singleton<NetManager>.instance.m_lanes.m_buffer[data.m_lane].m_flags}"); if (roadAi is RoadBridgeAI roadBridgeAI) { roadBridgeAI.UpdateSegmentStopFlags(segment, ref Singleton <NetManager> .instance.m_segments.m_buffer[segment]); } Log.Debug($"segment flags updated {Singleton<NetManager>.instance.m_segments.m_buffer[segment].m_flags}"); return(true); }
static void Postfix(uint __state) { if (__state == 0) { return; } NetLane lane = Singleton <NetManager> .instance.m_lanes.m_buffer[__state]; int index = Singleton <SharedStopsTool> .instance.sharedStopSegments.FindIndex(s => s.m_lanes.Keys.Contains(__state)); if (index == -1) { return; } foreach (var line in Singleton <SharedStopsTool> .instance.sharedStopSegments[index].m_lanes[__state]) { NetLane.Flags stopflag = Singleton <TransportManager> .instance.m_lines.m_buffer[line].Info.m_stopFlag; if (((NetLane.Flags)lane.m_flags & stopflag) == stopflag) { continue; } lane.m_flags |= (ushort)stopflag; } Singleton <NetManager> .instance.m_lanes.m_buffer[__state].m_flags = lane.m_flags; Log.Debug($"lane flags after update: {(NetLane.Flags)Singleton<NetManager>.instance.m_lanes.m_buffer[__state].m_flags}"); Singleton <NetManager> .instance.UpdateSegmentFlags(Singleton <NetManager> .instance.m_lanes.m_buffer[__state].m_segment); Singleton <NetManager> .instance.UpdateSegmentRenderer(Singleton <NetManager> .instance.m_lanes.m_buffer[__state].m_segment, true); }
static bool Prefix(out uint __state, VehicleInfo.VehicleType ___m_vehicleType, ushort nodeID, ref NetNode data) { __state = 0; if (nodeID == 0 || !___m_vehicleType.IsSharedStopTransport()) { return(true); } ushort segment = Singleton <NetManager> .instance.m_lanes.m_buffer[data.m_lane].m_segment; ushort lineID = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeID].m_transportLine; TransportLine line = Singleton <TransportManager> .instance.m_lines.m_buffer[lineID]; __state = data.m_lane; NetLane.Flags flags = (NetLane.Flags)Singleton <NetManager> .instance.m_lanes.m_buffer[data.m_lane].m_flags; if (!Singleton <SharedStopsTool> .instance.sharedStopSegments.Any(s => s.m_segment == segment)) { return(true); } NetSegment segData = Singleton <NetManager> .instance.m_segments.m_buffer[segment]; Log.Debug($"RemoveLaneConn on segment {segment}, {segData}"); Singleton <SharedStopsTool> .instance.RemoveSharedStop(segment, lineID, data.m_lane); return(true); }
NetLanes(NetLane.Flags flags = NetLane.Flags.Created) { var mgr = Singleton <Cities::NetManager> .instance; return(mgr.m_lanes.m_buffer.Where(e => ((NetLane.Flags)e.m_flags & flags) != NetLane.Flags.None )); }
/// <summary> /// Check lane flags contain at least one of the flags in <paramref name="flagMask"/>. /// </summary> /// /// <param name="laneId">The id of the lane to inspect.</param> /// <param name="flagMask">The flags to test for.</param> /// <param name="expectedResult">If specified, ensure only the expected flags are found.</param> /// /// <returns>Returns <c>true</c> if the test passes, otherwise <c>false</c>.</returns> public bool CheckLaneFlags(uint laneId, NetLane.Flags flagMask, NetLane.Flags?expectedResult = null) { uint result = Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_flags & (uint)flagMask; return(expectedResult == null ? result != 0 : result == (uint)expectedResult); }
public static bool AllFlagsAreForward(ushort segmentID, bool startNode) { NetLane.Flags flags = 0; foreach (var lane in NetUtil.IterateLanes(segmentID, startNode:startNode)) { flags |= lane.Flags; } return((flags & NetLane.Flags.LeftForwardRight) == NetLane.Flags.Forward); }
public bool CheckLaneFlags(uint laneId, NetLane.Flags flagMask, NetLane.Flags?expectedResult = null) { bool ret = false; ProcessLane(laneId, delegate(uint lId, ref NetLane lane) { ret = LogicUtil.CheckFlags((uint)lane.m_flags, (uint)flagMask, (uint?)expectedResult); return(true); }); return(ret); }
protected override bool IsActive() { if (LaneId == 0) { Log.Error("LaneArrowButton: LaneId is 0, too bad"); return(false); } NetLane.Flags flags = (NetLane.Flags)LaneId.ToLane().m_flags; return((flags & NetlaneFlagsMask) == NetlaneFlagsMask); }
protected override bool IsActive() { if (LaneId == 0) { Log.Error("LaneArrowButton: LaneId is 0, too bad"); return(false); } NetLane[] lanesBuffer = Singleton <NetManager> .instance.m_lanes.m_buffer; NetLane.Flags flags = (NetLane.Flags)lanesBuffer[LaneId].m_flags; return((flags & NetlaneFlagsMask) == NetlaneFlagsMask); }
public void UpdateArrows() { VerifyConnections(); NetLane lane = NetManager.instance.m_lanes.m_buffer[m_laneId]; NetSegment segment = NetManager.instance.m_segments.m_buffer[lane.m_segment]; if ((m_nodeId == 0 && !FindNode(segment)) || NetManager.instance.m_nodes.m_buffer[m_nodeId].CountSegments() <= 2) { return; } if (ConnectionCount() == 0) { if ((lane.m_flags & TrafficManager_ImprovedAI.SerializableDataExtension.CONTROL_BIT) != TrafficManager_ImprovedAI.SerializableDataExtension.CONTROL_BIT) { SetDefaultArrows(lane.m_segment, ref NetManager.instance.m_segments.m_buffer[lane.m_segment]); } return; } NetLane.Flags flags = (NetLane.Flags)lane.m_flags; flags &= ~(NetLane.Flags.LeftForwardRight); Vector3 segDir = segment.GetDirection(m_nodeId); uint[] connections = GetConnectionsAsArray(); foreach (uint connection in connections) { ushort seg = NetManager.instance.m_lanes.m_buffer[connection].m_segment; Vector3 dir = NetManager.instance.m_segments.m_buffer[seg].GetDirection(m_nodeId); if (Vector3.Angle(segDir, dir) > 150f) { flags |= NetLane.Flags.Forward; } else { if (Vector3.Dot(Vector3.Cross(segDir, -dir), Vector3.up) > 0f) { flags |= NetLane.Flags.Right; } else { flags |= NetLane.Flags.Left; } } } NetManager.instance.m_lanes.m_buffer[m_laneId].m_flags = (ushort)flags; }
public void DrawButton(uint lane, NetLane.Flags flag, Vector3 relativePosition) { this.laneId = lane; this.toggleFlag = (ushort)flag; this.relativePosition = relativePosition; this.normalBgSprite = "ButtonMenu"; this.disabledBgSprite = "ButtonMenuDisabled"; this.hoveredBgSprite = "ButtonMenuHovered"; this.pressedBgSprite = "ButtonMenuPressed"; this.pressedColor = new Color(0f, 0.6f, 0f); this.eventClick += ButtonClick; this.text = flag == NetLane.Flags.Forward ? "F" : flag == NetLane.Flags.Left ? "L" : "R"; this.height = 30; this.width = 30; UpdateButtonState(); }
public static void UpdateSegmentStopFlags(this RoadBridgeAI roadbridge, ushort segmentID, ref NetSegment data) { Log.Debug($"updateflags on {segmentID}"); roadbridge.UpdateSegmentFlags(segmentID, ref data); NetSegment.Flags flags = data.m_flags & ~(NetSegment.Flags.StopRight | NetSegment.Flags.StopLeft | NetSegment.Flags.StopRight2 | NetSegment.Flags.StopLeft2); if (roadbridge.m_info.m_lanes == null) { return; } NetManager instance = Singleton <NetManager> .instance; bool inverted = (data.m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None; uint lane = instance.m_segments.m_buffer[(int)segmentID].m_lanes; int i = 0; while (i < roadbridge.m_info.m_lanes.Length && lane != 0U) { NetLane.Flags laneFlags = (NetLane.Flags)instance.m_lanes.m_buffer[(int)((UIntPtr)lane)].m_flags; if ((laneFlags & NetLane.Flags.Stop) != NetLane.Flags.None) { if (roadbridge.m_info.m_lanes[i].m_position < 0f != inverted) { flags |= NetSegment.Flags.StopLeft; } else { flags |= NetSegment.Flags.StopRight; } } else if ((laneFlags & NetLane.Flags.Stop2) != NetLane.Flags.None) { if (roadbridge.m_info.m_lanes[i].m_position < 0f != inverted) { flags |= NetSegment.Flags.StopLeft2; } else { flags |= NetSegment.Flags.StopRight2; } } lane = instance.m_lanes.m_buffer[(int)((UIntPtr)lane)].m_nextLane; i++; } data.m_flags = flags; Log.Debug($"flags {flags}"); }
public static void UpdateSegmentStopFlags(this RoadBridgeAI roadbridge, ushort segmentID, ref NetSegment data) { roadbridge.UpdateSegmentFlags(segmentID, ref data); var oldflags = data.m_flags; NetSegment.Flags flags = data.m_flags & ~(NetSegment.Flags.StopRight | NetSegment.Flags.StopLeft | NetSegment.Flags.StopRight2 | NetSegment.Flags.StopLeft2); if (roadbridge.m_info.m_lanes != null) { NetManager instance = Singleton <NetManager> .instance; bool flag = (data.m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None; uint num = instance.m_segments.m_buffer[(int)segmentID].m_lanes; int num2 = 0; while (num2 < roadbridge.m_info.m_lanes.Length && num != 0U) { NetLane.Flags flags2 = (NetLane.Flags)instance.m_lanes.m_buffer[(int)((UIntPtr)num)].m_flags; if ((flags2 & NetLane.Flags.Stop) != NetLane.Flags.None) { if (roadbridge.m_info.m_lanes[num2].m_position < 0f != flag) { flags |= NetSegment.Flags.StopLeft; } else { flags |= NetSegment.Flags.StopRight; } } if ((flags2 & NetLane.Flags.Stop2) != NetLane.Flags.None) { if (roadbridge.m_info.m_lanes[num2].m_position < 0f != flag) { flags |= NetSegment.Flags.StopLeft2; } else { flags |= NetSegment.Flags.StopRight2; } } num = instance.m_lanes.m_buffer[(int)((UIntPtr)num)].m_nextLane; num2++; } } Log.Debug($"oldflags {oldflags} newflags {flags} on segment {segmentID} bridge"); data.m_flags = flags; }
private static void UpdateLaneMarker(NetLane.Flags flag, NetInfo.Direction direction, NetSegment segment) { NetManager netManager = NetManager.instance; NetLane currentLane = netManager.m_lanes.m_buffer[segment.m_lanes]; ulong laneID = segment.m_lanes; for (int i = 0; i < segment.Info.m_lanes.Length; i++) { if (segment.Info.m_lanes[i].m_direction == direction && segment.Info.m_lanes[i].m_laneType == NetInfo.LaneType.Vehicle && ((NetLane.Flags)currentLane.m_flags & flag) == flag) { NetLane.Flags newFlags = (NetLane.Flags)currentLane.m_flags; newFlags &= ~flag; newFlags |= NetLane.Flags.Forward; netManager.m_lanes.m_buffer[laneID].m_flags = (ushort)newFlags; } laneID = currentLane.m_nextLane; currentLane = netManager.m_lanes.m_buffer[currentLane.m_nextLane]; } }
static bool Prefix(NetLane.Flags ___m_stopFlag, VehicleInfo.VehicleType ___m_vehicleType, ushort nodeID, ref NetNode data, uint laneID, byte offset) { if (nodeID == 0 || !___m_vehicleType.IsSharedStopTransport()) { return(true); } ushort segment = Singleton <NetManager> .instance.m_lanes.m_buffer[laneID].m_segment; ushort lineID = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeID].m_transportLine; if (Singleton <NetManager> .instance.m_segments.m_buffer[segment].Info.m_netAI is RoadBridgeAI roadBridgeAI) { NetLane.Flags flags = (NetLane.Flags)Singleton <NetManager> .instance.m_lanes.m_buffer[laneID].m_flags; flags |= ___m_stopFlag; Singleton <NetManager> .instance.m_lanes.m_buffer[laneID].m_flags = (ushort)flags; roadBridgeAI.UpdateSegmentStopFlags(segment, ref Singleton <NetManager> .instance.m_segments.m_buffer[segment]); } Singleton <SharedStopsTool> .instance.AddSharedStop(segment, lineID, laneID); return(true); }
public static bool CheckLaneConnection(uint lane1, uint lane2, ushort nodeID) { if ((NetManager.instance.m_lanes.m_buffer[lane1].m_flags & Lane.CONTROL_BIT) == Lane.CONTROL_BIT) { var lane = GetLane(lane1); if (lane != null && lane.ConnectionCount() > 0) { return(CheckLaneConnection(lane1, lane2)); } } ushort seg1 = NetManager.instance.m_lanes.m_buffer[lane1].m_segment; ushort seg2 = NetManager.instance.m_lanes.m_buffer[lane2].m_segment; Vector3 dir1 = NetManager.instance.m_segments.m_buffer[seg1].GetDirection(nodeID); Vector3 dir2 = NetManager.instance.m_segments.m_buffer[seg2].GetDirection(nodeID); NetLane.Flags flags = (NetLane.Flags)NetManager.instance.m_lanes.m_buffer[lane1].m_flags; if ((flags & NetLane.Flags.LeftForwardRight) == 0 || seg1 == seg2) { return(true); } else if (Vector3.Angle(dir1, dir2) > 150f) { return((flags & NetLane.Flags.Forward) == NetLane.Flags.Forward); } else { if (Vector3.Dot(Vector3.Cross(dir1, -dir2), Vector3.up) > 0f) { return((flags & NetLane.Flags.Right) == NetLane.Flags.Right); } else { return((flags & NetLane.Flags.Left) == NetLane.Flags.Left); } } }
private static void Mirror(ref NetLane.Flags direction) { switch (direction) { case NetLane.Flags.Left: direction = NetLane.Flags.Right; break; case NetLane.Flags.Right: direction = NetLane.Flags.Left; break; case NetLane.Flags.LeftForward: direction = NetLane.Flags.ForwardRight; break; case NetLane.Flags.ForwardRight: direction = NetLane.Flags.LeftForward; break; default: break; } }
protected override void CalculateSegmentPosition(ushort vehicleID, ref Vehicle vehicleData, PathUnit.Position nextPosition, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, int index, out Vector3 pos, out Vector3 dir, out float maxSpeed) { NetManager instance = Singleton <NetManager> .instance; instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CalculatePositionAndDirection((float)offset * 0.003921569f, out pos, out dir); Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData(); Vector3 position2 = lastFrameData.m_position; Vector3 b = instance.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].CalculatePosition((float)prevOffset * 0.003921569f); float num = 0.5f * lastFrameData.m_velocity.sqrMagnitude / this.m_info.m_braking + this.m_info.m_generatedInfo.m_size.z * 0.5f; if (Vector3.Distance(position2, b) >= num - 1f) { Segment3 segment; segment.a = pos; ushort num2; ushort num3; if (offset < position.m_offset) { segment.b = pos + dir.normalized * this.m_info.m_generatedInfo.m_size.z; num2 = instance.m_segments.m_buffer[(int)position.m_segment].m_startNode; num3 = instance.m_segments.m_buffer[(int)position.m_segment].m_endNode; } else { segment.b = pos - dir.normalized * this.m_info.m_generatedInfo.m_size.z; num2 = instance.m_segments.m_buffer[(int)position.m_segment].m_endNode; num3 = instance.m_segments.m_buffer[(int)position.m_segment].m_startNode; } ushort num4; if (prevOffset == 0) { num4 = instance.m_segments.m_buffer[(int)prevPos.m_segment].m_startNode; } else { num4 = instance.m_segments.m_buffer[(int)prevPos.m_segment].m_endNode; } if (num2 == num4) { NetNode.Flags flags = instance.m_nodes.m_buffer[(int)num2].m_flags; NetLane.Flags flags2 = (NetLane.Flags)instance.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_flags; bool flag = (flags & NetNode.Flags.TrafficLights) != NetNode.Flags.None; bool flag2 = (flags & NetNode.Flags.LevelCrossing) != NetNode.Flags.None; bool flag3 = (flags2 & NetLane.Flags.JoinedJunction) != NetLane.Flags.None; if ((flags & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) == NetNode.Flags.Junction && instance.m_nodes.m_buffer[(int)num2].CountSegments() != 2) { float len = vehicleData.CalculateTotalLength(vehicleID) + 2f; if (!instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CheckSpace(len)) { bool flag4 = false; if (nextPosition.m_segment != 0 && instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_length < 30f) { NetNode.Flags flags3 = instance.m_nodes.m_buffer[(int)num3].m_flags; if ((flags3 & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) != NetNode.Flags.Junction || instance.m_nodes.m_buffer[(int)num3].CountSegments() == 2) { uint laneID2 = PathManager.GetLaneID(nextPosition); if (laneID2 != 0u) { flag4 = instance.m_lanes.m_buffer[(int)((UIntPtr)laneID2)].CheckSpace(len); } } } if (!flag4) { maxSpeed = 0f; return; } } } if (flag && (!flag3 || flag2)) { uint currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex; uint num5 = (uint)(((int)num4 << 8) / 32768); uint num6 = currentFrameIndex - num5 & 255u; NetInfo info = instance.m_nodes.m_buffer[(int)num2].Info; RoadBaseAI.TrafficLightState vehicleLightState; RoadBaseAI.TrafficLightState pedestrianLightState; bool flag5; bool pedestrians; RoadBaseAI.GetTrafficLightState(num4, ref instance.m_segments.m_buffer[(int)prevPos.m_segment], currentFrameIndex - num5, out vehicleLightState, out pedestrianLightState, out flag5, out pedestrians); if (!flag5 && num6 >= 196u) { flag5 = true; RoadBaseAI.SetTrafficLightState(num4, ref instance.m_segments.m_buffer[(int)prevPos.m_segment], currentFrameIndex - num5, vehicleLightState, pedestrianLightState, flag5, pedestrians); } if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == 0 || info.m_class.m_service != ItemClass.Service.Road) { switch (vehicleLightState) { case RoadBaseAI.TrafficLightState.RedToGreen: if (num6 < 60u) { maxSpeed = 0f; return; } break; case RoadBaseAI.TrafficLightState.Red: maxSpeed = 0f; return; case RoadBaseAI.TrafficLightState.GreenToRed: if (num6 >= 30u) { maxSpeed = 0f; return; } break; } } } } } NetInfo info2 = instance.m_segments.m_buffer[(int)position.m_segment].Info; if (info2.m_lanes != null && info2.m_lanes.Length > (int)position.m_lane) { maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, LaneManager.GetLaneSpeed(laneID, info2.m_lanes[(int)position.m_lane]), instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_curve); } else { maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1f, 0f); } if (instance.m_treatWetAsSnow) { DistrictManager instance2 = Singleton <DistrictManager> .instance; byte district = instance2.GetDistrict(pos); DistrictPolicies.CityPlanning cityPlanningPolicies = instance2.m_districts.m_buffer[(int)district].m_cityPlanningPolicies; if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.StuddedTires) != DistrictPolicies.CityPlanning.None) { maxSpeed *= 1f - (float)instance.m_segments.m_buffer[(int)position.m_segment].m_wetness * 0.0005882353f; District[] expr_5C2_cp_0 = instance2.m_districts.m_buffer; byte expr_5C2_cp_1 = district; expr_5C2_cp_0[(int)expr_5C2_cp_1].m_cityPlanningPoliciesEffect = (expr_5C2_cp_0[(int)expr_5C2_cp_1].m_cityPlanningPoliciesEffect | DistrictPolicies.CityPlanning.StuddedTires); } else { maxSpeed *= 1f - (float)instance.m_segments.m_buffer[(int)position.m_segment].m_wetness * 0.00117647066f; } } else { maxSpeed *= 1f - (float)instance.m_segments.m_buffer[(int)position.m_segment].m_wetness * 0.0005882353f; } maxSpeed *= 1f + (float)instance.m_segments.m_buffer[(int)position.m_segment].m_condition * 0.0005882353f; }
internal static bool IsFlagSet(this NetLane.Flags value, NetLane.Flags flag) => (value & flag) != 0;
//from source code private void CheckNextLane(ushort vehicleID, ref Vehicle vehicleData, ref float maxSpeed, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, Bezier3 bezier) { NetManager instance = Singleton <NetManager> .instance; Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData(); Vector3 a = lastFrameData.m_position; Vector3 a2 = lastFrameData.m_position; Vector3 b = lastFrameData.m_rotation * new Vector3(0f, 0f, this.m_info.m_generatedInfo.m_wheelBase * 0.5f); a += b; a2 -= b; float num = 0.5f * lastFrameData.m_velocity.sqrMagnitude / this.m_info.m_braking; float a3 = Vector3.Distance(a, bezier.a); float b2 = Vector3.Distance(a2, bezier.a); if (Mathf.Min(a3, b2) >= num - 5f) { if (!instance.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CheckSpace(1000f, vehicleID)) { vehicleData.m_flags2 |= Vehicle.Flags2.Yielding; vehicleData.m_waitCounter = 0; maxSpeed = 0f; return; } Vector3 vector = bezier.Position(0.5f); Segment3 segment; if (Vector3.SqrMagnitude(vehicleData.m_segment.a - vector) < Vector3.SqrMagnitude(bezier.a - vector)) { segment = new Segment3(vehicleData.m_segment.a, vector); } else { segment = new Segment3(bezier.a, vector); } if (segment.LengthSqr() >= 3f) { segment.a += (segment.b - segment.a).normalized * 2.5f; if (SingleTrainTrackAI.CheckOverlap(vehicleID, ref vehicleData, segment, vehicleID)) { vehicleData.m_flags2 |= Vehicle.Flags2.Yielding; vehicleData.m_waitCounter = 0; maxSpeed = 0f; return; } } segment = new Segment3(vector, bezier.d); if (segment.LengthSqr() >= 1f && SingleTrainTrackAI.CheckOverlap(vehicleID, ref vehicleData, segment, vehicleID)) { vehicleData.m_flags2 |= Vehicle.Flags2.Yielding; vehicleData.m_waitCounter = 0; maxSpeed = 0f; return; } if (this.m_info.m_vehicleType != VehicleInfo.VehicleType.Monorail) { ushort num2; if (offset < position.m_offset) { num2 = instance.m_segments.m_buffer[(int)position.m_segment].m_startNode; } else { num2 = instance.m_segments.m_buffer[(int)position.m_segment].m_endNode; } ushort num3; if (prevOffset == 0) { num3 = instance.m_segments.m_buffer[(int)prevPos.m_segment].m_startNode; } else { num3 = instance.m_segments.m_buffer[(int)prevPos.m_segment].m_endNode; } if (num2 == num3) { NetNode.Flags flags = instance.m_nodes.m_buffer[(int)num2].m_flags; NetLane.Flags flags2 = (NetLane.Flags)instance.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_flags; bool flag = (flags & NetNode.Flags.TrafficLights) != NetNode.Flags.None; bool flag2 = (flags2 & (NetLane.Flags.YieldStart | NetLane.Flags.YieldEnd)) != NetLane.Flags.None && (flags & (NetNode.Flags.Junction | NetNode.Flags.TrafficLights | NetNode.Flags.OneWayIn)) == NetNode.Flags.Junction; if (flag) { uint currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex; uint num4 = (uint)(((int)num3 << 8) / 32768); uint num5 = currentFrameIndex - num4 & 255u; RoadBaseAI.TrafficLightState trafficLightState; RoadBaseAI.TrafficLightState pedestrianLightState; bool flag3; bool pedestrians; RoadBaseAI.GetTrafficLightState(num3, ref instance.m_segments.m_buffer[(int)prevPos.m_segment], currentFrameIndex - num4, out trafficLightState, out pedestrianLightState, out flag3, out pedestrians); if (!flag3 && num5 >= 196u) { flag3 = true; RoadBaseAI.SetTrafficLightState(num3, ref instance.m_segments.m_buffer[(int)prevPos.m_segment], currentFrameIndex - num4, trafficLightState, pedestrianLightState, flag3, pedestrians); } if (trafficLightState != RoadBaseAI.TrafficLightState.RedToGreen) { if (trafficLightState != RoadBaseAI.TrafficLightState.GreenToRed) { if (trafficLightState == RoadBaseAI.TrafficLightState.Red) { vehicleData.m_flags2 |= Vehicle.Flags2.Yielding; vehicleData.m_waitCounter = 0; maxSpeed = 0f; return; } } else if (num5 >= 30u) { vehicleData.m_flags2 |= Vehicle.Flags2.Yielding; vehicleData.m_waitCounter = 0; maxSpeed = 0f; return; } } else if (num5 < 60u) { vehicleData.m_flags2 |= Vehicle.Flags2.Yielding; vehicleData.m_waitCounter = 0; maxSpeed = 0f; return; } } if (flag2 && (vehicleData.m_flags2 & Vehicle.Flags2.Yielding) != (Vehicle.Flags2) 0) { vehicleData.m_waitCounter = (byte)Mathf.Min((int)(vehicleData.m_waitCounter + 1), 4); if (vehicleData.m_waitCounter < 4) { maxSpeed = 0f; return; } vehicleData.m_flags2 &= ~Vehicle.Flags2.Yielding; vehicleData.m_waitCounter = 0; } } } } }
public static void Postfix(ref NetSegment __instance) { if (__instance.m_flags != NetSegment.Flags.None) { var m_info = __instance.Info; if (m_info == null) { return; } if (__instance.m_lanes != 0u || (m_info.m_lanes != null && m_info.m_lanes.Length != 0)) { //Patch Begin NetManager instance = Singleton <NetManager> .instance; uint firstLane = __instance.m_lanes; float num = 0f; float num2 = 0f; if ((m_info.m_netAI is RoadAI) || (m_info.m_netAI is RoadBridgeAI) || (m_info.m_netAI is RoadTunnelAI)) { if (CSURUtil.IsCSURLaneOffset(m_info)) { for (int i = 0; i < m_info.m_lanes.Length; i++) { if (firstLane == 0) { break; } float laneOffset = 0; NetInfo.Lane lane = m_info.m_lanes[i]; float laneOffsetUnit = CSURUtil.CSURLaneOffset(m_info, lane); laneOffset = laneOffsetUnit * 3.75f; //DebugLog.LogToFileOnly("lanepostion = " + lane.m_position.ToString() + " laneoffset = " + laneOffset.ToString()); float effort = (OptionUI.smoothLevel == 2) ? 0.002f : (OptionUI.smoothLevel == 1) ? 0.01f : 0.05f; //EG: before patch: point1-point4 is 1.5*3.75 //After patch, point1-point4 is (1 1.3333 1.6667 2)*3.75 var bezier = instance.m_lanes.m_buffer[firstLane].m_bezier; Vector3 newBezierA = bezier.Position(0) + (new Vector3(-bezier.Tangent(0).z, 0, bezier.Tangent(0).x).normalized) * (laneOffset * 0.5f); Vector3 newBezierA1 = bezier.Position(effort) + (new Vector3(-bezier.Tangent(effort).z, 0, bezier.Tangent(effort).x).normalized) * (laneOffset * (0.5f - effort)); Vector3 newBezierADir = VectorUtils.NormalizeXZ(newBezierA1 - newBezierA); Vector3 newBezierD = bezier.Position(1) + (new Vector3(bezier.Tangent(1).z, 0, -bezier.Tangent(1).x).normalized) * (laneOffset * 0.5f); Vector3 newBezierD1 = bezier.Position(1f - effort) + (new Vector3(bezier.Tangent(1f - effort).z, 0, -bezier.Tangent(1f - effort).x).normalized) * (laneOffset * (0.5f - effort)); Vector3 newBezierDDir = VectorUtils.NormalizeXZ(newBezierD1 - newBezierD); Bezier3 newBezier = default(Bezier3); newBezier.a = newBezierA; newBezier.d = newBezierD; //Try to get smooth bezier as close as real roadmesh NetSegment.CalculateMiddlePoints(newBezierA, newBezierADir, newBezierD, newBezierDDir, true, true, out newBezier.b, out newBezier.c); instance.m_lanes.m_buffer[firstLane].m_bezier = newBezier; num += instance.m_lanes.m_buffer[firstLane].UpdateLength(); num2 += 1f; firstLane = instance.m_lanes.m_buffer[firstLane].m_nextLane; } if (num2 != 0f) { __instance.m_averageLength = num / num2; } else { __instance.m_averageLength = 0f; } bool flag7 = false; if (__instance.m_averageLength < 11f && (instance.m_nodes.m_buffer[__instance.m_startNode].m_flags & NetNode.Flags.Junction) != 0 && (instance.m_nodes.m_buffer[__instance.m_endNode].m_flags & NetNode.Flags.Junction) != 0) { flag7 = true; } firstLane = __instance.m_lanes; for (int j = 0; j < m_info.m_lanes.Length; j++) { if (firstLane == 0) { break; } NetLane.Flags flags4 = (NetLane.Flags)(instance.m_lanes.m_buffer[firstLane].m_flags & -9); if (flag7) { flags4 |= NetLane.Flags.JoinedJunction; } instance.m_lanes.m_buffer[firstLane].m_flags = (ushort)flags4; firstLane = instance.m_lanes.m_buffer[firstLane].m_nextLane; } } //Patch End } } } }
public static void Postfix(ref NetSegment __instance) { if (__instance.m_flags != NetSegment.Flags.None) { var m_info = __instance.Info; if (m_info == null) { return; } if (__instance.m_lanes != 0u || (m_info.m_lanes != null && m_info.m_lanes.Length != 0)) { //Patch Begin NetManager instance = Singleton <NetManager> .instance; uint firstLane = __instance.m_lanes; float num = 0f; float num2 = 0f; if ((m_info.m_netAI is RoadAI) || (m_info.m_netAI is RoadBridgeAI) || (m_info.m_netAI is RoadTunnelAI)) { if (CSURUtil.IsCSURLaneOffset(m_info)) { for (int i = 0; i < m_info.m_lanes.Length; i++) { if (firstLane == 0) { break; } //Thanks for macsergey to optimize this var laneInfo = m_info.m_lanes[i]; var laneOffsetUnit = CSURUtil.CSURLaneOffset(m_info, laneInfo); var laneOffset = laneOffsetUnit * 3.75f; var startDir = __instance.m_startDirection; var endDir = __instance.m_endDirection; var bezier = instance.m_lanes.m_buffer[firstLane].m_bezier; var newBezier = MathLine(startDir, endDir, bezier, laneOffset); //Thanks end. instance.m_lanes.m_buffer[firstLane].m_bezier = newBezier; instance.m_lanes.m_buffer[firstLane].UpdateLength(); num2 += 1f; firstLane = instance.m_lanes.m_buffer[firstLane].m_nextLane; } if (num2 != 0f) { __instance.m_averageLength = num / num2; } else { __instance.m_averageLength = 0f; } bool flag7 = false; if (__instance.m_averageLength < 11f && (instance.m_nodes.m_buffer[__instance.m_startNode].m_flags & NetNode.Flags.Junction) != 0 && (instance.m_nodes.m_buffer[__instance.m_endNode].m_flags & NetNode.Flags.Junction) != 0) { flag7 = true; } firstLane = __instance.m_lanes; for (int j = 0; j < m_info.m_lanes.Length; j++) { if (firstLane == 0) { break; } NetLane.Flags flags4 = (NetLane.Flags)(instance.m_lanes.m_buffer[firstLane].m_flags & -9); if (flag7) { flags4 |= NetLane.Flags.JoinedJunction; } instance.m_lanes.m_buffer[firstLane].m_flags = (ushort)flags4; firstLane = instance.m_lanes.m_buffer[firstLane].m_nextLane; } } //Patch End } } } }
private bool GetStopPosition(TransportInfo info, ushort segment, ushort building, ushort firstStop, ref Vector3 hitPos, out bool fixedPlatform) { //begin mod(+): detect key bool alternateMode = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift); //end mod NetManager instance1 = Singleton <NetManager> .instance; BuildingManager instance2 = Singleton <BuildingManager> .instance; TransportManager instance3 = Singleton <TransportManager> .instance; fixedPlatform = false; if (info.m_transportType == TransportInfo.TransportType.Pedestrian) { Vector3 position = Vector3.zero; float laneOffset = 0.0f; uint laneID = 0; int laneIndex; if ((int)segment != 0 && !instance1.m_segments.m_buffer[(int)segment].GetClosestLanePosition(hitPos, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, VehicleInfo.VehicleType.None, out position, out laneID, out laneIndex, out laneOffset)) { laneID = 0U; if ((instance1.m_segments.m_buffer[(int)segment].m_flags & NetSegment.Flags.Untouchable) != NetSegment.Flags.None && (int)building == 0) { building = NetSegment.FindOwnerBuilding(segment, 363f); } } if ((int)building != 0) { if (instance2.m_buildings.m_buffer[(int)building].Info.m_hasPedestrianPaths) { laneID = instance2.m_buildings.m_buffer[(int)building].FindLane(NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, hitPos, out position, out laneOffset); } if ((int)laneID == 0) { Vector3 sidewalkPosition = instance2.m_buildings.m_buffer[(int)building].CalculateSidewalkPosition(); laneID = instance2.m_buildings.m_buffer[(int)building].FindAccessLane(NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, sidewalkPosition, out position, out laneOffset); } } if ((int)laneID == 0) { return(false); } if ((double)laneOffset < 0.00392156885936856) { laneOffset = 0.003921569f; position = instance1.m_lanes.m_buffer[laneID].CalculatePosition(laneOffset); } else if ((double)laneOffset > 0.996078431606293) { laneOffset = 0.9960784f; position = instance1.m_lanes.m_buffer[laneID].CalculatePosition(laneOffset); } if ((int)this.m_line != 0) { firstStop = instance3.m_lines.m_buffer[(int)this.m_line].m_stops; ushort stop = firstStop; int num = 0; while ((int)stop != 0) { if ((int)instance1.m_nodes.m_buffer[(int)stop].m_lane == (int)laneID) { hitPos = instance1.m_nodes.m_buffer[(int)stop].m_position; fixedPlatform = true; return(true); } stop = TransportLine.GetNextStop(stop); if ((int)stop != (int)firstStop) { if (++num >= 32768) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace); break; } } else { break; } } } hitPos = position; fixedPlatform = true; return(true); } if ((int)segment != 0) { if ((instance1.m_segments.m_buffer[(int)segment].m_flags & NetSegment.Flags.Untouchable) != NetSegment.Flags.None) { building = NetSegment.FindOwnerBuilding(segment, 363f); if ((int)building != 0) { BuildingInfo info1 = instance2.m_buildings.m_buffer[(int)building].Info; TransportInfo transportLineInfo1 = info1.m_buildingAI.GetTransportLineInfo(); TransportInfo transportLineInfo2 = info1.m_buildingAI.GetSecondaryTransportLineInfo(); //begin mod(*): check for !alternateMode if (!alternateMode && transportLineInfo1 != null && transportLineInfo1.m_transportType == info.m_transportType || !alternateMode && transportLineInfo2 != null && transportLineInfo2.m_transportType == info.m_transportType) { //end mod segment = (ushort)0; } else { building = (ushort)0; } } } Vector3 position1; uint laneID1; int laneIndex1; float laneOffset1; if ((int)segment != 0 && instance1.m_segments.m_buffer[(int)segment].GetClosestLanePosition(hitPos, NetInfo.LaneType.Pedestrian, VehicleInfo.VehicleType.None, info.m_vehicleType, out position1, out laneID1, out laneIndex1, out laneOffset1)) { if (info.m_vehicleType == VehicleInfo.VehicleType.None) { NetLane.Flags flags1 = (NetLane.Flags)((int)instance1.m_lanes.m_buffer[laneID1].m_flags & 768); NetLane.Flags flags2 = info.m_stopFlag; NetInfo info1 = instance1.m_segments.m_buffer[(int)segment].Info; if (info1.m_vehicleTypes != VehicleInfo.VehicleType.None) { flags2 = NetLane.Flags.None; } if (flags1 != NetLane.Flags.None && flags2 != NetLane.Flags.None && flags1 != flags2) { return(false); } float stopOffset = info1.m_lanes[laneIndex1].m_stopOffset; if ((instance1.m_segments.m_buffer[(int)segment].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) { stopOffset = -stopOffset; } Vector3 direction; instance1.m_lanes.m_buffer[laneID1].CalculateStopPositionAndDirection(0.5019608f, stopOffset, out hitPos, out direction); fixedPlatform = true; return(true); } Vector3 position2; uint laneID2; int laneIndex2; float laneOffset2; if (instance1.m_segments.m_buffer[(int)segment].GetClosestLanePosition(position1, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, info.m_vehicleType, out position2, out laneID2, out laneIndex2, out laneOffset2)) { NetLane.Flags flags = (NetLane.Flags)((int)instance1.m_lanes.m_buffer[laneID1].m_flags & 768); if (flags != NetLane.Flags.None && info.m_stopFlag != NetLane.Flags.None && flags != info.m_stopFlag) { return(false); } float stopOffset = instance1.m_segments.m_buffer[(int)segment].Info.m_lanes[laneIndex2].m_stopOffset; if ((instance1.m_segments.m_buffer[(int)segment].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None) { stopOffset = -stopOffset; } Vector3 direction; instance1.m_lanes.m_buffer[laneID2].CalculateStopPositionAndDirection(0.5019608f, stopOffset, out hitPos, out direction); fixedPlatform = true; return(true); } } } //begin mod(*): check for !alternateMode if (!alternateMode && (int)building != 0) { //end mod ushort num1 = 0; if ((instance2.m_buildings.m_buffer[(int)building].m_flags & Building.Flags.Untouchable) != Building.Flags.None) { num1 = Building.FindParentBuilding(building); } if (this.m_building != 0 && (int)firstStop != 0 && (this.m_building == (int)building || this.m_building == (int)num1)) { hitPos = instance1.m_nodes.m_buffer[(int)firstStop].m_position; return(true); } 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) { BuildingInfo info1 = instance2.m_buildings.m_buffer[(int)building].Info; TransportInfo transportLineInfo1 = info1.m_buildingAI.GetTransportLineInfo(); if (transportLineInfo1 == null && (int)num1 != 0) { building = num1; info1 = instance2.m_buildings.m_buffer[(int)building].Info; transportLineInfo1 = info1.m_buildingAI.GetTransportLineInfo(); } TransportInfo transportLineInfo2 = info1.m_buildingAI.GetSecondaryTransportLineInfo(); if (transportLineInfo1 != null && transportLineInfo1.m_transportType == info.m_transportType || transportLineInfo2 != null && transportLineInfo2.m_transportType == info.m_transportType) { Vector3 vector3 = Vector3.zero; int num2 = 1000000; for (int index = 0; index < 12; ++index) { Randomizer randomizer = new Randomizer((ulong)index); Vector3 position; Vector3 target; info1.m_buildingAI.CalculateSpawnPosition(building, ref instance2.m_buildings.m_buffer[(int)building], ref randomizer, randomVehicleInfo, out position, out target); int num3 = 0; if (info.m_avoidSameStopPlatform) { num3 = this.GetLineCount(position, target - position, info.m_transportType); } if (num3 < num2) { vector3 = position; num2 = num3; } else if (num3 == num2 && (double)Vector3.SqrMagnitude(position - hitPos) < (double)Vector3.SqrMagnitude(vector3 - hitPos)) { vector3 = position; } } if ((int)firstStop != 0) { Vector3 position = instance1.m_nodes.m_buffer[(int)firstStop].m_position; if ((double)Vector3.SqrMagnitude(position - vector3) < 16384.0) { uint lane = instance1.m_nodes.m_buffer[(int)firstStop].m_lane; if ((int)lane != 0) { ushort segment1 = instance1.m_lanes.m_buffer[lane].m_segment; if ((int)segment1 != 0 && (instance1.m_segments.m_buffer[(int)segment1].m_flags & NetSegment.Flags.Untouchable) != NetSegment.Flags.None) { ushort ownerBuilding = NetSegment.FindOwnerBuilding(segment1, 363f); if ((int)building == (int)ownerBuilding) { hitPos = position; return(true); } } } } } hitPos = vector3; return(num2 != 1000000); } } } return(false); }
// RoadBaseAI public override void UpdateLanes(ushort segmentID, ref NetSegment segment, bool loading) { bool LHT = Singleton <SimulationManager> .instance.m_metaData.m_invertTraffic == SimulationMetaData.MetaBool.True; segment.CalculateCorner(segmentID, heightOffset: true, start: true, true, out var cornerPosStartLeft, out var cornerDirStartLeft, out _); segment.CalculateCorner(segmentID, heightOffset: true, start: false, leftSide: true, out var cornerPosEndLeft, out var cornerDirEndLeft, out bool smoothStart); segment.CalculateCorner(segmentID, heightOffset: true, start: true, leftSide: false, out var cornerPosStartRight, out var cornerDirStartRight, out _); segment.CalculateCorner(segmentID, heightOffset: true, start: false, leftSide: false, out var cornerPosEndRight, out var cornerDirEndRight, out bool smoothEnd); if (segment.m_flags.IsFlagSet(NetSegment.Flags.Invert)) { segment.m_cornerAngleStart = (byte)(Mathf.RoundToInt(Mathf.Atan2(cornerPosStartRight.z - cornerPosStartLeft.z, cornerPosStartRight.x - cornerPosStartLeft.x) * 40.7436638f) & 255); segment.m_cornerAngleEnd = (byte)(Mathf.RoundToInt(Mathf.Atan2(cornerPosEndLeft.z - cornerPosEndRight.z, cornerPosEndLeft.x - cornerPosEndRight.x) * 40.7436638f) & 255); } else { segment.m_cornerAngleStart = (byte)(Mathf.RoundToInt(Mathf.Atan2(cornerPosStartLeft.z - cornerPosStartRight.z, cornerPosStartLeft.x - cornerPosStartRight.x) * 40.7436638f) & 255); segment.m_cornerAngleEnd = (byte)(Mathf.RoundToInt(Mathf.Atan2(cornerPosEndRight.z - cornerPosEndLeft.z, cornerPosEndRight.x - cornerPosEndLeft.x) * 40.7436638f) & 255); } int endLeft = 0; int endForward = 0; int endRight = 0; int endLeft2 = 0; int endForward2 = 0; int endRight2 = 0; bool flag2 = false; bool flag3 = false; segment.m_endNode.ToNode().CountLanes(segment.m_endNode, segmentID, NetInfo.Direction.Forward, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, -segment.m_endDirection, ref endLeft, ref endForward, ref endRight, ref endLeft2, ref endForward2, ref endRight2); if (segment.m_endNode.ToNode().m_flags.IsFlagSet( NetNode.Flags.End | NetNode.Flags.Middle | NetNode.Flags.Bend | NetNode.Flags.Outside)) { if (endLeft + endForward + endRight == 0) { flag3 = true; } else { flag2 = true; } } int startLeft = 0; int startForward = 0; int startRight = 0; int startLeft2 = 0; int startForward2 = 0; int startRight2 = 0; bool hasStartLanes = false; bool noStartLanes = false; segment.m_startNode.ToNode().CountLanes( segment.m_startNode, segmentID, NetInfo.Direction.Forward, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, -segment.m_startDirection, ref startLeft, ref startForward, ref startRight, ref startLeft2, ref startForward2, ref startRight2); if (segment.m_startNode.ToNode().m_flags.IsFlagSet(NetNode.Flags.End | NetNode.Flags.Middle | NetNode.Flags.Bend | NetNode.Flags.Outside)) { if (startLeft + startForward + startRight == 0) { noStartLanes = true; } else { hasStartLanes = true; } } NetLane.Flags flags = NetLane.Flags.None; if (endLeft2 != 0 && endLeft == 0) { flags |= segment.m_flags.IsFlagSet(NetSegment.Flags.Invert) ? NetLane.Flags.EndOneWayLeft : NetLane.Flags.StartOneWayLeft; } if (endRight2 != 0 && endRight == 0) { flags |= segment.m_flags.IsFlagSet(NetSegment.Flags.Invert) ? NetLane.Flags.EndOneWayRight : NetLane.Flags.StartOneWayRight; } if (startLeft2 != 0 && startLeft == 0) { flags |= segment.m_flags.IsFlagSet(NetSegment.Flags.Invert)? NetLane.Flags.StartOneWayLeft : NetLane.Flags.EndOneWayLeft; } if (startRight2 != 0 && startRight == 0) { flags |= segment.m_flags.IsFlagSet(NetSegment.Flags.Invert) ? NetLane.Flags.StartOneWayRight : NetLane.Flags.EndOneWayRight; } if ((segment.m_flags.IsFlagSet(NetSegment.Flags.YieldStart))) { flags |= segment.m_flags.IsFlagSet(NetSegment.Flags.Invert) ? NetLane.Flags.YieldStart : NetLane.Flags.YieldEnd; } if ((segment.m_flags.IsFlagSet(NetSegment.Flags.YieldEnd))) { flags |= segment.m_flags.IsFlagSet(NetSegment.Flags.Invert)? NetLane.Flags.YieldEnd : NetLane.Flags.YieldStart; } float lengthAcc = 0f; float lengthCount = 0f; uint prevLaneID = 0u; uint laneID = segment.m_lanes; for (int i = 0; i < this.m_info.m_lanes.Length; i++) { if (laneID == 0u) { if (!NetManager.instance.CreateLanes(out laneID, ref Singleton <SimulationManager> .instance.m_randomizer, segmentID, 1)) { break; } if (prevLaneID != 0u) { NetManager.instance.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_nextLane = laneID; } else { segment.m_lanes = laneID; } } NetInfo.Lane lane = this.m_info.m_lanes[i]; float lanePos01 = lane.m_position / (this.m_info.m_halfWidth * 2f) + 0.5f; if ((segment.m_flags.IsFlagSet(NetSegment.Flags.Invert))) { lanePos01 = 1f - lanePos01; } Vector3 startPos = cornerPosStartLeft + (cornerPosStartRight - cornerPosStartLeft) * lanePos01; Vector3 startDir = Vector3.Lerp(cornerDirStartLeft, cornerDirStartRight, lanePos01); Vector3 endPos = cornerPosEndRight + (cornerPosEndLeft - cornerPosEndRight) * lanePos01; Vector3 endDir = Vector3.Lerp(cornerDirEndRight, cornerDirEndLeft, lanePos01); startPos.y += lane.m_verticalOffset; endPos.y += lane.m_verticalOffset; NetSegment.CalculateMiddlePoints(startPos, startDir, endPos, endDir, smoothStart, smoothEnd, out var b, out var c); NetLane.Flags flags2 = laneID.ToLane().Flags(); NetLane.Flags flags3 = flags; flags2 &= ~(NetLane.Flags.Forward | NetLane.Flags.Left | NetLane.Flags.Right | NetLane.Flags.Merge | NetLane.Flags.YieldStart | NetLane.Flags.YieldEnd | NetLane.Flags.StartOneWayLeft | NetLane.Flags.StartOneWayRight | NetLane.Flags.EndOneWayLeft | NetLane.Flags.EndOneWayRight); if ((byte)(lane.m_finalDirection & NetInfo.Direction.Both) == 2) { flags3 &= ~NetLane.Flags.YieldEnd; } if ((byte)(lane.m_finalDirection & NetInfo.Direction.Both) == 1) { flags3 &= ~NetLane.Flags.YieldStart; } if ((lane.m_vehicleType & VehicleInfo.VehicleType.Monorail) != VehicleInfo.VehicleType.None) { flags3 &= ~(NetLane.Flags.YieldStart | NetLane.Flags.YieldEnd); } flags2 |= flags3; if (LHT) { flags2 |= NetLane.Flags.Inverted; } else { flags2 &= ~NetLane.Flags.Inverted; } int tailInnerPortion = 0; int tailOuterPortion = 255; if ((byte)(lane.m_laneType & (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle)) != 0) { bool backward = lane.m_finalDirection.IsFlagSet(NetInfo.Direction.Forward) == segment.m_flags.IsFlagSet(NetSegment.Flags.Invert); int tailLeft; int tailForward; int tailRight; if (backward) { tailLeft = endLeft; tailForward = endForward; tailRight = endRight; } else { tailLeft = startLeft; tailForward = startForward; tailRight = startRight; } int innterSimilarLaneIndex; int outerSimilarLaneIndex; if ((byte)(lane.m_finalDirection & NetInfo.Direction.Forward) != 0) { innterSimilarLaneIndex = lane.m_similarLaneIndex; outerSimilarLaneIndex = lane.m_similarLaneCount - lane.m_similarLaneIndex - 1; } else { innterSimilarLaneIndex = lane.m_similarLaneCount - lane.m_similarLaneIndex - 1; outerSimilarLaneIndex = lane.m_similarLaneIndex; } int totalTail = tailLeft + tailForward + tailRight; tailInnerPortion = 255; tailOuterPortion = 0; if (totalTail != 0) { if (lane.m_similarLaneCount > totalTail && totalTail > 0) { tailInnerPortion = totalTail * innterSimilarLaneIndex / lane.m_similarLaneCount; tailOuterPortion = totalTail - totalTail * outerSimilarLaneIndex / lane.m_similarLaneCount; flags2 |= NetLane.Flags.Merge; if (tailInnerPortion < tailLeft) { flags2 |= NetLane.Flags.Left; } if (totalTail - tailOuterPortion < tailRight) { flags2 |= NetLane.Flags.Right; } if (tailForward != 0 && tailInnerPortion < tailLeft + tailForward && tailOuterPortion > tailLeft) { flags2 |= NetLane.Flags.Forward; } } else { int num26; int num27; if (lane.m_similarLaneCount >= totalTail) { num26 = tailLeft; num27 = tailRight; } else { num26 = tailLeft * lane.m_similarLaneCount / (totalTail + (tailForward >> 1)); num27 = tailRight * lane.m_similarLaneCount / (totalTail + (tailForward >> 1)); } int num28 = num26; int num29 = lane.m_similarLaneCount - num26 - num27; int num30 = num27; if (num29 > 0) { if (tailLeft > num26) { num28++; } if (tailRight > num27) { num30++; } } if (innterSimilarLaneIndex < num28) { int num31 = (innterSimilarLaneIndex * tailLeft + num28 - 1) / num28; int num32 = ((innterSimilarLaneIndex + 1) * tailLeft + num28 - 1) / num28; if (num32 > num31) { flags2 |= NetLane.Flags.Left; tailInnerPortion = Mathf.Min(tailInnerPortion, num31); tailOuterPortion = Mathf.Max(tailOuterPortion, num32); } } if (innterSimilarLaneIndex >= num26 && outerSimilarLaneIndex >= num27 && tailForward != 0) { if (lane.m_similarLaneCount > totalTail) { num26++; } int num33 = tailLeft + ((innterSimilarLaneIndex - num26) * tailForward + num29 - 1) / num29; int num34 = tailLeft + ((innterSimilarLaneIndex + 1 - num26) * tailForward + num29 - 1) / num29; if (num34 > num33) { flags2 |= NetLane.Flags.Forward; tailInnerPortion = Mathf.Min(tailInnerPortion, num33); tailOuterPortion = Mathf.Max(tailOuterPortion, num34); } } if (outerSimilarLaneIndex < num30) { int num35 = totalTail - ((outerSimilarLaneIndex + 1) * tailRight + num30 - 1) / num30; int num36 = totalTail - (outerSimilarLaneIndex * tailRight + num30 - 1) / num30; if (num36 > num35) { flags2 |= NetLane.Flags.Right; tailInnerPortion = Mathf.Min(tailInnerPortion, num35); tailOuterPortion = Mathf.Max(tailOuterPortion, num36); } } if (this.m_highwayRules) { if ((flags2 & NetLane.Flags.LeftRight) == NetLane.Flags.Left) { if ((flags2 & NetLane.Flags.Forward) == NetLane.Flags.None || (tailForward >= 2 && tailLeft == 1)) { tailOuterPortion = Mathf.Min(tailOuterPortion, tailInnerPortion + 1); } } else if ((flags2 & NetLane.Flags.LeftRight) == NetLane.Flags.Right && ((flags2 & NetLane.Flags.Forward) == NetLane.Flags.None || (tailForward >= 2 && tailRight == 1))) { tailInnerPortion = Mathf.Max(tailInnerPortion, tailOuterPortion - 1); } } } } if (backward) { if (flag2) { flags2 &= ~(NetLane.Flags.Forward | NetLane.Flags.Left | NetLane.Flags.Right); } else if (flag3) { flags2 |= NetLane.Flags.Forward; } } else if (hasStartLanes) { flags2 &= ~(NetLane.Flags.Forward | NetLane.Flags.Left | NetLane.Flags.Right); } else if (noStartLanes) { flags2 |= NetLane.Flags.Forward; } } laneID.ToLane().m_bezier = new Bezier3(startPos, b, c, endPos); laneID.ToLane().m_segment = segmentID; laneID.ToLane().m_flags = (ushort)flags2; laneID.ToLane().m_firstTarget = (byte)tailInnerPortion; laneID.ToLane().m_lastTarget = (byte)tailOuterPortion; lengthAcc += laneID.ToLane().UpdateLength(); lengthCount += 1f; prevLaneID = laneID; laneID = laneID.ToLane().m_nextLane; } if (lengthCount != 0f) { segment.m_averageLength = lengthAcc / lengthCount; } else { segment.m_averageLength = 0f; } bool joinedJunction = segment.m_averageLength < 11f && segment.m_startNode.ToNode().m_flags.IsFlagSet(NetNode.Flags.Junction) && segment.m_endNode.ToNode().m_flags.IsFlagSet(NetNode.Flags.Junction); laneID = segment.m_lanes; int laneIndex = 0; while (laneIndex < m_info.m_lanes.Length && laneID != 0u) { NetLane.Flags flags4 = laneID.ToLane().Flags() & ~NetLane.Flags.JoinedJunction; if (joinedJunction) { flags4 |= NetLane.Flags.JoinedJunction; } laneID.ToLane().m_flags = (ushort)flags4; laneID = laneID.ToLane().m_nextLane; laneIndex++; } if (!loading) { int xBountStart = Mathf.Max((int)((segment.m_bounds.min.x - 16f) / 64f + 135f), 0); int zBountStart = Mathf.Max((int)((segment.m_bounds.min.z - 16f) / 64f + 135f), 0); int xBountEnd = Mathf.Min((int)((segment.m_bounds.max.x + 16f) / 64f + 135f), 269); int zBoundEnd = Mathf.Min((int)((segment.m_bounds.max.z + 16f) / 64f + 135f), 269); for (int zBound = zBountStart; zBound <= zBoundEnd; zBound++) { for (int xBound = xBountStart; xBound <= xBountEnd; xBound++) { ushort gridIndex = NetManager.instance.m_nodeGrid[zBound * 270 + xBound]; int watchDog = 0; while (gridIndex != 0) { NetInfo info = NetManager.instance.m_nodes.m_buffer[(int)gridIndex].Info; Vector3 position = NetManager.instance.m_nodes.m_buffer[(int)gridIndex].m_position; float num44 = Mathf.Max(Mathf.Max(segment.m_bounds.min.x - 16f - position.x, segment.m_bounds.min.z - 16f - position.z), Mathf.Max(position.x - segment.m_bounds.max.x - 16f, position.z - segment.m_bounds.max.z - 16f)); if (num44 < 0f) { info.m_netAI.NearbyLanesUpdated(gridIndex, ref NetManager.instance.m_nodes.m_buffer[(int)gridIndex]); } gridIndex = NetManager.instance.m_nodes.m_buffer[(int)gridIndex].m_nextGridNode; if (++watchDog >= 32768) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } if (this.m_info.m_hasPedestrianLanes && (this.m_info.m_hasForwardVehicleLanes || this.m_info.m_hasBackwardVehicleLanes)) { RoadBaseAI.CheckBuildings(segmentID, ref segment); } } }
public virtual void UpdateLanes(ushort segmentID, ref NetSegment segment, bool loading) { bool flag = Singleton <SimulationManager> .instance.m_metaData.m_invertTraffic == SimulationMetaData.MetaBool.True; uint prevLaneID = 0u; uint laneID = segment.m_lanes; segment.CalculateCorner(segmentID, heightOffset: true, start: true, true, out var cornerPosStartLeft, out var cornerDirStartLeft, out _); segment.CalculateCorner(segmentID, heightOffset: true, start: false, leftSide: true, out var cornerPosEndLeft, out var cornerDirEndLeft, out bool smoothStart); segment.CalculateCorner(segmentID, heightOffset: true, start: true, leftSide: false, out var cornerPosStartRight, out var cornerDirStartRight, out _); segment.CalculateCorner(segmentID, heightOffset: true, start: false, leftSide: false, out var cornerPosEndRight, out var cornerDirEndRight, out bool smoothEnd); bool segmentInverted = segment.m_flags.IsFlagSet(NetSegment.Flags.Invert); float cc = 128 / Mathf.PI;//40.7436638f Vector3 deltaPosStart = cornerPosStartRight - cornerPosStartLeft; Vector3 deltaPosEnd = cornerPosEndRight - cornerPosEndLeft; if (segmentInverted) { segment.m_cornerAngleStart = (byte)(Mathf.RoundToInt(Mathf.Atan2(deltaPosStart.z, deltaPosStart.x) * cc) & 255); segment.m_cornerAngleEnd = (byte)(Mathf.RoundToInt(Mathf.Atan2(-deltaPosEnd.z, -deltaPosEnd.x) * cc) & 255); } else { segment.m_cornerAngleStart = (byte)(Mathf.RoundToInt(Mathf.Atan2(-deltaPosStart.z, -deltaPosStart.x) * cc) & 255); segment.m_cornerAngleEnd = (byte)(Mathf.RoundToInt(Mathf.Atan2(deltaPosEnd.z, deltaPosEnd.x) * cc) & 255); } NetLane.Flags flags = NetLane.Flags.None; if (segment.m_flags.IsFlagSet(NetSegment.Flags.YieldStart)) { flags |= segmentInverted ? NetLane.Flags.YieldStart : NetLane.Flags.YieldEnd; } if (segment.m_flags.IsFlagSet(NetSegment.Flags.YieldEnd)) { flags |= segmentInverted ? NetLane.Flags.YieldEnd : NetLane.Flags.YieldStart; } float lengthAcc = 0f; float laneCount = 0f; for (int i = 0; i < this.m_info.m_lanes.Length; i++) { if (laneID == 0u) { if (!Singleton <NetManager> .instance.CreateLanes( out laneID, ref Singleton <SimulationManager> .instance.m_randomizer, segmentID, 1)) { break; } if (prevLaneID != 0u) { prevLaneID.ToLane().m_nextLane = laneID; } else { segment.m_lanes = laneID; } } NetInfo.Lane laneInfo = this.m_info.m_lanes[i]; float lanePos01 = laneInfo.m_position / (this.m_info.m_halfWidth * 2f) + 0.5f; // lane pos rescaled between 0~1 if (segmentInverted) { lanePos01 = 1f - lanePos01; } Vector3 startPos = cornerPosStartLeft + (cornerPosStartRight - cornerPosStartLeft) * lanePos01; Vector3 startDir = Vector3.Lerp(cornerDirStartLeft, cornerDirStartRight, lanePos01); Vector3 endPos = cornerPosEndRight + (cornerPosEndLeft - cornerPosEndRight) * lanePos01; Vector3 endDir = Vector3.Lerp(cornerDirEndRight, cornerDirEndLeft, lanePos01); startPos.y += laneInfo.m_verticalOffset; endPos.y += laneInfo.m_verticalOffset; Vector3 b; Vector3 c; NetSegment.CalculateMiddlePoints(startPos, startDir, endPos, endDir, smoothStart, smoothEnd, out b, out c); NetLane.Flags flags2 = laneID.ToLane().Flags(); NetLane.Flags flags3 = flags; flags2 &= ~(NetLane.Flags.YieldStart | NetLane.Flags.YieldEnd); if ((byte)(laneInfo.m_finalDirection & NetInfo.Direction.Both) == 2) { flags3 &= ~NetLane.Flags.YieldEnd; } if ((byte)(laneInfo.m_finalDirection & NetInfo.Direction.Both) == 1) { flags3 &= ~NetLane.Flags.YieldStart; } flags2 |= flags3; if (flag) { flags2 |= NetLane.Flags.Inverted; } else { flags2 &= ~NetLane.Flags.Inverted; } laneID.ToLane().m_bezier = new Bezier3(startPos, b, c, endPos); laneID.ToLane().m_segment = segmentID; laneID.ToLane().m_flags = (ushort)flags2; laneID.ToLane().m_firstTarget = 0; laneID.ToLane().m_lastTarget = byte.MaxValue; lengthAcc += laneID.ToLane().UpdateLength(); laneCount += 1f; prevLaneID = laneID; laneID = laneID.ToLane().m_nextLane; } if (laneCount != 0f) { segment.m_averageLength = lengthAcc / laneCount; } else { segment.m_averageLength = 0f; } }
internal static bool CheckFlags(this NetLane.Flags value, NetLane.Flags required, NetLane.Flags forbidden = 0) => (value & (required | forbidden)) == required;
public LaneConnectionInfo(NetLane.Flags direction, byte firstTarget, byte lastTarget) { this.direction = direction; this.firstTarget = firstTarget; this.lastTarget = lastTarget; }
public static void AssignLanes(LaneInfo inLanes, Vector3 outVector, ushort segmentID, ushort nodeID, NetNode junctionNode, bool lht) { var nodeInfo = AnalyseNode(junctionNode, nodeID, segmentID, vehicleLaneTypes, VehicleInfo.VehicleType.Car, outVector); if (nodeInfo.GetLaneCount() == 0) { // This can happen if multiple one-way roads meet creating a dead end. return; } if (lht) { inLanes.Mirror(); nodeInfo.Mirror(); } var busLaneHandler = new BusLaneHandler(); busLaneHandler.PreProcess(ref inLanes, ref nodeInfo); AdjustSharpTurns(inLanes.GetLaneCount(), ref nodeInfo); List <LaneConnectionInfo> lanesInfo = AssignLanes(inLanes.lanes.Count, nodeInfo.laneCounts[Direction.Left], nodeInfo.laneCounts[Direction.Forward], nodeInfo.laneCounts[Direction.Right]); AccountForSharpTurnLanes(ref lanesInfo, (byte)nodeInfo.laneCounts[Direction.SharpLeft], (byte)nodeInfo.laneCounts[Direction.SharpRight]); busLaneHandler.PostProcess(ref inLanes, ref lanesInfo); if (lht) { inLanes.Mirror(); LHTHandler.Mirror(ref lanesInfo); } int i = 0; NetManager netManager = Singleton <NetManager> .instance; foreach (var lane in inLanes.lanes) { var laneInfo = lanesInfo[i]; var laneId = lane.Value; // Note: NetLane is a value type netManager.m_lanes.m_buffer[laneId].m_firstTarget = (byte)(laneInfo.firstTarget); netManager.m_lanes.m_buffer[laneId].m_lastTarget = (byte)(laneInfo.lastTarget + 1); NetLane.Flags flags = (NetLane.Flags)netManager.m_lanes.m_buffer[laneId].m_flags; flags &= noDirections; flags |= laneInfo.direction; netManager.m_lanes.m_buffer[laneId].m_flags = (ushort)flags; i += 1; } }