Пример #1
0
        /*
         * Private unmodified methods
         */

        private void TryCollectGarbage(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData)
        {
            Vector3         position = frameData.m_position;
            float           num      = position.x - 32f;
            float           num2     = position.z - 32f;
            float           num3     = position.x + 32f;
            float           num4     = position.z + 32f;
            int             num5     = Mathf.Max((int)((num - 72f) / 64f + 135f), 0);
            int             num6     = Mathf.Max((int)((num2 - 72f) / 64f + 135f), 0);
            int             num7     = Mathf.Min((int)((num3 + 72f) / 64f + 135f), 269);
            int             num8     = Mathf.Min((int)((num4 + 72f) / 64f + 135f), 269);
            BuildingManager instance = Singleton <BuildingManager> .instance;

            for (int i = num6; i <= num8; i++)
            {
                for (int j = num5; j <= num7; j++)
                {
                    ushort num9  = instance.m_buildingGrid[i * 270 + j];
                    int    num10 = 0;
                    while (num9 != 0)
                    {
                        this.TryCollectGarbage(vehicleID, ref vehicleData, ref frameData, num9, ref instance.m_buildings.m_buffer[(int)num9]);
                        num9 = instance.m_buildings.m_buffer[(int)num9].m_nextGridBuilding;
                        if (++num10 >= 32768)
                        {
                            CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace);

                            break;
                        }
                    }
                }
            }
        }
Пример #2
0
        private void CalculatePositionAndRotation(ushort vehicleID, ref Vehicle vehicleData, out Vector3 position, out Vector3 swayPosition, out Quaternion rotation)
        {
            uint targetFrame = vehicleData.GetTargetFrame(m_info, vehicleID);

            Vehicle.Frame frameData  = vehicleData.GetFrameData(targetFrame - 32);
            Vehicle.Frame frameData2 = vehicleData.GetFrameData(targetFrame - 16);
            float         t          = ((float)(targetFrame & 0xF) + Singleton <SimulationManager> .instance.m_referenceTimer) * 0.0625f;
            Bezier3       bezier     = default(Bezier3);

            bezier.a = frameData.m_position;
            bezier.b = frameData.m_position + frameData.m_velocity * 0.333f;
            bezier.c = frameData2.m_position - frameData2.m_velocity * 0.333f;
            bezier.d = frameData2.m_position;
            position = bezier.Position(t);
            Bezier3 bezier2 = default(Bezier3);

            bezier2.a       = frameData.m_swayPosition;
            bezier2.b       = frameData.m_swayPosition + frameData.m_swayVelocity * 0.333f;
            bezier2.c       = frameData2.m_swayPosition - frameData2.m_swayVelocity * 0.333f;
            bezier2.d       = frameData2.m_swayPosition;
            swayPosition    = bezier2.Position(t);
            swayPosition.x *= m_info.m_leanMultiplier / Mathf.Max(1f, m_info.m_generatedInfo.m_wheelGauge);
            swayPosition.z *= m_info.m_nodMultiplier / Mathf.Max(1f, m_info.m_generatedInfo.m_wheelBase);
            rotation        = Quaternion.Lerp(frameData.m_rotation, frameData2.m_rotation, t);
        }
Пример #3
0
        private void CheckOtherVehicles(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ref float maxSpeed, ref bool blocked, float maxDistance, float maxBraking, int lodPhysics)
        {
            VehicleManager instance = Singleton <VehicleManager> .instance;
            Vector3        vector   = ((Vector3)vehicleData.m_targetPos3) - frameData.m_position;
            Vector3        rhs      = frameData.m_position + Vector3.ClampMagnitude(vector, maxDistance);
            Vector3        min      = Vector3.Min(vehicleData.m_segment.Min(), rhs);
            Vector3        max      = Vector3.Max(vehicleData.m_segment.Max(), rhs);
            int            num      = Mathf.Max((int)((min.x - 100f) / 320f + 27f), 0);
            int            num2     = Mathf.Max((int)((min.z - 100f) / 320f + 27f), 0);
            int            num3     = Mathf.Min((int)((max.x + 100f) / 320f + 27f), 53);
            int            num4     = Mathf.Min((int)((max.z + 100f) / 320f + 27f), 53);

            for (int i = num2; i <= num4; i++)
            {
                for (int j = num; j <= num3; j++)
                {
                    ushort num5 = instance.m_vehicleGrid2 [i * 54 + j];
                    int    num6 = 0;
                    while (num5 != 0)
                    {
                        num5 = this.CheckOtherVehicle(vehicleID, ref vehicleData, ref frameData, ref maxSpeed, ref blocked, maxBraking, num5, ref instance.m_vehicles.m_buffer [(int)num5], min, max, lodPhysics);
                        if (++num6 > 65536)
                        {
                            CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace);

                            break;
                        }
                    }
                }
            }
        }
Пример #4
0
        public bool CustomCreateVehicle(out ushort vehicleId, ref Randomizer r, VehicleInfo info, Vector3 position, TransferManager.TransferReason type, bool transferToSource, bool transferToTarget)
        {
            ushort vehId;

            if (this.m_vehicles.CreateItem(out vehId, ref r))
            {
                vehicleId = vehId;
                Vehicle.Frame frame = new Vehicle.Frame(position, Quaternion.identity);
                this.m_vehicles.m_buffer[(int)vehicleId].m_flags = Vehicle.Flags.Created;
                if (transferToSource)
                {
                    this.m_vehicles.m_buffer[vehicleId].m_flags = (this.m_vehicles.m_buffer[vehicleId].m_flags | Vehicle.Flags.TransferToSource);
                }
                if (transferToTarget)
                {
                    this.m_vehicles.m_buffer[vehicleId].m_flags = (this.m_vehicles.m_buffer[vehicleId].m_flags | Vehicle.Flags.TransferToTarget);
                }
                this.m_vehicles.m_buffer[(int)vehicleId].Info                = info;
                this.m_vehicles.m_buffer[(int)vehicleId].m_frame0            = frame;
                this.m_vehicles.m_buffer[(int)vehicleId].m_frame1            = frame;
                this.m_vehicles.m_buffer[(int)vehicleId].m_frame2            = frame;
                this.m_vehicles.m_buffer[(int)vehicleId].m_frame3            = frame;
                this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos0        = Vector4.zero;
                this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos1        = Vector4.zero;
                this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos2        = Vector4.zero;
                this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos3        = Vector4.zero;
                this.m_vehicles.m_buffer[(int)vehicleId].m_sourceBuilding    = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_targetBuilding    = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_transferType      = (byte)type;
                this.m_vehicles.m_buffer[(int)vehicleId].m_transferSize      = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_waitCounter       = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_blockCounter      = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_nextGridVehicle   = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_nextOwnVehicle    = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_nextGuestVehicle  = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_nextLineVehicle   = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_transportLine     = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_leadingVehicle    = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_trailingVehicle   = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_cargoParent       = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_firstCargo        = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_nextCargo         = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_citizenUnits      = 0u;
                this.m_vehicles.m_buffer[(int)vehicleId].m_path              = 0u;
                this.m_vehicles.m_buffer[(int)vehicleId].m_lastFrame         = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_pathPositionIndex = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_lastPathOffset    = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_gateIndex         = 0;
                info.m_vehicleAI.CreateVehicle(vehicleId, ref this.m_vehicles.m_buffer[vehicleId]);
                info.m_vehicleAI.FrameDataUpdated(vehicleId, ref this.m_vehicles.m_buffer[vehicleId], ref this.m_vehicles.m_buffer[vehicleId].m_frame0);
                this.m_vehicleCount = (int)(this.m_vehicles.ItemCount() - 1u);

                VehicleStateManager.Instance().DetermineVehicleType(vehicleId, ref this.m_vehicles.m_buffer[vehicleId]);                 // NON-STOCK CODE

                return(true);
            }
            vehicleId = 0;
            return(false);
        }
 internal static void Postfix(ref Vehicle vehicleData, ref Vehicle.Frame frameData)
 {
     if (!RotationUpdated)
     {
         return;
     }
     RotationUpdated = false;
     SuperElevationCommons.Postfix(ref vehicleData, ref frameData);
 }
        public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ushort leaderID, ref Vehicle leaderData, int lodPhysics)
        {
            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                if (CustomCarAI.sm_speedData[vehicleID].speedMultiplier == 0 || CustomCarAI.sm_speedData[vehicleID].currentPath != vehicleData.m_path)
                {
                    CustomCarAI.sm_speedData[vehicleID].currentPath = vehicleData.m_path;
                    CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(0.7f, 1.1f);
                }
                CustomCarAI.sm_speedData[vehicleID].ApplySpeedMultiplier(this.m_info);
            }


            if ((vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None)
            {
                Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData();
                if (this.m_info.m_isLargeVehicle)
                {
                    int num  = Mathf.Clamp((int)(lastFrameData.m_position.x / 320f + 27f), 0, 53);
                    int num2 = Mathf.Clamp((int)(lastFrameData.m_position.z / 320f + 27f), 0, 53);
                    CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref lastFrameData, leaderID, ref leaderData, lodPhysics);
                    int num3 = Mathf.Clamp((int)(lastFrameData.m_position.x / 320f + 27f), 0, 53);
                    int num4 = Mathf.Clamp((int)(lastFrameData.m_position.z / 320f + 27f), 0, 53);
                    if ((num3 != num || num4 != num2) && (vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None)
                    {
                        Singleton <VehicleManager> .instance.RemoveFromGrid(vehicleID, ref vehicleData, true, num, num2);

                        Singleton <VehicleManager> .instance.AddToGrid(vehicleID, ref vehicleData, true, num3, num4);
                    }
                }
                else
                {
                    int num5 = Mathf.Clamp((int)(lastFrameData.m_position.x / 32f + 270f), 0, 539);
                    int num6 = Mathf.Clamp((int)(lastFrameData.m_position.z / 32f + 270f), 0, 539);
                    CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref lastFrameData, leaderID, ref leaderData, lodPhysics);
                    int num7 = Mathf.Clamp((int)(lastFrameData.m_position.x / 32f + 270f), 0, 539);
                    int num8 = Mathf.Clamp((int)(lastFrameData.m_position.z / 32f + 270f), 0, 539);
                    if ((num7 != num5 || num8 != num6) && (vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None)
                    {
                        Singleton <VehicleManager> .instance.RemoveFromGrid(vehicleID, ref vehicleData, false, num5, num6);

                        Singleton <VehicleManager> .instance.AddToGrid(vehicleID, ref vehicleData, false, num7, num8);
                    }
                }
                if ((vehicleData.m_flags & (Vehicle.Flags.Created | Vehicle.Flags.Deleted)) == Vehicle.Flags.Created)
                {
                    this.FrameDataUpdated(vehicleID, ref vehicleData, ref lastFrameData);
                    vehicleData.SetFrameData(Singleton <SimulationManager> .instance.m_currentFrameIndex, lastFrameData);
                }
            }

            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                CustomCarAI.sm_speedData[vehicleID].RestoreVehicleSpeed(this.m_info);
            }
        }
Пример #7
0
 private bool CustomArriveAtTarget(ushort vehicleID, ref Vehicle data)
 {
     // NON-STOCK CODE START
     //RealCity Mod related
     if (Loader.isRealCityRunning)
     {
         GetVehicleRunningTimingForRealCity(vehicleID, ref data);
     }
     //RealGasStation Mod related
     if (data.m_transferType == 112)
     {
         PassengerCarAIArriveAtTargetForRealGasStationPre(vehicleID, ref data);
         return(true);
     }
     // NON-STOCK CODE END
     if ((data.m_flags & Vehicle.Flags.Parking) != (Vehicle.Flags) 0)
     {
         VehicleManager instance       = Singleton <VehicleManager> .instance;
         CitizenManager instance2      = Singleton <CitizenManager> .instance;
         ushort         driverInstance = this.GetDriverInstance(vehicleID, ref data);
         if (driverInstance != 0)
         {
             uint citizen = instance2.m_instances.m_buffer[(int)driverInstance].m_citizen;
             if (citizen != 0u)
             {
                 ushort parkedVehicle = instance2.m_citizens.m_buffer[(int)((UIntPtr)citizen)].m_parkedVehicle;
                 if (parkedVehicle != 0)
                 {
                     Vehicle.Frame lastFrameData = data.GetLastFrameData();
                     instance.m_parkedVehicles.m_buffer[(int)parkedVehicle].m_travelDistance = lastFrameData.m_travelDistance;
                     VehicleParked[] expr_A1_cp_0 = instance.m_parkedVehicles.m_buffer;
                     ushort          expr_A1_cp_1 = parkedVehicle;
                     expr_A1_cp_0[(int)expr_A1_cp_1].m_flags = (ushort)(expr_A1_cp_0[(int)expr_A1_cp_1].m_flags & 65527);
                     InstanceID empty = InstanceID.Empty;
                     empty.Vehicle = vehicleID;
                     InstanceID empty2 = InstanceID.Empty;
                     empty2.ParkedVehicle = parkedVehicle;
                     Singleton <InstanceManager> .instance.ChangeInstance(empty, empty2);
                 }
             }
         }
     }
     this.UnloadPassengers(vehicleID, ref data);
     if (data.m_targetBuilding == 0)
     {
         return(true);
     }
     data.m_targetPos0   = Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)data.m_targetBuilding].CalculateSidewalkPosition();
     data.m_targetPos0.w = 2f;
     data.m_targetPos1   = data.m_targetPos0;
     data.m_targetPos2   = data.m_targetPos0;
     data.m_targetPos3   = data.m_targetPos0;
     this.RemoveTarget(vehicleID, ref data);
     return(true);
 }
        private void TryCollectCrime(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort buildingID, ref Building building)
        {
            Vector3 a = building.CalculateSidewalkPosition();

            if (Vector3.SqrMagnitude(a - frameData.m_position) < 1024f)
            {
                int          num  = -this.m_crimeCapacity;
                BuildingInfo info = building.Info;
                info.m_buildingAI.ModifyMaterialBuffer(buildingID, ref building, TransferManager.TransferReason.Crime, ref num);
            }
        }
