Files
Performance-Fish/Source/PerformanceFish/Hediffs/ImmunityHandlerCaching.cs
T

146 lines
4.6 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 ImmunityInfoCache
= PerformanceFish.Cache.ByInt<Verse.Pawn,
PerformanceFish.Hediffs.ImmunityHandlerCaching.ImmunityInfoCacheValue>;
using ImmunityRecordExistsCache
= PerformanceFish.Cache.ByInt<Verse.Pawn, Verse.HediffDef,
PerformanceFish.Hediffs.ImmunityHandlerCaching.ImmunityRecordExistsCacheValue>;
namespace PerformanceFish.Hediffs;
public sealed class ImmunityHandlerCaching : ClassWithFishPatches
{
public sealed class NeededImmunitiesNow : FirstPriorityFishPatch
{
public override string Description { get; }
= "Caches results of the ImmunityHandler.NeededImmunitiesNow method. Impact scales with hediff quantity.";
public override MethodBase TargetMethodInfo { get; }
= AccessTools.Method(typeof(ImmunityHandler), nameof(ImmunityHandler.NeededImmunitiesNow));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Prefix(ImmunityHandler __instance, ref List<ImmunityHandler.ImmunityInfo> __result,
out bool __state)
{
ref var cache = ref ImmunityInfoCache.GetOrAddReference(__instance.pawn.thingIDNumber);
if (cache.Dirty)
return __state = true;
(__result = ImmunityHandler.tmpNeededImmunitiesNow).Clear();
__result.AddRangeFast(cache.Infos);
return __state = false;
}
// ImmunityHandler.tmpNeededImmunitiesNow, which is normally used for the result, is static
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Postfix(ImmunityHandler __instance, List<ImmunityHandler.ImmunityInfo> __result,
bool __state)
{
if (!__state)
return;
UpdateCache(__instance, __result);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void UpdateCache(ImmunityHandler __instance, List<ImmunityHandler.ImmunityInfo> __result)
=> ImmunityInfoCache.GetExistingReference(__instance.pawn)
.Update(__instance.pawn.health.hediffSet, __result);
}
public sealed class ImmunityRecordExists : FishPatch
{
public override string? Description { get; } = "Required by the TryAddImmunityRecord optimization.";
public override bool Enabled
{
set
{
if (base.Enabled == value)
return;
Get<TryAddImmunityRecord>().Enabled = base.Enabled = value;
}
}
public override MethodBase TargetMethodInfo { get; }
= AccessTools.Method(typeof(ImmunityHandler), nameof(ImmunityHandler.ImmunityRecordExists));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Postfix(ImmunityHandler __instance, HediffDef def, bool __result)
{
ref var cache
= ref ImmunityRecordExistsCache.GetOrAddReference(__instance.pawn.thingIDNumber, def.shortHash);
cache.Value = __result;
cache.ImmunityListVersion = __instance.immunityList._version;
}
}
public sealed class TryAddImmunityRecord : FishPatch
{
public override string? Description { get; }
= "Optimization for this specific method to not run more checks than necessary.";
public override bool Enabled
{
set
{
if (base.Enabled == value)
return;
Get<ImmunityRecordExists>().Enabled = base.Enabled = value;
}
}
public override MethodBase TargetMethodInfo { get; }
= AccessTools.Method(typeof(ImmunityHandler), nameof(ImmunityHandler.TryAddImmunityRecord));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Prefix(ImmunityHandler __instance, HediffDef def)
{
ref var cache
= ref ImmunityRecordExistsCache.GetOrAddReference(__instance.pawn.thingIDNumber, def.shortHash);
return !cache.Value || cache.ImmunityListVersion != __instance.immunityList._version;
}
}
public record struct ImmunityInfoCacheValue
{
private int _version = -1;
private List<Hediff> _hediffsInSet = [];
private int _nextRefreshTick;
public List<ImmunityHandler.ImmunityInfo> Infos = [];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(HediffSet set, List<ImmunityHandler.ImmunityInfo> infos)
{
Infos.ReplaceContentsWith(infos);
_hediffsInSet = set.hediffs;
_version = _hediffsInSet._version;
_nextRefreshTick = TickHelper.Add(GenTicks.TickLongInterval, set.pawn.thingIDNumber);
}
public bool Dirty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _version != _hediffsInSet._version || TickHelper.Past(_nextRefreshTick);
}
public ImmunityInfoCacheValue()
{
}
}
public record struct ImmunityRecordExistsCacheValue
{
public bool Value;
public int ImmunityListVersion;
}
}