Compare commits
4 Commits
3199c1a85e
...
e1a79fc0b0
| Author | SHA1 | Date | |
|---|---|---|---|
|
e1a79fc0b0
|
|||
|
ff3119a810
|
|||
|
9d31b36805
|
|||
|
227dcd173f
|
Binary file not shown.
Binary file not shown.
+3
-3
@@ -7,9 +7,9 @@
|
|||||||
<li>1.5</li>
|
<li>1.5</li>
|
||||||
<li>1.6</li>
|
<li>1.6</li>
|
||||||
</supportedVersions>
|
</supportedVersions>
|
||||||
<author>bradson</author>
|
<author>bradson, localavaster, Lionel Colaso, Riggs0</author>
|
||||||
<modIconPath IgnoreIfNoMatchingField="True">PerformanceFish/ModIcon</modIconPath>
|
<modIconPath IgnoreIfNoMatchingField="True">PerformanceFish/ModIcon</modIconPath>
|
||||||
<url>https://github.com/bbradson/performance-fish</url>
|
<url>hhttps://git.hudsonriggs.systems/HRiggs/Performance-Fish</url>
|
||||||
<loadBefore>
|
<loadBefore>
|
||||||
<li>Dubwise.DubsPerformanceAnalyzer</li>
|
<li>Dubwise.DubsPerformanceAnalyzer</li>
|
||||||
<li>Dubwise.DubsPerformanceAnalyzerButchered</li>
|
<li>Dubwise.DubsPerformanceAnalyzerButchered</li>
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
<packageId>bs.fishery</packageId>
|
<packageId>bs.fishery</packageId>
|
||||||
<displayName>Fishery</displayName>
|
<displayName>Fishery</displayName>
|
||||||
<steamWorkshopUrl>n/a</steamWorkshopUrl>
|
<steamWorkshopUrl>n/a</steamWorkshopUrl>
|
||||||
<downloadUrl>https://github.com/bbradson/Fishery</downloadUrl>
|
<downloadUrl>https://git.hudsonriggs.systems/HRiggs/Fishery</downloadUrl>
|
||||||
</li>
|
</li>
|
||||||
</modDependencies>
|
</modDependencies>
|
||||||
<incompatibleWith>
|
<incompatibleWith>
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<packageSources>
|
||||||
|
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutDir>..\..\1.6\Assemblies\</OutDir>
|
<OutDir>..\..\1.6\Assemblies\</OutDir>
|
||||||
<Copyright>Copyright (c) 2026 Bradson</Copyright>
|
<Copyright>Copyright (c) 2026 Bradson</Copyright>
|
||||||
|
<PolySharpUseEmbeddedAttributeForGeneratedTypes>false</PolySharpUseEmbeddedAttributeForGeneratedTypes>
|
||||||
<FisheryRepoRoot Condition="Exists('$(MSBuildThisFileDirectory)..\..\..\Fishery\1.6\Assemblies\1Fishery.dll')">$(MSBuildThisFileDirectory)..\..\..\Fishery</FisheryRepoRoot>
|
<FisheryRepoRoot Condition="Exists('$(MSBuildThisFileDirectory)..\..\..\Fishery\1.6\Assemblies\1Fishery.dll')">$(MSBuildThisFileDirectory)..\..\..\Fishery</FisheryRepoRoot>
|
||||||
<FisheryRepoRoot Condition="'$(FisheryRepoRoot)' == '' and Exists('$(MSBuildThisFileDirectory)..\..\..\Fishery-clean\1.6\Assemblies\1Fishery.dll')">$(MSBuildThisFileDirectory)..\..\..\Fishery-clean</FisheryRepoRoot>
|
<FisheryRepoRoot Condition="'$(FisheryRepoRoot)' == '' and Exists('$(MSBuildThisFileDirectory)..\..\..\Fishery-clean\1.6\Assemblies\1Fishery.dll')">$(MSBuildThisFileDirectory)..\..\..\Fishery-clean</FisheryRepoRoot>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -13,8 +14,13 @@
|
|||||||
<DefineConstants>V1_5;V1_6</DefineConstants>
|
<DefineConstants>V1_5;V1_6</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.6.*" />
|
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net48" Version="1.0.3" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.6.4871" />
|
||||||
<PackageReference Include="Lib.Harmony" Version="2.3.3" ExcludeAssets="runtime" />
|
<PackageReference Include="Lib.Harmony" Version="2.3.3" ExcludeAssets="runtime" />
|
||||||
|
<PackageReference Update="Zetrith.Prepatcher" Version="1.2.0" />
|
||||||
|
<PackageReference Update="PolySharp" Version="1.16.0" />
|
||||||
|
<PackageReference Update="Krafs.Publicizer" Version="2.3.2" />
|
||||||
|
<PackageReference Update="JetBrains.Annotations" Version="2023.3.0" />
|
||||||
<Reference Include="1Fishery">
|
<Reference Include="1Fishery">
|
||||||
<HintPath>$(FisheryRepoRoot)\1.6\Assemblies\1Fishery.dll</HintPath>
|
<HintPath>$(FisheryRepoRoot)\1.6\Assemblies\1Fishery.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (c) 2026
|
||||||
|
// 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/.
|
||||||
|
|
||||||
|
#if V1_6
|
||||||
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
|
using PerformanceFish.Prepatching;
|
||||||
|
|
||||||
|
namespace PerformanceFish;
|
||||||
|
|
||||||
|
public sealed class AbilityTrackerTickOptimization : ClassWithFishPrepatches
|
||||||
|
{
|
||||||
|
public sealed class AbilitiesTickPatch : FishPrepatch
|
||||||
|
{
|
||||||
|
public override string? Description { get; }
|
||||||
|
= "Reads the pawn ability list once per ability tick instead of twice, while still observing list changes between abilities.";
|
||||||
|
|
||||||
|
public override MethodBase TargetMethodBase { get; }
|
||||||
|
= AccessTools.DeclaredMethod(typeof(Pawn_AbilityTracker), nameof(Pawn_AbilityTracker.AbilitiesTick));
|
||||||
|
|
||||||
|
public override void Transpiler(ILProcessor ilProcessor, ModuleDefinition module)
|
||||||
|
=> ilProcessor.ReplaceBodyWith(AbilitiesTick);
|
||||||
|
|
||||||
|
public static void AbilitiesTick(Pawn_AbilityTracker instance)
|
||||||
|
{
|
||||||
|
for (var i = 0;; i++)
|
||||||
|
{
|
||||||
|
var abilities = instance.AllAbilitiesForReading;
|
||||||
|
if (i >= abilities.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
abilities[i].AbilityTick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -59,27 +59,33 @@ public static class Utility
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_gcInProgress = true;
|
_gcInProgress = true;
|
||||||
|
try
|
||||||
if (_cachesToProcessForGC is null || _currentGCProgress >= _cachesToProcessForGC.Length)
|
|
||||||
{
|
{
|
||||||
_cachesToProcessForGC = All.ToArray();
|
if (_cachesToProcessForGC is null || _currentGCProgress >= _cachesToProcessForGC.Length)
|
||||||
_gcRate = GenDate.TicksPerTwelfth / _cachesToProcessForGC.CountNonEmpty();
|
{
|
||||||
_currentGCProgress = 0;
|
_cachesToProcessForGC = All.ToArray();
|
||||||
_destroyedThingCounter = 0;
|
var nonEmptyCount = _cachesToProcessForGC.CountNonEmpty();
|
||||||
}
|
_gcRate = nonEmptyCount > 0 ? GenDate.TicksPerTwelfth / nonEmptyCount : 1000;
|
||||||
|
_currentGCProgress = 0;
|
||||||
|
_destroyedThingCounter = 0;
|
||||||
|
if (nonEmptyCount == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (_cachesToProcessForGC[_currentGCProgress].Count == 0
|
while (_currentGCProgress < _cachesToProcessForGC.Length
|
||||||
&& _cachesToProcessForGC.Length - _currentGCProgress > 1)
|
&& _cachesToProcessForGC[_currentGCProgress].Count == 0)
|
||||||
|
{
|
||||||
|
_currentGCProgress++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentGCProgress < _cachesToProcessForGC.Length)
|
||||||
|
_cachesToProcessForGC[_currentGCProgress++].Clear();
|
||||||
|
}
|
||||||
|
finally
|
||||||
{
|
{
|
||||||
_currentGCProgress++;
|
_lastGCTick = TickHelper.TicksGame;
|
||||||
|
_gcInProgress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentGCProgress < _cachesToProcessForGC.Length)
|
|
||||||
_cachesToProcessForGC[_currentGCProgress++].Clear();
|
|
||||||
|
|
||||||
_lastGCTick = TickHelper.TicksGame;
|
|
||||||
|
|
||||||
_gcInProgress = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,15 @@ namespace PerformanceFish;
|
|||||||
|
|
||||||
public sealed class CompTickOptimization : ClassWithFishPrepatches
|
public sealed class CompTickOptimization : ClassWithFishPrepatches
|
||||||
{
|
{
|
||||||
|
#if V1_6
|
||||||
|
public struct ThingTickCache
|
||||||
|
{
|
||||||
|
public List<ThingComp>? Source;
|
||||||
|
public int Version;
|
||||||
|
public bool AllTrivial;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private static readonly MethodInfo _thingCompTickMethod
|
private static readonly MethodInfo _thingCompTickMethod
|
||||||
= AccessTools.DeclaredMethod(typeof(ThingComp), nameof(ThingComp.CompTick));
|
= AccessTools.DeclaredMethod(typeof(ThingComp), nameof(ThingComp.CompTick));
|
||||||
|
|
||||||
@@ -39,8 +48,12 @@ public sealed class CompTickOptimization : ClassWithFishPrepatches
|
|||||||
private static readonly bool _hediffCompPostTickIntervalBaseIsTrivial
|
private static readonly bool _hediffCompPostTickIntervalBaseIsTrivial
|
||||||
= IsTrivialVoidMethod(_hediffCompPostTickIntervalMethod);
|
= IsTrivialVoidMethod(_hediffCompPostTickIntervalMethod);
|
||||||
|
|
||||||
|
#if V1_6
|
||||||
|
private static int _canSkipInheritedBaseThingCompTickState;
|
||||||
|
#else
|
||||||
private static readonly Lazy<bool> _canSkipInheritedBaseThingCompTick
|
private static readonly Lazy<bool> _canSkipInheritedBaseThingCompTick
|
||||||
= new(static () => _thingCompTickBaseIsTrivial && !HasHarmonyPatches(_thingCompTickMethod));
|
= new(static () => _thingCompTickBaseIsTrivial && !HasHarmonyPatches(_thingCompTickMethod));
|
||||||
|
#endif
|
||||||
|
|
||||||
private static readonly Lazy<bool> _canSkipInheritedBaseThingCompTickInterval
|
private static readonly Lazy<bool> _canSkipInheritedBaseThingCompTickInterval
|
||||||
= new(static () => _thingCompTickIntervalBaseIsTrivial && !HasHarmonyPatches(_thingCompTickIntervalMethod));
|
= new(static () => _thingCompTickIntervalBaseIsTrivial && !HasHarmonyPatches(_thingCompTickIntervalMethod));
|
||||||
@@ -89,10 +102,19 @@ public sealed class CompTickOptimization : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public sealed class ThingTickPatch : FishPrepatch
|
public sealed class ThingTickPatch : FishPrepatch
|
||||||
{
|
{
|
||||||
public override bool DefaultState => false;
|
public override bool DefaultState =>
|
||||||
|
#if V1_6
|
||||||
|
true;
|
||||||
|
#else
|
||||||
|
false;
|
||||||
|
#endif
|
||||||
|
|
||||||
public override string? Description { get; }
|
public override string? Description { get; }
|
||||||
|
#if V1_6
|
||||||
|
= "Skips the component tick loop when every component inherits the unpatched, empty base CompTick method.";
|
||||||
|
#else
|
||||||
= "Skips inherited empty ThingComp.CompTick calls when the base method is still unpatched and trivial.";
|
= "Skips inherited empty ThingComp.CompTick calls when the base method is still unpatched and trivial.";
|
||||||
|
#endif
|
||||||
|
|
||||||
public override MethodBase TargetMethodBase { get; }
|
public override MethodBase TargetMethodBase { get; }
|
||||||
= AccessTools.DeclaredMethod(typeof(ThingWithComps), "Tick");
|
= AccessTools.DeclaredMethod(typeof(ThingWithComps), "Tick");
|
||||||
@@ -102,16 +124,61 @@ public sealed class CompTickOptimization : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public static void ReplacementBody(ThingWithComps instance)
|
public static void ReplacementBody(ThingWithComps instance)
|
||||||
{
|
{
|
||||||
|
#if V1_6
|
||||||
|
var comps = instance.comps;
|
||||||
|
if (comps is null)
|
||||||
|
return;
|
||||||
|
#else
|
||||||
var comps = instance.AllComps;
|
var comps = instance.AllComps;
|
||||||
|
#endif
|
||||||
|
|
||||||
var count = comps.Count;
|
var count = comps.Count;
|
||||||
|
#if V1_6
|
||||||
|
// Small lists cost less to dispatch normally than to validate a cache.
|
||||||
|
if (count >= 4 && CanSkipInheritedBaseThingCompTick())
|
||||||
|
{
|
||||||
|
ref var cache = ref instance.ThingTickCache();
|
||||||
|
if (!ReferenceEquals(cache.Source, comps) || cache.Version != comps._version)
|
||||||
|
UpdateThingTickCache(comps, ref cache);
|
||||||
|
|
||||||
|
if (cache.AllTrivial)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
var canSkipInheritedBase = CanSkipInheritedBaseThingCompTick();
|
var canSkipInheritedBase = CanSkipInheritedBaseThingCompTick();
|
||||||
|
#endif
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
|
#if V1_6
|
||||||
|
instance.comps![i].CompTick();
|
||||||
|
#else
|
||||||
var comp = comps[i];
|
var comp = comps[i];
|
||||||
if (!canSkipInheritedBase || !_thingCompTickTypes.GetOrAdd(comp.GetType()))
|
if (!canSkipInheritedBase || !_thingCompTickTypes.GetOrAdd(comp.GetType()))
|
||||||
comp.CompTick();
|
comp.CompTick();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if V1_6
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
private static void UpdateThingTickCache(List<ThingComp> comps, ref ThingTickCache cache)
|
||||||
|
{
|
||||||
|
var allTrivial = true;
|
||||||
|
for (var i = 0; i < comps.Count; i++)
|
||||||
|
{
|
||||||
|
var comp = comps[i];
|
||||||
|
if (comp is null || !_thingCompTickTypes.GetOrAdd(comp.GetType()))
|
||||||
|
{
|
||||||
|
allTrivial = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.Source = comps;
|
||||||
|
cache.Version = comps._version;
|
||||||
|
cache.AllTrivial = allTrivial;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ThingTickIntervalPatch : FishPrepatch
|
public sealed class ThingTickIntervalPatch : FishPrepatch
|
||||||
@@ -267,7 +334,19 @@ public sealed class CompTickOptimization : ClassWithFishPrepatches
|
|||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool CanSkipInheritedBaseThingCompTick()
|
private static bool CanSkipInheritedBaseThingCompTick()
|
||||||
=> _canSkipInheritedBaseThingCompTick.Value;
|
{
|
||||||
|
#if V1_6
|
||||||
|
var state = _canSkipInheritedBaseThingCompTickState;
|
||||||
|
if (state == 0)
|
||||||
|
{
|
||||||
|
state = _thingCompTickBaseIsTrivial && !HasHarmonyPatches(_thingCompTickMethod) ? 2 : 1;
|
||||||
|
_canSkipInheritedBaseThingCompTickState = state;
|
||||||
|
}
|
||||||
|
return state == 2;
|
||||||
|
#else
|
||||||
|
return _canSkipInheritedBaseThingCompTick.Value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool CanSkipInheritedBaseThingCompTickInterval()
|
private static bool CanSkipInheritedBaseThingCompTickInterval()
|
||||||
|
|||||||
@@ -61,7 +61,15 @@ public sealed class GeneTrackerOptimization : ClassWithFishPrepatches
|
|||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool Dirty(Pawn_GeneTracker instance, List<Gene> genesToTick)
|
public static bool Dirty(Pawn_GeneTracker instance, List<Gene> genesToTick)
|
||||||
|
#if V1_6
|
||||||
|
{
|
||||||
|
ref var versions = ref instance.GeneListVersions();
|
||||||
|
return !versions.Initialized || versions.Xenogenes != instance.xenogenes._version
|
||||||
|
|| versions.Endogenes != instance.endogenes._version;
|
||||||
|
}
|
||||||
|
#else
|
||||||
=> GetListVersion(instance) != genesToTick._version;
|
=> GetListVersion(instance) != genesToTick._version;
|
||||||
|
#endif
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public static void Update(Pawn_GeneTracker instance, List<Gene> genesToTick)
|
public static void Update(Pawn_GeneTracker instance, List<Gene> genesToTick)
|
||||||
@@ -71,12 +79,21 @@ public sealed class GeneTrackerOptimization : ClassWithFishPrepatches
|
|||||||
AddTickableGenes(genesToTick, instance.xenogenes);
|
AddTickableGenes(genesToTick, instance.xenogenes);
|
||||||
AddTickableGenes(genesToTick, instance.endogenes);
|
AddTickableGenes(genesToTick, instance.endogenes);
|
||||||
|
|
||||||
|
#if V1_6
|
||||||
|
ref var versions = ref instance.GeneListVersions();
|
||||||
|
versions.Xenogenes = instance.xenogenes._version;
|
||||||
|
versions.Endogenes = instance.endogenes._version;
|
||||||
|
versions.Initialized = true;
|
||||||
|
#else
|
||||||
genesToTick._version = GetListVersion(instance);
|
genesToTick._version = GetListVersion(instance);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !V1_6
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static int GetListVersion(Pawn_GeneTracker instance)
|
private static int GetListVersion(Pawn_GeneTracker instance)
|
||||||
=> (instance.xenogenes._version << 16) | (instance.endogenes._version & 0b1111_1111_1111_1111);
|
=> (instance.xenogenes._version << 16) | (instance.endogenes._version & 0b1111_1111_1111_1111);
|
||||||
|
#endif
|
||||||
|
|
||||||
private static void AddTickableGenes(List<Gene> genesToTick, List<Gene> genes)
|
private static void AddTickableGenes(List<Gene> genesToTick, List<Gene> genes)
|
||||||
{
|
{
|
||||||
@@ -115,6 +132,15 @@ public sealed class GeneTrackerOptimization : ClassWithFishPrepatches
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if V1_6
|
||||||
|
public struct GeneListVersionState
|
||||||
|
{
|
||||||
|
public int Xenogenes;
|
||||||
|
public int Endogenes;
|
||||||
|
public bool Initialized;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public sealed class GeneTrackerTickIntervalPatch : FishPrepatch
|
public sealed class GeneTrackerTickIntervalPatch : FishPrepatch
|
||||||
{
|
{
|
||||||
// i am iffy about this
|
// i am iffy about this
|
||||||
|
|||||||
@@ -53,11 +53,13 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public record struct CacheValue<T>() where T : ThingComp
|
public record struct CacheValue<T>() where T : ThingComp
|
||||||
{
|
{
|
||||||
|
private List<ThingComp>? _listReference;
|
||||||
private int _listVersion = -2;
|
private int _listVersion = -2;
|
||||||
public T? Comp;
|
public T? Comp;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool IsDirty(List<ThingComp> comps) => comps._version != _listVersion;
|
public bool IsDirty(List<ThingComp> comps)
|
||||||
|
=> !ReferenceEquals(comps, _listReference) || comps._version != _listVersion;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public void Update(ThingWithComps thing, T? comp)
|
public void Update(ThingWithComps thing, T? comp)
|
||||||
@@ -65,6 +67,7 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
if (thing.thingIDNumber < 0)
|
if (thing.thingIDNumber < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_listReference = thing.comps;
|
||||||
_listVersion = thing.comps._version;
|
_listVersion = thing.comps._version;
|
||||||
Comp = comp;
|
Comp = comp;
|
||||||
}
|
}
|
||||||
@@ -113,11 +116,13 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public record struct CacheValue<T>() where T : CompProperties
|
public record struct CacheValue<T>() where T : CompProperties
|
||||||
{
|
{
|
||||||
|
private List<CompProperties>? _listReference;
|
||||||
private int _listVersion = -2;
|
private int _listVersion = -2;
|
||||||
public T? Comp;
|
public T? Comp;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool IsDirty(List<CompProperties> comps) => comps._version != _listVersion;
|
public bool IsDirty(List<CompProperties> comps)
|
||||||
|
=> !ReferenceEquals(comps, _listReference) || comps._version != _listVersion;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public void Update(ThingDef thingDef, T? comp)
|
public void Update(ThingDef thingDef, T? comp)
|
||||||
@@ -125,6 +130,7 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
if (thingDef.shortHash == default)
|
if (thingDef.shortHash == default)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_listReference = thingDef.comps;
|
||||||
_listVersion = thingDef.comps._version;
|
_listVersion = thingDef.comps._version;
|
||||||
Comp = comp;
|
Comp = comp;
|
||||||
}
|
}
|
||||||
@@ -174,11 +180,13 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public record struct CacheValue()
|
public record struct CacheValue()
|
||||||
{
|
{
|
||||||
|
private List<CompProperties>? _listReference;
|
||||||
private int _listVersion = -2;
|
private int _listVersion = -2;
|
||||||
public bool HasComp;
|
public bool HasComp;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool IsDirty(List<CompProperties> comps) => comps._version != _listVersion;
|
public bool IsDirty(List<CompProperties> comps)
|
||||||
|
=> !ReferenceEquals(comps, _listReference) || comps._version != _listVersion;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public void Update(ThingDef thingDef, bool hasComp)
|
public void Update(ThingDef thingDef, bool hasComp)
|
||||||
@@ -186,6 +194,7 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
if (thingDef.shortHash == default)
|
if (thingDef.shortHash == default)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_listReference = thingDef.comps;
|
||||||
_listVersion = thingDef.comps._version;
|
_listVersion = thingDef.comps._version;
|
||||||
HasComp = hasComp;
|
HasComp = hasComp;
|
||||||
}
|
}
|
||||||
@@ -236,11 +245,13 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public record struct CacheValue<T>() where T : ThingComp
|
public record struct CacheValue<T>() where T : ThingComp
|
||||||
{
|
{
|
||||||
|
private List<CompProperties>? _listReference;
|
||||||
private int _listVersion = -2;
|
private int _listVersion = -2;
|
||||||
public bool HasComp;
|
public bool HasComp;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool IsDirty(List<CompProperties> comps) => comps._version != _listVersion;
|
public bool IsDirty(List<CompProperties> comps)
|
||||||
|
=> !ReferenceEquals(comps, _listReference) || comps._version != _listVersion;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public void Update(ThingDef thingDef, bool hasComp)
|
public void Update(ThingDef thingDef, bool hasComp)
|
||||||
@@ -248,6 +259,7 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
if (thingDef.shortHash == default)
|
if (thingDef.shortHash == default)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_listReference = thingDef.comps;
|
||||||
_listVersion = thingDef.comps._version;
|
_listVersion = thingDef.comps._version;
|
||||||
HasComp = hasComp;
|
HasComp = hasComp;
|
||||||
}
|
}
|
||||||
@@ -296,11 +308,13 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public record struct CacheValue<T>() where T : HediffComp
|
public record struct CacheValue<T>() where T : HediffComp
|
||||||
{
|
{
|
||||||
|
private List<HediffComp>? _listReference;
|
||||||
private int _listVersion = -2;
|
private int _listVersion = -2;
|
||||||
public T? Comp;
|
public T? Comp;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool IsDirty(List<HediffComp> comps) => comps._version != _listVersion;
|
public bool IsDirty(List<HediffComp> comps)
|
||||||
|
=> !ReferenceEquals(comps, _listReference) || comps._version != _listVersion;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public void Update(HediffWithComps hediff, T? comp)
|
public void Update(HediffWithComps hediff, T? comp)
|
||||||
@@ -308,6 +322,7 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
if (hediff.loadID < 0)
|
if (hediff.loadID < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_listReference = hediff.comps;
|
||||||
_listVersion = hediff.comps._version;
|
_listVersion = hediff.comps._version;
|
||||||
Comp = comp;
|
Comp = comp;
|
||||||
}
|
}
|
||||||
@@ -355,11 +370,13 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public record struct CacheValue<T>() where T : HediffCompProperties
|
public record struct CacheValue<T>() where T : HediffCompProperties
|
||||||
{
|
{
|
||||||
|
private List<HediffCompProperties>? _listReference;
|
||||||
private int _listVersion = -2;
|
private int _listVersion = -2;
|
||||||
public T? Comp;
|
public T? Comp;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool IsDirty(List<HediffCompProperties> comps) => comps._version != _listVersion;
|
public bool IsDirty(List<HediffCompProperties> comps)
|
||||||
|
=> !ReferenceEquals(comps, _listReference) || comps._version != _listVersion;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public void Update(HediffDef hediffDef, T? comp)
|
public void Update(HediffDef hediffDef, T? comp)
|
||||||
@@ -367,6 +384,7 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
if (hediffDef.shortHash == 0)
|
if (hediffDef.shortHash == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_listReference = hediffDef.comps;
|
||||||
_listVersion = hediffDef.comps._version;
|
_listVersion = hediffDef.comps._version;
|
||||||
Comp = comp;
|
Comp = comp;
|
||||||
}
|
}
|
||||||
@@ -414,11 +432,13 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public record struct CacheValue<T>() where T : AbilityComp
|
public record struct CacheValue<T>() where T : AbilityComp
|
||||||
{
|
{
|
||||||
|
private List<AbilityComp>? _listReference;
|
||||||
private int _listVersion = -2;
|
private int _listVersion = -2;
|
||||||
public T? Comp;
|
public T? Comp;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool IsDirty(List<AbilityComp> comps) => comps._version != _listVersion;
|
public bool IsDirty(List<AbilityComp> comps)
|
||||||
|
=> !ReferenceEquals(comps, _listReference) || comps._version != _listVersion;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public void Update(Ability ability, T? comp)
|
public void Update(Ability ability, T? comp)
|
||||||
@@ -426,6 +446,7 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
if (ability.Id < 0)
|
if (ability.Id < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_listReference = ability.comps;
|
||||||
_listVersion = ability.comps._version;
|
_listVersion = ability.comps._version;
|
||||||
Comp = comp;
|
Comp = comp;
|
||||||
}
|
}
|
||||||
@@ -468,11 +489,13 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public record struct CacheValue<T>() where T : WorldObjectComp
|
public record struct CacheValue<T>() where T : WorldObjectComp
|
||||||
{
|
{
|
||||||
|
private List<WorldObjectComp>? _listReference;
|
||||||
private int _listVersion = -2;
|
private int _listVersion = -2;
|
||||||
public T? Comp;
|
public T? Comp;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool IsDirty(List<WorldObjectComp> comps) => comps._version != _listVersion;
|
public bool IsDirty(List<WorldObjectComp> comps)
|
||||||
|
=> !ReferenceEquals(comps, _listReference) || comps._version != _listVersion;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public void Update(WorldObject worldObject, T? comp)
|
public void Update(WorldObject worldObject, T? comp)
|
||||||
@@ -480,6 +503,7 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
if (worldObject.ID < 0)
|
if (worldObject.ID < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_listReference = worldObject.comps;
|
||||||
_listVersion = worldObject.comps._version;
|
_listVersion = worldObject.comps._version;
|
||||||
Comp = comp;
|
Comp = comp;
|
||||||
}
|
}
|
||||||
@@ -522,11 +546,13 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public record struct CacheValue<T>() where T : MapComponent
|
public record struct CacheValue<T>() where T : MapComponent
|
||||||
{
|
{
|
||||||
|
private List<MapComponent>? _listReference;
|
||||||
private int _listVersion = -2;
|
private int _listVersion = -2;
|
||||||
public T? Comp;
|
public T? Comp;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool IsDirty(List<MapComponent> comps) => comps._version != _listVersion;
|
public bool IsDirty(List<MapComponent> comps)
|
||||||
|
=> !ReferenceEquals(comps, _listReference) || comps._version != _listVersion;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public void Update(Map map, T? comp)
|
public void Update(Map map, T? comp)
|
||||||
@@ -534,6 +560,7 @@ public sealed class GetCompCaching : ClassWithFishPrepatches
|
|||||||
if (map.uniqueID < 0)
|
if (map.uniqueID < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_listReference = map.components;
|
||||||
_listVersion = map.components._version;
|
_listVersion = map.components._version;
|
||||||
Comp = comp;
|
Comp = comp;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ public sealed class NeedsTrackerCaching : ClassWithFishPrepatches
|
|||||||
{
|
{
|
||||||
public sealed class TryGetNeedPatch : FishPrepatch
|
public sealed class TryGetNeedPatch : FishPrepatch
|
||||||
{
|
{
|
||||||
|
public override bool DefaultState => true;
|
||||||
|
|
||||||
public override string? Description { get; }
|
public override string? Description { get; }
|
||||||
= "Caches generic need lookups behind the needs list version.";
|
= "Caches generic need lookups behind the needs list version.";
|
||||||
|
|
||||||
@@ -30,6 +32,8 @@ public sealed class NeedsTrackerCaching : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public sealed class TryGetNeedOutPatch : FishPrepatch
|
public sealed class TryGetNeedOutPatch : FishPrepatch
|
||||||
{
|
{
|
||||||
|
public override bool DefaultState => true;
|
||||||
|
|
||||||
public override string? Description { get; }
|
public override string? Description { get; }
|
||||||
= "Caches generic need lookups behind the needs list version.";
|
= "Caches generic need lookups behind the needs list version.";
|
||||||
|
|
||||||
@@ -55,18 +59,18 @@ public sealed class NeedsTrackerCaching : ClassWithFishPrepatches
|
|||||||
return cache.Found;
|
return cache.Found;
|
||||||
}
|
}
|
||||||
|
|
||||||
return UpdateCache(instance, typeof(T), out need, ref cache);
|
return UpdateCache(instance, out need, ref cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
private static bool UpdateCache<T>(Pawn_NeedsTracker instance, Type needType, out T? need, ref CacheValue cache)
|
private static bool UpdateCache<T>(Pawn_NeedsTracker instance, out T? need, ref CacheValue cache)
|
||||||
where T : Need
|
where T : Need
|
||||||
{
|
{
|
||||||
var needs = instance.needs;
|
var needs = instance.needs;
|
||||||
for (var i = 0; i < needs.Count; i++)
|
for (var i = 0; i < needs.Count; i++)
|
||||||
{
|
{
|
||||||
var candidate = needs[i];
|
var candidate = needs[i];
|
||||||
if (candidate.GetType() != needType)
|
if (candidate.GetType() != typeof(T))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
need = (T)candidate;
|
need = (T)candidate;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public static class OnAssembliesLoaded
|
|||||||
PerformanceFishMod.AllPatchClasses = PerformanceFishMod.InitializeAllPatchClasses<IHasFishPatch>();
|
PerformanceFishMod.AllPatchClasses = PerformanceFishMod.InitializeAllPatchClasses<IHasFishPatch>();
|
||||||
PerformanceFishMod.AllPrepatchClasses ??= PerformanceFishMod.InitializeAllPatchClasses<ClassWithFishPrepatches>();
|
PerformanceFishMod.AllPrepatchClasses ??= PerformanceFishMod.InitializeAllPatchClasses<ClassWithFishPrepatches>();
|
||||||
|
|
||||||
TryInitialize(AnalyzerFixes.Patch, true);
|
TryInitialize(AnalyzerFixes.Patch);
|
||||||
|
|
||||||
_ = FishSettings.Instance;
|
_ = FishSettings.Instance;
|
||||||
|
|
||||||
@@ -109,14 +109,11 @@ public static class OnAssembliesLoaded
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async void TryInitialize(Action action, bool async = false)
|
private static void TryInitialize(Action action)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (async)
|
action();
|
||||||
await Task.Run(action).ConfigureAwait(false);
|
|
||||||
else
|
|
||||||
action();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ public abstract class FishPatch : SingletonFactory<FishPatch>, IExposable, IHasD
|
|||||||
public List<MethodInfo> BenchmarkHarmonyMethodInfos { get; } = [];
|
public List<MethodInfo> BenchmarkHarmonyMethodInfos { get; } = [];
|
||||||
private bool Patched { get; set; }
|
private bool Patched { get; set; }
|
||||||
private bool ShouldBePatched { get; set; }
|
private bool ShouldBePatched { get; set; }
|
||||||
|
private readonly HashSet<MethodBase> _patchedTargets = [];
|
||||||
|
|
||||||
public virtual string? Name => null;
|
public virtual string? Name => null;
|
||||||
|
|
||||||
@@ -190,15 +191,16 @@ public abstract class FishPatch : SingletonFactory<FishPatch>, IExposable, IHasD
|
|||||||
|
|
||||||
protected virtual void ApplyPatch()
|
protected virtual void ApplyPatch()
|
||||||
{
|
{
|
||||||
Patched = true;
|
var targets = TargetMethodInfos.ToArray();
|
||||||
foreach (var method in TargetMethodInfos)
|
foreach (var method in targets)
|
||||||
{
|
{
|
||||||
|
if (_patchedTargets.Contains(method))
|
||||||
|
continue;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (IsBenchmarking)
|
if (IsBenchmarking)
|
||||||
{
|
{
|
||||||
Patched = false;
|
|
||||||
|
|
||||||
if (AccessTools.EnumeratorMoveNext(method) is { } moveNext)
|
if (AccessTools.EnumeratorMoveNext(method) is { } moveNext)
|
||||||
{
|
{
|
||||||
BenchmarkHarmonyMethodInfos.Add(PerformanceFishMod.Harmony!.Patch(moveNext,
|
BenchmarkHarmonyMethodInfos.Add(PerformanceFishMod.Harmony!.Patch(moveNext,
|
||||||
@@ -229,6 +231,7 @@ public abstract class FishPatch : SingletonFactory<FishPatch>, IExposable, IHasD
|
|||||||
transpiler: TryMakeHarmonyMethod(TranspilerMethodInfo, TranspilerMethodPriority),
|
transpiler: TryMakeHarmonyMethod(TranspilerMethodInfo, TranspilerMethodPriority),
|
||||||
finalizer: TryMakeHarmonyMethod(FinalizerMethodInfo, FinalizerMethodPriority)));
|
finalizer: TryMakeHarmonyMethod(FinalizerMethodInfo, FinalizerMethodPriority)));
|
||||||
}
|
}
|
||||||
|
_patchedTargets.Add(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -240,6 +243,7 @@ public abstract class FishPatch : SingletonFactory<FishPatch>, IExposable, IHasD
|
|||||||
FinalizerMethodInfo.FullDescription()}:\n{e}");
|
FinalizerMethodInfo.FullDescription()}:\n{e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Patched = !IsBenchmarking && targets.All(_patchedTargets.Contains);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HarmonyMethod? TryMakeHarmonyMethod(MethodInfo? method, int priority = -1, string[]? before = null,
|
private static HarmonyMethod? TryMakeHarmonyMethod(MethodInfo? method, int priority = -1, string[]? before = null,
|
||||||
@@ -249,7 +253,7 @@ public abstract class FishPatch : SingletonFactory<FishPatch>, IExposable, IHasD
|
|||||||
public virtual void TryUnpatch()
|
public virtual void TryUnpatch()
|
||||||
{
|
{
|
||||||
ShouldBePatched = false;
|
ShouldBePatched = false;
|
||||||
if ( /*!Enabled &&*/ Patched)
|
if (Patched || _patchedTargets.Count != 0)
|
||||||
ApplyUnpatching();
|
ApplyUnpatching();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,6 +273,7 @@ public abstract class FishPatch : SingletonFactory<FishPatch>, IExposable, IHasD
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_patchedTargets.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void TryUnpatchMethod(MethodBase targetMethod, MethodInfo? patchMethod)
|
private static void TryUnpatchMethod(MethodBase targetMethod, MethodInfo? patchMethod)
|
||||||
|
|||||||
@@ -15,16 +15,21 @@ public sealed class WorldObjectsOptimization : ClassWithFishPrepatches
|
|||||||
{
|
{
|
||||||
public sealed class WorldObjectsHolderTickPatch : FishPrepatch
|
public sealed class WorldObjectsHolderTickPatch : FishPrepatch
|
||||||
{
|
{
|
||||||
|
public override bool DefaultState => true;
|
||||||
|
|
||||||
private static FishTable<Type, bool> _skippableCompTypes = null!;
|
private static FishTable<Type, bool> _skippableCompTypes = null!;
|
||||||
private static FishTable<Type, bool> _skippableWorldObjectTypes = null!;
|
private static FishTable<Type, bool> _skippableWorldObjectTypes = null!;
|
||||||
private static readonly List<IThingHolder> _tmpThingHolders = [];
|
private static readonly List<IThingHolder> _tmpThingHolders = [];
|
||||||
|
private static readonly List<SkippedWorldObject> _skippedWorldObjects = [];
|
||||||
|
private static List<WorldObject>? _cachedWorldObjectsReference;
|
||||||
|
private static List<Map>? _cachedMapsReference;
|
||||||
|
|
||||||
|
private readonly record struct SkippedWorldObject(WorldObject WorldObject,
|
||||||
|
List<WorldObjectComp> Comps, int CompsVersion, bool HasEnterCooldownComp);
|
||||||
|
|
||||||
public override string? Description { get; }
|
public override string? Description { get; }
|
||||||
= "The world objects holder is responsible for ticking every world object. This includes settlements, "
|
= "Caches the world objects that need ticking and skips objects with no active tick behavior. "
|
||||||
+ "caravans, outposts and any other object placed in the world, instead of maps. Normally it ticks "
|
+ "Objects with changing contents or components are rechecked before each tick.";
|
||||||
+ "everything equally, including many static objects that cannot possibly affect anything from a tick. "
|
|
||||||
+ "This patch improves the world objects holder to determine objects that need ticking in advance, cache "
|
|
||||||
+ "the list of them, and only tick those, skipping all the others.";
|
|
||||||
|
|
||||||
public override MethodBase TargetMethodBase { get; }
|
public override MethodBase TargetMethodBase { get; }
|
||||||
= AccessTools.Method(typeof(WorldObjectsHolder), nameof(WorldObjectsHolder.WorldObjectsHolderTick));
|
= AccessTools.Method(typeof(WorldObjectsHolder), nameof(WorldObjectsHolder.WorldObjectsHolderTick));
|
||||||
@@ -38,7 +43,7 @@ public sealed class WorldObjectsOptimization : ClassWithFishPrepatches
|
|||||||
UpdateCache(instance);
|
UpdateCache(instance);
|
||||||
|
|
||||||
var worldObjects = WorldObjectsHolder.tmpWorldObjects;
|
var worldObjects = WorldObjectsHolder.tmpWorldObjects;
|
||||||
for (var i = worldObjects.Count; i-- > 0;)
|
for (var i = 0; i < worldObjects.Count; i++)
|
||||||
#if V1_6
|
#if V1_6
|
||||||
worldObjects[i].DoTick();
|
worldObjects[i].DoTick();
|
||||||
#else
|
#else
|
||||||
@@ -50,18 +55,23 @@ public sealed class WorldObjectsOptimization : ClassWithFishPrepatches
|
|||||||
{
|
{
|
||||||
var staticWorldObjects = WorldObjectsHolder.tmpWorldObjects;
|
var staticWorldObjects = WorldObjectsHolder.tmpWorldObjects;
|
||||||
staticWorldObjects.Clear();
|
staticWorldObjects.Clear();
|
||||||
|
_skippedWorldObjects.Clear();
|
||||||
|
|
||||||
var instanceWorldObjects = instance.worldObjects;
|
var instanceWorldObjects = instance.worldObjects;
|
||||||
|
|
||||||
for (var i = instanceWorldObjects.Count; i-- > 0;)
|
for (var i = 0; i < instanceWorldObjects.Count; i++)
|
||||||
{
|
{
|
||||||
var worldObject = instanceWorldObjects[i];
|
var worldObject = instanceWorldObjects[i];
|
||||||
|
|
||||||
if (worldObject is not MapParent { HasMap: true }
|
if (worldObject is not MapParent { HasMap: true }
|
||||||
&& CanSkipWorldObjectTick(worldObject)
|
&& CanSkipWorldObjectTick(worldObject)
|
||||||
&& (worldObject is not Settlement settlement || settlement.trader?.stock is null)
|
|
||||||
&& CanSkipCompTick(worldObject))
|
&& CanSkipCompTick(worldObject))
|
||||||
{
|
{
|
||||||
|
var comps = worldObject.comps;
|
||||||
|
var hasEnterCooldownComp = false;
|
||||||
|
for (var j = 0; j < comps.Count; j++)
|
||||||
|
hasEnterCooldownComp |= comps[j] is EnterCooldownComp;
|
||||||
|
_skippedWorldObjects.Add(new(worldObject, comps, comps._version, hasEnterCooldownComp));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +80,8 @@ public sealed class WorldObjectsOptimization : ClassWithFishPrepatches
|
|||||||
|
|
||||||
CachedWorldObjectsVersion = instanceWorldObjects._version;
|
CachedWorldObjectsVersion = instanceWorldObjects._version;
|
||||||
CachedMapsVersion = Current.gameInt.maps._version;
|
CachedMapsVersion = Current.gameInt.maps._version;
|
||||||
|
_cachedWorldObjectsReference = instanceWorldObjects;
|
||||||
|
_cachedMapsReference = Current.gameInt.maps;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CanSkipWorldObjectTick(WorldObject worldObject)
|
private static bool CanSkipWorldObjectTick(WorldObject worldObject)
|
||||||
@@ -79,31 +91,30 @@ public sealed class WorldObjectsOptimization : ClassWithFishPrepatches
|
|||||||
|
|
||||||
private static bool HasTickableContents(WorldObject worldObject)
|
private static bool HasTickableContents(WorldObject worldObject)
|
||||||
{
|
{
|
||||||
if (worldObject is not IThingHolder holder)
|
if (worldObject is not IThingHolder holder
|
||||||
|
|| worldObject is IThingHolderTickable { ShouldTickContents: false })
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
lock (_tmpThingHolders)
|
lock (_tmpThingHolders)
|
||||||
{
|
{
|
||||||
_tmpThingHolders.Clear();
|
_tmpThingHolders.Clear();
|
||||||
_tmpThingHolders.Add(holder);
|
try
|
||||||
holder.GetChildHolders(_tmpThingHolders);
|
|
||||||
|
|
||||||
for (var i = 0; i < _tmpThingHolders.Count; i++)
|
|
||||||
{
|
{
|
||||||
var thingHolder = _tmpThingHolders[i];
|
_tmpThingHolders.Add(holder);
|
||||||
if (thingHolder is IThingHolderTickable tickable && !tickable.ShouldTickContents)
|
holder.GetChildHolders(_tmpThingHolders);
|
||||||
continue;
|
for (var i = 0; i < _tmpThingHolders.Count; i++)
|
||||||
|
|
||||||
var directlyHeldThings = thingHolder.GetDirectlyHeldThings();
|
|
||||||
if (directlyHeldThings?.Owner is not null and not Map and not Caravan)
|
|
||||||
{
|
{
|
||||||
_tmpThingHolders.Clear();
|
var heldThings = _tmpThingHolders[i].GetDirectlyHeldThings();
|
||||||
return true;
|
if (heldThings is not null && heldThings.Owner is not Map and not Caravan)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
_tmpThingHolders.Clear();
|
return false;
|
||||||
return false;
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_tmpThingHolders.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,10 +148,9 @@ public sealed class WorldObjectsOptimization : ClassWithFishPrepatches
|
|||||||
],
|
],
|
||||||
_whitelistedWorldObjectTypes =
|
_whitelistedWorldObjectTypes =
|
||||||
[
|
[
|
||||||
|
// Settlement.TickInterval checks trader and defeat state even without a map.
|
||||||
typeof(WorldObject),
|
typeof(WorldObject),
|
||||||
typeof(MapParent),
|
typeof(MapParent)
|
||||||
typeof(Settlement),
|
|
||||||
ModCompatibility.Types.RealRuins.POIWorldObject
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public static void AddCompToWhiteList(Type compType)
|
public static void AddCompToWhiteList(Type compType)
|
||||||
@@ -211,8 +221,31 @@ public sealed class WorldObjectsOptimization : ClassWithFishPrepatches
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static bool CacheDirty(WorldObjectsHolder instance)
|
public static bool CacheDirty(WorldObjectsHolder instance)
|
||||||
=> CachedWorldObjectsVersion != instance.worldObjects._version
|
{
|
||||||
|| CachedMapsVersion != Current.gameInt.maps._version;
|
if (!ReferenceEquals(_cachedWorldObjectsReference, instance.worldObjects)
|
||||||
|
|| CachedWorldObjectsVersion != instance.worldObjects._version
|
||||||
|
|| !ReferenceEquals(_cachedMapsReference, Current.gameInt.maps)
|
||||||
|
|| CachedMapsVersion != Current.gameInt.maps._version)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (var i = 0; i < _skippedWorldObjects.Count; i++)
|
||||||
|
{
|
||||||
|
var skipped = _skippedWorldObjects[i];
|
||||||
|
var worldObject = skipped.WorldObject;
|
||||||
|
var comps = worldObject.comps;
|
||||||
|
if (!ReferenceEquals(comps, skipped.Comps) || comps._version != skipped.CompsVersion
|
||||||
|
|| worldObject is MapParent { HasMap: true }
|
||||||
|
|| HasTickableContents(worldObject))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (skipped.HasEnterCooldownComp)
|
||||||
|
for (var j = 0; j < comps.Count; j++)
|
||||||
|
if (comps[j] is EnterCooldownComp { Active: true })
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static void SetDirty() => CachedWorldObjectsVersion = CachedMapsVersion = -2;
|
public static void SetDirty() => CachedWorldObjectsVersion = CachedMapsVersion = -2;
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,16 @@ public static class PrepatcherFields
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static extern List<Gene> GenesToTick(this Pawn_GeneTracker geneTracker);
|
public static extern List<Gene> GenesToTick(this Pawn_GeneTracker geneTracker);
|
||||||
|
|
||||||
|
#if V1_6
|
||||||
|
[PrepatcherField]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static extern ref GeneTrackerOptimization.GeneListVersionState GeneListVersions(this Pawn_GeneTracker geneTracker);
|
||||||
|
|
||||||
|
[PrepatcherField]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static extern ref CompTickOptimization.ThingTickCache ThingTickCache(this ThingWithComps thing);
|
||||||
|
#endif
|
||||||
|
|
||||||
[PrepatcherField]
|
[PrepatcherField]
|
||||||
[ValueInitializer(nameof(CreateWorldPawnsCache))]
|
[ValueInitializer(nameof(CreateWorldPawnsCache))]
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ public sealed class PawnRenderingOptimizations : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public sealed class IsHiddenFromPlayerPatch : FishPrepatch
|
public sealed class IsHiddenFromPlayerPatch : FishPrepatch
|
||||||
{
|
{
|
||||||
|
public override bool DefaultState => true;
|
||||||
|
|
||||||
// not 100% on this even benefitting, bionics, scars, etc likely worsen performance here because of the extra check
|
// not 100% on this even benefitting, bionics, scars, etc likely worsen performance here because of the extra check
|
||||||
// probably better to just track if a hediff adds invisibility
|
// probably better to just track if a hediff adds invisibility
|
||||||
public override string? Description { get; }
|
public override string? Description { get; }
|
||||||
@@ -53,6 +55,8 @@ public sealed class PawnRenderingOptimizations : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public sealed class PawnRenderTreeComputeMatrixPatch : FishPrepatch
|
public sealed class PawnRenderTreeComputeMatrixPatch : FishPrepatch
|
||||||
{
|
{
|
||||||
|
public override bool DefaultState => true;
|
||||||
|
|
||||||
public override string? Description { get; }
|
public override string? Description { get; }
|
||||||
= "Avoids Matrix4x4 inverse work when undoing a pivot translation in PawnRenderTree.ComputeMatrix.";
|
= "Avoids Matrix4x4 inverse work when undoing a pivot translation in PawnRenderTree.ComputeMatrix.";
|
||||||
|
|
||||||
@@ -85,6 +89,8 @@ public sealed class PawnRenderingOptimizations : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public sealed class DamageFlasherCurColorPatch : FishPrepatch
|
public sealed class DamageFlasherCurColorPatch : FishPrepatch
|
||||||
{
|
{
|
||||||
|
public override bool DefaultState => true;
|
||||||
|
|
||||||
private static readonly AccessTools.FieldRef<DamageFlasher, int> _lastDamageTick
|
private static readonly AccessTools.FieldRef<DamageFlasher, int> _lastDamageTick
|
||||||
= AccessTools.FieldRefAccess<DamageFlasher, int>("lastDamageTick");
|
= AccessTools.FieldRefAccess<DamageFlasher, int>("lastDamageTick");
|
||||||
|
|
||||||
@@ -110,6 +116,8 @@ public sealed class PawnRenderingOptimizations : ClassWithFishPrepatches
|
|||||||
|
|
||||||
public sealed class DamageFlasherGetDamagedMatPatch : FishPrepatch
|
public sealed class DamageFlasherGetDamagedMatPatch : FishPrepatch
|
||||||
{
|
{
|
||||||
|
public override bool DefaultState => true;
|
||||||
|
|
||||||
private static readonly AccessTools.FieldRef<DamageFlasher, int> _lastDamageTick
|
private static readonly AccessTools.FieldRef<DamageFlasher, int> _lastDamageTick
|
||||||
= AccessTools.FieldRefAccess<DamageFlasher, int>("lastDamageTick");
|
= AccessTools.FieldRefAccess<DamageFlasher, int>("lastDamageTick");
|
||||||
|
|
||||||
|
|||||||
@@ -535,6 +535,13 @@ public sealed class ReflectionCaching : ClassWithFishPatches
|
|||||||
public static bool Prefix(ICustomAttributeProvider obj, Type attributeType, bool inherit,
|
public static bool Prefix(ICustomAttributeProvider obj, Type attributeType, bool inherit,
|
||||||
out object[]? __result, out CustomAttributeState __state)
|
out object[]? __result, out CustomAttributeState __state)
|
||||||
{
|
{
|
||||||
|
if (obj is null || attributeType is null)
|
||||||
|
{
|
||||||
|
__state = default;
|
||||||
|
__result = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
var key = new CustomAttributeCache(obj, attributeType.TypeHandle, inherit);
|
var key = new CustomAttributeCache(obj, attributeType.TypeHandle, inherit);
|
||||||
__state = new() { Key = key };
|
__state = new() { Key = key };
|
||||||
|
|
||||||
@@ -656,7 +663,9 @@ public sealed class ReflectionCaching : ClassWithFishPatches
|
|||||||
{
|
{
|
||||||
var value = new CustomAttributeCacheValue
|
var value = new CustomAttributeCacheValue
|
||||||
{
|
{
|
||||||
Attributes = CopyCachedAttributes(result),
|
Attributes = result.Length == 0
|
||||||
|
? (object[])Array.CreateInstance(Type.GetTypeFromHandle(key.Second), 0)
|
||||||
|
: CopyCachedAttributes(result),
|
||||||
Status = CustomAttributeCacheStatus.Completed
|
Status = CustomAttributeCacheStatus.Completed
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -693,7 +702,7 @@ public sealed class ReflectionCaching : ClassWithFishPatches
|
|||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static object[] CopyCachedAttributes(object[] attributes)
|
private static object[] CopyCachedAttributes(object[] attributes)
|
||||||
=> attributes.Length != 0 ? (object[])attributes.Clone() : Array.Empty<object>();
|
=> attributes.Length != 0 ? (object[])attributes.Clone() : attributes;
|
||||||
|
|
||||||
private static object _lock = new();
|
private static object _lock = new();
|
||||||
}
|
}
|
||||||
@@ -1024,8 +1033,6 @@ public sealed class ReflectionCaching : ClassWithFishPatches
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool Prefix(FieldInfo __instance, object? obj, ref object? __result)
|
public static bool Prefix(FieldInfo __instance, object? obj, ref object? __result)
|
||||||
{
|
{
|
||||||
ValidateGetValueCall(__instance, obj);
|
|
||||||
|
|
||||||
ref var cache = ref FieldGetters.GetOrAddReference(__instance.FieldHandle);
|
ref var cache = ref FieldGetters.GetOrAddReference(__instance.FieldHandle);
|
||||||
|
|
||||||
if (cache.Dirty
|
if (cache.Dirty
|
||||||
@@ -1035,6 +1042,8 @@ public sealed class ReflectionCaching : ClassWithFishPatches
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsupported fields fall back to Mono's implementation, including its exception behavior.
|
||||||
|
ValidateGetValueCall(__instance, obj);
|
||||||
__result = cache.Result!(obj);
|
__result = cache.Result!(obj);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user