Пример #9
0
		public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics)
		{
			CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics);
			if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None && this.CanLeave(vehicleID, ref vehicleData))
			{
				vehicleData.m_flags &= ~Vehicle.Flags.Stopped;
				vehicleData.m_flags |= Vehicle.Flags.Leaving;
			}
			if ((vehicleData.m_flags & (Vehicle.Flags.TransferToSource | Vehicle.Flags.GoingBack)) == Vehicle.Flags.TransferToSource && this.ShouldReturnToSource(vehicleID, ref vehicleData))
			{
				this.SetTarget(vehicleID, ref vehicleData, 0);
			}
		}
Пример #10
0
        public static void Postfix(ref Vehicle vehicleData, ref Vehicle.Frame frameData)
        {
            if (!vehicleData.GetCurrentPathPos(out var pathPos))
            {
                return;
            }

            float se = GetCurrentSE(pathPos, vehicleData.m_lastPathOffset * (1f / 255f), ref vehicleData);


            var rot = Quaternion.Euler(0, 0f, se);

            frameData.m_rotation *= rot;
        }
        internal static void Postfix(ref Vehicle vehicleData, ref Vehicle.Frame frameData)
        {
            if (vehicleData.Info.m_leanMultiplier < 0)
            {
                return; // motor cycle.
            }
            if (!RotationUpdated)
            {
                //Log.Debug("CarTrailerAI_SimulationStepPatch rotation was not updated! leadID=" + vehicleData.m_leadingVehicle);
                return;
            }
            RotationUpdated = false;

            ref Vehicle leadingVehicle = ref VehicleBuffer[vehicleData.m_leadingVehicle];
Пример #12
0
		public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics)
		{
            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                if (m_speedData.currentPath != vehicleData.m_path)
                {
                    m_speedData.currentPath = vehicleData.m_path;
                    if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.Emergency2)
                        m_speedData.SetRandomSpeedMultiplier(1f, 1.75f);
                    else
                        m_speedData.SetRandomSpeedMultiplier(0.7f, 1.1f);
                }
                m_speedData.ApplySpeedMultiplier(this.m_info);
            }
            

			frameData.m_blinkState = (((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None) ? 0f : 10f);
			this.TryCollectCrime(vehicleID, ref vehicleData, ref frameData);
			CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics);
			if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None)
			{
				if (this.CanLeave(vehicleID, ref vehicleData))
				{
					vehicleData.m_flags &= ~Vehicle.Flags.Stopped;
					vehicleData.m_flags |= Vehicle.Flags.Leaving;
				}
			}
			else
			{
				if ((vehicleData.m_flags & Vehicle.Flags.Arriving) != Vehicle.Flags.None && vehicleData.m_targetBuilding != 0 && (vehicleData.m_flags & (Vehicle.Flags.Emergency2 | Vehicle.Flags.WaitingPath | Vehicle.Flags.GoingBack | Vehicle.Flags.WaitingTarget)) == Vehicle.Flags.None)
				{
					this.ArriveAtTarget(vehicleID, ref vehicleData);
				}
			}
			if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == Vehicle.Flags.None && this.ShouldReturnToSource(vehicleID, ref vehicleData))
			{
				this.SetTarget(vehicleID, ref vehicleData, 0);
			}

            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                m_speedData.RestoreVehicleSpeed(this.m_info);
            }
		}
Пример #13
0
        private void TryCollectGarbage(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort buildingID, ref Building building)
        {
            Vector3 a = building.CalculateSidewalkPosition();

            if (Vector3.SqrMagnitude(a - frameData.m_position) < 1024f)
            {
                int num = Mathf.Min(0, (int)vehicleData.m_transferSize - this.m_cargoCapacity);
                if (num == 0)
                {
                    return;
                }
                BuildingInfo info = building.Info;
                info.m_buildingAI.ModifyMaterialBuffer(buildingID, ref building, (TransferManager.TransferReason)vehicleData.m_transferType, ref num);
                if (num != 0)
                {
                    vehicleData.m_transferSize += (ushort)Mathf.Max(0, -num);
                }
            }
        }
Пример #14
0
        public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ushort leaderID, ref Vehicle leaderData, int lodPhysics)
        {
            if ((vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None)
            {
                Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData();
                if (this.m_info.m_isLargeVehicle)
                {
                    int num  = Mathf.Clamp((int)(lastFrameData.m_position.x / 320f + 27f), 0, 53);
                    int num2 = Mathf.Clamp((int)(lastFrameData.m_position.z / 320f + 27f), 0, 53);
                    CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref lastFrameData, leaderID, ref leaderData, lodPhysics);
                    int num3 = Mathf.Clamp((int)(lastFrameData.m_position.x / 320f + 27f), 0, 53);
                    int num4 = Mathf.Clamp((int)(lastFrameData.m_position.z / 320f + 27f), 0, 53);
                    if ((num3 != num || num4 != num2) && (vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None)
                    {
                        Singleton <VehicleManager> .instance.RemoveFromGrid(vehicleID, ref vehicleData, true, num, num2);

                        Singleton <VehicleManager> .instance.AddToGrid(vehicleID, ref vehicleData, true, num3, num4);
                    }
                }
                else
                {
                    int num5 = Mathf.Clamp((int)(lastFrameData.m_position.x / 32f + 270f), 0, 539);
                    int num6 = Mathf.Clamp((int)(lastFrameData.m_position.z / 32f + 270f), 0, 539);
                    CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref lastFrameData, leaderID, ref leaderData, lodPhysics);
                    int num7 = Mathf.Clamp((int)(lastFrameData.m_position.x / 32f + 270f), 0, 539);
                    int num8 = Mathf.Clamp((int)(lastFrameData.m_position.z / 32f + 270f), 0, 539);
                    if ((num7 != num5 || num8 != num6) && (vehicleData.m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None)
                    {
                        Singleton <VehicleManager> .instance.RemoveFromGrid(vehicleID, ref vehicleData, false, num5, num6);

                        Singleton <VehicleManager> .instance.AddToGrid(vehicleID, ref vehicleData, false, num7, num8);
                    }
                }
                if ((vehicleData.m_flags & (Vehicle.Flags.Created | Vehicle.Flags.Deleted)) == Vehicle.Flags.Created)
                {
                    this.FrameDataUpdated(vehicleID, ref vehicleData, ref lastFrameData);
                    vehicleData.SetFrameData(Singleton <SimulationManager> .instance.m_currentFrameIndex, lastFrameData);
                }
            }
        }
Пример #15
0
        public bool CustomCreateVehicle(out ushort vehicleId, ref Randomizer r, VehicleInfo info, Vector3 position, TransferManager.TransferReason type, bool transferToSource, bool transferToTarget)
        {
            // NON-STOCK CODE START
            if (this.m_vehicleCount > VehicleManager.MAX_VEHICLE_COUNT - 5)
            {
                // prioritize service vehicles and public transport when hitting the vehicle limit
                ItemClass.Service service = info.GetService();
                if (service == ItemClass.Service.Residential || service == ItemClass.Service.Industrial || service == ItemClass.Service.Commercial || service == ItemClass.Service.Office)
                {
                    vehicleId = 0;
                    return(false);
                }
            }
            // NON-STOCK CODE END

            ushort vehId;

            if (this.m_vehicles.CreateItem(out vehId, ref r))
            {
                vehicleId = vehId;
                Vehicle.Frame frame = new Vehicle.Frame(position, Quaternion.identity);
                this.m_vehicles.m_buffer[(int)vehicleId].m_flags  = Vehicle.Flags.Created;
                this.m_vehicles.m_buffer[(int)vehicleId].m_flags2 = (Vehicle.Flags2) 0;
                if (transferToSource)
                {
                    this.m_vehicles.m_buffer[vehicleId].m_flags = (this.m_vehicles.m_buffer[vehicleId].m_flags | Vehicle.Flags.TransferToSource);
                }
                if (transferToTarget)
                {
                    this.m_vehicles.m_buffer[vehicleId].m_flags = (this.m_vehicles.m_buffer[vehicleId].m_flags | Vehicle.Flags.TransferToTarget);
                }
                this.m_vehicles.m_buffer[(int)vehicleId].Info                = info;
                this.m_vehicles.m_buffer[(int)vehicleId].m_frame0            = frame;
                this.m_vehicles.m_buffer[(int)vehicleId].m_frame1            = frame;
                this.m_vehicles.m_buffer[(int)vehicleId].m_frame2            = frame;
                this.m_vehicles.m_buffer[(int)vehicleId].m_frame3            = frame;
                this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos0        = Vector4.zero;
                this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos1        = Vector4.zero;
                this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos2        = Vector4.zero;
                this.m_vehicles.m_buffer[(int)vehicleId].m_targetPos3        = Vector4.zero;
                this.m_vehicles.m_buffer[(int)vehicleId].m_sourceBuilding    = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_targetBuilding    = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_transferType      = (byte)type;
                this.m_vehicles.m_buffer[(int)vehicleId].m_transferSize      = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_waitCounter       = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_blockCounter      = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_nextGridVehicle   = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_nextOwnVehicle    = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_nextGuestVehicle  = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_nextLineVehicle   = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_transportLine     = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_leadingVehicle    = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_trailingVehicle   = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_cargoParent       = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_firstCargo        = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_nextCargo         = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_citizenUnits      = 0u;
                this.m_vehicles.m_buffer[(int)vehicleId].m_path              = 0u;
                this.m_vehicles.m_buffer[(int)vehicleId].m_lastFrame         = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_pathPositionIndex = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_lastPathOffset    = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_gateIndex         = 0;
                this.m_vehicles.m_buffer[(int)vehicleId].m_waterSource       = 0;
                info.m_vehicleAI.CreateVehicle(vehicleId, ref this.m_vehicles.m_buffer[vehicleId]);
                info.m_vehicleAI.FrameDataUpdated(vehicleId, ref this.m_vehicles.m_buffer[vehicleId], ref this.m_vehicles.m_buffer[vehicleId].m_frame0);
                this.m_vehicleCount = (int)(this.m_vehicles.ItemCount() - 1u);

                VehicleStateManager.Instance.OnCreateVehicle(vehicleId, ref this.m_vehicles.m_buffer[vehicleId]);                 // NON-STOCK CODE

                return(true);
            }
            vehicleId = 0;
            return(false);
        }
Пример #16
0
        public void CustomCalculateSegmentPosition(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)
        {
            Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData();
            float         sqrVelocity   = lastFrameData.m_velocity.sqrMagnitude;

            // NON-STOCK CODE START
            VehicleStateManager.Instance.UpdateVehiclePosition(vehicleId, ref vehicleData, lastFrameData.m_velocity.magnitude);
            // NON-STOCK CODE END

            NetManager netManager = Singleton <NetManager> .instance;

            netManager.m_lanes.m_buffer[laneID].CalculatePositionAndDirection((float)offset * 0.003921569f, out pos, out dir);
            Vector3 b  = netManager.m_lanes.m_buffer[prevLaneID].CalculatePosition((float)prevOffset * 0.003921569f);
            Vector3 a  = lastFrameData.m_position;
            Vector3 a2 = lastFrameData.m_position;
            Vector3 b2 = lastFrameData.m_rotation * new Vector3(0f, 0f, this.m_info.m_generatedInfo.m_wheelBase * 0.5f);

            a  += b2;
            a2 -= b2;
            float crazyValue = 0.5f * sqrVelocity / this.m_info.m_braking;
            float a3         = Vector3.Distance(a, b);
            float b3         = Vector3.Distance(a2, b);

            if (Mathf.Min(a3, b3) >= crazyValue - 1f)
            {
                Segment3 segment;
                segment.a = pos;
                ushort targetNodeId;
                ushort nextTargetNodeId;
                if (offset < position.m_offset)
                {
                    segment.b        = pos + dir.normalized * this.m_info.m_generatedInfo.m_size.z;
                    targetNodeId     = netManager.m_segments.m_buffer[(int)position.m_segment].m_startNode;
                    nextTargetNodeId = netManager.m_segments.m_buffer[(int)position.m_segment].m_endNode;
                }
                else
                {
                    segment.b        = pos - dir.normalized * this.m_info.m_generatedInfo.m_size.z;
                    targetNodeId     = netManager.m_segments.m_buffer[(int)position.m_segment].m_endNode;
                    nextTargetNodeId = netManager.m_segments.m_buffer[(int)position.m_segment].m_startNode;
                }
                ushort prevTargetNodeId;
                if (prevOffset == 0)
                {
                    prevTargetNodeId = netManager.m_segments.m_buffer[(int)prevPos.m_segment].m_startNode;
                }
                else
                {
                    prevTargetNodeId = netManager.m_segments.m_buffer[(int)prevPos.m_segment].m_endNode;
                }
                if (targetNodeId == prevTargetNodeId)
                {
                    if (!VehicleBehaviorManager.Instance.MayChangeSegment(vehicleId, ref VehicleStateManager.Instance.VehicleStates[vehicleId], ref vehicleData, ref lastFrameData, false, ref prevPos, ref netManager.m_segments.m_buffer[prevPos.m_segment], prevTargetNodeId, prevLaneID, ref position, targetNodeId, ref netManager.m_nodes.m_buffer[targetNodeId], laneID, ref nextPosition, nextTargetNodeId, out maxSpeed))
                    {
                        return;
                    }
                }
            }
            NetInfo info = netManager.m_segments.m_buffer[(int)position.m_segment].Info;

            if (info.m_lanes != null && info.m_lanes.Length > (int)position.m_lane)
            {
                float speedLimit = Options.customSpeedLimitsEnabled ? SpeedLimitManager.Instance.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, info.m_lanes[position.m_lane]) : info.m_lanes[position.m_lane].m_speedLimit;
                maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, speedLimit, netManager.m_lanes.m_buffer[laneID].m_curve);
            }
            else
            {
                maxSpeed = this.CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f);
            }
        }
        /// <summary>
        /// Checks for traffic lights and priority signs when changing segments (for road & rail vehicles).
        /// Sets the maximum allowed speed <paramref name="maxSpeed"/> if segment change is not allowed (otherwise <paramref name="maxSpeed"/> has to be set by the calling method).
        /// </summary>
        /// <param name="vehicleId">vehicle id</param>
        /// <param name="vehicleData">vehicle data</param>
        /// <param name="lastFrameData">last frame data of vehicle</param>
        /// <param name="isRecklessDriver">if true, this vehicle ignores red traffic lights and priority signs</param>
        /// <param name="prevPos">previous path position</param>
        /// <param name="prevTargetNodeId">previous target node</param>
        /// <param name="prevLaneID">previous lane</param>
        /// <param name="position">current path position</param>
        /// <param name="targetNodeId">transit node</param>
        /// <param name="laneID">current lane</param>
        /// <param name="nextPosition">next path position</param>
        /// <param name="nextTargetNodeId">next target node</param>
        /// <param name="maxSpeed">maximum allowed speed (only valid if method returns false)</param>
        /// <returns>true, if the vehicle may change segments, false otherwise.</returns>
        internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData, ref Vehicle.Frame lastFrameData, bool isRecklessDriver, ref PathUnit.Position prevPos, ushort prevTargetNodeId, uint prevLaneID, ref PathUnit.Position position, ushort targetNodeId, uint laneID, ref PathUnit.Position nextPosition, ushort nextTargetNodeId, out float maxSpeed, bool debug = false)
        {
            debug = false;
            if (prevTargetNodeId != targetNodeId)
            {
                // method should only be called if targetNodeId == prevTargetNode
                maxSpeed = 0f;
                return(true);
            }

            bool         forceUpdatePos = false;
            VehicleState vehicleState   = null;

            try {
                vehicleState = VehicleStateManager.GetVehicleState(vehicleId);

                if (vehicleState == null)
                {
                    VehicleStateManager.OnPathFindReady(vehicleId, ref vehicleData);
                    vehicleState = VehicleStateManager.GetVehicleState(vehicleId);

                    if (vehicleState == null)
                    {
#if DEBUG
                        Log._Debug($"Could not get vehicle state of {vehicleId}!");
#endif
                    }
                    else
                    {
                        forceUpdatePos = true;
                    }
                }
            } catch (Exception e) {
                Log.Error("VehicleAI MayChangeSegment vehicle state error: " + e.ToString());
            }

            if (forceUpdatePos || Options.simAccuracy >= 2)
            {
                try {
                    VehicleStateManager.UpdateVehiclePos(vehicleId, ref vehicleData, ref prevPos, ref position);
                } catch (Exception e) {
                    Log.Error("VehicleAI MayChangeSegment Error: " + e.ToString());
                }
            }

            var netManager = Singleton <NetManager> .instance;

            uint currentFrameIndex        = Singleton <SimulationManager> .instance.m_currentFrameIndex;
            uint prevTargetNodeLower8Bits = (uint)((prevTargetNodeId << 8) / 32768);
            uint random = currentFrameIndex - prevTargetNodeLower8Bits & 255u;

            bool isRailVehicle = (vehicleData.Info.m_vehicleType & (VehicleInfo.VehicleType.Train | VehicleInfo.VehicleType.Metro)) != VehicleInfo.VehicleType.None;

            NetNode.Flags targetNodeFlags    = netManager.m_nodes.m_buffer[targetNodeId].m_flags;
            bool          hasTrafficLight    = (targetNodeFlags & NetNode.Flags.TrafficLights) != NetNode.Flags.None;
            bool          checkTrafficLights = false;
            if (!isRailVehicle)
            {
                // check if to check space

#if DEBUG
                if (debug)
                {
                    Log._Debug($"CustomVehicleAI.MayChangeSegment: Vehicle {vehicleId} is not a train.");
                }
#endif

                var  prevLaneFlags    = (NetLane.Flags)netManager.m_lanes.m_buffer[(int)((UIntPtr)prevLaneID)].m_flags;
                var  hasCrossing      = (targetNodeFlags & NetNode.Flags.LevelCrossing) != NetNode.Flags.None;
                var  isJoinedJunction = (prevLaneFlags & NetLane.Flags.JoinedJunction) != NetLane.Flags.None;
                bool checkSpace       = !Flags.getEnterWhenBlockedAllowed(prevPos.m_segment, netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode == targetNodeId) && !isRecklessDriver;
                //TrafficLightSimulation nodeSim = TrafficLightSimulation.GetNodeSimulation(destinationNodeId);
                //if (timedNode != null && timedNode.vehiclesMayEnterBlockedJunctions) {
                //	checkSpace = false;
                //}

                if (checkSpace)
                {
                    // check if there is enough space
                    if ((targetNodeFlags & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) == NetNode.Flags.Junction &&
                        netManager.m_nodes.m_buffer[targetNodeId].CountSegments() != 2)
                    {
                        var len = vehicleData.CalculateTotalLength(vehicleId) + 2f;
                        if (!netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].CheckSpace(len))
                        {
                            var sufficientSpace = false;
                            if (nextPosition.m_segment != 0 && netManager.m_lanes.m_buffer[(int)((UIntPtr)laneID)].m_length < 30f)
                            {
                                NetNode.Flags nextTargetNodeFlags = netManager.m_nodes.m_buffer[nextTargetNodeId].m_flags;
                                if ((nextTargetNodeFlags & (NetNode.Flags.Junction | NetNode.Flags.OneWayOut | NetNode.Flags.OneWayIn)) != NetNode.Flags.Junction ||
                                    netManager.m_nodes.m_buffer[nextTargetNodeId].CountSegments() == 2)
                                {
                                    uint nextLaneId = PathManager.GetLaneID(nextPosition);
                                    if (nextLaneId != 0u)
                                    {
                                        sufficientSpace = netManager.m_lanes.m_buffer[(int)((UIntPtr)nextLaneId)].CheckSpace(len);
                                    }
                                }
                            }
                            if (!sufficientSpace)
                            {
                                maxSpeed = 0f;
                                try {
                                    if (vehicleState != null)
                                    {
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to BLOCKED");
                                        }
#endif

                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Blocked;
                                    }
                                } catch (Exception e) {
                                    Log.Error("VehicleAI MayChangeSegment error while setting junction state to BLOCKED: " + e.ToString());
                                }
                                return(false);
                            }
                        }
                    }
                }

                checkTrafficLights = (!isJoinedJunction || hasCrossing);
            }
            else
            {
#if DEBUG
                if (debug)
                {
                    Log._Debug($"CustomVehicleAI.MayChangeSegment: Vehicle {vehicleId} is a train.");
                }
#endif

                checkTrafficLights = true;
            }

            try {
                if (vehicleState != null && vehicleState.JunctionTransitState == VehicleJunctionTransitState.Blocked)
                {
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState from BLOCKED to ENTER");
                    }
#endif
                    vehicleState.JunctionTransitState = VehicleJunctionTransitState.Enter;
                }

                if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == 0)
                {
                    if (hasTrafficLight && checkTrafficLights)
                    {
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomVehicleAI.MayChangeSegment: Node {targetNodeId} has a traffic light.");
                        }
#endif

                        var destinationInfo = netManager.m_nodes.m_buffer[targetNodeId].Info;

                        if (vehicleState != null && vehicleState.JunctionTransitState == VehicleJunctionTransitState.None)
                        {
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to ENTER (1)");
                            }
#endif
                            vehicleState.JunctionTransitState = VehicleJunctionTransitState.Enter;
                        }

                        RoadBaseAI.TrafficLightState vehicleLightState;
                        RoadBaseAI.TrafficLightState pedestrianLightState;
                        bool vehicles;
                        bool pedestrians;
                        CustomRoadAI.GetTrafficLightState(vehicleId, ref vehicleData, targetNodeId, prevPos.m_segment, prevPos.m_lane, position.m_segment, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - prevTargetNodeLower8Bits, out vehicleLightState, out pedestrianLightState, out vehicles, out pedestrians);

                        if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Car && isRecklessDriver)                           // no reckless driving at railroad crossings
                        {
                            vehicleLightState = RoadBaseAI.TrafficLightState.Green;
                        }

