Constrain reflection fast paths and preserve 1.6 tick behavior

This commit is contained in:
2026-10-02 14:37:44 -04:00
parent e1a79fc0b0
commit e766ac833c
6 changed files with 247 additions and 496 deletions
+72 -44
View File
@@ -48,27 +48,19 @@ public sealed class CompTickOptimization : ClassWithFishPrepatches
private static readonly bool _hediffCompPostTickIntervalBaseIsTrivial
= IsTrivialVoidMethod(_hediffCompPostTickIntervalMethod);
#if V1_6
private static int _canSkipInheritedBaseThingCompTickState;
#else
private static readonly Lazy<bool> _canSkipInheritedBaseThingCompTick
= new(static () => _thingCompTickBaseIsTrivial && !HasHarmonyPatches(_thingCompTickMethod));
#endif
private struct BasePatchState
{
public int CheckedTick;
public bool HasChecked;
public bool CanSkip;
}
private static readonly Lazy<bool> _canSkipInheritedBaseThingCompTickInterval
= new(static () => _thingCompTickIntervalBaseIsTrivial && !HasHarmonyPatches(_thingCompTickIntervalMethod));
private static readonly Lazy<bool> _canSkipInheritedBaseThingCompTickRare
= new(static () => _thingCompTickRareBaseIsTrivial && !HasHarmonyPatches(_thingCompTickRareMethod));
private static readonly Lazy<bool> _canSkipInheritedBaseThingCompTickLong
= new(static () => _thingCompTickLongBaseIsTrivial && !HasHarmonyPatches(_thingCompTickLongMethod));
private static readonly Lazy<bool> _canSkipInheritedBaseHediffCompPostTick
= new(static () => _hediffCompPostTickBaseIsTrivial && !HasHarmonyPatches(_hediffCompPostTickMethod));
private static readonly Lazy<bool> _canSkipInheritedBaseHediffCompPostTickInterval = new(
static () => _hediffCompPostTickIntervalBaseIsTrivial && !HasHarmonyPatches(_hediffCompPostTickIntervalMethod));
private static BasePatchState _thingCompTickState;
private static BasePatchState _thingCompTickIntervalState;
private static BasePatchState _thingCompTickRareState;
private static BasePatchState _thingCompTickLongState;
private static BasePatchState _hediffCompPostTickState;
private static BasePatchState _hediffCompPostTickIntervalState;
private static readonly FishTable<Type, bool> _thingCompTickTypes = new()
{
@@ -196,12 +188,22 @@ public sealed class CompTickOptimization : ClassWithFishPrepatches
public static void ReplacementBody(ThingWithComps instance, int delta)
{
#if V1_6
var comps = instance.comps;
if (comps is null)
return;
#else
var comps = instance.AllComps;
#endif
var count = comps.Count;
var canSkipInheritedBase = CanSkipInheritedBaseThingCompTickInterval();
for (var i = 0; i < count; i++)
{
#if V1_6
var comp = instance.comps![i];
#else
var comp = comps[i];
#endif
if (!canSkipInheritedBase || !_thingCompTickIntervalTypes.GetOrAdd(comp.GetType()))
comp.CompTickInterval(delta);
}
@@ -223,12 +225,22 @@ public sealed class CompTickOptimization : ClassWithFishPrepatches
public static void ReplacementBody(ThingWithComps instance)
{
#if V1_6
var comps = instance.comps;
if (comps is null)
return;
#else
var comps = instance.AllComps;
#endif
var count = comps.Count;
var canSkipInheritedBase = CanSkipInheritedBaseThingCompTickRare();
for (var i = 0; i < count; i++)
{
#if V1_6
var comp = instance.comps![i];
#else
var comp = comps[i];
#endif
if (!canSkipInheritedBase || !_thingCompTickRareTypes.GetOrAdd(comp.GetType()))
comp.CompTickRare();
}
@@ -250,12 +262,22 @@ public sealed class CompTickOptimization : ClassWithFishPrepatches
public static void ReplacementBody(ThingWithComps instance)
{
#if V1_6
var comps = instance.comps;
if (comps is null)
return;
#else
var comps = instance.AllComps;
#endif
var count = comps.Count;
var canSkipInheritedBase = CanSkipInheritedBaseThingCompTickLong();
for (var i = 0; i < count; i++)
{
#if V1_6
var comp = instance.comps![i];
#else
var comp = comps[i];
#endif
if (!canSkipInheritedBase || !_thingCompTickLongTypes.GetOrAdd(comp.GetType()))
comp.CompTickLong();
}
@@ -281,13 +303,12 @@ public sealed class CompTickOptimization : ClassWithFishPrepatches
if (comps == null)
return;
var count = comps.Count;
var severityAdjustment = 0f;
var canSkipInheritedBase = CanSkipInheritedBaseHediffCompPostTick();
for (var i = 0; i < count; i++)
for (var i = 0; i < instance.comps!.Count; i++)
{
var comp = comps[i];
var comp = instance.comps[i];
if (!canSkipInheritedBase || !_hediffCompPostTickTypes.GetOrAdd(comp.GetType()))
comp.CompPostTick(ref severityAdjustment);
}
@@ -316,13 +337,12 @@ public sealed class CompTickOptimization : ClassWithFishPrepatches
if (comps == null)
return;
var count = comps.Count;
var severityAdjustment = 0f;
var canSkipInheritedBase = CanSkipInheritedBaseHediffCompPostTickInterval();
for (var i = 0; i < count; i++)
for (var i = 0; i < instance.comps!.Count; i++)
{
var comp = comps[i];
var comp = instance.comps[i];
if (!canSkipInheritedBase || !_hediffCompPostTickIntervalTypes.GetOrAdd(comp.GetType()))
comp.CompPostTickInterval(ref severityAdjustment, delta);
}
@@ -334,39 +354,47 @@ public sealed class CompTickOptimization : ClassWithFishPrepatches
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool CanSkipInheritedBaseThingCompTick()
{
#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
}
=> CanSkipBaseMethod(_thingCompTickMethod, _thingCompTickBaseIsTrivial, ref _thingCompTickState);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool CanSkipInheritedBaseThingCompTickInterval()
=> _canSkipInheritedBaseThingCompTickInterval.Value;
=> CanSkipBaseMethod(_thingCompTickIntervalMethod, _thingCompTickIntervalBaseIsTrivial,
ref _thingCompTickIntervalState);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool CanSkipInheritedBaseThingCompTickRare()
=> _canSkipInheritedBaseThingCompTickRare.Value;
=> CanSkipBaseMethod(_thingCompTickRareMethod, _thingCompTickRareBaseIsTrivial, ref _thingCompTickRareState);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool CanSkipInheritedBaseThingCompTickLong()
=> _canSkipInheritedBaseThingCompTickLong.Value;
=> CanSkipBaseMethod(_thingCompTickLongMethod, _thingCompTickLongBaseIsTrivial, ref _thingCompTickLongState);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool CanSkipInheritedBaseHediffCompPostTick()
=> _canSkipInheritedBaseHediffCompPostTick.Value;
=> CanSkipBaseMethod(_hediffCompPostTickMethod, _hediffCompPostTickBaseIsTrivial,
ref _hediffCompPostTickState);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool CanSkipInheritedBaseHediffCompPostTickInterval()
=> _canSkipInheritedBaseHediffCompPostTickInterval.Value;
=> CanSkipBaseMethod(_hediffCompPostTickIntervalMethod, _hediffCompPostTickIntervalBaseIsTrivial,
ref _hediffCompPostTickIntervalState);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool CanSkipBaseMethod(MethodBase method, bool isTrivial, ref BasePatchState state)
{
if (!isTrivial)
return false;
var tick = Find.TickManager?.TicksGame ?? int.MinValue;
if (!state.HasChecked || state.CheckedTick != tick)
{
state.CanSkip = !HasHarmonyPatches(method);
state.CheckedTick = tick;
state.HasChecked = true;
}
return state.CanSkip;
}
private static bool InheritsThingCompTick(Type type)
=> AccessTools.Method(type, nameof(ThingComp.CompTick))?.DeclaringType == typeof(ThingComp);