Files
Performance-Fish/Source/PerformanceFish/MassUtilityCaching.cs
T
bbradson be3dae46bb Added stat caching, fixed all the bugs
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
2024-03-10 20:05:24 +01:00

129 lines
4.1 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 GearMassCache = PerformanceFish.Cache.ByInt<Verse.Pawn, PerformanceFish.MassUtilityCaching.GearMassCacheValue>;
using InventoryMassCache
= PerformanceFish.Cache.ByInt<Verse.Pawn, PerformanceFish.MassUtilityCaching.InventoryMassCacheValue>;
namespace PerformanceFish;
public sealed class MassUtilityCaching : ClassWithFishPatches
{
public sealed class GearMass_Patch : FirstPriorityFishPatch
{
public override string Description { get; } = "Caches pawn gear mass. Hauling jobs check this quite a lot";
public override Delegate TargetMethodGroup { get; } = MassUtility.GearMass;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Prefix(Pawn p, ref float __result, out bool __state)
{
ref var cache = ref GearMassCache.GetOrAddReference(p.thingIDNumber);
if (cache.IsDirty(p))
return __state = true;
__result = cache.Mass;
return __state = false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Postfix(Pawn p, bool __state, float __result)
{
if (!__state)
return;
UpdateCache(p, __result);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void UpdateCache(Pawn p, float __result)
=> GearMassCache.GetExistingReference(p).Update(__result, p);
}
public sealed class InventoryMass_Patch : FirstPriorityFishPatch
{
public override string Description { get; } = "Caches pawn inventory mass. Hauling jobs check this quite a lot";
public override Delegate TargetMethodGroup { get; } = MassUtility.InventoryMass;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Prefix(Pawn p, ref float __result, out bool __state)
{
ref var cache = ref InventoryMassCache.GetOrAddReference(p.thingIDNumber);
if (cache.IsDirty(p))
return __state = true;
__result = cache.Mass;
return __state = false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Postfix(Pawn p, bool __state, float __result)
{
if (!__state)
return;
UpdateCache(p, __result);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void UpdateCache(Pawn p, float __result)
=> InventoryMassCache.GetExistingReference(p).Update(__result, p);
}
public record struct GearMassCacheValue()
{
public float Mass;
private int _nextRefreshTick = -2;
private int _equipmentListsState = -69123;
public void Update(float mass, Pawn p)
{
Mass = mass;
_nextRefreshTick = TickHelper.Add(3072, p.thingIDNumber, 2048);
_equipmentListsState = GetEquipmentListsState(p);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetEquipmentListsState(Pawn p)
{
var result = p.apparel != null ? p.apparel.WornApparel._version : -1;
if (p.equipment != null)
{
var equipmentListVersion = (uint)p.equipment.AllEquipmentListForReading._version;
result += (int)((equipmentListVersion << 16) | (equipmentListVersion >> 16));
}
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsDirty(Pawn p)
=> TickHelper.Past(_nextRefreshTick)
|| _equipmentListsState != GetEquipmentListsState(p);
}
public record struct InventoryMassCacheValue()
{
public float Mass;
private int _nextRefreshTick = -2;
private int _inventoryListsState = -2;
public void Update(float mass, Pawn p)
{
Mass = mass;
//shorter refresh interval because of stack sizes not being considered by the listVersion check
_nextRefreshTick = TickHelper.Add(GenTicks.TickRareInterval, p.thingIDNumber);
_inventoryListsState = GetInventoryListsState(p);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetInventoryListsState(Pawn p)
=> p.inventory?.innerContainer is { } container ? container.innerList._version : -42;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsDirty(Pawn p)
=> TickHelper.Past(_nextRefreshTick)
|| _inventoryListsState != GetInventoryListsState(p);
}
}