#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomVehicleAI.MayChangeSegment: Vehicle {vehicleId} has {vehicleLightState} at node {targetNodeId}");
                        }
#endif

                        if (!vehicles && random >= 196u)
                        {
                            vehicles = true;
                            RoadBaseAI.SetTrafficLightState(targetNodeId, ref netManager.m_segments.m_buffer[prevPos.m_segment], currentFrameIndex - prevTargetNodeLower8Bits, vehicleLightState, pedestrianLightState, vehicles, pedestrians);
                        }

                        var stopCar = false;
                        switch (vehicleLightState)
                        {
                        case RoadBaseAI.TrafficLightState.RedToGreen:
                            if (random < 60u)
                            {
                                stopCar = true;
                            }
                            else
                            {
#if DEBUG
                                if (debug)
                                {
                                    Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (RedToGreen)");
                                }
#endif
                                if (vehicleState != null)
                                {
                                    vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                }
                            }
                            break;

                        case RoadBaseAI.TrafficLightState.Red:
                            stopCar = true;
                            break;

                        case RoadBaseAI.TrafficLightState.GreenToRed:
                            if (random >= 30u)
                            {
                                stopCar = true;
                            }
                            else if (vehicleState != null)
                            {
#if DEBUG
                                if (debug)
                                {
                                    Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (GreenToRed)");
                                }
#endif
                                vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                            }
                            break;
                        }

                        /*if ((vehicleLightState == RoadBaseAI.TrafficLightState.Green || vehicleLightState == RoadBaseAI.TrafficLightState.RedToGreen) && !Flags.getEnterWhenBlockedAllowed(prevPos.m_segment, netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode == targetNodeId)) {
                         *      var hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, targetNodeId);
                         *
                         *      if (hasIncomingCars) {
                         *              // green light but other cars are incoming and they have priority: stop
                         *              stopCar = true;
                         *      }
                         * }*/

                        if (stopCar)
                        {
                            if (vehicleState != null)
                            {
#if DEBUG
                                if (debug)
                                {
                                    Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP");
                                }
#endif
                                vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop;
                            }
                            maxSpeed = 0f;
                            return(false);
                        }
                    }
                    else if (vehicleState != null)
                    {
#if DEBUG
                        //bool debug = destinationNodeId == 10864;
                        //bool debug = destinationNodeId == 13531;
                        //bool debug = false;// targetNodeId == 5027;
#endif
                        //bool debug = false;
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"Vehicle {vehicleId} is arriving @ seg. {prevPos.m_segment} ({position.m_segment}, {nextPosition.m_segment}), node {targetNodeId} which is not a traffic light.");
                        }
#endif

                        var prioritySegment = TrafficPriority.GetPrioritySegment(targetNodeId, prevPos.m_segment);
                        if (prioritySegment != null)
                        {
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"Vehicle {vehicleId} is arriving @ seg. {prevPos.m_segment} ({position.m_segment}, {nextPosition.m_segment}), node {targetNodeId} which is not a traffic light and is a priority segment.");
                            }
#endif
                            //if (prioritySegment.HasVehicle(vehicleId)) {
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"Vehicle {vehicleId}: segment target position found");
                            }
#endif
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"Vehicle {vehicleId}: global target position found. carState = {vehicleState.JunctionTransitState.ToString()}");
                            }
#endif
                            var   currentFrameIndex2 = Singleton <SimulationManager> .instance.m_currentFrameIndex;
                            var   frame = currentFrameIndex2 >> 4;
                            float speed = lastFrameData.m_velocity.magnitude;

                            if (vehicleState.JunctionTransitState == VehicleJunctionTransitState.None)
                            {
#if DEBUG
                                if (debug)
                                {
                                    Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to ENTER (prio)");
                                }
#endif
                                vehicleState.JunctionTransitState = VehicleJunctionTransitState.Enter;
                            }

                            if (vehicleState.JunctionTransitState != VehicleJunctionTransitState.Leave)
                            {
                                bool hasIncomingCars;
                                switch (prioritySegment.Type)
                                {
                                case SegmentEnd.PriorityType.Stop:
#if DEBUG
                                    if (debug)
                                    {
                                        Log._Debug($"Vehicle {vehicleId}: STOP sign. waittime={vehicleState.WaitTime}, vel={speed}");
                                    }
#endif

                                    if (Options.simAccuracy <= 2 || (Options.simAccuracy >= 3 && vehicleState.WaitTime < MaxPriorityWaitTime))
                                    {
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP (wait)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop;

                                        if (speed <= TrafficPriority.maxStopVelocity)
                                        {
                                            vehicleState.WaitTime++;

                                            float minStopWaitTime = UnityEngine.Random.Range(0f, 3f);
                                            if (vehicleState.WaitTime >= minStopWaitTime)
                                            {
                                                if (Options.simAccuracy >= 4)
                                                {
                                                    vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                                }
                                                else
                                                {
                                                    hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, ref vehicleData, ref prevPos, ref position);
#if DEBUG
                                                    if (debug)
                                                    {
                                                        Log._Debug($"hasIncomingCars: {hasIncomingCars}");
                                                    }
#endif

                                                    if (hasIncomingCars)
                                                    {
                                                        maxSpeed = 0f;
                                                        return(false);
                                                    }
#if DEBUG
                                                    if (debug)
                                                    {
                                                        Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (min wait timeout)");
                                                    }
#endif
                                                    vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                                }
                                            }
                                            else
                                            {
                                                maxSpeed = 0;
                                                return(false);
                                            }
                                        }
                                        else
                                        {
                                            vehicleState.WaitTime = 0;
                                            maxSpeed = 0f;
                                            return(false);
                                        }
                                    }
                                    else
                                    {
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (max wait timeout)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                    }
                                    break;

                                case SegmentEnd.PriorityType.Yield:
#if DEBUG
                                    if (debug)
                                    {
                                        Log._Debug($"Vehicle {vehicleId}: YIELD sign. waittime={vehicleState.WaitTime}");
                                    }
#endif

                                    if (Options.simAccuracy <= 2 || (Options.simAccuracy >= 3 && vehicleState.WaitTime < MaxPriorityWaitTime))
                                    {
                                        vehicleState.WaitTime++;
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP (wait)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop;

                                        if (speed <= TrafficPriority.maxYieldVelocity || Options.simAccuracy <= 2)
                                        {
                                            if (Options.simAccuracy >= 4)
                                            {
                                                vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                            }
                                            else
                                            {
                                                hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, ref vehicleData, ref prevPos, ref position);
#if DEBUG
                                                if (debug)
                                                {
                                                    Log._Debug($"Vehicle {vehicleId}: hasIncomingCars: {hasIncomingCars}");
                                                }
#endif

                                                if (hasIncomingCars)
                                                {
                                                    maxSpeed = 0f;
                                                    return(false);
                                                }
                                                else
                                                {
#if DEBUG
                                                    if (debug)
                                                    {
                                                        Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (no incoming cars)");
                                                    }
#endif
                                                    vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                                }
                                            }
                                        }
                                        else
                                        {
#if DEBUG
                                            if (debug)
                                            {
                                                Log._Debug($"Vehicle {vehicleId}: Vehicle has not yet reached yield speed (reduce {speed} by {vehicleState.ReduceSpeedByValueToYield})");
                                            }
#endif

                                            // vehicle has not yet reached yield speed
                                            maxSpeed = TrafficPriority.maxYieldVelocity;
                                            return(false);
                                        }
                                    }
                                    else
                                    {
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (max wait timeout)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                    }
                                    break;

                                case SegmentEnd.PriorityType.Main:
                                case SegmentEnd.PriorityType.None:
