Skip to content

Commit

Permalink
Merge pull request #802 from zymex22/issue788
Browse files Browse the repository at this point in the history
Fixes Issue where Smart Recycler Won't produce anything for non Smeltable Stuff
  • Loading branch information
Sn1p3rr3c0n authored Jul 23, 2024
2 parents e5f5cdd + 8f3113a commit 69e1788
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 80 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using HarmonyLib;
using ProjectRimFactory.Drones;
using RimWorld;
using Verse;

namespace ProjectRimFactory.Common.HarmonyPatches;

[HarmonyPatch(typeof(QualityUtility), "GenerateQualityCreatedByPawn", new Type[] { typeof(Pawn), typeof(SkillDef) })]
class Patch_GenRecipe_GenerateQualityCreatedByPawn
{
static bool Prefix(ref QualityCategory __result, Pawn pawn, SkillDef relevantSkill)
{
ISetQualityDirectly isqd = PatchStorageUtil.Get<ISetQualityDirectly>(pawn.Map, pawn.Position);
if (isqd != null)
{
__result = isqd.GetQuality(relevantSkill);
return false;
}
return true;
}

//Prevent Biotech(Mech Changes) from interfering with Drone Skills
static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{

bool foundReplaceMarker = false;
bool repacedCheck = false;
int cnt = 0;
foreach (var instruction in instructions)
{
cnt++;
//Search for IL_0000: ldarg.0 -> Loading the Pawn
if (instruction.opcode == OpCodes.Ldarg_0 && !repacedCheck)
{
repacedCheck = true;
foundReplaceMarker = true;
cnt = 0;
}
//remove IL_0001: callvirt instance class Verse.RaceProperties Verse.Pawn::get_RaceProps()
if (instruction.opcode == OpCodes.Callvirt && foundReplaceMarker && cnt == 1)
{
continue;
}
if (instruction.opcode == OpCodes.Callvirt && foundReplaceMarker && cnt == 2)
{
//Replace IL_0006: callvirt instance bool Verse.RaceProperties::get_IsMechanoid()
//with a call to Patch_GenRecipe_GenerateQualityCreatedByPawn:IsMechanoid(Pawn pawn)
instruction.operand = AccessTools.Method(
typeof(Patch_GenRecipe_GenerateQualityCreatedByPawn),
nameof(Patch_GenRecipe_GenerateQualityCreatedByPawn.IsMechanoid), new[] { typeof(Pawn)});
foundReplaceMarker = false;
}


yield return instruction;
}

}

/// <summary>
/// if a Pawn is a Mechanoid then it's skills will be ignored by QualityUtility:GenerateQualityCreatedByPawn
/// This prevents Drones from being detected as Mechanoid
/// </summary>
/// <param name="pawn"></param>
/// <returns></returns>
public static bool IsMechanoid(Pawn pawn)
{
if (pawn is Pawn_Drone)
{
return false;
}
return pawn.RaceProps.IsMechanoid;
}
}

interface ISetQualityDirectly
{
QualityCategory GetQuality(SkillDef relevantSkill);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using HarmonyLib;
using ProjectRimFactory.Drones;
using ProjectRimFactory.SAL3.Things.Assemblers;
using RimWorld;
using System;
Expand Down Expand Up @@ -28,7 +27,7 @@ namespace ProjectRimFactory.Common.HarmonyPatches
* use Transpiler to modify the code.
*/
[HarmonyPatch]
public static class Patch_GenRecipe_foodPoisoning
public static class Patch_GenRecipe_MakeRecipeProducts_foodPoisoning
{
/// <summary>
/// Doing this should find the inner iterator class no matter how the compiler calls it.
Expand Down Expand Up @@ -75,8 +74,8 @@ public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructio
yield return new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(hiddenClass, "billGiver"));
// Call our UsingSpaceCooker method
yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(
typeof(Patch_GenRecipe_foodPoisoning),
nameof(Patch_GenRecipe_foodPoisoning.UsingSpaceCooker)));
typeof(Patch_GenRecipe_MakeRecipeProducts_foodPoisoning),
nameof(Patch_GenRecipe_MakeRecipeProducts_foodPoisoning.UsingSpaceCooker)));
// If that returned true, skip past the original condition
yield return new CodeInstruction(OpCodes.Brtrue_S, (Label)instruction.operand);
codeHasStoredCompPoisonable = false;
Expand All @@ -97,8 +96,8 @@ public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructio
yield return new CodeInstruction(OpCodes.Ldarg_0);
yield return new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(hiddenClass, "billGiver"));
yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(
typeof(Patch_GenRecipe_foodPoisoning),
nameof(Patch_GenRecipe_foodPoisoning.GetRoomOfPawnOrGiver)));
typeof(Patch_GenRecipe_MakeRecipeProducts_foodPoisoning),
nameof(Patch_GenRecipe_MakeRecipeProducts_foodPoisoning.GetRoomOfPawnOrGiver)));

continue; // Don't emit the original instruction.
}
Expand Down Expand Up @@ -139,78 +138,4 @@ public static Room GetRoomOfPawnOrGiver(Pawn pawn, RegionType allowedRegionTypes
}
}

