be3dae46bb
Added RitualObligationTriggers analyzer category, Fixed defs from other mods with broken market value breaking fish's storage patches, Fixed storage caches not updating for quality, rotting and similar changes to stored things, Fixed storage caches not updating capacity when reinstalling storage, Fixed prison labor compatibility, Improved multiplayer compatibility, Fixed ideology style dominance and altar sharing patches throwing errors instead of defaulting to disabled when not having ideology, Fixed compatibility with RIMMSqol's world pawn GC patch by disabling that patch, Fixed rare threading issues throwing errors on startup
144 lines
4.5 KiB
C#
144 lines
4.5 KiB
C#
// Copyright (c) 2023 bradson
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
using RecipeUsersCache
|
|
= PerformanceFish.Cache.ByInt<Verse.RecipeDef,
|
|
PerformanceFish.Defs.RecipeDefCaching.AllRecipeUsers_Patch.RecipeUsersCacheValue>;
|
|
|
|
namespace PerformanceFish.Defs;
|
|
|
|
public sealed class RecipeDefCaching : ClassWithFishPatches
|
|
{
|
|
public override bool RequiresLoadedGameForPatching => true;
|
|
|
|
public sealed class AllRecipeUsers_Patch : FirstPriorityFishPatch
|
|
{
|
|
public override string Description { get; }
|
|
= "Caches results of the AllRecipeUsers method. Becomes impactful with lots of unfinished things around, "
|
|
+ "as those check everything for potentially accepting them";
|
|
|
|
public override MethodBase TargetMethodInfo { get; }
|
|
= AccessTools.PropertyGetter(typeof(RecipeDef), nameof(RecipeDef.AllRecipeUsers));
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static bool Prefix(RecipeDef? __instance, ref IEnumerable<ThingDef> __result, out bool __state)
|
|
{
|
|
if (__instance is null)
|
|
{
|
|
__state = false;
|
|
return true;
|
|
}
|
|
|
|
ref var cache = ref RecipeUsersCache.GetOrAddReference(__instance.shortHash);
|
|
if (cache.Dirty)
|
|
return __state = true;
|
|
|
|
__result = cache.RecipeUsers;
|
|
return __state = false;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void Postfix(RecipeDef __instance, IEnumerable<ThingDef> __result, bool __state)
|
|
{
|
|
if (!__state)
|
|
return;
|
|
|
|
UpdateCache(__instance, __result);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
private static void UpdateCache(RecipeDef __instance, IEnumerable<ThingDef> __result)
|
|
=> RecipeUsersCache.GetExistingReference(__instance).Update(__instance, __result);
|
|
|
|
public record struct RecipeUsersCacheValue()
|
|
{
|
|
private int _defDatabaseVersion = -2;
|
|
private int _defRecipeUsersVersion = -2;
|
|
private RecipeDef _def;
|
|
public List<ThingDef> RecipeUsers;
|
|
|
|
public void Update(RecipeDef instance, IEnumerable<ThingDef> result)
|
|
{
|
|
if (RecipeUsers is { } list)
|
|
{
|
|
list.Clear();
|
|
list.AddRange(result);
|
|
}
|
|
else
|
|
{
|
|
RecipeUsers = [..result];
|
|
}
|
|
|
|
_def = instance;
|
|
_defDatabaseVersion = DefDatabase<ThingDef>.defsList._version;
|
|
_defRecipeUsersVersion = instance.recipeUsers?._version ?? 0;
|
|
}
|
|
|
|
public bool Dirty
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get
|
|
=> _defDatabaseVersion != DefDatabase<ThingDef>.defsList._version
|
|
|| _defRecipeUsersVersion != (_def.recipeUsers?._version ?? 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*public sealed class PotentiallyMissingIngredients_Patch : FirstPriorityFishPatch
|
|
{
|
|
public override Expression<Action> TargetMethod { get; }
|
|
= () => new RecipeDef().PotentiallyMissingIngredients(null, null);
|
|
|
|
public static bool Prefix(RecipeDef __instance, Pawn billDoer, Map map, ref IEnumerable<ThingDef> __result)
|
|
{
|
|
if (!Cache.ByReference<RecipeDef, Pawn, Map, MissingIngredientsCache>.TryGetValue(__instance, billDoer, map,
|
|
out var cache))
|
|
return true;
|
|
|
|
if (__instance.ingredients.Count != 0)
|
|
{
|
|
Log.Warning("RecipeDef ingredients mismatched its cache in Performance Fish, forcing a refresh");
|
|
return true;
|
|
}
|
|
|
|
__result = cache.ingredientThingDefs;
|
|
return false;
|
|
}
|
|
|
|
public static void Postfix(RecipeDef __instance, Pawn billDoer, Map map, IEnumerable<ThingDef> __result,
|
|
bool __runOriginal)
|
|
{
|
|
if (!__runOriginal)
|
|
return;
|
|
|
|
Cache.ByReference<RecipeDef, Pawn, Map, MissingIngredientsCache>.Get[new(__instance, billDoer, map)]
|
|
= new()
|
|
{
|
|
ingredientThingDefs = __result.ToArray(),
|
|
firstIngredientsItemCount = __instance.ingredients.FirstOrDefault()?.count ?? 0,
|
|
ShouldRefreshNow = false
|
|
};
|
|
}
|
|
|
|
public static MissingIngredientsCache GetCache(RecipeDef def, Pawn billDoer, Map map)
|
|
=> Cache.ByReference<RecipeDef, Pawn, Map, MissingIngredientsCache>.GetValue(def, billDoer, map);
|
|
|
|
public record struct MissingIngredientsCache
|
|
{
|
|
public ThingDef[] ingredientThingDefs;
|
|
private int _nextRefreshFrame;
|
|
public int firstIngredientsItemCount;
|
|
|
|
public bool ShouldRefreshNow
|
|
{
|
|
get => Time.frameCount > _nextRefreshFrame;
|
|
set => _nextRefreshFrame = value ? 0 : Time.frameCount + 2048 + Math.Abs(Rand.Int % 1024);
|
|
}
|
|
|
|
public MissingIngredientsCache SetNewValue(Cache<RecipeDef, Pawn, Map, MissingIngredientsCache> key)
|
|
=> throw new NotImplementedException();
|
|
}
|
|
}*/
|
|
} |