#if DEBUG
                                    if (debug)
                                    {
                                        Log._Debug($"Vehicle {vehicleId}: MAIN sign. waittime={vehicleState.WaitTime}");
                                    }
#endif
                                    maxSpeed = 0f;

                                    if (Options.simAccuracy == 4)
                                    {
                                        return(true);
                                    }

                                    if (Options.simAccuracy <= 2 || (Options.simAccuracy == 3 && vehicleState.WaitTime < MaxPriorityWaitTime))
                                    {
                                        vehicleState.WaitTime++;
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to STOP (wait)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Stop;

                                        hasIncomingCars = TrafficPriority.HasIncomingVehiclesWithHigherPriority(vehicleId, ref vehicleData, ref prevPos, ref position);
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"hasIncomingCars: {hasIncomingCars}");
                                        }
#endif

                                        if (hasIncomingCars)
                                        {
                                            return(false);
                                        }
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState to LEAVE (no conflicting car)");
                                        }
#endif
                                        vehicleState.JunctionTransitState = VehicleJunctionTransitState.Leave;
                                    }
                                    return(true);
                                }
                            }
                            else if (speed <= TrafficPriority.maxStopVelocity)
                            {
                                // vehicle is not moving. reset allowance to leave junction
#if DEBUG
                                if (debug)
                                {
                                    Log._Debug($"Vehicle {vehicleId}: Setting JunctionTransitState from LEAVE to BLOCKED (speed to low)");
                                }
#endif
                                vehicleState.JunctionTransitState = VehicleJunctionTransitState.Blocked;

                                maxSpeed = 0f;
                                return(false);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                Log.Error($"Error occured in MayChangeSegment: {e.ToString()}");
            }
            maxSpeed = 0f;             // maxSpeed should be set by caller
            return(true);
        }
Пример #18
0
        public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics)
        {
            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                if (m_speedData.currentPath != vehicleData.m_path)
                {
                    m_speedData.currentPath = vehicleData.m_path;
                    m_speedData.SetRandomSpeedMultiplier(0.65f, 1.05f);
                }
                m_speedData.ApplySpeedMultiplier(this.m_info);
            }


            if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None)
            {
                vehicleData.m_waitCounter += 1;
                if (this.CanLeave(vehicleID, ref vehicleData))
                {
                    vehicleData.m_flags      &= ~Vehicle.Flags.Stopped;
                    vehicleData.m_flags      |= Vehicle.Flags.Leaving;
                    vehicleData.m_waitCounter = 0;
                }
            }
            CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics);
            if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == Vehicle.Flags.None && this.ShouldReturnToSource(vehicleID, ref vehicleData))
            {
                this.SetTransportLine(vehicleID, ref vehicleData, 0);
            }

            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                m_speedData.RestoreVehicleSpeed(this.m_info);
            }
        }
        public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics)
        {
            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                if (CustomCarAI.sm_speedData[vehicleID].speedMultiplier == 0 || CustomCarAI.sm_speedData[vehicleID].currentPath != vehicleData.m_path)
                {
                    CustomCarAI.sm_speedData[vehicleID].currentPath = vehicleData.m_path;
                    if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.Emergency2)
                    {
                        CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(1f, 1.5f);
                    }
                    else
                    {
                        CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(0.7f, 1.05f);
                    }
                }
                CustomCarAI.sm_speedData[vehicleID].ApplySpeedMultiplier(this.m_info);
            }


            frameData.m_blinkState = (((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.None) ? 0f : 10f);
            CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics);
            if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None && this.CanLeave(vehicleID, ref vehicleData))
            {
                vehicleData.m_flags &= ~Vehicle.Flags.Stopped;
                vehicleData.m_flags |= Vehicle.Flags.Leaving;
            }
            if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == Vehicle.Flags.None && this.ShouldReturnToSource(vehicleID, ref vehicleData))
            {
                this.SetTarget(vehicleID, ref vehicleData, 0);
            }

            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                CustomCarAI.sm_speedData[vehicleID].RestoreVehicleSpeed(this.m_info);
            }
        }
 /// <summary>
 /// Checks for traffic lights and priority signs when changing segments (for rail vehicles).
 /// Sets the maximum allowed speed <paramref name="maxSpeed"/> if segment change is not allowed (otherwise <paramref name="maxSpeed"/> has to be set by the calling method).
 /// </summary>
 /// <param name="vehicleId">vehicle id</param>
 /// <param name="vehicleData">vehicle data</param>
 /// <param name="lastFrameData">last frame data of vehicle</param>
 /// <param name="isRecklessDriver">if true, this vehicle ignores red traffic lights and priority signs</param>
 /// <param name="prevPos">previous path position</param>
 /// <param name="prevTargetNodeId">previous target node</param>
 /// <param name="prevLaneID">previous lane</param>
 /// <param name="position">current path position</param>
 /// <param name="targetNodeId">transit node</param>
 /// <param name="laneID">current lane</param>
 /// <param name="maxSpeed">maximum allowed speed (only valid if method returns false)</param>
 /// <returns>true, if the vehicle may change segments, false otherwise.</returns>
 internal static bool MayChangeSegment(ushort vehicleId, ref Vehicle vehicleData, ref Vehicle.Frame lastFrameData, bool isRecklessDriver, ref PathUnit.Position prevPos, ushort prevTargetNodeId, uint prevLaneID, ref PathUnit.Position position, ushort targetNodeId, uint laneID, out float maxSpeed, bool debug = false)
 {
     return(MayChangeSegment(vehicleId, ref vehicleData, ref lastFrameData, isRecklessDriver, ref prevPos, prevTargetNodeId, prevLaneID, ref position, targetNodeId, laneID, ref DUMMY_POS, 0, out maxSpeed, debug));
 }
Пример #21
0
        private static bool CreateVehicle(VehicleManager vMgr, out ushort vehicle, ref Randomizer r, VehicleInfo info, Vector3 position, TransferManager.TransferReason type, bool transferToSource, bool transferToTarget)
        {
            bool AttemptFlag = false;
            uint ReserveMax = (vMgr.m_vehicles.m_size - 1) - Mod.RESERVEAMOUNT;  //we subtract 1 cause game doesn't use entry 0 for a real vehicle.
            int CurrentVehicleNum = vMgr.m_vehicleCount; //vMgr.m_vehicles.ItemCount(); //found they were never different ~+\- a nanosecond.
            int m_VecCount = vMgr.m_vehicleCount;  //unly
            Mod.timesCV_CalledTotal++; //stat tracking.
            if (CurrentVehicleNum >= ReserveMax && type != TransferManager.TransferReason.Fire && type != TransferManager.TransferReason.Sick
                && type != TransferManager.TransferReason.Garbage && type != TransferManager.TransferReason.Dead
                && type != TransferManager.TransferReason.Crime && type != TransferManager.TransferReason.Bus
                && type != TransferManager.TransferReason.MetroTrain && type != TransferManager.TransferReason.PassengerTrain
                && type != TransferManager.TransferReason.DeadMove && type != TransferManager.TransferReason.CriminalMove
                && type != TransferManager.TransferReason.Taxi && type != TransferManager.TransferReason.GarbageMove
                && type != TransferManager.TransferReason.Tram && type != TransferManager.TransferReason.RoadMaintenance
                && type != TransferManager.TransferReason.Snow && type != TransferManager.TransferReason.SnowMove
                && type != TransferManager.TransferReason.Fire2 && type != TransferManager.TransferReason.ForestFire
                && type != TransferManager.TransferReason.FloodWater && type !=TransferManager.TransferReason.SickMove
                && type != TransferManager.TransferReason.Sick2 && type !=TransferManager.TransferReason.EvacuateVipA
                && type != TransferManager.TransferReason.EvacuateVipB && type != TransferManager.TransferReason.EvacuateVipC
                && type != TransferManager.TransferReason.EvacuateVipD)

            {
                Mod.timesFailedByReserve++; //stat tracking
                Mod.timesFailedToCreate++;  //stat tracking
                vehicle = 0;
                return false;
            }

            if (CurrentVehicleNum >= ReserveMax)
            {
                AttemptFlag = true;
                Mod.timesReservedAttempted++;  //stat tracking.
                if (CurrentVehicleNum == (vMgr.m_vehicles.m_size -1)) { Mod.timesLimitReached++; } //stattracking
                if (Mod.DEBUG_LOG_ON && Mod.DEBUG_LOG_LEVEL >= 3) { Helper.dbgLog(" Vehicles[" + CurrentVehicleNum.ToString() +
                    "] max reached, attempting to use reserve for a " + type.ToString() + " - " + System.DateTime.Now.ToString() +
                    " : " + DateTime.Now.Millisecond.ToString() + " counter=" + Mod.timesReservedAttempted.ToString() + " reservemax=" +
                    ReserveMax.ToString()); }
            }

            //Original Untouched Below except for attemptflag and Mod.timeFailedToCreate Counters and debug logging.
            ushort num;
            if (!vMgr.m_vehicles.CreateItem(out num, ref r))
            {
                vehicle = 0;
                if (AttemptFlag)
                {
                    Mod.timesReserveAttemptFailed++ ; //stat tracking.
                    if (Mod.DEBUG_LOG_ON && Mod.DEBUG_LOG_LEVEL >= 2) {  Helper.dbgLog(" Vehicles[" + CurrentVehicleNum.ToString() +
                        "] max reached, attempted to use reserve for a " + type.ToString() + " but Failed! " + System.DateTime.Now.ToString() + " : " +
                        DateTime.Now.Millisecond.ToString() + " counter=" + Mod.timesReservedAttempted.ToString()); }
                }

                Mod.timesFailedToCreate++;  //stat tracking
                return false;
            }

            vehicle = num;
            Vehicle.Frame frame = new Vehicle.Frame(position, Quaternion.identity);
            vMgr.m_vehicles.m_buffer[vehicle].m_flags = Vehicle.Flags.Created;
            if (transferToSource)
            {
                vMgr.m_vehicles.m_buffer[vehicle].m_flags = vMgr.m_vehicles.m_buffer[vehicle].m_flags | Vehicle.Flags.TransferToSource;
            }
            if (transferToTarget)
            {
                vMgr.m_vehicles.m_buffer[vehicle].m_flags = vMgr.m_vehicles.m_buffer[vehicle].m_flags | Vehicle.Flags.TransferToTarget;
            }
            vMgr.m_vehicles.m_buffer[vehicle].Info = info;
            vMgr.m_vehicles.m_buffer[vehicle].m_frame0 = frame;
            vMgr.m_vehicles.m_buffer[vehicle].m_frame1 = frame;
            vMgr.m_vehicles.m_buffer[vehicle].m_frame2 = frame;
            vMgr.m_vehicles.m_buffer[vehicle].m_frame3 = frame;
            vMgr.m_vehicles.m_buffer[vehicle].m_targetPos0 = Vector4.zero;
            vMgr.m_vehicles.m_buffer[vehicle].m_targetPos1 = Vector4.zero;
            vMgr.m_vehicles.m_buffer[vehicle].m_targetPos2 = Vector4.zero;
            vMgr.m_vehicles.m_buffer[vehicle].m_targetPos3 = Vector4.zero;
            vMgr.m_vehicles.m_buffer[vehicle].m_sourceBuilding = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_targetBuilding = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_transferType = (byte)type;
            vMgr.m_vehicles.m_buffer[vehicle].m_transferSize = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_waitCounter = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_blockCounter = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_nextGridVehicle = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_nextOwnVehicle = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_nextGuestVehicle = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_nextLineVehicle = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_transportLine = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_leadingVehicle = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_trailingVehicle = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_cargoParent = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_firstCargo = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_nextCargo = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_citizenUnits = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_path = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_lastFrame = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_pathPositionIndex = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_lastPathOffset = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_gateIndex = 0;
            vMgr.m_vehicles.m_buffer[vehicle].m_waterSource = 0;
            info.m_vehicleAI.CreateVehicle(vehicle, ref vMgr.m_vehicles.m_buffer[vehicle]);
            info.m_vehicleAI.FrameDataUpdated(vehicle, ref vMgr.m_vehicles.m_buffer[vehicle], ref vMgr.m_vehicles.m_buffer[vehicle].m_frame0);
            vMgr.m_vehicleCount = (int)(vMgr.m_vehicles.ItemCount() - 1);
            return true;
        }
