Lots of new optimizations utilizing prepatcher

To start, this mod now requires Prepatcher and Fishery.
New optimizations include: gene ticking improvements, world object improvements, hediff optimizations, world pawn gc optimizations, better mothballing, dds support, ContentFinder caching, additions and changes to reflection caching, as well as various other additions. Multiplayer support has been improved too, but should be considered highly experimental. The WorkGiver_DoBill bug is fixed in this build. Multiple patches aiming to improve RimWorld's load time have been added too.
This commit is contained in:
bbradson
2023-06-03 20:24:38 +02:00
parent cb0a407425
commit ca9321add8
125 changed files with 11272 additions and 3681 deletions
+57 -31
View File
@@ -1,10 +1,11 @@
// Copyright (c) 2022 bradson
// 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.ByIndex<Verse.Pawn, PerformanceFish.MassUtilityCaching.GearMassCacheValue>;
using InventoryMassCache = PerformanceFish.Cache.ByIndex<Verse.Pawn, PerformanceFish.MassUtilityCaching.InventoryMassCacheValue>;
using GearMassCache = PerformanceFish.Cache.ByInt<Verse.Pawn, PerformanceFish.MassUtilityCaching.GearMassCacheValue>;
using InventoryMassCache
= PerformanceFish.Cache.ByInt<Verse.Pawn, PerformanceFish.MassUtilityCaching.InventoryMassCacheValue>;
namespace PerformanceFish;
@@ -12,17 +13,17 @@ public class MassUtilityCaching : ClassWithFishPatches
{
public class GearMass_Patch : FirstPriorityFishPatch
{
public override string Description => "Caches pawn gear mass. Hauling jobs check this quite a lot";
public override Delegate TargetMethodGroup => MassUtility.GearMass;
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.Get.GetReference(p);
if (cache.ShouldRefreshNow(p))
ref var cache = ref GearMassCache.GetOrAddReference(p.thingIDNumber);
if (cache.IsDirty(p))
return __state = true;
__result = cache.mass;
__result = cache.Mass;
return __state = false;
}
@@ -32,23 +33,27 @@ public class MassUtilityCaching : ClassWithFishPatches
if (!__state)
return;
GearMassCache.Get[p] = new(__result, p);
UpdateCache(p, __result);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void UpdateCache(Pawn p, float __result)
=> GearMassCache.GetExistingReference(p).Update(__result, p);
}
public class InventoryMass_Patch : FirstPriorityFishPatch
{
public override string Description => "Caches pawn inventory mass. Hauling jobs check this quite a lot";
public override Delegate TargetMethodGroup => MassUtility.InventoryMass;
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.Get.GetReference(p);
if (cache.ShouldRefreshNow(p))
ref var cache = ref InventoryMassCache.GetOrAddReference(p.thingIDNumber);
if (cache.IsDirty(p))
return __state = true;
__result = cache.mass;
__result = cache.Mass;
return __state = false;
}
@@ -58,43 +63,64 @@ public class MassUtilityCaching : ClassWithFishPatches
if (!__state)
return;
InventoryMassCache.Get[p] = new(__result, p);
UpdateCache(p, __result);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void UpdateCache(Pawn p, float __result)
=> InventoryMassCache.GetExistingReference(p).Update(__result, p);
}
public struct GearMassCacheValue
public record struct GearMassCacheValue
{
public float mass;
public float Mass;
private int _nextRefreshTick;
private int _equipmentListsState;
public GearMassCacheValue(float mass, Pawn p)
public void Update(float mass, Pawn p)
{
this.mass = mass;
_nextRefreshTick = Current.Game.tickManager.TicksGame + 3072 + Math.Abs(Rand.Int % 2048);
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() : 0;
var result = p.apparel != null ? p.apparel.WornApparel._version : 0;
if (p.equipment != null)
result += p.equipment.AllEquipmentListForReading.Version();
result += p.equipment.AllEquipmentListForReading._version;
return result;
}
public bool ShouldRefreshNow(Pawn p) => _nextRefreshTick < Current.Game.tickManager.TicksGame || _equipmentListsState != GetEquipmentListsState(p);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsDirty(Pawn p)
=> TickHelper.Past(_nextRefreshTick)
|| _equipmentListsState != GetEquipmentListsState(p);
}
public struct InventoryMassCacheValue
public record struct InventoryMassCacheValue
{
public float mass;
public float Mass;
private int _nextRefreshTick;
private int _inventoryListsState;
public InventoryMassCacheValue(float mass, Pawn p)
public void Update(float mass, Pawn p)
{
this.mass = mass;
_nextRefreshTick = Current.Game.tickManager.TicksGame + 256 + Math.Abs(Rand.Int % 256);
_inventoryListsState = GetInventoryListsState(p); //shorter refresh interval because of stack sizes not being considered by the listVersion check
Mass = mass;
_nextRefreshTick = TickHelper.Add(GenTicks.TickRareInterval, p.thingIDNumber);
_inventoryListsState
= GetInventoryListsState(
p); //shorter refresh interval because of stack sizes not being considered by the listVersion check
}
private static int GetInventoryListsState(Pawn p) => p.inventory?.innerContainer is { } container ? container.innerList.Version() : 0;
public bool ShouldRefreshNow(Pawn p) => _nextRefreshTick < Current.Game.tickManager.TicksGame || _inventoryListsState != GetInventoryListsState(p);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetInventoryListsState(Pawn p)
=> p.inventory?.innerContainer is { } container ? container.innerList._version : 0;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsDirty(Pawn p)
=> TickHelper.Past(_nextRefreshTick)
|| _inventoryListsState != GetInventoryListsState(p);
}
}