/// <summary> /// Principles: /// 1) max concurrent orders per building per type is capped per MAX_TTL day period /// 2) /// </summary> /// <param name="material"></param> /// <param name="requestBuilding"></param> /// <param name="responseBuilding"></param> /// <returns></returns> public bool IsRestricted(TransferManager.TransferReason material, ushort requestBuilding, ushort responseBuilding) { if (!Events.TryGetValue(requestBuilding, out var list)) { return(false); } var isRequestBuildingOutside = TransferManagerInfo.IsOutsideBuilding(requestBuilding); var isResponseBuildingOutside = TransferManagerInfo.IsOutsideBuilding(responseBuilding); if (!Settings.enableDummyCargoTraffic.value && isRequestBuildingOutside && isResponseBuildingOutside) { return(true); } var concurrentOrderCount = list.Count; var concurrentOrderCountToOutsideConnection = 0; var concurrentOrderCountToResponseBuilding = 0; for (int i = 0; i < list.Count; i++) { if (list[i].ResponseBuilding == responseBuilding) { concurrentOrderCountToResponseBuilding++; } if (TransferManagerInfo.IsOutsideBuilding(list[i].ResponseBuilding)) { concurrentOrderCountToOutsideConnection++; } } var vehicleCount = TransferManagerInfo.GetCargoVehicleCount(requestBuilding, material); var maxConcurrentOrderCount = Math.Ceiling(Constraints.GlobalOutsideConnectionIntensity() / 10.0); if (isRequestBuildingOutside && TransferManagerInfo.IsOutsideRoadConnection(requestBuilding)) { maxConcurrentOrderCount *= 4; } var maxConcurrentOrderCountToResponseBuilding = Math.Ceiling(maxConcurrentOrderCount / 2.0); var maxConcurrentOrderCountToOutsideConnection = Math.Ceiling(maxConcurrentOrderCount * Constraints.GlobalOutsideToOutsidePerc() / 100.0); var maxVehicleCount = Math.Ceiling(maxConcurrentOrderCount / 2.0); bool isRestrictedConcurrent = concurrentOrderCount >= maxConcurrentOrderCount; bool isRestrictedConcurrentToBuilding = concurrentOrderCountToResponseBuilding >= maxConcurrentOrderCountToResponseBuilding; bool isRestrictedConcurrentToOutsideConnection = isRequestBuildingOutside && isResponseBuildingOutside && concurrentOrderCountToOutsideConnection >= maxConcurrentOrderCountToOutsideConnection; bool isVehicleConstrained = vehicleCount >= maxVehicleCount; return(isRestrictedConcurrent || isRestrictedConcurrentToBuilding || isRestrictedConcurrentToOutsideConnection || isVehicleConstrained); }
private static bool IsSameLocation( ref TransferManager.TransferOffer requestOffer, ref TransferManager.TransferOffer responseOffer) { if (requestOffer.m_object == responseOffer.m_object) { return(true); } var requestHomeBuilding = TransferManagerInfo.GetHomeBuilding(ref requestOffer); var responseHomeBuilding = TransferManagerInfo.GetHomeBuilding(ref responseOffer); if (requestHomeBuilding == responseHomeBuilding) { return(true); } // Don't match a guest vehicle to its host building. For instance, Taxi stands. if (responseOffer.Vehicle != 0 && BuildingManager.instance.m_buildings.m_buffer[requestHomeBuilding].m_guestVehicles != 0) { var vehicleID = BuildingManager.instance.m_buildings.m_buffer[requestHomeBuilding].m_guestVehicles; int num = 0; while (vehicleID != 0) { if (responseOffer.Vehicle == vehicleID) { return(true); } vehicleID = VehicleManager.instance.m_vehicles.m_buffer[vehicleID].m_nextGuestVehicle; ++num; if (++num > 16384) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace); break; } } } // Don't match outside connections that are too close to each other. if (TransferManagerInfo.IsOutsideBuilding(requestHomeBuilding) && TransferManagerInfo.IsOutsideBuilding(responseHomeBuilding)) { var requestPosition = BuildingManager.instance.m_buildings.m_buffer[requestHomeBuilding].m_position; var responsePosition = BuildingManager.instance.m_buildings.m_buffer[responseHomeBuilding].m_position; var distanceSquared = Vector3.SqrMagnitude(responsePosition - requestPosition); return(distanceSquared <= 100000); } return(false); }
/// <summary> /// Returns true if we can potentially match the two given offers. /// </summary> /// <returns></returns> private static bool IsValidLowPriorityOffer( TransferManager.TransferReason material, ref TransferManager.TransferOffer requestOffer, int requestPriority, ref TransferManager.TransferOffer responseOffer, int responsePriority) { var requestBuilding = TransferManagerInfo.GetHomeBuilding(ref requestOffer); var responseBuilding = TransferManagerInfo.GetHomeBuilding(ref responseOffer); if (responseBuilding == 0) { Logger.LogMaterial( $"TransferManager::IsValidLowPriorityOffer: {Utils.ToString(ref responseOffer, material)}, not a district services building", material); return(false); } // Special logic if both buildings are warehouses. Used to prevent goods from being shuffled back and forth between warehouses. if (BuildingManager.instance.m_buildings.m_buffer[requestBuilding].Info.GetAI() is WarehouseAI && BuildingManager.instance.m_buildings.m_buffer[responseBuilding].Info.GetAI() is WarehouseAI) { return(false); } // Special logic for recycling centers, since they can produce recycled goods but the district policies // should not apply to these materials. if (responseBuilding != 0 && BuildingManager.instance.m_buildings.m_buffer[responseBuilding].Info.GetAI() is LandfillSiteAI) { if (TransferManagerInfo.IsOutsideOffer(ref requestOffer)) { Logger.LogMaterial( $"TransferManager::IsValidLowPriorityOffer: {Utils.ToString(ref responseOffer, material)}, allow recycling centers", material); return(true); } // Only allow if there are no restrictions on the request, OR if recycling center resides in an allowed district. var requestDistrictParksServed = Constraints.InputDistrictParkServiced(requestBuilding); var responseDistrictPark = TransferManagerInfo.GetDistrictPark(responseBuilding); if (Constraints.InputAllLocalAreas(requestBuilding) || responseDistrictPark.IsServedBy(requestDistrictParksServed)) { Logger.LogMaterial( $"TransferManager::IsValidLowPriorityOffer: {Utils.ToString(ref responseOffer, material)}, allow recycling centers", material); return(true); } else { return(false); } } // See if the request is from an outside connection ... if (TransferManagerInfo.IsOutsideOffer(ref requestOffer)) { if (TransferManagerInfo.IsOutsideOffer(ref responseOffer)) { // Prevent matching roads that are too close together ... var distanceSquared = Vector3.SqrMagnitude(responseOffer.Position - requestOffer.Position); return(distanceSquared > 100000); } else if (TransferManagerInfo.GetSupplyBuildingAmount(responseBuilding) > Constraints.InternalSupplyBuffer(responseBuilding)) { Logger.LogMaterial( $"TransferManager::IsValidLowPriorityOffer: {Utils.ToString(ref responseOffer, material)}, internal supply buffer, supply amount={TransferManagerInfo.GetSupplyBuildingAmount(responseBuilding)}, supply buffer={Constraints.InternalSupplyBuffer(responseBuilding)}", material); return(true); } else if (Constraints.OutputOutsideConnections(responseBuilding)) { Logger.LogMaterial( $"TransferManager::IsValidLowPriorityOffer: {Utils.ToString(ref responseOffer, material)}, matched inside to outside offer", material); return(true); } else { Logger.LogMaterial( $"TransferManager::IsValidLowPriorityOffer: {Utils.ToString(ref responseOffer, material)}, disallowed outside offer", material); return(false); } } // Here, we are guaranteed that the request is a local offer. if (TransferManagerInfo.IsOutsideBuilding(responseBuilding)) { // Don't be so aggressive in trying to serve low priority orders with outside connections. if (requestPriority > 1 && Constraints.InputOutsideConnections(requestBuilding)) { Logger.LogMaterial( $"TransferManager::IsValidLowPriorityOffer: {Utils.ToString(ref responseOffer, material)}, matched outside to inside offer", material); return(true); } } else if (TransferManagerInfo.GetSupplyBuildingAmount(responseBuilding) > Constraints.InternalSupplyBuffer(responseBuilding)) { // Only allow if the request building allows all incoming shipments if (Constraints.InputAllLocalAreas(requestBuilding)) { Logger.LogMaterial( $"TransferManager::IsValidLowPriorityOffer: {Utils.ToString(ref responseOffer, material)}, internal supply buffer, supply amount={TransferManagerInfo.GetSupplyBuildingAmount(responseBuilding)}, supply buffer={Constraints.InternalSupplyBuffer(responseBuilding)}", material); return(true); } } Logger.LogMaterial( $"TransferManager::IsValidLowPriorityOffer: {Utils.ToString(ref responseOffer, material)}, not valid", material); return(false); }