Пример #22
0
        public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics)
        {
            if ((TrafficMod.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                var speedData = CarSpeedData.Of(vehicleID);

                if (speedData.SpeedMultiplier == 0 || speedData.CurrentPath != vehicleData.m_path)
                {
                    speedData.CurrentPath = vehicleData.m_path;
                    if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.Emergency2)
                    {
                        speedData.SetRandomSpeedMultiplier(1f, 1.75f);
                    }
                    else
                    {
                        speedData.SetRandomSpeedMultiplier(0.7f, 1.1f);
                    }
                }
                m_info.ApplySpeedMultiplier(CarSpeedData.Of(vehicleID));
            }

            if (this.m_info.m_class.m_level >= ItemClass.Level.Level4)
            {
                base.SimulationStep(vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics);
                if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != 0 && this.CanLeave(vehicleID, ref vehicleData))
                {
                    vehicleData.m_flags &= ~Vehicle.Flags.Stopped;
                    vehicleData.m_flags |= Vehicle.Flags.Leaving;
                }
                if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == 0 && this.ShouldReturnToSource(vehicleID, ref vehicleData))
                {
                    this.SetTarget(vehicleID, ref vehicleData, 0);
                }
            }
            else
            {
                frameData.m_blinkState = (((vehicleData.m_flags & Vehicle.Flags.Emergency2) == 0) ? 0f : 10f);
                this.TryCollectCrime(vehicleID, ref vehicleData, ref frameData);
                base.SimulationStep(vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics);
                if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != 0)
                {
                    if (this.CanLeave(vehicleID, ref vehicleData))
                    {
                        vehicleData.m_flags &= ~Vehicle.Flags.Stopped;
                        vehicleData.m_flags |= Vehicle.Flags.Leaving;
                    }
                }
                else if ((vehicleData.m_flags & Vehicle.Flags.Arriving) != 0 && vehicleData.m_targetBuilding != 0 && (vehicleData.m_flags & (Vehicle.Flags.Emergency2 | Vehicle.Flags.WaitingPath | Vehicle.Flags.GoingBack | Vehicle.Flags.WaitingTarget)) == 0)
                {
                    this.ArriveAtTarget(vehicleID, ref vehicleData);
                }
                if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == 0 && this.ShouldReturnToSource(vehicleID, ref vehicleData))
                {
                    this.SetTarget(vehicleID, ref vehicleData, 0);
                }
            }

            if ((TrafficMod.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                m_info.RestoreVehicleSpeed(CarSpeedData.Of(vehicleID));
            }
        }
Пример #23
0
        // HACK
        public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID,
                                            ref Vehicle leaderData, int lodPhysics)
        {
            var baseAcceleration = m_info.m_acceleration;

            if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.Emergency2)
            {
                m_info.m_acceleration *= 3;
            }

            base.SimulationStep(vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics);

            m_info.m_acceleration = baseAcceleration;
        }
Пример #24
0
        public void CustomSimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics)
        {
#if DEBUG
            bool debug = GlobalConfig.Instance.Debug.Switches[16] && GlobalConfig.Instance.Debug.NodeId == vehicleID;
#endif

            ushort      leadingVehicle    = vehicleData.m_leadingVehicle;
            uint        currentFrameIndex = Singleton <SimulationManager> .instance.m_currentFrameIndex;
            VehicleInfo leaderInfo;
            if (leaderID != vehicleID)
            {
                leaderInfo = leaderData.Info;
            }
            else
            {
                leaderInfo = this.m_info;
            }
            TramBaseAI tramBaseAI = leaderInfo.m_vehicleAI as TramBaseAI;

            if (leadingVehicle != 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 wheelBaseRot      = frameData.m_rotation * new Vector3(0f, 0f, this.m_info.m_generatedInfo.m_wheelBase * 0.5f);
            Vector3 posAfterWheelRot  = frameData.m_position + wheelBaseRot;
            Vector3 posBeforeWheelRot = frameData.m_position - wheelBaseRot;

            float acceleration = this.m_info.m_acceleration;
            float braking      = this.m_info.m_braking;
            float curSpeed     = frameData.m_velocity.magnitude;

            Vector3 afterRotToTargetPos1Diff       = (Vector3)vehicleData.m_targetPos1 - posAfterWheelRot;
            float   afterRotToTargetPos1DiffSqrMag = afterRotToTargetPos1Diff.sqrMagnitude;

            Quaternion curInvRot    = Quaternion.Inverse(frameData.m_rotation);
            Vector3    curveTangent = curInvRot * frameData.m_velocity;

#if DEBUG
            if (debug)
            {
                Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): ================================================");
                Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): leadingVehicle={leadingVehicle} frameData.m_position={frameData.m_position} frameData.m_swayPosition={frameData.m_swayPosition} wheelBaseRot={wheelBaseRot} posAfterWheelRot={posAfterWheelRot} posBeforeWheelRot={posBeforeWheelRot} acceleration={acceleration} braking={braking} curSpeed={curSpeed} afterRotToTargetPos1Diff={afterRotToTargetPos1Diff} afterRotToTargetPos1DiffSqrMag={afterRotToTargetPos1DiffSqrMag} curInvRot={curInvRot} curveTangent={curveTangent} this.m_info.m_generatedInfo.m_wheelBase={this.m_info.m_generatedInfo.m_wheelBase}");
            }
#endif

            Vector3 forward      = Vector3.forward;
            Vector3 targetMotion = Vector3.zero;
            float   targetSpeed  = 0f;
            float   motionFactor = 0.5f;
            float   turnAngle    = 0f;
            if (leadingVehicle != 0)
            {
                VehicleManager vehMan = Singleton <VehicleManager> .instance;
                Vehicle.Frame  leadingVehLastFrameData = vehMan.m_vehicles.m_buffer[(int)leadingVehicle].GetLastFrameData();
                VehicleInfo    leadingVehInfo          = vehMan.m_vehicles.m_buffer[(int)leadingVehicle].Info;

                float attachOffset;
                if ((vehicleData.m_flags & Vehicle.Flags.Inverted) != (Vehicle.Flags) 0)
                {
                    attachOffset = this.m_info.m_attachOffsetBack - this.m_info.m_generatedInfo.m_size.z * 0.5f;
                }
                else
                {
                    attachOffset = this.m_info.m_attachOffsetFront - this.m_info.m_generatedInfo.m_size.z * 0.5f;
                }

                float leadingAttachOffset;
                if ((vehMan.m_vehicles.m_buffer[(int)leadingVehicle].m_flags & Vehicle.Flags.Inverted) != (Vehicle.Flags) 0)
                {
                    leadingAttachOffset = leadingVehInfo.m_attachOffsetFront - leadingVehInfo.m_generatedInfo.m_size.z * 0.5f;
                }
                else
                {
                    leadingAttachOffset = leadingVehInfo.m_attachOffsetBack - leadingVehInfo.m_generatedInfo.m_size.z * 0.5f;
                }

                Vector3 curPosMinusRotAttachOffset    = frameData.m_position - frameData.m_rotation * new Vector3(0f, 0f, attachOffset);
                Vector3 leadingPosPlusRotAttachOffset = leadingVehLastFrameData.m_position + leadingVehLastFrameData.m_rotation * new Vector3(0f, 0f, leadingAttachOffset);

                wheelBaseRot = leadingVehLastFrameData.m_rotation * new Vector3(0f, 0f, leadingVehInfo.m_generatedInfo.m_wheelBase * 0.5f);
                Vector3 leadingPosBeforeWheelRot = leadingVehLastFrameData.m_position - wheelBaseRot;

                if (Vector3.Dot(vehicleData.m_targetPos1 - vehicleData.m_targetPos0, (Vector3)vehicleData.m_targetPos0 - posBeforeWheelRot) < 0f && vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == (Vehicle.Flags) 0)
                {
                    int someIndex = -1;
                    InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, vehicleData.m_targetPos0, posBeforeWheelRot, 0, ref leaderData, ref someIndex, 0, 0, Vector3.SqrMagnitude(posBeforeWheelRot - (Vector3)vehicleData.m_targetPos0) + 1f, 1f);
                    afterRotToTargetPos1DiffSqrMag = 0f;
                }

                float attachRotDist = Mathf.Max(Vector3.Distance(curPosMinusRotAttachOffset, leadingPosPlusRotAttachOffset), 2f);

                float one = 1f;
                float attachRotSqrDist = attachRotDist * attachRotDist;
                float oneSqr           = one * one;
                int   i = 0;
                if (afterRotToTargetPos1DiffSqrMag < attachRotSqrDist)
                {
                    if (vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == (Vehicle.Flags) 0)
                    {
                        InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, posBeforeWheelRot, posAfterWheelRot, 0, ref leaderData, ref i, 1, 2, attachRotSqrDist, oneSqr);
                    }
                    while (i < 4)
                    {
                        vehicleData.SetTargetPos(i, vehicleData.GetTargetPos(i - 1));
                        i++;
                    }
                    afterRotToTargetPos1Diff       = (Vector3)vehicleData.m_targetPos1 - posAfterWheelRot;
                    afterRotToTargetPos1DiffSqrMag = afterRotToTargetPos1Diff.sqrMagnitude;
                }
                afterRotToTargetPos1Diff = curInvRot * afterRotToTargetPos1Diff;

                float negTotalAttachLen = -((this.m_info.m_generatedInfo.m_wheelBase + leadingVehInfo.m_generatedInfo.m_wheelBase) * 0.5f + attachOffset + leadingAttachOffset);
                bool  hasPath           = false;
                if (vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == (Vehicle.Flags) 0)
                {
                    float u1;
                    float u2;
                    if (Line3.Intersect(posAfterWheelRot, vehicleData.m_targetPos1, leadingPosBeforeWheelRot, negTotalAttachLen, out u1, out u2))
                    {
                        targetMotion = afterRotToTargetPos1Diff * Mathf.Clamp(Mathf.Min(u1, u2) / 0.6f, 0f, 2f);
                    }
                    else
                    {
                        Line3.DistanceSqr(posAfterWheelRot, vehicleData.m_targetPos1, leadingPosBeforeWheelRot, out u1);
                        targetMotion = afterRotToTargetPos1Diff * Mathf.Clamp(u1 / 0.6f, 0f, 2f);
                    }
                    hasPath = true;
                }

                if (hasPath)
                {
                    if (Vector3.Dot(leadingPosBeforeWheelRot - posAfterWheelRot, posAfterWheelRot - posBeforeWheelRot) < 0f)
                    {
                        motionFactor = 0f;
                    }
                }
                else
                {
                    float leadingPosBeforeToAfterWheelRotDist = Vector3.Distance(leadingPosBeforeWheelRot, posAfterWheelRot);
                    motionFactor = 0f;
                    targetMotion = curInvRot * ((leadingPosBeforeWheelRot - posAfterWheelRot) * (Mathf.Max(0f, leadingPosBeforeToAfterWheelRotDist - negTotalAttachLen) / Mathf.Max(1f, leadingPosBeforeToAfterWheelRotDist * 0.6f)));
                }
            }
            else
            {
                float estimatedFrameDist = (curSpeed + acceleration) * (0.5f + 0.5f * (curSpeed + acceleration) / braking) + (this.m_info.m_generatedInfo.m_size.z - this.m_info.m_generatedInfo.m_wheelBase) * 0.5f;
                float maxSpeedAdd        = Mathf.Max(curSpeed + acceleration, 2f);
                float meanSpeedAdd       = Mathf.Max((estimatedFrameDist - maxSpeedAdd) / 2f, 2f);
                float maxSpeedAddSqr     = maxSpeedAdd * maxSpeedAdd;
                float meanSpeedAddSqr    = meanSpeedAdd * meanSpeedAdd;
                if (Vector3.Dot(vehicleData.m_targetPos1 - vehicleData.m_targetPos0, (Vector3)vehicleData.m_targetPos0 - posBeforeWheelRot) < 0f && vehicleData.m_path != 0u && (leaderData.m_flags & (Vehicle.Flags.WaitingPath | Vehicle.Flags.Stopped)) == (Vehicle.Flags) 0)
                {
                    int someIndex = -1;
                    InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, vehicleData.m_targetPos0, posBeforeWheelRot, leaderID, ref leaderData, ref someIndex, 0, 0, Vector3.SqrMagnitude(posBeforeWheelRot - (Vector3)vehicleData.m_targetPos0) + 1f, 1f);
                    afterRotToTargetPos1DiffSqrMag = 0f;
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): dot < 0");
                    }
#endif
                }

#if DEBUG
                if (debug)
                {
                    Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Leading vehicle is 0. vehicleData.m_targetPos0={vehicleData.m_targetPos0} vehicleData.m_targetPos1={vehicleData.m_targetPos1} posBeforeWheelRot={posBeforeWheelRot} posBeforeWheelRot={posAfterWheelRot} estimatedFrameDist={estimatedFrameDist} maxSpeedAdd={maxSpeedAdd} meanSpeedAdd={meanSpeedAdd} maxSpeedAddSqr={maxSpeedAddSqr} meanSpeedAddSqr={meanSpeedAddSqr} afterRotToTargetPos1DiffSqrMag={afterRotToTargetPos1DiffSqrMag}");
                }
#endif

                int  posIndex = 0;
                bool hasValidPathTargetPos = false;
                if ((afterRotToTargetPos1DiffSqrMag < maxSpeedAddSqr || vehicleData.m_targetPos3.w < 0.01f) && (leaderData.m_flags & (Vehicle.Flags.WaitingPath | Vehicle.Flags.Stopped)) == (Vehicle.Flags) 0)
                {
                    if (vehicleData.m_path != 0u)
                    {
                        InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, posBeforeWheelRot, posAfterWheelRot, leaderID, ref leaderData, ref posIndex, 1, 4, maxSpeedAddSqr, meanSpeedAddSqr);
                    }
                    if (posIndex < 4)
                    {
                        hasValidPathTargetPos = true;
                        while (posIndex < 4)
                        {
                            vehicleData.SetTargetPos(posIndex, vehicleData.GetTargetPos(posIndex - 1));
                            posIndex++;
                        }
                    }
                    afterRotToTargetPos1Diff       = (Vector3)vehicleData.m_targetPos1 - posAfterWheelRot;
                    afterRotToTargetPos1DiffSqrMag = afterRotToTargetPos1Diff.sqrMagnitude;
                }

