/// <summary> /// Logs the transfer offers. /// </summary> /// <param name="direction">The direction.</param> /// <param name="offers">The offers.</param> /// <param name="count">The count.</param> /// <param name="amount">The amount.</param> /// <param name="buildings">The buildings.</param> /// <param name="material">The material.</param> private static void DebugListLog( string direction, TransferManager.TransferOffer[] offers, ushort[] count, int[] amount, Building[] buildings, TransferManager.TransferReason material) { for (int priority = 0; priority < 8; priority++) { int index = ((int)material * 8) + priority; for (int i = 0; i < count[index]; i++) { Log.InfoList info = new Log.InfoList(); TransferManager.TransferOffer offer = offers[(index * 256) + i]; info.Add("Active", offer.Active); info.Add("Amount", offer.Amount); info.Add("Priority", offer.Priority); info.Add("Vehicle", offer.Vehicle, VehicleHelper.GetVehicleName(offer.Vehicle)); info.Add("Citizen", offer.Citizen, CitizenHelper.GetCitizenName(offer.Citizen)); info.Add("TransportLine", offer.TransportLine, TransportLineHelper.GetLineName(offer.TransportLine)); info.Add("Building", offer.Building, BuildingHelper.GetBuildingName(offer.Building), BuildingHelper.GetDistrictName(offer.Building)); if (buildings != null && offer.Building > 0 && buildings[offer.Building].Info != null && (buildings[offer.Building].m_flags & Building.Flags.Created) == Building.Flags.Created) { info.Add("Garbage", buildings[offer.Building].m_garbageBuffer); info.Add("Dead", buildings[offer.Building].m_deathProblemTimer); } Log.DevDebug(typeof(TransferManagerHelper), "DebugListLog", direction, material, info); } } }
/// <summary> /// De-spawns the vehicle. /// </summary> private static void DeSpawnVehicle(ushort vehicleId) { if (Global.Buildings != null) { foreach (BuildingKeeper.StandardServiceBuildings buildings in Global.Buildings.StandardServices) { foreach (ServiceBuildingInfo serviceBuilding in buildings.ServiceBuildings.Values) { ServiceVehicleInfo serviceVehicle; if (serviceBuilding.Vehicles.TryGetValue(vehicleId, out serviceVehicle) && serviceVehicle.Target != 0) { TargetBuildingInfo targetBuilding; if (buildings.TargetBuildings.TryGetValue(serviceVehicle.Target, out targetBuilding)) { targetBuilding.Handled = false; } } serviceBuilding.Vehicles.Remove(vehicleId); } } } VehicleHelper.DeSpawn(vehicleId); }
/// <summary> /// Creates a new instance of an information list with garbage vehicle info. /// </summary> /// <param name="vehicleId">The vehicle identifier.</param> /// <param name="vehicle">The vehicle.</param> /// <param name="dirtyBuildingId">The dirty building identifier.</param> /// <param name="dirtyBuilding">The dirty building.</param> /// <returns>The information list.</returns> private static Log.InfoList NewGarbageVehicleInfoList(ushort vehicleId, ref Vehicle vehicle, ushort dirtyBuildingId, ref Building dirtyBuilding) { Log.InfoList infoList = new Log.InfoList(); infoList.Add("SourceBuilding", vehicle.m_sourceBuilding, BuildingHelper.GetBuildingName(vehicle.m_sourceBuilding)); infoList.Add("Vehicle", vehicleId, VehicleHelper.GetVehicleName(vehicleId)); infoList.Add("DirtyBuilding", dirtyBuildingId, BuildingHelper.GetBuildingName(dirtyBuildingId)); infoList.Add("TargetBuilding", vehicle.m_targetBuilding, BuildingHelper.GetBuildingName(vehicle.m_targetBuilding)); return(infoList); }
/// <summary> /// Logs a list of building info for debug use. /// </summary> /// <param name="serviceBuildings">The service buildings.</param> public static void DebugListLog(IEnumerable <ServiceBuildingInfo> serviceBuildings) { Building[] buildings = Singleton <BuildingManager> .instance.m_buildings.m_buffer; Vehicle[] vehicles = Singleton <VehicleManager> .instance.m_vehicles.m_buffer; DistrictManager districtManager = Singleton <DistrictManager> .instance; CitizenManager citizenManager = Singleton <CitizenManager> .instance; foreach (ServiceBuildingInfo building in serviceBuildings) { DebugListLog(buildings, vehicles, districtManager, citizenManager, building.BuildingId, building, null, null); } foreach (ServiceBuildingInfo building in serviceBuildings) { VehicleHelper.DebugListLog(building); } }
/// <summary> /// Assigns target to vehicle. /// </summary> /// <param name="vehicleId">The vehicle identifier.</param> /// <param name="vehicle">The vehicle.</param> /// <param name="material">The material.</param> /// <param name="targetBuildingId">The target building identifier.</param> /// <param name="targetCitizenId">The target citizen identifier.</param> /// <returns>The result of the action.</returns> /// <exception cref="System.InvalidOperationException">Ambulances must use citizen assignment /// or /// Material must be specified.</exception> /// <exception cref="System.NotImplementedException">Ambulance dispatching not fully implemented yet.</exception> public static VehicleResult AssignTarget(ushort vehicleId, ref Vehicle vehicle, TransferManager.TransferReason?material, ushort targetBuildingId, uint targetCitizenId) { if (targetBuildingId == 0 && targetCitizenId == 0) { return(VehicleHelper.SetTarget(vehicleId, ref vehicle, targetBuildingId, targetCitizenId)); } if (vehicle.Info.m_vehicleAI is AmbulanceAI && targetCitizenId == 0) { throw new InvalidOperationException("Ambulances must use citizen assignment"); } if (Global.Settings.AssignmentCompatibilityMode == ServiceDispatcherSettings.ModCompatibilityMode.UseCustomCode) { if (vehicle.Info.m_vehicleAI is AmbulanceAI) { throw new NotImplementedException("Ambulance dispatching not fully implemented yet"); } return(VehicleHelper.SetTarget(vehicleId, ref vehicle, targetBuildingId, targetCitizenId)); } if (material == null || !material.HasValue) { if (vehicle.Info.m_vehicleAI is HearseAI) { material = TransferManager.TransferReason.Dead; } else if (vehicle.Info.m_vehicleAI is GarbageTruckAI) { material = TransferManager.TransferReason.Garbage; } else if (vehicle.Info.m_vehicleAI is AmbulanceAI) { material = TransferManager.TransferReason.Sick; } else { throw new InvalidOperationException("Material must be specified"); } } return(new VehicleResult(StartTransfer(vehicleId, ref vehicle, material.Value, targetBuildingId, targetCitizenId), VehicleResult.Result.Assigned)); }
/// <summary> /// De-assigns the vehicle. /// </summary> private void DeAssign() { if (Global.Buildings != null) { foreach (BuildingKeeper.StandardServiceBuildings buildings in Global.Buildings.StandardServices) { foreach (ServiceBuildingInfo serviceBuilding in buildings.ServiceBuildings.Values) { ServiceVehicleInfo serviceVehicle; if (serviceBuilding.Vehicles.TryGetValue(this.VehicleId, out serviceVehicle) && serviceVehicle.Target != 0) { TargetBuildingInfo targetBuilding; if (buildings.TargetBuildings.TryGetValue(serviceVehicle.Target, out targetBuilding)) { targetBuilding.Handled = false; } if (this.lastDeAssignStamp != Global.CurrentFrame) { if (serviceVehicle.DeAssign().DeSpawned) { serviceBuilding.Vehicles.Remove(this.VehicleId); } this.lastDeAssignStamp = Global.CurrentFrame; } } } } } if (this.lastDeAssignStamp != Global.CurrentFrame) { if (Log.LogALot) { Log.DevDebug(this, "DeAssign", this.dispatcherType, this.VehicleId); } VehicleHelper.DeAssign(this.VehicleId); } }
/// <summary> /// De-assign target from vehicle. /// </summary> /// <param name="vehicle">The vehicle.</param> /// <param name="force">If set to <c>true</c> force de-assignment.</param> /// <param name="sourceObject">The source object.</param> /// <param name="sourceBlock">The source block.</param> /// <param name="logMessage">The log message.</param> /// <returns>The result of the action.</returns> public VehicleResult DeAssign(ref Vehicle vehicle, bool force = false, object sourceObject = null, string sourceBlock = null, string logMessage = null) { if (this.lastDeAssignStamp == Global.CurrentFrame) { return(new VehicleResult(vehicle.m_targetBuilding == 0 && this.Target == 0)); } if (force || Global.CurrentFrame - this.LastAssigned > Global.TargetLingerDelay || (vehicle.m_targetBuilding != this.Target && !this.LingerWrongTargets)) { this.lastDeAssignStamp = Global.CurrentFrame; if (vehicle.m_targetBuilding == 0 && this.Target == 0) { return(new VehicleResult(true)); } if (Log.LogALot && (sourceObject != null || sourceBlock != null || logMessage != null)) { Log.DevDebug(this, "DeAssign", sourceBlock, logMessage, this.VehicleId, vehicle.m_targetBuilding, this.Target); } // Set internal target. this.Target = 0; // Unassign the vehicle. ushort serviceBuildingId = vehicle.m_sourceBuilding; VehicleResult result = VehicleHelper.DeAssign(this.VehicleId, ref vehicle); if (result.DeSpawned) { ServiceBuildingInfo building = Global.Buildings.GetServiceBuilding(serviceBuildingId); if (building != null) { building.Vehicles.Remove(this.VehicleId); } } return(result); } return(new VehicleResult(vehicle.m_targetBuilding == 0 && this.Target == 0)); }
/// <summary> /// Creates the specified service building. /// </summary> /// <param name="serviceBuilding">The service building.</param> /// <param name="material">The material.</param> /// <param name="dispatcherType">Type of the dispatcher.</param> /// <param name="targetBuildingId">The target building identifier.</param> /// <param name="targetCitizenId">The target citizen identifier.</param> /// <returns> /// The service vehicle. /// </returns> public static ServiceVehicleInfo Create(ServiceBuildingInfo serviceBuilding, TransferManager.TransferReason material, Dispatcher.DispatcherTypes dispatcherType, ushort targetBuildingId, uint targetCitizenId) { ushort vehicleId = 0; VehicleInfo info = null; if (Global.Settings.CreationCompatibilityMode == ServiceDispatcherSettings.ModCompatibilityMode.UseCustomCode) { info = VehicleHelper.CreateServiceVehicle(serviceBuilding.BuildingId, material, targetBuildingId, targetCitizenId, out vehicleId); } else { info = BuildingHelper.StartTransfer(serviceBuilding.BuildingId, material, targetBuildingId, targetCitizenId, out vehicleId); } if (info == null) { return(null); } VehicleManager manager = Singleton <VehicleManager> .instance; return(new ServiceVehicleInfo(vehicleId, ref manager.m_vehicles.m_buffer[vehicleId], targetBuildingId == 0, dispatcherType, targetBuildingId)); }
/// <summary> /// Sets the target and updates the games vehicle object. /// </summary> /// <param name="targetBuildingId">The target building identifier.</param> /// <param name="vehicle">The vehicle.</param> /// <param name="material">The material.</param> /// <returns>The result of the action.</returns> public VehicleResult SetTarget(ushort targetBuildingId, ref Vehicle vehicle, TransferManager.TransferReason?material) { if (targetBuildingId == 0) { if (this.Target == 0 && vehicle.m_targetBuilding == 0) { return(new VehicleResult(true)); } return(this.DeAssign(ref vehicle, true, "SetTarget")); } if (Log.LogALot) { Log.DevDebug(this, "SetTarget", this.VehicleId, targetBuildingId, this.Target, vehicle.m_targetBuilding, vehicle.m_flags); } VehicleResult result = VehicleHelper.AssignTarget(this.VehicleId, ref vehicle, material, targetBuildingId, 0); if (result) { this.LastAssigned = Global.CurrentFrame; this.FreeToCollect = false; this.Target = targetBuildingId; } else { Log.Debug(this, "SetTarget", "Failed", this.VehicleId, targetBuildingId, this.Target, vehicle.m_targetBuilding, vehicle.m_flags); this.LastAssigned = 0; this.FreeToCollect = false; this.Target = 0; } return(result); }
/// <summary> /// Starts the transfer. /// </summary> /// <param name="serviceBuildingId">The building identifier.</param> /// <param name="building">The building.</param> /// <param name="material">The material.</param> /// <param name="targetBuildingId">The target building identifier.</param> /// <param name="targetCitizenId">The target citizen identifier.</param> /// <param name="vehicleId">The vehicle identifier.</param> /// <returns>Vehicle info for the created vehicle.</returns> public static VehicleInfo StartTransfer(ushort serviceBuildingId, ref Building building, TransferManager.TransferReason material, ushort targetBuildingId, uint targetCitizenId, out ushort vehicleId) { if (building.Info.m_buildingAI is HospitalAI && targetCitizenId == 0) { return(VehicleHelper.CreateServiceVehicle(serviceBuildingId, material, targetBuildingId, targetCitizenId, out vehicleId)); } Vehicle[] vehicles = Singleton <VehicleManager> .instance.m_vehicles.m_buffer; Citizen[] citizens = Singleton <CitizenManager> .instance.m_citizens.m_buffer; TransferManager.TransferOffer offer = TransferManagerHelper.MakeOffer(targetBuildingId, targetCitizenId); int count; HashSet <ushort> ownVehicles = new HashSet <ushort>(); count = 0; vehicleId = building.m_ownVehicles; while (vehicleId != 0) { ownVehicles.Add(vehicleId); if (count >= ushort.MaxValue) { throw new Exception("Loop counter too high"); } count++; vehicleId = vehicles[vehicleId].m_nextOwnVehicle; } // Cast AI as games original AI so detoured methods are called, but not methods from not replaced classes. if (Global.Settings.CreationCompatibilityMode == ServiceDispatcherSettings.ModCompatibilityMode.UseInstanciatedClassMethods || !Global.Settings.AllowReflection()) { building.Info.m_buildingAI.StartTransfer(serviceBuildingId, ref building, material, offer); } else if (building.Info.m_buildingAI is CemeteryAI) { ((CemeteryAI)building.Info.m_buildingAI.CastTo <CemeteryAI>()).StartTransfer(serviceBuildingId, ref building, material, offer); } else if (building.Info.m_buildingAI is LandfillSiteAI) { ((LandfillSiteAI)building.Info.m_buildingAI.CastTo <LandfillSiteAI>()).StartTransfer(serviceBuildingId, ref building, material, offer); } else if (building.Info.m_buildingAI is HospitalAI) { ((HospitalAI)building.Info.m_buildingAI.CastTo <HospitalAI>()).StartTransfer(serviceBuildingId, ref building, material, offer); } else { building.Info.m_buildingAI.StartTransfer(serviceBuildingId, ref building, material, offer); } ushort newVehicleId = 0; ushort waitingVehicleId = 0; Vehicle.Flags findFlags = Vehicle.Flags.Created; switch (material) { case TransferManager.TransferReason.Dead: case TransferManager.TransferReason.Garbage: case TransferManager.TransferReason.Sick: findFlags |= Vehicle.Flags.TransferToSource; break; case TransferManager.TransferReason.DeadMove: case TransferManager.TransferReason.GarbageMove: case TransferManager.TransferReason.SickMove: findFlags |= Vehicle.Flags.TransferToSource; break; } count = 0; vehicleId = building.m_ownVehicles; while (vehicleId != 0) { if (!ownVehicles.Contains(vehicleId) && (vehicles[vehicleId].m_flags & findFlags) == findFlags && vehicles[vehicleId].Info != null) { if (vehicles[vehicleId].m_targetBuilding == targetBuildingId && (targetCitizenId == 0 || citizens[targetCitizenId].m_vehicle == vehicleId)) { return(vehicles[vehicleId].Info); } newVehicleId = vehicleId; if ((vehicles[vehicleId].m_flags & Vehicle.Flags.WaitingTarget) == Vehicle.Flags.WaitingTarget) { waitingVehicleId = vehicleId; } } if (count >= ushort.MaxValue) { throw new Exception("Loop counter too high"); } count++; vehicleId = vehicles[vehicleId].m_nextOwnVehicle; } if (waitingVehicleId != 0) { vehicleId = waitingVehicleId; //Log.DevDebug(typeof(BuildingHelper), "StartTransfer", "Waiting Vehicle", serviceBuildingId, targetBuildingId, targetCitizenId, material, vehicleId, vehicles[vehicleId].m_flags); } else if (newVehicleId != 0) { vehicleId = newVehicleId; //Log.DevDebug(typeof(BuildingHelper), "StartTransfer", "Guess Vehicle", serviceBuildingId, targetBuildingId, targetCitizenId, material, vehicleId, vehicles[vehicleId].m_flags); } else { vehicleId = 0; Log.Info(typeof(BuildingHelper), "StartTransfer", "Lost Vehicle", serviceBuildingId, targetBuildingId, targetCitizenId, material); return(null); } if (!VehicleHelper.AssignTarget(vehicleId, ref vehicles[vehicleId], material, targetBuildingId, targetCitizenId)) { return(null); } return(vehicles[vehicleId].Info); }
/// <summary> /// Updates the specified vehicle. /// </summary> /// <param name="vehicle">The vehicle.</param> public void Update(ref Vehicle vehicle) { this.targetBuildingId = vehicle.m_targetBuilding; this.isTrailer = vehicle.m_leadingVehicle != 0; this.hasCargoParent = vehicle.m_cargoParent != 0; if (this.hasCargoParent && !Global.Settings.Experimental.AllowTrackingOfCargoChildren) { return; } if (this.isTrailer) { if (Global.Settings.Experimental.TrackLostTrailers) { this.UpdateTrailer(ref vehicle); } return; } // Check if vehicle has flag that should be checked. Vehicle.Flags flags = vehicle.m_flags & FlagsToCheck; if ((flags & VehicleHelper.VehicleAll) != ~VehicleHelper.VehicleAll) { Vector3 position = vehicle.GetLastFramePosition(); // Remember first time stamp the vehicle was seen with this flag at this position. if (this.checkFlagSinceFrame == 0 || this.checkFlagSinceTime == 0 || flags != this.checkFlags || Math.Truncate((position - this.checkFlagPosition).sqrMagnitude) > 0) { this.isFlagged = false; this.checkFlags = flags; this.checkFlagPosition = position; this.checkFlagSinceTime = Global.SimulationTime; this.checkFlagSinceFrame = Global.CurrentFrame; } else if (!this.isFlagged && this.CheckFlaggedForFrames > Global.CheckFlagStuckDelay) { // Check if stuck with flag. double delta = this.CheckFlaggedForSeconds; if (delta > Global.Settings.RecoveryCrews.DelaySeconds) { Log.Info(this, "IsFlagged", this.checkFlags, this.VehicleId, delta, VehicleHelper.GetVehicleName(this.VehicleId)); this.isFlagged = true; } } } else if ((this.checkFlags & VehicleHelper.VehicleAll) != ~VehicleHelper.VehicleAll || this.checkFlagSinceTime != 0 || this.checkFlagSinceFrame != 0) { this.isFlagged = false; this.checkFlags = ~VehicleHelper.VehicleAll; this.checkFlagSinceTime = 0; this.checkFlagSinceFrame = 0; } // Check if vehicle is confused. if (ConfusionHelper.VehicleIsConfused(ref vehicle)) { if (this.confusedDeAssignedSinceFrame == 0) { this.confusedDeAssignedSinceFrame = Global.CurrentFrame; } if (this.confusedSinceFrame == 0 || this.confusedSinceTime == 0) { if (Log.LogALot) { Log.DevDebug(this, "Update", "NewConfused", this.VehicleId, this.ConfusedForSeconds, this.ConfusedForFrames, Global.Settings.RecoveryCrews.DelaySeconds, Global.DeAssignConfusedDelay, vehicle.m_targetBuilding, vehicle.m_flags, VehicleHelper.GetVehicleName(this.VehicleId)); } this.isConfused = false; this.confusedSinceTime = Global.SimulationTime; this.confusedSinceFrame = Global.CurrentFrame; this.confusedDeAssignedSinceFrame = Global.CurrentFrame; } else if (!this.isConfused && this.ConfusedForFrames > Global.CheckFlagStuckDelay) { // Check if stuck confused. double delta = this.ConfusedForSeconds; if (delta > Global.Settings.RecoveryCrews.DelaySeconds) { Log.Info(this, "IsConfused", this.VehicleId, delta, VehicleHelper.GetVehicleName(this.VehicleId)); this.isConfused = true; } } } else if (this.confusedSinceTime != 0 || this.confusedSinceFrame != 0 || this.confusedDeAssignedSinceFrame != 0) { this.isConfused = false; this.confusedSinceTime = 0; this.confusedSinceFrame = 0; this.confusedDeAssignedSinceFrame = 0; } this.isStuck = this.isLost || this.isConfused || this.isFlagged || this.isBroken; }
/// <summary> /// Logs the debug lists. /// </summary> /// <param name="initializing">if set to <c>true</c> level is loading.</param> /// <param name="deInitializing">if set to <c>true</c> level is unloading.</param> private static void LogDebugLists(bool initializing, bool deInitializing) { try { bool flush = false; if (initializing) { if (Log.LogDebugLists) { Log.Debug(typeof(Global), "LogDebugLists", "Initializing"); } } else if (deInitializing) { if (Log.LogDebugLists) { Log.Debug(typeof(Global), "LogDebugLists", "DeInitializing"); } } else if (CurrentFrame == 0) { if (Log.LogDebugLists) { Log.Debug(typeof(Global), "LogDebugLists", "Started"); Detours.LogInfo(); TransferManagerHelper.LogInfo(); VehicleHelper.DebugListLog(); BuildingHelper.DebugListLog(); TransferManagerHelper.DebugListLog(); flush = true; } } else if (CurrentFrame > 0) { if (Log.LogDebugLists) { Log.Debug(typeof(Global), "LogDebugLists", "Running"); if (Global.Buildings != null) { Global.Buildings.DebugListLogBuildings(); } if (Global.Vehicles != null) { Global.Vehicles.DebugListLogVehicles(); } TransferManagerHelper.DebugListLog(); flush = true; } if (Global.ServiceProblems != null) { Global.ServiceProblems.DebugListLogServiceProblems(); flush = true; } } if (flush) { Log.FlushBuffer(); } } catch (Exception ex) { Log.Error(typeof(Global), "LogDebugLists", ex); } }
/// <summary> /// Updates the specified trailer vehicle. /// </summary> /// <param name="vehicle">The vehicle.</param> private void UpdateTrailer(ref Vehicle vehicle) { Vehicle[] vehicles = Singleton <VehicleManager> .instance.m_vehicles.m_buffer; LostReasons lost = LostReasons.None; ushort count = 0; ushort leadId = this.VehicleId; ushort nextId = vehicle.m_leadingVehicle; while (nextId != 0) { if (vehicles[nextId].m_trailingVehicle != leadId) { lost = LostReasons.IgnorantLead; break; } if (count >= ushort.MaxValue) { throw new Exception("Loop counter too high"); } count++; leadId = nextId; nextId = vehicles[leadId].m_leadingVehicle; } if (lost == LostReasons.None && (vehicles[leadId].Info == null || (vehicles[leadId].m_flags & Vehicle.Flags.Spawned) == ~VehicleHelper.VehicleAll)) { lost = LostReasons.NoLead; } if (lost != LostReasons.None) { if (this.lostSinceFrame == 0 || this.lostSinceTime == 0 || this.lostReason == LostReasons.None || lost != this.lostReason) { if (Log.LogALot) { Log.DevDebug(this, "UpdateTrailer", "NewLost", lost, this.VehicleId, this.LostForSeconds, this.LostForFrames, Global.Settings.RecoveryCrews.DelaySeconds, Global.CheckFlagStuckDelay, vehicle.m_leadingVehicle, vehicle.m_flags, VehicleHelper.GetVehicleName(this.VehicleId)); } this.isLost = false; this.lostReason = lost; this.lostSinceTime = Global.SimulationTime; this.lostSinceFrame = Global.CurrentFrame; } else if (!this.isLost) { double delta; if (this.lostReason != LostReasons.None && this.LostForFrames > Global.CheckFlagStuckDelay) { delta = this.LostForSeconds; if (delta > Global.Settings.RecoveryCrews.DelaySeconds) { Log.Info(this, "IsLost", lost, this.VehicleId, delta, VehicleHelper.GetVehicleName(this.VehicleId)); this.isLost = true; } } } } else { this.isLost = false; this.lostReason = LostReasons.None; this.lostSinceTime = 0; this.lostSinceFrame = 0; } this.isStuck = this.isLost || this.isConfused || this.isFlagged || this.isBroken; }
private void DeSpawnTrailer() { ushort count; ushort prevId; ushort nextId; Vehicle[] vehicles = Singleton <VehicleManager> .instance.m_vehicles.m_buffer; LinkedList <ushort> ids = new LinkedList <ushort>(new ushort[] { this.VehicleId }); count = 0; prevId = this.VehicleId; nextId = vehicles[prevId].m_leadingVehicle; while (nextId != 0) { if (vehicles[nextId].m_trailingVehicle != prevId) { break; } ids.AddFirst(nextId); if (count >= ushort.MaxValue) { throw new Exception("Loop counter too high"); } count++; prevId = nextId; nextId = vehicles[prevId].m_leadingVehicle; } count = 0; prevId = this.VehicleId; nextId = vehicles[prevId].m_trailingVehicle; while (nextId != 0) { if (vehicles[nextId].m_leadingVehicle != prevId) { break; } ids.AddLast(nextId); if (count >= ushort.MaxValue) { throw new Exception("Loop counter too high"); } count++; prevId = nextId; nextId = vehicles[prevId].m_trailingVehicle; } count = 0; foreach (ushort id in ids) { if (count == 0 && vehicles[id].m_leadingVehicle == 0) { DeSpawnVehicle(id); } else { VehicleHelper.DeSpawn(id); } count++; } }
/// <summary> /// Categorizes the vehicles. /// </summary> /// <param name="firstVehicleId">The first vehicle identifier.</param> /// <param name="lastVehicleId">The last vehicle identifier.</param> private void HandleVehicles(ushort firstVehicleId, int lastVehicleId) { Vehicle[] vehicles = Singleton <VehicleManager> .instance.m_vehicles.m_buffer; Building[] buildings = Singleton <BuildingManager> .instance.m_buildings.m_buffer; for (ushort id = firstVehicleId; id < lastVehicleId; id++) { // Is the vehicle? if (vehicles[id].m_leadingVehicle != 0 || vehicles[id].m_cargoParent != 0 || vehicles[id].Info == null || (vehicles[id].m_flags & VehicleHelper.VehicleExists) == ~VehicleHelper.VehicleAll) { if (this.removedFromGrid != null && this.removedFromGrid.Contains(id)) { this.removedFromGrid.Remove(id); } if (this.StuckVehicles != null && this.StuckVehicles.ContainsKey(id)) { //if (Log.LogALot) //{ // Log.DevDebug(this, "HandleVehicles", "StuckVehicles", "Gone", id); //} this.StuckVehicles.Remove(id); } } else { // Check target assignments for service vehicles. if ((vehicles[id].m_flags & Vehicle.Flags.TransferToSource) != ~VehicleHelper.VehicleAll && (vehicles[id].m_flags & (Vehicle.Flags.TransferToTarget | Vehicle.Flags.Arriving | Vehicle.Flags.Stopped)) == ~VehicleHelper.VehicleAll && (vehicles[id].m_flags & VehicleHelper.VehicleUnavailable) == ~VehicleHelper.VehicleAll && vehicles[id].m_targetBuilding != vehicles[id].m_sourceBuilding && (buildings[vehicles[id].m_sourceBuilding].m_flags & Building.Flags.Downgrading) == Building.Flags.None) { if (Global.Settings.DeathCare.DispatchVehicles && Global.HearseDispatcher != null && vehicles[id].m_transferType == Global.HearseDispatcher.TransferType) { Global.HearseDispatcher.CheckVehicleTarget(id, ref vehicles[id]); } if (Global.Settings.Garbage.DispatchVehicles && Global.GarbageTruckDispatcher != null && vehicles[id].m_transferType == Global.GarbageTruckDispatcher.TransferType) { Global.GarbageTruckDispatcher.CheckVehicleTarget(id, ref vehicles[id]); } if (Global.Settings.HealthCare.DispatchVehicles && Global.AmbulanceDispatcher != null && vehicles[id].m_transferType == Global.AmbulanceDispatcher.TransferType) { Global.AmbulanceDispatcher.CheckVehicleTarget(id, ref vehicles[id]); } } // Handle grid removals. if (this.removedFromGrid != null) { if ((vehicles[id].m_flags & Vehicle.Flags.Stopped) == ~VehicleHelper.VehicleAll && (vehicles[id].Info.m_vehicleAI is HearseAI || vehicles[id].Info.m_vehicleAI is AmbulanceAI)) { if (this.removedFromGrid.Contains(id)) { if (Log.LogALot) { Log.Debug(this, "HandleVehicles", "Moving", id, vehicles[id].m_targetBuilding, vehicles[id].Info.name, VehicleHelper.GetVehicleName(id), vehicles[id].m_flags); } this.removedFromGrid.Remove(id); } } else if ((Global.Settings.DeathCare.RemoveFromGrid && vehicles[id].Info.m_vehicleAI is HearseAI) || (Global.Settings.HealthCare.RemoveFromGrid && vehicles[id].Info.m_vehicleAI is AmbulanceAI)) { if (!this.removedFromGrid.Contains(id)) { if (Log.LogALot) { Log.Debug(this, "HandleVehicles", "RemoveFromGrid", id, vehicles[id].m_targetBuilding, vehicles[id].Info.name, VehicleHelper.GetVehicleName(id), vehicles[id].m_flags); } Singleton <VehicleManager> .instance.RemoveFromGrid(id, ref vehicles[id], false); this.removedFromGrid.Add(id); } } } // Try to fix stuck vehicles. if (this.StuckVehicles != null) { if (StuckVehicleInfo.HasProblem(id, ref vehicles[id])) { StuckVehicleInfo stuckVehicle; if (this.StuckVehicles.TryGetValue(id, out stuckVehicle)) { stuckVehicle.Update(ref vehicles[id]); } else { stuckVehicle = new StuckVehicleInfo(id, ref vehicles[id]); this.StuckVehicles[id] = stuckVehicle; if (Log.LogALot) { Log.DevDebug(this, "HandleVehicles", "StuckVehicles", "New", id, vehicles[id].m_flags, stuckVehicle.Flagged, stuckVehicle.Lost, stuckVehicle.Confused, stuckVehicle.ExtraInfo); } } if (stuckVehicle.HandleProblem()) { if (Log.LogALot) { Log.DevDebug(this, "HandleVehicles", "StuckVehicles", "Handled", id); } this.StuckVehicles.Remove(id); } } else if (this.StuckVehicles.ContainsKey(id)) { if (Log.LogALot) { Log.DevDebug(this, "HandleVehicles", "StuckVehicles", "NoProblem", id, vehicles[id].m_flags, vehicles[id].m_flags & StuckVehicleInfo.FlagsToCheck, ConfusionHelper.VehicleIsConfused(ref vehicles[id])); } this.StuckVehicles.Remove(id); } } } } }
/// <summary> /// Handles the vehicles problems. /// </summary> /// <returns>True if a problem was handled.</returns> public bool HandleProblem() { if (this.hasCargoParent && !((this.isFlagged || this.isLost) && Global.Settings.Experimental.AllowRemovalOfStuckCargoChildren) && !(this.isConfused && Global.Settings.Experimental.AllowRemovalOfConfusedCargoChildren)) { if (Log.LogALot) { Log.DevDebug(this, "HandleProblem", "StuckLostBroken", "IgnoreCargoChild", this.VehicleId, VehicleHelper.GetVehicleName(this.VehicleId)); } this.lastHandledStamp = Global.CurrentFrame; return(false); } if (this.isTrailer && !Global.Settings.Experimental.RemoveLostTrailers) { if (Log.LogALot) { Log.DevDebug(this, "HandleProblem", "StuckLostBroken", "IgnoreTrailer", this.VehicleId, VehicleHelper.GetVehicleName(this.VehicleId)); } this.lastHandledStamp = Global.CurrentFrame; return(false); } if (this.isStuck && this.lastHandledStamp + Global.CheckFlagStuckDelay < Global.CurrentFrame) { try { if (this.isTrailer) { // Remove trailer vehicle. Log.Debug(this, "HandleProblem", "StuckLostBroken", "DeSpawnTrailer", this.VehicleId, this.ExtraInfo, VehicleHelper.GetVehicleName(this.VehicleId)); this.DeSpawnTrailer(); } else { // Remove vehicle. Log.Debug(this, "HandleProblem", "StuckLostBroken", "DeSpawn", this.VehicleId, this.ExtraInfo, VehicleHelper.GetVehicleName(this.VehicleId)); this.DeSpawn(); } return(true); } catch (Exception ex) { Log.Error(this, "HandleProblem", ex, this.VehicleId); this.handlingErrors++; return(this.handlingErrors > 10); } finally { this.isStuck = false; this.lastHandledStamp = Global.CurrentFrame; } } if (this.ConfusedDeAssignedForFrames > Global.DeAssignConfusedDelay && !this.isTrailer && IsDispatchersResponsibility(this.dispatcherType)) { try { // De-assign vehicle. Log.Debug(this, "HandleProblem", "Confused", "DeAssign", this.VehicleId, VehicleHelper.GetVehicleName(this.VehicleId)); this.DeAssign(); } catch (Exception ex) { Log.Error(this, "HandleProblem", ex, this.VehicleId); this.handlingErrors++; return(this.handlingErrors > 10); } finally { this.confusedDeAssignedSinceFrame = Global.CurrentFrame; } } return(false); }
/// <summary> /// Initializes the helpers. /// </summary> public static void InitializeHelpers() { TransferManagerHelper.DeInitialize(); VehicleHelper.Initialize(); BulldozeHelper.Initialize(); }