Fix transpiler pointing towards old version of ApplyBirthOutcome, add checks to all transpilers that they are actually applied

This commit is contained in:
lutepickle 2024-05-04 16:07:20 -07:00
parent 7e4518a98a
commit bfcb469969
4 changed files with 49 additions and 9 deletions

Binary file not shown.

View file

@ -150,7 +150,7 @@ namespace RJW_Menstruation
}
}
[HarmonyPatch(typeof(PregnancyUtility), nameof(PregnancyUtility.ApplyBirthOutcome))]
[HarmonyPatch(typeof(PregnancyUtility), nameof(PregnancyUtility.ApplyBirthOutcome_NewTemp))]
public static class ApplyBirthOutcome_PregeneratedBabies_Patch
{
private static Pawn GetPregeneratedBaby(PawnGenerationRequest request, Thing birtherThing)
@ -182,6 +182,7 @@ namespace RJW_Menstruation
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
bool methodPatched = false;
if (birtherThing < 0) throw new InvalidOperationException("Could not locate index of birtherThing");
if (GeneratePawn?.ReturnType != typeof(Pawn)) throw new InvalidOperationException("GeneratePawn not found");
foreach (CodeInstruction instruction in instructions)
@ -190,16 +191,18 @@ namespace RJW_Menstruation
{
yield return new CodeInstruction(OpCodes.Ldarg, birtherThing);
yield return CodeInstruction.Call(typeof(ApplyBirthOutcome_PregeneratedBabies_Patch), nameof(GetPregeneratedBaby));
methodPatched = true;
}
else yield return instruction;
}
if (!methodPatched) throw new InvalidOperationException("PregnancyUtility.ApplyBirthOutcome_NewTemp not patched");
}
}
[HarmonyPatch(typeof(Hediff_LaborPushing), nameof(Hediff_LaborPushing.PreRemoved))]
public static class Hediff_LaborPushing_PreRemoved_Patch
{
private static Thing ApplyBirthLoop(RitualOutcomePossibility outcome, float quality, Precept_Ritual ritual, List<GeneDef> genes, Pawn geneticMother, Thing birtherThing, Pawn father, Pawn doctor, LordJob_Ritual lordJobRitual, RitualRoleAssignments assignments)
private static Thing ApplyBirthLoop(RitualOutcomePossibility outcome, float quality, Precept_Ritual ritual, List<GeneDef> genes, Pawn geneticMother, Thing birtherThing, Pawn father, Pawn doctor, LordJob_Ritual lordJobRitual, RitualRoleAssignments assignments, bool preventLetter)
{
if (birtherThing is Pawn mother)
{
@ -215,7 +218,7 @@ namespace RJW_Menstruation
Pawn thisFather = baby.GetFather() ?? father;
baby.relations.ClearAllRelations(); // To keep ApplyBirthOutcome from erroring when it tries to set up relations
PregnancyUtility.ApplyBirthOutcome(thisOutcome, quality, ritual, genes, geneticMother, birtherThing, thisFather, doctor, lordJobRitual, assignments);
PregnancyUtility.ApplyBirthOutcome_NewTemp(thisOutcome, quality, ritual, genes, geneticMother, birtherThing, thisFather, doctor, lordJobRitual, assignments, preventLetter);
// No more babies if mom dies halfway through. Unrealistic maybe, but saves a lot of headache in ApplyBirthOutcome
if (mother.Dead) break;
if (xxx.is_human(baby))
@ -230,20 +233,25 @@ namespace RJW_Menstruation
}
}
return PregnancyUtility.ApplyBirthOutcome(outcome, quality, ritual, genes, geneticMother, birtherThing, father, doctor, lordJobRitual, assignments);
return PregnancyUtility.ApplyBirthOutcome_NewTemp(outcome, quality, ritual, genes, geneticMother, birtherThing, father, doctor, lordJobRitual, assignments, preventLetter);
}
private static readonly MethodInfo ApplyBirthOutcome = typeof(PregnancyUtility).GetMethod(nameof(PregnancyUtility.ApplyBirthOutcome),
new Type[] {typeof(RitualOutcomePossibility), typeof(float), typeof(Precept_Ritual), typeof(List<GeneDef>), typeof(Pawn), typeof(Thing), typeof(Pawn), typeof(Pawn), typeof(LordJob_Ritual), typeof(RitualRoleAssignments)});
private static readonly MethodInfo ApplyBirthOutcome_NewTemp = typeof(PregnancyUtility).GetMethod(nameof(PregnancyUtility.ApplyBirthOutcome_NewTemp),
new Type[] {typeof(RitualOutcomePossibility), typeof(float), typeof(Precept_Ritual), typeof(List<GeneDef>), typeof(Pawn), typeof(Thing), typeof(Pawn), typeof(Pawn), typeof(LordJob_Ritual), typeof(RitualRoleAssignments), typeof(bool)});
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
if (ApplyBirthOutcome?.ReturnType != typeof(Thing)) throw new InvalidOperationException("ApplyBirthOutcome not found");
bool methodPatched = false;
if (ApplyBirthOutcome_NewTemp?.ReturnType != typeof(Thing)) throw new InvalidOperationException("ApplyBirthOutcome_NewTemp not found");
foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(ApplyBirthOutcome))
if (instruction.Calls(ApplyBirthOutcome_NewTemp))
{
yield return CodeInstruction.Call(typeof(Hediff_LaborPushing_PreRemoved_Patch), nameof(Hediff_LaborPushing_PreRemoved_Patch.ApplyBirthLoop));
methodPatched = true;
}
else yield return instruction;
}
if (!methodPatched) throw new InvalidOperationException("Hediff_LaborPushing.PreRemoved not patched");
}
}
@ -283,17 +291,23 @@ namespace RJW_Menstruation
}
return PregnancyUtility.ApplyBirthOutcome(outcome, quality, ritual, genes, geneticMother, birtherThing, father, doctor, lordJobRitual, assignments);
}
// RitualOutcomeEffectWorker_ChildBirth.Apply does not call ApplyBirthOutcome_NewTemp
private static readonly MethodInfo ApplyBirthOutcome = typeof(PregnancyUtility).GetMethod(nameof(PregnancyUtility.ApplyBirthOutcome),
new Type[] { typeof(RitualOutcomePossibility), typeof(float), typeof(Precept_Ritual), typeof(List<GeneDef>), typeof(Pawn), typeof(Thing), typeof(Pawn), typeof(Pawn), typeof(LordJob_Ritual), typeof(RitualRoleAssignments) });
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
bool methodPatched = false;
if (ApplyBirthOutcome?.ReturnType != typeof(Thing)) throw new InvalidOperationException("ApplyBirthOutcome not found");
foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(ApplyBirthOutcome))
{
yield return CodeInstruction.Call(typeof(Ritual_ChildBirth_Apply_Patch), nameof(Ritual_ChildBirth_Apply_Patch.ApplyBirthLoop));
methodPatched = true;
}
else yield return instruction;
}
if (!methodPatched) throw new InvalidOperationException("RitualOutcomeEffectWorker_ChildBirth.Apply not patched");
}
}