#if DEBUG
                if (debug)
                {
                    Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): posIndex={posIndex} hasValidPathTargetPos={hasValidPathTargetPos}");
                }
#endif

                if (leaderData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == (Vehicle.Flags) 0)
                {
                    NetManager netMan               = Singleton <NetManager> .instance;
                    byte       leaderPathPosIndex   = leaderData.m_pathPositionIndex;
                    byte       leaderLastPathOffset = leaderData.m_lastPathOffset;
                    if (leaderPathPosIndex == 255)
                    {
                        leaderPathPosIndex = 0;
                    }
                    float leaderLen = 1f + leaderData.CalculateTotalLength(leaderID);

#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): leaderPathPosIndex={leaderPathPosIndex} leaderLastPathOffset={leaderLastPathOffset} leaderPathPosIndex={leaderPathPosIndex} leaderLen={leaderLen}");
                    }
#endif

                    // reserve space / add traffic
                    PathManager       pathMan = Singleton <PathManager> .instance;
                    PathUnit.Position pathPos;
                    if (pathMan.m_pathUnits.m_buffer[leaderData.m_path].GetPosition(leaderPathPosIndex >> 1, out pathPos))
                    {
                        netMan.m_segments.m_buffer[(int)pathPos.m_segment].AddTraffic(Mathf.RoundToInt(leaderLen * 2.5f));
                        bool reservedSpaceOnCurrentLane = false;
                        if ((leaderPathPosIndex & 1) == 0 || leaderLastPathOffset == 0)
                        {
                            uint laneId = PathManager.GetLaneID(pathPos);
                            if (laneId != 0u)
                            {
                                Vector3 curPathOffsetPos = netMan.m_lanes.m_buffer[laneId].CalculatePosition((float)pathPos.m_offset * 0.003921569f);
                                float   speedAdd         = 0.5f * curSpeed * curSpeed / this.m_info.m_braking;
                                float   afterWheelRotCurPathOffsetDist  = Vector3.Distance(posAfterWheelRot, curPathOffsetPos);
                                float   beforeWheelRotCurPathOffsetDist = Vector3.Distance(posBeforeWheelRot, curPathOffsetPos);
                                if (Mathf.Min(afterWheelRotCurPathOffsetDist, beforeWheelRotCurPathOffsetDist) >= speedAdd - 1f)
                                {
                                    netMan.m_lanes.m_buffer[laneId].ReserveSpace(leaderLen);
                                    reservedSpaceOnCurrentLane = true;
                                }
                            }
                        }

                        if (!reservedSpaceOnCurrentLane && pathMan.m_pathUnits.m_buffer[leaderData.m_path].GetNextPosition(leaderPathPosIndex >> 1, out pathPos))
                        {
                            uint nextLaneId = PathManager.GetLaneID(pathPos);
                            if (nextLaneId != 0u)
                            {
                                netMan.m_lanes.m_buffer[nextLaneId].ReserveSpace(leaderLen);
                            }
                        }
                    }

                    if ((ulong)(currentFrameIndex >> 4 & 15u) == (ulong)((long)(leaderID & 15)))
                    {
                        // check if vehicle can proceed to next path position

                        bool canProceeed           = false;
                        uint curLeaderPathId       = leaderData.m_path;
                        int  curLeaderPathPosIndex = leaderPathPosIndex >> 1;
                        int  k = 0;
                        while (k < 5)
                        {
                            bool invalidPos;
                            if (PathUnit.GetNextPosition(ref curLeaderPathId, ref curLeaderPathPosIndex, out pathPos, out invalidPos))
                            {
                                uint laneId = PathManager.GetLaneID(pathPos);
                                if (laneId != 0u && !netMan.m_lanes.m_buffer[laneId].CheckSpace(leaderLen))
                                {
                                    k++;
                                    continue;
                                }
                            }
                            if (invalidPos)
                            {
                                this.InvalidPath(vehicleID, ref vehicleData, leaderID, ref leaderData);
                            }
                            canProceeed = true;
                            break;
                        }
                        if (!canProceeed)
                        {
                            leaderData.m_flags |= Vehicle.Flags.Congestion;
                        }
                    }
                }

                float maxSpeed;
                if ((leaderData.m_flags & Vehicle.Flags.Stopped) != (Vehicle.Flags) 0)
                {
                    maxSpeed = 0f;
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Vehicle is stopped. maxSpeed={maxSpeed}");
                    }
#endif
                }
                else
                {
                    maxSpeed = Mathf.Min(vehicleData.m_targetPos1.w, GetMaxSpeed(leaderID, ref leaderData));
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Vehicle is not stopped. maxSpeed={maxSpeed}");
                    }
#endif
                }

#if DEBUG
                if (debug)
                {
                    Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Start of second part. curSpeed={curSpeed} curInvRot={curInvRot}");
                }
#endif

                afterRotToTargetPos1Diff = curInvRot * afterRotToTargetPos1Diff;
#if DEBUG
                if (debug)
                {
                    Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): afterRotToTargetPos1Diff={afterRotToTargetPos1Diff} (old afterRotToTargetPos1DiffSqrMag={afterRotToTargetPos1DiffSqrMag})");
                }
#endif
                Vector3 zero       = Vector3.zero;
                bool    blocked    = false;
                float   forwardLen = 0f;
                if (afterRotToTargetPos1DiffSqrMag > 1f)                   // TODO why is this not recalculated?
                {
                    forward = VectorUtils.NormalizeXZ(afterRotToTargetPos1Diff, out forwardLen);
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): afterRotToTargetPos1DiffSqrMag > 1f. forward={forward} forwardLen={forwardLen}");
                    }
#endif
                    if (forwardLen > 1f)
                    {
                        Vector3 fwd = afterRotToTargetPos1Diff;
                        maxSpeedAdd    = Mathf.Max(curSpeed, 2f);
                        maxSpeedAddSqr = maxSpeedAdd * maxSpeedAdd;
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): forwardLen > 1f. fwd={fwd} maxSpeedAdd={maxSpeedAdd} maxSpeedAddSqr={maxSpeedAddSqr}");
                        }
#endif
                        if (afterRotToTargetPos1DiffSqrMag > maxSpeedAddSqr)
                        {
                            float fwdLimiter = maxSpeedAdd / Mathf.Sqrt(afterRotToTargetPos1DiffSqrMag);
                            fwd.x *= fwdLimiter;
                            fwd.y *= fwdLimiter;

#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): afterRotToTargetPos1DiffSqrMag > maxSpeedAddSqr. afterRotToTargetPos1DiffSqrMag={afterRotToTargetPos1DiffSqrMag} maxSpeedAddSqr={maxSpeedAddSqr} fwdLimiter={fwdLimiter} fwd={fwd}");
                            }
#endif
                        }

                        if (fwd.z < -1f)                           // !!!
                        {
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): fwd.z < -1f. fwd={fwd}");
                            }
#endif

                            if (vehicleData.m_path != 0u && (leaderData.m_flags & Vehicle.Flags.WaitingPath) == (Vehicle.Flags) 0)
                            {
                                Vector3 targetPos0TargetPos1Diff = vehicleData.m_targetPos1 - vehicleData.m_targetPos0;
                                if ((curInvRot * targetPos0TargetPos1Diff).z < -0.01f)                                   // !!!
                                {
#if DEBUG
                                    if (debug)
                                    {
                                        Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): (curInvRot * targetPos0TargetPos1Diff).z < -0.01f. curInvRot={curInvRot} targetPos0TargetPos1Diff={targetPos0TargetPos1Diff}");
                                    }
#endif
                                    if (afterRotToTargetPos1Diff.z < Mathf.Abs(afterRotToTargetPos1Diff.x) * -10f)                                       // !!!
                                    {
#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): afterRotToTargetPos1Diff.z < Mathf.Abs(afterRotToTargetPos1Diff.x) * -10f. fwd={fwd} targetPos0TargetPos1Diff={targetPos0TargetPos1Diff} afterRotToTargetPos1Diff={afterRotToTargetPos1Diff}");
                                        }
#endif

                                        /*fwd.z = 0f;
                                         * afterRotToTargetPos1Diff = Vector3.zero;*/
                                        maxSpeed = 0.5f;                                         // NON-STOCK CODE

#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): (1) set maxSpeed={maxSpeed}");
                                        }
#endif
                                    }
                                    else
                                    {
                                        posAfterWheelRot = posBeforeWheelRot + Vector3.Normalize(vehicleData.m_targetPos1 - vehicleData.m_targetPos0) * this.m_info.m_generatedInfo.m_wheelBase;
                                        posIndex         = -1;
                                        InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, vehicleData.m_targetPos0, vehicleData.m_targetPos1, leaderID, ref leaderData, ref posIndex, 0, 0, Vector3.SqrMagnitude(vehicleData.m_targetPos1 - vehicleData.m_targetPos0) + 1f, 1f);

#if DEBUG
                                        if (debug)
                                        {
                                            Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): afterRotToTargetPos1Diff.z >= Mathf.Abs(afterRotToTargetPos1Diff.x) * -10f. Invoked UpdatePathTargetPositions. posAfterWheelRot={posAfterWheelRot} posBeforeWheelRot={posBeforeWheelRot} this.m_info.m_generatedInfo.m_wheelBase={this.m_info.m_generatedInfo.m_wheelBase}");
                                        }
#endif
                                    }
                                }
                                else
                                {
                                    posIndex = -1;
                                    InvokeUpdatePathTargetPositions(tramBaseAI, vehicleID, ref vehicleData, vehicleData.m_targetPos0, posBeforeWheelRot, leaderID, ref leaderData, ref posIndex, 0, 0, Vector3.SqrMagnitude(posBeforeWheelRot - (Vector3)vehicleData.m_targetPos0) + 1f, 1f);
                                    vehicleData.m_targetPos1 = posAfterWheelRot;
                                    fwd.z = 0f;
                                    afterRotToTargetPos1Diff = Vector3.zero;
                                    maxSpeed = 0f;

#if DEBUG
                                    if (debug)
                                    {
                                        Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Vehicle is waiting for a path. posIndex={posIndex} vehicleData.m_targetPos1={vehicleData.m_targetPos1} fwd={fwd} afterRotToTargetPos1Diff={afterRotToTargetPos1Diff} maxSpeed={maxSpeed}");
                                    }
#endif
                                }
                            }
                            motionFactor = 0f;
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Reset motion factor. motionFactor={motionFactor}");
                            }
#endif
                        }

                        forward = VectorUtils.NormalizeXZ(fwd, out forwardLen);
                        float curve = Mathf.PI / 2f /* 1.57079637f*/ * (1f - forward.z);                       // <- constant: a bit inaccurate PI/2
                        if (forwardLen > 1f)
                        {
                            curve /= forwardLen;
                        }
                        float targetDist = forwardLen;
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): targetDist={targetDist} fwd={fwd} curve={curve} maxSpeed={maxSpeed}");
                        }
#endif

                        if (vehicleData.m_targetPos1.w < 0.1f)
                        {
                            maxSpeed = this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1000f, curve);
                            maxSpeed = Mathf.Min(maxSpeed, CalculateMaxSpeed(targetDist, vehicleData.m_targetPos1.w, braking * 0.9f));
                        }
                        else
                        {
                            maxSpeed = Mathf.Min(maxSpeed, this.CalculateTargetSpeed(vehicleID, ref vehicleData, 1000f, curve));
                        }
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): [1] maxSpeed={maxSpeed}");
                        }
#endif
                        maxSpeed = Mathf.Min(maxSpeed, CalculateMaxSpeed(targetDist, vehicleData.m_targetPos2.w, braking * 0.9f));
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): [2] maxSpeed={maxSpeed}");
                        }
#endif
                        targetDist += VectorUtils.LengthXZ(vehicleData.m_targetPos2 - vehicleData.m_targetPos1);
                        maxSpeed    = Mathf.Min(maxSpeed, CalculateMaxSpeed(targetDist, vehicleData.m_targetPos3.w, braking * 0.9f));
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): [3] maxSpeed={maxSpeed}");
                        }
#endif
                        targetDist += VectorUtils.LengthXZ(vehicleData.m_targetPos3 - vehicleData.m_targetPos2);
                        if (vehicleData.m_targetPos3.w < 0.01f)
                        {
                            targetDist = Mathf.Max(0f, targetDist + (this.m_info.m_generatedInfo.m_wheelBase - this.m_info.m_generatedInfo.m_size.z) * 0.5f);
                        }
                        maxSpeed = Mathf.Min(maxSpeed, CalculateMaxSpeed(targetDist, 0f, braking * 0.9f));
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): [4] maxSpeed={maxSpeed}");
                        }
#endif
                        CarAI.CheckOtherVehicles(vehicleID, ref vehicleData, ref frameData, ref maxSpeed, ref blocked, ref zero, estimatedFrameDist, braking * 0.9f, lodPhysics);
#if DEBUG
                        if (debug)
                        {
                            Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): CheckOtherVehicles finished. blocked={blocked}");
                        }
#endif
                        if (maxSpeed < curSpeed)
                        {
                            float brake = Mathf.Max(acceleration, Mathf.Min(braking, curSpeed));
                            targetSpeed = Mathf.Max(maxSpeed, curSpeed - brake);
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): maxSpeed < curSpeed. maxSpeed={maxSpeed} curSpeed={curSpeed} brake={brake} targetSpeed={targetSpeed}");
                            }
