1.5, added stuff, fixed stuff

- mod icon
- fixes for new vanilla clipping issues
- GenClosest optimization improving repairing, wardening, tending jobs
- caching for new ListerBuildings methods
- DynamicDrawManager single threading
- Type.GetFields caching
- StatParts analyzer category
- removed duplicate steam warning and optionally window
- added exception handling for debug menu, incidentworker, Graphic_Multi, InitializeComps, making all those now log what mod broke and not cause black screens or whatever
This commit is contained in:
bbradson
2024-04-27 22:31:07 +02:00
parent be3dae46bb
commit d34bc77869
76 changed files with 3061 additions and 1134 deletions
@@ -86,7 +86,7 @@ public sealed class EquatableValueTypeEqualityComparer<T> : EqualityComparer<T>
/// <summary>
/// Equals method for the comparer itself.
/// </summary>
public override bool Equals(object? obj) => obj is EquatableValueTypeEqualityComparer<T>;
public override bool Equals(object? obj) => obj?.GetType() == typeof(EquatableValueTypeEqualityComparer<T>);
public override int GetHashCode() => GetType().Name.GetHashCode();
}
@@ -106,7 +106,7 @@ public sealed class EquatableNullableEqualityComparer<T> : EqualityComparer<T?>
/// <summary>
/// Equals method for the comparer itself.
/// </summary>
public override bool Equals(object? obj) => obj is EquatableNullableEqualityComparer<T>;
public override bool Equals(object? obj) => obj?.GetType() == typeof(EquatableNullableEqualityComparer<T>);
public override int GetHashCode() => GetType().Name.GetHashCode();
}
@@ -126,7 +126,7 @@ public sealed class NullableEqualityComparer<T> : EqualityComparer<T?> where T :
/// <summary>
/// Equals method for the comparer itself.
/// </summary>
public override bool Equals(object? obj) => obj is NullableEqualityComparer<T>;
public override bool Equals(object? obj) => obj?.GetType() == typeof(NullableEqualityComparer<T>);
public override int GetHashCode() => GetType().Name.GetHashCode();
}
@@ -135,7 +135,6 @@ public sealed class NullableEqualityComparer<T> : EqualityComparer<T?> where T :
public sealed class StringEqualityComparer : EqualityComparer<string?>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[SuppressMessage("Globalization", "CA1307")]
[SuppressMessage("Globalization", "CA1309")]
public override bool Equals(string? x, string? y)
=> string.Equals(x, y); // already does a null check, so this skips the extra check that'd otherwise happen
@@ -146,7 +145,7 @@ public sealed class StringEqualityComparer : EqualityComparer<string?>
/// <summary>
/// Equals method for the comparer itself.
/// </summary>
public override bool Equals(object? obj) => obj is StringEqualityComparer;
public override bool Equals(object? obj) => obj?.GetType() == typeof(StringEqualityComparer);
public override int GetHashCode() => GetType().Name.GetHashCode();
}
@@ -163,7 +162,7 @@ public sealed class IntEqualityComparer : EqualityComparer<int>
/// <summary>
/// Equals method for the comparer itself.
/// </summary>
public override bool Equals(object? obj) => obj is IntEqualityComparer;
public override bool Equals(object? obj) => obj?.GetType() == typeof(IntEqualityComparer);
public override int GetHashCode() => GetType().Name.GetHashCode();
}
@@ -180,7 +179,7 @@ public sealed class UshortEqualityComparer : EqualityComparer<ushort>
/// <summary>
/// Equals method for the comparer itself.
/// </summary>
public override bool Equals(object? obj) => obj is UshortEqualityComparer;
public override bool Equals(object? obj) => obj?.GetType() == typeof(UshortEqualityComparer);
public override int GetHashCode() => GetType().Name.GetHashCode();
}
@@ -199,7 +198,7 @@ public sealed class ReferenceEqualityComparer<T> : EqualityComparer<T>
/// <summary>
/// Equals method for the comparer itself.
/// </summary>
public override bool Equals(object? obj) => obj is ReferenceEqualityComparer<T>;
public override bool Equals(object? obj) => obj?.GetType() == typeof(ReferenceEqualityComparer<T>);
public override int GetHashCode() => GetType().Name.GetHashCode();
}
@@ -218,7 +217,7 @@ public sealed class ValueTypeEqualityComparer<T> : EqualityComparer<T> where T :
/// <summary>
/// Equals method for the comparer itself.
/// </summary>
public override bool Equals(object? obj) => obj is ReferenceEqualityComparer<T>;
public override bool Equals(object? obj) => obj?.GetType() == typeof(ReferenceEqualityComparer<T>);
public override int GetHashCode() => GetType().Name.GetHashCode();
}
@@ -6,14 +6,13 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Security;
using System.Threading.Tasks;
using PerformanceFish.Cache;
using PerformanceFish.ModCompatibility;
using ConstructorInfoCache
= PerformanceFish.Cache.ByReference<System.RuntimeTypeHandle, System.Reflection.BindingFlags,
PerformanceFish.System.ReflectionCaching.ByValueComparableArray<System.Type>,
PerformanceFish.System.ReflectionCaching.RecordArray<System.Type>,
PerformanceFish.System.ReflectionCaching.TypePatches.ConstructorInfoCacheValue>;
using FieldGetters
= PerformanceFish.Cache.ByReferenceUnclearable<System.RuntimeFieldHandle,
@@ -21,6 +20,9 @@ using FieldGetters
using FieldInfoCache
= PerformanceFish.Cache.ByReference<System.RuntimeTypeHandle, System.Reflection.BindingFlags, string,
PerformanceFish.System.ReflectionCaching.TypePatches.FieldInfoCacheValue>;
using FieldInfosCache
= PerformanceFish.Cache.ByReference<System.RuntimeTypeHandle, System.Reflection.BindingFlags,
PerformanceFish.System.ReflectionCaching.TypePatches.FieldInfosCacheValue>;
using FieldSetters
= PerformanceFish.Cache.ByReferenceUnclearable<System.RuntimeFieldHandle,
PerformanceFish.System.ReflectionCaching.FieldInfoPatches.FieldInfoSetterCache>;
@@ -29,11 +31,11 @@ using MethodInfoCache
PerformanceFish.System.ReflectionCaching.TypePatches.MethodInfoCacheValue>;
using MethodInfoWithTypesAndFlagsCache
= PerformanceFish.Cache.ByReference<System.RuntimeTypeHandle, System.Reflection.BindingFlags, string,
PerformanceFish.System.ReflectionCaching.ByValueComparableArray<System.Type>,
PerformanceFish.System.ReflectionCaching.RecordArray<System.Type>,
PerformanceFish.System.ReflectionCaching.TypePatches.MethodInfoCacheValue>;
using MethodInfoWithTypesCache
= PerformanceFish.Cache.ByReference<System.RuntimeTypeHandle, string,
PerformanceFish.System.ReflectionCaching.ByValueComparableArray<System.Type>,
PerformanceFish.System.ReflectionCaching.RecordArray<System.Type>,
PerformanceFish.System.ReflectionCaching.TypePatches.MethodInfoCacheValue>;
using MethodInvokers
= PerformanceFish.Cache.ByReferenceUnclearable<System.RuntimeMethodHandle,
@@ -41,9 +43,6 @@ using MethodInvokers
using PropertyInfoCache
= PerformanceFish.Cache.ByReference<System.RuntimeTypeHandle, System.Reflection.BindingFlags, string,
PerformanceFish.System.ReflectionCaching.TypePatches.PropertyInfoCacheValue>;
using CustomAttributeCache
= PerformanceFish.Cache.ByReference<System.Reflection.ICustomAttributeProvider, System.RuntimeTypeHandle, bool,
PerformanceFish.System.ReflectionCaching.MonoCustomAttrs.CustomAttributeCacheValue>;
using TypeFullNameCache
= PerformanceFish.Cache.ByReferenceUnclearable<System.RuntimeTypeHandle,
PerformanceFish.System.ReflectionCaching.TypePatches.TypeFullNameCacheValue>;
@@ -54,6 +53,9 @@ using ActivatorCache
// = PerformanceFish.Cache.ByReference<System.RuntimeTypeHandle,
// PerformanceFish.System.ReflectionCaching.ByValueComparableArray<System.Type>,
// PerformanceFish.System.ReflectionCaching.ActivatorPatches.ActivatorCacheValue>;
using CustomAttributeCache
= PerformanceFish.Cache.ByReferenceClassic<System.Reflection.ICustomAttributeProvider, System.RuntimeTypeHandle, bool,
PerformanceFish.System.ReflectionCaching.MonoCustomAttrs.CustomAttributeCacheValue>;
namespace PerformanceFish.System;
@@ -66,12 +68,17 @@ public sealed class ReflectionCaching : ClassWithFishPatches
ConstructorInfoCache.Initialize();
FieldGetters.Initialize();
FieldInfoCache.Initialize();
FieldInfosCache.Initialize();
FieldSetters.Initialize();
MethodInfoCache.Initialize();
MethodInfoWithTypesAndFlagsCache.Initialize();
MethodInfoWithTypesCache.Initialize();
MethodInvokers.Initialize();
PropertyInfoCache.Initialize();
TypeFullNameCache.Initialize();
ActivatorCache.Initialize();
// ActivatorWithArgumentsCache.Initialize();
CustomAttributeCache.Initialize();
}
catch (Exception ex)
{
@@ -104,16 +111,17 @@ public sealed class ReflectionCaching : ClassWithFishPatches
ToLowerIfNeededForBindingFlags(name, bindingAttr));
__result = FieldInfoCache.Get.GetOrAdd(ref key).Info;
__state.Flags = bindingAttr;
if (__result is null)
if (__result != null)
{
__state = new() { State = true, Flags = bindingAttr };
return true;
__state.State = false;
return false;
}
else
{
__state = new() { State = false, Flags = bindingAttr };
return false;
__state.State = true;
return true;
}
}
@@ -132,6 +140,47 @@ public sealed class ReflectionCaching : ClassWithFishPatches
ToLowerIfNeededForBindingFlags(name, __state.Flags)).Info
= __result;
}
public sealed class GetFieldsPatch : FishPatch
{
public override string Description { get; } = "Caches GetFields lookups";
public override MethodBase TargetMethodInfo { get; }
= AccessTools.Method(typeof(RuntimeType), nameof(RuntimeType.GetFields), [typeof(BindingFlags)])!;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Prefix(Type __instance, BindingFlags bindingAttr, out FieldInfo[]? __result,
out bool __state)
{
var key = new FieldInfosCache(__instance.TypeHandle, bindingAttr);
__result = FieldInfosCache.Get.GetOrAdd(ref key).Info;
if (__result != null)
{
__state = false;
return false;
}
else
{
__state = true;
return true;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Postfix(Type __instance, FieldInfo[] __result, BindingFlags bindingAttr, bool __state)
{
if (!__state)
return;
UpdateCache(__instance, __result, bindingAttr);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void UpdateCache(Type __instance, FieldInfo[] __result, BindingFlags bindingAttr)
=> FieldInfosCache.GetExistingReference(__instance.TypeHandle, bindingAttr).Info = __result;
}
public sealed class GetMethodWithFlags_Patch : FishPatch
{
@@ -400,6 +449,11 @@ public sealed class ReflectionCaching : ClassWithFishPatches
public FieldInfo? Info;
}
public record struct FieldInfosCacheValue
{
public FieldInfo[]? Info;
}
public record struct MethodInfoCacheValue
{
public MethodInfo? Info;
@@ -506,33 +560,35 @@ public sealed class ReflectionCaching : ClassWithFishPatches
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public record struct ByValueComparableArray<T>
public record struct RecordArray<T>
where T : class
{
public byte Length;
private int _hashCode;
public T[] Array;
public T[]? Array;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ByValueComparableArray(T[] array)
public RecordArray(T[] array)
{
Guard.IsNotNull(array);
Guard.IsLessThanOrEqualTo(array.Length, byte.MaxValue);
Array = array;
Length = (byte)array.Length;
_hashCode = HashCode.Combine((int)Length, Length > 0 && Array[0] is { } item ? item.GetHashCode() : 0);
var length = array.Length;
_hashCode = HashCode.Combine(length, length > 0 && Array[0] is { } item ? item.GetHashCode() : 0);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ByValueComparableArray<T> other)
public bool Equals(RecordArray<T> other)
{
if (Length != other.Length)
if (Array is null)
return other.Array is null;
if (other.Array is null || Array.Length != other.Array.Length)
return false;
for (var i = 0; i < Length; i++)
var length = Array.Length;
for (var i = 0; i < length; i++)
{
if (!Array[i].Equals(other.Array[i]))
if (!Array[i].Equals(other.Array![i]))
return false;
}
@@ -540,8 +596,7 @@ public sealed class ReflectionCaching : ClassWithFishPatches
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
=> _hashCode;
public override int GetHashCode() => _hashCode;
}
public sealed class ActivatorPatches
@@ -744,7 +799,7 @@ public sealed class ReflectionCaching : ClassWithFishPatches
cache.Task = _fieldSetterFailureTask;
Log.Error($"FieldInfo.SetValue has been called on '{
info.FullDescription()}'. This is a const that gets copied at compile time. An attempt at "
+ $"setting a value will always fail.\n{new StackTrace(true)}");
+ $"setting a value will always fail.\n{new StackTrace(2, true)}");
return false;
}