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; ref NetSegment currentPositionSegment = ref position.m_segment.ToSegment();
public static bool Prefix(TrainAI __instance, ushort vehicleID, ref Vehicle vehicleData, PathUnit.Position position, uint laneID, byte offset, out Vector3 pos, out Vector3 dir, out float maxSpeed) { VehicleAICommons.CustomCalculateSegmentPosition( __instance, vehicleID, ref vehicleData, position, laneID, offset, out pos, out dir, out maxSpeed); return(false); }
public static bool Prefix(TrainAI __instance, VehicleInfo ___m_info, ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics) { bool reversed = (leaderData.m_flags & Vehicle.Flags.Reversed) != 0; ushort frontVehicleId = (!reversed) ? vehicleData.m_leadingVehicle : vehicleData.m_trailingVehicle; VehicleInfo vehicleInfo = leaderID != vehicleID ? leaderData.Info : ___m_info; TrainAI trainAi = vehicleInfo.m_vehicleAI as TrainAI; if (frontVehicleId != 0) { frameData.m_position += frameData.m_velocity * 0.4f; } else { frameData.m_position += frameData.m_velocity * 0.5f; } frameData.m_swayPosition += frameData.m_swayVelocity * 0.5f; Vector3 posBeforeWheelRot = frameData.m_position; Vector3 posAfterWheelRot = frameData.m_position; Vector3 wheelBaseRot = frameData.m_rotation * new Vector3(0f, 0f, ___m_info.m_generatedInfo.m_wheelBase * 0.5f); if (reversed) { posBeforeWheelRot -= wheelBaseRot; posAfterWheelRot += wheelBaseRot; } else { posBeforeWheelRot += wheelBaseRot; posAfterWheelRot -= wheelBaseRot; } float acceleration = ___m_info.m_acceleration; float braking = ___m_info.m_braking; float curSpeed = frameData.m_velocity.magnitude; Vector3 beforeRotToTargetPos1Diff = (Vector3)vehicleData.m_targetPos1 - posBeforeWheelRot; float beforeRotToTargetPos1DiffSqrMag = beforeRotToTargetPos1Diff.sqrMagnitude; Quaternion curInvRot = Quaternion.Inverse(frameData.m_rotation); Vector3 curveTangent = curInvRot * frameData.m_velocity; Vector3 forward = Vector3.forward; Vector3 targetMotion = Vector3.zero; float targetSpeed = 0f; float motionFactor = 0.5f; if (frontVehicleId != 0) { VehicleManager vehMan = VehicleManager.instance; Vehicle.Frame frontVehLastFrameData = vehMan.m_vehicles.m_buffer[frontVehicleId].GetLastFrameData(); VehicleInfo frontVehInfo = vehMan.m_vehicles.m_buffer[frontVehicleId].Info; float attachOffset; if ((vehicleData.m_flags & Vehicle.Flags.Inverted) != 0 != reversed) { attachOffset = ___m_info.m_attachOffsetBack - (___m_info.m_generatedInfo.m_size.z * 0.5f); } else { attachOffset = ___m_info.m_attachOffsetFront - (___m_info.m_generatedInfo.m_size.z * 0.5f); } float frontAttachOffset; if ((vehMan.m_vehicles.m_buffer[frontVehicleId].m_flags & Vehicle.Flags.Inverted) != 0 != reversed) { frontAttachOffset = frontVehInfo.m_attachOffsetFront - (frontVehInfo.m_generatedInfo.m_size.z * 0.5f); } else { frontAttachOffset = (frontVehInfo.m_attachOffsetBack - (frontVehInfo.m_generatedInfo.m_size.z * 0.5f)); } Vector3 posMinusAttachOffset = frameData.m_position; if (reversed) { posMinusAttachOffset += frameData.m_rotation * new Vector3(0f, 0f, attachOffset); } else { posMinusAttachOffset -= frameData.m_rotation * new Vector3(0f, 0f, attachOffset); } Vector3 frontPosPlusAttachOffset = frontVehLastFrameData.m_position; if (reversed) { frontPosPlusAttachOffset -= frontVehLastFrameData.m_rotation * new Vector3(0f, 0f, frontAttachOffset); } else { frontPosPlusAttachOffset += frontVehLastFrameData.m_rotation * new Vector3(0f, 0f, frontAttachOffset); } Vector3 frontPosMinusWheelBaseRot = frontVehLastFrameData.m_position; wheelBaseRot = frontVehLastFrameData.m_rotation * new Vector3( 0f, 0f, frontVehInfo.m_generatedInfo.m_wheelBase * 0.5f); if (reversed) { frontPosMinusWheelBaseRot += wheelBaseRot; } else { frontPosMinusWheelBaseRot -= wheelBaseRot; } if (Vector3.Dot( vehicleData.m_targetPos1 - vehicleData.m_targetPos0, (Vector3)vehicleData.m_targetPos0 - posAfterWheelRot) < 0f && vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == 0) { int someIndex = -1; UpdatePathTargetPositions( trainAi, vehicleID, ref vehicleData, vehicleData.m_targetPos0, posAfterWheelRot, 0, ref leaderData, ref someIndex, 0, 0, Vector3.SqrMagnitude(posAfterWheelRot - (Vector3)vehicleData.m_targetPos0) + 1f, 1f); beforeRotToTargetPos1DiffSqrMag = 0f; } float maxAttachDist = Mathf.Max(Vector3.Distance(posMinusAttachOffset, frontPosPlusAttachOffset), 2f); const float ONE = 1f; float maxAttachSqrDist = maxAttachDist * maxAttachDist; const float ONE_SQR = ONE * ONE; int i = 0; if (beforeRotToTargetPos1DiffSqrMag < maxAttachSqrDist) { if (vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == 0) { UpdatePathTargetPositions( trainAi, vehicleID, ref vehicleData, posAfterWheelRot, posBeforeWheelRot, 0, ref leaderData, ref i, 1, 2, maxAttachSqrDist, ONE_SQR); } while (i < 4) { vehicleData.SetTargetPos(i, vehicleData.GetTargetPos(i - 1)); i++; } beforeRotToTargetPos1Diff = (Vector3)vehicleData.m_targetPos1 - posBeforeWheelRot; beforeRotToTargetPos1DiffSqrMag = beforeRotToTargetPos1Diff.sqrMagnitude; } if (vehicleData.m_path != 0u) { NetManager netMan = NetManager.instance; byte pathPosIndex = vehicleData.m_pathPositionIndex; byte lastPathOffset = vehicleData.m_lastPathOffset; if (pathPosIndex == 255) { pathPosIndex = 0; } PathManager pathMan = PathManager.instance; if (pathMan.m_pathUnits.m_buffer[vehicleData.m_path] .GetPosition(pathPosIndex >> 1, out PathUnit.Position curPathPos)) { netMan.m_segments.m_buffer[curPathPos.m_segment].AddTraffic( Mathf.RoundToInt(___m_info.m_generatedInfo.m_size.z * 3f), GetNoiseLevel(trainAi)); if ((pathPosIndex & 1) == 0 || lastPathOffset == 0 || (leaderData.m_flags & Vehicle.Flags.WaitingPath) != 0) { uint laneId = PathManager.GetLaneID(curPathPos); if (laneId != 0u) { netMan.m_lanes.m_buffer[laneId].ReserveSpace(___m_info.m_generatedInfo.m_size.z); } } else if (pathMan.m_pathUnits.m_buffer[vehicleData.m_path] .GetNextPosition(pathPosIndex >> 1, out PathUnit.Position nextPathPos)) { // NON-STOCK CODE START ushort transitNodeId; if (curPathPos.m_offset < 128) { transitNodeId = netMan.m_segments.m_buffer[curPathPos.m_segment].m_startNode; } else { transitNodeId = netMan.m_segments.m_buffer[curPathPos.m_segment].m_endNode; } if (VehicleBehaviorManager.Instance.IsSpaceReservationAllowed( transitNodeId, curPathPos, nextPathPos)) { // NON-STOCK CODE END uint nextLaneId = PathManager.GetLaneID(nextPathPos); if (nextLaneId != 0u) { netMan.m_lanes.m_buffer[nextLaneId].ReserveSpace(___m_info.m_generatedInfo.m_size.z); } } // NON-STOCK CODE } } } beforeRotToTargetPos1Diff = curInvRot * beforeRotToTargetPos1Diff; float negTotalAttachLen = -(((___m_info.m_generatedInfo.m_wheelBase + frontVehInfo.m_generatedInfo.m_wheelBase) * 0.5f) + attachOffset + frontAttachOffset); bool hasPath = false; if (vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == 0) { if (Line3.Intersect( posBeforeWheelRot, vehicleData.m_targetPos1, frontPosMinusWheelBaseRot, negTotalAttachLen, out float u1, out float u2)) { targetMotion = beforeRotToTargetPos1Diff * Mathf.Clamp(Mathf.Min(u1, u2) / 0.6f, 0f, 2f); } else { Line3.DistanceSqr( posBeforeWheelRot, vehicleData.m_targetPos1, frontPosMinusWheelBaseRot, out u1); targetMotion = beforeRotToTargetPos1Diff * Mathf.Clamp(u1 / 0.6f, 0f, 2f); } hasPath = true; } if (hasPath) { if (Vector3.Dot( frontPosMinusWheelBaseRot - posBeforeWheelRot, posBeforeWheelRot - posAfterWheelRot) < 0f) { motionFactor = 0f; } } else { float frontPosBeforeToAfterWheelRotDist = Vector3.Distance( frontPosMinusWheelBaseRot, posBeforeWheelRot); motionFactor = 0f; targetMotion = curInvRot * ((frontPosMinusWheelBaseRot - posBeforeWheelRot) * (Mathf.Max(0f, frontPosBeforeToAfterWheelRotDist - negTotalAttachLen) / Mathf.Max(1f, frontPosBeforeToAfterWheelRotDist * 0.6f))); } }
public static bool Prefix(TrainAI __instance, ushort vehicleID, ref Vehicle vehicleData, bool reserveSpace) { uint pathUnitId = vehicleData.m_path; if (pathUnitId == 0u) { return(false); } NetManager netMan = NetManager.instance; PathManager pathMan = PathManager.instance; byte pathPosIndex = vehicleData.m_pathPositionIndex; if (pathPosIndex == 255) { pathPosIndex = 0; } pathPosIndex = (byte)(pathPosIndex >> 1); bool stopLoop = false; // NON-STOCK CODE for (int i = 0; i < 6; i++) { if (!pathMan.m_pathUnits.m_buffer[pathUnitId].GetPosition(pathPosIndex, out PathUnit.Position position)) { return(false); } ref NetSegment positionSegment = ref position.m_segment.ToSegment(); // NON-STOCK CODE START ushort transitNodeId = position.m_offset < 128 ? positionSegment.m_startNode : positionSegment.m_endNode; if (Options.timedLightsEnabled) { // when a TTL is active only reserve space if it shows green if (pathMan.m_pathUnits.m_buffer[pathUnitId].GetNextPosition(pathPosIndex, out PathUnit.Position nextPos)) { if (!VehicleBehaviorManager.Instance.IsSpaceReservationAllowed( transitNodeId, position, nextPos)) { stopLoop = true; } } } // NON-STOCK CODE END if (reserveSpace && i >= 1 && i <= 2) { uint laneId = PathManager.GetLaneID(position); if (laneId != 0u) { reserveSpace = laneId.ToLane().ReserveSpace(__instance.m_info.m_generatedInfo.m_size.z, vehicleID); } } ForceTrafficLights(transitNodeId, position); // NON-STOCK CODE // NON-STOCK CODE START if (stopLoop) { return(false); } // NON-STOCK CODE END if ((pathPosIndex += 1) < pathMan.m_pathUnits.m_buffer[pathUnitId].m_positionCount) { continue; } pathUnitId = pathMan.m_pathUnits.m_buffer[pathUnitId].m_nextPathUnit; pathPosIndex = 0; if (pathUnitId == 0u) { return(false); } }
private static void ResetTargets(ushort vehicleID, ref Vehicle vehicleData, ushort leaderID, ref Vehicle leaderData, bool pushPathPos) { Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData(); VehicleInfo info = vehicleData.Info; TrainAI trainAI = info.m_vehicleAI as TrainAI; Vector3 vector = lastFrameData.m_position; Vector3 vector2 = lastFrameData.m_position; Vector3 b = lastFrameData.m_rotation * new Vector3(0f, 0f, info.m_generatedInfo.m_wheelBase * 0.5f); if ((leaderData.m_flags & Vehicle.Flags.Reversed) != Vehicle.Flags.None) { vector -= b; vector2 += b; } else { vector += b; vector2 -= b; } vehicleData.m_targetPos0 = vector2; vehicleData.m_targetPos0.w = 2f; vehicleData.m_targetPos1 = vector; vehicleData.m_targetPos1.w = 2f; vehicleData.m_targetPos2 = vehicleData.m_targetPos1; vehicleData.m_targetPos3 = vehicleData.m_targetPos1; if (vehicleData.m_path != 0u) { PathManager instance = Singleton <PathManager> .instance; int num = (vehicleData.m_pathPositionIndex >> 1) + 1; uint num2 = vehicleData.m_path; if (num >= (int)instance.m_pathUnits.m_buffer [(int)((UIntPtr)num2)].m_positionCount) { num = 0; num2 = instance.m_pathUnits.m_buffer [(int)((UIntPtr)num2)].m_nextPathUnit; } PathUnit.Position pathPos; if (instance.m_pathUnits.m_buffer [(int)((UIntPtr)vehicleData.m_path)].GetPosition(vehicleData.m_pathPositionIndex >> 1, out pathPos)) { uint laneID = PathManager.GetLaneID(pathPos); PathUnit.Position pathPos2; if (num2 != 0u && instance.m_pathUnits.m_buffer [(int)((UIntPtr)num2)].GetPosition(num, out pathPos2)) { uint laneID2 = PathManager.GetLaneID(pathPos2); if (laneID2 == laneID) { if (num2 != vehicleData.m_path) { instance.ReleaseFirstUnit(ref vehicleData.m_path); } vehicleData.m_pathPositionIndex = (byte)(num << 1); } } PathUnit.CalculatePathPositionOffset(laneID, vector2, out vehicleData.m_lastPathOffset); } } if (vehicleData.m_path != 0u) { int num3 = 0; ((FakeTrainAI)trainAI).UpdatePathTargetPositions(vehicleID, ref vehicleData, vector2, vector, 0, ref leaderData, ref num3, 1, 4, 4f, 1f); } }
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); }