#endif
                        }
                        else
                        {
                            float accel = Mathf.Max(acceleration, Mathf.Min(braking, -curSpeed));
                            targetSpeed = Mathf.Min(maxSpeed, curSpeed + accel);
#if DEBUG
                            if (debug)
                            {
                                Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): maxSpeed >= curSpeed. maxSpeed={maxSpeed} curSpeed={curSpeed} accel={accel} targetSpeed={targetSpeed}");
                            }
#endif
                        }
                    }
                }
                else if (curSpeed < 0.1f && hasValidPathTargetPos && leaderInfo.m_vehicleAI.ArriveAtDestination(leaderID, ref leaderData))
                {
                    leaderData.Unspawn(leaderID);
                    return;
                }
                if ((leaderData.m_flags & Vehicle.Flags.Stopped) == (Vehicle.Flags) 0 && maxSpeed < 0.1f)
                {
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomTramBaseAI.SimulationStep({vehicleID}): Vehicle is not stopped but maxSpeed < 0.1. maxSpeed={maxSpeed}");
                    }
#endif
                    blocked = true;
                }
                if (blocked)
                {
                    leaderData.m_blockCounter = (byte)Mathf.Min((int)(leaderData.m_blockCounter + 1), 255);
                }
                else
                {
                    leaderData.m_blockCounter = 0;
                }
                if (forwardLen > 1f)
                {
                    turnAngle    = Mathf.Asin(forward.x) * Mathf.Sign(targetSpeed);
                    targetMotion = forward * targetSpeed;
                }
                else
                {
                    Vector3 vel = Vector3.ClampMagnitude(afterRotToTargetPos1Diff * 0.5f - curveTangent, braking);
                    targetMotion = curveTangent + vel;
                }
            }
            bool    mayBlink = (currentFrameIndex + (uint)leaderID & 16u) != 0u;
            Vector3 springs  = targetMotion - curveTangent;
            Vector3 targetAfterWheelRotMotion  = frameData.m_rotation * targetMotion;
            Vector3 targetBeforeWheelRotMotion = Vector3.Normalize((Vector3)vehicleData.m_targetPos0 - posBeforeWheelRot) * (targetMotion.magnitude * motionFactor);
            targetBeforeWheelRotMotion -= targetAfterWheelRotMotion * (Vector3.Dot(targetAfterWheelRotMotion, targetBeforeWheelRotMotion) / Mathf.Max(1f, targetAfterWheelRotMotion.sqrMagnitude));
            posAfterWheelRot           += targetAfterWheelRotMotion;
            posBeforeWheelRot          += targetBeforeWheelRotMotion;
            frameData.m_rotation        = Quaternion.LookRotation(posAfterWheelRot - posBeforeWheelRot);
            Vector3 targetPos = posAfterWheelRot - frameData.m_rotation * new Vector3(0f, 0f, this.m_info.m_generatedInfo.m_wheelBase * 0.5f);
            frameData.m_velocity = targetPos - frameData.m_position;
            if (leadingVehicle != 0)
            {
                frameData.m_position += frameData.m_velocity * 0.6f;
            }
            else
            {
                frameData.m_position += frameData.m_velocity * 0.5f;
            }
            frameData.m_swayVelocity    = frameData.m_swayVelocity * (1f - this.m_info.m_dampers) - springs * (1f - this.m_info.m_springs) - frameData.m_swayPosition * this.m_info.m_springs;
            frameData.m_swayPosition   += frameData.m_swayVelocity * 0.5f;
            frameData.m_steerAngle      = 0f;
            frameData.m_travelDistance += targetMotion.z;
            if (leadingVehicle != 0)
            {
                frameData.m_lightIntensity = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[(int)leaderID].GetLastFrameData().m_lightIntensity;
            }
            else
            {
                frameData.m_lightIntensity.x = 5f;
                frameData.m_lightIntensity.y = ((springs.z >= -0.1f) ? 0.5f : 5f);
                frameData.m_lightIntensity.z = ((turnAngle >= -0.1f || !mayBlink) ? 0f : 5f);
                frameData.m_lightIntensity.w = ((turnAngle <= 0.1f || !mayBlink) ? 0f : 5f);
            }
            frameData.m_underground = ((vehicleData.m_flags & Vehicle.Flags.Underground) != (Vehicle.Flags) 0);
            frameData.m_transition  = ((vehicleData.m_flags & Vehicle.Flags.Transition) != (Vehicle.Flags) 0);
            //base.SimulationStep(vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics);
        }
        public void CustomCalculateSegmentPosition(ushort vehicleId, ref Vehicle vehicleData, PathUnit.Position nextPosition,
                                                   PathUnit.Position prevPosition, uint prevLaneId, byte prevOffset, PathUnit.Position refPosition, uint refLaneId,
                                                   byte refOffset, int index, out Vector3 pos, out Vector3 dir, out float maxSpeed)
        {
            var netManager = Singleton <NetManager> .instance;
            ushort prevSourceNodeId;
            ushort prevTargetNodeId;

            if (prevOffset < prevPosition.m_offset)
            {
                prevSourceNodeId = netManager.m_segments.m_buffer[prevPosition.m_segment].m_startNode;
                prevTargetNodeId = netManager.m_segments.m_buffer[prevPosition.m_segment].m_endNode;
            }
            else
            {
                prevSourceNodeId = netManager.m_segments.m_buffer[prevPosition.m_segment].m_endNode;
                prevTargetNodeId = netManager.m_segments.m_buffer[prevPosition.m_segment].m_startNode;
            }

            ushort refTargetNodeId;

            if (refOffset == 0)
            {
                refTargetNodeId = netManager.m_segments.m_buffer[(int)refPosition.m_segment].m_startNode;
            }
            else
            {
                refTargetNodeId = netManager.m_segments.m_buffer[(int)refPosition.m_segment].m_endNode;
            }

#if DEBUG
            bool debug = GlobalConfig.Instance.Debug.Switches[21] && (GlobalConfig.Instance.Debug.NodeId <= 0 || refTargetNodeId == GlobalConfig.Instance.Debug.NodeId) && (GlobalConfig.Instance.Debug.ExtVehicleType == ExtVehicleType.None || GlobalConfig.Instance.Debug.ExtVehicleType == ExtVehicleType.RoadVehicle) && (GlobalConfig.Instance.Debug.VehicleId == 0 || GlobalConfig.Instance.Debug.VehicleId == vehicleId);

            if (debug)
            {
                Log._Debug($"CustomCarAI.CustomCalculateSegmentPosition({vehicleId}) called.\n" +
                           $"\trefPosition.m_segment={refPosition.m_segment}, refPosition.m_offset={refPosition.m_offset}\n" +
                           $"\tprevPosition.m_segment={prevPosition.m_segment}, prevPosition.m_offset={prevPosition.m_offset}\n" +
                           $"\tnextPosition.m_segment={nextPosition.m_segment}, nextPosition.m_offset={nextPosition.m_offset}\n" +
                           $"\trefLaneId={refLaneId}, refOffset={refOffset}\n" +
                           $"\tprevLaneId={prevLaneId}, prevOffset={prevOffset}\n" +
                           $"\tprevSourceNodeId={prevSourceNodeId}, prevTargetNodeId={prevTargetNodeId}\n" +
                           $"\trefTargetNodeId={refTargetNodeId}, refTargetNodeId={refTargetNodeId}\n" +
                           $"\tindex={index}");
            }
#endif

            Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData();
            Vector3 lastFrameVehiclePos = lastFrameData.m_position;
            float sqrVelocity           = lastFrameData.m_velocity.sqrMagnitude;

            netManager.m_lanes.m_buffer[prevLaneId].CalculatePositionAndDirection(prevOffset * 0.003921569f, out pos, out dir);

            float braking = this.m_info.m_braking;
            if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) != (Vehicle.Flags) 0)
            {
                braking *= 2f;
            }

            // car position on the Bezier curve of the lane
            var refVehiclePosOnBezier = netManager.m_lanes.m_buffer[refLaneId].CalculatePosition(refOffset * 0.003921569f);
            //ushort currentSegmentId = netManager.m_lanes.m_buffer[prevLaneID].m_segment;

            // this seems to be like the required braking force in order to stop the vehicle within its half length.
            var crazyValue             = 0.5f * sqrVelocity / braking + m_info.m_generatedInfo.m_size.z * 0.5f;
            bool withinBrakingDistance = Vector3.Distance(lastFrameVehiclePos, refVehiclePosOnBezier) >= crazyValue - 1f;

            if (prevSourceNodeId == refTargetNodeId && withinBrakingDistance)
            {
                // NON-STOCK CODE START (stock code replaced)
#if BENCHMARK
                using (var bm = new Benchmark(null, "MayChangeSegment")) {
#endif
                //bool isRecklessDriver = VehicleStateManager.Instance.IsRecklessDriver(vehicleId, ref vehicleData); // NON-STOCK CODE

                if (!VehicleBehaviorManager.Instance.MayChangeSegment(vehicleId, ref vehicleData, sqrVelocity, ref refPosition, ref netManager.m_segments.m_buffer[refPosition.m_segment], refTargetNodeId, refLaneId, ref prevPosition, prevSourceNodeId, ref netManager.m_nodes.m_buffer[prevSourceNodeId], prevLaneId, ref nextPosition, prevTargetNodeId, out maxSpeed))                   // NON-STOCK CODE
                {
                    return;
                }
                else
                {
#if BENCHMARK
                    using (var bm = new Benchmark(null, "UpdateVehiclePosition")) {
#endif
                    VehicleStateManager.Instance.UpdateVehiclePosition(vehicleId, ref vehicleData /*, lastFrameData.m_velocity.magnitude*/);
#if BENCHMARK
                }
#endif
                }
#if BENCHMARK
            }
#endif
                // NON-STOCK CODE END
            }

            var segmentInfo = netManager.m_segments.m_buffer[prevPosition.m_segment].Info;
            if (segmentInfo.m_lanes != null && segmentInfo.m_lanes.Length > prevPosition.m_lane)
            {
                // NON-STOCK CODE START
                float laneSpeedLimit = 1f;

                if (!Options.customSpeedLimitsEnabled)
                {
                    laneSpeedLimit = segmentInfo.m_lanes[prevPosition.m_lane].m_speedLimit;
                }
                else
                {
                    laneSpeedLimit = Constants.ManagerFactory.SpeedLimitManager.GetLockFreeGameSpeedLimit(prevPosition.m_segment, prevPosition.m_lane, prevLaneId, segmentInfo.m_lanes[prevPosition.m_lane]);
                }

                // NON-STOCK CODE END
                maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[prevLaneId].m_curve);
            }
            else
            {
                maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f);
            }

            // NON-STOCK CODE START (stock code replaced)
            maxSpeed = Constants.ManagerFactory.VehicleBehaviorManager.CalcMaxSpeed(vehicleId, ref vehicleData, this.m_info, prevPosition, ref netManager.m_segments.m_buffer[prevPosition.m_segment], pos, maxSpeed);
            // NON-STOCK CODE END
        }
Пример #26
0
        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)));
                }
            }
Пример #27
0
        public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics)
        {
            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                if (CustomCarAI.sm_speedData[vehicleID].speedMultiplier == 0 || CustomCarAI.sm_speedData[vehicleID].currentPath != vehicleData.m_path)
                {
                    CustomCarAI.sm_speedData[vehicleID].currentPath = vehicleData.m_path;
                    if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) == Vehicle.Flags.Emergency2)
                    {
                        CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(1f, 1.75f);
                    }
                    else
                    {
                        CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(0.65f, 1f);
                    }
                }
                CustomCarAI.sm_speedData[vehicleID].ApplySpeedMultiplier(this.m_info);
            }


            frameData.m_blinkState = (((vehicleData.m_flags & (Vehicle.Flags.Emergency1 | Vehicle.Flags.Emergency2)) == Vehicle.Flags.None) ? 0f : 10f);
            CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics);
            bool flag = false;

            if (vehicleData.m_targetBuilding != 0)
            {
                BuildingManager instance = Singleton <BuildingManager> .instance;
                Vector3         a        = instance.m_buildings.m_buffer[(int)vehicleData.m_targetBuilding].CalculateSidewalkPosition();
                flag = ((a - frameData.m_position).sqrMagnitude < 4096f);
                bool flag2 = (vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None || frameData.m_velocity.sqrMagnitude < 0.0100000007f;
                if (flag && (vehicleData.m_flags & Vehicle.Flags.Emergency2) != Vehicle.Flags.None)
                {
                    vehicleData.m_flags = ((vehicleData.m_flags & ~Vehicle.Flags.Emergency2) | Vehicle.Flags.Emergency1);
                }
                if (flag && flag2)
                {
                    if (vehicleData.m_blockCounter > 8)
                    {
                        vehicleData.m_blockCounter = 8;
                    }
                    if (vehicleData.m_blockCounter == 8 && (vehicleData.m_flags & Vehicle.Flags.Stopped) == Vehicle.Flags.None)
                    {
                        this.ArriveAtTarget(leaderID, ref leaderData);
                    }
                    if (this.ExtinguishFire(vehicleID, ref vehicleData, vehicleData.m_targetBuilding, ref Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)vehicleData.m_targetBuilding]))
                    {
                        this.SetTarget(vehicleID, ref vehicleData, 0);
                    }
                }
                else
                {
                    if (instance.m_buildings.m_buffer[(int)vehicleData.m_targetBuilding].m_fireIntensity == 0)
                    {
                        this.SetTarget(vehicleID, ref vehicleData, 0);
                    }
                }
            }
            if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None && !flag && this.CanLeave(vehicleID, ref vehicleData))
            {
                vehicleData.m_flags &= ~Vehicle.Flags.Stopped;
                vehicleData.m_flags |= Vehicle.Flags.Leaving;
            }
            if ((vehicleData.m_flags & Vehicle.Flags.GoingBack) == Vehicle.Flags.None)
            {
                if (this.ShouldReturnToSource(vehicleID, ref vehicleData))
                {
                    this.SetTarget(vehicleID, ref vehicleData, 0);
                }
            }
            else
            {
                if ((ulong)(Singleton <SimulationManager> .instance.m_currentFrameIndex >> 4 & 15u) == (ulong)((long)(vehicleID & 15)) && !this.ShouldReturnToSource(vehicleID, ref vehicleData))
                {
                    TransferManager.TransferOffer offer = default(TransferManager.TransferOffer);
                    offer.Priority = 3;
                    offer.Vehicle  = vehicleID;
                    offer.Position = frameData.m_position;
                    offer.Amount   = 1;
                    offer.Active   = true;
                    Singleton <TransferManager> .instance.AddIncomingOffer((TransferManager.TransferReason) vehicleData.m_transferType, offer);
                }
            }

            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                CustomCarAI.sm_speedData[vehicleID].RestoreVehicleSpeed(this.m_info);
            }
        }
