Added gas grid optimization, various despawn optimizations, new hauling optimizations utilizing events and regions, bugfixes for old patches and for vanilla functions too, as well as smaller additions. 1.3 files removed.
This commit is contained in:
@@ -5,44 +5,55 @@
|
||||
|
||||
using System.Linq;
|
||||
using System.Reflection.Emit;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using PerformanceFish.Prepatching;
|
||||
using Verse.AI;
|
||||
using IngredientCacheList
|
||||
= PerformanceFish.Utility.KeyedList<Verse.IngredientCount, (System.Collections.Generic.List<Verse.ThingDef> Defs,
|
||||
bool Found)>;
|
||||
using OpCodes = System.Reflection.Emit.OpCodes;
|
||||
using RecipeIngredientCache
|
||||
= PerformanceFish.Cache.ByIndex<RimWorld.Bill,
|
||||
PerformanceFish.JobSystem.WorkGiver_DoBillOptimization.RecipeIngredientCacheValue>;
|
||||
|
||||
namespace PerformanceFish.JobSystem;
|
||||
|
||||
public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
public sealed class WorkGiver_DoBillPrepatches : ClassWithFishPrepatches
|
||||
{
|
||||
public static List<Type?> BlackListedModExtensions
|
||||
=> _blackListedModExtensions ??= new() { Reflection.Type("VFEAncients", "VFEAncients.RecipeExtension_Mend") };
|
||||
public static List<Type> BlackListedModExtensions
|
||||
=> _blackListedModExtensions ??= InitializeBlackListedModExtensions();
|
||||
|
||||
private static List<Type?>? _blackListedModExtensions;
|
||||
|
||||
public class TryFindBestIngredientsHelper_InnerDelegate_Patch : FirstPriorityFishPatch
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static List<Type> InitializeBlackListedModExtensions()
|
||||
{
|
||||
var list = new List<Type>();
|
||||
|
||||
if (ModCompatibility.Types.VFEAncients.RecipeExtensionMend is { } VFEAncientsRecipeExtension)
|
||||
list.Add(VFEAncientsRecipeExtension);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static List<Type>? _blackListedModExtensions;
|
||||
|
||||
public sealed class TryFindBestIngredientsHelper_InnerDelegate_Patch : FishPrepatch
|
||||
{
|
||||
public override List<string> IncompatibleModIDs { get; }
|
||||
= [ModCompatibility.PackageIDs.USE_BEST_MATERIALS];
|
||||
|
||||
public override List<Type> LinkedPatches { get; } =
|
||||
[
|
||||
typeof(WorkGiver_DoBillOptimization.TryFindBestIngredientsHelper_Patch),
|
||||
typeof(WorkGiver_DoBillOptimization.TryFindBestIngredientsInSet_NoMixHelper_Patch)
|
||||
];
|
||||
|
||||
public override string Description { get; }
|
||||
= "Optimizes WorkGiver_DoBill to only check things that get accepted by a bill's filter for its "
|
||||
+ "ingredient lookup, instead of looping over everything and then checking filters afterwards. "
|
||||
+ "Also caches these filter acceptances. Large performance impact.";
|
||||
|
||||
public override bool Enabled
|
||||
{
|
||||
set
|
||||
{
|
||||
if (base.Enabled == value)
|
||||
return;
|
||||
|
||||
Get<TryFindBestIngredientsHelper_Patch>().Enabled
|
||||
= Get<TryFindBestIngredientsInSet_NoMixHelper_Patch>().Enabled
|
||||
= base.Enabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override MethodBase TargetMethodInfo { get; }
|
||||
public override MethodBase TargetMethodBase { get; }
|
||||
= AccessTools.FirstMethod(DelegateInstanceType, static m
|
||||
=> m.GetParameters() is { Length: 1 } parameterInfos
|
||||
&& parameterInfos[0].ParameterType == typeof(Region)
|
||||
@@ -52,12 +63,15 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
&& instruction.operand is MethodInfo info
|
||||
&& info == AccessTools.Method(typeof(ListerThings), nameof(ListerThings.ThingsMatching))));
|
||||
|
||||
public static CodeInstructions Transpiler(CodeInstructions codeInstructions, MethodBase method)
|
||||
=> Reflection.MakeReplacementCall(AccessTools.Method(
|
||||
typeof(TryFindBestIngredientsHelper_InnerDelegate_Patch), nameof(Replacement),
|
||||
generics: new[] { DelegateInstanceType }));
|
||||
public override void Transpiler(ILProcessor ilProcessor, ModuleDefinition module)
|
||||
=> ilProcessor.ReplaceBodyWith(ReplacementBody);
|
||||
|
||||
public static bool Replacement<T>(T __instance, Region r) where T : class
|
||||
// public static CodeInstructions Transpiler(CodeInstructions codeInstructions, MethodBase method)
|
||||
// => Reflection.MakeReplacementCall(AccessTools.Method(
|
||||
// typeof(TryFindBestIngredientsHelper_InnerDelegate_Patch), nameof(ReplacementBody),
|
||||
// generics: new[] { DelegateInstanceType }));
|
||||
|
||||
public static bool ReplacementBody(object __instance, Region r)
|
||||
{
|
||||
var instance = _delegateInstance.Get(__instance);
|
||||
var thingValidator = _thingValidatorInstance.Get(instance.ThingValidator.Target);
|
||||
@@ -75,7 +89,7 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
#if V1_4
|
||||
|| bill.billStack?.billGiver is Building_MechGestator
|
||||
#endif
|
||||
|| (BlackListedModExtensions.Exists(static b => b != null)
|
||||
|| (BlackListedModExtensions.Count > 0
|
||||
&& IsBlackListed(bill))) // <-- Fuck these too
|
||||
{
|
||||
list = GetDefaultList(r);
|
||||
@@ -89,7 +103,7 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
cache.Update(bill);
|
||||
}
|
||||
|
||||
list = GetList(r.listerThings.listsByDef, cache.thingDefs);
|
||||
list = GetList(r, cache.thingDefs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,10 +124,9 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
|
||||
instance.FoundAll = true;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private static bool HasNoFilters(Bill bill)
|
||||
public static bool HasNoFilters(Bill bill)
|
||||
=> bill.ingredientFilter is null
|
||||
|| bill.recipe.fixedIngredientFilter is null;
|
||||
|
||||
@@ -135,13 +148,13 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
return false;
|
||||
}*/
|
||||
|
||||
private static bool IsBlackListed(Bill? bill)
|
||||
public static bool IsBlackListed(Bill? bill)
|
||||
=> bill is null
|
||||
|| bill.recipe.modExtensions.ExistsAndNotNull(static e
|
||||
=> BlackListedModExtensions.Contains(e.GetType()));
|
||||
|
||||
private static List<Thing> GetDefaultList(Region r)
|
||||
=> r.ListerThings.ThingsMatching(ThingRequest.ForGroup(ThingRequestGroup.HaulableEver));
|
||||
public static List<Thing> GetDefaultList(Region r)
|
||||
=> r.listerThings.ThingsMatching(ThingRequest.ForGroup(ThingRequestGroup.HaulableEver));
|
||||
|
||||
public static void InsertAtCorrectPosition(List<Thing> list, List<Thing> thingsToInsert, Pawn pawn)
|
||||
{
|
||||
@@ -159,7 +172,8 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ThingPositionComparer _insertAtCorrectPositionComparer = new();
|
||||
private static readonly WorkGiver_DoBillOptimization.ThingPositionComparer _insertAtCorrectPositionComparer
|
||||
= new();
|
||||
|
||||
public static void ActualLoop(List<Thing> list, Region r, Pawn pawn, Predicate<Thing> baseValidator,
|
||||
bool billGiverIsPawn)
|
||||
@@ -182,8 +196,10 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Thing> GetList(Dictionary<ThingDef, List<Thing>> listsByDef, IngredientCacheList cacheList)
|
||||
public static List<Thing> GetList(Region region, IngredientCacheList cacheList)
|
||||
{
|
||||
var listsByDef = region.listerThings.listsByDef;
|
||||
|
||||
var list = _tempListForIngredients;
|
||||
list.Clear();
|
||||
var set = _tempSetForIngredientDefs;
|
||||
@@ -216,7 +232,7 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
{
|
||||
var recipe = bill.recipe;
|
||||
var ingredients = recipe.ingredients;
|
||||
var listsByDef = r.Map.listerThings.listsByDef;
|
||||
var listsByDef = r.GetMap().listerThings.listsByDef;
|
||||
var result = cacheList ?? new(3);
|
||||
|
||||
for (var i = 0; i < ingredients.Count;
|
||||
@@ -229,7 +245,7 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
}
|
||||
else
|
||||
{
|
||||
result[ingredients[i]] = ingredientList = new(new(), false);
|
||||
result[ingredients[i]] = ingredientList = new([], false);
|
||||
}
|
||||
|
||||
var filter = ingredients[i].filter;
|
||||
@@ -291,8 +307,8 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
(mediumFilter, largestFilter) = (largestFilter, mediumFilter);
|
||||
}
|
||||
|
||||
private static readonly List<Thing> _tempListForIngredients = new();
|
||||
private static readonly HashSet<ThingDef> _tempSetForIngredientDefs = new();
|
||||
private static readonly List<Thing> _tempListForIngredients = [];
|
||||
private static readonly HashSet<ThingDef> _tempSetForIngredientDefs = [];
|
||||
}
|
||||
|
||||
private static Type DelegateInstanceType { get; }
|
||||
@@ -308,8 +324,8 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
&& AccessTools.Field(t, "foundAllIngredientsAndChoose") != null
|
||||
&& AccessTools.Field(t, "foundAll") != null
|
||||
&& AccessTools.Field(t, "thingValidator") != null)
|
||||
?? throw new("Performance Fish failed to find the target type for its WorkGiver_DoBill patch. "
|
||||
+ "This means that specific patch won't apply.");
|
||||
?? ThrowHelper.ThrowInvalidOperationException<Type>("Performance Fish failed to find the target type "
|
||||
+ "for its WorkGiver_DoBill patch. This means that specific patch won't apply.");
|
||||
|
||||
private static Type ThingValidatorInstanceType { get; }
|
||||
= AccessTools.FirstInner(typeof(WorkGiver_DoBill), static t
|
||||
@@ -320,20 +336,20 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
//&& AccessTools.Field(t, "chosen") != null
|
||||
//&& AccessTools.Field(t, "billGiver") != null
|
||||
/*&& AccessTools.Field(t, "pawn") != null*/)
|
||||
?? throw new("Performance Fish failed to find the thingValidator type for its WorkGiver_DoBill patch. "
|
||||
+ "This likely flat out breaks the entire patch.");
|
||||
?? ThrowHelper.ThrowInvalidOperationException<Type>("Performance Fish failed to find the thingValidator "
|
||||
+ "type for its WorkGiver_DoBill patch. This likely flat out breaks the entire patch.");
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static DelegateInstance _delegateInstance { get; }
|
||||
public static DelegateInstance _delegateInstance { get; }
|
||||
= (DelegateInstance)Activator.CreateInstance(
|
||||
typeof(DelegateInstanceImplementation<>).MakeGenericType(DelegateInstanceType));
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static ThingValidatorInstance _thingValidatorInstance { get; }
|
||||
public static ThingValidatorInstance _thingValidatorInstance { get; }
|
||||
= (ThingValidatorInstance)Activator.CreateInstance(
|
||||
typeof(ThingValidatorInstanceImplementation<>).MakeGenericType(ThingValidatorInstanceType));
|
||||
|
||||
private abstract class DelegateInstance
|
||||
public abstract class DelegateInstance
|
||||
{
|
||||
public abstract DelegateInstance Get(object obj);
|
||||
|
||||
@@ -347,7 +363,7 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
public abstract Predicate<Thing> ThingValidator { get; set; }
|
||||
}
|
||||
|
||||
private class DelegateInstanceImplementation<T> : DelegateInstance where T : class
|
||||
private sealed class DelegateInstanceImplementation<T> : DelegateInstance where T : class
|
||||
{
|
||||
#pragma warning disable CS8618
|
||||
private T _instance;
|
||||
@@ -430,7 +446,7 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
= AccessTools.FieldRefAccess<T, Predicate<Thing>>("thingValidator");
|
||||
}
|
||||
|
||||
private abstract class ThingValidatorInstance
|
||||
public abstract class ThingValidatorInstance
|
||||
{
|
||||
public abstract ThingValidatorInstance? Get(object obj);
|
||||
|
||||
@@ -438,7 +454,7 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
//public abstract Thing BillGiver { get; set; }
|
||||
}
|
||||
|
||||
private class ThingValidatorInstanceImplementation<T> : ThingValidatorInstance where T : class
|
||||
private sealed class ThingValidatorInstanceImplementation<T> : ThingValidatorInstance where T : class
|
||||
{
|
||||
#pragma warning disable CS8618
|
||||
private T _instance;
|
||||
@@ -467,27 +483,21 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
private static AccessTools.FieldRef<T, Bill> _bill = AccessTools.FieldRefAccess<T, Bill>("bill");
|
||||
//private static AccessTools.FieldRef<T, Thing> _billGiver = AccessTools.FieldRefAccess<T, Thing>("billGiver");
|
||||
}
|
||||
}
|
||||
|
||||
public class TryFindBestIngredientsHelper_Patch : FishPatch
|
||||
public sealed class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
{
|
||||
public sealed class TryFindBestIngredientsHelper_Patch : FishPatch
|
||||
{
|
||||
public override bool ShowSettings => false;
|
||||
|
||||
public override string Description { get; } = "Part of the DoBill optimization";
|
||||
|
||||
public override bool Enabled
|
||||
{
|
||||
set
|
||||
{
|
||||
if (base.Enabled == value)
|
||||
return;
|
||||
|
||||
Get<TryFindBestIngredientsInSet_NoMixHelper_Patch>().Enabled = base.Enabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override Delegate TargetMethodGroup { get; } = WorkGiver_DoBill.TryFindBestIngredientsHelper;
|
||||
|
||||
public static void Postfix(Predicate<Thing> thingValidator)
|
||||
{
|
||||
var thingValidatorInstance = _thingValidatorInstance.Get(thingValidator.Target);
|
||||
var thingValidatorInstance = WorkGiver_DoBillPrepatches._thingValidatorInstance.Get(thingValidator.Target);
|
||||
if (thingValidatorInstance is null)
|
||||
return;
|
||||
|
||||
@@ -505,8 +515,10 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
}
|
||||
}
|
||||
|
||||
public class TryFindBestIngredientsInSet_NoMixHelper_Patch : FishPatch
|
||||
public sealed class TryFindBestIngredientsInSet_NoMixHelper_Patch : FishPatch
|
||||
{
|
||||
public override List<Type> LinkedPatches { get; } = [typeof(TryFindBestIngredientsHelper_Patch)];
|
||||
|
||||
public override string Description { get; }
|
||||
= "Part of the DoBill optimization. Bills that need multiple ingredients, like for example steel and "
|
||||
+ "components for guns, normally scan their surroundings for all those ingredients and count them, until "
|
||||
@@ -515,17 +527,6 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
+ "case of steel and components that could mean not having to go over 100s of steel stacks at times. "
|
||||
+ "Prevents large spikes from these situations, does nothing for all other bills.";
|
||||
|
||||
public override bool Enabled
|
||||
{
|
||||
set
|
||||
{
|
||||
if (base.Enabled == value)
|
||||
return;
|
||||
|
||||
Get<TryFindBestIngredientsHelper_Patch>().Enabled = base.Enabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override Delegate TargetMethodGroup { get; } = WorkGiver_DoBill.TryFindBestIngredientsInSet_NoMixHelper;
|
||||
|
||||
public static void Prefix(ref bool alreadySorted, Bill? bill)
|
||||
@@ -549,16 +550,15 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
&& codes[i + 1] == FishTranspiler.Constant(1) // i++;
|
||||
&& codes[i + 2] == FishTranspiler.Add
|
||||
&& codes[i + 3] == i_variable.Store(),
|
||||
code
|
||||
=> new[]
|
||||
{
|
||||
code =>
|
||||
[
|
||||
new(OpCodes.Br_S, new_i_label), // else
|
||||
FishTranspiler.FirstLocalVariable(method, typeof(IngredientCount))
|
||||
.WithLabels(code.ExtractLabels()),
|
||||
FishTranspiler.FirstArgument(method, typeof(Bill)),
|
||||
FishTranspiler.Call(MarkIngredientCountAsFound),
|
||||
code.WithLabels(new_i_label)
|
||||
});
|
||||
]);
|
||||
|
||||
// if (!flag)
|
||||
// {
|
||||
@@ -599,7 +599,7 @@ public class WorkGiver_DoBillOptimization : ClassWithFishPatches
|
||||
}
|
||||
}
|
||||
|
||||
public class ThingPositionComparer : IComparer<Thing>
|
||||
public sealed class ThingPositionComparer : IComparer<Thing>
|
||||
{
|
||||
public IntVec3 rootCell;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user