//from source code private static ushort CheckOverlap(ushort vehicleID, ref Vehicle vehicleData, Segment3 segment, ushort ignoreVehicle, ushort otherID, ref Vehicle otherData, ref bool overlap, Vector3 min, Vector3 max) { if (ignoreVehicle == 0 || (otherID != ignoreVehicle && otherData.m_leadingVehicle != ignoreVehicle && otherData.m_trailingVehicle != ignoreVehicle)) { VehicleInfo info = otherData.Info; if (info.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { return(otherData.m_nextGridVehicle); } if (((vehicleData.m_flags | otherData.m_flags) & Vehicle.Flags.Transition) == (Vehicle.Flags) 0 && (vehicleData.m_flags & Vehicle.Flags.Underground) != (otherData.m_flags & Vehicle.Flags.Underground)) { return(otherData.m_nextGridVehicle); } Vector3 vector = Vector3.Min(otherData.m_segment.Min(), otherData.m_targetPos3); Vector3 vector2 = Vector3.Max(otherData.m_segment.Max(), otherData.m_targetPos3); if (min.x < vector2.x + 2f && min.y < vector2.y + 2f && min.z < vector2.z + 2f && vector.x < max.x + 2f && vector.y < max.y + 2f && vector.z < max.z + 2f) { Vector3 rhs = Vector3.Normalize(segment.b - segment.a); Vector3 lhs = otherData.m_segment.a - vehicleData.m_segment.b; Vector3 lhs2 = otherData.m_segment.b - vehicleData.m_segment.b; if (Vector3.Dot(lhs, rhs) >= 1f || Vector3.Dot(lhs2, rhs) >= 1f) { float num2; float num3; float num = segment.DistanceSqr(otherData.m_segment, out num2, out num3); if (num < 4f) { overlap = true; } Vector3 a = otherData.m_segment.b; segment.a.y = segment.a.y * 0.5f; segment.b.y = segment.b.y * 0.5f; for (int i = 0; i < 4; i++) { Vector3 vector3 = otherData.GetTargetPos(i); Segment3 segment2 = new Segment3(a, vector3); segment2.a.y = segment2.a.y * 0.5f; segment2.b.y = segment2.b.y * 0.5f; if (segment2.LengthSqr() > 0.01f) { num = segment.DistanceSqr(segment2, out num2, out num3); if (num < 4f) { overlap = true; break; } } a = vector3; } } } } return(otherData.m_nextGridVehicle); }
public void CustomCheckNextLane(ushort vehicleID, ref Vehicle vehicleData, ref float maxSpeed, PathUnit.Position position, uint laneID, byte offset, PathUnit.Position prevPos, uint prevLaneID, byte prevOffset, Bezier3 bezier) { if ((Options.prioritySignsEnabled || Options.timedLightsEnabled) && Options.simAccuracy <= 1) { try { VehicleStateManager.Instance().UpdateVehiclePos(vehicleID, ref vehicleData, ref prevPos, ref position); } catch (Exception e) { Log.Error("TrainAI CustomCheckNextLane Error: " + e.ToString()); } } 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)) { 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 (CustomTrainAI.CheckOverlap(vehicleID, ref vehicleData, segment, vehicleID)) { maxSpeed = 0f; return; } } segment = new Segment3(vector, bezier.d); if (segment.LengthSqr() >= 1f && CustomTrainAI.CheckOverlap(vehicleID, ref vehicleData, segment, vehicleID)) { maxSpeed = 0f; return; } ushort targetNodeId; if (offset < position.m_offset) { targetNodeId = instance.m_segments.m_buffer[(int)position.m_segment].m_startNode; } else { targetNodeId = instance.m_segments.m_buffer[(int)position.m_segment].m_endNode; } ushort prevTargetNodeId; if (prevOffset == 0) { prevTargetNodeId = instance.m_segments.m_buffer[(int)prevPos.m_segment].m_startNode; } else { prevTargetNodeId = instance.m_segments.m_buffer[(int)prevPos.m_segment].m_endNode; } if (targetNodeId == prevTargetNodeId) { float oldMaxSpeed = maxSpeed; #if DEBUG bool debug = false; // targetNodeId == 14527 || targetNodeId == 15048; if (debug) { Log._Debug($"Train {vehicleID} wants to change segment. seg. {prevPos.m_segment} -> node {targetNodeId} -> seg. {position.m_segment}"); } #else bool debug = false; #endif bool mayChange = CustomVehicleAI.MayChangeSegment(vehicleID, ref vehicleData, ref lastFrameData, false, ref prevPos, prevTargetNodeId, prevLaneID, ref position, targetNodeId, laneID, out maxSpeed, debug); if (!mayChange) { return; } maxSpeed = oldMaxSpeed; } } }
public static bool NetSegmentRayCastMasked(NetSegment mysegment, ushort segmentID, Segment3 ray, float snapElevation, bool bothSides, out float t, out float priority) { bool lht = false; //if (SimulationManager.instance.m_metaData.m_invertTraffic == SimulationMetaData.MetaBool.True) lht = true; //Debug.Log(mysegment.m_flags); if ((mysegment.m_flags & NetSegment.Flags.Invert) != 0) { lht = true; } bool isMasked = false; NetInfo info = mysegment.Info; t = 0f; priority = 0f; Bounds bounds = mysegment.m_bounds; bounds.Expand(16f); if (!bounds.IntersectRay(new Ray(ray.a, ray.b - ray.a))) { return(false); } NetManager instance = Singleton <NetManager> .instance; Bezier3 bezier = default(Bezier3); bezier.a = instance.m_nodes.m_buffer[mysegment.m_startNode].m_position; bezier.d = instance.m_nodes.m_buffer[mysegment.m_endNode].m_position; bool result = false; info.m_netAI.GetRayCastHeights(segmentID, ref mysegment, out float leftMin, out float rightMin, out float max); bezier.a.y += max; bezier.d.y += max; bool flag = (instance.m_nodes.m_buffer[mysegment.m_startNode].m_flags & NetNode.Flags.Middle) != 0; bool flag2 = (instance.m_nodes.m_buffer[mysegment.m_endNode].m_flags & NetNode.Flags.Middle) != 0; NetSegment.CalculateMiddlePoints(bezier.a, mysegment.m_startDirection, bezier.d, mysegment.m_endDirection, flag, flag2, out bezier.b, out bezier.c); float minNodeDistance = info.GetMinNodeDistance(); // float collisionHalfWidth = info.m_halfWidth; float maskHalfWidth = info.m_pavementWidth; // float num4 = (int)instance.m_nodes.m_buffer[mysegment.m_startNode].m_elevation; float num5 = (int)instance.m_nodes.m_buffer[mysegment.m_endNode].m_elevation; if (info.m_netAI.IsUnderground()) { num4 = 0f - num4; num5 = 0f - num5; } num4 += info.m_netAI.GetSnapElevation(); num5 += info.m_netAI.GetSnapElevation(); float a = Mathf.Lerp(minNodeDistance, collisionHalfWidth, Mathf.Clamp01(Mathf.Abs(snapElevation - num4) / 12f)); float b2 = Mathf.Lerp(minNodeDistance, collisionHalfWidth, Mathf.Clamp01(Mathf.Abs(snapElevation - num5) / 12f)); float am = Mathf.Lerp(minNodeDistance, maskHalfWidth, Mathf.Clamp01(Mathf.Abs(snapElevation - num4) / 12f)); float b2m = Mathf.Lerp(minNodeDistance, maskHalfWidth, Mathf.Clamp01(Mathf.Abs(snapElevation - num5) / 12f)); float num6 = Mathf.Min(leftMin, rightMin); t = 1000000f; priority = 1000000f; Segment3 segment = default(Segment3); segment.a = bezier.a; Segment2 segment2 = default(Segment2); //Debug.Log($"mouse ray: {ray.a} --> {ray.b}"); //Debug.Log($"segment direction: {bezier.a} --> {bezier.b}"); for (int i = 1; i <= 16; i++) { segment.b = bezier.Position((float)i / 16f); float num7 = ray.DistanceSqr(segment, out float u2, out float v2); float num8 = Mathf.Lerp(a, b2, ((float)(i - 1) + v2) / 16f); float num8m = Mathf.Lerp(am, b2m, ((float)(i - 1) + v2) / 16f); Vector3 vector2 = segment.Position(v2); bool atOffsetSide = bothSides || IsTrafficHandSideOf(segment, ray, u2, lht); if (atOffsetSide && num7 < priority && Segment1.Intersect(ray.a.y, ray.b.y, vector2.y, out u2)) { Vector3 vector3 = ray.Position(u2); num7 = Vector3.SqrMagnitude(vector3 - vector2); //Debug.Log($"num7: {num7}, num8: {num8}, num8m: {num8m}"); if (num7 < priority && num7 < num8 * num8) { if (flag && i == 1 && v2 < 0.001f) { Vector3 rhs = segment.a - segment.b; u2 += Mathf.Max(0f, Vector3.Dot(vector3, rhs)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs.sqrMagnitude * ray.LengthSqr())); } if (flag2 && i == 16 && v2 > 0.999f) { Vector3 rhs2 = segment.b - segment.a; u2 += Mathf.Max(0f, Vector3.Dot(vector3, rhs2)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs2.sqrMagnitude * ray.LengthSqr())); } priority = num7; t = u2; result = true; if (num7 < num8m * num8m) { isMasked = true; } } } if (atOffsetSide && num6 < max) { float num9 = vector2.y + num6 - max; if (Mathf.Max(ray.a.y, ray.b.y) > num9 && Mathf.Min(ray.a.y, ray.b.y) < vector2.y) { float num10; if (Segment1.Intersect(ray.a.y, ray.b.y, vector2.y, out u2)) { segment2.a = VectorUtils.XZ(ray.Position(u2)); num10 = u2; } else { segment2.a = VectorUtils.XZ(ray.a); num10 = 0f; } float num11; if (Segment1.Intersect(ray.a.y, ray.b.y, num9, out u2)) { segment2.b = VectorUtils.XZ(ray.Position(u2)); num11 = u2; } else { segment2.b = VectorUtils.XZ(ray.b); num11 = 1f; } num7 = segment2.DistanceSqr(VectorUtils.XZ(vector2), out u2); if (num7 < priority && num7 < num8 * num8) { u2 = num10 + (num11 - num10) * u2; Vector3 lhs = ray.Position(u2); if (flag && i == 1 && v2 < 0.001f) { Vector3 rhs3 = segment.a - segment.b; u2 += Mathf.Max(0f, Vector3.Dot(lhs, rhs3)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs3.sqrMagnitude * ray.LengthSqr())); } if (flag2 && i == 16 && v2 > 0.999f) { Vector3 rhs4 = segment.b - segment.a; u2 += Mathf.Max(0f, Vector3.Dot(lhs, rhs4)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs4.sqrMagnitude * ray.LengthSqr())); } priority = num7; t = u2; result = true; if (num7 < num8m * num8m) { isMasked = true; } } } } segment.a = segment.b; } priority = Mathf.Max(0f, Mathf.Sqrt(priority) - collisionHalfWidth); if (isMasked) { result = false; } return(result); }
public static bool Prefix(ref NetSegment __instance, ushort segmentID, Segment3 ray, float snapElevation, bool nameOnly, out float t, out float priority, ref bool __result) { // NON-STOCK CODE STARTS float laneOffset = 0; float startOffset = 0; float endOffset = 0; bool IsCSURSLane = CSURUtil.IsCSURSLane(__instance.Info.m_netAI.m_info, ref laneOffset, ref startOffset, ref endOffset); if (CSURUtil.IsCSUROffset(__instance.Info.m_netAI.m_info) && !IsCSURSLane) { __result = NetSegmentRayCastMasked(__instance, segmentID, ray, -1000f, false, out t, out priority); return(false); } // NON-STOCK CODE ENDS NetInfo info = __instance.Info; t = 0f; priority = 0f; if (nameOnly && (__instance.m_flags & NetSegment.Flags.NameVisible2) == NetSegment.Flags.None) { __result = false; return(false); } Bounds bounds = __instance.m_bounds; bounds.Expand(16f); if (!bounds.IntersectRay(new Ray(ray.a, ray.b - ray.a))) { __result = false; return(false); } NetManager instance = Singleton <NetManager> .instance; Bezier3 bezier = default(Bezier3); bezier.a = instance.m_nodes.m_buffer[__instance.m_startNode].m_position; bezier.d = instance.m_nodes.m_buffer[__instance.m_endNode].m_position; bool result = false; if (nameOnly) { RenderManager instance2 = Singleton <RenderManager> .instance; if (instance2.GetInstanceIndex((uint)(49152 + segmentID), out uint instanceIndex)) { InstanceManager.NameData nameData = instance2.m_instances[instanceIndex].m_nameData; Vector3 position = instance2.m_instances[instanceIndex].m_position; Matrix4x4 dataMatrix = instance2.m_instances[instanceIndex].m_dataMatrix2; float num = Vector3.Distance(position, ray.a); if (nameData != null && num < 1000f) { float snapElevation2 = info.m_netAI.GetSnapElevation(); bezier.a.y += snapElevation2; bezier.d.y += snapElevation2; NetSegment.CalculateMiddlePoints(bezier.a, __instance.m_startDirection, bezier.d, __instance.m_endDirection, true, true, out bezier.b, out bezier.c); float num2 = Mathf.Max(1f, Mathf.Abs(dataMatrix.m33 - dataMatrix.m30)); float d = num * 0.0002f + 0.05f / (1f + num * 0.001f); Vector2 vector = nameData.m_size * d; float t2 = Mathf.Max(0f, 0.5f - vector.x / num2 * 0.5f); float t3 = Mathf.Min(1f, 0.5f + vector.x / num2 * 0.5f); bezier = bezier.Cut(t2, t3); float num3 = bezier.DistanceSqr(ray, out float u, out float _); if (num3 < vector.y * vector.y * 0.25f) { Vector3 b = bezier.Position(u); if (Segment1.Intersect(ray.a.y, ray.b.y, b.y, out u)) { num3 = Vector3.SqrMagnitude(ray.Position(u) - b); if (num3 < vector.y * vector.y * 0.25f) { t = u; result = true; } } } } } } else { info.m_netAI.GetRayCastHeights(segmentID, ref __instance, out float leftMin, out float rightMin, out float max); bezier.a.y += max; bezier.d.y += max; bool flag = (instance.m_nodes.m_buffer[__instance.m_startNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None; bool flag2 = (instance.m_nodes.m_buffer[__instance.m_endNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None; NetSegment.CalculateMiddlePoints(bezier.a, __instance.m_startDirection, bezier.d, __instance.m_endDirection, flag, flag2, out bezier.b, out bezier.c); // NON-STOCK CODE STARTS if (IsCSURSLane) { float vehicleLaneNum = CSURUtil.CountCSURSVehicleLanes(info); float otherLaneNum = CSURUtil.CountCSURSOtherLanes(info); float laneNum = vehicleLaneNum + otherLaneNum; startOffset = startOffset * 3.75f - laneNum * 1.875f + 1.875f + otherLaneNum * 3.75f; endOffset = endOffset * 3.75f - laneNum * 1.875f + 1.875f + otherLaneNum * 3.75f; if ((__instance.m_flags & NetSegment.Flags.Invert) != 0) { startOffset = -startOffset; endOffset = -endOffset; } //EG: before patch: point1-point4 is 1.5*3.75 //After patch, point1-point4 is (1 1.3333 1.6667 2)*3.75 Vector3 newBezierA = bezier.a + (new Vector3(__instance.m_startDirection.z, 0, -__instance.m_startDirection.x).normalized) * (startOffset); Vector3 newBezierBDir = VectorUtils.NormalizeXZ(bezier.Tangent(0.333f)); Vector3 newBezierB = bezier.b + (new Vector3(newBezierBDir.z, 0, -newBezierBDir.x).normalized) * (startOffset * 0.667f + endOffset * 0.333f); Vector3 newBezierCDir = VectorUtils.NormalizeXZ(bezier.Tangent(0.667f)); Vector3 newBezierC = bezier.c + (new Vector3(newBezierCDir.z, 0, -newBezierCDir.x).normalized) * (startOffset * 0.333f + endOffset * 0.667f); Vector3 newBezierD = bezier.d + (new Vector3(-__instance.m_endDirection.z, 0, __instance.m_endDirection.x).normalized) * (endOffset); bezier.a = newBezierA; bezier.b = newBezierB; bezier.c = newBezierC; bezier.d = newBezierD; } float minNodeDistance = info.GetMinNodeDistance(); float collisionHalfWidth = info.m_netAI.GetCollisionHalfWidth(); float num4 = (float)(int)instance.m_nodes.m_buffer[__instance.m_startNode].m_elevation; float num5 = (float)(int)instance.m_nodes.m_buffer[__instance.m_endNode].m_elevation; if (info.m_netAI.IsUnderground()) { num4 = 0f - num4; num5 = 0f - num5; } num4 += info.m_netAI.GetSnapElevation(); num5 += info.m_netAI.GetSnapElevation(); float a = Mathf.Lerp(minNodeDistance, collisionHalfWidth, Mathf.Clamp01(Mathf.Abs(snapElevation - num4) / 12f)); float b2 = Mathf.Lerp(minNodeDistance, collisionHalfWidth, Mathf.Clamp01(Mathf.Abs(snapElevation - num5) / 12f)); float num6 = Mathf.Min(leftMin, rightMin); t = 1000000f; priority = 1000000f; Segment3 segment = default(Segment3); segment.a = bezier.a; for (int i = 1; i <= 16; i++) { segment.b = bezier.Position((float)i / 16f); float num7 = ray.DistanceSqr(segment, out float u2, out float v2); float num8 = Mathf.Lerp(a, b2, ((float)(i - 1) + v2) / 16f); Vector3 vector2 = segment.Position(v2); if (num7 < priority && Segment1.Intersect(ray.a.y, ray.b.y, vector2.y, out u2)) { Vector3 vector3 = ray.Position(u2); num7 = Vector3.SqrMagnitude(vector3 - vector2); if (num7 < priority && num7 < num8 * num8) { if (flag && i == 1 && v2 < 0.001f) { Vector3 rhs = segment.a - segment.b; u2 += Mathf.Max(0f, Vector3.Dot(vector3, rhs)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs.sqrMagnitude * ray.LengthSqr())); } if (flag2 && i == 16 && v2 > 0.999f) { Vector3 rhs2 = segment.b - segment.a; u2 += Mathf.Max(0f, Vector3.Dot(vector3, rhs2)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs2.sqrMagnitude * ray.LengthSqr())); } priority = num7; t = u2; result = true; } } if (num6 < max) { float num9 = vector2.y + num6 - max; if (Mathf.Max(ray.a.y, ray.b.y) > num9 && Mathf.Min(ray.a.y, ray.b.y) < vector2.y) { Segment2 segment2 = default(Segment2); float num10; if (Segment1.Intersect(ray.a.y, ray.b.y, vector2.y, out u2)) { segment2.a = VectorUtils.XZ(ray.Position(u2)); num10 = u2; } else { segment2.a = VectorUtils.XZ(ray.a); num10 = 0f; } float num11; if (Segment1.Intersect(ray.a.y, ray.b.y, num9, out u2)) { segment2.b = VectorUtils.XZ(ray.Position(u2)); num11 = u2; } else { segment2.b = VectorUtils.XZ(ray.b); num11 = 1f; } num7 = segment2.DistanceSqr(VectorUtils.XZ(vector2), out u2); if (num7 < priority && num7 < num8 * num8) { u2 = num10 + (num11 - num10) * u2; Vector3 lhs = ray.Position(u2); if (flag && i == 1 && v2 < 0.001f) { Vector3 rhs3 = segment.a - segment.b; u2 += Mathf.Max(0f, Vector3.Dot(lhs, rhs3)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs3.sqrMagnitude * ray.LengthSqr())); } if (flag2 && i == 16 && v2 > 0.999f) { Vector3 rhs4 = segment.b - segment.a; u2 += Mathf.Max(0f, Vector3.Dot(lhs, rhs4)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs4.sqrMagnitude * ray.LengthSqr())); } priority = num7; t = u2; result = true; } } } segment.a = segment.b; } priority = Mathf.Max(0f, Mathf.Sqrt(priority) - collisionHalfWidth); } __result = result; return(false); }
public void CustomCheckNextLane(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)) { 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 (CustomTrainAI.CheckOverlap(vehicleID, ref vehicleData, segment, vehicleID)) { maxSpeed = 0f; return; } } segment = new Segment3(vector, bezier.d); if (segment.LengthSqr() >= 1f && CustomTrainAI.CheckOverlap(vehicleID, ref vehicleData, segment, vehicleID)) { maxSpeed = 0f; return; } 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; if ((flags & NetNode.Flags.TrafficLights) != NetNode.Flags.None) { uint currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex; uint num4 = (uint)(((int)num3 << 8) / 32768); uint num5 = currentFrameIndex - num4 & 255u; RoadBaseAI.TrafficLightState vehicleLightState; RoadBaseAI.TrafficLightState pedestrianLightState; bool flag; bool pedestrians; /// NON-STOCK CODE START /// CustomRoadAI.GetTrafficLightState(vehicleID, ref vehicleData, num3, prevPos.m_segment, position.m_segment, ref instance.m_segments.m_buffer[(int)prevPos.m_segment], currentFrameIndex - num4, out vehicleLightState, out pedestrianLightState, out flag, out pedestrians); /// NON-STOCK CODE END /// //RoadBaseAI.GetTrafficLightState(num3, ref instance.m_segments.m_buffer[(int)prevPos.m_segment], currentFrameIndex - num4, out vehicleLightState, out pedestrianLightState, out flag, out pedestrians); if (!flag && num5 >= 196u) { flag = true; RoadBaseAI.SetTrafficLightState(num3, ref instance.m_segments.m_buffer[(int)prevPos.m_segment], currentFrameIndex - num4, vehicleLightState, pedestrianLightState, flag, pedestrians); } switch (vehicleLightState) { case RoadBaseAI.TrafficLightState.RedToGreen: if (num5 < 60u) { maxSpeed = 0f; return; } break; case RoadBaseAI.TrafficLightState.Red: maxSpeed = 0f; return; case RoadBaseAI.TrafficLightState.GreenToRed: if (num5 >= 30u) { maxSpeed = 0f; return; } break; } } } } }
//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 bool RayCast(ref NetSegment mysegment, ushort segmentID, Segment3 ray, float snapElevation, bool nameOnly, out float t, out float priority) { if (CSUROffset.IsCSUROffset(mysegment.Info.m_netAI.m_info)) { return(NetSegmentRayCastMasked(mysegment, segmentID, ray, -1000f, false, out t, out priority)); } NetInfo info = mysegment.Info; t = 0f; priority = 0f; if (nameOnly && (mysegment.m_flags & NetSegment.Flags.NameVisible2) == NetSegment.Flags.None) { return(false); } Bounds bounds = mysegment.m_bounds; bounds.Expand(16f); if (!bounds.IntersectRay(new Ray(ray.a, ray.b - ray.a))) { return(false); } NetManager instance = Singleton <NetManager> .instance; Bezier3 bezier = default(Bezier3); bezier.a = instance.m_nodes.m_buffer[mysegment.m_startNode].m_position; bezier.d = instance.m_nodes.m_buffer[mysegment.m_endNode].m_position; bool result = false; if (nameOnly) { RenderManager instance2 = Singleton <RenderManager> .instance; if (instance2.GetInstanceIndex((uint)(49152 + segmentID), out uint instanceIndex)) { InstanceManager.NameData nameData = instance2.m_instances[instanceIndex].m_nameData; Vector3 position = instance2.m_instances[instanceIndex].m_position; Matrix4x4 dataMatrix = instance2.m_instances[instanceIndex].m_dataMatrix2; float num = Vector3.Distance(position, ray.a); if (nameData != null && num < 1000f) { float snapElevation2 = info.m_netAI.GetSnapElevation(); bezier.a.y += snapElevation2; bezier.d.y += snapElevation2; NetSegment.CalculateMiddlePoints(bezier.a, mysegment.m_startDirection, bezier.d, mysegment.m_endDirection, true, true, out bezier.b, out bezier.c); float num2 = Mathf.Max(1f, Mathf.Abs(dataMatrix.m33 - dataMatrix.m30)); float d = num * 0.0002f + 0.05f / (1f + num * 0.001f); Vector2 vector = nameData.m_size * d; float t2 = Mathf.Max(0f, 0.5f - vector.x / num2 * 0.5f); float t3 = Mathf.Min(1f, 0.5f + vector.x / num2 * 0.5f); bezier = bezier.Cut(t2, t3); float num3 = bezier.DistanceSqr(ray, out float u, out float _); if (num3 < vector.y * vector.y * 0.25f) { Vector3 b = bezier.Position(u); if (Segment1.Intersect(ray.a.y, ray.b.y, b.y, out u)) { num3 = Vector3.SqrMagnitude(ray.Position(u) - b); if (num3 < vector.y * vector.y * 0.25f) { t = u; result = true; } } } } } } else { info.m_netAI.GetRayCastHeights(segmentID, ref mysegment, out float leftMin, out float rightMin, out float max); bezier.a.y += max; bezier.d.y += max; bool flag = (instance.m_nodes.m_buffer[mysegment.m_startNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None; bool flag2 = (instance.m_nodes.m_buffer[mysegment.m_endNode].m_flags & NetNode.Flags.Middle) != NetNode.Flags.None; NetSegment.CalculateMiddlePoints(bezier.a, mysegment.m_startDirection, bezier.d, mysegment.m_endDirection, flag, flag2, out bezier.b, out bezier.c); float minNodeDistance = info.GetMinNodeDistance(); float collisionHalfWidth = info.m_netAI.GetCollisionHalfWidth(); float num4 = (float)(int)instance.m_nodes.m_buffer[mysegment.m_startNode].m_elevation; float num5 = (float)(int)instance.m_nodes.m_buffer[mysegment.m_endNode].m_elevation; if (info.m_netAI.IsUnderground()) { num4 = 0f - num4; num5 = 0f - num5; } num4 += info.m_netAI.GetSnapElevation(); num5 += info.m_netAI.GetSnapElevation(); float a = Mathf.Lerp(minNodeDistance, collisionHalfWidth, Mathf.Clamp01(Mathf.Abs(snapElevation - num4) / 12f)); float b2 = Mathf.Lerp(minNodeDistance, collisionHalfWidth, Mathf.Clamp01(Mathf.Abs(snapElevation - num5) / 12f)); float num6 = Mathf.Min(leftMin, rightMin); t = 1000000f; priority = 1000000f; Segment3 segment = default(Segment3); segment.a = bezier.a; for (int i = 1; i <= 16; i++) { segment.b = bezier.Position((float)i / 16f); float num7 = ray.DistanceSqr(segment, out float u2, out float v2); float num8 = Mathf.Lerp(a, b2, ((float)(i - 1) + v2) / 16f); Vector3 vector2 = segment.Position(v2); if (num7 < priority && Segment1.Intersect(ray.a.y, ray.b.y, vector2.y, out u2)) { Vector3 vector3 = ray.Position(u2); num7 = Vector3.SqrMagnitude(vector3 - vector2); if (num7 < priority && num7 < num8 * num8) { if (flag && i == 1 && v2 < 0.001f) { Vector3 rhs = segment.a - segment.b; u2 += Mathf.Max(0f, Vector3.Dot(vector3, rhs)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs.sqrMagnitude * ray.LengthSqr())); } if (flag2 && i == 16 && v2 > 0.999f) { Vector3 rhs2 = segment.b - segment.a; u2 += Mathf.Max(0f, Vector3.Dot(vector3, rhs2)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs2.sqrMagnitude * ray.LengthSqr())); } priority = num7; t = u2; result = true; } } if (num6 < max) { float num9 = vector2.y + num6 - max; if (Mathf.Max(ray.a.y, ray.b.y) > num9 && Mathf.Min(ray.a.y, ray.b.y) < vector2.y) { Segment2 segment2 = default(Segment2); float num10; if (Segment1.Intersect(ray.a.y, ray.b.y, vector2.y, out u2)) { segment2.a = VectorUtils.XZ(ray.Position(u2)); num10 = u2; } else { segment2.a = VectorUtils.XZ(ray.a); num10 = 0f; } float num11; if (Segment1.Intersect(ray.a.y, ray.b.y, num9, out u2)) { segment2.b = VectorUtils.XZ(ray.Position(u2)); num11 = u2; } else { segment2.b = VectorUtils.XZ(ray.b); num11 = 1f; } num7 = segment2.DistanceSqr(VectorUtils.XZ(vector2), out u2); if (num7 < priority && num7 < num8 * num8) { u2 = num10 + (num11 - num10) * u2; Vector3 lhs = ray.Position(u2); if (flag && i == 1 && v2 < 0.001f) { Vector3 rhs3 = segment.a - segment.b; u2 += Mathf.Max(0f, Vector3.Dot(lhs, rhs3)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs3.sqrMagnitude * ray.LengthSqr())); } if (flag2 && i == 16 && v2 > 0.999f) { Vector3 rhs4 = segment.b - segment.a; u2 += Mathf.Max(0f, Vector3.Dot(lhs, rhs4)) / Mathf.Max(0.001f, Mathf.Sqrt(rhs4.sqrMagnitude * ray.LengthSqr())); } priority = num7; t = u2; result = true; } } } segment.a = segment.b; } priority = Mathf.Max(0f, Mathf.Sqrt(priority) - collisionHalfWidth); } return(result); }
private static ushort CheckOverlap(ushort vehicleID, ref Vehicle vehicleData, Segment3 segment, ushort ignoreVehicle, ushort otherID, ref Vehicle otherData, ref bool overlap, Vector3 min, Vector3 max) { if (ignoreVehicle == 0 || (otherID != ignoreVehicle && otherData.m_leadingVehicle != ignoreVehicle && otherData.m_trailingVehicle != ignoreVehicle)) { VehicleInfo info = otherData.Info; if (info.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { return otherData.m_nextGridVehicle; } if (((vehicleData.m_flags | otherData.m_flags) & Vehicle.Flags.Transition) == Vehicle.Flags.None && (vehicleData.m_flags & Vehicle.Flags.Underground) != (otherData.m_flags & Vehicle.Flags.Underground)) { return otherData.m_nextGridVehicle; } Vector3 vector = Vector3.Min (otherData.m_segment.Min (), otherData.m_targetPos3); Vector3 vector2 = Vector3.Max (otherData.m_segment.Max (), otherData.m_targetPos3); if (min.x < vector2.x + 2f && min.y < vector2.y + 2f && min.z < vector2.z + 2f && vector.x < max.x + 2f && vector.y < max.y + 2f && vector.z < max.z + 2f) { Vector3 rhs = Vector3.Normalize (segment.b - segment.a); Vector3 lhs = otherData.m_segment.a - vehicleData.m_segment.b; Vector3 lhs2 = otherData.m_segment.b - vehicleData.m_segment.b; if (Vector3.Dot (lhs, rhs) >= 1f || Vector3.Dot (lhs2, rhs) >= 1f) { float num2; float num3; float num = segment.DistanceSqr (otherData.m_segment, out num2, out num3); if (num < 4f) { overlap = true; } Vector3 a = otherData.m_segment.b; segment.a.y = segment.a.y * 0.5f; segment.b.y = segment.b.y * 0.5f; for (int i = 0; i < 4; i++) { Vector3 vector3 = otherData.GetTargetPos (i); Segment3 segment2 = new Segment3 (a, vector3); segment2.a.y = segment2.a.y * 0.5f; segment2.b.y = segment2.b.y * 0.5f; if (segment2.LengthSqr () > 0.01f) { num = segment.DistanceSqr (segment2, out num2, out num3); if (num < 4f) { overlap = true; break; } } a = vector3; } } } } return otherData.m_nextGridVehicle; }
public static bool Prefix(TrainAI __instance, 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 netManager = NetManager.instance; ushort nextSourceNodeId = offset < position.m_offset ? netManager.m_segments.m_buffer[position.m_segment].m_startNode : netManager.m_segments.m_buffer[position.m_segment].m_endNode; ushort refTargetNodeId = prevOffset == 0 ? netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode : netManager.m_segments.m_buffer[prevPos.m_segment].m_endNode; #if DEBUG bool logLogic = DebugSwitch.CalculateSegmentPosition.Get() && (DebugSettings.NodeId <= 0 || refTargetNodeId == DebugSettings.NodeId) && (GlobalConfig.Instance.Debug.ApiExtVehicleType == ExtVehicleType.None || GlobalConfig.Instance.Debug.ApiExtVehicleType == ExtVehicleType.RailVehicle) && (DebugSettings.VehicleId == 0 || DebugSettings.VehicleId == vehicleID); if (logLogic) { Log._Debug($"CustomTrainAI.CustomCheckNextLane({vehicleID}) called.\n" + $"\tprevPos.m_segment={prevPos.m_segment}, " + $"prevPos.m_offset={prevPos.m_offset}\n" + $"\tposition.m_segment={position.m_segment}, " + $"position.m_offset={position.m_offset}\n" + $"\tprevLaneID={prevLaneID}, prevOffset={prevOffset}\n" + $"\tprevLaneId={laneID}, prevOffset={offset}\n" + $"\tnextSourceNodeId={nextSourceNodeId}\n" + $"\trefTargetNodeId={refTargetNodeId}, " + $"refTargetNodeId={refTargetNodeId}"); } #endif Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData(); Vector3 lastPosPlusRot = lastFrameData.m_position; Vector3 lastPosMinusRot = lastFrameData.m_position; Vector3 rotationAdd = lastFrameData.m_rotation * new Vector3(0f, 0f, __instance.m_info.m_generatedInfo.m_wheelBase * 0.5f); lastPosPlusRot += rotationAdd; lastPosMinusRot -= rotationAdd; float breakingDist = 0.5f * lastFrameData.m_velocity.sqrMagnitude / __instance.m_info.m_braking; float distToTargetAfterRot = Vector3.Distance(lastPosPlusRot, bezier.a); float distToTargetBeforeRot = Vector3.Distance(lastPosMinusRot, bezier.a); #if DEBUG if (logLogic) { Log._Debug($"CustomTrainAI.CustomCheckNextLane({vehicleID}): " + $"lastPos={lastFrameData.m_position} " + $"lastPosMinusRot={lastPosMinusRot} " + $"lastPosPlusRot={lastPosPlusRot} " + $"rotationAdd={rotationAdd} " + $"breakingDist={breakingDist} " + $"distToTargetAfterRot={distToTargetAfterRot} " + $"distToTargetBeforeRot={distToTargetBeforeRot}"); } #endif if (Mathf.Min(distToTargetAfterRot, distToTargetBeforeRot) >= breakingDist - 5f) { /*VehicleManager vehMan = Singleton<VehicleManager>.instance; * ushort firstVehicleId = vehicleData.GetFirstVehicle(vehicleID); * if (VehicleBehaviorManager.Instance.MayDespawn(ref vehMan.m_vehicles.m_buffer[firstVehicleId]) || vehMan.m_vehicles.m_buffer[firstVehicleId].m_blockCounter < 100) {*/// NON-STOCK CODE #if DEBUG if (logLogic) { Log._Debug($"CustomTrainAI.CustomCheckNextLane({vehicleID}): " + $"Checking for free space on lane {laneID}."); } #endif if (!netManager.m_lanes.m_buffer[laneID].CheckSpace(1000f, vehicleID)) { #if DEBUG if (logLogic) { Log._Debug($"CustomTrainAI.CustomCheckNextLane({vehicleID}): " + $"No space available on lane {laneID}. ABORT."); } #endif vehicleData.m_flags2 |= Vehicle.Flags2.Yielding; vehicleData.m_waitCounter = 0; maxSpeed = 0f; return(false); } Vector3 bezierMiddlePoint = bezier.Position(0.5f); Segment3 segment = Vector3.SqrMagnitude(vehicleData.m_segment.a - bezierMiddlePoint) < Vector3.SqrMagnitude(bezier.a - bezierMiddlePoint) ? new Segment3(vehicleData.m_segment.a, bezierMiddlePoint) : new Segment3(bezier.a, bezierMiddlePoint); #if DEBUG if (logLogic) { Log._Debug($"CustomTrainAI.CustomCheckNextLane({vehicleID}): " + $"Checking for overlap (1). segment.a={segment.a} segment.b={segment.b}"); } #endif if (segment.LengthSqr() >= 3f) { segment.a += (segment.b - segment.a).normalized * 2.5f; if (CheckOverlap(vehicleID, ref vehicleData, segment, vehicleID)) { #if DEBUG if (logLogic) { Log._Debug($"CustomTrainAI.CustomCheckNextLane({vehicleID}): " + $"Overlap detected (1). segment.LengthSqr()={segment.LengthSqr()} " + $"segment.a={segment.a} ABORT."); } #endif vehicleData.m_flags2 |= Vehicle.Flags2.Yielding; vehicleData.m_waitCounter = 0; maxSpeed = 0f; return(false); } } segment = new Segment3(bezierMiddlePoint, bezier.d); #if DEBUG if (logLogic) { Log._Debug($"CustomTrainAI.CustomCheckNextLane({vehicleID}): " + $"Checking for overlap (2). segment.a={segment.a} segment.b={segment.b}"); } #endif if (segment.LengthSqr() >= 1f && CheckOverlap(vehicleID, ref vehicleData, segment, vehicleID)) { #if DEBUG if (logLogic) { Log._Debug($"CustomTrainAI.CustomCheckNextLane({vehicleID}): " + $"Overlap detected (2). ABORT."); } #endif vehicleData.m_flags2 |= Vehicle.Flags2.Yielding; vehicleData.m_waitCounter = 0; maxSpeed = 0f; return(false); } // } // NON-STOCK CODE // if (this.m_info.m_vehicleType != VehicleInfo.VehicleType.Monorail) { // NON-STOCK CODE if (nextSourceNodeId != refTargetNodeId) { return(false); } #if DEBUG if (logLogic) { Log._Debug($"CustomTrainAI.CustomCheckNextLane({vehicleID}): " + $"Checking if vehicle is allowed to change segment."); } #endif float oldMaxSpeed = maxSpeed; if (!VehicleBehaviorManager.Instance.MayChangeSegment( vehicleID, ref vehicleData, lastFrameData.m_velocity.sqrMagnitude, ref prevPos, ref netManager.m_segments.m_buffer[prevPos.m_segment], refTargetNodeId, prevLaneID, ref position, refTargetNodeId, ref netManager.m_nodes.m_buffer[refTargetNodeId], laneID, out maxSpeed)) { #if DEBUG if (logLogic) { Log._Debug($"CustomTrainAI.CustomCheckNextLane({vehicleID}): " + $"Vehicle is NOT allowed to change segment. ABORT."); } #endif maxSpeed = 0; return(false); } ExtVehicleManager.Instance.UpdateVehiclePosition( vehicleID, ref vehicleData); maxSpeed = oldMaxSpeed; // NON-STOCK CODE } return(false); }