Пример #28
0
 private void TryCollectCrime(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData)
 {
     throw new NotImplementedException("TryCollectCrime is target of redirection and is not implemented.");
 }
Пример #29
0
        public void CustomCalculateSegmentPosition(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)
        {
            var netManager = Singleton <NetManager> .instance;
            ushort targetNodeId;
            ushort nextTargetNodeId;

            if (offset < position.m_offset)
            {
                targetNodeId     = netManager.m_segments.m_buffer[position.m_segment].m_startNode;
                nextTargetNodeId = netManager.m_segments.m_buffer[position.m_segment].m_endNode;
            }
            else
            {
                targetNodeId     = netManager.m_segments.m_buffer[position.m_segment].m_endNode;
                nextTargetNodeId = netManager.m_segments.m_buffer[position.m_segment].m_startNode;
            }
            var prevTargetNodeId = prevOffset == 0 ? netManager.m_segments.m_buffer[prevPos.m_segment].m_startNode : netManager.m_segments.m_buffer[prevPos.m_segment].m_endNode;

            Vehicle.Frame lastFrameData = vehicleData.GetLastFrameData();
            Vector3 lastFrameVehiclePos = lastFrameData.m_position;
            float sqrVelocity           = lastFrameData.m_velocity.sqrMagnitude;

            netManager.m_lanes.m_buffer[laneID].CalculatePositionAndDirection(offset * 0.003921569f, out pos, out dir);

            float braking = this.m_info.m_braking;

            if ((vehicleData.m_flags & Vehicle.Flags.Emergency2) != (Vehicle.Flags) 0)
            {
                braking *= 2f;
            }

            // car position on the Bezier curve of the lane
            var vehiclePosOnBezier = netManager.m_lanes.m_buffer[prevLaneID].CalculatePosition(prevOffset * 0.003921569f);
            //ushort currentSegmentId = netManager.m_lanes.m_buffer[prevLaneID].m_segment;

            // this seems to be like the required braking force in order to stop the vehicle within its half length.
            var crazyValue             = 0.5f * sqrVelocity / braking + m_info.m_generatedInfo.m_size.z * 0.5f;
            bool withinBrakingDistance = Vector3.Distance(lastFrameVehiclePos, vehiclePosOnBezier) >= crazyValue - 1f;

            // NON-STOCK CODE START
#if BENCHMARK
            using (var bm = new Benchmark(null, "UpdateVehiclePosition")) {
#endif
            VehicleStateManager.Instance.UpdateVehiclePosition(vehicleId, ref vehicleData, lastFrameData.m_velocity.magnitude);
#if BENCHMARK
        }
#endif
            // NON-STOCK CODE END

            bool isRecklessDriver = VehicleStateManager.Instance.VehicleStates[vehicleId].recklessDriver;
            if (targetNodeId == prevTargetNodeId && withinBrakingDistance)
            {
                // NON-STOCK CODE START (stock code replaced)
#if BENCHMARK
                using (var bm = new Benchmark(null, "MayChangeSegment")) {
#endif
                //bool isRecklessDriver = VehicleStateManager.Instance.IsRecklessDriver(vehicleId, ref vehicleData); // NON-STOCK CODE

                if (!VehicleBehaviorManager.Instance.MayChangeSegment(vehicleId, ref VehicleStateManager.Instance.VehicleStates[vehicleId], ref vehicleData, sqrVelocity, isRecklessDriver, ref prevPos, ref netManager.m_segments.m_buffer[prevPos.m_segment], prevTargetNodeId, prevLaneID, ref position, targetNodeId, ref netManager.m_nodes.m_buffer[targetNodeId], laneID, ref nextPosition, nextTargetNodeId, out maxSpeed))                         // NON-STOCK CODE
                {
                    return;
                }
#if BENCHMARK
            }
#endif
                // NON-STOCK CODE END
            }

            var segmentInfo = netManager.m_segments.m_buffer[position.m_segment].Info;
            if (segmentInfo.m_lanes != null && segmentInfo.m_lanes.Length > position.m_lane)
            {
                // NON-STOCK CODE START
                // NON-STOCK CODE START
                float laneSpeedLimit = 1f;
#if BENCHMARK
                using (var bm = new Benchmark(null, "GetLockFreeGameSpeedLimit")) {
#endif
                if (!Options.customSpeedLimitsEnabled)
                {
                    laneSpeedLimit = segmentInfo.m_lanes[position.m_lane].m_speedLimit;
                }
                else
                {
                    // === START INLINED VERSION OF SpeedLimitManager.GetLockFreeGameSpeedLimit ===
                    ushort?[] fastArray = Flags.laneSpeedLimitArray[position.m_segment];
                    if (fastArray != null && fastArray.Length > position.m_lane && fastArray[position.m_lane] != null)
                    {
                        // === START INLINED VERSION OF SpeedLimitManager.ToGameSpeedLimit ===
                        laneSpeedLimit = (float)fastArray[position.m_lane];
                        if (laneSpeedLimit == 0)
                        {
                            laneSpeedLimit = SpeedLimitManager.MAX_SPEED;
                        }
                        else
                        {
                            laneSpeedLimit = laneSpeedLimit / 50f;
                        }
                        // === END INLINED VERSION OF SpeedLimitManager.ToGameSpeedLimit ===
                        // laneSpeedLimit = ToGameSpeedLimit((ushort)fastArray[position.m_lane]);
                    }
                    else
                    {
                        laneSpeedLimit = segmentInfo.m_lanes[position.m_lane].m_speedLimit;
                    }
                    // === END INLINED VERSION OF SpeedLimitManager.GetLockFreeGameSpeedLimit ===
                    //laneSpeedLimit = SpeedLimitManager.Instance.GetLockFreeGameSpeedLimit(position.m_segment, position.m_lane, laneID, segmentInfo.m_lanes[position.m_lane]); // info2.m_lanes[position.m_lane].m_speedLimit; // NON-STOCK CODE
                }
#if BENCHMARK
            }
#endif
                // NON-STOCK CODE END
                maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, laneSpeedLimit, netManager.m_lanes.m_buffer[laneID].m_curve);
            }
            else
            {
                maxSpeed = CalculateTargetSpeed(vehicleId, ref vehicleData, 1f, 0f);
            }

            // NON-STOCK CODE START (stock code replaced)
#if BENCHMARK
            using (var bm = new Benchmark(null, "CalcMaxSpeed")) {
#endif
            // === START INLINED VERSION OF VehicleBehaviorManager.CalcMaxSpeed ===
            if (Singleton <NetManager> .instance.m_treatWetAsSnow)
            {
                DistrictManager districtManager = Singleton <DistrictManager> .instance;
                byte district = districtManager.GetDistrict(pos);
                DistrictPolicies.CityPlanning cityPlanningPolicies = districtManager.m_districts.m_buffer[(int)district].m_cityPlanningPolicies;
                if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.StuddedTires) != DistrictPolicies.CityPlanning.None)
                {
                    if (Options.strongerRoadConditionEffects)
                    {
                        if (maxSpeed > VehicleBehaviorManager.ICY_ROADS_STUDDED_MIN_SPEED)
                        {
                            maxSpeed = VehicleBehaviorManager.ICY_ROADS_STUDDED_MIN_SPEED + (float)(255 - netManager.m_segments.m_buffer[position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - VehicleBehaviorManager.ICY_ROADS_STUDDED_MIN_SPEED);
                        }
                    }
                    else
                    {
                        maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[position.m_segment].m_wetness * 0.0005882353f;                                 // vanilla: -15% .. ±0%
                    }
                    districtManager.m_districts.m_buffer[(int)district].m_cityPlanningPoliciesEffect |= DistrictPolicies.CityPlanning.StuddedTires;
                }
                else
                {
                    if (Options.strongerRoadConditionEffects)
                    {
                        if (maxSpeed > VehicleBehaviorManager.ICY_ROADS_MIN_SPEED)
                        {
                            maxSpeed = VehicleBehaviorManager.ICY_ROADS_MIN_SPEED + (float)(255 - netManager.m_segments.m_buffer[position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - VehicleBehaviorManager.ICY_ROADS_MIN_SPEED);
                        }
                    }
                    else
                    {
                        maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[position.m_segment].m_wetness * 0.00117647066f;                                 // vanilla: -30% .. ±0%
                    }
                }
            }
            else
            {
                if (Options.strongerRoadConditionEffects)
                {
                    float minSpeed = Math.Min(maxSpeed * VehicleBehaviorManager.WET_ROADS_FACTOR, VehicleBehaviorManager.WET_ROADS_MAX_SPEED);                             // custom: -25% .. 0
                    if (maxSpeed > minSpeed)
                    {
                        maxSpeed = minSpeed + (float)(255 - netManager.m_segments.m_buffer[position.m_segment].m_wetness) * 0.0039215686f * (maxSpeed - minSpeed);
                    }
                }
                else
                {
                    maxSpeed *= 1f - (float)netManager.m_segments.m_buffer[position.m_segment].m_wetness * 0.0005882353f;                             // vanilla: -15% .. ±0%
                }
            }

            if (Options.strongerRoadConditionEffects)
            {
                float minSpeed = Math.Min(maxSpeed * VehicleBehaviorManager.BROKEN_ROADS_FACTOR, VehicleBehaviorManager.BROKEN_ROADS_MAX_SPEED);
                if (maxSpeed > minSpeed)
                {
                    maxSpeed = minSpeed + (float)netManager.m_segments.m_buffer[position.m_segment].m_condition * 0.0039215686f * (maxSpeed - minSpeed);
                }
            }
            else
            {
                maxSpeed *= 1f + (float)netManager.m_segments.m_buffer[position.m_segment].m_condition * 0.0005882353f;                         // vanilla: ±0% .. +15 %
            }

            // === START INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds ===
            if (Options.realisticSpeeds)
            {
                // === START INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds ===
                float vehicleRand = 0.01f * (float)(vehicleId % 100);
                // float vehicleRand = 0.01f * (float)GetVehicleRand(vehicleId);
                // === END INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds ===
                if (this.m_info.m_isLargeVehicle)
                {
                    maxSpeed *= 0.9f + vehicleRand * 0.1f;                             // a little variance, 0.9 .. 1
                }
                else if (isRecklessDriver)
                {
                    maxSpeed *= 1.3f + vehicleRand * 1.7f;                             // woohooo, 1.3 .. 3
                }
                else
                {
                    maxSpeed *= 0.8f + vehicleRand * 0.5f;                             // a little variance, 0.8 .. 1.3
                }
            }
            else if (isRecklessDriver)
            {
                maxSpeed *= 1.5f;
            }
            // === END INLINED VERSION OF VehicleBehaviorManager.ApplyRealisticSpeeds ===

            //maxSpeed = ApplyRealisticSpeeds(maxSpeed, vehicleId, this.m_info, isRecklessDriver);
            maxSpeed = Math.Max(VehicleBehaviorManager.MIN_SPEED, maxSpeed);                     // at least 10 km/h
            // === END INLINED VERSION OF VehicleBehaviorManager.CalcMaxSpeed ===
            //maxSpeed = VehicleBehaviorManager.Instance.CalcMaxSpeed(vehicleId, this.m_info, position, ref netManager.m_segments.m_buffer[position.m_segment], pos, maxSpeed, isRecklessDriver);
#if BENCHMARK
        }
#endif
            // NON-STOCK CODE END
        }
 private static ushort CheckOtherVehicle(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ref float maxSpeed, ref bool blocked, ref Vector3 collisionPush, float maxBraking, ushort otherID, ref Vehicle otherData, Vector3 min, Vector3 max, int lodPhysics)
 {
     Log.Error("CustomCarAI.CheckOtherVehicle called");
     return(0);
 }
Пример #31
0
        public override void SimulationStep(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData, ushort leaderID, ref Vehicle leaderData, int lodPhysics)
        {
            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                if (CustomCarAI.sm_speedData[vehicleID].speedMultiplier == 0 || CustomCarAI.sm_speedData[vehicleID].currentPath != vehicleData.m_path)
                {
                    CustomCarAI.sm_speedData[vehicleID].currentPath = vehicleData.m_path;
                    CustomCarAI.sm_speedData[vehicleID].SetRandomSpeedMultiplier(0.6f, 1.4f);
                }
                CustomCarAI.sm_speedData[vehicleID].ApplySpeedMultiplier(this.m_info);
            }

            if ((vehicleData.m_flags & Vehicle.Flags.Stopped) != Vehicle.Flags.None)
            {
                vehicleData.m_waitCounter += 1;
                if (this.CanLeave(vehicleID, ref vehicleData))
                {
                    vehicleData.m_flags      &= ~Vehicle.Flags.Stopped;
                    vehicleData.m_waitCounter = 0;
                }
            }
            CustomCarAI.SimulationStep(this, vehicleID, ref vehicleData, ref frameData, leaderID, ref leaderData, lodPhysics);

            if ((CSLTraffic.Options & OptionsManager.ModOptions.UseRealisticSpeeds) == OptionsManager.ModOptions.UseRealisticSpeeds)
            {
                CustomCarAI.sm_speedData[vehicleID].RestoreVehicleSpeed(this.m_info);
            }
        }