diff --git a/Source/ProjectRimFactory/Common/ConditionalPatchHelper.cs b/Source/ProjectRimFactory/Common/ConditionalPatchHelper.cs index 683c64f0..e1b0a56e 100644 --- a/Source/ProjectRimFactory/Common/ConditionalPatchHelper.cs +++ b/Source/ProjectRimFactory/Common/ConditionalPatchHelper.cs @@ -12,7 +12,8 @@ public static class ConditionalPatchHelper { public class TogglePatch { - private bool Patched = false; + private bool patched = false; + public bool Status => patched; private readonly MethodInfo base_m; private readonly HarmonyMethod trans_hm = null; @@ -35,17 +36,17 @@ public TogglePatch(MethodInfo base_method, MethodInfo prefix = null, MethodInfo public void PatchHandler(bool patch) { - if (patch && !Patched) + if (patch && !patched) { harmony_instance.Patch(base_m, pre_hm, post_hm, trans_hm); - Patched = true; + patched = true; } - else if (Patched && !patch) + else if (patched && !patch) { if (trans_m != null) harmony_instance.Unpatch(base_m, trans_m); if (pre_m != null) harmony_instance.Unpatch(base_m, pre_m); if (post_m != null) harmony_instance.Unpatch(base_m, post_m); - Patched = false; + patched = false; } } @@ -56,7 +57,8 @@ public void PatchHandler(bool patch) public static TogglePatch Patch_Reachability_CanReach = new TogglePatch( AccessTools.Method(typeof(Verse.Reachability), "CanReach", new Type[] { typeof(IntVec3), typeof(LocalTargetInfo), typeof(PathEndMode), typeof(TraverseParms) }), - AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_Reachability_CanReach), "Prefix") + null, + AccessTools.Method(typeof(ProjectRimFactory.Common.HarmonyPatches.Patch_Reachability_CanReach), "Postfix") ); public static TogglePatch Patch_WealthWatcher_CalculateWealthItems = new TogglePatch( diff --git a/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_FoodUtility_SpawnedFoodSearchInnerScan.cs b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_FoodUtility_SpawnedFoodSearchInnerScan.cs index 6909c348..207fae66 100644 --- a/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_FoodUtility_SpawnedFoodSearchInnerScan.cs +++ b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_FoodUtility_SpawnedFoodSearchInnerScan.cs @@ -49,10 +49,11 @@ static IEnumerable Transpiler(IEnumerable inst yield return new CodeInstruction(OpCodes.Ldloca_S, instruction.operand); yield return new CodeInstruction(OpCodes.Ldloc_S, Thingarg); - + yield return new CodeInstruction(OpCodes.Ldarg_0); + yield return new CodeInstruction(OpCodes.Ldarg_1); yield return new CodeInstruction(OpCodes.Call, AccessTools.Method( typeof(Patch_FoodUtility_SpawnedFoodSearchInnerScan), - nameof(Patch_FoodUtility_SpawnedFoodSearchInnerScan.isCanIOPortGetItem), new[] { typeof(float).MakeByRefType(), typeof(Thing) })); + nameof(Patch_FoodUtility_SpawnedFoodSearchInnerScan.isIOPortBetter), new[] { typeof(float).MakeByRefType(), typeof(Thing), typeof(Pawn), typeof(IntVec3) })); continue; } @@ -84,7 +85,7 @@ public static void findClosestPort(Pawn pawn, IntVec3 root) if (pawn.Faction == null || !pawn.Faction.IsPlayer) return; - //Not Optimal for the search. might need update + //TODO: Not Optimal for the search. might need update var closest = AdvancedIO_PatchHelper.GetClosestPort(pawn.Map, pawn.Position); mindist = closest.Key; closestPort = closest.Value; @@ -94,38 +95,37 @@ public static void findClosestPort(Pawn pawn, IntVec3 root) private static Thing ioPortSelectedFor = null; - public static void isCanIOPortGetItem(ref float Distance, Thing thing) + /// + /// Checks if the IO Port is a better or the only Option + /// + /// + /// + public static void isIOPortBetter(ref float Distance, Thing thing, Pawn pawn, IntVec3 start) { ioPortSelected = false; - if (mindist < Distance && closestPort != null && ((AdvancedIO_PatchHelper.CanMoveItem(closestPort, thing)))) - { - Distance = mindist; - ioPortSelected = true; - ioPortSelectedFor = thing; + //If the Port is Closer then it is a better choice + //#691 If the Port is the only Option it must be used + if ( mindist < Distance || (ConditionalPatchHelper.Patch_Reachability_CanReach.Status && pawn.Map.reachability.CanReach(start,thing,Verse.AI.PathEndMode.Touch, TraverseParms.For(pawn)) && Patch_Reachability_CanReach.CanReachThing(thing) )) + { + //Check if the Port can be used + //TODO: Check TODO in Line 88 + if (closestPort != null && AdvancedIO_PatchHelper.CanMoveItem(closestPort, thing)) + { + Distance = mindist; + ioPortSelected = true; + ioPortSelectedFor = thing; + } } } public static void moveItemIfNeeded(Thing thing) { //When using replimat it might replace thing - if (thing != ioPortSelectedFor) - { - return; - } - if (ioPortSelected && thing != null) - { - ioPortSelected = false; - try - { - thing.Position = closestPort.Position; - } - catch (NullReferenceException) - { - Log.Message($"moveItemIfNeeded NullReferenceException - {thing} - {closestPort}"); - } - - } + if (thing != ioPortSelectedFor || !ioPortSelected || thing == null) return; + + ioPortSelected = false; + closestPort.PlaceThingNow(thing); } } } diff --git a/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_Reachability_CanReach.cs b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_Reachability_CanReach.cs index 6a6e0127..05f0f800 100644 --- a/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_Reachability_CanReach.cs +++ b/Source/ProjectRimFactory/Common/HarmonyPatches/Patch_Reachability_CanReach.cs @@ -7,29 +7,78 @@ namespace ProjectRimFactory.Common.HarmonyPatches //Managed by ConditionalPatchHelper.Update_Patch_Reachability_CanReach class Patch_Reachability_CanReach { - public static bool Prefix(IntVec3 start, LocalTargetInfo dest, PathEndMode peMode, TraverseParms traverseParams, out bool __result, Map ___map, Reachability __instance) + //canReachThing Holds the Last item that was checked and Required the use of a Advanced IO Port + //This is used in other patches to force the use of an IO Port + private static Thing canReachThing =null; + public static bool CanReachThing(Thing thing) { - __result = false; - if (dest.Thing == null || dest.Thing.def.category != ThingCategory.Item) return true; + var ret = thing == canReachThing; + canReachThing = null; + return ret; + } + + /// + /// This Patch allows Pawns to receive Items from a Advanced IO Port when the direct Path to the DSU(current Item Location) is Blocked + /// This Patch has a noticeable Performance Impact and shall only be use if the Path is Blocked + /// + /// + /// + /// + /// + /// + /// + /// + public static void Postfix(IntVec3 start, LocalTargetInfo dest, PathEndMode peMode, TraverseParms traverseParams, ref bool __result, Map ___map, Reachability __instance) + { + //There is already a Path + if (__result) return; + + var thing = dest.Thing; + + + //Ignore everything that is not a Item + if (thing == null || thing.def.category != ThingCategory.Item) return; + + //Quickly get the Map Component (abort if nonexistent) var mapcomp = PatchStorageUtil.GetPRFMapComponent(___map); - if (mapcomp == null) return true; - //Not optimal lets correct that later - var ThingPos = dest.Thing.Position; - if (mapcomp.ShouldHideItemsAtPos(ThingPos)) + if (mapcomp == null) return; + + //Is in a DSU + if (hasPathToItem(thing,mapcomp,__instance,start,traverseParams)) { - //Is in a DSU - var pathToIO = mapcomp.GetadvancedIOLocations.Where(p => p.Value.boundStorageUnit?.GetPosition == ThingPos && __instance.CanReach(start, p.Key, PathEndMode.Touch, traverseParams)).Any(); - if (pathToIO) - { - __result = true; - return false; - } + canReachThing = thing; + __result = true; } + } + //I think i need to rework how, what and where stuff is save for event caching + private static bool hasPathToItem(Thing thing, PRFMapComponent mapComp, Reachability reachability, IntVec3 start, TraverseParms traverseParams) + { + var ThingPos = thing.Position; - return true; - } + //Quickly Check if the Item is in a Storage Unit + //TODO: Rework that -> This includes items in PRF Crates & Excludes items from Cold Storage(Note they currently have bigger issues) + if (!mapComp.ShouldHideItemsAtPos(ThingPos)) return false; + var AdvancedIOLocations = mapComp.GetadvancedIOLocations; + var cnt = AdvancedIOLocations.Count; + //Check Every Advanced IO Port + for (int i = 0; i < cnt; i++) + { + var current = AdvancedIOLocations.ElementAt(i); + + //Check if that Port has access to the Item + //TODO: Rework that -> Is the Use of the Position really best? + if (current.Value.boundStorageUnit?.GetPosition == ThingPos) + { + //The Port has access to the Item + //Now check if we can reach that Port + if (reachability.CanReach(start, current.Key, PathEndMode.Touch, traverseParams)) return true; + } + } + + return false; + } } } diff --git a/Source/ProjectRimFactory/Storage/Building_AdvancedStorageUnitIOPort.cs b/Source/ProjectRimFactory/Storage/Building_AdvancedStorageUnitIOPort.cs index 6ee1033a..b3c70c7a 100644 --- a/Source/ProjectRimFactory/Storage/Building_AdvancedStorageUnitIOPort.cs +++ b/Source/ProjectRimFactory/Storage/Building_AdvancedStorageUnitIOPort.cs @@ -68,14 +68,19 @@ private void updateQueue() if (CanGetNewItem && placementQueue.Count > 0) { var nextItemInQueue = placementQueue[0]; - if (nextItemInQueue != null) - { - placementQueue[0].Position = this.Position; - } + PlaceThingNow(nextItemInQueue); placementQueue.RemoveAt(0); } } + public void PlaceThingNow(Thing thing) + { + if (thing != null) + { + thing.Position = this.Position; + } + } + public override void Tick() { updateQueue();