[HarmonyPatch(typeof(QualityUtility), "GenerateQualityCreatedByPawn", new Type[] { typeof(Pawn), typeof(SkillDef) })]
class Patch_GenRecipe_GenerateQualityCreatedByPawn
{
static bool Prefix(ref QualityCategory __result, Pawn pawn, SkillDef relevantSkill)
{
ISetQualityDirectly isqd = PatchStorageUtil.Get<ISetQualityDirectly>(pawn.Map, pawn.Position);
if (isqd != null)
{
__result = isqd.GetQuality(relevantSkill);
return false;
}
return true;
}

//Prevent Biotech(Mech Changes) from interfering with Drone Skills
static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{

bool foundReplaceMarker = false;
bool repacedCheck = false;
int cnt = 0;
foreach (var instruction in instructions)
{
cnt++;
//Search for IL_0000: ldarg.0 -> Loading the Pawn
if (instruction.opcode == OpCodes.Ldarg_0 && !repacedCheck)
{
repacedCheck = true;
foundReplaceMarker = true;
cnt = 0;
}
//remove IL_0001: callvirt instance class Verse.RaceProperties Verse.Pawn::get_RaceProps()
if (instruction.opcode == OpCodes.Callvirt && foundReplaceMarker && cnt == 1)
{
continue;
}
if (instruction.opcode == OpCodes.Callvirt && foundReplaceMarker && cnt == 2)
{
//Replace IL_0006: callvirt instance bool Verse.RaceProperties::get_IsMechanoid()
//with a call to Patch_GenRecipe_GenerateQualityCreatedByPawn:IsMechanoid(Pawn pawn)
instruction.operand = AccessTools.Method(
typeof(Patch_GenRecipe_GenerateQualityCreatedByPawn),
nameof(Patch_GenRecipe_GenerateQualityCreatedByPawn.IsMechanoid), new[] { typeof(Pawn)});
foundReplaceMarker = false;
}


yield return instruction;
}

}

/// <summary>
/// if a Pawn is a Mechanoid then it's skills will be ignored by QualityUtility:GenerateQualityCreatedByPawn
/// This prevents Drones from being detected as Mechanoid
/// </summary>
/// <param name="pawn"></param>
/// <returns></returns>
public static bool IsMechanoid(Pawn pawn)
{
if (pawn is Pawn_Drone)
{
return false;
}
return pawn.RaceProps.IsMechanoid;
}

}

interface ISetQualityDirectly
{
QualityCategory GetQuality(SkillDef relevantSkill);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using HarmonyLib;
using Verse;

namespace ProjectRimFactory.Common.HarmonyPatches;

/// <summary>
/// Change Thing.SmeltProducts so that if
/// ProjectRimFactory.Common.HarmonyPatches.Patch_Thing_SmeltProducts.RecyclerProducingItems
/// is Set, the Check "costListAdj[j].thingDef.smeltable" will be Ignored
///
/// Since Vanilla uses the actual Value instead of the Getter we Can't simply patch the Getter,
/// Instead we need to Transpile Thing.SmeltProducts
/// </summary>
[HarmonyPatch]
public class Patch_Thing_SmeltProducts
{
private static readonly Type hiddenClass = AccessTools.FirstInner(
typeof(Thing),
type => type.HasAttribute<CompilerGeneratedAttribute>() && type.Name.Contains(nameof(Thing.SmeltProducts)));

public static MethodBase TargetMethod()
{
// Decompiler showed the hidden inner class is "<SmeltProducts>d__223"
if (hiddenClass == null)
{
Log.Error("Couldn't find iterator class -- This should never be reached.");
return null;
}
// and we want the iterator's MoveNext:
MethodBase iteratorMethod = HarmonyLib.AccessTools.Method(hiddenClass, "MoveNext");
if (iteratorMethod == null) Log.Error("Couldn't find MoveNext");
return iteratorMethod;
}

private static bool smeltableFound = false;

static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
foreach (var instruction in instructions)
{
if (!smeltableFound)
{
if (instruction.opcode == OpCodes.Ldfld && instruction.operand.ToString().Contains("smeltable"))
{
smeltableFound = true;

// now replace it with a call to Patch_Thing_SmeltProducts.Smeltable
yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(
typeof(Patch_Thing_SmeltProducts),
nameof(Patch_Thing_SmeltProducts.Smeltable)));
continue;

}
else
{
yield return instruction;
continue;
}
}

// Don't touch the rest
yield return instruction;
}


}

public static bool RecyclerProducingItems = false;

/// <summary>
/// Skips the def.smeltable Check if RecyclerProducingItems
/// </summary>
/// <param name="def"></param>
/// <returns></returns>
public static bool Smeltable(ThingDef def)
{
return RecyclerProducingItems || def.smeltable;
}



}
1 change: 1 addition & 0 deletions Source/ProjectRimFactory/Common/PRFDefOf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ static PRFDefOf()
public static ThingDef PRF_DroneModule;
public static ThingDef Column;
public static ThingDef PRF_MiniDroneColumn;
public static ThingDef PRF_Recycler;

public static BackstoryDef ChildSpy47;
public static BackstoryDef ColonySettler53;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,12 +437,14 @@ protected virtual void ProduceItems()
return;
}
// GenRecipe handles creating any bonus products
if (this.def == PRFDefOf.PRF_Recycler) Patch_Thing_SmeltProducts.RecyclerProducingItems = true;
IEnumerable<Thing> products = GenRecipe.MakeRecipeProducts(currentBillReport.bill.recipe, buildingPawn, currentBillReport.selected, ProjectSAL_Utilities.CalculateDominantIngredient(currentBillReport.bill.recipe, currentBillReport.selected), this);
foreach (Thing thing in products)
{
PostProcessRecipeProduct(thing);
thingQueue.Add(thing);
}
Patch_Thing_SmeltProducts.RecyclerProducingItems = false;
for (int i = 0; i < currentBillReport.selected.Count; i++)
{
if (currentBillReport.selected[i] is Corpse c)
Expand Down

0 comments on commit 69e1788

Please sign in to comment.