diff --git a/CustomAI/CustomCargoTruckAI.cs b/CustomAI/CustomCargoTruckAI.cs index 935bb26..e8dd3df 100644 --- a/CustomAI/CustomCargoTruckAI.cs +++ b/CustomAI/CustomCargoTruckAI.cs @@ -23,7 +23,7 @@ public static void CargoTruckAISetSourceForRealConstruction(ushort vehicleID, re } else { - DebugLog.LogToFileOnly("find unknow transfor for SpecialBuilding " + data.m_transferType.ToString()); + DebugLog.LogToFileOnly("find unknown transfer for SpecialBuilding " + data.m_transferType.ToString()); } } } diff --git a/CustomManager/CustomTransferManager.cs b/CustomManager/CustomTransferManager.cs index 3bcb7d0..665987d 100644 --- a/CustomManager/CustomTransferManager.cs +++ b/CustomManager/CustomTransferManager.cs @@ -1,14 +1,18 @@ using ColossalFramework; using ColossalFramework.Plugins; +using HarmonyLib; using RealConstruction.CustomAI; using RealConstruction.NewAI; using RealConstruction.Util; +using System; using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Remoting.Messaging; using UnityEngine; namespace RealConstruction.CustomManager { - public class CustomTransferManager: TransferManager + public class CustomTransferManager : TransferManager { public static bool _init = false; public static void StartSpecialBuildingTransfer(ushort buildingID, ref Building data, TransferManager.TransferReason material, TransferManager.TransferOffer offer) @@ -23,7 +27,6 @@ public static void StartSpecialBuildingTransfer(ushort buildingID, ref Building vehicleInfo = Singleton.instance.GetRandomVehicleInfo(ref Singleton.instance.m_randomizer, ItemClass.Service.Industrial, ItemClass.SubService.IndustrialFarming, ItemClass.Level.Level1); } - if (vehicleInfo != null) { Array16 vehicles = Singleton.instance.m_vehicles; @@ -49,8 +52,7 @@ public static void StartSpecialBuildingTransfer(ushort buildingID, ref Building } } } - - public static void StartTransfer(TransferManager.TransferReason material, TransferManager.TransferOffer offerOut, TransferManager.TransferOffer offerIn, int delta) + public void StartTransfer(TransferManager.TransferReason material, TransferManager.TransferOffer offerOut, TransferManager.TransferOffer offerIn, int delta) { bool offerInActive = offerIn.Active; bool offerOutActive = offerOut.Active; @@ -88,9 +90,14 @@ public static void StartTransfer(TransferManager.TransferReason material, Transf { DebugLog.LogToFileOnly("Error: offerInActive && offerIn.Building"); } + else + { + MethodInfo func = typeof(TransferManager).GetMethod("StartTransfer", BindingFlags.NonPublic | BindingFlags.Instance); + func.Invoke(this, new object[] { material, offerOut, offerIn, delta }); + } } - public static void ForgetFailedBuilding(ushort targetBuilding, int idex) + public static void ForgetFailedBuilding(ushort targetBuilding, int index) { if (RealConstruction.fixUnRouteTransfer) { @@ -102,7 +109,7 @@ public static void ForgetFailedBuilding(ushort targetBuilding, int idex) { //After several times we can refresh fail building list. MainDataStore.canNotConnectedBuildingIDCount[targetBuilding]--; - MainDataStore.canNotConnectedBuildingID[targetBuilding, idex] = MainDataStore.canNotConnectedBuildingID[targetBuilding, MainDataStore.canNotConnectedBuildingIDCount[targetBuilding]]; + MainDataStore.canNotConnectedBuildingID[targetBuilding, index] = MainDataStore.canNotConnectedBuildingID[targetBuilding, MainDataStore.canNotConnectedBuildingIDCount[targetBuilding]]; MainDataStore.canNotConnectedBuildingID[targetBuilding, MainDataStore.canNotConnectedBuildingIDCount[targetBuilding]] = 0; MainDataStore.refreshCanNotConnectedBuildingIDCount[targetBuilding] = 0; } @@ -250,12 +257,13 @@ private static void Init() public static void CustomSimulationStepImpl() { + return; int frameIndex = (int)(Singleton.instance.m_currentFrameIndex & 255u); if (frameIndex == 229) { //construction resource matchoffer MatchOffers((TransferReason)124); - } + } else if (frameIndex == 213) { //operation resource matchoffer @@ -265,8 +273,13 @@ public static void CustomSimulationStepImpl() private static bool CanUseNewMatchOffers(ushort buildingID, TransferReason material) { + if (material == (TransferReason)124) + return true; + if (material == (TransferReason)125) + return true; + //For RealConstruction Mod, always use new matchoffers - return true; + return false; } private static byte MatchOffersMode(TransferReason material) @@ -278,7 +291,7 @@ private static byte MatchOffersMode(TransferReason material) return 0; } - private static void MatchOffers(TransferReason material) + private static void MatchOffers_old(TransferReason material) { if (!_init) { @@ -292,35 +305,35 @@ private static void MatchOffers(TransferReason material) float maxDistance = (distanceMultiplier == 0f) ? 0f : (0.01f / distanceMultiplier); for (int priority = 7; priority >= 0; priority--) { - int offerIdex = (int)material * 8 + priority; - int incomingCount = m_incomingCount[offerIdex]; - int outgoingCount = m_outgoingCount[offerIdex]; - int incomingIdex = 0; - int outgoingIdex = 0; + int offerIndex = (int)material * 8 + priority; + int incomingCount = m_incomingCount[offerIndex]; + int outgoingCount = m_outgoingCount[offerIndex]; + int incomingIndex = 0; + int outgoingIndex = 0; int oldPriority = priority; // NON-STOCK CODE START byte matchOffersMode = MatchOffersMode(material); bool isLoopValid = false; if (matchOffersMode == 2) { - isLoopValid = (incomingIdex < incomingCount || outgoingIdex < outgoingCount); + isLoopValid = (incomingIndex < incomingCount || outgoingIndex < outgoingCount); } else if (matchOffersMode == 1) { - isLoopValid = (outgoingIdex < outgoingCount); + isLoopValid = (outgoingIndex < outgoingCount); } else if (matchOffersMode == 0) { - isLoopValid = (incomingIdex < incomingCount); + isLoopValid = (incomingIndex < incomingCount); } // NON-STOCK CODE END while (isLoopValid) { //use incomingOffer to match outgoingOffer - if (incomingIdex < incomingCount && (matchOffersMode != 1)) + if (incomingIndex < incomingCount && (matchOffersMode != 1)) { - TransferOffer incomingOffer = m_incomingOffers[offerIdex * 256 + incomingIdex]; + TransferOffer incomingOffer = m_incomingOffers[offerIndex * 256 + incomingIndex]; // NON-STOCK CODE START Vector3 incomingPositionNew = Vector3.zero; bool canUseNewMatchOffers = CanUseNewMatchOffers(incomingOffer.Building, material); @@ -356,13 +369,13 @@ private static void MatchOffers(TransferReason material) // NON-STOCK CODE END int incomingPriorityExclude = (!incomingOffer.Exclude) ? incomingPriority : Mathf.Max(0, 3 - priority); int validPriority = -1; - int validOutgoingIdex = -1; + int validOutgoingIndex = -1; float distanceOffsetPre = -1f; - int outgoingIdexInsideIncoming = outgoingIdex; + int outgoingIndexInsideIncoming = outgoingIndex; for (int incomingPriorityInside = priority; incomingPriorityInside >= incomingPriority; incomingPriorityInside--) { - int outgoingIdexWithPriority = (int)material * 8 + incomingPriorityInside; - int outgoingCountWithPriority = m_outgoingCount[outgoingIdexWithPriority]; + int outgoingIndexWithPriority = (int)material * 8 + incomingPriorityInside; + int outgoingCountWithPriority = m_outgoingCount[outgoingIndexWithPriority]; //To let incomingPriorityInsideFloat!=0 float incomingPriorityInsideFloat = (float)incomingPriorityInside + 0.1f; //Higher priority will get more chance to match @@ -372,9 +385,9 @@ private static void MatchOffers(TransferReason material) break; } //Find the nearest offer to match in every priority. - for (int i = outgoingIdexInsideIncoming; i < outgoingCountWithPriority; i++) + for (int i = outgoingIndexInsideIncoming; i < outgoingCountWithPriority; i++) { - TransferOffer outgoingOfferPre = m_outgoingOffers[outgoingIdexWithPriority * 256 + i]; + TransferOffer outgoingOfferPre = m_outgoingOffers[outgoingIndexWithPriority * 256 + i]; if (incomingOffer.m_object != outgoingOfferPre.m_object && (!outgoingOfferPre.Exclude || incomingPriorityInside >= incomingPriorityExclude)) { float incomingOutgoingDistance = Vector3.SqrMagnitude(outgoingOfferPre.Position - incomingPosition); @@ -397,7 +410,7 @@ private static void MatchOffers(TransferReason material) if (!IsUnRoutedMatch(incomingOffer, outgoingOfferPre, material)) { validPriority = incomingPriorityInside; - validOutgoingIdex = i; + validOutgoingIndex = i; currentShortestDistance = incomingOutgoingDistanceNew; } } @@ -407,7 +420,7 @@ private static void MatchOffers(TransferReason material) if ((distanceOffset > distanceOffsetPre) && !canUseNewMatchOffers) { validPriority = incomingPriorityInside; - validOutgoingIdex = i; + validOutgoingIndex = i; distanceOffsetPre = distanceOffset; if ((incomingOutgoingDistance < maxDistance)) { @@ -416,7 +429,7 @@ private static void MatchOffers(TransferReason material) } } } - outgoingIdexInsideIncoming = 0; + outgoingIndexInsideIncoming = 0; } // NON-STOCK CODE START if (canUseNewMatchOffers) @@ -429,23 +442,23 @@ private static void MatchOffers(TransferReason material) break; } //Find a validPriority, get outgoingOffer - int matchedOutgoingOfferIdex = (int)material * 8 + validPriority; - TransferOffer outgoingOffer = m_outgoingOffers[matchedOutgoingOfferIdex * 256 + validOutgoingIdex]; + int matchedOutgoingOfferIndex = (int)material * 8 + validPriority; + TransferOffer outgoingOffer = m_outgoingOffers[matchedOutgoingOfferIndex * 256 + validOutgoingIndex]; int outgoingOfferAmount = outgoingOffer.Amount; int matchedOfferAmount = Mathf.Min(incomingOfferAmount, outgoingOfferAmount); if (matchedOfferAmount != 0) { - StartTransfer(material, outgoingOffer, incomingOffer, matchedOfferAmount); + Singleton.instance.StartTransfer(material, outgoingOffer, incomingOffer, matchedOfferAmount); } incomingOfferAmount -= matchedOfferAmount; outgoingOfferAmount -= matchedOfferAmount; //matched outgoingOffer is empty now if (outgoingOfferAmount == 0) { - int outgoingCountPost = m_outgoingCount[matchedOutgoingOfferIdex] - 1; - m_outgoingCount[matchedOutgoingOfferIdex] = (ushort)outgoingCountPost; - m_outgoingOffers[matchedOutgoingOfferIdex * 256 + validOutgoingIdex] = m_outgoingOffers[matchedOutgoingOfferIdex * 256 + outgoingCountPost]; - if (matchedOutgoingOfferIdex == offerIdex) + int outgoingCountPost = m_outgoingCount[matchedOutgoingOfferIndex] - 1; + m_outgoingCount[matchedOutgoingOfferIndex] = (ushort)outgoingCountPost; + m_outgoingOffers[matchedOutgoingOfferIndex * 256 + validOutgoingIndex] = m_outgoingOffers[matchedOutgoingOfferIndex * 256 + outgoingCountPost]; + if (matchedOutgoingOfferIndex == offerIndex) { outgoingCount = outgoingCountPost; } @@ -453,7 +466,7 @@ private static void MatchOffers(TransferReason material) else { outgoingOffer.Amount = outgoingOfferAmount; - m_outgoingOffers[matchedOutgoingOfferIdex * 256 + validOutgoingIdex] = outgoingOffer; + m_outgoingOffers[matchedOutgoingOfferIndex * 256 + validOutgoingIndex] = outgoingOffer; } incomingOffer.Amount = incomingOfferAmount; } @@ -462,21 +475,21 @@ private static void MatchOffers(TransferReason material) if (incomingOfferAmount == 0) { incomingCount--; - m_incomingCount[offerIdex] = (ushort)incomingCount; - m_incomingOffers[offerIdex * 256 + incomingIdex] = m_incomingOffers[offerIdex * 256 + incomingCount]; + m_incomingCount[offerIndex] = (ushort)incomingCount; + m_incomingOffers[offerIndex * 256 + incomingIndex] = m_incomingOffers[offerIndex * 256 + incomingCount]; } else { incomingOffer.Amount = incomingOfferAmount; - m_incomingOffers[offerIdex * 256 + incomingIdex] = incomingOffer; - incomingIdex++; + m_incomingOffers[offerIndex * 256 + incomingIndex] = incomingOffer; + incomingIndex++; } } //For RealConstruction, We only satisify incoming building //use outgoingOffer to match incomingOffer - if (outgoingIdex < outgoingCount && (matchOffersMode != 0)) + if (outgoingIndex < outgoingCount && (matchOffersMode != 0)) { - TransferOffer outgoingOffer = m_outgoingOffers[offerIdex * 256 + outgoingIdex]; + TransferOffer outgoingOffer = m_outgoingOffers[offerIndex * 256 + outgoingIndex]; // NON-STOCK CODE START bool canUseNewMatchOffers = CanUseNewMatchOffers(outgoingOffer.Building, material); Vector3 outgoingPositionNew = Vector3.zero; @@ -512,13 +525,13 @@ private static void MatchOffers(TransferReason material) // NON-STOCK CODE END int outgoingPriorityExclude = (!outgoingOffer.Exclude) ? outgoingPriority : Mathf.Max(0, 3 - priority); int validPriority = -1; - int validIncomingIdex = -1; + int validIncomingIndex = -1; float distanceOffsetPre = -1f; - int incomingIdexInsideOutgoing = incomingIdex; + int incomingIndexInsideOutgoing = incomingIndex; for (int outgoingPriorityInside = priority; outgoingPriorityInside >= outgoingPriority; outgoingPriorityInside--) { - int incomingIdexWithPriority = (int)material * 8 + outgoingPriorityInside; - int incomingCountWithPriority = m_incomingCount[incomingIdexWithPriority]; + int incomingIndexWithPriority = (int)material * 8 + outgoingPriorityInside; + int incomingCountWithPriority = m_incomingCount[incomingIndexWithPriority]; //To let outgoingPriorityInsideFloat!=0 float outgoingPriorityInsideFloat = (float)outgoingPriorityInside + 0.1f; //Higher priority will get more chance to match @@ -526,9 +539,9 @@ private static void MatchOffers(TransferReason material) { break; } - for (int j = incomingIdexInsideOutgoing; j < incomingCountWithPriority; j++) + for (int j = incomingIndexInsideOutgoing; j < incomingCountWithPriority; j++) { - TransferOffer incomingOfferPre = m_incomingOffers[incomingIdexWithPriority * 256 + j]; + TransferOffer incomingOfferPre = m_incomingOffers[incomingIndexWithPriority * 256 + j]; if (outgoingOffer.m_object != incomingOfferPre.m_object && (!incomingOfferPre.Exclude || outgoingPriorityInside >= outgoingPriorityExclude)) { float incomingOutgoingDistance = Vector3.SqrMagnitude(incomingOfferPre.Position - outgoingPosition); @@ -551,7 +564,7 @@ private static void MatchOffers(TransferReason material) if (!IsUnRoutedMatch(incomingOfferPre, outgoingOffer, material)) { validPriority = outgoingPriorityInside; - validIncomingIdex = j; + validIncomingIndex = j; currentShortestDistance = incomingOutgoingDistanceNew; } } @@ -561,7 +574,7 @@ private static void MatchOffers(TransferReason material) if ((distanceOffset > distanceOffsetPre) && !canUseNewMatchOffers) { validPriority = outgoingPriorityInside; - validIncomingIdex = j; + validIncomingIndex = j; distanceOffsetPre = distanceOffset; if (incomingOutgoingDistance < maxDistance) { @@ -570,7 +583,7 @@ private static void MatchOffers(TransferReason material) } } } - incomingIdexInsideOutgoing = 0; + incomingIndexInsideOutgoing = 0; } // NON-STOCK CODE START if (canUseNewMatchOffers) @@ -583,23 +596,23 @@ private static void MatchOffers(TransferReason material) break; } //Find a validPriority, get incomingOffer - int matchedIncomingOfferIdex = (int)material * 8 + validPriority; - TransferOffer incomingOffers = m_incomingOffers[matchedIncomingOfferIdex * 256 + validIncomingIdex]; + int matchedIncomingOfferIndex = (int)material * 8 + validPriority; + TransferOffer incomingOffers = m_incomingOffers[matchedIncomingOfferIndex * 256 + validIncomingIndex]; int incomingOffersAmount = incomingOffers.Amount; int matchedOfferAmount = Mathf.Min(outgoingOfferAmount, incomingOffersAmount); if (matchedOfferAmount != 0) { - StartTransfer(material, outgoingOffer, incomingOffers, matchedOfferAmount); + Singleton.instance.StartTransfer(material, outgoingOffer, incomingOffers, matchedOfferAmount); } outgoingOfferAmount -= matchedOfferAmount; incomingOffersAmount -= matchedOfferAmount; //matched incomingOffer is empty now if (incomingOffersAmount == 0) { - int incomingCountPost = m_incomingCount[matchedIncomingOfferIdex] - 1; - m_incomingCount[matchedIncomingOfferIdex] = (ushort)incomingCountPost; - m_incomingOffers[matchedIncomingOfferIdex * 256 + validIncomingIdex] = m_incomingOffers[matchedIncomingOfferIdex * 256 + incomingCountPost]; - if (matchedIncomingOfferIdex == offerIdex) + int incomingCountPost = m_incomingCount[matchedIncomingOfferIndex] - 1; + m_incomingCount[matchedIncomingOfferIndex] = (ushort)incomingCountPost; + m_incomingOffers[matchedIncomingOfferIndex * 256 + validIncomingIndex] = m_incomingOffers[matchedIncomingOfferIndex * 256 + incomingCountPost]; + if (matchedIncomingOfferIndex == offerIndex) { incomingCount = incomingCountPost; } @@ -607,7 +620,7 @@ private static void MatchOffers(TransferReason material) else { incomingOffers.Amount = incomingOffersAmount; - m_incomingOffers[matchedIncomingOfferIdex * 256 + validIncomingIdex] = incomingOffers; + m_incomingOffers[matchedIncomingOfferIndex * 256 + validIncomingIndex] = incomingOffers; } outgoingOffer.Amount = outgoingOfferAmount; } @@ -616,29 +629,29 @@ private static void MatchOffers(TransferReason material) if (outgoingOfferAmount == 0) { outgoingCount--; - m_outgoingCount[offerIdex] = (ushort)outgoingCount; - m_outgoingOffers[offerIdex * 256 + outgoingIdex] = m_outgoingOffers[offerIdex * 256 + outgoingCount]; + m_outgoingCount[offerIndex] = (ushort)outgoingCount; + m_outgoingOffers[offerIndex * 256 + outgoingIndex] = m_outgoingOffers[offerIndex * 256 + outgoingCount]; } else { outgoingOffer.Amount = outgoingOfferAmount; - m_outgoingOffers[offerIdex * 256 + outgoingIdex] = outgoingOffer; - outgoingIdex++; + m_outgoingOffers[offerIndex * 256 + outgoingIndex] = outgoingOffer; + outgoingIndex++; } } // NON-STOCK CODE START if (matchOffersMode == 2) { - isLoopValid = (incomingIdex < incomingCount || outgoingIdex < outgoingCount); + isLoopValid = (incomingIndex < incomingCount || outgoingIndex < outgoingCount); } else if (matchOffersMode == 1) { - isLoopValid = (outgoingIdex < outgoingCount); + isLoopValid = (outgoingIndex < outgoingCount); } else if (matchOffersMode == 0) { - isLoopValid = (incomingIdex < incomingCount); + isLoopValid = (incomingIndex < incomingCount); } // NON-STOCK CODE END } @@ -653,5 +666,432 @@ private static void MatchOffers(TransferReason material) m_outgoingAmount[(int)material] = 0; } } + + [MethodImpl(512)] //=[MethodImpl(MethodImplOptions.AggressiveOptimization)] + private static void MatchOffers(TransferManager.TransferReason material) + { + //-------------------------------------------------- + // BEGIN + if (!_init) + { + Init(); + _init = true; + } + // END + //-------------------------------------------------- + + if (material == TransferReason.None) + { + return; + } +#if true + MethodInfo func = typeof(TransferManager).GetMethod("GetDistanceMultiplier", BindingFlags.NonPublic | BindingFlags.Static); + float distanceMultiplier = (float)func.Invoke(null, new object[] { material }); +#else + float distanceMultiplier = GetDistanceMultiplier(material); +#endif + float maxDistance = ((distanceMultiplier == 0f) ? 0f : (0.01f / distanceMultiplier)); + for (int priority = 7; priority >= 0; priority--) + { + int offerIndex = (int)material * 8 + priority; + int incomingCount = m_incomingCount[offerIndex]; + int outgoingCount = m_outgoingCount[offerIndex]; + int incomingIndex = 0; + int outgoingIndex = 0; + int oldPriority = priority; + + while (incomingIndex < incomingCount || outgoingIndex < outgoingCount) + { + // use incomingOffer to match outgoingOffer + if (incomingIndex < incomingCount) + { + TransferOffer incomingOffer = m_incomingOffers[offerIndex * 256 + incomingIndex]; + + //-------------------------------------------------- + // BEGIN + Vector3 incomingPositionNew = Vector3.zero; + bool canUseNewMatchOffers = CanUseNewMatchOffers(incomingOffer.Building, material); + if (canUseNewMatchOffers) + { + if (Singleton.instance.m_buildings.m_buffer[incomingOffer.Building].m_flags.IsFlagSet(Building.Flags.Untouchable)) + { + incomingPositionNew = Singleton.instance.m_buildings.m_buffer[incomingOffer.Building].m_position; + } + else + { + incomingPositionNew = incomingOffer.Position; + } + } + // END + //-------------------------------------------------- + + Vector3 incomingPosition = incomingOffer.Position; + int incomingOfferAmount = incomingOffer.Amount; + do + { + int incomingPriority = Mathf.Max(0, 2 - priority); + + //-------------------------------------------------- + // BEGIN + float currentShortestDistance = -1f; + if (canUseNewMatchOffers) + { + priority = 7; + incomingPriority = 0; + } + else + { + priority = oldPriority; + incomingPriority = Mathf.Max(0, 2 - priority); + } + // END + //-------------------------------------------------- + + int incomingPriorityExclude = ((!incomingOffer.Exclude) ? incomingPriority : Mathf.Max(0, 3 - priority)); + int validPriority = -1; + int validOutgoingIndex = -1; + float distanceOffsetPre = -1f; + int outgoingIndexInsideIncoming = outgoingIndex; + for (int incomingPriorityInside = priority; incomingPriorityInside >= incomingPriority; incomingPriorityInside--) + { + int outgoingIndexWithPriority = (int)material * 8 + incomingPriorityInside; + int outgoingCountWithPriority = m_outgoingCount[outgoingIndexWithPriority]; + // To let incomingPriorityInsideFloat != 0 + float incomingPriorityInsideFloat = (float)incomingPriorityInside + 0.1f; + + // Higher priority will get more chance to match + // UseNewMatchOffers to find the shortest transfer building +#if true + if (distanceOffsetPre >= incomingPriorityInsideFloat && !canUseNewMatchOffers) + { + break; + } +#else + if (distanceOffsetPre >= incomingPriorityInsideFloat) + { + break; + } +#endif + // Find the nearest offer to match in every priority. + for (int i = outgoingIndexInsideIncoming; i < outgoingCountWithPriority; i++) + { + TransferOffer outgoingOfferPre = m_outgoingOffers[outgoingIndexWithPriority * 256 + i]; + if (!(incomingOffer.m_object != outgoingOfferPre.m_object) || incomingOffer.m_isLocalPark != outgoingOfferPre.m_isLocalPark || (outgoingOfferPre.Exclude && incomingPriorityInside < incomingPriorityExclude)) + { + continue; + } + + float incomingOutgoingDistance = Vector3.SqrMagnitude(outgoingOfferPre.Position - incomingPosition); + + //-------------------------------------------------- + // BEGIN + Vector3 outgoingPositionNew = Vector3.zero; + float incomingOutgoingDistanceNew = 0; + if (canUseNewMatchOffers) + { + if (Singleton.instance.m_buildings.m_buffer[outgoingOfferPre.Building].m_flags.IsFlagSet(Building.Flags.Untouchable)) + { + outgoingPositionNew = Singleton.instance.m_buildings.m_buffer[outgoingOfferPre.Building].m_position; + } + else + { + outgoingPositionNew = outgoingOfferPre.Position; + } + incomingOutgoingDistanceNew = Vector3.SqrMagnitude(outgoingPositionNew - incomingPositionNew); + if ((incomingOutgoingDistanceNew < currentShortestDistance) || currentShortestDistance == -1) + { + if (!IsUnRoutedMatch(incomingOffer, outgoingOfferPre, material)) + { + validPriority = incomingPriorityInside; + validOutgoingIndex = i; + currentShortestDistance = incomingOutgoingDistanceNew; + } + } + } + // END + //-------------------------------------------------- + + float distanceOffset = ((!(distanceMultiplier < 0f)) ? (incomingPriorityInsideFloat / (1f + incomingOutgoingDistance * distanceMultiplier)) : (incomingPriorityInsideFloat - incomingPriorityInsideFloat / (1f - incomingOutgoingDistance * distanceMultiplier))); + if (distanceOffset > distanceOffsetPre) + { + validPriority = incomingPriorityInside; + validOutgoingIndex = i; + distanceOffsetPre = distanceOffset; + if (incomingOutgoingDistance < maxDistance) + { + break; + } + } + } + + outgoingIndexInsideIncoming = 0; + } + + //-------------------------------------------------- + // BEGIN + if (canUseNewMatchOffers) + { + priority = oldPriority; + } + // END + //-------------------------------------------------- + + if (validPriority == -1) + { + break; + } + + // Find a validPriority, get outgoingOffer + int matchedOutgoingOfferIndex = (int)material * 8 + validPriority; + TransferOffer outgoingOffer = m_outgoingOffers[matchedOutgoingOfferIndex * 256 + validOutgoingIndex]; + int outgoingOfferAmount = outgoingOffer.Amount; + int matchedOfferAmount = ((!incomingOffer.Unlimited || !outgoingOffer.Unlimited) ? Mathf.Min(incomingOfferAmount, outgoingOfferAmount) : Mathf.Max(incomingOfferAmount, outgoingOfferAmount)); + if (matchedOfferAmount != 0) + { + Singleton.instance.StartTransfer(material, outgoingOffer, incomingOffer, matchedOfferAmount); + } + + incomingOfferAmount = Math.Max(incomingOfferAmount - matchedOfferAmount, 0); + outgoingOfferAmount = Math.Max(outgoingOfferAmount - matchedOfferAmount, 0); + + // matched outgoingOffer is empty now + if (outgoingOfferAmount == 0) + { + int outgoingCountPost = m_outgoingCount[matchedOutgoingOfferIndex] - 1; + m_outgoingCount[matchedOutgoingOfferIndex] = (ushort)outgoingCountPost; + m_outgoingOffers[matchedOutgoingOfferIndex * 256 + validOutgoingIndex] = m_outgoingOffers[matchedOutgoingOfferIndex * 256 + outgoingCountPost]; + if (matchedOutgoingOfferIndex == offerIndex) + { + outgoingCount = outgoingCountPost; + } + } + else + { + outgoingOffer.Amount = outgoingOfferAmount; + m_outgoingOffers[matchedOutgoingOfferIndex * 256 + validOutgoingIndex] = outgoingOffer; + } + + incomingOffer.Amount = incomingOfferAmount; + } + while (incomingOfferAmount != 0); + + // matched incomingOffer is empty now + if (incomingOfferAmount == 0) + { + incomingCount--; + m_incomingCount[offerIndex] = (ushort)incomingCount; + m_incomingOffers[offerIndex * 256 + incomingIndex] = m_incomingOffers[offerIndex * 256 + incomingCount]; + } + else + { + incomingOffer.Amount = incomingOfferAmount; + m_incomingOffers[offerIndex * 256 + incomingIndex] = incomingOffer; + incomingIndex++; + } + } + + // For RealConstruction, We only satisify incoming building + // use outgoingOffer to match incomingOffer + if (outgoingIndex >= outgoingCount) + { + continue; + } + + { + TransferOffer outgoingOffer = m_outgoingOffers[offerIndex * 256 + outgoingIndex]; + + //-------------------------------------------------- + // BEGIN + bool canUseNewMatchOffers = CanUseNewMatchOffers(outgoingOffer.Building, material); + Vector3 outgoingPositionNew = Vector3.zero; + if (canUseNewMatchOffers) + { + if (Singleton.instance.m_buildings.m_buffer[outgoingOffer.Building].m_flags.IsFlagSet(Building.Flags.Untouchable)) + { + outgoingPositionNew = Singleton.instance.m_buildings.m_buffer[outgoingOffer.Building].m_position; + } + else + { + outgoingPositionNew = outgoingOffer.Position; + } + } + // END + //-------------------------------------------------- + + Vector3 outgoingPosition = outgoingOffer.Position; + int outgoingOfferAmount = outgoingOffer.Amount; + do + { + int outgoingPriority = Mathf.Max(0, 2 - priority); + + //-------------------------------------------------- + // BEGIN + float currentShortestDistance = -1f; + if (canUseNewMatchOffers) + { + priority = 7; + outgoingPriority = 0; + } + else + { + priority = oldPriority; + outgoingPriority = Mathf.Max(0, 2 - priority); + } + // END + //-------------------------------------------------- + + + int outgoingPriorityExclude = ((!outgoingOffer.Exclude) ? outgoingPriority : Mathf.Max(0, 3 - priority)); + int validPriority = -1; + int validIncomingIndex = -1; + float distanceOffsetPre = -1f; + int incomingIndexInsideOutgoing = incomingIndex; + for (int outgoingPriorityInside = priority; outgoingPriorityInside >= outgoingPriority; outgoingPriorityInside--) + { + int incomingIndexWithPriority = (int)material * 8 + outgoingPriorityInside; + int incomingCountWithPriority = m_incomingCount[incomingIndexWithPriority]; + // To let outgoingPriorityInsideFloat != 0 + float outgoingPriorityInsideFloat = (float)outgoingPriorityInside + 0.1f; + // Higher priority will get more chance to match +#if true + if (distanceOffsetPre >= outgoingPriorityInsideFloat && !canUseNewMatchOffers) + { + break; + } +#else + if (distanceOffsetPre >= outgoingPriorityInsideFloat) + { + break; + } +#endif + for (int j = incomingIndexInsideOutgoing; j < incomingCountWithPriority; j++) + { + TransferOffer incomingOfferPre = m_incomingOffers[incomingIndexWithPriority * 256 + j]; + if (!(outgoingOffer.m_object != incomingOfferPre.m_object) || outgoingOffer.m_isLocalPark != incomingOfferPre.m_isLocalPark || (incomingOfferPre.Exclude && outgoingPriorityInside < outgoingPriorityExclude)) + { + continue; + } + + float incomingOutgoingDistance = Vector3.SqrMagnitude(incomingOfferPre.Position - outgoingPosition); + + //-------------------------------------------------- + // BEGIN + Vector3 incomingPositionNew = Vector3.zero; + float incomingOutgoingDistanceNew = 0; + if (canUseNewMatchOffers) + { + if (Singleton.instance.m_buildings.m_buffer[incomingOfferPre.Building].m_flags.IsFlagSet(Building.Flags.Untouchable)) + { + incomingPositionNew = Singleton.instance.m_buildings.m_buffer[incomingOfferPre.Building].m_position; + } + else + { + incomingPositionNew = incomingOfferPre.Position; + } + incomingOutgoingDistanceNew = Vector3.SqrMagnitude(outgoingPositionNew - incomingPositionNew); + if ((incomingOutgoingDistanceNew < currentShortestDistance) || currentShortestDistance == -1) + { + if (!IsUnRoutedMatch(incomingOfferPre, outgoingOffer, material)) + { + validPriority = outgoingPriorityInside; + validIncomingIndex = j; + currentShortestDistance = incomingOutgoingDistanceNew; + } + } + } + // END + //-------------------------------------------------- + + float distanceOffset = ((!(distanceMultiplier < 0f)) ? (outgoingPriorityInsideFloat / (1f + incomingOutgoingDistance * distanceMultiplier)) : (outgoingPriorityInsideFloat - outgoingPriorityInsideFloat / (1f - incomingOutgoingDistance * distanceMultiplier))); + if (distanceOffset > distanceOffsetPre) + { + validPriority = outgoingPriorityInside; + validIncomingIndex = j; + distanceOffsetPre = distanceOffset; + if (incomingOutgoingDistance < maxDistance) + { + break; + } + } + } + + incomingIndexInsideOutgoing = 0; + } + + //-------------------------------------------------- + // BEGIN + if (canUseNewMatchOffers) + { + priority = oldPriority; + } + // END + //-------------------------------------------------- + + if (validPriority == -1) + { + break; + } + + // Find a validPriority, get incomingOffer + int matchedIncomingOfferIndex = (int)material * 8 + validPriority; + TransferOffer incomingOffers = m_incomingOffers[matchedIncomingOfferIndex * 256 + validIncomingIndex]; + int incomingOffersAmount = incomingOffers.Amount; + int matchedOfferAmount = ((!outgoingOffer.Unlimited || !incomingOffers.Unlimited) ? Mathf.Min(outgoingOfferAmount, incomingOffersAmount) : Mathf.Max(outgoingOfferAmount, incomingOffersAmount)); + if (matchedOfferAmount != 0) + { + Singleton.instance.StartTransfer(material, outgoingOffer, incomingOffers, matchedOfferAmount); + } + + outgoingOfferAmount = Math.Max(outgoingOfferAmount - matchedOfferAmount, 0); + incomingOffersAmount = Math.Max(incomingOffersAmount - matchedOfferAmount, 0); + + // matched incomingOffer is empty now + if (incomingOffersAmount == 0) + { + int incomingCountPost = m_incomingCount[matchedIncomingOfferIndex] - 1; + m_incomingCount[matchedIncomingOfferIndex] = (ushort)incomingCountPost; + m_incomingOffers[matchedIncomingOfferIndex * 256 + validIncomingIndex] = m_incomingOffers[matchedIncomingOfferIndex * 256 + incomingCountPost]; + if (matchedIncomingOfferIndex == offerIndex) + { + incomingCount = incomingCountPost; + } + } + else + { + incomingOffers.Amount = incomingOffersAmount; + m_incomingOffers[matchedIncomingOfferIndex * 256 + validIncomingIndex] = incomingOffers; + } + + outgoingOffer.Amount = outgoingOfferAmount; + } + while (outgoingOfferAmount != 0); + + // matched outgoingOffer is empty now + if (outgoingOfferAmount == 0) + { + outgoingCount--; + m_outgoingCount[offerIndex] = (ushort)outgoingCount; + m_outgoingOffers[offerIndex * 256 + outgoingIndex] = m_outgoingOffers[offerIndex * 256 + outgoingCount]; + } + else + { + outgoingOffer.Amount = outgoingOfferAmount; + m_outgoingOffers[offerIndex * 256 + outgoingIndex] = outgoingOffer; + outgoingIndex++; + } + } + } + } + + for (int k = 0; k < 8; k++) + { + int index = (int)material * 8 + k; + m_incomingCount[index] = 0; + m_outgoingCount[index] = 0; + } + + m_incomingAmount[(int)material] = 0; + m_outgoingAmount[(int)material] = 0; + } } } diff --git a/Loader.cs b/Loader.cs index 266ae53..e4e5174 100644 --- a/Loader.cs +++ b/Loader.cs @@ -46,7 +46,9 @@ public override void OnLevelLoaded(LoadMode mode) HarmonyInitDetour(); SetupGui(); SetupLocalization(); - isRealCityRunning = CheckRealCityIsLoaded(); + + // [RealCity] Disable it temporarily. Will support "RealCity Revised" in the future. + // isRealCityRunning = CheckRealCityIsLoaded(); RealConstruction.LoadSetting(); if (mode == LoadMode.NewGame) diff --git a/Locales/de.txt b/Locales/de.txt new file mode 100644 index 0000000..94697b9 --- /dev/null +++ b/Locales/de.txt @@ -0,0 +1,24 @@ +FOOD_STORED Lebensmittel +LUMBER_STORED Holz +COAL_STORED Kohle +PETROL_STORED Erdöl +CONSTRUCTION_RESOURCE Baumaterial +OPERATION_RESOURCE Betriebsmittel +OPERATION_RESOURCE_LEFT Überschüssige Betriebsmittel +TRANSFER_CONSTRUCTION_RESOURCE_TO Liefere Baumaterial nach +TRANSFER_OPERATION_RESOURCE_TO Liefere Betriebsmittel an +GOING_FOR_FUEL_TO Auf dem Weg zur Tankstelle in +BUILDING_TYPE Gebäude Funktion +NORMAL_BUILDING Normales Gebäude +GENERATE_BOTH_RESOURCES Beide Ressourcen produzieren +GENERATE_CONSTRUCTION_RESOURCES Produziere Baumaterial +GENERATE_OPERATION_RESOURCES Produziere Betriebsmittel +NONEED_RESOURCE Kein Bedarf an Ressourcen +DEBUG_MODE Debug UI +SHOW_LACK_OF_RESOURCE Symbolen über Gebäuden anzeigen, wenn Bau-oder Betriebsstoffe knapp sind. +FIX_UNROUTED_TRANSFER_MATCH_DESCRIPTION Wenn ein Gebiet von Straßenverbindungen in andere Gebiete isoliert ist +FIX_UNROUTED_TRANSFER_MATCH_ENALBE Reparieren Sie den unverbundenen Transport. +OPERATION_RESOURCE_CONSUMPTION Betriebsmittelverbrauchsgeschwindigkeit +NORMAL Normal +HALF Halb +NONE Keine diff --git a/Locales/es.txt b/Locales/es.txt new file mode 100644 index 0000000..834a461 --- /dev/null +++ b/Locales/es.txt @@ -0,0 +1,24 @@ +FOOD_STORED alimentos +LUMBER_STORED madera +COAL_STORED mineral +PETROL_STORED petróleo +CONSTRUCTION_RESOURCE materiales de construcción +OPERATION_RESOURCE recursos operativos +OPERATION_RESOURCE_LEFT exceso de recursos de explotación +TRANSFER_CONSTRUCTION_RESOURCE_TO Transporte de materiales de construcción +TRANSFER_OPERATION_RESOURCE_TO Recursos operativos de transporte +GOING_FOR_FUEL_TO De camino a la gasolinera +BUILDING_TYPE Función del edificio +NORMAL_BUILDING Edificio normal +GENERATE_BOTH_RESOURCES Produciendo ambas cosas. +GENERATE_CONSTRUCTION_RESOURCES Sólo materiales de construcción +GENERATE_OPERATION_RESOURCES Producir sólo recursos operativos. +NONEED_RESOURCE sin recursos +DEBUG_MODE Interfaz de depuración +SHOW_LACK_OF_RESOURCE Mostrar iconos en los edificios cuando los recursos son escasos. +FIX_UNROUTED_TRANSFER_MATCH_DESCRIPTION Fijar el transporte no conectado cuando se aísla de una conexión por carretera. +FIX_UNROUTED_TRANSFER_MATCH_ENALBE Arreglar transporte desconectado. +OPERATION_RESOURCE_CONSUMPTION Tasa de consumo de recursos operativos +NORMAL Habitual +HALF Medio +NONE Ninguno \ No newline at end of file diff --git a/Locales/fr.txt b/Locales/fr.txt new file mode 100644 index 0000000..9579e59 --- /dev/null +++ b/Locales/fr.txt @@ -0,0 +1,24 @@ +FOOD_STORED nourriture +LUMBER_STORED Bois +COAL_STORED Charbon +PETROL_STORED Pétrole +CONSTRUCTION_RESOURCE Ressources pour la construction +OPERATION_RESOURCE Ressources opérationnelles +OPERATION_RESOURCE_LEFT Ressources opérationnelles excédentaires +TRANSFER_CONSTRUCTION_RESOURCE_TO Transport de matériaux de construction +TRANSFER_OPERATION_RESOURCE_TO Transport des ressources opérationnelles. +GOING_FOR_FUEL_TO Sur le chemin de la station-service +BUILDING_TYPE Fonction du bâtiment +NORMAL_BUILDING Bâtiment normal +GENERATE_BOTH_RESOURCES Produire les deux ressources +GENERATE_CONSTRUCTION_RESOURCES Produce Construction Resources +GENERATE_OPERATION_RESOURCES Produire des ressources de construction +NONEED_RESOURCE Pas de ressources nécessaires +DEBUG_MODE Debug UI +SHOW_LACK_OF_RESOURCE Afficher des icônes sur les bâtiments en cas de pénurie de ressources. +FIX_UNROUTED_TRANSFER_MATCH_DESCRIPTION Lorsqu'ils sont isolés des connexions routières dans d'autres zones +FIX_UNROUTED_TRANSFER_MATCH_ENALBE Correction des transports non connectés. +OPERATION_RESOURCE_CONSUMPTION Opération ressource consommation vitesse +NORMAL Habituel +HALF La moitié +NONE Aucun \ No newline at end of file diff --git a/Locales/ja.txt b/Locales/ja.txt new file mode 100644 index 0000000..756916e --- /dev/null +++ b/Locales/ja.txt @@ -0,0 +1,24 @@ +FOOD_STORED 食料品 +LUMBER_STORED 材木 +COAL_STORED 鉱石 +PETROL_STORED 石油 +CONSTRUCTION_RESOURCE 建設資材 +OPERATION_RESOURCE 運営資材 +OPERATION_RESOURCE_LEFT 余剰運営資材 +TRANSFER_CONSTRUCTION_RESOURCE_TO 建設資材を輸送 +TRANSFER_OPERATION_RESOURCE_TO 運営資材を輸送 +GOING_FOR_FUEL_TO ガソリンスタンドへ行く途中 +BUILDING_TYPE 建築タイプ +NORMAL_BUILDING 通常建築 +GENERATE_BOTH_RESOURCES 両方を生産 +GENERATE_CONSTRUCTION_RESOURCES 建設資材の生産のみ +GENERATE_OPERATION_RESOURCES 運営資材の生産のみ +NONEED_RESOURCE 資材不要 +DEBUG_MODE デバッグUI +SHOW_LACK_OF_RESOURCE 建設や運営の資材が不足している場合に建物に資源不足のアイコンを表示する +FIX_UNROUTED_TRANSFER_MATCH_DESCRIPTION 他のエリアの道路接続から孤立している場合に未接続の輸送を修正する +FIX_UNROUTED_TRANSFER_MATCH_ENALBE 未接続の輸送を修正 +OPERATION_RESOURCE_CONSUMPTION 運営資材の消費速度 +NORMAL 通常 +HALF 半分 +NONE なし \ No newline at end of file diff --git a/Locales/pl.txt b/Locales/pl.txt new file mode 100644 index 0000000..eda4fa2 --- /dev/null +++ b/Locales/pl.txt @@ -0,0 +1,24 @@ +FOOD_STORED Żywność +LUMBER_STORED Tarcica +COAL_STORED Węgiel +PETROL_STORED Benzyna +CONSTRUCTION_RESOURCE Zasoby budowlane +OPERATION_RESOURCE Zasoby operacyjne +OPERATION_RESOURCE_LEFT nadmiar zasobów operacyjnych +TRANSFER_CONSTRUCTION_RESOURCE_TO Transport materiałów budowlanych +TRANSFER_OPERATION_RESOURCE_TO Transport środków operacyjnych. +GOING_FOR_FUEL_TO W drodze na stację benzynową +BUILDING_TYPE Rodzaj budynku +NORMAL_BUILDING Normalny budynek +GENERATE_BOTH_RESOURCES Produkuj oba zasoby +GENERATE_CONSTRUCTION_RESOURCES Produkuj zasoby budowlane +GENERATE_OPERATION_RESOURCES Produkuj zasoby operacyjne +NONEED_RESOURCE Nie potrzeba zasobów +DEBUG_MODE Debug UI +SHOW_LACK_OF_RESOURCE Pokaż ikonę braku zasobów na budynkach, gdy brakuje zasobów budowlanych lub operacyjnych. +FIX_UNROUTED_TRANSFER_MATCH_DESCRIPTION W przypadku odizolowania od innych połączeń drogowych obszaru. +FIX_UNROUTED_TRANSFER_MATCH_ENALBE Naprawić niepołączony transport. +OPERATION_RESOURCE_CONSUMPTION Działanie zużycie zasobów szybkość +NORMAL Normalna +HALF Pół +NONE Bez \ No newline at end of file diff --git a/Locales/pt.txt b/Locales/pt.txt new file mode 100644 index 0000000..8b8010d --- /dev/null +++ b/Locales/pt.txt @@ -0,0 +1,24 @@ +FOOD_STORED Alimentos +LUMBER_STORED Madeira +COAL_STORED Minério +PETROL_STORED Petróleo +CONSTRUCTION_RESOURCE Recursos de construção +OPERATION_RESOURCE Recursos operacionais +OPERATION_RESOURCE_LEFT Recursos operacionais excedentes +TRANSFER_CONSTRUCTION_RESOURCE_TO Transporte de recursos de construção +TRANSFER_OPERATION_RESOURCE_TO Transporte de recursos operacionais. +GOING_FOR_FUEL_TO No caminho para o posto de gasolina +BUILDING_TYPE Tipo de edifício +NORMAL_BUILDING Edifício normal +GENERATE_BOTH_RESOURCES Produzir ambos os recursos +GENERATE_CONSTRUCTION_RESOURCES Produzir recursos de construção +GENERATE_OPERATION_RESOURCES Produzir recursos operacionais +NONEED_RESOURCE Não há necessidade de recursos +DEBUG_MODE UI de depuração +SHOW_LACK_OF_RESOURCE Exibir ícones nos edifícios quando houver escassez de recursos. +FIX_UNROUTED_TRANSFER_MATCH_DESCRIPTION Quando isolado de outras conexões rodoviárias da área +FIX_UNROUTED_TRANSFER_MATCH_ENALBE Correção de transporte não conectado. +OPERATION_RESOURCE_CONSUMPTION Velocidade de consumo de recursos de operação +NORMAL Normais +HALF Metade +NONE Nenhum diff --git a/Patch/MatchOffersPatch.cs b/Patch/MatchOffersPatch.cs new file mode 100644 index 0000000..1706a1a --- /dev/null +++ b/Patch/MatchOffersPatch.cs @@ -0,0 +1,30 @@ +using ColossalFramework; +using HarmonyLib; +using RealConstruction.CustomManager; +using RealConstruction.Util; +using System.Reflection; +using static ItemClass; + +namespace RealConstruction.Patch +{ + [HarmonyPatch] + public class MatchOffersPatch + { + public static MethodBase TargetMethod() + { + return typeof(TransferManager).GetMethod("MatchOffers", BindingFlags.NonPublic | BindingFlags.Instance); + } + + // Specify the order of execution, since this mod will not work if TransferManagerCE is executed first. + [HarmonyBefore(new string[] { "Sleepy.TransferManagerCE" })] + public static void Prefix(TransferManager.TransferReason material) + { + if (material == (TransferManager.TransferReason)124 || + material == (TransferManager.TransferReason)125) + { + MethodInfo func = typeof(CustomTransferManager).GetMethod("MatchOffers", BindingFlags.NonPublic | BindingFlags.Static); + func.Invoke(null, new object[] { material }); + } + } + } +} diff --git a/Patch/PlayerBuildingAISimulationStepPatch.cs b/Patch/PlayerBuildingAISimulationStepPatch.cs index 92e1732..1ff9642 100644 --- a/Patch/PlayerBuildingAISimulationStepPatch.cs +++ b/Patch/PlayerBuildingAISimulationStepPatch.cs @@ -71,7 +71,7 @@ public static void Postfix(ushort buildingID, ref Building buildingData, ref Bui if (CustomPlayerBuildingAI.CanRemoveNoResource(buildingID, ref buildingData)) { - Notification.Problem problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem.NoResources); + Notification.Problem1 problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem1.NoResources); buildingData.m_problems = problem; } } @@ -80,9 +80,9 @@ public static void Postfix(ushort buildingID, ref Building buildingData, ref Bui MainDataStore.operationResourceBuffer[buildingID] = 0; if (RealConstruction.debugMode) { - if (buildingData.m_problems == Notification.Problem.None) + if (buildingData.m_problems == Notification.Problem1.None) { - Notification.Problem problem = Notification.AddProblems(buildingData.m_problems, Notification.Problem.NoResources); + Notification.Problem1 problem = Notification.AddProblems(buildingData.m_problems, Notification.Problem1.NoResources); buildingData.m_problems = problem; } } @@ -90,7 +90,7 @@ public static void Postfix(ushort buildingID, ref Building buildingData, ref Bui { if (CustomPlayerBuildingAI.CanRemoveNoResource(buildingID, ref buildingData)) { - Notification.Problem problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem.NoResources); + Notification.Problem1 problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem1.NoResources); buildingData.m_problems = problem; } } @@ -100,7 +100,7 @@ public static void Postfix(ushort buildingID, ref Building buildingData, ref Bui { if (CustomPlayerBuildingAI.CanRemoveNoResource(buildingID, ref buildingData)) { - Notification.Problem problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem.NoResources); + Notification.Problem1 problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem1.NoResources); buildingData.m_problems = problem; } } @@ -112,16 +112,16 @@ public static void Postfix(ushort buildingID, ref Building buildingData, ref Bui ConstructionAI.ProcessBuildingConstruction(buildingID, ref buildingData, ref frameData); if (MainDataStore.constructionResourceBuffer[buildingID] >= 8000) { - Notification.Problem problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem.NoResources); + Notification.Problem1 problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem1.NoResources); buildingData.m_problems = problem; } else { if (RealConstruction.debugMode) { - if (buildingData.m_problems == Notification.Problem.None) + if (buildingData.m_problems == Notification.Problem1.None) { - Notification.Problem problem = Notification.AddProblems(buildingData.m_problems, Notification.Problem.NoResources); + Notification.Problem1 problem = Notification.AddProblems(buildingData.m_problems, Notification.Problem1.NoResources); buildingData.m_problems = problem; } } diff --git a/Patch/PrivateBuildingAISimulationStepPatch.cs b/Patch/PrivateBuildingAISimulationStepPatch.cs index 24fc831..f9ca969 100644 --- a/Patch/PrivateBuildingAISimulationStepPatch.cs +++ b/Patch/PrivateBuildingAISimulationStepPatch.cs @@ -22,16 +22,16 @@ public static void Postfix(ushort buildingID, ref Building buildingData, ref Bui { if (MainDataStore.constructionResourceBuffer[buildingID] >= 8000) { - Notification.Problem problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem.NoResources); + Notification.Problem1 problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem1.NoResources); buildingData.m_problems = problem; } else { if (RealConstruction.debugMode) { - if (buildingData.m_problems == Notification.Problem.None) + if (buildingData.m_problems == Notification.Problem1.None) { - Notification.Problem problem = Notification.AddProblems(buildingData.m_problems, Notification.Problem.NoResources); + Notification.Problem1 problem = Notification.AddProblems(buildingData.m_problems, Notification.Problem1.NoResources); buildingData.m_problems = problem; } } @@ -39,7 +39,7 @@ public static void Postfix(ushort buildingID, ref Building buildingData, ref Bui } else { - Notification.Problem problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem.NoResources); + Notification.Problem1 problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem1.NoResources); buildingData.m_problems = problem; } } diff --git a/PreviewImage2.png b/PreviewImage2.png new file mode 100644 index 0000000..a41615c Binary files /dev/null and b/PreviewImage2.png differ diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index d48fa7d..13b7643 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -2,9 +2,10 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// 有关程序集的一般信息由以下 -// 控制。更改这些特性值可修改 -// 与程序集关联的信息。 +// [en]> General information about the assembly is controlled by the following. +// Changing the values of these characteristics modifies the information associated with the assembly. +// [zh]> 有关程序集的一般信息由以下控制。更改这些特性值可修改与程序集关联的信息。 +// [ja]> アセンブリに関する一般的な情報は以下によって制御されます。 これらの特性の値を変更することでアセンブリに関連する情報が変更されます。 [assembly: AssemblyTitle("RealConstruction")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] @@ -14,23 +15,28 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -//将 ComVisible 设置为 false 将使此程序集中的类型 -//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, -//请将此类型的 ComVisible 特性设置为 true。 +// [en]> Setting ComVisible to false will make the types in this assembly invisible to COM components. +// If you need to access the types in this assembly from COM, set the ComVisible feature of this type to true. +// [zh]> 将 ComVisible 设置为 false 将使此程序集中的类型对 COM 组件不可见。 +// 如果需要从 COM 访问此程序集中的类型,请将此类型的 ComVisible 特性设置为 true。 +// [ja]> ComVisibleをfalseに設定すると、このアセンブリの型はCOMコンポーネントから見えなくなります。 +// COMからこのアセンブリの型にアクセスする必要がある場合は、この型のComVisible機能をtrueに設定します。 [assembly: ComVisible(false)] -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +// [en]> If this project is public to COM, the following GUID is used for the type library ID +// [zh]> 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +// [ja]> この項目がCOMに公開されている場合、タイプライブラリのIDには以下のGUIDが使用されます。 [assembly: Guid("d02f1eac-f10c-4938-a148-84124780ddc6")] -// 程序集的版本信息由下列四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, -// 方法是按如下所示使用“*”: : +// [en]> The version information of the assembly consists of the following four values. +// ("Primary version . Secondary version . Generate number . Revision number") +// You can specify all of these values, or you can use the default values for "Generate" and "Revision" by using "*" as shown below. +// [zh]> 程序集的版本信息由下列四个值组成: +// ("主版本 . 次版本 . 生成号 . 修订号") +// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,方法是按如下所示使用“*”: +// [ja]> プログラムセットのバージョン情報は、以下の4つの値で構成されます。 +// ("プライマリーバージョン . セカンダリーバージョン . 世代番号(Generation Number) . リビジョン番号") +// これらの値をすべて指定することもできますが、以下のように "*"を使用することで、"Generate "と "Revision "のデフォルト値を使用することができます。 // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.1.02.16")] -[assembly: AssemblyFileVersion("3.1.02.16")] +[assembly: AssemblyVersion("3.2.05.18")] +[assembly: AssemblyFileVersion("3.2.05.18")] diff --git a/README.md b/README.md index f960795..0e15a11 100644 --- a/README.md +++ b/README.md @@ -60,12 +60,24 @@ Author: **@pcfantasy** -Collaborators: **@Pourov(Sagiluv1)** - +Collaborators: **@Pourov(Sagiluv1)** **@iwarin123(iwarin123)** *Update logs:* --- +* 08/05/2023: + 1. German wording has been corrected under @DJKLI supervision. + +* 03/05/2023: + 1. Add Spanish, French, Polish, Brazilian Portuguese translation. + +* 02/05/2023: + 1. Add German translation de.txt. + +* 27/04/2023: + 1. Compatible with Cities Skylines 1.16.1-f2 (Hubs & Transport) + 2. Add Japanese translation ja.txt. + * 20/03/2019: 1. Increase resource building production speed a little 2. Add garbage service as high priority in resource supply diff --git a/RealConstruction.cs b/RealConstruction.cs index d0026d8..920ed38 100644 --- a/RealConstruction.cs +++ b/RealConstruction.cs @@ -1,7 +1,9 @@ using CitiesHarmony.API; using ICities; using RealConstruction.Util; +using System; using System.IO; +using System.Reflection; namespace RealConstruction { @@ -12,9 +14,25 @@ public class RealConstruction : IUserMod public static bool fixUnRouteTransfer = false; public static int operationConsumption = 2; +#if DEBUG + private static string config => " [DEBUG]"; +#else + private static string config => ""; +#endif + public static string ModName => $"Real Construction{config}"; + public string Name { - get { return "Real Construction"; } + get { + // Get the currently executing assembly (.exe assembly) + var assembly = Assembly.GetExecutingAssembly(); + var name = assembly.GetName(); + + // Retrieve and display the version + var version = $" {name.Version}"; + + return ModName + version; + } } public string Description diff --git a/RealConstruction.csproj b/RealConstruction.csproj index 73c2263..34a846f 100644 --- a/RealConstruction.csproj +++ b/RealConstruction.csproj @@ -33,10 +33,10 @@ - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp.dll + C:\Program Files (x86)\Steam\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp.dll - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp-firstpass.dll + C:\Program Files (x86)\Steam\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp-firstpass.dll packages\CitiesHarmony.API.2.0.0\lib\net35\CitiesHarmony.API.dll @@ -45,10 +45,10 @@ packages\CitiesHarmony.Harmony.2.0.4\lib\net35\CitiesHarmony.Harmony.dll - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ColossalManaged.dll + C:\Program Files (x86)\Steam\steamapps\common\Cities_Skylines\Cities_Data\Managed\ColossalManaged.dll - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICities.dll + C:\Program Files (x86)\Steam\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICities.dll @@ -57,7 +57,7 @@ - F:\SteamLibrary\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.dll + C:\Program Files (x86)\Steam\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.dll @@ -69,6 +69,7 @@ + @@ -99,7 +100,15 @@ + + + + + + + + @@ -109,15 +118,20 @@ - rd /q /s "F:\SteamLibrary\steamapps\workshop\content\255710\1614061108" -mkdir "F:\SteamLibrary\steamapps\workshop\content\255710\1614061108" -copy "D:\Mod\RealConstruction\bin\Release\RealConstruction.dll" "F:\SteamLibrary\steamapps\workshop\content\255710\1614061108\RealConstruction.dll" -mkdir "F:\SteamLibrary\steamapps\workshop\content\255710\1614061108\Locales" -copy "D:\Mod\RealConstruction\Locales\*.txt" "F:\SteamLibrary\steamapps\workshop\content\255710\1614061108\Locales" -copy "D:\Mod\RealConstruction\bin\Release\CitiesHarmony.API.dll" "F:\SteamLibrary\steamapps\workshop\content\255710\1614061108\CitiesHarmony.API.dll" -mkdir "F:\SteamLibrary\steamapps\workshop\content\255710\1614061108\Icon" -copy "D:\Mod\RealConstruction\Icon\*.png" "F:\SteamLibrary\steamapps\workshop\content\255710\1614061108\Icon" -copy "D:\Mod\RealConstruction\PreviewImage.png" "F:\SteamLibrary\steamapps\workshop\content\255710\1614061108\PreviewImage.png" + setlocal +set SRC_PATH=$(ProjectDir) +set DST_PATH=%25LOCALAPPDATA%25\Colossal Order\Cities_Skylines\Addons\Mods\RealConstruction +rd /q /s "%25DST_PATH%25" +mkdir "%25DST_PATH%25" +copy "$(TargetPath)" "%25DST_PATH%25\RealConstruction.dll" +mkdir "%25DST_PATH%25\Locales" +copy "%25SRC_PATH%25\Locales\*.txt" "%25DST_PATH%25\Locales" +rem copy "$(TargetDir)CitiesHarmony.API.dll" "%25DST_PATH%25\CitiesHarmony.API.dll" +mkdir "%25DST_PATH%25\Icon" +copy "%25SRC_PATH%25\Icon\*.png" "%25DST_PATH%25\Icon" +copy "%25SRC_PATH%25\PreviewImage2.png" "%25DST_PATH%25\PreviewImage.png" +start "" "%25DST_PATH%25\" +endlocal