View file

@ -128,7 +128,7 @@ namespace RJW_Menstruation
public static IEnumerable<MethodBase> TargetMethods()
{
yield return AccessTools.Method(typeof(PregnancyUtility), nameof(PregnancyUtility.TryTerminatePregnancy));
yield return AccessTools.Method(typeof(Recipe_TerminatePregnancy), nameof(Recipe_TerminatePregnancy.ApplyOnPawn));
// yield return AccessTools.Method(typeof(Recipe_TerminatePregnancy), nameof(Recipe_TerminatePregnancy.ApplyOnPawn));
}
private static PregnancyAttitude? GetAttitude(Hediff pregnancy)
@ -155,19 +155,30 @@ namespace RJW_Menstruation
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
int methodPatched = 0;
if (GetPregnancyHediff?.ReturnType != typeof(Hediff)) throw new InvalidOperationException("GetPregnancyHediff not found");
if (Get_Attitude == null || Nullable.GetUnderlyingType(Get_Attitude.ReturnType) != typeof(PregnancyAttitude)) throw new InvalidOperationException("get_Attitude not found");
foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(GetPregnancyHediff))
{
yield return CodeInstruction.Call(typeof(TerminatePregnancy_Patch), nameof(TerminatePregnancy_Patch.GetEarliestPregnancy));
methodPatched++;
}
// Menstruation pregnancies don't have an attitude, so skip the cast to Hediff_Pregnant and call a version that handles it
else if (instruction.opcode == OpCodes.Castclass && (Type)instruction.operand == typeof(Hediff_Pregnant))
{
yield return new CodeInstruction(OpCodes.Nop);
methodPatched++;
}
else if (instruction.Calls(Get_Attitude))
{
yield return CodeInstruction.Call(typeof(TerminatePregnancy_Patch), nameof(TerminatePregnancy_Patch.GetAttitude));
methodPatched++;
}
else yield return instruction;
}
if (methodPatched != 3) throw new InvalidOperationException($"PregnancyUtility.TryTerminatePregnancy or Recipe_TerminatePregnancy.ApplyOnPawn not patched ({methodPatched}");
}
}

