/* 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; } }