diff --git a/1.5/Assemblies/CleanPathfinding.dll b/1.5/Assemblies/CleanPathfinding.dll new file mode 100644 index 0000000..e4294c1 Binary files /dev/null and b/1.5/Assemblies/CleanPathfinding.dll differ diff --git a/1.5/Assemblies/CleanPathfinding.pdb b/1.5/Assemblies/CleanPathfinding.pdb new file mode 100644 index 0000000..ceae249 Binary files /dev/null and b/1.5/Assemblies/CleanPathfinding.pdb differ diff --git a/1.5/Patches/patch.owlchemist.cleanpathfinding.xml b/1.5/Patches/patch.owlchemist.cleanpathfinding.xml new file mode 100644 index 0000000..c676457 --- /dev/null +++ b/1.5/Patches/patch.owlchemist.cleanpathfinding.xml @@ -0,0 +1,32 @@ + + + + +
  • + Defs/TerrainDef[tags]/tags[li/text()="Road" or li/text()="FineFloor"] + +
  • CleanPath
  • + + +
  • + Always + Defs/TerrainTemplateDef[tags]/tags[li/text()="FineFloor"] + +
  • CleanPath
  • + + +
  • + Defs/TerrainDef[defName="PavedTile" or defName="Concrete" or @Name="TileStoneBase"][not(tags)] + + + +
  • +
  • + Defs/TerrainDef[defName="PavedTile" or defName="Concrete" or @Name="TileStoneBase"]/tags + +
  • CleanPath
  • + + +
    +
    +
    \ No newline at end of file diff --git a/About/About.xml b/About/About.xml index ad75689..4d9e0de 100644 --- a/About/About.xml +++ b/About/About.xml @@ -6,6 +6,7 @@
  • 1.4
  • +
  • 1.5
  • When pathfinding costs are calculated, any terrain tiles that generate filth are taken into account and given some degree of avoidance. Also, roads can be given a bonus attraction, and the overall pathfinding range can be adjusted. Other features such as light attraction and extra range can also be enabled. diff --git a/Source/CleanPathfinding.csproj b/Source/CleanPathfinding.csproj index 3c44b8d..2e2f7b4 100644 --- a/Source/CleanPathfinding.csproj +++ b/Source/CleanPathfinding.csproj @@ -9,18 +9,17 @@ net48 preview false + 1.4;1.5 - - ..\..\..\Mods\$(Product)\$(Version)\Assemblies - TRACE;NDEBUG - 4 - false - None - - + ..\..\..\Mods\$(Product)\$(Version)\Assemblies TRACE;DEBUG;NETFRAMEWORK;NET48; + + ..\..\..\Mods\Clean Pathfinding\1.5\Assemblies + NETFRAMEWORK;NET48;v1_5 + true + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -31,7 +30,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/Source/CleanPathfinding.sln b/Source/CleanPathfinding.sln new file mode 100644 index 0000000..811372b --- /dev/null +++ b/Source/CleanPathfinding.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.34601.136 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CleanPathfinding", "CleanPathfinding.csproj", "{580CD268-7D44-402D-9FBE-76A743993959}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + 1.4|Any CPU = 1.4|Any CPU + 1.5|Any CPU = 1.5|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {580CD268-7D44-402D-9FBE-76A743993959}.1.4|Any CPU.ActiveCfg = 1.4|Any CPU + {580CD268-7D44-402D-9FBE-76A743993959}.1.4|Any CPU.Build.0 = 1.4|Any CPU + {580CD268-7D44-402D-9FBE-76A743993959}.1.5|Any CPU.ActiveCfg = 1.5|Any CPU + {580CD268-7D44-402D-9FBE-76A743993959}.1.5|Any CPU.Build.0 = 1.5|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {058A7526-2742-491F-B717-AC7BC5D88641} + EndGlobalSection +EndGlobal diff --git a/Source/CleanPathfindingUtility.cs b/Source/CleanPathfindingUtility.cs index dc09058..8f56e5b 100644 --- a/Source/CleanPathfindingUtility.cs +++ b/Source/CleanPathfindingUtility.cs @@ -4,6 +4,7 @@ using Verse.AI; using System; using System.Collections.Generic; +using System.Reflection; using System.Reflection.Emit; using System.Linq; using static CleanPathfinding.ModSettings_CleanPathfinding; @@ -11,15 +12,100 @@ namespace CleanPathfinding { #region Harmony - [HarmonyPatch(typeof(PathFinder), nameof(PathFinder.FindPath), new Type[] { - typeof(IntVec3), - typeof(LocalTargetInfo), - typeof(TraverseParms), - typeof(PathEndMode), - typeof(PathFinderCostTuning) })] - static class Patch_PathFinder - { - static IEnumerable Transpiler(IEnumerable instructions) + + + [HarmonyPatch(typeof(PathFinder))] + + static class Patch_PathFinder_Finalize + { + /* here to trouble shoot memory leaks + * Soyuz caught this error. Please don't report this to the RocketMan team unless you're certain RocketMan caused this error. with error System.OutOfMemoryException: Out of memory +[Ref 3B9F4383] + at (wrapper managed-to-native) System.Object.__icall_wrapper_ves_icall_array_new_specific(intptr,int) + at System.Collections.Generic.List`1[T].set_Capacity (System.Int32 value) [0x00021] in :0 + at System.Collections.Generic.List`1[T].EnsureCapacity (System.Int32 min) [0x00036] in :0 + at System.Collections.Generic.List`1[T].Add (T item) [0x00010] in :0 + at Verse.AI.PawnPath.AddNode (Verse.IntVec3 nodePosition) [0x00000] in <957a20e0be784a65bc32cf449445b937>:0 + at Verse.AI.PathFinder.FinalizedPath (System.Int32 finalIndex, System.Boolean usedRegionHeuristics) [0x00036] in <957a20e0be784a65bc32cf449445b937>:0 + at Verse.AI.PathFinder.FindPath (Verse.IntVec3 start, Verse.LocalTargetInfo dest, Verse.TraverseParms traverseParms, Verse.AI.PathEndMode peMode, Verse.AI.PathFinderCostTuning tuning) [0x005a5] in <957a20e0be784a65bc32cf449445b937>:0 + - TRANSPILER Owlchemist.CleanPathfinding.tmp: IEnumerable`1 CleanPathfinding.Patch_PathFinder:Transpiler(IEnumerable`1 instructions) + - TRANSPILER OskarPotocki.VanillaFurnitureExpanded.Security: IEnumerable`1 VFESecurity.Patch_PathFinder+FindPath:Transpiler(IEnumerable`1 instructions) + at Verse.AI.PathFinder.FindPath (Verse.IntVec3 start, Verse.LocalTargetInfo dest, Verse.Pawn pawn, Verse.AI.PathEndMode peMode, Verse.AI.PathFinderCostTuning tuning) [0x0003e] in <957a20e0be784a65bc32cf449445b937>:0 + at Verse.AI.Pawn_PathFollower.GenerateNewPath () [0x0005e] in <957a20e0be784a65bc32cf449445b937>:0 + - PREFIX OskarPotocki.VFECore: Boolean VFECore.PhasingPatches:GenerateNewPath_Prefix(Pawn_PathFollower __instance, Pawn ___pawn, LocalTargetInfo ___destination, PathEndMode ___peMode, PawnPath& __result) + at Verse.AI.Pawn_PathFollower.TrySetNewPath () [0x00000] in <957a20e0be784a65bc32cf449445b937>:0 + at Verse.AI.Pawn_PathFollower.TryEnterNextPathCell () [0x00303] in <957a20e0be784a65bc32cf449445b937>:0 + - PREFIX juanlopez2008.LightsOut: Void LightsOut.Patches.Lights.DetectPawnRoomChange:Prefix(Pawn ___pawn, Room& __state) + - POSTFIX OskarPotocki.VFECore: Void VFECore.PhasingPatches:UnfogEnteredCells(Pawn_PathFollower __instance, Pawn ___pawn) + - POSTFIX juanlopez2008.LightsOut: Void LightsOut.Patches.Lights.DetectPawnRoomChange:Postfix(Pawn ___pawn, Room& __state) + at Verse.AI.Pawn_PathFollower.PatherTick () [0x00404] in <957a20e0be784a65bc32cf449445b937>:0 + - PREFIX Krkr.RocketMan.Soyuz: Void Soyuz.Patches.Pawn_PathFollower_Patch+Pawn_PathFollower_PatherTick:Prefix(Pawn_PathFollower __instance) + - POSTFIX Krkr.RocketMan.Soyuz: Void Soyuz.Patches.Pawn_PathFollower_Patch+Pawn_PathFollower_PatherTick:Postfix(Pawn_PathFollower __instance) + - FINALIZER Krkr.RocketMan.Soyuz: Void Soyuz.Patches.Pawn_PathFollower_Patch+Pawn_PathFollower_PatherTick:Finalizer(Exception __exception) + at Verse.Pawn.Tick () [0x000d8] in <957a20e0be784a65bc32cf449445b937>:0 + - TRANSPILER Krkr.RocketMan.Soyuz: IEnumerable`1 Soyuz.Patches.Pawn_Tick_Patch:Transpiler(IEnumerable`1 instructions, ILGenerator generator) + - POSTFIX Roolo.DualWield: Void DualWield.HarmonyInstance.Pawn_Tick:Postfix(Pawn __instance) + - FINALIZER Krkr.RocketMan.Soyuz: Void Soyuz.Patches.Pawn_Tick_Patch:Finalizer(Pawn __instance, Exception __exception) +UnityEngine.StackTraceUtility:ExtractStackTrace () +(wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition:Verse.Log.Error_Patch7 (string) +RocketMan.Logger:Debug (string,System.Exception,string) +Soyuz.Patches.Pawn_Tick_Patch:Finalizer (Verse.Pawn,System.Exception) +(wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition:Verse.Pawn.Tick_Patch2 (Verse.Pawn) +(wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition:Verse.TickList.Tick_Patch2 (Verse.TickList) +(wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition:Verse.TickManager.DoSingleTick_Patch4 (Verse.TickManager) +Verse.TickManager:TickManagerUpdate () +(wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition:Verse.Game.UpdatePlay_Patch2 (Verse.Game) +Verse.Root_Play:Update () + */ + static MethodBase TargetMethod() + { + return typeof(PathFinder).GetMethod("FinalizedPath", BindingFlags.NonPublic | BindingFlags.Instance); + } + + [HarmonyPrefix] + static bool FinalizedPath_Prefix(ref PathFinder __instance, ref PawnPath __result, int finalIndex, bool usedRegionHeuristics) + { + PawnPath emptyPawnPath = __instance.map.pawnPathPool.GetEmptyPawnPath(); + int num = finalIndex; + + int max = 0; + for (; ; ) + { + int parentIndex = PathFinder.calcGrid[num].parentIndex; + emptyPawnPath.AddNode(__instance.map.cellIndices.IndexToCell(num)); + if (num == parentIndex) + { + break; + } + if (max>1000) + { + + TraverseParms traverse = __instance.traverseParms; + Log.Warning("bailing out of path calculation for "+traverse.pawn+" with "+traverse.pawn.TicksPerMoveCardinal+"/"+traverse.pawn.TicksPerMoveDiagonal+" TicksPerMoveCardinal/Diagonal after 1000 path nodes added to prevent mem leaks, on num " + num + " aiming for " + parentIndex); + __result = PawnPath.NotFound; + + return false; + } + num = parentIndex; + max++; + } + emptyPawnPath.SetupFound((float)PathFinder.calcGrid[finalIndex].knownCost, usedRegionHeuristics); + __result = emptyPawnPath; + + return false; + } + + } + [HarmonyPatch(typeof(PathFinder), nameof(PathFinder.FindPath), new Type[] { + typeof(IntVec3), + typeof(LocalTargetInfo), + typeof(TraverseParms), + typeof(PathEndMode), + typeof(PathFinderCostTuning) })] + static class Patch_PathFinder + { + + static IEnumerable Transpiler(IEnumerable instructions) { int offset = -1, objectsFound = 0; bool ran = false, searchForObjects = false, thresholdReplaced = false; @@ -48,7 +134,7 @@ static IEnumerable Transpiler(IEnumerable inst if (searchForObjects && objectsFound < 3 && code.opcode == OpCodes.Ldloc_S) { objects[objectsFound++] = code.operand; - //As of 12/5, object 0 should be 48, object 1 should be 12, and object 2 should be 45 + //As of 4/2024, object 0 should be 46, object 1 should be 12, and object 2 should be 43 } if (offset == -1 && code.opcode == OpCodes.Ldfld && code.OperandIs(field_extraNonDraftedPerceivedPathCost)) @@ -56,21 +142,22 @@ static IEnumerable Transpiler(IEnumerable inst offset = 0; continue; } + if (offset > -1 && ++offset == 2) { - yield return new CodeInstruction(OpCodes.Ldloc_0); + yield return new CodeInstruction(OpCodes.Ldloc_0); //pawn yield return new CodeInstruction(OpCodes.Ldloc_S, objects[1]); //topGrid - yield return new CodeInstruction(OpCodes.Ldloc_S, objects[2]); //TerrainDef within the grid - yield return new CodeInstruction(OpCodes.Ldelem_Ref); - yield return new CodeInstruction(OpCodes.Ldloc_S, objects[0]); //Pathcost total - yield return new CodeInstruction(OpCodes.Ldarg_0); + yield return new CodeInstruction(OpCodes.Ldloc_S, objects[2]); //topGrid index number + yield return new CodeInstruction(OpCodes.Ldelem_Ref); //TerrainDef within the grid + yield return new CodeInstruction(OpCodes.Ldloc_S, objects[0]); //Pathcost total + yield return new CodeInstruction(OpCodes.Ldarg_0); //start position (not used by adjust cost?) yield return new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PathFinder), nameof(PathFinder.map))); yield return new CodeInstruction(OpCodes.Ldloc_S, objects[2]); //cell location yield return new CodeInstruction(OpCodes.Call, typeof(CleanPathfindingUtility).GetMethod(nameof(CleanPathfindingUtility.AdjustCosts))); yield return new CodeInstruction(OpCodes.Stloc_S, objects[0]); ran = true; - } + } } if (!ran) Log.Warning("[Clean Pathfinding] Transpiler could not find target. There may be a mod conflict, or RimWorld updated?"); @@ -164,7 +251,7 @@ public static void UpdatePathCosts() Log.Error("[Clean Pathfinding] Error processing settings, skipping...\n" + ex); } } - static public int AdjustCosts(Pawn pawn, TerrainDef def, int cost, Map map, int index) + static public float AdjustCosts(Pawn pawn, TerrainDef def, float cost, Map map, int index) { if (pawn == null) goto skipAdjustment; @@ -267,13 +354,18 @@ float GameGlowAtFast(Map map, int index) daylight = map.skyManager.curSkyGlowInt; if (daylight == 1f) return 1f; } +#if v1_5 + +#else ColorInt color = map.glowGrid.glowGrid[index]; +#endif + UnityEngine.Color32 color = map.glowGrid.VisualGlowAt(index); if (color.a == 1) return 1; return (float)(color.r + color.g + color.b) * 0.0047058823529412f; //n / 3f / 255f * 3.6f pre-computed, since I guess the assembler doesn't optimize this } - #endregion +#endregion } } } \ No newline at end of file diff --git a/Source/DoorPathingUtility.cs b/Source/DoorPathingUtility.cs index a72cd3d..26f5ca0 100644 --- a/Source/DoorPathingUtility.cs +++ b/Source/DoorPathingUtility.cs @@ -13,6 +13,15 @@ namespace CleanPathfinding { + static class Area_Assit + { + public static void SetLabel(this Area_Allowed self, string label) + { + + } + } + + //Add gizmos to the doors [HarmonyPatch(typeof(Building_Door), nameof(Building_Door.GetGizmos))] static class Patch_Building_Door_GetGizmos @@ -81,6 +90,9 @@ public static void Prefix(Area __instance) } } +#if v1_5 + //SetLabel removed in 1.5 +#else [HarmonyPatch(typeof(Area_Allowed), nameof(Area_Allowed.SetLabel))] static class Patch_Area_Allowed_SetLabel { @@ -100,6 +112,7 @@ public static void Postfix(Area_Allowed __instance) else if (__instance.Label == "Avoid" && compCache.TryGetValue(__instance.Map.uniqueID, out MapComponent_DoorPathing mapComp)) mapComp.RegisterAvoidArea(__instance); } } +#endif [HarmonyPatch(typeof(World), nameof(World.FinalizeInit))] static class Patch_FinalizeInit diff --git a/Source/Mod_CleanPathfinding.cs b/Source/Mod_CleanPathfinding.cs index d5a827c..5d9a400 100644 --- a/Source/Mod_CleanPathfinding.cs +++ b/Source/Mod_CleanPathfinding.cs @@ -86,7 +86,10 @@ public class Mod_CleanPathfinding : Mod public Mod_CleanPathfinding(ModContentPack content) : base(content) { base.GetSettings(); - new Harmony(this.Content.PackageIdPlayerFacing).PatchAll(); + + Harmony harmony = new Harmony(this.Content.PackageIdPlayerFacing); + Harmony.DEBUG = true; + harmony.PatchAll(); } public override void DoSettingsWindowContents(Rect inRect)