/*
Copyright 2025 Maciej Pawłowski
This file is part of "Table Eating Toggle".
"Table Eating Toggle" is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
"Table Eating Toggle" is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with "Table Eating Toggle". If not, see .
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using HarmonyLib;
using RimWorld;
using Verse;
namespace TableToggle;
[HarmonyPatch]
public static class BaseChairValidator_Patch
{
[HarmonyTranspiler]
public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator)
{
CodeMatcher codeMatcher = new(instructions, generator);
try
{
codeMatcher.Start();
codeMatcher.MatchStartForward(
[
CodeMatch.LoadsField(typeof(Thing).GetField(nameof(Thing.def))),
CodeMatch.LoadsField(typeof(ThingDef).GetField(nameof(ThingDef.surfaceType))),
CodeMatch.LoadsConstant(),
CodeMatch.Branches()
]
)
.ThrowIfInvalid("Could not find SurfaceType check");
}
catch (Exception e)
{
Log.Error(e.Message);
return instructions;
}
CodeInstruction[] replace = [
new(OpCodes.Call, AccessTools.Method(typeof(ThingWithComps), nameof(ThingWithComps.GetComp), null, [typeof(EatableComp)])),
new(OpCodes.Stloc_3),
new(OpCodes.Ldloc_3),
new(OpCodes.Brfalse_S, (Label)codeMatcher.InstructionAt(3).operand),
new(OpCodes.Ldloc_3),
new(OpCodes.Ldfld, typeof(EatableComp).GetField(nameof(EatableComp.EatableFrom))),
new(OpCodes.Brfalse_S, (Label)codeMatcher.InstructionAt(3).operand)
];
codeMatcher.RemoveInstructions(4);
codeMatcher.Insert(replace);
return codeMatcher.Instructions().AsEnumerable();
}
[HarmonyTargetMethod]
private static MethodBase TargetMethod()
{
MethodInfo method = typeof(Toils_Ingest).GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
.FirstOrDefault(m => m.GetCustomAttribute() != null && Regex.IsMatch(m.Name, $@"^g__BaseChairValidator\|\d+(_\d+)?"));
if (method is not null) return method;
IEnumerable nestedTypes = typeof(Toils_Ingest).GetNestedTypes(BindingFlags.NonPublic).Where(t => t.GetCustomAttribute() != null);
foreach(Type nested in nestedTypes)
{
method = nested.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(m => Regex.IsMatch(m.Name, $@"^g__BaseChairValidator\|\d+(_\d+)?"));
if (method is not null) return method;
}
return null;
}
// Building.GetComp().EatableFrom
}