Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save pardeike/a11f494e65877cf361c9ec22c646c198 to your computer and use it in GitHub Desktop.
Save pardeike/a11f494e65877cf361c9ec22c646c198 to your computer and use it in GitHub Desktop.
A robust transpiler to add extra pathing costs to FindPath in RimWorld
[HarmonyPatch(typeof(PathFinder), "FindPath")]
[HarmonyPatch(new Type[] { typeof(IntVec3), typeof(LocalTargetInfo), typeof(TraverseParms), typeof(PathEndMode) })]
public static class PathFinder_FindPath_Patch
{
static int GetExtraCosts(Pawn pawn, int gridIdx)
{
return 0; // extra costs to add for gridIdx
}
static readonly MethodInfo m_CellToIndex_int_int = AccessTools.Method(typeof(CellIndices), nameof(CellIndices.CellToIndex), new Type[] { typeof(int), typeof(int) });
static readonly FieldInfo f_TraverseParms_pawn = AccessTools.Field(typeof(TraverseParms), nameof(TraverseParms.pawn));
static readonly MethodInfo m_GetExtraCosts = SymbolExtensions.GetMethodInfo(() => GetZombieCosts(null, 0));
static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
{
var list = instructions.ToList();
while (true)
{
var t_PathFinderNodeFast = AccessTools.Inner(typeof(PathFinder), "PathFinderNodeFast");
var f_knownCost = AccessTools.Field(t_PathFinderNodeFast, "knownCost");
if (f_knownCost == null)
{
Log.Error($"Cannot find field Verse.AI.PathFinder.PathFinderNodeFast.knownCost");
break;
}
var idx = list.FirstIndexOf(ins => ins.Calls(m_CellToIndex_int_int));
if (idx < 0 || idx >= list.Count() || list[idx + 1].opcode != OpCodes.Stloc_S)
{
Log.Error($"Cannot find CellToIndex(n,n)/Stloc_S in {original.FullDescription()}");
break;
}
var gridIdx = list[idx + 1].operand;
var insertLoc = list.FirstIndexOf(ins => ins.opcode == OpCodes.Ldfld && (FieldInfo)ins.operand == f_knownCost);
while (insertLoc >= 0 && insertLoc < list.Count)
{
if (list[insertLoc].opcode == OpCodes.Add) break;
insertLoc++;
}
if (insertLoc < 0 || insertLoc >= list.Count())
{
Log.Error($"Cannot find Ldfld knownCost ... Add in {original.FullDescription()}");
break;
}
var traverseParmsIdx = original.GetParameters().FirstIndexOf(info => info.ParameterType == typeof(TraverseParms)) + 1;
list.Insert(insertLoc++, new CodeInstruction(OpCodes.Add));
list.Insert(insertLoc++, new CodeInstruction(OpCodes.Ldarga_S, traverseParmsIdx));
list.Insert(insertLoc++, new CodeInstruction(OpCodes.Ldfld, f_TraverseParms_pawn));
list.Insert(insertLoc++, new CodeInstruction(OpCodes.Ldloc_S, gridIdx));
list.Insert(insertLoc++, new CodeInstruction(OpCodes.Call, m_GetExtraCosts));
break;
}
foreach (var instr in list)
yield return instr;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment