Created
February 20, 2020 20:43
-
-
Save pardeike/a11f494e65877cf361c9ec22c646c198 to your computer and use it in GitHub Desktop.
A robust transpiler to add extra pathing costs to FindPath in RimWorld
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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