View file

@ -3,6 +3,7 @@ using RimWorld;
using rjw;
using rjw.Modules.Interactions.Enums;
using rjw.Modules.Interactions.Objects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
@ -132,13 +133,18 @@ namespace RJW_Menstruation
private static readonly MethodInfo IsPregnant = AccessTools.Method(typeof(PawnExtensions), nameof(PawnExtensions.IsPregnant), new System.Type[] { typeof(Pawn), typeof(bool) });
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
bool methodPatched = false;
if (IsPregnant?.ReturnType != typeof(bool)) throw new System.InvalidOperationException("IsPregnant not found");
foreach (CodeInstruction instruction in instructions)
{
if (instruction.Calls(IsPregnant))
{
yield return CodeInstruction.Call(typeof(CanImpregnate_Patch), nameof(PregnancyBlocksImpregnation));
methodPatched = true;
}
else yield return instruction;
}
if (!methodPatched) throw new InvalidOperationException("PregnancyHelper.CanImpregnate not patched");
}
}
@ -238,6 +244,7 @@ namespace RJW_Menstruation
private static readonly FieldInfo MinimumFuckabilityToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumFuckabilityToHookup));
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
bool methodPatched = false;
if (MinimumFuckabilityToHookup?.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumFuckabilityToHookup not found");
bool first_fuckability = true;
foreach (CodeInstruction instruction in instructions)
@ -250,9 +257,11 @@ namespace RJW_Menstruation
yield return CodeInstruction.Call(typeof(Roll_To_Skip_Patch), nameof(FuckabilityThreshold));
first_fuckability = false;
methodPatched = true;
}
else yield return instruction;
}
if (!methodPatched) throw new InvalidOperationException("CasualSex_Helper.roll_to_skip not patched");
}
}
@ -274,6 +283,7 @@ namespace RJW_Menstruation
private static readonly FieldInfo MinimumRelationshipToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumRelationshipToHookup));
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
int methodPatched = 0;
if (MinimumAttractivenessToHookup?.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumAttractivenessToHookup not found");
if (MinimumRelationshipToHookup?.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumRelationshipToHookup not found");
LocalBuilder pawn_index = null;
@ -287,6 +297,7 @@ namespace RJW_Menstruation
{ // a future RJW or compiler update might change this, or maybe another mod's patch
pawn_index = (LocalBuilder)instruction.operand;
yield return instruction;
methodPatched++;
}
else if (instruction.LoadsField(MinimumAttractivenessToHookup))
{
@ -298,6 +309,7 @@ namespace RJW_Menstruation
yield return CodeInstruction.Call(typeof(FindBestPartner_Patch), nameof(AttractivenessThreshold));
first_attractiveness = false;
methodPatched++;
}
else if (instruction.LoadsField(MinimumRelationshipToHookup))
{
@ -309,9 +321,12 @@ namespace RJW_Menstruation
yield return CodeInstruction.Call(typeof(FindBestPartner_Patch), nameof(RelationshipThreshold));
first_relationship = false;
methodPatched++;
}
else yield return instruction;
}
// 5 because each LoadsField gets checked twice
if (methodPatched != 5) throw new System.InvalidOperationException($"CasualSex_Helper.FindBestPartner not patched ({methodPatched})");
}
}