Decompiled source of CityMonitor v0.3.0
System.Collections.Immutable.dll
Decompiled a year ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading; using FxResources.System.Collections.Immutable; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("System.Collections.Immutable.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] [assembly: AssemblyDefaultAlias("System.Collections.Immutable")] [assembly: AssemblyMetadata(".NETFrameworkAssembly", "")] [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: AssemblyMetadata("PreferInbox", "True")] [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyDescription("System.Collections.Immutable")] [assembly: AssemblyFileVersion("4.700.20.21406")] [assembly: AssemblyInformationalVersion("3.1.4+c4164928b270ee2369808ab347d33423ef765216")] [assembly: AssemblyProduct("Microsoft® .NET Core")] [assembly: AssemblyTitle("System.Collections.Immutable")] [assembly: CLSCompliant(true)] [assembly: AssemblyVersion("1.2.5.0")] [module: System.Runtime.CompilerServices.NullablePublicOnly(true)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class NullablePublicOnlyAttribute : Attribute { public readonly bool IncludesInternals; public NullablePublicOnlyAttribute(bool P_0) { IncludesInternals = P_0; } } } namespace FxResources.System.Collections.Immutable { internal static class SR { } } namespace System { internal static class SR { private static ResourceManager s_resourceManager; internal static ResourceManager ResourceManager => s_resourceManager ?? (s_resourceManager = new ResourceManager(typeof(SR))); internal static string Arg_KeyNotFoundWithKey => GetResourceString("Arg_KeyNotFoundWithKey"); internal static string ArrayInitializedStateNotEqual => GetResourceString("ArrayInitializedStateNotEqual"); internal static string ArrayLengthsNotEqual => GetResourceString("ArrayLengthsNotEqual"); internal static string CannotFindOldValue => GetResourceString("CannotFindOldValue"); internal static string CapacityMustBeGreaterThanOrEqualToCount => GetResourceString("CapacityMustBeGreaterThanOrEqualToCount"); internal static string CapacityMustEqualCountOnMove => GetResourceString("CapacityMustEqualCountOnMove"); internal static string CollectionModifiedDuringEnumeration => GetResourceString("CollectionModifiedDuringEnumeration"); internal static string DuplicateKey => GetResourceString("DuplicateKey"); internal static string InvalidEmptyOperation => GetResourceString("InvalidEmptyOperation"); internal static string InvalidOperationOnDefaultArray => GetResourceString("InvalidOperationOnDefaultArray"); [MethodImpl(MethodImplOptions.NoInlining)] private static bool UsingResourceKeys() { return false; } internal static string GetResourceString(string resourceKey, string? defaultString = null) { if (UsingResourceKeys()) { return defaultString ?? resourceKey; } string text = null; try { text = ResourceManager.GetString(resourceKey); } catch (MissingManifestResourceException) { } if (defaultString != null && resourceKey.Equals(text)) { return defaultString; } return text; } internal static string Format(string resourceFormat, object? p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(resourceFormat, p1); } internal static string Format(string resourceFormat, object? p1, object? p2) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2); } return string.Format(resourceFormat, p1, p2); } internal static string Format(string resourceFormat, object? p1, object? p2, object? p3) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2, p3); } return string.Format(resourceFormat, p1, p2, p3); } internal static string Format(string resourceFormat, params object?[]? args) { if (args != null) { if (UsingResourceKeys()) { return resourceFormat + ", " + string.Join(", ", args); } return string.Format(resourceFormat, args); } return resourceFormat; } internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(provider, resourceFormat, p1); } internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1, object? p2) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2); } return string.Format(provider, resourceFormat, p1, p2); } internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1, object? p2, object? p3) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2, p3); } return string.Format(provider, resourceFormat, p1, p2, p3); } internal static string Format(IFormatProvider? provider, string resourceFormat, params object?[]? args) { if (args != null) { if (UsingResourceKeys()) { return resourceFormat + ", " + string.Join(", ", args); } return string.Format(provider, resourceFormat, args); } return resourceFormat; } } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method, AllowMultiple = false, Inherited = false)] internal sealed class NonVersionableAttribute : Attribute { } } namespace System.Linq { public static class ImmutableArrayExtensions { public static IEnumerable<TResult> Select<T, TResult>(this ImmutableArray<T> immutableArray, Func<T, TResult> selector) { immutableArray.ThrowNullRefIfNotInitialized(); return immutableArray.array.Select(selector); } public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this ImmutableArray<TSource> immutableArray, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector) { immutableArray.ThrowNullRefIfNotInitialized(); if (collectionSelector == null || resultSelector == null) { return Enumerable.SelectMany(immutableArray, collectionSelector, resultSelector); } if (immutableArray.Length != 0) { return immutableArray.SelectManyIterator(collectionSelector, resultSelector); } return Enumerable.Empty<TResult>(); } public static IEnumerable<T> Where<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate) { immutableArray.ThrowNullRefIfNotInitialized(); return immutableArray.array.Where(predicate); } public static bool Any<T>(this ImmutableArray<T> immutableArray) { return immutableArray.Length > 0; } public static bool Any<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate) { immutableArray.ThrowNullRefIfNotInitialized(); Requires.NotNull(predicate, "predicate"); T[] array = immutableArray.array; foreach (T arg in array) { if (predicate(arg)) { return true; } } return false; } public static bool All<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate) { immutableArray.ThrowNullRefIfNotInitialized(); Requires.NotNull(predicate, "predicate"); T[] array = immutableArray.array; foreach (T arg in array) { if (!predicate(arg)) { return false; } } return true; } public static bool SequenceEqual<TDerived, TBase>(this ImmutableArray<TBase> immutableArray, ImmutableArray<TDerived> items, IEqualityComparer<TBase> comparer = null) where TDerived : TBase { immutableArray.ThrowNullRefIfNotInitialized(); items.ThrowNullRefIfNotInitialized(); if (immutableArray.array == items.array) { return true; } if (immutableArray.Length != items.Length) { return false; } if (comparer == null) { comparer = EqualityComparer<TBase>.Default; } for (int i = 0; i < immutableArray.Length; i++) { if (!comparer.Equals(immutableArray.array[i], (TBase)(object)items.array[i])) { return false; } } return true; } public static bool SequenceEqual<TDerived, TBase>(this ImmutableArray<TBase> immutableArray, IEnumerable<TDerived> items, IEqualityComparer<TBase> comparer = null) where TDerived : TBase { Requires.NotNull(items, "items"); if (comparer == null) { comparer = EqualityComparer<TBase>.Default; } int num = 0; int length = immutableArray.Length; foreach (TDerived item in items) { if (num == length) { return false; } if (!comparer.Equals(immutableArray[num], (TBase)(object)item)) { return false; } num++; } return num == length; } public static bool SequenceEqual<TDerived, TBase>(this ImmutableArray<TBase> immutableArray, ImmutableArray<TDerived> items, Func<TBase, TBase, bool> predicate) where TDerived : TBase { Requires.NotNull(predicate, "predicate"); immutableArray.ThrowNullRefIfNotInitialized(); items.ThrowNullRefIfNotInitialized(); if (immutableArray.array == items.array) { return true; } if (immutableArray.Length != items.Length) { return false; } int i = 0; for (int length = immutableArray.Length; i < length; i++) { if (!predicate(immutableArray[i], (TBase)(object)items[i])) { return false; } } return true; } public static T Aggregate<T>(this ImmutableArray<T> immutableArray, Func<T, T, T> func) { Requires.NotNull(func, "func"); if (immutableArray.Length == 0) { return default(T); } T val = immutableArray[0]; int i = 1; for (int length = immutableArray.Length; i < length; i++) { val = func(val, immutableArray[i]); } return val; } public static TAccumulate Aggregate<TAccumulate, T>(this ImmutableArray<T> immutableArray, TAccumulate seed, Func<TAccumulate, T, TAccumulate> func) { Requires.NotNull(func, "func"); TAccumulate val = seed; T[] array = immutableArray.array; foreach (T arg in array) { val = func(val, arg); } return val; } public static TResult Aggregate<TAccumulate, TResult, T>(this ImmutableArray<T> immutableArray, TAccumulate seed, Func<TAccumulate, T, TAccumulate> func, Func<TAccumulate, TResult> resultSelector) { Requires.NotNull(resultSelector, "resultSelector"); return resultSelector(immutableArray.Aggregate(seed, func)); } public static T ElementAt<T>(this ImmutableArray<T> immutableArray, int index) { return immutableArray[index]; } public static T ElementAtOrDefault<T>(this ImmutableArray<T> immutableArray, int index) { if (index < 0 || index >= immutableArray.Length) { return default(T); } return immutableArray[index]; } public static T First<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate) { Requires.NotNull(predicate, "predicate"); T[] array = immutableArray.array; foreach (T val in array) { if (predicate(val)) { return val; } } return Enumerable.Empty<T>().First(); } public static T First<T>(this ImmutableArray<T> immutableArray) { if (immutableArray.Length <= 0) { return immutableArray.array.First(); } return immutableArray[0]; } public static T FirstOrDefault<T>(this ImmutableArray<T> immutableArray) { if (immutableArray.array.Length == 0) { return default(T); } return immutableArray.array[0]; } public static T FirstOrDefault<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate) { Requires.NotNull(predicate, "predicate"); T[] array = immutableArray.array; foreach (T val in array) { if (predicate(val)) { return val; } } return default(T); } public static T Last<T>(this ImmutableArray<T> immutableArray) { if (immutableArray.Length <= 0) { return immutableArray.array.Last(); } return immutableArray[immutableArray.Length - 1]; } public static T Last<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate) { Requires.NotNull(predicate, "predicate"); for (int num = immutableArray.Length - 1; num >= 0; num--) { if (predicate(immutableArray[num])) { return immutableArray[num]; } } return Enumerable.Empty<T>().Last(); } public static T LastOrDefault<T>(this ImmutableArray<T> immutableArray) { immutableArray.ThrowNullRefIfNotInitialized(); return immutableArray.array.LastOrDefault(); } public static T LastOrDefault<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate) { Requires.NotNull(predicate, "predicate"); for (int num = immutableArray.Length - 1; num >= 0; num--) { if (predicate(immutableArray[num])) { return immutableArray[num]; } } return default(T); } public static T Single<T>(this ImmutableArray<T> immutableArray) { immutableArray.ThrowNullRefIfNotInitialized(); return immutableArray.array.Single(); } public static T Single<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate) { Requires.NotNull(predicate, "predicate"); bool flag = true; T result = default(T); T[] array = immutableArray.array; foreach (T val in array) { if (predicate(val)) { if (!flag) { ImmutableArray.TwoElementArray.Single(); } flag = false; result = val; } } if (flag) { Enumerable.Empty<T>().Single(); } return result; } public static T SingleOrDefault<T>(this ImmutableArray<T> immutableArray) { immutableArray.ThrowNullRefIfNotInitialized(); return immutableArray.array.SingleOrDefault(); } public static T SingleOrDefault<T>(this ImmutableArray<T> immutableArray, Func<T, bool> predicate) { Requires.NotNull(predicate, "predicate"); bool flag = true; T result = default(T); T[] array = immutableArray.array; foreach (T val in array) { if (predicate(val)) { if (!flag) { ImmutableArray.TwoElementArray.Single(); } flag = false; result = val; } } return result; } public static Dictionary<TKey, T> ToDictionary<TKey, T>(this ImmutableArray<T> immutableArray, Func<T, TKey> keySelector) { return immutableArray.ToDictionary(keySelector, EqualityComparer<TKey>.Default); } public static Dictionary<TKey, TElement> ToDictionary<TKey, TElement, T>(this ImmutableArray<T> immutableArray, Func<T, TKey> keySelector, Func<T, TElement> elementSelector) { return immutableArray.ToDictionary(keySelector, elementSelector, EqualityComparer<TKey>.Default); } public static Dictionary<TKey, T> ToDictionary<TKey, T>(this ImmutableArray<T> immutableArray, Func<T, TKey> keySelector, IEqualityComparer<TKey> comparer) { Requires.NotNull(keySelector, "keySelector"); Dictionary<TKey, T> dictionary = new Dictionary<TKey, T>(immutableArray.Length, comparer); ImmutableArray<T>.Enumerator enumerator = immutableArray.GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; dictionary.Add(keySelector(current), current); } return dictionary; } public static Dictionary<TKey, TElement> ToDictionary<TKey, TElement, T>(this ImmutableArray<T> immutableArray, Func<T, TKey> keySelector, Func<T, TElement> elementSelector, IEqualityComparer<TKey> comparer) { Requires.NotNull(keySelector, "keySelector"); Requires.NotNull(elementSelector, "elementSelector"); Dictionary<TKey, TElement> dictionary = new Dictionary<TKey, TElement>(immutableArray.Length, comparer); T[] array = immutableArray.array; foreach (T arg in array) { dictionary.Add(keySelector(arg), elementSelector(arg)); } return dictionary; } public static T[] ToArray<T>(this ImmutableArray<T> immutableArray) { immutableArray.ThrowNullRefIfNotInitialized(); if (immutableArray.array.Length == 0) { return ImmutableArray<T>.Empty.array; } return (T[])immutableArray.array.Clone(); } public static T First<T>(this ImmutableArray<T>.Builder builder) { Requires.NotNull(builder, "builder"); if (!builder.Any()) { throw new InvalidOperationException(); } return builder[0]; } public static T FirstOrDefault<T>(this ImmutableArray<T>.Builder builder) { Requires.NotNull(builder, "builder"); if (!builder.Any()) { return default(T); } return builder[0]; } public static T Last<T>(this ImmutableArray<T>.Builder builder) { Requires.NotNull(builder, "builder"); if (!builder.Any()) { throw new InvalidOperationException(); } return builder[builder.Count - 1]; } public static T LastOrDefault<T>(this ImmutableArray<T>.Builder builder) { Requires.NotNull(builder, "builder"); if (!builder.Any()) { return default(T); } return builder[builder.Count - 1]; } public static bool Any<T>(this ImmutableArray<T>.Builder builder) { Requires.NotNull(builder, "builder"); return builder.Count > 0; } private static IEnumerable<TResult> SelectManyIterator<TSource, TCollection, TResult>(this ImmutableArray<TSource> immutableArray, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector) { TSource[] array = immutableArray.array; foreach (TSource item in array) { foreach (TCollection item2 in collectionSelector(item)) { yield return resultSelector(item, item2); } } } } } namespace System.Collections.Immutable { internal static class AllocFreeConcurrentStack<T> { private const int MaxSize = 35; private static readonly Type s_typeOfT = typeof(T); private static Stack<RefAsValueType<T>> ThreadLocalStack { get { Dictionary<Type, object> dictionary = AllocFreeConcurrentStack.t_stacks; if (dictionary == null) { dictionary = (AllocFreeConcurrentStack.t_stacks = new Dictionary<Type, object>()); } if (!dictionary.TryGetValue(s_typeOfT, out var value)) { value = new Stack<RefAsValueType<T>>(35); dictionary.Add(s_typeOfT, value); } return (Stack<RefAsValueType<T>>)value; } } public static void TryAdd(T item) { Stack<RefAsValueType<T>> threadLocalStack = ThreadLocalStack; if (threadLocalStack.Count < 35) { threadLocalStack.Push(new RefAsValueType<T>(item)); } } public static bool TryTake(out T item) { Stack<RefAsValueType<T>> threadLocalStack = ThreadLocalStack; if (threadLocalStack != null && threadLocalStack.Count > 0) { item = threadLocalStack.Pop().Value; return true; } item = default(T); return false; } } internal static class AllocFreeConcurrentStack { [ThreadStatic] internal static Dictionary<Type, object> t_stacks; } internal sealed class DictionaryEnumerator<TKey, TValue> : IDictionaryEnumerator, IEnumerator { private readonly IEnumerator<KeyValuePair<TKey, TValue>> _inner; public DictionaryEntry Entry => new DictionaryEntry(_inner.Current.Key, _inner.Current.Value); public object Key => _inner.Current.Key; public object Value => _inner.Current.Value; public object Current => Entry; internal DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> inner) { Requires.NotNull(inner, "inner"); _inner = inner; } public bool MoveNext() { return _inner.MoveNext(); } public void Reset() { _inner.Reset(); } } internal struct DisposableEnumeratorAdapter<T, TEnumerator> : IDisposable where TEnumerator : struct, IEnumerator<T> { private readonly IEnumerator<T> _enumeratorObject; private TEnumerator _enumeratorStruct; public T Current { get { if (_enumeratorObject == null) { return _enumeratorStruct.Current; } return _enumeratorObject.Current; } } internal DisposableEnumeratorAdapter(TEnumerator enumerator) { _enumeratorStruct = enumerator; _enumeratorObject = null; } internal DisposableEnumeratorAdapter(IEnumerator<T> enumerator) { _enumeratorStruct = default(TEnumerator); _enumeratorObject = enumerator; } public bool MoveNext() { if (_enumeratorObject == null) { return _enumeratorStruct.MoveNext(); } return _enumeratorObject.MoveNext(); } public void Dispose() { if (_enumeratorObject != null) { _enumeratorObject.Dispose(); } else { _enumeratorStruct.Dispose(); } } public DisposableEnumeratorAdapter<T, TEnumerator> GetEnumerator() { return this; } } internal interface IBinaryTree { int Height { get; } bool IsEmpty { get; } int Count { get; } IBinaryTree Left { get; } IBinaryTree Right { get; } } internal interface IBinaryTree<out T> : IBinaryTree { T Value { get; } new IBinaryTree<T> Left { get; } new IBinaryTree<T> Right { get; } } internal interface IImmutableArray { Array Array { get; } } public interface IImmutableDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IReadOnlyCollection<KeyValuePair<TKey, TValue>> { IImmutableDictionary<TKey, TValue> Clear(); IImmutableDictionary<TKey, TValue> Add(TKey key, TValue value); IImmutableDictionary<TKey, TValue> AddRange(IEnumerable<KeyValuePair<TKey, TValue>> pairs); IImmutableDictionary<TKey, TValue> SetItem(TKey key, TValue value); IImmutableDictionary<TKey, TValue> SetItems(IEnumerable<KeyValuePair<TKey, TValue>> items); IImmutableDictionary<TKey, TValue> RemoveRange(IEnumerable<TKey> keys); IImmutableDictionary<TKey, TValue> Remove(TKey key); bool Contains(KeyValuePair<TKey, TValue> pair); bool TryGetKey(TKey equalKey, out TKey actualKey); } internal interface IImmutableDictionaryInternal<TKey, TValue> { bool ContainsValue(TValue value); } public interface IImmutableList<T> : IReadOnlyList<T>, IEnumerable<T>, IEnumerable, IReadOnlyCollection<T> { IImmutableList<T> Clear(); int IndexOf(T item, int index, int count, IEqualityComparer<T> equalityComparer); int LastIndexOf(T item, int index, int count, IEqualityComparer<T> equalityComparer); IImmutableList<T> Add(T value); IImmutableList<T> AddRange(IEnumerable<T> items); IImmutableList<T> Insert(int index, T element); IImmutableList<T> InsertRange(int index, IEnumerable<T> items); IImmutableList<T> Remove(T value, IEqualityComparer<T> equalityComparer); IImmutableList<T> RemoveAll(Predicate<T> match); IImmutableList<T> RemoveRange(IEnumerable<T> items, IEqualityComparer<T> equalityComparer); IImmutableList<T> RemoveRange(int index, int count); IImmutableList<T> RemoveAt(int index); IImmutableList<T> SetItem(int index, T value); IImmutableList<T> Replace(T oldValue, T newValue, IEqualityComparer<T> equalityComparer); } internal interface IImmutableListQueries<T> : IReadOnlyList<T>, IEnumerable<T>, IEnumerable, IReadOnlyCollection<T> { ImmutableList<TOutput> ConvertAll<TOutput>(Func<T, TOutput> converter); void ForEach(Action<T> action); ImmutableList<T> GetRange(int index, int count); void CopyTo(T[] array); void CopyTo(T[] array, int arrayIndex); void CopyTo(int index, T[] array, int arrayIndex, int count); bool Exists(Predicate<T> match); T Find(Predicate<T> match); ImmutableList<T> FindAll(Predicate<T> match); int FindIndex(Predicate<T> match); int FindIndex(int startIndex, Predicate<T> match); int FindIndex(int startIndex, int count, Predicate<T> match); T FindLast(Predicate<T> match); int FindLastIndex(Predicate<T> match); int FindLastIndex(int startIndex, Predicate<T> match); int FindLastIndex(int startIndex, int count, Predicate<T> match); bool TrueForAll(Predicate<T> match); int BinarySearch(T item); int BinarySearch(T item, IComparer<T> comparer); int BinarySearch(int index, int count, T item, IComparer<T> comparer); } public interface IImmutableQueue<T> : IEnumerable<T>, IEnumerable { bool IsEmpty { get; } IImmutableQueue<T> Clear(); T Peek(); IImmutableQueue<T> Enqueue(T value); IImmutableQueue<T> Dequeue(); } public interface IImmutableSet<T> : IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable { IImmutableSet<T> Clear(); bool Contains(T value); IImmutableSet<T> Add(T value); IImmutableSet<T> Remove(T value); bool TryGetValue(T equalValue, out T actualValue); IImmutableSet<T> Intersect(IEnumerable<T> other); IImmutableSet<T> Except(IEnumerable<T> other); IImmutableSet<T> SymmetricExcept(IEnumerable<T> other); IImmutableSet<T> Union(IEnumerable<T> other); bool SetEquals(IEnumerable<T> other); bool IsProperSubsetOf(IEnumerable<T> other); bool IsProperSupersetOf(IEnumerable<T> other); bool IsSubsetOf(IEnumerable<T> other); bool IsSupersetOf(IEnumerable<T> other); bool Overlaps(IEnumerable<T> other); } public interface IImmutableStack<T> : IEnumerable<T>, IEnumerable { bool IsEmpty { get; } IImmutableStack<T> Clear(); IImmutableStack<T> Push(T value); IImmutableStack<T> Pop(); T Peek(); } [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] public sealed class ImmutableHashSet<T> : IImmutableSet<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable, IHashKeyCollection<T>, ICollection<T>, ISet<T>, ICollection, IStrongEnumerable<T, ImmutableHashSet<T>.Enumerator> { private class HashBucketByValueEqualityComparer : IEqualityComparer<HashBucket> { private static readonly IEqualityComparer<HashBucket> s_defaultInstance = new HashBucketByValueEqualityComparer(EqualityComparer<T>.Default); private readonly IEqualityComparer<T> _valueComparer; internal static IEqualityComparer<HashBucket> DefaultInstance => s_defaultInstance; internal HashBucketByValueEqualityComparer(IEqualityComparer<T> valueComparer) { Requires.NotNull(valueComparer, "valueComparer"); _valueComparer = valueComparer; } public bool Equals(HashBucket x, HashBucket y) { return x.EqualsByValue(y, _valueComparer); } public int GetHashCode(HashBucket obj) { throw new NotSupportedException(); } } private class HashBucketByRefEqualityComparer : IEqualityComparer<HashBucket> { private static readonly IEqualityComparer<HashBucket> s_defaultInstance = new HashBucketByRefEqualityComparer(); internal static IEqualityComparer<HashBucket> DefaultInstance => s_defaultInstance; private HashBucketByRefEqualityComparer() { } public bool Equals(HashBucket x, HashBucket y) { return x.EqualsByRef(y); } public int GetHashCode(HashBucket obj) { throw new NotSupportedException(); } } [DebuggerDisplay("Count = {Count}")] public sealed class Builder : IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable, ISet<T>, ICollection<T> { private SortedInt32KeyNode<HashBucket> _root = SortedInt32KeyNode<HashBucket>.EmptyNode; private IEqualityComparer<T> _equalityComparer; private IEqualityComparer<HashBucket> _hashBucketEqualityComparer; private int _count; private ImmutableHashSet<T> _immutable; private int _version; public int Count => _count; bool ICollection<T>.IsReadOnly => false; public IEqualityComparer<T> KeyComparer { get { return _equalityComparer; } set { Requires.NotNull(value, "value"); if (value != _equalityComparer) { MutationResult mutationResult = ImmutableHashSet<T>.Union((IEnumerable<T>)this, new MutationInput(SortedInt32KeyNode<HashBucket>.EmptyNode, value, _hashBucketEqualityComparer, 0)); _immutable = null; _equalityComparer = value; Root = mutationResult.Root; _count = mutationResult.Count; } } } internal int Version => _version; private MutationInput Origin => new MutationInput(Root, _equalityComparer, _hashBucketEqualityComparer, _count); private SortedInt32KeyNode<HashBucket> Root { get { return _root; } set { _version++; if (_root != value) { _root = value; _immutable = null; } } } internal Builder(ImmutableHashSet<T> set) { Requires.NotNull(set, "set"); _root = set._root; _count = set._count; _equalityComparer = set._equalityComparer; _hashBucketEqualityComparer = set._hashBucketEqualityComparer; _immutable = set; } public Enumerator GetEnumerator() { return new Enumerator(_root, this); } public ImmutableHashSet<T> ToImmutable() { if (_immutable == null) { _immutable = ImmutableHashSet<T>.Wrap(_root, _equalityComparer, _count); } return _immutable; } public bool Add(T item) { MutationResult result = ImmutableHashSet<T>.Add(item, Origin); Apply(result); return result.Count != 0; } public bool Remove(T item) { MutationResult result = ImmutableHashSet<T>.Remove(item, Origin); Apply(result); return result.Count != 0; } public bool Contains(T item) { return ImmutableHashSet<T>.Contains(item, Origin); } public void Clear() { _count = 0; Root = SortedInt32KeyNode<HashBucket>.EmptyNode; } public void ExceptWith(IEnumerable<T> other) { MutationResult result = ImmutableHashSet<T>.Except(other, _equalityComparer, _hashBucketEqualityComparer, _root); Apply(result); } public void IntersectWith(IEnumerable<T> other) { MutationResult result = ImmutableHashSet<T>.Intersect(other, Origin); Apply(result); } public bool IsProperSubsetOf(IEnumerable<T> other) { return ImmutableHashSet<T>.IsProperSubsetOf(other, Origin); } public bool IsProperSupersetOf(IEnumerable<T> other) { return ImmutableHashSet<T>.IsProperSupersetOf(other, Origin); } public bool IsSubsetOf(IEnumerable<T> other) { return ImmutableHashSet<T>.IsSubsetOf(other, Origin); } public bool IsSupersetOf(IEnumerable<T> other) { return ImmutableHashSet<T>.IsSupersetOf(other, Origin); } public bool Overlaps(IEnumerable<T> other) { return ImmutableHashSet<T>.Overlaps(other, Origin); } public bool SetEquals(IEnumerable<T> other) { if (this == other) { return true; } return ImmutableHashSet<T>.SetEquals(other, Origin); } public void SymmetricExceptWith(IEnumerable<T> other) { MutationResult result = ImmutableHashSet<T>.SymmetricExcept(other, Origin); Apply(result); } public void UnionWith(IEnumerable<T> other) { MutationResult result = ImmutableHashSet<T>.Union(other, Origin); Apply(result); } void ICollection<T>.Add(T item) { Add(item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array[arrayIndex++] = current; } } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private void Apply(MutationResult result) { Root = result.Root; if (result.CountType == CountType.Adjustment) { _count += result.Count; } else { _count = result.Count; } } } public struct Enumerator : IEnumerator<T>, IEnumerator, IDisposable, IStrongEnumerator<T> { private readonly Builder _builder; private SortedInt32KeyNode<HashBucket>.Enumerator _mapEnumerator; private HashBucket.Enumerator _bucketEnumerator; private int _enumeratingBuilderVersion; public T Current { get { _mapEnumerator.ThrowIfDisposed(); return _bucketEnumerator.Current; } } object IEnumerator.Current => Current; internal Enumerator(SortedInt32KeyNode<HashBucket> root, Builder builder = null) { _builder = builder; _mapEnumerator = new SortedInt32KeyNode<HashBucket>.Enumerator(root); _bucketEnumerator = default(HashBucket.Enumerator); _enumeratingBuilderVersion = builder?.Version ?? (-1); } public bool MoveNext() { ThrowIfChanged(); if (_bucketEnumerator.MoveNext()) { return true; } if (_mapEnumerator.MoveNext()) { _bucketEnumerator = new HashBucket.Enumerator(_mapEnumerator.Current.Value); return _bucketEnumerator.MoveNext(); } return false; } public void Reset() { _enumeratingBuilderVersion = ((_builder != null) ? _builder.Version : (-1)); _mapEnumerator.Reset(); _bucketEnumerator.Dispose(); _bucketEnumerator = default(HashBucket.Enumerator); } public void Dispose() { _mapEnumerator.Dispose(); _bucketEnumerator.Dispose(); } private void ThrowIfChanged() { if (_builder != null && _builder.Version != _enumeratingBuilderVersion) { throw new InvalidOperationException(System.SR.CollectionModifiedDuringEnumeration); } } } internal enum OperationResult { SizeChanged, NoChangeRequired } internal readonly struct HashBucket { internal struct Enumerator : IEnumerator<T>, IEnumerator, IDisposable { private enum Position { BeforeFirst, First, Additional, End } private readonly HashBucket _bucket; private bool _disposed; private Position _currentPosition; private ImmutableList<T>.Enumerator _additionalEnumerator; object IEnumerator.Current => Current; public T Current { get { ThrowIfDisposed(); return _currentPosition switch { Position.First => _bucket._firstValue, Position.Additional => _additionalEnumerator.Current, _ => throw new InvalidOperationException(), }; } } internal Enumerator(HashBucket bucket) { _disposed = false; _bucket = bucket; _currentPosition = Position.BeforeFirst; _additionalEnumerator = default(ImmutableList<T>.Enumerator); } public bool MoveNext() { ThrowIfDisposed(); if (_bucket.IsEmpty) { _currentPosition = Position.End; return false; } switch (_currentPosition) { case Position.BeforeFirst: _currentPosition = Position.First; return true; case Position.First: if (_bucket._additionalElements.IsEmpty) { _currentPosition = Position.End; return false; } _currentPosition = Position.Additional; _additionalEnumerator = new ImmutableList<T>.Enumerator(_bucket._additionalElements); return _additionalEnumerator.MoveNext(); case Position.Additional: return _additionalEnumerator.MoveNext(); case Position.End: return false; default: throw new InvalidOperationException(); } } public void Reset() { ThrowIfDisposed(); _additionalEnumerator.Dispose(); _currentPosition = Position.BeforeFirst; } public void Dispose() { _disposed = true; _additionalEnumerator.Dispose(); } private void ThrowIfDisposed() { if (_disposed) { Requires.FailObjectDisposed(this); } } } private readonly T _firstValue; private readonly ImmutableList<T>.Node _additionalElements; internal bool IsEmpty => _additionalElements == null; private HashBucket(T firstElement, ImmutableList<T>.Node additionalElements = null) { _firstValue = firstElement; _additionalElements = additionalElements ?? ImmutableList<T>.Node.EmptyNode; } public Enumerator GetEnumerator() { return new Enumerator(this); } public override bool Equals(object obj) { throw new NotSupportedException(); } public override int GetHashCode() { throw new NotSupportedException(); } internal bool EqualsByRef(HashBucket other) { if ((object)_firstValue == (object)other._firstValue) { return _additionalElements == other._additionalElements; } return false; } internal bool EqualsByValue(HashBucket other, IEqualityComparer<T> valueComparer) { if (valueComparer.Equals(_firstValue, other._firstValue)) { return _additionalElements == other._additionalElements; } return false; } internal HashBucket Add(T value, IEqualityComparer<T> valueComparer, out OperationResult result) { if (IsEmpty) { result = OperationResult.SizeChanged; return new HashBucket(value); } if (valueComparer.Equals(value, _firstValue) || _additionalElements.IndexOf(value, valueComparer) >= 0) { result = OperationResult.NoChangeRequired; return this; } result = OperationResult.SizeChanged; return new HashBucket(_firstValue, _additionalElements.Add(value)); } internal bool Contains(T value, IEqualityComparer<T> valueComparer) { if (IsEmpty) { return false; } if (!valueComparer.Equals(value, _firstValue)) { return _additionalElements.IndexOf(value, valueComparer) >= 0; } return true; } internal bool TryExchange(T value, IEqualityComparer<T> valueComparer, out T existingValue) { if (!IsEmpty) { if (valueComparer.Equals(value, _firstValue)) { existingValue = _firstValue; return true; } int num = _additionalElements.IndexOf(value, valueComparer); if (num >= 0) { existingValue = _additionalElements.ItemRef(num); return true; } } existingValue = value; return false; } internal HashBucket Remove(T value, IEqualityComparer<T> equalityComparer, out OperationResult result) { if (IsEmpty) { result = OperationResult.NoChangeRequired; return this; } if (equalityComparer.Equals(_firstValue, value)) { if (_additionalElements.IsEmpty) { result = OperationResult.SizeChanged; return default(HashBucket); } int count = _additionalElements.Left.Count; result = OperationResult.SizeChanged; return new HashBucket(_additionalElements.Key, _additionalElements.RemoveAt(count)); } int num = _additionalElements.IndexOf(value, equalityComparer); if (num < 0) { result = OperationResult.NoChangeRequired; return this; } result = OperationResult.SizeChanged; return new HashBucket(_firstValue, _additionalElements.RemoveAt(num)); } internal void Freeze() { if (_additionalElements != null) { _additionalElements.Freeze(); } } } private readonly struct MutationInput { private readonly SortedInt32KeyNode<HashBucket> _root; private readonly IEqualityComparer<T> _equalityComparer; private readonly int _count; private readonly IEqualityComparer<HashBucket> _hashBucketEqualityComparer; internal SortedInt32KeyNode<HashBucket> Root => _root; internal IEqualityComparer<T> EqualityComparer => _equalityComparer; internal int Count => _count; internal IEqualityComparer<HashBucket> HashBucketEqualityComparer => _hashBucketEqualityComparer; internal MutationInput(ImmutableHashSet<T> set) { Requires.NotNull(set, "set"); _root = set._root; _equalityComparer = set._equalityComparer; _count = set._count; _hashBucketEqualityComparer = set._hashBucketEqualityComparer; } internal MutationInput(SortedInt32KeyNode<HashBucket> root, IEqualityComparer<T> equalityComparer, IEqualityComparer<HashBucket> hashBucketEqualityComparer, int count) { Requires.NotNull(root, "root"); Requires.NotNull(equalityComparer, "equalityComparer"); Requires.Range(count >= 0, "count"); Requires.NotNull(hashBucketEqualityComparer, "hashBucketEqualityComparer"); _root = root; _equalityComparer = equalityComparer; _count = count; _hashBucketEqualityComparer = hashBucketEqualityComparer; } } private enum CountType { Adjustment, FinalValue } private readonly struct MutationResult { private readonly SortedInt32KeyNode<HashBucket> _root; private readonly int _count; private readonly CountType _countType; internal SortedInt32KeyNode<HashBucket> Root => _root; internal int Count => _count; internal CountType CountType => _countType; internal MutationResult(SortedInt32KeyNode<HashBucket> root, int count, CountType countType = CountType.Adjustment) { Requires.NotNull(root, "root"); _root = root; _count = count; _countType = countType; } internal ImmutableHashSet<T> Finalize(ImmutableHashSet<T> priorSet) { Requires.NotNull(priorSet, "priorSet"); int num = Count; if (CountType == CountType.Adjustment) { num += priorSet._count; } return priorSet.Wrap(Root, num); } } private readonly struct NodeEnumerable : IEnumerable<T>, IEnumerable { private readonly SortedInt32KeyNode<HashBucket> _root; internal NodeEnumerable(SortedInt32KeyNode<HashBucket> root) { Requires.NotNull(root, "root"); _root = root; } public Enumerator GetEnumerator() { return new Enumerator(_root); } [ExcludeFromCodeCoverage] IEnumerator<T> IEnumerable<T>.GetEnumerator() { return GetEnumerator(); } [ExcludeFromCodeCoverage] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public static readonly ImmutableHashSet<T> Empty = new ImmutableHashSet<T>(SortedInt32KeyNode<HashBucket>.EmptyNode, EqualityComparer<T>.Default, 0); private static readonly Action<KeyValuePair<int, HashBucket>> s_FreezeBucketAction = delegate(KeyValuePair<int, HashBucket> kv) { kv.Value.Freeze(); }; private readonly IEqualityComparer<T> _equalityComparer; private readonly int _count; private readonly SortedInt32KeyNode<HashBucket> _root; private readonly IEqualityComparer<HashBucket> _hashBucketEqualityComparer; public int Count => _count; public bool IsEmpty => Count == 0; public IEqualityComparer<T> KeyComparer => _equalityComparer; [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot => this; [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => true; internal IBinaryTree Root => _root; private MutationInput Origin => new MutationInput(this); bool ICollection<T>.IsReadOnly => true; internal ImmutableHashSet(IEqualityComparer<T> equalityComparer) : this(SortedInt32KeyNode<HashBucket>.EmptyNode, equalityComparer, 0) { } private ImmutableHashSet(SortedInt32KeyNode<HashBucket> root, IEqualityComparer<T> equalityComparer, int count) { Requires.NotNull(root, "root"); Requires.NotNull(equalityComparer, "equalityComparer"); root.Freeze(s_FreezeBucketAction); _root = root; _count = count; _equalityComparer = equalityComparer; _hashBucketEqualityComparer = GetHashBucketEqualityComparer(equalityComparer); } public ImmutableHashSet<T> Clear() { if (!IsEmpty) { return Empty.WithComparer(_equalityComparer); } return this; } [ExcludeFromCodeCoverage] IImmutableSet<T> IImmutableSet<T>.Clear() { return Clear(); } public Builder ToBuilder() { return new Builder(this); } public ImmutableHashSet<T> Add(T item) { return Add(item, Origin).Finalize(this); } public ImmutableHashSet<T> Remove(T item) { return Remove(item, Origin).Finalize(this); } public bool TryGetValue(T equalValue, out T actualValue) { int hashCode = _equalityComparer.GetHashCode(equalValue); if (_root.TryGetValue(hashCode, out var value)) { return value.TryExchange(equalValue, _equalityComparer, out actualValue); } actualValue = equalValue; return false; } public ImmutableHashSet<T> Union(IEnumerable<T> other) { Requires.NotNull(other, "other"); return Union(other, avoidWithComparer: false); } public ImmutableHashSet<T> Intersect(IEnumerable<T> other) { Requires.NotNull(other, "other"); return Intersect(other, Origin).Finalize(this); } public ImmutableHashSet<T> Except(IEnumerable<T> other) { Requires.NotNull(other, "other"); return Except(other, _equalityComparer, _hashBucketEqualityComparer, _root).Finalize(this); } public ImmutableHashSet<T> SymmetricExcept(IEnumerable<T> other) { Requires.NotNull(other, "other"); return SymmetricExcept(other, Origin).Finalize(this); } public bool SetEquals(IEnumerable<T> other) { Requires.NotNull(other, "other"); if (this == other) { return true; } return SetEquals(other, Origin); } public bool IsProperSubsetOf(IEnumerable<T> other) { Requires.NotNull(other, "other"); return IsProperSubsetOf(other, Origin); } public bool IsProperSupersetOf(IEnumerable<T> other) { Requires.NotNull(other, "other"); return IsProperSupersetOf(other, Origin); } public bool IsSubsetOf(IEnumerable<T> other) { Requires.NotNull(other, "other"); return IsSubsetOf(other, Origin); } public bool IsSupersetOf(IEnumerable<T> other) { Requires.NotNull(other, "other"); return IsSupersetOf(other, Origin); } public bool Overlaps(IEnumerable<T> other) { Requires.NotNull(other, "other"); return Overlaps(other, Origin); } [ExcludeFromCodeCoverage] IImmutableSet<T> IImmutableSet<T>.Add(T item) { return Add(item); } [ExcludeFromCodeCoverage] IImmutableSet<T> IImmutableSet<T>.Remove(T item) { return Remove(item); } [ExcludeFromCodeCoverage] IImmutableSet<T> IImmutableSet<T>.Union(IEnumerable<T> other) { return Union(other); } [ExcludeFromCodeCoverage] IImmutableSet<T> IImmutableSet<T>.Intersect(IEnumerable<T> other) { return Intersect(other); } [ExcludeFromCodeCoverage] IImmutableSet<T> IImmutableSet<T>.Except(IEnumerable<T> other) { return Except(other); } [ExcludeFromCodeCoverage] IImmutableSet<T> IImmutableSet<T>.SymmetricExcept(IEnumerable<T> other) { return SymmetricExcept(other); } public bool Contains(T item) { return Contains(item, Origin); } public ImmutableHashSet<T> WithComparer(IEqualityComparer<T> equalityComparer) { if (equalityComparer == null) { equalityComparer = EqualityComparer<T>.Default; } if (equalityComparer == _equalityComparer) { return this; } ImmutableHashSet<T> immutableHashSet = new ImmutableHashSet<T>(equalityComparer); return immutableHashSet.Union(this, avoidWithComparer: true); } bool ISet<T>.Add(T item) { throw new NotSupportedException(); } void ISet<T>.ExceptWith(IEnumerable<T> other) { throw new NotSupportedException(); } void ISet<T>.IntersectWith(IEnumerable<T> other) { throw new NotSupportedException(); } void ISet<T>.SymmetricExceptWith(IEnumerable<T> other) { throw new NotSupportedException(); } void ISet<T>.UnionWith(IEnumerable<T> other) { throw new NotSupportedException(); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array[arrayIndex++] = current; } } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } void ICollection.CopyTo(Array array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array.SetValue(current, arrayIndex++); } } public Enumerator GetEnumerator() { return new Enumerator(_root); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { if (!IsEmpty) { return GetEnumerator(); } return Enumerable.Empty<T>().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private static bool IsSupersetOf(IEnumerable<T> other, MutationInput origin) { Requires.NotNull(other, "other"); foreach (T item in other.GetEnumerableDisposable<T, Enumerator>()) { if (!Contains(item, origin)) { return false; } } return true; } private static MutationResult Add(T item, MutationInput origin) { int hashCode = origin.EqualityComparer.GetHashCode(item); OperationResult result; HashBucket newBucket = origin.Root.GetValueOrDefault(hashCode).Add(item, origin.EqualityComparer, out result); if (result == OperationResult.NoChangeRequired) { return new MutationResult(origin.Root, 0); } SortedInt32KeyNode<HashBucket> root = UpdateRoot(origin.Root, hashCode, origin.HashBucketEqualityComparer, newBucket); return new MutationResult(root, 1); } private static MutationResult Remove(T item, MutationInput origin) { OperationResult result = OperationResult.NoChangeRequired; int hashCode = origin.EqualityComparer.GetHashCode(item); SortedInt32KeyNode<HashBucket> root = origin.Root; if (origin.Root.TryGetValue(hashCode, out var value)) { HashBucket newBucket = value.Remove(item, origin.EqualityComparer, out result); if (result == OperationResult.NoChangeRequired) { return new MutationResult(origin.Root, 0); } root = UpdateRoot(origin.Root, hashCode, origin.HashBucketEqualityComparer, newBucket); } return new MutationResult(root, (result == OperationResult.SizeChanged) ? (-1) : 0); } private static bool Contains(T item, MutationInput origin) { int hashCode = origin.EqualityComparer.GetHashCode(item); if (origin.Root.TryGetValue(hashCode, out var value)) { return value.Contains(item, origin.EqualityComparer); } return false; } private static MutationResult Union(IEnumerable<T> other, MutationInput origin) { Requires.NotNull(other, "other"); int num = 0; SortedInt32KeyNode<HashBucket> sortedInt32KeyNode = origin.Root; foreach (T item in other.GetEnumerableDisposable<T, Enumerator>()) { int hashCode = origin.EqualityComparer.GetHashCode(item); OperationResult result; HashBucket newBucket = sortedInt32KeyNode.GetValueOrDefault(hashCode).Add(item, origin.EqualityComparer, out result); if (result == OperationResult.SizeChanged) { sortedInt32KeyNode = UpdateRoot(sortedInt32KeyNode, hashCode, origin.HashBucketEqualityComparer, newBucket); num++; } } return new MutationResult(sortedInt32KeyNode, num); } private static bool Overlaps(IEnumerable<T> other, MutationInput origin) { Requires.NotNull(other, "other"); if (origin.Root.IsEmpty) { return false; } foreach (T item in other.GetEnumerableDisposable<T, Enumerator>()) { if (Contains(item, origin)) { return true; } } return false; } private static bool SetEquals(IEnumerable<T> other, MutationInput origin) { Requires.NotNull(other, "other"); HashSet<T> hashSet = new HashSet<T>(other, origin.EqualityComparer); if (origin.Count != hashSet.Count) { return false; } foreach (T item in hashSet) { if (!Contains(item, origin)) { return false; } } return true; } private static SortedInt32KeyNode<HashBucket> UpdateRoot(SortedInt32KeyNode<HashBucket> root, int hashCode, IEqualityComparer<HashBucket> hashBucketEqualityComparer, HashBucket newBucket) { bool mutated; if (newBucket.IsEmpty) { return root.Remove(hashCode, out mutated); } bool replacedExistingValue; return root.SetItem(hashCode, newBucket, hashBucketEqualityComparer, out replacedExistingValue, out mutated); } private static MutationResult Intersect(IEnumerable<T> other, MutationInput origin) { Requires.NotNull(other, "other"); SortedInt32KeyNode<HashBucket> root = SortedInt32KeyNode<HashBucket>.EmptyNode; int num = 0; foreach (T item in other.GetEnumerableDisposable<T, Enumerator>()) { if (Contains(item, origin)) { MutationResult mutationResult = Add(item, new MutationInput(root, origin.EqualityComparer, origin.HashBucketEqualityComparer, num)); root = mutationResult.Root; num += mutationResult.Count; } } return new MutationResult(root, num, CountType.FinalValue); } private static MutationResult Except(IEnumerable<T> other, IEqualityComparer<T> equalityComparer, IEqualityComparer<HashBucket> hashBucketEqualityComparer, SortedInt32KeyNode<HashBucket> root) { Requires.NotNull(other, "other"); Requires.NotNull(equalityComparer, "equalityComparer"); Requires.NotNull(root, "root"); int num = 0; SortedInt32KeyNode<HashBucket> sortedInt32KeyNode = root; foreach (T item in other.GetEnumerableDisposable<T, Enumerator>()) { int hashCode = equalityComparer.GetHashCode(item); if (sortedInt32KeyNode.TryGetValue(hashCode, out var value)) { OperationResult result; HashBucket newBucket = value.Remove(item, equalityComparer, out result); if (result == OperationResult.SizeChanged) { num--; sortedInt32KeyNode = UpdateRoot(sortedInt32KeyNode, hashCode, hashBucketEqualityComparer, newBucket); } } } return new MutationResult(sortedInt32KeyNode, num); } private static MutationResult SymmetricExcept(IEnumerable<T> other, MutationInput origin) { Requires.NotNull(other, "other"); ImmutableHashSet<T> immutableHashSet = ImmutableHashSet.CreateRange(origin.EqualityComparer, other); int num = 0; SortedInt32KeyNode<HashBucket> root = SortedInt32KeyNode<HashBucket>.EmptyNode; foreach (T item in new NodeEnumerable(origin.Root)) { if (!immutableHashSet.Contains(item)) { MutationResult mutationResult = Add(item, new MutationInput(root, origin.EqualityComparer, origin.HashBucketEqualityComparer, num)); root = mutationResult.Root; num += mutationResult.Count; } } foreach (T item2 in immutableHashSet) { if (!Contains(item2, origin)) { MutationResult mutationResult2 = Add(item2, new MutationInput(root, origin.EqualityComparer, origin.HashBucketEqualityComparer, num)); root = mutationResult2.Root; num += mutationResult2.Count; } } return new MutationResult(root, num, CountType.FinalValue); } private static bool IsProperSubsetOf(IEnumerable<T> other, MutationInput origin) { Requires.NotNull(other, "other"); if (origin.Root.IsEmpty) { return other.Any(); } HashSet<T> hashSet = new HashSet<T>(other, origin.EqualityComparer); if (origin.Count >= hashSet.Count) { return false; } int num = 0; bool flag = false; foreach (T item in hashSet) { if (Contains(item, origin)) { num++; } else { flag = true; } if (num == origin.Count && flag) { return true; } } return false; } private static bool IsProperSupersetOf(IEnumerable<T> other, MutationInput origin) { Requires.NotNull(other, "other"); if (origin.Root.IsEmpty) { return false; } int num = 0; foreach (T item in other.GetEnumerableDisposable<T, Enumerator>()) { num++; if (!Contains(item, origin)) { return false; } } return origin.Count > num; } private static bool IsSubsetOf(IEnumerable<T> other, MutationInput origin) { Requires.NotNull(other, "other"); if (origin.Root.IsEmpty) { return true; } HashSet<T> hashSet = new HashSet<T>(other, origin.EqualityComparer); int num = 0; foreach (T item in hashSet) { if (Contains(item, origin)) { num++; } } return num == origin.Count; } private static ImmutableHashSet<T> Wrap(SortedInt32KeyNode<HashBucket> root, IEqualityComparer<T> equalityComparer, int count) { Requires.NotNull(root, "root"); Requires.NotNull(equalityComparer, "equalityComparer"); Requires.Range(count >= 0, "count"); return new ImmutableHashSet<T>(root, equalityComparer, count); } private static IEqualityComparer<HashBucket> GetHashBucketEqualityComparer(IEqualityComparer<T> valueComparer) { if (!ImmutableExtensions.IsValueType<T>()) { return HashBucketByRefEqualityComparer.DefaultInstance; } if (valueComparer == EqualityComparer<T>.Default) { return HashBucketByValueEqualityComparer.DefaultInstance; } return new HashBucketByValueEqualityComparer(valueComparer); } private ImmutableHashSet<T> Wrap(SortedInt32KeyNode<HashBucket> root, int adjustedCountIfDifferentRoot) { if (root == _root) { return this; } return new ImmutableHashSet<T>(root, _equalityComparer, adjustedCountIfDifferentRoot); } private ImmutableHashSet<T> Union(IEnumerable<T> items, bool avoidWithComparer) { Requires.NotNull(items, "items"); if (IsEmpty && !avoidWithComparer && items is ImmutableHashSet<T> immutableHashSet) { return immutableHashSet.WithComparer(KeyComparer); } return Union(items, Origin).Finalize(this); } } internal interface IStrongEnumerable<out T, TEnumerator> where TEnumerator : struct, IStrongEnumerator<T> { TEnumerator GetEnumerator(); } internal interface IStrongEnumerator<T> { T Current { get; } bool MoveNext(); } internal interface IOrderedCollection<out T> : IEnumerable<T>, IEnumerable { int Count { get; } T this[int index] { get; } } public static class ImmutableArray { internal static readonly byte[] TwoElementArray = new byte[2]; public static ImmutableArray<T> Create<T>() { return ImmutableArray<T>.Empty; } public static ImmutableArray<T> Create<T>(T item) { T[] items = new T[1] { item }; return new ImmutableArray<T>(items); } public static ImmutableArray<T> Create<T>(T item1, T item2) { T[] items = new T[2] { item1, item2 }; return new ImmutableArray<T>(items); } public static ImmutableArray<T> Create<T>(T item1, T item2, T item3) { T[] items = new T[3] { item1, item2, item3 }; return new ImmutableArray<T>(items); } public static ImmutableArray<T> Create<T>(T item1, T item2, T item3, T item4) { T[] items = new T[4] { item1, item2, item3, item4 }; return new ImmutableArray<T>(items); } public static ImmutableArray<T> CreateRange<T>(IEnumerable<T> items) { Requires.NotNull(items, "items"); if (items is IImmutableArray immutableArray) { Array array = immutableArray.Array; if (array == null) { throw new InvalidOperationException(System.SR.InvalidOperationOnDefaultArray); } return new ImmutableArray<T>((T[])array); } if (items.TryGetCount(out var count)) { return new ImmutableArray<T>(items.ToArray(count)); } return new ImmutableArray<T>(items.ToArray()); } public static ImmutableArray<T> Create<T>(params T[] items) { if (items == null) { return Create<T>(); } return CreateDefensiveCopy(items); } public static ImmutableArray<T> Create<T>(T[] items, int start, int length) { Requires.NotNull(items, "items"); Requires.Range(start >= 0 && start <= items.Length, "start"); Requires.Range(length >= 0 && start + length <= items.Length, "length"); if (length == 0) { return Create<T>(); } T[] array = new T[length]; for (int i = 0; i < array.Length; i++) { array[i] = items[start + i]; } return new ImmutableArray<T>(array); } public static ImmutableArray<T> Create<T>(ImmutableArray<T> items, int start, int length) { Requires.Range(start >= 0 && start <= items.Length, "start"); Requires.Range(length >= 0 && start + length <= items.Length, "length"); if (length == 0) { return Create<T>(); } if (start == 0 && length == items.Length) { return items; } T[] array = new T[length]; Array.Copy(items.array, start, array, 0, length); return new ImmutableArray<T>(array); } public static ImmutableArray<TResult> CreateRange<TSource, TResult>(ImmutableArray<TSource> items, Func<TSource, TResult> selector) { Requires.NotNull(selector, "selector"); int length = items.Length; if (length == 0) { return Create<TResult>(); } TResult[] array = new TResult[length]; for (int i = 0; i < array.Length; i++) { array[i] = selector(items[i]); } return new ImmutableArray<TResult>(array); } public static ImmutableArray<TResult> CreateRange<TSource, TResult>(ImmutableArray<TSource> items, int start, int length, Func<TSource, TResult> selector) { int length2 = items.Length; Requires.Range(start >= 0 && start <= length2, "start"); Requires.Range(length >= 0 && start + length <= length2, "length"); Requires.NotNull(selector, "selector"); if (length == 0) { return Create<TResult>(); } TResult[] array = new TResult[length]; for (int i = 0; i < array.Length; i++) { array[i] = selector(items[i + start]); } return new ImmutableArray<TResult>(array); } public static ImmutableArray<TResult> CreateRange<TSource, TArg, TResult>(ImmutableArray<TSource> items, Func<TSource, TArg, TResult> selector, TArg arg) { Requires.NotNull(selector, "selector"); int length = items.Length; if (length == 0) { return Create<TResult>(); } TResult[] array = new TResult[length]; for (int i = 0; i < array.Length; i++) { array[i] = selector(items[i], arg); } return new ImmutableArray<TResult>(array); } public static ImmutableArray<TResult> CreateRange<TSource, TArg, TResult>(ImmutableArray<TSource> items, int start, int length, Func<TSource, TArg, TResult> selector, TArg arg) { int length2 = items.Length; Requires.Range(start >= 0 && start <= length2, "start"); Requires.Range(length >= 0 && start + length <= length2, "length"); Requires.NotNull(selector, "selector"); if (length == 0) { return Create<TResult>(); } TResult[] array = new TResult[length]; for (int i = 0; i < array.Length; i++) { array[i] = selector(items[i + start], arg); } return new ImmutableArray<TResult>(array); } public static ImmutableArray<T>.Builder CreateBuilder<T>() { return Create<T>().ToBuilder(); } public static ImmutableArray<T>.Builder CreateBuilder<T>(int initialCapacity) { return new ImmutableArray<T>.Builder(initialCapacity); } public static ImmutableArray<TSource> ToImmutableArray<TSource>(this IEnumerable<TSource> items) { if (items is ImmutableArray<TSource>) { return (ImmutableArray<TSource>)(object)items; } return CreateRange(items); } public static ImmutableArray<TSource> ToImmutableArray<TSource>(this ImmutableArray<TSource>.Builder builder) { Requires.NotNull(builder, "builder"); return builder.ToImmutable(); } public static int BinarySearch<T>(this ImmutableArray<T> array, T value) { return Array.BinarySearch(array.array, value); } public static int BinarySearch<T>(this ImmutableArray<T> array, T value, IComparer<T> comparer) { return Array.BinarySearch(array.array, value, comparer); } public static int BinarySearch<T>(this ImmutableArray<T> array, int index, int length, T value) { return Array.BinarySearch(array.array, index, length, value); } public static int BinarySearch<T>(this ImmutableArray<T> array, int index, int length, T value, IComparer<T> comparer) { return Array.BinarySearch(array.array, index, length, value, comparer); } internal static ImmutableArray<T> CreateDefensiveCopy<T>(T[] items) { if (items.Length == 0) { return ImmutableArray<T>.Empty; } T[] array = new T[items.Length]; Array.Copy(items, 0, array, 0, items.Length); return new ImmutableArray<T>(array); } } [DebuggerDisplay("{DebuggerDisplay,nq}")] [System.Runtime.Versioning.NonVersionable] public struct ImmutableArray<T> : IReadOnlyList<T>, IEnumerable<T>, IEnumerable, IReadOnlyCollection<T>, IList<T>, ICollection<T>, IEquatable<ImmutableArray<T>>, IList, ICollection, IImmutableArray, IStructuralComparable, IStructuralEquatable, IImmutableList<T> { [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableArrayBuilderDebuggerProxy<>))] public sealed class Builder : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IReadOnlyList<T>, IReadOnlyCollection<T> { private T[] _elements; private int _count; public int Capacity { get { return _elements.Length; } set { if (value < _count) { throw new ArgumentException(System.SR.CapacityMustBeGreaterThanOrEqualToCount, "value"); } if (value == _elements.Length) { return; } if (value > 0) { T[] array = new T[value]; if (_count > 0) { Array.Copy(_elements, 0, array, 0, _count); } _elements = array; } else { _elements = ImmutableArray<T>.Empty.array; } } } public int Count { get { return _count; } set { Requires.Range(value >= 0, "value"); if (value < _count) { if (_count - value > 64) { Array.Clear(_elements, value, _count - value); } else { for (int i = value; i < Count; i++) { _elements[i] = default(T); } } } else if (value > _count) { EnsureCapacity(value); } _count = value; } } public T this[int index] { get { if (index >= Count) { ThrowIndexOutOfRangeException(); } return _elements[index]; } set { if (index >= Count) { ThrowIndexOutOfRangeException(); } _elements[index] = value; } } bool ICollection<T>.IsReadOnly => false; internal Builder(int capacity) { Requires.Range(capacity >= 0, "capacity"); _elements = new T[capacity]; _count = 0; } internal Builder() : this(8) { } private static void ThrowIndexOutOfRangeException() { throw new IndexOutOfRangeException(); } public ref readonly T ItemRef(int index) { if (index >= Count) { ThrowIndexOutOfRangeException(); } return ref _elements[index]; } public ImmutableArray<T> ToImmutable() { return new ImmutableArray<T>(ToArray()); } public ImmutableArray<T> MoveToImmutable() { if (Capacity != Count) { throw new InvalidOperationException(System.SR.CapacityMustEqualCountOnMove); } T[] elements = _elements; _elements = ImmutableArray<T>.Empty.array; _count = 0; return new ImmutableArray<T>(elements); } public void Clear() { Count = 0; } public void Insert(int index, T item) { Requires.Range(index >= 0 && index <= Count, "index"); EnsureCapacity(Count + 1); if (index < Count) { Array.Copy(_elements, index, _elements, index + 1, Count - index); } _count++; _elements[index] = item; } public void Add(T item) { int num = _count + 1; EnsureCapacity(num); _elements[_count] = item; _count = num; } public void AddRange(IEnumerable<T> items) { Requires.NotNull(items, "items"); if (items.TryGetCount(out var count)) { EnsureCapacity(Count + count); if (items.TryCopyTo(_elements, _count)) { _count += count; return; } } foreach (T item in items) { Add(item); } } public void AddRange(params T[] items) { Requires.NotNull(items, "items"); int count = Count; Count += items.Length; Array.Copy(items, 0, _elements, count, items.Length); } public void AddRange<TDerived>(TDerived[] items) where TDerived : T { Requires.NotNull(items, "items"); int count = Count; Count += items.Length; Array.Copy(items, 0, _elements, count, items.Length); } public void AddRange(T[] items, int length) { Requires.NotNull(items, "items"); Requires.Range(length >= 0 && length <= items.Length, "length"); int count = Count; Count += length; Array.Copy(items, 0, _elements, count, length); } public void AddRange(ImmutableArray<T> items) { AddRange(items, items.Length); } public void AddRange(ImmutableArray<T> items, int length) { Requires.Range(length >= 0, "length"); if (items.array != null) { AddRange(items.array, length); } } public void AddRange<TDerived>(ImmutableArray<TDerived> items) where TDerived : T { if (items.array != null) { AddRange(items.array); } } public void AddRange(Builder items) { Requires.NotNull(items, "items"); AddRange(items._elements, items.Count); } public void AddRange<TDerived>(ImmutableArray<TDerived>.Builder items) where TDerived : T { Requires.NotNull(items, "items"); AddRange(items._elements, items.Count); } public bool Remove(T element) { int num = IndexOf(element); if (num >= 0) { RemoveAt(num); return true; } return false; } public void RemoveAt(int index) { Requires.Range(index >= 0 && index < Count, "index"); if (index < Count - 1) { Array.Copy(_elements, index + 1, _elements, index, Count - index - 1); } Count--; } public bool Contains(T item) { return IndexOf(item) >= 0; } public T[] ToArray() { if (Count == 0) { return ImmutableArray<T>.Empty.array; } T[] array = new T[Count]; Array.Copy(_elements, 0, array, 0, Count); return array; } public void CopyTo(T[] array, int index) { Requires.NotNull(array, "array"); Requires.Range(index >= 0 && index + Count <= array.Length, "index"); Array.Copy(_elements, 0, array, index, Count); } private void EnsureCapacity(int capacity) { if (_elements.Length < capacity) { int newSize = Math.Max(_elements.Length * 2, capacity); Array.Resize(ref _elements, newSize); } } public int IndexOf(T item) { return IndexOf(item, 0, _count, EqualityComparer<T>.Default); } public int IndexOf(T item, int startIndex) { return IndexOf(item, startIndex, Count - startIndex, EqualityComparer<T>.Default); } public int IndexOf(T item, int startIndex, int count) { return IndexOf(item, startIndex, count, EqualityComparer<T>.Default); } public int IndexOf(T item, int startIndex, int count, IEqualityComparer<T> equalityComparer) { if (count == 0 && startIndex == 0) { return -1; } Requires.Range(startIndex >= 0 && startIndex < Count, "startIndex"); Requires.Range(count >= 0 && startIndex + count <= Count, "count"); equalityComparer = equalityComparer ?? EqualityComparer<T>.Default; if (equalityComparer == EqualityComparer<T>.Default) { return Array.IndexOf(_elements, item, startIndex, count); } for (int i = startIndex; i < startIndex + count; i++) { if (equalityComparer.Equals(_elements[i], item)) { return i; } } return -1; } public int LastIndexOf(T item) { if (Count == 0) { return -1; } return LastIndexOf(item, Count - 1, Count, EqualityComparer<T>.Default); } public int LastIndexOf(T item, int startIndex) { if (Count == 0 && startIndex == 0) { return -1; } Requires.Range(startIndex >= 0 && startIndex < Count, "startIndex"); return LastIndexOf(item, startIndex, startIndex + 1, EqualityComparer<T>.Default); } public int LastIndexOf(T item, int startIndex, int count) { return LastIndexOf(item, startIndex, count, EqualityComparer<T>.Default); } public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer<T> equalityComparer) { if (count == 0 && startIndex == 0) { return -1; } Requires.Range(startIndex >= 0 && startIndex < Count, "startIndex"); Requires.Range(count >= 0 && startIndex - count + 1 >= 0, "count"); equalityComparer = equalityComparer ?? EqualityComparer<T>.Default; if (equalityComparer == EqualityComparer<T>.Default) { return Array.LastIndexOf(_elements, item, startIndex, count); } for (int num = startIndex; num >= startIndex - count + 1; num--) { if (equalityComparer.Equals(item, _elements[num])) { return num; } } return -1; } public void Reverse() { int num = 0; int num2 = _count - 1; T[] elements = _elements; while (num < num2) { T val = elements[num]; elements[num] = elements[num2]; elements[num2] = val; num++; num2--; } } public void Sort() { if (Count > 1) { Array.Sort(_elements, 0, Count, Comparer<T>.Default); } } public void Sort(Comparison<T> comparison) { Requires.NotNull(comparison, "comparison"); if (Count > 1) { Array.Sort(_elements, 0, _count, Comparer<T>.Create(comparison)); } } public void Sort(IComparer<T> comparer) { if (Count > 1) { Array.Sort(_elements, 0, _count, comparer); } } public void Sort(int index, int count, IComparer<T> comparer) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0 && index + count <= Count, "count"); if (count > 1) { Array.Sort(_elements, index, count, comparer); } } public IEnumerator<T> GetEnumerator() { for (int i = 0; i < Count; i++) { yield return this[i]; } } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private void AddRange<TDerived>(TDerived[] items, int length) where TDerived : T { EnsureCapacity(Count + length); int count = Count; Count += length; T[] elements = _elements; for (int i = 0; i < length; i++) { elements[count + i] = (T)(object)items[i]; } } } public struct Enumerator { private readonly T[] _array; private int _index; public T Current => _array[_index]; internal Enumerator(T[] array) { _array = array; _index = -1; } public bool MoveNext() { return ++_index < _array.Length; } } private class EnumeratorObject : IEnumerator<T>, IEnumerator, IDisposable { private static readonly IEnumerator<T> s_EmptyEnumerator = new EnumeratorObject(ImmutableArray<T>.Empty.array); private readonly T[] _array; private int _index; public T Current { get { if ((uint)_index < (uint)_array.Length) { return _array[_index]; } throw new InvalidOperationException(); } } object IEnumerator.Current => Current; private EnumeratorObject(T[] array) { _index = -1; _array = array; } public bool MoveNext() { int num = _index + 1; int num2 = _array.Length; if ((uint)num <= (uint)num2) { _index = num; return (uint)num < (uint)num2; } return false; } void IEnumerator.Reset() { _index = -1; } public void Dispose() { } internal static IEnumerator<T> Create(T[] array) { if (array.Length != 0) { return new EnumeratorObject(array); } return s_EmptyEnumerator; } } public static readonly ImmutableArray<T> Empty = new ImmutableArray<T>(new T[0]); [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] internal T[] array; T IList<T>.this[int index] { get { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray[index]; } set { throw new NotSupportedException(); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection<T>.IsReadOnly => true; [DebuggerBrowsable(DebuggerBrowsableState.Never)] int ICollection<T>.Count { get { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Length; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] int IReadOnlyCollection<T>.Count { get { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Length; } } T IReadOnlyList<T>.this[int index] { get { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray[index]; } } [ExcludeFromCodeCoverage] [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool IList.IsFixedSize => true; [ExcludeFromCodeCoverage] [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool IList.IsReadOnly => true; [ExcludeFromCodeCoverage] [DebuggerBrowsable(DebuggerBrowsableState.Never)] int ICollection.Count { get { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Length; } } [ExcludeFromCodeCoverage] [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => true; [ExcludeFromCodeCoverage] [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot { get { throw new NotSupportedException(); } } [ExcludeFromCodeCoverage] object IList.this[int index] { get { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray[index]; } set { throw new NotSupportedException(); } } public T this[int index] { [System.Runtime.Versioning.NonVersionable] get { return array[index]; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public bool IsEmpty { [System.Runtime.Versioning.NonVersionable] get { return Length == 0; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public int Length { [System.Runtime.Versioning.NonVersionable] get { return array.Length; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public bool IsDefault => array == null; [DebuggerBrowsable(DebuggerBrowsableState.Never)] public bool IsDefaultOrEmpty { get { ImmutableArray<T> immutableArray = this; if (immutableArray.array != null) { return immutableArray.array.Length == 0; } return true; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] Array IImmutableArray.Array => array; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string DebuggerDisplay { get { ImmutableArray<T> immutableArray = this; if (!immutableArray.IsDefault) { return string.Format(CultureInfo.CurrentCulture, "Length = {0}", immutableArray.Length); } return "Uninitialized"; } } public ReadOnlySpan<T> AsSpan() { return new ReadOnlySpan<T>(array); } public ReadOnlyMemory<T> AsMemory() { return new ReadOnlyMemory<T>(array); } public int IndexOf(T item) { ImmutableArray<T> immutableArray = this; return immutableArray.IndexOf(item, 0, immutableArray.Length, EqualityComparer<T>.Default); } public int IndexOf(T item, int startIndex, IEqualityComparer<T> equalityComparer) { ImmutableArray<T> immutableArray = this; return immutableArray.IndexOf(item, startIndex, immutableArray.Length - startIndex, equalityComparer); } public int IndexOf(T item, int startIndex) { ImmutableArray<T> immutableArray = this; return immutableArray.IndexOf(item, startIndex, immutableArray.Length - startIndex, EqualityComparer<T>.Default); } public int IndexOf(T item, int startIndex, int count) { return IndexOf(item, startIndex, count, EqualityComparer<T>.Default); } public int IndexOf(T item, int startIndex, int count, IEqualityComparer<T> equalityComparer) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); if (count == 0 && startIndex == 0) { return -1; } Requires.Range(startIndex >= 0 && startIndex < immutableArray.Length, "startIndex"); Requires.Range(count >= 0 && startIndex + count <= immutableArray.Length, "count"); equalityComparer = equalityComparer ?? EqualityComparer<T>.Default; if (equalityComparer == EqualityComparer<T>.Default) { return Array.IndexOf(immutableArray.array, item, startIndex, count); } for (int i = startIndex; i < startIndex + count; i++) { if (equalityComparer.Equals(immutableArray.array[i], item)) { return i; } } return -1; } public int LastIndexOf(T item) { ImmutableArray<T> immutableArray = this; if (immutableArray.Length == 0) { return -1; } return immutableArray.LastIndexOf(item, immutableArray.Length - 1, immutableArray.Length, EqualityComparer<T>.Default); } public int LastIndexOf(T item, int startIndex) { ImmutableArray<T> immutableArray = this; if (immutableArray.Length == 0 && startIndex == 0) { return -1; } return immutableArray.LastIndexOf(item, startIndex, startIndex + 1, EqualityComparer<T>.Default); } public int LastIndexOf(T item, int startIndex, int count) { return LastIndexOf(item, startIndex, count, EqualityComparer<T>.Default); } public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer<T> equalityComparer) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); if (startIndex == 0 && count == 0) { return -1; } Requires.Range(startIndex >= 0 && startIndex < immutableArray.Length, "startIndex"); Requires.Range(count >= 0 && startIndex - count + 1 >= 0, "count"); equalityComparer = equalityComparer ?? EqualityComparer<T>.Default; if (equalityComparer == EqualityComparer<T>.Default) { return Array.LastIndexOf(immutableArray.array, item, startIndex, count); } for (int num = startIndex; num >= startIndex - count + 1; num--) { if (equalityComparer.Equals(item, immutableArray.array[num])) { return num; } } return -1; } public bool Contains(T item) { return IndexOf(item) >= 0; } public ImmutableArray<T> Insert(int index, T item) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index <= immutableArray.Length, "index"); if (immutableArray.Length == 0) { return ImmutableArray.Create(item); } T[] array = new T[immutableArray.Length + 1]; array[index] = item; if (index != 0) { Array.Copy(immutableArray.array, 0, array, 0, index); } if (index != immutableArray.Length) { Array.Copy(immutableArray.array, index, array, index + 1, immutableArray.Length - index); } return new ImmutableArray<T>(array); } public ImmutableArray<T> InsertRange(int index, IEnumerable<T> items) { ImmutableArray<T> result = this; result.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index <= result.Length, "index"); Requires.NotNull(items, "items"); if (result.Length == 0) { return ImmutableArray.CreateRange(items); } int count = ImmutableExtensions.GetCount(ref items); if (count == 0) { return result; } T[] array = new T[result.Length + count]; if (index != 0) { Array.Copy(result.array, 0, array, 0, index); } if (index != result.Length) { Array.Copy(result.array, index, array, index + count, result.Length - index); } if (!items.TryCopyTo(array, index)) { int num = index; foreach (T item in items) { array[num++] = item; } } return new ImmutableArray<T>(array); } public ImmutableArray<T> InsertRange(int index, ImmutableArray<T> items) { ImmutableArray<T> result = this; result.ThrowNullRefIfNotInitialized(); items.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index <= result.Length, "index"); if (result.IsEmpty) { return items; } if (items.IsEmpty) { return result; } T[] array = new T[result.Length + items.Length]; if (index != 0) { Array.Copy(result.array, 0, array, 0, index); } if (index != result.Length) { Array.Copy(result.array, index, array, index + items.Length, result.Length - index); } Array.Copy(items.array, 0, array, index, items.Length); return new ImmutableArray<T>(array); } public ImmutableArray<T> Add(T item) { ImmutableArray<T> immutableArray = this; if (immutableArray.Length == 0) { return ImmutableArray.Create(item); } return immutableArray.Insert(immutableArray.Length, item); } public ImmutableArray<T> AddRange(IEnumerable<T> items) { ImmutableArray<T> immutableArray = this; return immutableArray.InsertRange(immutableArray.Length, items); } public ImmutableArray<T> AddRange(ImmutableArray<T> items) { ImmutableArray<T> immutableArray = this; return immutableArray.InsertRange(immutableArray.Length, items); } public ImmutableArray<T> SetItem(int index, T item) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index < immutableArray.Length, "index"); T[] array = new T[immutableArray.Length]; Array.Copy(immutableArray.array, 0, array, 0, immutableArray.Length); array[index] = item; return new ImmutableArray<T>(array); } public ImmutableArray<T> Replace(T oldValue, T newValue) { return Replace(oldValue, newValue, EqualityComparer<T>.Default); } public ImmutableArray<T> Replace(T oldValue, T newValue, IEqualityComparer<T> equalityComparer) { ImmutableArray<T> immutableArray = this; int num = immutableArray.IndexOf(oldValue, 0, immutableArray.Length, equalityComparer); if (num < 0) { throw new ArgumentException(System.SR.CannotFindOldValue, "oldValue"); } return immutableArray.SetItem(num, newValue); } public ImmutableArray<T> Remove(T item) { return Remove(item, EqualityComparer<T>.Default); } public ImmutableArray<T> Remove(T item, IEqualityComparer<T> equalityComparer) { ImmutableArray<T> result = this; result.ThrowNullRefIfNotInitialized(); int num = result.IndexOf(item, 0, result.Length, equalityComparer); if (num >= 0) { return result.RemoveAt(num); } return result; } public ImmutableArray<T> RemoveAt(int index) { return RemoveRange(index, 1); } public ImmutableArray<T> RemoveRange(int index, int length) { ImmutableArray<T> result = this; result.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index <= result.Length, "index"); Requires.Range(length >= 0 && index + length <= result.Length, "length"); if (length == 0) { return result; } T[] array = new T[result.Length - length]; Array.Copy(result.array, 0, array, 0, index); Array.Copy(result.array, index + length, array, index, result.Length - index - length); return new ImmutableArray<T>(array); } public ImmutableArray<T> RemoveRange(IEnumerable<T> items) { return RemoveRange(items, EqualityComparer<T>.Default); } public ImmutableArray<T> RemoveRange(IEnumerable<T> items, IEqualityComparer<T> equalityComparer) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Requires.NotNull(items, "items"); SortedSet<int> sortedSet = new SortedSet<int>(); foreach (T item in items) { int num = immutableArray.IndexOf(item, 0, immutableArray.Length, equalityComparer); while (num >= 0 && !sortedSet.Add(num) && num + 1 < immutableArray.Length) { num = immutableArray.IndexOf(item, num + 1, equalityComparer); } } return immutableArray.RemoveAtRange(sortedSet); } public ImmutableArray<T> RemoveRange(ImmutableArray<T> items) { return RemoveRange(items, EqualityComparer<T>.Default); } public ImmutableArray<T> RemoveRange(ImmutableArray<T> items, IEqualityComparer<T> equalityComparer) { ImmutableArray<T> result = this; Requires.NotNull(items.array, "items"); if (items.IsEmpty) { result.ThrowNullRefIfNotInitialized(); return result; } if (items.Length == 1) { return result.Remove(items[0], equalityComparer); } return result.RemoveRange(items.array, equalityComparer); } public ImmutableArray<T> RemoveAll(Predicate<T> match) { ImmutableArray<T> result = this; result.ThrowNullRefIfNotInitialized(); Requires.NotNull(match, "match"); if (result.IsEmpty) { return result; } List<int> list = null; for (int i = 0; i < result.array.Length; i++) { if (match(result.array[i])) { if (list == null) { list = new List<int>(); } list.Add(i); } } if (list == null) { return result; } return result.RemoveAtRange(list); } public ImmutableArray<T> Clear() { return Empty; } public ImmutableArray<T> Sort() { ImmutableArray<T> immutableArray = this; return immutableArray.Sort(0, immutableArray.Length, Comparer<T>.Default); } public ImmutableArray<T> Sort(Comparison<T> comparison) { Requires.NotNull(comparison, "comparison"); ImmutableArray<T> immutableArray = this; return immutableArray.Sort(Comparer<T>.Create(comparison)); } public ImmutableArray<T> Sort(IComparer<T> comparer) { ImmutableArray<T> immutableArray = this; return immutableArray.Sort(0, immutableArray.Length, comparer); } public ImmutableArray<T> Sort(int index, int count, IComparer<T> comparer) { ImmutableArray<T> result = this; result.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0, "index"); Requires.Range(count >= 0 && index + count <= result.Length, "count"); if (count > 1) { if (comparer == null) { comparer = Comparer<T>.Default; } bool flag = false; for (int i = index + 1; i < index + count; i++) { if (comparer.Compare(result.array[i - 1], result.array[i]) > 0) { flag = true; break; } } if (flag) { T[] array = new T[result.Length]; Array.Copy(result.array, 0, array, 0, result.Length); Array.Sort(array, index, count, comparer); return new ImmutableArray<T>(array); } } return result; } public IEnumerable<TResult> OfType<TResult>() { ImmutableArray<T> immutableArray = this; if (immutableArray.array == null || immutableArray.array.Length == 0) { return Enumerable.Empty<TResult>(); } return immutableArray.array.OfType<TResult>(); } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } [ExcludeFromCodeCoverage] IImmutableList<T> IImmutableList<T>.Clear() { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Clear(); } [ExcludeFromCodeCoverage] IImmutableList<T> IImmutableList<T>.Add(T value) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Add(value); } [ExcludeFromCodeCoverage] IImmutableList<T> IImmutableList<T>.AddRange(IEnumerable<T> items) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.AddRange(items); } [ExcludeFromCodeCoverage] IImmutableList<T> IImmutableList<T>.Insert(int index, T element) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Insert(index, element); } [ExcludeFromCodeCoverage] IImmutableList<T> IImmutableList<T>.InsertRange(int index, IEnumerable<T> items) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.InsertRange(index, items); } [ExcludeFromCodeCoverage] IImmutableList<T> IImmutableList<T>.Remove(T value, IEqualityComparer<T> equalityComparer) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Remove(value, equalityComparer); } [ExcludeFromCodeCoverage] IImmutableList<T> IImmutableList<T>.RemoveAll(Predicate<T> match) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.RemoveAll(match); } [ExcludeFromCodeCoverage] IImmutableList<T> IImmutableList<T>.RemoveRange(IEnumerable<T> items, IEqualityComparer<T> equalityComparer) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.RemoveRange(items, equalityComparer); } [ExcludeFromCodeCoverage] IImmutableList<T> IImmutableList<T>.RemoveRange(int index, int count) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.RemoveRange(index, count); } [ExcludeFromCodeCoverage] IImmutableList<T> IImmutableList<T>.RemoveAt(int index) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.RemoveAt(index); } [ExcludeFromCodeCoverage] IImmutableList<T> IImmutableList<T>.SetItem(int index, T value) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.SetItem(index, value); } IImmutableList<T> IImmutableList<T>.Replace(T oldValue, T newValue, IEqualityComparer<T> equalityComparer) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Replace(oldValue, newValue, equalityComparer); } [ExcludeFromCodeCoverage] int IList.Add(object value) { throw new NotSupportedException(); } [ExcludeFromCodeCoverage] void IList.Clear() { throw new NotSupportedException(); } [ExcludeFromCodeCoverage] bool IList.Contains(object value) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Contains((T)value); } [ExcludeFromCodeCoverage] int IList.IndexOf(object value) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.IndexOf((T)value); } [ExcludeFromCodeCoverage] void IList.Insert(int index, object value) { throw new NotSupportedException(); } [ExcludeFromCodeCoverage] void IList.Remove(object value) { throw new NotSupportedException(); } [ExcludeFromCodeCoverage] void IList.RemoveAt(int index) { throw new NotSupportedException(); } [ExcludeFromCodeCoverage] void ICollection.CopyTo(Array array, int index) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); Array.Copy(immutableArray.array, 0, array, index, immutableArray.Length); } bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { ImmutableArray<T> immutableArray = this; Array array = other as Array; if (array == null && other is IImmutableArray immutableArray2) { array = immutableArray2.Array; if (immutableArray.array == null && array == null) { return true; } if (immutableArray.array == null) { return false; } } IStructuralEquatable structuralEquatable = immutableArray.array; return structuralEquatable.Equals(array, comparer); } int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { ImmutableArray<T> immutableArray = this; return ((IStructuralEquatable)immutableArray.array)?.GetHashCode(comparer) ?? immutableArray.GetHashCode(); } int IStructuralComparable.CompareTo(object other, IComparer comparer) { ImmutableArray<T> immutableArray = this; Array array = other as Array; if (array == null && other is IImmutableArray immutableArray2) { array = immutableArray2.Array; if (immutableArray.array == null && array == null) { return 0; } if ((immutableArray.array == null) ^ (array == null)) { throw new ArgumentException(System.SR.ArrayInitializedStateNotEqual, "other"); } } if (array != null) { IStructuralComparable structuralComparable = immutableArray.array; return structuralComparable.CompareTo(array, comparer); } throw new ArgumentException(System.SR.ArrayLengthsNotEqual, "other"); } private ImmutableArray<T> RemoveAtRange(ICollection<int> indicesToRemove) { ImmutableArray<T> result = this; result.ThrowNullRefIfNotInitialized(); Requires.NotNull(indicesToRemove, "indicesToRemove"); if (indicesToRemove.Count == 0) { return result; } T[] array = new T[result.Length - indicesToRemove.Count]; int num = 0; int num2 = 0; int num3 = -1; foreach (int item in indicesToRemove) { int num4 = ((num3 == -1) ? item : (item - num3 - 1)); Array.Copy(result.array, num + num2, array, num, num4); num2++; num += num4; num3 = item; } Array.Copy(result.array, num + num2, array, num, result.Length - (num + num2)); return new ImmutableArray<T>(array); } internal ImmutableArray(T[] items) { array = items; } [System.Runtime.Versioning.NonVersionable] public static bool operator ==(ImmutableArray<T> left, ImmutableArray<T> right) { return left.Equals(right); } [System.Runtime.Versioning.NonVersionable] public static bool operator !=(ImmutableArray<T> left, ImmutableArray<T> right) { return !left.Equals(right); } public static bool operator ==(ImmutableArray<T>? left, ImmutableArray<T>? right) { return left.GetValueOrDefault().Equals(right.GetValueOrDefault()); } public static bool operator !=(ImmutableArray<T>? left, ImmutableArray<T>? right) { return !left.GetValueOrDefault().Equals(right.GetValueOrDefault()); } public ref readonly T ItemRef(int index) { return ref array[index]; } public void CopyTo(T[] destination) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Array.Copy(immutableArray.array, 0, destination, 0, immutableArray.Length); } public void CopyTo(T[] destination, int destinationIndex) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Array.Copy(immutableArray.array, 0, destination, destinationIndex, immutableArray.Length); } public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int length) { ImmutableArray<T> immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Array.Copy(immutableArray.array, sourceIndex, destination, destinationIndex, length); } public Builder ToBuilder() { ImmutableArray<T> items = this; if (items.Length == 0) { return new Builder(); } Builder builder = new Builder(items.Length); builder.AddRange(items); return builder; } p
0Harmony.dll
Decompiled a year ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using HarmonyLib.Internal.Patching; using HarmonyLib.Internal.RuntimeFixes; using HarmonyLib.Internal.Util; using HarmonyLib.Public.Patching; using HarmonyLib.Tools; using JetBrains.Annotations; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; using MonoMod.Cil; using MonoMod.RuntimeDetour; using MonoMod.Utils; using MonoMod.Utils.Cil; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: ComVisible(false)] [assembly: InternalsVisibleTo("HarmonyTests")] [assembly: InternalsVisibleTo("MonoMod.Utils.Cil.ILGeneratorProxy")] [assembly: Guid("69aee16a-b6e7-4642-8081-3928b32455df")] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("BepInEx")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © BepInEx 2022")] [assembly: AssemblyDescription("A library for patching, replacing and decorating .NET and Mono methods during runtime powered by MonoMod.")] [assembly: AssemblyFileVersion("2.10.2.0")] [assembly: AssemblyInformationalVersion("2.10.2")] [assembly: AssemblyProduct("HarmonyX")] [assembly: AssemblyTitle("0Harmony")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.10.2.0")] [module: UnverifiableCode] namespace JetBrains.Annotations { [AttributeUsage(AttributeTargets.All)] internal sealed class UsedImplicitlyAttribute : Attribute { public ImplicitUseKindFlags UseKindFlags { get; } public ImplicitUseTargetFlags TargetFlags { get; } public UsedImplicitlyAttribute() : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) : this(useKindFlags, ImplicitUseTargetFlags.Default) { } public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) : this(ImplicitUseKindFlags.Default, targetFlags) { } public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) { UseKindFlags = useKindFlags; TargetFlags = targetFlags; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter | AttributeTargets.GenericParameter)] internal sealed class MeansImplicitUseAttribute : Attribute { [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; } [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; } public MeansImplicitUseAttribute() : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) : this(useKindFlags, ImplicitUseTargetFlags.Default) { } public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) : this(ImplicitUseKindFlags.Default, targetFlags) { } public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) { UseKindFlags = useKindFlags; TargetFlags = targetFlags; } } [Flags] internal enum ImplicitUseKindFlags { Default = 7, Access = 1, Assign = 2, InstantiatedWithFixedConstructorSignature = 4, InstantiatedNoFixedConstructorSignature = 8 } [Flags] internal enum ImplicitUseTargetFlags { Default = 1, Itself = 1, Members = 2, WithInheritors = 4, WithMembers = 3 } } namespace HarmonyLib { public class DelegateTypeFactory { private class DelegateEntry { public CallingConvention? callingConvention; public Type delegateType; } private static int counter; private static readonly Dictionary<MethodInfo, List<DelegateEntry>> TypeCache = new Dictionary<MethodInfo, List<DelegateEntry>>(); private static readonly MethodBase CallingConvAttr = AccessTools.Constructor(typeof(UnmanagedFunctionPointerAttribute), new Type[1] { typeof(CallingConvention) }); public static readonly DelegateTypeFactory instance = new DelegateTypeFactory(); public Type CreateDelegateType(Type returnType, Type[] argTypes) { return CreateDelegateType(returnType, argTypes, null); } public Type CreateDelegateType(Type returnType, Type[] argTypes, CallingConvention? convention) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Expected O, but got Unknown //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) counter++; AssemblyDefinition val = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition($"HarmonyDTFAssembly{counter}", new Version(1, 0)), $"HarmonyDTFModule{counter}", (ModuleKind)0); ModuleDefinition module = val.MainModule; TypeDefinition val2 = new TypeDefinition("", $"HarmonyDTFType{counter}", (TypeAttributes)257) { BaseType = module.ImportReference(typeof(MulticastDelegate)) }; module.Types.Add(val2); if (convention.HasValue) { CustomAttribute val3 = new CustomAttribute(module.ImportReference(CallingConvAttr)); val3.ConstructorArguments.Add(new CustomAttributeArgument(module.ImportReference(typeof(CallingConvention)), (object)convention.Value)); val2.CustomAttributes.Add(val3); } MethodDefinition val4 = new MethodDefinition(".ctor", (MethodAttributes)4230, module.ImportReference(typeof(void))) { ImplAttributes = (MethodImplAttributes)3 }; Extensions.AddRange<ParameterDefinition>(((MethodReference)val4).Parameters, (IEnumerable<ParameterDefinition>)(object)new ParameterDefinition[2] { new ParameterDefinition(module.ImportReference(typeof(object))), new ParameterDefinition(module.ImportReference(typeof(IntPtr))) }); val2.Methods.Add(val4); MethodDefinition val5 = new MethodDefinition("Invoke", (MethodAttributes)198, module.ImportReference(returnType)) { ImplAttributes = (MethodImplAttributes)3 }; Extensions.AddRange<ParameterDefinition>(((MethodReference)val5).Parameters, ((IEnumerable<Type>)argTypes).Select((Func<Type, ParameterDefinition>)((Type t) => new ParameterDefinition(module.ImportReference(t))))); val2.Methods.Add(val5); return ReflectionHelper.Load(val.MainModule).GetType($"HarmonyDTFType{counter}"); } public Type CreateDelegateType(MethodInfo method) { return CreateDelegateType(method, null); } public Type CreateDelegateType(MethodInfo method, CallingConvention? convention) { DelegateEntry delegateEntry; if (TypeCache.TryGetValue(method, out var value) && (delegateEntry = value.FirstOrDefault((DelegateEntry e) => e.callingConvention == convention)) != null) { return delegateEntry.delegateType; } if (value == null) { value = (TypeCache[method] = new List<DelegateEntry>()); } delegateEntry = new DelegateEntry { delegateType = CreateDelegateType(method.ReturnType, method.GetParameters().Types().ToArray(), convention), callingConvention = convention }; value.Add(delegateEntry); return delegateEntry.delegateType; } } [Obsolete("Use AccessTools.FieldRefAccess<T, S> for fields and AccessTools.MethodDelegate<Func<T, S>> for property getters")] public delegate S GetterHandler<in T, out S>(T source); [Obsolete("Use AccessTools.FieldRefAccess<T, S> for fields and AccessTools.MethodDelegate<Action<T, S>> for property setters")] public delegate void SetterHandler<in T, in S>(T source, S value); public delegate T InstantiationHandler<out T>(); public static class FastAccess { public static InstantiationHandler<T> CreateInstantiationHandler<T>() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) ConstructorInfo constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null); if ((object)constructor == null) { throw new ApplicationException($"The type {typeof(T)} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public)."); } DynamicMethodDefinition val = new DynamicMethodDefinition("InstantiateObject_" + typeof(T).Name, typeof(T), (Type[])null); ILGenerator iLGenerator = val.GetILGenerator(); iLGenerator.Emit(OpCodes.Newobj, constructor); iLGenerator.Emit(OpCodes.Ret); return (InstantiationHandler<T>)val.Generate().CreateDelegate(typeof(InstantiationHandler<T>)); } [Obsolete("Use AccessTools.MethodDelegate<Func<T, S>>(PropertyInfo.GetGetMethod(true))")] public static GetterHandler<T, S> CreateGetterHandler<T, S>(PropertyInfo propertyInfo) { MethodInfo getMethod = propertyInfo.GetGetMethod(nonPublic: true); DynamicMethodDefinition obj = CreateGetDynamicMethod<T, S>(propertyInfo.DeclaringType); ILGenerator iLGenerator = obj.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Call, getMethod); iLGenerator.Emit(OpCodes.Ret); return (GetterHandler<T, S>)obj.Generate().CreateDelegate(typeof(GetterHandler<T, S>)); } [Obsolete("Use AccessTools.FieldRefAccess<T, S>(fieldInfo)")] public static GetterHandler<T, S> CreateGetterHandler<T, S>(FieldInfo fieldInfo) { DynamicMethodDefinition obj = CreateGetDynamicMethod<T, S>(fieldInfo.DeclaringType); ILGenerator iLGenerator = obj.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, fieldInfo); iLGenerator.Emit(OpCodes.Ret); return (GetterHandler<T, S>)obj.Generate().CreateDelegate(typeof(GetterHandler<T, S>)); } [Obsolete("Use AccessTools.FieldRefAccess<T, S>(name) for fields and AccessTools.MethodDelegate<Func<T, S>>(AccessTools.PropertyGetter(typeof(T), name)) for properties")] public static GetterHandler<T, S> CreateFieldGetter<T, S>(params string[] names) { foreach (string name in names) { FieldInfo field = typeof(T).GetField(name, AccessTools.all); if ((object)field != null) { return CreateGetterHandler<T, S>(field); } PropertyInfo property = typeof(T).GetProperty(name, AccessTools.all); if ((object)property != null) { return CreateGetterHandler<T, S>(property); } } return null; } [Obsolete("Use AccessTools.MethodDelegate<Action<T, S>>(PropertyInfo.GetSetMethod(true))")] public static SetterHandler<T, S> CreateSetterHandler<T, S>(PropertyInfo propertyInfo) { MethodInfo setMethod = propertyInfo.GetSetMethod(nonPublic: true); DynamicMethodDefinition obj = CreateSetDynamicMethod<T, S>(propertyInfo.DeclaringType); ILGenerator iLGenerator = obj.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Call, setMethod); iLGenerator.Emit(OpCodes.Ret); return (SetterHandler<T, S>)obj.Generate().CreateDelegate(typeof(SetterHandler<T, S>)); } [Obsolete("Use AccessTools.FieldRefAccess<T, S>(fieldInfo)")] public static SetterHandler<T, S> CreateSetterHandler<T, S>(FieldInfo fieldInfo) { DynamicMethodDefinition obj = CreateSetDynamicMethod<T, S>(fieldInfo.DeclaringType); ILGenerator iLGenerator = obj.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Stfld, fieldInfo); iLGenerator.Emit(OpCodes.Ret); return (SetterHandler<T, S>)obj.Generate().CreateDelegate(typeof(SetterHandler<T, S>)); } private static DynamicMethodDefinition CreateGetDynamicMethod<T, S>(Type type) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown return new DynamicMethodDefinition("DynamicGet_" + type.Name, typeof(S), new Type[1] { typeof(T) }); } private static DynamicMethodDefinition CreateSetDynamicMethod<T, S>(Type type) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown return new DynamicMethodDefinition("DynamicSet_" + type.Name, typeof(void), new Type[2] { typeof(T), typeof(S) }); } } public delegate object FastInvokeHandler(object target, params object[] parameters); public static class MethodInvoker { public static FastInvokeHandler GetHandler(MethodInfo methodInfo, bool directBoxValueAccess = false) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown DynamicMethodDefinition val = new DynamicMethodDefinition("FastInvoke_" + methodInfo.Name + "_" + (directBoxValueAccess ? "direct" : "indirect"), typeof(object), new Type[2] { typeof(object), typeof(object[]) }); ILGenerator iLGenerator = val.GetILGenerator(); if (!methodInfo.IsStatic) { Emit(iLGenerator, OpCodes.Ldarg_0); EmitUnboxIfNeeded(iLGenerator, methodInfo.DeclaringType); } bool flag = true; ParameterInfo[] parameters = methodInfo.GetParameters(); for (int i = 0; i < parameters.Length; i++) { Type type = parameters[i].ParameterType; bool isByRef = type.IsByRef; if (isByRef) { type = type.GetElementType(); } bool isValueType = type.IsValueType; if (isByRef && isValueType && !directBoxValueAccess) { Emit(iLGenerator, OpCodes.Ldarg_1); EmitFastInt(iLGenerator, i); } Emit(iLGenerator, OpCodes.Ldarg_1); EmitFastInt(iLGenerator, i); if (isByRef && !isValueType) { Emit(iLGenerator, OpCodes.Ldelema, typeof(object)); continue; } Emit(iLGenerator, OpCodes.Ldelem_Ref); if (!isValueType) { continue; } if (!isByRef || !directBoxValueAccess) { Emit(iLGenerator, OpCodes.Unbox_Any, type); if (isByRef) { Emit(iLGenerator, OpCodes.Box, type); Emit(iLGenerator, OpCodes.Dup); if (flag) { flag = false; iLGenerator.DeclareLocal(typeof(object), pinned: false); } Emit(iLGenerator, OpCodes.Stloc_0); Emit(iLGenerator, OpCodes.Stelem_Ref); Emit(iLGenerator, OpCodes.Ldloc_0); Emit(iLGenerator, OpCodes.Unbox, type); } } else { Emit(iLGenerator, OpCodes.Unbox, type); } } if (methodInfo.IsStatic) { EmitCall(iLGenerator, OpCodes.Call, methodInfo); } else { EmitCall(iLGenerator, OpCodes.Callvirt, methodInfo); } if (methodInfo.ReturnType == typeof(void)) { Emit(iLGenerator, OpCodes.Ldnull); } else { EmitBoxIfNeeded(iLGenerator, methodInfo.ReturnType); } Emit(iLGenerator, OpCodes.Ret); return (FastInvokeHandler)val.Generate().CreateDelegate(typeof(FastInvokeHandler)); } internal static void Emit(ILGenerator il, OpCode opcode) { il.Emit(opcode); } internal static void Emit(ILGenerator il, OpCode opcode, Type type) { il.Emit(opcode, type); } internal static void EmitCall(ILGenerator il, OpCode opcode, MethodInfo methodInfo) { il.EmitCall(opcode, methodInfo, null); } private static void EmitUnboxIfNeeded(ILGenerator il, Type type) { if (type.IsValueType) { Emit(il, OpCodes.Unbox_Any, type); } } private static void EmitBoxIfNeeded(ILGenerator il, Type type) { if (type.IsValueType) { Emit(il, OpCodes.Box, type); } } internal static void EmitFastInt(ILGenerator il, int value) { switch (value) { case -1: il.Emit(OpCodes.Ldc_I4_M1); return; case 0: il.Emit(OpCodes.Ldc_I4_0); return; case 1: il.Emit(OpCodes.Ldc_I4_1); return; case 2: il.Emit(OpCodes.Ldc_I4_2); return; case 3: il.Emit(OpCodes.Ldc_I4_3); return; case 4: il.Emit(OpCodes.Ldc_I4_4); return; case 5: il.Emit(OpCodes.Ldc_I4_5); return; case 6: il.Emit(OpCodes.Ldc_I4_6); return; case 7: il.Emit(OpCodes.Ldc_I4_7); return; case 8: il.Emit(OpCodes.Ldc_I4_8); return; } if (value > -129 && value < 128) { il.Emit(OpCodes.Ldc_I4_S, (sbyte)value); } else { il.Emit(OpCodes.Ldc_I4, value); } } } internal class AccessCache { internal enum MemberType { Any, Static, Instance } private const BindingFlags BasicFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty; private static readonly Dictionary<MemberType, BindingFlags> declaredOnlyBindingFlags = new Dictionary<MemberType, BindingFlags> { { MemberType.Any, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty }, { MemberType.Instance, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty }, { MemberType.Static, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty } }; private readonly Dictionary<Type, Dictionary<string, FieldInfo>> declaredFields = new Dictionary<Type, Dictionary<string, FieldInfo>>(); private readonly Dictionary<Type, Dictionary<string, PropertyInfo>> declaredProperties = new Dictionary<Type, Dictionary<string, PropertyInfo>>(); private readonly Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>> declaredMethods = new Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>>(); private readonly Dictionary<Type, Dictionary<string, FieldInfo>> inheritedFields = new Dictionary<Type, Dictionary<string, FieldInfo>>(); private readonly Dictionary<Type, Dictionary<string, PropertyInfo>> inheritedProperties = new Dictionary<Type, Dictionary<string, PropertyInfo>>(); private readonly Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>> inheritedMethods = new Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>>(); private static T Get<T>(Dictionary<Type, Dictionary<string, T>> dict, Type type, string name, Func<T> fetcher) { lock (dict) { if (!dict.TryGetValue(type, out var value)) { value = (dict[type] = new Dictionary<string, T>()); } if (!value.TryGetValue(name, out var value2)) { value2 = (value[name] = fetcher()); } return value2; } } private static T Get<T>(Dictionary<Type, Dictionary<string, Dictionary<int, T>>> dict, Type type, string name, Type[] arguments, Func<T> fetcher) { lock (dict) { if (!dict.TryGetValue(type, out var value)) { value = (dict[type] = new Dictionary<string, Dictionary<int, T>>()); } if (!value.TryGetValue(name, out var value2)) { value2 = (value[name] = new Dictionary<int, T>()); } int key = AccessTools.CombinedHashCode(arguments); if (!value2.TryGetValue(key, out var value3)) { value3 = (value2[key] = fetcher()); } return value3; } } internal FieldInfo GetFieldInfo(Type type, string name, MemberType memberType = MemberType.Any, bool declaredOnly = false) { FieldInfo fieldInfo = Get(declaredFields, type, name, () => type.GetField(name, declaredOnlyBindingFlags[memberType])); if ((object)fieldInfo == null && !declaredOnly) { fieldInfo = Get(inheritedFields, type, name, () => AccessTools.FindIncludingBaseTypes(type, (Type t) => t.GetField(name, AccessTools.all))); } return fieldInfo; } internal PropertyInfo GetPropertyInfo(Type type, string name, MemberType memberType = MemberType.Any, bool declaredOnly = false) { PropertyInfo propertyInfo = Get(declaredProperties, type, name, () => type.GetProperty(name, declaredOnlyBindingFlags[memberType])); if ((object)propertyInfo == null && !declaredOnly) { propertyInfo = Get(inheritedProperties, type, name, () => AccessTools.FindIncludingBaseTypes(type, (Type t) => t.GetProperty(name, AccessTools.all))); } return propertyInfo; } internal MethodBase GetMethodInfo(Type type, string name, Type[] arguments, MemberType memberType = MemberType.Any, bool declaredOnly = false) { MethodBase methodBase = Get(declaredMethods, type, name, arguments, () => type.GetMethod(name, declaredOnlyBindingFlags[memberType], null, arguments, null)); if ((object)methodBase == null && !declaredOnly) { methodBase = Get(inheritedMethods, type, name, arguments, () => AccessTools.Method(type, name, arguments)); } return methodBase; } } internal static class PatchArgumentExtensions { private static HarmonyArgument[] AllHarmonyArguments(object[] attributes) { return (from attr in attributes select (attr.GetType().Name != "HarmonyArgument") ? null : AccessTools.MakeDeepCopy<HarmonyArgument>(attr) into harg where harg != null select harg).ToArray(); } private static HarmonyArgument GetArgumentAttribute(this ParameterInfo parameter) { return AllHarmonyArguments(parameter.GetCustomAttributes(inherit: false)).FirstOrDefault(); } private static HarmonyArgument[] GetArgumentAttributes(this MethodInfo method) { if ((object)method == null || method is DynamicMethod) { return null; } return AllHarmonyArguments(method.GetCustomAttributes(inherit: false)); } private static HarmonyArgument[] GetArgumentAttributes(this Type type) { return AllHarmonyArguments(type.GetCustomAttributes(inherit: false)); } private static string GetOriginalArgumentName(this ParameterInfo parameter, string[] originalParameterNames) { HarmonyArgument argumentAttribute = parameter.GetArgumentAttribute(); if (argumentAttribute == null) { return null; } if (!string.IsNullOrEmpty(argumentAttribute.OriginalName)) { return argumentAttribute.OriginalName; } if (argumentAttribute.Index >= 0 && argumentAttribute.Index < originalParameterNames.Length) { return originalParameterNames[argumentAttribute.Index]; } return null; } private static string GetOriginalArgumentName(HarmonyArgument[] attributes, string name, string[] originalParameterNames) { if (((attributes != null && attributes.Length != 0) ? 1 : 0) <= (false ? 1 : 0)) { return null; } HarmonyArgument harmonyArgument = attributes.SingleOrDefault((HarmonyArgument p) => p.NewName == name); if (harmonyArgument == null) { return null; } if (!string.IsNullOrEmpty(harmonyArgument.OriginalName)) { return harmonyArgument.OriginalName; } if (originalParameterNames != null && harmonyArgument.Index >= 0 && harmonyArgument.Index < originalParameterNames.Length) { return originalParameterNames[harmonyArgument.Index]; } return null; } private static string GetOriginalArgumentName(this MethodInfo method, string[] originalParameterNames, string name) { string originalArgumentName = GetOriginalArgumentName(((object)method != null) ? method.GetArgumentAttributes() : null, name, originalParameterNames); if (originalArgumentName != null) { return originalArgumentName; } object attributes; if ((object)method == null) { attributes = null; } else { Type? declaringType = method.DeclaringType; attributes = (((object)declaringType != null) ? declaringType.GetArgumentAttributes() : null); } originalArgumentName = GetOriginalArgumentName((HarmonyArgument[])attributes, name, originalParameterNames); if (originalArgumentName != null) { return originalArgumentName; } return name; } internal static int GetArgumentIndex(this MethodInfo patch, string[] originalParameterNames, ParameterInfo patchParam) { if (patch is DynamicMethod) { return Array.IndexOf<string>(originalParameterNames, patchParam.Name); } string originalArgumentName = patchParam.GetOriginalArgumentName(originalParameterNames); if (originalArgumentName != null) { return Array.IndexOf(originalParameterNames, originalArgumentName); } originalArgumentName = patch.GetOriginalArgumentName(originalParameterNames, patchParam.Name); if (originalArgumentName != null) { return Array.IndexOf(originalParameterNames, originalArgumentName); } return -1; } } internal static class PatchFunctions { internal static List<MethodInfo> GetSortedPatchMethods(MethodBase original, Patch[] patches, bool debug) { return new PatchSorter(patches, debug).Sort(original); } internal static Patch[] GetSortedPatchMethodsAsPatches(MethodBase original, Patch[] patches, bool debug) { return new PatchSorter(patches, debug).SortAsPatches(original); } internal static MethodInfo UpdateWrapper(MethodBase original, PatchInfo patchInfo) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown MethodPatcher methodPatcher = original.GetMethodPatcher(); DynamicMethodDefinition val = methodPatcher.PrepareOriginal(); if (val != null) { ILContext ctx = new ILContext(val.Definition); HarmonyManipulator.Manipulate(original, patchInfo, ctx); } try { return methodPatcher.DetourTo((val != null) ? val.Generate() : null) as MethodInfo; } catch (Exception ex) { object body; if (val == null) { body = null; } else { MethodDefinition definition = val.Definition; body = ((definition != null) ? definition.Body : null); } throw HarmonyException.Create(ex, (MethodBody)body); } } internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, MethodInfo postTranspiler, MethodInfo postManipulator) { //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Expected O, but got Unknown //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Expected O, but got Unknown if (standin == null) { throw new ArgumentNullException("standin"); } if ((object)standin.method == null) { throw new ArgumentNullException("standin", "standin.method is NULL"); } if (!standin.method.IsStatic) { throw new ArgumentException("standin", "standin.method is not static"); } bool debug = standin.debug.GetValueOrDefault(); List<MethodInfo> transpilers = new List<MethodInfo>(); List<MethodInfo> ilmanipulators = new List<MethodInfo>(); if (standin.reversePatchType == HarmonyReversePatchType.Snapshot) { Patches patchInfo = Harmony.GetPatchInfo(original); transpilers.AddRange(GetSortedPatchMethods(original, patchInfo.Transpilers.ToArray(), debug)); ilmanipulators.AddRange(GetSortedPatchMethods(original, patchInfo.ILManipulators.ToArray(), debug)); } if ((object)postTranspiler != null) { transpilers.Add(postTranspiler); } if ((object)postManipulator != null) { ilmanipulators.Add(postManipulator); } Logger.Log(Logger.LogChannel.Info, delegate { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Reverse patching " + standin.method.FullDescription() + " with " + original.FullDescription()); PrintInfo(stringBuilder, transpilers, "Transpiler"); PrintInfo(stringBuilder, ilmanipulators, "Manipulators"); return stringBuilder.ToString(); }, debug); MethodBody patchBody = null; ILHook val = new ILHook((MethodBase)standin.method, (Manipulator)delegate(ILContext ctx) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) if (original is MethodInfo methodInfo2) { patchBody = ctx.Body; MethodPatcher methodPatcher = methodInfo2.GetMethodPatcher(); DynamicMethodDefinition val2 = methodPatcher.CopyOriginal(); if (val2 == null) { throw new NullReferenceException("Cannot reverse patch " + methodInfo2.FullDescription() + ": method patcher (" + methodPatcher.GetType().FullDescription() + ") can't copy original method body"); } ILManipulator iLManipulator = new ILManipulator(val2.Definition.Body, debug); ctx.Body.Variables.Clear(); Enumerator<VariableDefinition> enumerator2 = iLManipulator.Body.Variables.GetEnumerator(); try { while (enumerator2.MoveNext()) { VariableDefinition current2 = enumerator2.Current; ctx.Body.Variables.Add(new VariableDefinition(ctx.Module.ImportReference(((VariableReference)current2).VariableType))); } } finally { ((IDisposable)enumerator2).Dispose(); } foreach (MethodInfo item in transpilers) { iLManipulator.AddTranspiler(item); } iLManipulator.WriteTo(ctx.Body, standin.method); HarmonyManipulator.ApplyManipulators(ctx, original, ilmanipulators, null); Instruction val3 = null; foreach (Instruction item2 in ((IEnumerable<Instruction>)ctx.Instrs).Where((Instruction i) => i.OpCode == OpCodes.Ret)) { if (val3 == null) { val3 = ctx.IL.Create(OpCodes.Ret); } item2.OpCode = OpCodes.Br; item2.Operand = val3; } if (val3 != null) { ctx.IL.Append(val3); } Logger.Log(Logger.LogChannel.IL, () => "Generated reverse patcher (" + ((MemberReference)ctx.Method).FullName + "):\n" + ctx.Body.ToILDasmString(), debug); } }, new ILHookConfig { ManualApply = true }); try { val.Apply(); } catch (Exception ex) { throw HarmonyException.Create(ex, patchBody); } MethodInfo methodInfo = val.GetCurrentTarget() as MethodInfo; PatchTools.RememberObject(standin.method, methodInfo); return methodInfo; static void PrintInfo(StringBuilder sb, ICollection<MethodInfo> methods, string name) { if (methods.Count <= 0) { return; } sb.AppendLine(name + ":"); foreach (MethodInfo method in methods) { sb.AppendLine(" * " + method.FullDescription()); } } } internal static IEnumerable<CodeInstruction> ApplyTranspilers(MethodBase methodBase, ILGenerator generator, int maxTranspilers = 0) { MethodPatcher methodPatcher = methodBase.GetMethodPatcher(); DynamicMethodDefinition val = methodPatcher.CopyOriginal(); if (val == null) { throw new NullReferenceException("Cannot reverse patch " + methodBase.FullDescription() + ": method patcher (" + methodPatcher.GetType().FullDescription() + ") can't copy original method body"); } ILManipulator iLManipulator = new ILManipulator(val.Definition.Body, debug: false); PatchInfo patchInfo = methodBase.GetPatchInfo(); if (patchInfo != null) { List<MethodInfo> sortedPatchMethods = GetSortedPatchMethods(methodBase, patchInfo.transpilers, debug: false); for (int i = 0; i < maxTranspilers && i < sortedPatchMethods.Count; i++) { iLManipulator.AddTranspiler(sortedPatchMethods[i]); } } return iLManipulator.GetInstructions(generator, methodBase); } internal static void UnpatchConditional(Func<Patch, bool> executionCondition) { foreach (MethodBase item in PatchProcessor.GetAllPatchedMethods().ToList()) { bool num = item.HasMethodBody(); Patches patchInfo2 = PatchProcessor.GetPatchInfo(item); PatchProcessor patchProcessor = new PatchProcessor(null, item); if (num) { patchInfo2.Postfixes.DoIf(executionCondition, delegate(Patch patchInfo) { patchProcessor.Unpatch(patchInfo.PatchMethod); }); patchInfo2.Prefixes.DoIf(executionCondition, delegate(Patch patchInfo) { patchProcessor.Unpatch(patchInfo.PatchMethod); }); } patchInfo2.ILManipulators.DoIf(executionCondition, delegate(Patch patchInfo) { patchProcessor.Unpatch(patchInfo.PatchMethod); }); patchInfo2.Transpilers.DoIf(executionCondition, delegate(Patch patchInfo) { patchProcessor.Unpatch(patchInfo.PatchMethod); }); if (num) { patchInfo2.Finalizers.DoIf(executionCondition, delegate(Patch patchInfo) { patchProcessor.Unpatch(patchInfo.PatchMethod); }); } } } } internal class PatchJobs<T> { internal class Job { internal MethodBase original; internal T replacement; internal List<HarmonyMethod> prefixes = new List<HarmonyMethod>(); internal List<HarmonyMethod> postfixes = new List<HarmonyMethod>(); internal List<HarmonyMethod> transpilers = new List<HarmonyMethod>(); internal List<HarmonyMethod> finalizers = new List<HarmonyMethod>(); internal List<HarmonyMethod> ilmanipulators = new List<HarmonyMethod>(); internal void AddPatch(AttributePatch patch) { HarmonyPatchType? type = patch.type; if (type.HasValue) { switch (type.GetValueOrDefault()) { case HarmonyPatchType.Prefix: prefixes.Add(patch.info); break; case HarmonyPatchType.Postfix: postfixes.Add(patch.info); break; case HarmonyPatchType.Transpiler: transpilers.Add(patch.info); break; case HarmonyPatchType.Finalizer: finalizers.Add(patch.info); break; case HarmonyPatchType.ILManipulator: ilmanipulators.Add(patch.info); break; case HarmonyPatchType.ReversePatch: break; } } } } internal Dictionary<MethodBase, Job> state = new Dictionary<MethodBase, Job>(); internal Job GetJob(MethodBase method) { if ((object)method == null) { return null; } if (!state.TryGetValue(method, out var value)) { value = new Job { original = method }; state[method] = value; } return value; } internal List<Job> GetJobs() { return state.Values.Where((Job job) => job.prefixes.Count + job.postfixes.Count + job.transpilers.Count + job.finalizers.Count + job.ilmanipulators.Count > 0).ToList(); } internal List<T> GetReplacements() { return state.Values.Select((Job job) => job.replacement).ToList(); } } internal class AttributePatch { private static readonly HarmonyPatchType[] allPatchTypes = new HarmonyPatchType[6] { HarmonyPatchType.Prefix, HarmonyPatchType.Postfix, HarmonyPatchType.Transpiler, HarmonyPatchType.Finalizer, HarmonyPatchType.ReversePatch, HarmonyPatchType.ILManipulator }; internal HarmonyMethod info; internal HarmonyPatchType? type; private static readonly string harmonyAttributeName = typeof(HarmonyAttribute).FullName; internal static IEnumerable<AttributePatch> Create(MethodInfo patch, bool collectIncomplete = false) { if ((object)patch == null) { throw new NullReferenceException("Patch method cannot be null"); } object[] customAttributes = patch.GetCustomAttributes(inherit: true); string name = patch.Name; HarmonyPatchType? type = GetPatchType(name, customAttributes); if (!type.HasValue) { return Enumerable.Empty<AttributePatch>(); } if (type != HarmonyPatchType.ReversePatch && !patch.IsStatic) { throw new ArgumentException("Patch method " + patch.FullDescription() + " must be static"); } List<HarmonyMethod> list = (from attr in customAttributes where attr.GetType().BaseType.FullName == harmonyAttributeName select AccessTools.Field(attr.GetType(), "info").GetValue(attr) into harmonyInfo select AccessTools.MakeDeepCopy<HarmonyMethod>(harmonyInfo)).ToList(); List<HarmonyMethod> list2 = new List<HarmonyMethod>(); ILookup<bool, HarmonyMethod> lookup = list.ToLookup((HarmonyMethod m) => IsComplete(m, collectIncomplete)); List<HarmonyMethod> incomplete = lookup[false].ToList(); HarmonyMethod info = HarmonyMethod.Merge(incomplete); List<HarmonyMethod> list3 = lookup[true].Where((HarmonyMethod m) => !Same(m, info)).ToList(); if (list3.Count > 1) { list2.AddRange(list3.Select((HarmonyMethod m) => HarmonyMethod.Merge(incomplete.AddItem(m)))); } else { list2.Add(HarmonyMethod.Merge(list)); } foreach (HarmonyMethod item in list2) { item.method = patch; } return list2.Select((HarmonyMethod i) => new AttributePatch { info = i, type = type }).ToList(); static bool IsComplete(HarmonyMethod m, bool collectIncomplete) { if (collectIncomplete || m.GetDeclaringType() != null) { return m.methodName != null; } return false; } static bool Same(HarmonyMethod m1, HarmonyMethod m2) { if (m1.GetDeclaringType() == m2.GetDeclaringType() && m1.methodName == m2.methodName) { return m1.GetArgumentList().SequenceEqual(m2.GetArgumentList()); } return false; } } private static HarmonyPatchType? GetPatchType(string methodName, object[] allAttributes) { HashSet<string> hashSet = new HashSet<string>(from attr in allAttributes select attr.GetType().FullName into name where name.StartsWith("Harmony") select name); HarmonyPatchType? result = null; HarmonyPatchType[] array = allPatchTypes; for (int i = 0; i < array.Length; i++) { HarmonyPatchType value = array[i]; string text = value.ToString(); if (text == methodName || hashSet.Contains("HarmonyLib.Harmony" + text)) { result = value; break; } } return result; } } internal class PatchSorter { private class PatchSortingWrapper : IComparable { internal readonly HashSet<PatchSortingWrapper> after; internal readonly HashSet<PatchSortingWrapper> before; internal readonly Patch innerPatch; internal PatchSortingWrapper(Patch patch) { innerPatch = patch; before = new HashSet<PatchSortingWrapper>(); after = new HashSet<PatchSortingWrapper>(); } public int CompareTo(object obj) { return PatchInfoSerialization.PriorityComparer((obj as PatchSortingWrapper)?.innerPatch, innerPatch.index, innerPatch.priority); } public override bool Equals(object obj) { if (obj is PatchSortingWrapper patchSortingWrapper) { return innerPatch.PatchMethod == patchSortingWrapper.innerPatch.PatchMethod; } return false; } public override int GetHashCode() { return innerPatch.PatchMethod.GetHashCode(); } internal void AddBeforeDependency(IEnumerable<PatchSortingWrapper> dependencies) { foreach (PatchSortingWrapper dependency in dependencies) { before.Add(dependency); dependency.after.Add(this); } } internal void AddAfterDependency(IEnumerable<PatchSortingWrapper> dependencies) { foreach (PatchSortingWrapper dependency in dependencies) { after.Add(dependency); dependency.before.Add(this); } } internal void RemoveAfterDependency(PatchSortingWrapper afterNode) { after.Remove(afterNode); afterNode.before.Remove(this); } internal void RemoveBeforeDependency(PatchSortingWrapper beforeNode) { before.Remove(beforeNode); beforeNode.after.Remove(this); } } internal class PatchDetailedComparer : IEqualityComparer<Patch> { public bool Equals(Patch x, Patch y) { if (y != null && x != null && x.owner == y.owner && x.PatchMethod == y.PatchMethod && x.index == y.index && x.priority == y.priority && x.before.Length == y.before.Length && x.after.Length == y.after.Length && x.before.All(((IEnumerable<string>)y.before).Contains<string>)) { return x.after.All(((IEnumerable<string>)y.after).Contains<string>); } return false; } public int GetHashCode(Patch obj) { return obj.GetHashCode(); } } private List<PatchSortingWrapper> patches; private HashSet<PatchSortingWrapper> handledPatches; private List<PatchSortingWrapper> result; private List<PatchSortingWrapper> waitingList; internal Patch[] sortedPatchArray; private readonly bool debug; internal PatchSorter(Patch[] patches, bool debug = false) { this.patches = patches.Select((Patch x) => new PatchSortingWrapper(x)).ToList(); this.debug = debug; foreach (PatchSortingWrapper node in this.patches) { node.AddBeforeDependency(this.patches.Where((PatchSortingWrapper x) => node.innerPatch.before.Contains(x.innerPatch.owner))); node.AddAfterDependency(this.patches.Where((PatchSortingWrapper x) => node.innerPatch.after.Contains(x.innerPatch.owner))); } this.patches.Sort(); } internal List<MethodInfo> Sort(MethodBase original) { return (from x in SortAsPatches(original) select x.GetMethod(original)).ToList(); } internal Patch[] SortAsPatches(MethodBase original) { if (sortedPatchArray != null) { return sortedPatchArray; } handledPatches = new HashSet<PatchSortingWrapper>(); waitingList = new List<PatchSortingWrapper>(); result = new List<PatchSortingWrapper>(patches.Count); Queue<PatchSortingWrapper> queue = new Queue<PatchSortingWrapper>(patches); while (queue.Count != 0) { foreach (PatchSortingWrapper item in queue) { if (item.after.All((PatchSortingWrapper x) => handledPatches.Contains(x))) { AddNodeToResult(item); if (item.before.Count != 0) { ProcessWaitingList(); } } else { waitingList.Add(item); } } CullDependency(); queue = new Queue<PatchSortingWrapper>(waitingList); waitingList.Clear(); } sortedPatchArray = result.Select((PatchSortingWrapper x) => x.innerPatch).ToArray(); handledPatches = null; waitingList = null; patches = null; return sortedPatchArray; } internal bool ComparePatchLists(Patch[] patches) { if (sortedPatchArray == null) { Sort(null); } if (patches != null && sortedPatchArray.Length == patches.Length) { return sortedPatchArray.All((Patch x) => patches.Contains(x, new PatchDetailedComparer())); } return false; } private void CullDependency() { for (int i = waitingList.Count - 1; i >= 0; i--) { foreach (PatchSortingWrapper afterNode in waitingList[i].after) { if (!handledPatches.Contains(afterNode)) { waitingList[i].RemoveAfterDependency(afterNode); Logger.Log(Logger.LogChannel.Debug, delegate { string text = afterNode.innerPatch.PatchMethod.FullDescription(); string text2 = waitingList[i].innerPatch.PatchMethod.FullDescription(); return "Breaking dependence between " + text + " and " + text2; }, debug); return; } } } } private void ProcessWaitingList() { int num = waitingList.Count; int num2 = 0; while (num2 < num) { PatchSortingWrapper patchSortingWrapper = waitingList[num2]; if (patchSortingWrapper.after.All(handledPatches.Contains)) { waitingList.Remove(patchSortingWrapper); AddNodeToResult(patchSortingWrapper); num--; num2 = 0; } else { num2++; } } } private void AddNodeToResult(PatchSortingWrapper node) { result.Add(node); handledPatches.Add(node); } } internal static class PatchTools { [ThreadStatic] private static Dictionary<object, object> objectReferences; internal static void RememberObject(object key, object value) { if (objectReferences == null) { objectReferences = new Dictionary<object, object>(); } objectReferences[key] = value; } internal static MethodInfo GetPatchMethod(Type patchType, string attributeName) { MethodInfo methodInfo = patchType.GetMethods(AccessTools.all).FirstOrDefault((MethodInfo m) => m.GetCustomAttributes(inherit: true).Any((object a) => a.GetType().FullName == attributeName)); if ((object)methodInfo == null) { string name = attributeName.Replace("HarmonyLib.Harmony", ""); methodInfo = patchType.GetMethod(name, AccessTools.all); } return methodInfo; } internal static AssemblyBuilder DefineDynamicAssembly(string name) { return AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(name), AssemblyBuilderAccess.Run); } internal static List<AttributePatch> GetPatchMethods(Type type, bool collectIncomplete = false) { return (from attributePatch in AccessTools.GetDeclaredMethods(type).SelectMany((MethodInfo m) => AttributePatch.Create(m, collectIncomplete)) where attributePatch != null select attributePatch).ToList(); } internal static MethodBase GetOriginalMethod(this HarmonyMethod attr) { try { MethodType? methodType = attr.methodType; if (methodType.HasValue) { switch (methodType.GetValueOrDefault()) { case MethodType.Normal: if (attr.methodName == null) { return null; } return AccessTools.DeclaredMethod(attr.GetDeclaringType(), attr.methodName, attr.argumentTypes); case MethodType.Getter: if (attr.methodName == null) { return null; } return AccessTools.DeclaredProperty(attr.GetDeclaringType(), attr.methodName).GetGetMethod(nonPublic: true); case MethodType.Setter: if (attr.methodName == null) { return null; } return AccessTools.DeclaredProperty(attr.GetDeclaringType(), attr.methodName).GetSetMethod(nonPublic: true); case MethodType.Constructor: return AccessTools.DeclaredConstructor(attr.GetDeclaringType(), attr.argumentTypes); case MethodType.StaticConstructor: return AccessTools.GetDeclaredConstructors(attr.GetDeclaringType()).FirstOrDefault((ConstructorInfo c) => c.IsStatic); case MethodType.Enumerator: if (attr.methodName == null) { return null; } return AccessTools.EnumeratorMoveNext(AccessTools.DeclaredMethod(attr.GetDeclaringType(), attr.methodName, attr.argumentTypes)); } } } catch (AmbiguousMatchException ex) { throw new HarmonyException("Ambiguous match for HarmonyMethod[" + attr.Description() + "]", ex.InnerException ?? ex); } return null; } } public enum MethodType { Normal, Getter, Setter, Constructor, StaticConstructor, Enumerator } public enum ArgumentType { Normal, Ref, Out, Pointer } public enum HarmonyPatchType { All, Prefix, Postfix, Transpiler, Finalizer, ReversePatch, ILManipulator } public enum HarmonyReversePatchType { Original, Snapshot } public enum MethodDispatchType { VirtualCall, Call } [MeansImplicitUse] public class HarmonyAttribute : Attribute { public HarmonyMethod info = new HarmonyMethod(); } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Delegate, AllowMultiple = true)] public class HarmonyPatch : HarmonyAttribute { public HarmonyPatch() { } public HarmonyPatch(Type declaringType) { info.declaringType = declaringType; } public HarmonyPatch(Type declaringType, Type[] argumentTypes) { info.declaringType = declaringType; info.argumentTypes = argumentTypes; } public HarmonyPatch(Type declaringType, string methodName) { info.declaringType = declaringType; info.methodName = methodName; } public HarmonyPatch(Type declaringType, string methodName, params Type[] argumentTypes) { info.declaringType = declaringType; info.methodName = methodName; info.argumentTypes = argumentTypes; } public HarmonyPatch(Type declaringType, string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations) { info.declaringType = declaringType; info.methodName = methodName; ParseSpecialArguments(argumentTypes, argumentVariations); } public HarmonyPatch(string typeName, string methodName) { info.declaringType = AccessTools.TypeByName(typeName); info.methodName = methodName; } public HarmonyPatch(string typeName, string methodName, MethodType methodType, Type[] argumentTypes = null, ArgumentType[] argumentVariations = null) { info.declaringType = AccessTools.TypeByName(typeName); info.methodName = methodName; info.methodType = methodType; if (argumentTypes != null) { ParseSpecialArguments(argumentTypes, argumentVariations); } } public HarmonyPatch(Type declaringType, MethodType methodType) { info.declaringType = declaringType; info.methodType = methodType; } public HarmonyPatch(Type declaringType, MethodType methodType, params Type[] argumentTypes) { info.declaringType = declaringType; info.methodType = methodType; info.argumentTypes = argumentTypes; } public HarmonyPatch(Type declaringType, MethodType methodType, Type[] argumentTypes, ArgumentType[] argumentVariations) { info.declaringType = declaringType; info.methodType = methodType; ParseSpecialArguments(argumentTypes, argumentVariations); } public HarmonyPatch(Type declaringType, string methodName, MethodType methodType) { info.declaringType = declaringType; info.methodName = methodName; info.methodType = methodType; } public HarmonyPatch(string methodName) { info.methodName = methodName; } public HarmonyPatch(string methodName, params Type[] argumentTypes) { info.methodName = methodName; info.argumentTypes = argumentTypes; } public HarmonyPatch(string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations) { info.methodName = methodName; ParseSpecialArguments(argumentTypes, argumentVariations); } public HarmonyPatch(string methodName, MethodType methodType) { info.methodName = methodName; info.methodType = methodType; } public HarmonyPatch(MethodType methodType) { info.methodType = methodType; } public HarmonyPatch(MethodType methodType, params Type[] argumentTypes) { info.methodType = methodType; info.argumentTypes = argumentTypes; } public HarmonyPatch(MethodType methodType, Type[] argumentTypes, ArgumentType[] argumentVariations) { info.methodType = methodType; ParseSpecialArguments(argumentTypes, argumentVariations); } public HarmonyPatch(Type[] argumentTypes) { info.argumentTypes = argumentTypes; } public HarmonyPatch(Type[] argumentTypes, ArgumentType[] argumentVariations) { ParseSpecialArguments(argumentTypes, argumentVariations); } public HarmonyPatch(string typeName, string methodName, MethodType methodType = MethodType.Normal) { info.declaringType = AccessTools.TypeByName(typeName); info.methodName = methodName; info.methodType = methodType; } private void ParseSpecialArguments(Type[] argumentTypes, ArgumentType[] argumentVariations) { if (argumentVariations == null || argumentVariations.Length == 0) { info.argumentTypes = argumentTypes; return; } if (argumentTypes.Length < argumentVariations.Length) { throw new ArgumentException("argumentVariations contains more elements than argumentTypes", "argumentVariations"); } List<Type> list = new List<Type>(); for (int i = 0; i < argumentTypes.Length; i++) { Type type = argumentTypes[i]; switch (argumentVariations[i]) { case ArgumentType.Ref: case ArgumentType.Out: type = type.MakeByRefType(); break; case ArgumentType.Pointer: type = type.MakePointerType(); break; } list.Add(type); } info.argumentTypes = list.ToArray(); } } [AttributeUsage(AttributeTargets.Delegate, AllowMultiple = true)] public class HarmonyDelegate : HarmonyPatch { public HarmonyDelegate(Type declaringType) : base(declaringType) { } public HarmonyDelegate(Type declaringType, Type[] argumentTypes) : base(declaringType, argumentTypes) { } public HarmonyDelegate(Type declaringType, string methodName) : base(declaringType, methodName) { } public HarmonyDelegate(Type declaringType, string methodName, params Type[] argumentTypes) : base(declaringType, methodName, argumentTypes) { } public HarmonyDelegate(Type declaringType, string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations) : base(declaringType, methodName, argumentTypes, argumentVariations) { } public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType) : base(declaringType, MethodType.Normal) { info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; } public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType, params Type[] argumentTypes) : base(declaringType, MethodType.Normal, argumentTypes) { info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; } public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType, Type[] argumentTypes, ArgumentType[] argumentVariations) : base(declaringType, MethodType.Normal, argumentTypes, argumentVariations) { info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; } public HarmonyDelegate(Type declaringType, string methodName, MethodDispatchType methodDispatchType) : base(declaringType, methodName, MethodType.Normal) { info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; } public HarmonyDelegate(string methodName) : base(methodName) { } public HarmonyDelegate(string methodName, params Type[] argumentTypes) : base(methodName, argumentTypes) { } public HarmonyDelegate(string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations) : base(methodName, argumentTypes, argumentVariations) { } public HarmonyDelegate(string methodName, MethodDispatchType methodDispatchType) : base(methodName, MethodType.Normal) { info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; } public HarmonyDelegate(MethodDispatchType methodDispatchType) { info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; } public HarmonyDelegate(MethodDispatchType methodDispatchType, params Type[] argumentTypes) : base(MethodType.Normal, argumentTypes) { info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; } public HarmonyDelegate(MethodDispatchType methodDispatchType, Type[] argumentTypes, ArgumentType[] argumentVariations) : base(MethodType.Normal, argumentTypes, argumentVariations) { info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call; } public HarmonyDelegate(Type[] argumentTypes) : base(argumentTypes) { } public HarmonyDelegate(Type[] argumentTypes, ArgumentType[] argumentVariations) : base(argumentTypes, argumentVariations) { } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] public class HarmonyReversePatch : HarmonyAttribute { public HarmonyReversePatch(HarmonyReversePatchType type = HarmonyReversePatchType.Original) { info.reversePatchType = type; } } [AttributeUsage(AttributeTargets.Class)] public class HarmonyPatchAll : HarmonyAttribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class HarmonyPriority : HarmonyAttribute { public HarmonyPriority(int priority) { info.priority = priority; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class HarmonyBefore : HarmonyAttribute { public HarmonyBefore(params string[] before) { info.before = before; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class HarmonyAfter : HarmonyAttribute { public HarmonyAfter(params string[] after) { info.after = after; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class HarmonyDebug : HarmonyAttribute { public HarmonyDebug() { info.debug = true; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class HarmonyEmitIL : HarmonyAttribute { public HarmonyEmitIL() { info.debugEmitPath = "./"; } public HarmonyEmitIL(string dir) { info.debugEmitPath = dir; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class HarmonyWrapSafe : HarmonyAttribute { public HarmonyWrapSafe() { info.wrapTryCatch = true; } } [AttributeUsage(AttributeTargets.Method)] public class HarmonyPrepare : Attribute { } [AttributeUsage(AttributeTargets.Method)] public class HarmonyCleanup : Attribute { } [AttributeUsage(AttributeTargets.Method)] public class HarmonyTargetMethod : Attribute { } [AttributeUsage(AttributeTargets.Method)] public class HarmonyTargetMethods : Attribute { } [AttributeUsage(AttributeTargets.Method)] public class HarmonyPrefix : Attribute { } [AttributeUsage(AttributeTargets.Method)] public class HarmonyPostfix : Attribute { } [AttributeUsage(AttributeTargets.Method)] public class HarmonyTranspiler : Attribute { } [AttributeUsage(AttributeTargets.Method)] public class HarmonyILManipulator : Attribute { } [AttributeUsage(AttributeTargets.Method)] public class HarmonyFinalizer : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true)] public class HarmonyArgument : Attribute { public string OriginalName { get; private set; } public int Index { get; private set; } public string NewName { get; private set; } public HarmonyArgument(string originalName) : this(originalName, null) { } public HarmonyArgument(int index) : this(index, null) { } public HarmonyArgument(string originalName, string newName) { OriginalName = originalName; Index = -1; NewName = newName; } public HarmonyArgument(int index, string name) { OriginalName = null; Index = index; NewName = name; } } public class CodeInstruction { public OpCode opcode; public object operand; public List<Label> labels = new List<Label>(); public List<ExceptionBlock> blocks = new List<ExceptionBlock>(); internal CodeInstruction() { } public CodeInstruction(OpCode opcode, object operand = null) { this.opcode = opcode; this.operand = operand; } public CodeInstruction(CodeInstruction instruction) { opcode = instruction.opcode; operand = instruction.operand; labels = instruction.labels.ToList(); blocks = instruction.blocks.ToList(); } public CodeInstruction Clone() { return new CodeInstruction(this) { labels = new List<Label>(), blocks = new List<ExceptionBlock>() }; } public CodeInstruction Clone(OpCode opcode) { CodeInstruction codeInstruction = Clone(); codeInstruction.opcode = opcode; return codeInstruction; } public CodeInstruction Clone(object operand) { CodeInstruction codeInstruction = Clone(); codeInstruction.operand = operand; return codeInstruction; } public static CodeInstruction Call(Type type, string name, Type[] parameters = null, Type[] generics = null) { MethodInfo methodInfo = AccessTools.Method(type, name, parameters, generics); if ((object)methodInfo == null) { throw new ArgumentException($"No method found for type={type}, name={name}, parameters={parameters.Description()}, generics={generics.Description()}"); } return new CodeInstruction(OpCodes.Call, methodInfo); } public static CodeInstruction Call(string typeColonMethodname, Type[] parameters = null, Type[] generics = null) { MethodInfo methodInfo = AccessTools.Method(typeColonMethodname, parameters, generics); if ((object)methodInfo == null) { throw new ArgumentException("No method found for " + typeColonMethodname + ", parameters=" + parameters.Description() + ", generics=" + generics.Description()); } return new CodeInstruction(OpCodes.Call, methodInfo); } public static CodeInstruction Call(Expression<Action> expression) { return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression)); } public static CodeInstruction Call<T>(Expression<Action<T>> expression) { return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression)); } public static CodeInstruction Call<T, TResult>(Expression<Func<T, TResult>> expression) { return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression)); } public static CodeInstruction Call(LambdaExpression expression) { return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression)); } public static CodeInstruction CallClosure<T>(T closure) where T : Delegate { return Transpilers.EmitDelegate(closure); } public static CodeInstruction LoadField(Type type, string name, bool useAddress = false) { FieldInfo fieldInfo = AccessTools.Field(type, name); if ((object)fieldInfo == null) { throw new ArgumentException($"No field found for {type} and {name}"); } return new CodeInstruction((!useAddress) ? (fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld) : (fieldInfo.IsStatic ? OpCodes.Ldsflda : OpCodes.Ldflda), fieldInfo); } public static CodeInstruction StoreField(Type type, string name) { FieldInfo fieldInfo = AccessTools.Field(type, name); if ((object)fieldInfo == null) { throw new ArgumentException($"No field found for {type} and {name}"); } return new CodeInstruction(fieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo); } public override string ToString() { List<string> list = new List<string>(); foreach (Label label in labels) { list.Add($"Label{label.GetHashCode()}"); } foreach (ExceptionBlock block in blocks) { list.Add("EX_" + block.blockType.ToString().Replace("Block", "")); } string text = ((list.Count > 0) ? (" [" + string.Join(", ", list.ToArray()) + "]") : ""); string text2 = FormatArgument(operand); if (text2.Length > 0) { text2 = " " + text2; } OpCode opCode = opcode; return opCode.ToString() + text2 + text; } internal static string FormatArgument(object argument, string extra = null) { if (argument == null) { return "NULL"; } Type type = argument.GetType(); if (argument is MethodBase member) { return member.FullDescription() + ((extra != null) ? (" " + extra) : ""); } if (argument is FieldInfo fieldInfo) { return fieldInfo.FieldType.FullDescription() + " " + fieldInfo.DeclaringType.FullDescription() + "::" + fieldInfo.Name; } if (type == typeof(Label)) { return $"Label{((Label)argument).GetHashCode()}"; } if (type == typeof(Label[])) { return "Labels" + string.Join(",", ((Label[])argument).Select((Label l) => l.GetHashCode().ToString()).ToArray()); } if (type == typeof(LocalBuilder)) { return $"{((LocalBuilder)argument).LocalIndex} ({((LocalBuilder)argument).LocalType})"; } if (type == typeof(string)) { return argument.ToString().ToLiteral(); } return argument.ToString().Trim(); } } public enum ExceptionBlockType { BeginExceptionBlock, BeginCatchBlock, BeginExceptFilterBlock, BeginFaultBlock, BeginFinallyBlock, EndExceptionBlock } public class ExceptionBlock { public ExceptionBlockType blockType; public Type catchType; public ExceptionBlock(ExceptionBlockType blockType, Type catchType = null) { this.blockType = blockType; this.catchType = catchType ?? typeof(object); } } public class InvalidHarmonyPatchArgumentException : Exception { public MethodBase Original { get; } public MethodInfo Patch { get; } public override string Message => "(" + Patch.FullDescription() + "): " + base.Message; public InvalidHarmonyPatchArgumentException(string message, MethodBase original, MethodInfo patch) : base(message) { Original = original; Patch = patch; } } public class MemberNotFoundException : Exception { public MemberNotFoundException(string message) : base(message) { } } public class Harmony : IDisposable { [Obsolete("Use HarmonyFileLog.Enabled instead")] public static bool DEBUG; public string Id { get; } static Harmony() { StackTraceFixes.Install(); } public Harmony(string id) { if (string.IsNullOrEmpty(id)) { throw new ArgumentException("id cannot be null or empty"); } try { string environmentVariable = Environment.GetEnvironmentVariable("HARMONY_DEBUG"); if (environmentVariable != null && environmentVariable.Length > 0) { environmentVariable = environmentVariable.Trim(); DEBUG = environmentVariable == "1" || bool.Parse(environmentVariable); } } catch { } if (DEBUG) { HarmonyFileLog.Enabled = true; } MethodBase callingMethod = (Logger.IsEnabledFor(Logger.LogChannel.Info) ? AccessTools.GetOutsideCaller() : null); Logger.Log(Logger.LogChannel.Info, delegate { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); Assembly assembly = typeof(Harmony).Assembly; Version version = assembly.GetName().Version; string text = assembly.Location; string text2 = Environment.Version.ToString(); string text3 = Environment.OSVersion.Platform.ToString(); if (string.IsNullOrEmpty(text)) { text = new Uri(assembly.CodeBase).LocalPath; } int size = IntPtr.Size; Platform current = PlatformHelper.Current; stringBuilder.AppendLine($"### Harmony id={id}, version={version}, location={text}, env/clr={text2}, platform={text3}, ptrsize:runtime/env={size}/{current}"); if ((object)callingMethod?.DeclaringType != null) { Assembly assembly2 = callingMethod.DeclaringType.Assembly; text = assembly2.Location; if (string.IsNullOrEmpty(text)) { text = new Uri(assembly2.CodeBase).LocalPath; } stringBuilder.AppendLine("### Started from " + callingMethod.FullDescription() + ", location " + text); stringBuilder.Append($"### At {DateTime.Now:yyyy-MM-dd hh.mm.ss}"); } return stringBuilder.ToString(); }); Id = id; } public void PatchAll() { Assembly assembly = new StackTrace().GetFrame(1).GetMethod().ReflectedType.Assembly; PatchAll(assembly); } public PatchProcessor CreateProcessor(MethodBase original) { return new PatchProcessor(this, original); } public PatchClassProcessor CreateClassProcessor(Type type) { return new PatchClassProcessor(this, type); } public PatchClassProcessor CreateClassProcessor(Type type, bool allowUnannotatedType) { return new PatchClassProcessor(this, type, allowUnannotatedType); } public ReversePatcher CreateReversePatcher(MethodBase original, HarmonyMethod standin) { return new ReversePatcher(this, original, standin); } public void PatchAll(Assembly assembly) { AccessTools.GetTypesFromAssembly(assembly).Do(delegate(Type type) { CreateClassProcessor(type).Patch(); }); } public void PatchAll(Type type) { CreateClassProcessor(type, allowUnannotatedType: true).Patch(); } public MethodInfo Patch(MethodBase original, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null, HarmonyMethod finalizer = null, HarmonyMethod ilmanipulator = null) { PatchProcessor patchProcessor = CreateProcessor(original); patchProcessor.AddPrefix(prefix); patchProcessor.AddPostfix(postfix); patchProcessor.AddTranspiler(transpiler); patchProcessor.AddFinalizer(finalizer); patchProcessor.AddILManipulator(ilmanipulator); return patchProcessor.Patch(); } [Obsolete("Use newer Patch() instead", true)] public MethodInfo Patch(MethodBase original, HarmonyMethod prefix, HarmonyMethod postfix, HarmonyMethod transpiler, HarmonyMethod finalizer) { return Patch(original, prefix, postfix, transpiler, finalizer, null); } public static MethodInfo ReversePatch(MethodBase original, HarmonyMethod standin, MethodInfo transpiler = null, MethodInfo ilmanipulator = null) { return PatchFunctions.ReversePatch(standin, original, transpiler, ilmanipulator); } [Obsolete("Use newer ReversePatch() instead", true)] public static MethodInfo ReversePatch(MethodBase original, HarmonyMethod standin, MethodInfo transpiler) { return PatchFunctions.ReversePatch(standin, original, transpiler, null); } public static void UnpatchID(string harmonyID) { if (string.IsNullOrEmpty(harmonyID)) { throw new ArgumentNullException("harmonyID", "UnpatchID was called with a null or empty harmonyID."); } PatchFunctions.UnpatchConditional((Patch patchInfo) => patchInfo.owner == harmonyID); } void IDisposable.Dispose() { UnpatchSelf(); } public void UnpatchSelf() { UnpatchID(Id); } public static void UnpatchAll() { Logger.Log(Logger.LogChannel.Warn, () => "UnpatchAll has been called - This will remove ALL HARMONY PATCHES."); PatchFunctions.UnpatchConditional((Patch _) => true); } [Obsolete("Use UnpatchSelf() to unpatch the current instance. The functionality to unpatch either other ids or EVERYTHING has been moved the static methods UnpatchID() and UnpatchAll() respectively", true)] public void UnpatchAll(string harmonyID = null) { if (harmonyID == null) { if (HarmonyGlobalSettings.DisallowLegacyGlobalUnpatchAll) { Logger.Log(Logger.LogChannel.Warn, () => "Legacy UnpatchAll has been called AND DisallowLegacyGlobalUnpatchAll=true. Skipping execution of UnpatchAll"); } else { UnpatchAll(); } } else if (harmonyID.Length == 0) { Logger.Log(Logger.LogChannel.Warn, () => "Legacy UnpatchAll was called with harmonyID=\"\" which is an invalid id. Skipping execution of UnpatchAll"); } else { UnpatchID(harmonyID); } } public void Unpatch(MethodBase original, HarmonyPatchType type, string harmonyID = "*") { CreateProcessor(original).Unpatch(type, harmonyID); } public void Unpatch(MethodBase original, MethodInfo patch) { CreateProcessor(original).Unpatch(patch); } public static bool HasAnyPatches(string harmonyID) { return (from original in GetAllPatchedMethods() select GetPatchInfo(original)).Any((Patches info) => info.Owners.Contains(harmonyID)); } public static Patches GetPatchInfo(MethodBase method) { return PatchProcessor.GetPatchInfo(method); } public IEnumerable<MethodBase> GetPatchedMethods() { return from original in GetAllPatchedMethods() where GetPatchInfo(original).Owners.Contains(Id) select original; } public static IEnumerable<MethodBase> GetAllPatchedMethods() { return PatchProcessor.GetAllPatchedMethods(); } public static MethodBase GetOriginalMethod(MethodInfo replacement) { if (replacement == null) { throw new ArgumentNullException("replacement"); } return PatchManager.GetOriginal(replacement); } public static MethodBase GetMethodFromStackframe(StackFrame frame) { if (frame == null) { throw new ArgumentNullException("frame"); } return PatchManager.FindReplacement(frame) ?? frame.GetMethod(); } public static MethodBase GetOriginalMethodFromStackframe(StackFrame frame) { MethodBase methodBase = GetMethodFromStackframe(frame); if (methodBase is MethodInfo replacement) { methodBase = GetOriginalMethod(replacement) ?? methodBase; } return methodBase; } public static Dictionary<string, Version> VersionInfo(out Version currentVersion) { return PatchProcessor.VersionInfo(out currentVersion); } public static Harmony CreateAndPatchAll(Type type, string harmonyInstanceId = null) { Harmony harmony = new Harmony(harmonyInstanceId ?? $"harmony-auto-{Guid.NewGuid()}"); harmony.PatchAll(type); return harmony; } public static Harmony CreateAndPatchAll(Assembly assembly, string harmonyInstanceId = null) { Harmony harmony = new Harmony(harmonyInstanceId ?? $"harmony-auto-{Guid.NewGuid()}"); harmony.PatchAll(assembly); return harmony; } } [Serializable] public class HarmonyException : Exception { private Dictionary<int, CodeInstruction> instructions = new Dictionary<int, CodeInstruction>(); private int errorOffset = -1; internal HarmonyException() { } internal HarmonyException(string message) : base(message) { } internal HarmonyException(string message, Exception innerException) : base(message, innerException) { } protected HarmonyException(SerializationInfo serializationInfo, StreamingContext streamingContext) { throw new NotImplementedException(); } internal HarmonyException(Exception innerException, Dictionary<int, CodeInstruction> instructions, int errorOffset) : base("IL Compile Error", innerException) { this.instructions = instructions; this.errorOffset = errorOffset; } internal static Exception Create(Exception ex, MethodBody body) { if (ex is HarmonyException ex2) { Dictionary<int, CodeInstruction> dictionary = ex2.instructions; if (dictionary != null && dictionary.Count > 0 && ex2.errorOffset >= 0) { return ex; } } Match match = Regex.Match(ex.Message.TrimEnd(Array.Empty<char>()), "(?:Reason: )?Invalid IL code in.+: IL_(\\d{4}): (.+)$"); if (!match.Success) { return new HarmonyException("IL Compile Error (unknown location)", ex); } Dictionary<int, CodeInstruction> dictionary2 = ILManipulator.GetInstructions(body) ?? new Dictionary<int, CodeInstruction>(); int num = int.Parse(match.Groups[1].Value, NumberStyles.HexNumber); Regex.Replace(match.Groups[2].Value, " {2,}", " "); if (ex is HarmonyException ex3) { if (dictionary2.Count != 0) { ex3.instructions = dictionary2; ex3.errorOffset = num; } return ex3; } return new HarmonyException(ex, dictionary2, num); } public List<KeyValuePair<int, CodeInstruction>> GetInstructionsWithOffsets() { return instructions.OrderBy((KeyValuePair<int, CodeInstruction> ins) => ins.Key).ToList(); } public List<CodeInstruction> GetInstructions() { return (from ins in instructions orderby ins.Key select ins.Value).ToList(); } public int GetErrorOffset() { return errorOffset; } public int GetErrorIndex() { if (instructions.TryGetValue(errorOffset, out var value)) { return GetInstructions().IndexOf(value); } return -1; } } public static class HarmonyGlobalSettings { public static bool DisallowLegacyGlobalUnpatchAll { get; set; } } public class HarmonyMethod { public MethodInfo method; public Type declaringType; public string methodName; public MethodType? methodType; public Type[] argumentTypes; public int priority = -1; public string[] before; public string[] after; public HarmonyReversePatchType? reversePatchType; public bool? debug; public string debugEmitPath; public bool nonVirtualDelegate; public bool? wrapTryCatch; public HarmonyMethod() { } private void ImportMethod(MethodInfo theMethod) { if ((object)theMethod == null) { throw new ArgumentNullException("theMethod", "Harmony method is null (did you target a wrong or missing method?)"); } if (!theMethod.IsStatic) { throw new ArgumentException("Harmony method must be static", "theMethod"); } method = theMethod; List<HarmonyMethod> fromMethod = HarmonyMethodExtensions.GetFromMethod(method); if (fromMethod != null) { Merge(fromMethod).CopyTo(this); } } public HarmonyMethod(MethodInfo method) { if ((object)method == null) { throw new ArgumentNullException("method"); } ImportMethod(method); } public HarmonyMethod(MethodInfo method, int priority = -1, string[] before = null, string[] after = null, bool? debug = null) { if ((object)method == null) { throw new ArgumentNullException("method"); } ImportMethod(method); this.priority = priority; this.before = before; this.after = after; this.debug = debug; } public HarmonyMethod(Type methodType, string methodName, Type[] argumentTypes = null) { MethodInfo methodInfo = AccessTools.Method(methodType, methodName, argumentTypes); if ((object)methodInfo == null) { throw new ArgumentException($"Cannot not find method for type {methodType} and name {methodName} and parameters {argumentTypes?.Description()}"); } ImportMethod(methodInfo); } public static List<string> HarmonyFields() { return (from s in AccessTools.GetFieldNames(typeof(HarmonyMethod)) where s != "method" select s).ToList(); } public static HarmonyMethod Merge(List<HarmonyMethod> attributes) { return Merge((IEnumerable<HarmonyMethod>)attributes); } internal static HarmonyMethod Merge(IEnumerable<HarmonyMethod> attributes) { HarmonyMethod harmonyMethod = new HarmonyMethod(); if (attributes == null) { return harmonyMethod; } Traverse resultTrv = Traverse.Create(harmonyMethod); attributes.Do(delegate(HarmonyMethod attribute) { Traverse trv = Traverse.Create(attribute); HarmonyFields().ForEach(delegate(string f) { object value = trv.Field(f).GetValue(); if (value != null && (f != "priority" || (int)value != -1)) { HarmonyMethodExtensions.SetValue(resultTrv, f, value); } }); }); return harmonyMethod; } public override string ToString() { string result = ""; Traverse trv = Traverse.Create(this); HarmonyFields().ForEach(delegate(string f) { if (result.Length > 0) { result += ", "; } result += $"{f}={trv.Field(f).GetValue()}"; }); return "HarmonyMethod[" + result + "]"; } internal string Description() { string text = (((object)declaringType != null) ? declaringType.FullDescription() : "undefined"); string text2 = methodName ?? "undefined"; string text3 = (methodType.HasValue ? methodType.Value.ToString() : "undefined"); string text4 = ((argumentTypes != null) ? argumentTypes.Description() : "undefined"); return "(class=" + text + ", methodname=" + text2 + ", type=" + text3 + ", args=" + text4 + ")"; } internal Type GetDeclaringType() { return declaringType; } internal Type[] GetArgumentList() { return argumentTypes ?? EmptyType.NoArgs; } } internal static class EmptyType { internal static readonly Type[] NoArgs = new Type[0]; } public static class HarmonyMethodExtensions { internal static void SetValue(Traverse trv, string name, object val) { if (val != null) { Traverse traverse = trv.Field(name); if (name == "methodType" || name == "reversePatchType") { val = Enum.ToObject(Nullable.GetUnderlyingType(traverse.GetValueType()), (int)val); } traverse.SetValue(val); } } public static void CopyTo(this HarmonyMethod from, HarmonyMethod to) { if (to == null) { return; } Traverse fromTrv = Traverse.Create(from); Traverse toTrv = Traverse.Create(to); HarmonyMethod.HarmonyFields().ForEach(delegate(string f) { object value = fromTrv.Field(f).GetValue(); if (value != null) { SetValue(toTrv, f, value); } }); } public static HarmonyMethod Clone(this HarmonyMethod original) { HarmonyMethod harmonyMethod = new HarmonyMethod(); original.CopyTo(harmonyMethod); return harmonyMethod; } public static HarmonyMethod Merge(this HarmonyMethod master, HarmonyMethod detail) { if (detail == null) { return master; } HarmonyMethod harmonyMethod = new HarmonyMethod(); Traverse resultTrv = Traverse.Create(harmonyMethod); Traverse masterTrv = Traverse.Create(master); Traverse detailTrv = Traverse.Create(detail); HarmonyMethod.HarmonyFields().ForEach(delegate(string f) { object value = masterTrv.Field(f).GetValue(); object value2 = detailTrv.Field(f).GetValue(); if (f != "priority" || (int)value2 != -1) { SetValue(resultTrv, f, value2 ?? value); } }); return harmonyMethod; } private static HarmonyMethod GetHarmonyMethodInfo(object attribute) { FieldInfo field = attribute.GetType().GetField("info", AccessTools.all); if ((object)field == null) { return null; } if (field.FieldType.FullName != typeof(HarmonyMethod).FullName) { return null; } return AccessTools.MakeDeepCopy<HarmonyMethod>(field.GetValue(attribute)); } public static List<HarmonyMethod> GetFromType(Type type) { return (from attr in type.GetCustomAttributes(inherit: true) select GetHarmonyMethodInfo(attr) into info where info != null select info).ToList(); } public static HarmonyMethod GetMergedFromType(Type type) { return HarmonyMethod.Merge(GetFromType(type)); } public static List<HarmonyMethod> GetFromMethod(MethodBase method) { return (from attr in method.GetCustomAttributes(inherit: true) select GetHarmonyMethodInfo(attr) into info where info != null select info).ToList(); } public static HarmonyMethod GetMergedFromMethod(MethodBase method) { return HarmonyMethod.Merge(GetFromMethod(method)); } } public class InlineSignature : ICallSiteGenerator { public class ModifierType { public bool IsOptional; public Type Modifier; public object Type; public override string ToString() { return ((Type is Type type) ? type.FullDescription() : Type?.ToString()) + " mod" + (IsOptional ? "opt" : "req") + "(" + Modifier?.FullDescription() + ")"; } internal TypeReference ToTypeReference(ModuleDefinition module) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown if (!IsOptional) { return (TypeReference)new RequiredModifierType(module.ImportReference(Modifier), GetTypeReference(module, Type)); } return (TypeReference)new OptionalModifierType(module.ImportReference(Modifier), GetTypeReference(module, Type)); } } public bool HasThis { get; set; } public bool ExplicitThis { get; set; } public CallingConvention CallingConvention { get; set; } = CallingConvention.Winapi; public List<object> Parameters { get; set; } = new List<object>(); public object ReturnType { get; set; } = typeof(void); public override string ToString() { return ((ReturnType is Type type) ? type.FullDescription() : ReturnType?.ToString()) + " (" + Parameters.Join((object p) => (!(p is Type type2)) ? p?.ToString() : type2.FullDescription()) + ")"; } internal static TypeReference GetTypeReference(ModuleDefinition module, object param) { if (!(param is Type type)) { if (!(param is InlineSignature inlineSignature)) { if (param is ModifierType modifierType) { return modifierType.ToTypeReference(module); } throw new NotSupportedException($"Unsupported inline signature parameter type: {param} ({param?.GetType().FullDescription()})"); } return (TypeReference)(object)inlineSignature.ToFunctionPointer(module); } return module.ImportReference(type); } CallSite ICallSiteGenerator.ToCallSite(ModuleDefinition module) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown CallSite val = new CallSite(GetTypeReference(module, ReturnType)) { HasThis = HasThis, ExplicitThis = ExplicitThis, CallingConvention = (MethodCallingConvention)(byte)((byte)CallingConvention - 1) }; foreach (object parameter in Parameters) { val.Parameters.Add(new ParameterDefinition(GetTypeReference(module, parameter))); } return val; } private FunctionPointerType ToFunctionPointer(ModuleDefinition module) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown FunctionPointerType val = new FunctionPointerType { ReturnType = GetTypeReference(module, ReturnType), HasThis = HasThis, ExplicitThis = ExplicitThis, CallingConvention = (MethodCallingConvention)(byte)((byte)CallingConvention - 1) }; foreach (object parameter in Parameters) { val.Parameters.Add(new ParameterDefinition(GetTypeReference(module, parameter))); } return val; } } internal static class PatchInfoSerialization { private class Binder : SerializationBinder { public override Type BindToType(string assemblyName, string typeName) { Type[] array = new Type[3] { typeof(PatchInfo), typeof(Patch[]), typeof(Patch) }; foreach (Type type in array) { if (typeName == type.FullName) { return type; } } return Type.GetType($"{typeName}, {assemblyName}"); } } internal static byte[] Serialize(this PatchInfo patchInfo) { using MemoryStream memoryStream = new MemoryStream(); new BinaryFormatter().Serialize(memoryStream, patchInfo); return memoryStream.GetBuffer(); } internal static PatchInfo Deserialize(byte[] bytes) { BinaryFormatter obj = new BinaryFormatter { Binder = new Binder() }; MemoryStream serializationStream = new MemoryStream(bytes); return (PatchInfo)obj.Deserialize(serializationStream); } internal static int PriorityComparer(object obj, int index, int priority) { Traverse traverse = Traverse.Create(obj); int value = traverse.Field("priority").GetValue<int>(); int value2 = traverse.Field("index").GetValue<int>(); if (priority != value) { return -priority.CompareTo(value); } return index.CompareTo(value2); } } [Serializable] public class PatchInfo { public Patch[] prefixes = new Patch[0]; public Patch[] postfixes = new Patch[0]; public Patch[] transpilers = new Patch[0]; public Patch[] finalizers = new Patch[0]; public Patch[] ilmanipulators = new Patch[0]; public bool Debugging { get { if (!prefixes.Any((Patch p) => p.debug) && !postfixes.Any((Patch p) => p.debug) && !transpilers.Any((Patch p) => p.debug) && !finalizers.Any((Patch p) => p.debug)) { return ilmanipulators.Any((Patch p) => p.debug); } return true; } } public string[] DebugEmitPaths => (from p in prefixes.Concat(postfixes).Concat(transpilers).Concat(finalizers) .Concat(ilmanipulators) select p.debugEmitPath into p where p != null select p).ToArray(); internal void AddPrefixes(string owner, params HarmonyMethod[] methods) { prefixes = Add(owner, methods, prefixes); } [Obsolete("This method only exists for backwards compatibility since the class is public.")] public void AddPrefix(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug) { AddPrefixes(owner, new HarmonyMethod(patch, priority, before, after, debug)); } public void RemovePrefix(string owner) { prefixes = Remove(owner, prefixes); } internal void AddPostfixes(string owner, params HarmonyMethod[] methods) { postfixes = Add(owner, methods, postfixes); } [Obsolete("This method only exists for backwards compatibility since the class is public.")] public void AddPostfix(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug) { AddPostfixes(owner, new HarmonyMethod(patch, priority, before, after, debug)); } public void RemovePostfix(string owner) { postfixes = Remove(owner, postfixes); } internal void AddTranspilers(string owner, params HarmonyMethod[] methods) { transpilers = Add(owner, methods, transpilers); } [Obsolete("This method only exists for backwards compatibility since the class is public.")] public void AddTranspiler(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug) { AddTranspilers(owner, new HarmonyMethod(patch, priority, before, after, debug)); } public void RemoveTranspiler(string owner) { transpilers = Remove(owner, transpilers); } internal void AddFinalizers(string owner, params HarmonyMethod[] methods) { finalizers = Add(owner, methods, finalizers); } [Obsolete("This method only exists for backwards compatibility since the class is public.")] public void AddFinalizer(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug) { AddFinalizers(owner, new HarmonyMethod(patch, priority, before, after, debug)); } public void RemoveFinalizer(string owner) { finalizers = Remove(owner, finalizers); } internal void AddILManipulators(string owner, params HarmonyMethod[] methods) { ilmanipulators = Add(owner, methods, ilmanipulators); } public void RemoveILManipulator(string owner) { ilmanipulators = Remove(owner, ilmanipulators); } public void RemovePatch(MethodInfo patch) { prefixes = prefixes.Where((Patch p) => p.PatchMethod != patch).ToArray(); postfixes = postfixes.Where((Patch p) => p.PatchMethod != patch).ToArray(); transpilers = transpilers.Where((Patch p) => p.PatchMethod != patch).ToArray(); finalizers = finalizers.Where((Patch p) => p.PatchMethod != patch).ToArray(); ilmanipulators = ilmanipulators.Where((Patch p) => p.PatchMethod != patch).ToArray(); } private static Patch[] Add(string owner, HarmonyMethod[] add, Patch[] current) { if (add.Length == 0) { return current; } int initialIndex = current.Length; return current.Concat(add.Where((HarmonyMethod method) => method != null).Select((HarmonyMethod method, int i) => new Patch(method, i + initialIndex, owner))).ToArray(); } private static Patch[] Remove(string owner, Patch[] current) { if (!(owner == "*")) { return current.Where((Patch patch) => patch.owner != owner).ToArray(); } return new Patch[0]; } } [Serializable] public class Patch : IComparable { public readonly int index; public readonly string owner; public readonly int priority; public readonly string[] before; public readonly string[] after; public readonly bool debug; public readonly string debugEmitPath; public readonly bool wrapTryCatch; [NonSerialized] private MethodInfo patchMethod; private int methodToken; private string moduleGUID; public MethodInfo PatchMethod { get { if ((object)patchMethod == null) { Module module = (from a in AppDomain.CurrentDomain.GetAssemblies() where !a.FullName.StartsWith("Microsoft.VisualStudio") select a).SelectMany((Assembly a) => a.GetLoadedModules()).First((Module m) => m.ModuleVersionId.ToString() == moduleGUID); patchMethod = (MethodInfo)module.ResolveMethod(methodToken); } return patchMethod; } set { patchMethod = value; methodToken = patchMethod.MetadataToken; moduleGUID = patchMethod.Module.ModuleVersionId.ToString(); } } public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after, bool debug) { if (patch is DynamicMethod) { throw new Exception("Cannot directly reference dynamic method \"" + patch.FullDescription() + "\" in Harmony. Use a factory method instead that will return the dynamic method."); } this.index = index; this.owner = owner; this.priority = ((priority == -1) ? 400 : priority); this.before = before ?? new string[0]; this.after = after ?? new string[0]; this.debug = debug; PatchMethod = patch; } public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after, bool debug, bool wrapTryCatch) { if (patch is DynamicMethod) { throw new Exception("Cannot directly reference dynamic method \"" + patch.FullDescription() + "\" in Harmony. Use a factory method instead that will return the dynamic method."); } this.index = index; this.owner = owner; this.priority = ((priority == -1) ? 400 : priority); this.before = before ?? new string[0]; this.after = after ?? new string[0]; this.debug = debug; this.wrapTryCatch = wrapTryCatch; PatchMethod = patch; } public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after, bool debug, bool wrapTryCatch, string debugEmitPath) { if (patch is DynamicMethod) { throw new Exception("Cannot directly reference dynamic method \"" + patch.FullDescription() + "\" in Harmony. Use a factory method instead that will return the dynamic method."); } this.index = index; this.owner = owner; this.priority = ((priority == -1) ? 400 : priority); this.before = before ?? new string[0]; this.after = after ?? new string[0]; this.debug = debug; this.debugEmitPath = debugEmitPath; this.wrapTryCatch = wrapTryCatch; PatchMethod = patch; } public Patch(HarmonyMethod method, int index, string owner) : this(method.method, index, owner, method.priority, method.before, method.after, method.debug.GetValueOrDefault(), method.wrapTryCatch.GetValueOrDefault(), method.debugEmitPath) { } public MethodInfo GetMethod(MethodBase original) { MethodInfo methodInfo = PatchMethod; if (methodInfo.ReturnType != typeof(DynamicMethod) && methodInfo.ReturnType != typeof(MethodInfo)) { return methodInfo; } if (!methodInfo.IsStatic) { return methodInfo; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length != 1) { return methodInfo; } if (parameters[0].ParameterType != typeof(MethodBase)) { return methodInfo; } return methodInfo.Invoke(null, new object[1] { original }) as MethodInfo; } public override bool Equals(object obj) { if (obj != null && obj is Patch) { return PatchMethod == ((Patch)obj).PatchMethod; } return false; } public int CompareTo(object obj) { return PatchInfoSerialization.PriorityComparer(obj, index, priority); } public override int GetHashCode() { return PatchMethod.GetHashCode(); } } public class PatchClassProcessor { private readonly Harmony instance; private readonly Type containerType; private readonly HarmonyMethod containerAttributes; private readonly Dictionary<Type, MethodInfo> auxilaryMethods; private readonly List<AttributePatch> patchMethods; private static readonly List<Type> auxilaryTypes = new List<Type> { typeof(HarmonyPrepare), typeof(HarmonyCleanup), typeof(HarmonyTargetMethod), typeof(HarmonyTargetMethods) }; public PatchClassProcessor(Harmony instance, Type type) : this(instance, type, allowUnannotatedType: false) { } public PatchClassProcessor(Harmony instance, Type type, bool allowUnannotatedType) { if (instance == null) { throw new ArgumentNullException("instance"); } if ((object)type == null) { throw new ArgumentNullException("type"); } this.instance = instance; containerType = type; List<HarmonyMethod> fromType = HarmonyMethodExtensions.GetFromType(type); if (!allowUnannotatedType && (fromType == null || fromType.Count == 0)) { return; } containerAttributes = HarmonyMethod.Merge(fromType); MethodType? methodType = containerAttributes.methodType; if (!methodType.HasValue) { containerAttributes.methodType = MethodType.Normal; } auxilaryMethods = new Dictionary<Type, MethodInfo>(); foreach (Type auxilaryType in auxilaryTypes) { MethodInfo patchMethod = PatchTools.GetPatchMethod(containerType, auxilaryType.FullName); if ((object)patchMethod != null) { auxilaryMethods[auxilaryType] = patchMethod; } } patchMethods = PatchTools.GetPatchMethods(containerType, containerAttributes.GetDeclaringType() != null); foreach (AttributePatch patchMethod2 in patchMethods) { MethodInfo method = patchMethod2.info.method; patchMethod2.info = containerAttributes.Merge(patchMethod2.info); patchMethod2.info.method = method; } } public List<MethodInfo> Patch() { if (containerAttributes == null) { return null; } Exception exception = null; if (!RunMethod<HarmonyPrepare, bool>(defaultIfNotExisting: true, defaultIfFailing: false, null, Array.Empty<object>())) { RunMethod<HarmonyCleanup>(ref exception, Array.Empty<object>()); ReportException(exception, null); return new List<MethodInfo>(); } List<MethodInfo> result = new List<MethodInfo>(); MethodBase lastOriginal = null; try { List<MethodBase> bulkMethods = GetBulkMethods(); if (bulkMethods.Count == 1) { lastOriginal = bulkMethods[0]; } ReversePatch(ref lastOriginal); result = ((bulkMethods.Count > 0) ? BulkPatch(bulkMethods, ref lastOriginal) : PatchWithAttributes(ref lastOriginal)); } catch (Exception ex) { exception = ex; } RunMethod<HarmonyCleanup>(ref exception, new object[1] { exception }); ReportException(exception, lastOriginal); return result; } private void ReversePatch(ref MethodBase lastOriginal) { for (int i = 0; i < patchMethods.Count; i++) { AttributePatch attributePatch = patchMethods[i]; if (attributePatch.type == HarmonyPatchType.ReversePatch) { MethodBase originalMethod = attributePatch.info.GetOriginalMethod(); if ((object)originalMethod != null) { lastOriginal = originalMethod; } ReversePatcher reversePatcher = instance.CreateReversePatcher(lastOriginal, attributePatch.info); lock (PatchProcessor.locker) { reversePatcher.Patch(); } } } } private List<MethodInfo> BulkPatch(List<MethodBase> originals, ref MethodBase lastOriginal) { PatchJobs<MethodInfo> patchJobs = new PatchJobs<MethodInfo>(); for (int i = 0; i < originals.Count; i++) { lastOriginal = originals[i]; PatchJobs<MethodInfo>.Job job = patchJobs.GetJob(lastOriginal); foreach (AttributePatch patchMethod in patchMethods) { string text = "You cannot combine TargetMethod, TargetMethods or [HarmonyPatchAll] with individual annotations"; HarmonyMethod info = patchMethod.info; if (info.methodName != null) { throw new ArgumentException(text + " [" + info.methodName + "]"); } if (info.methodType.HasValue && info.methodType.Value != 0) { throw new ArgumentException($"{text} [{info.methodType}]"); } if (info.argumentTypes != null) { throw new ArgumentException(text + " [" + info.argumentTypes.Description() + "]"); } job.AddPatch(patchMethod); } } foreach (PatchJobs<MethodInfo>.Job job2 in patchJobs.GetJobs()) { lastOriginal = job2.original; ProcessPatchJob(job2); } return patchJobs.GetReplacements(); } private List<MethodInfo> PatchWithAttributes(ref MethodBase lastOriginal) { PatchJobs<MethodInfo> patchJobs = new PatchJobs<MethodInfo>(); foreach (AttributePatch patchMethod in patchMethods) { lastOriginal = patchMethod.info.GetOriginalMethod(); if ((object)lastOriginal == null) { throw new ArgumentException("Undefined targ
CityMonitor.dll
Decompiled a year agousing System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using CityMonitor.Systems; using Colossal.Annotations; using Colossal.UI.Binding; using Game; using Game.Common; using Game.UI; using HarmonyLib; using HookUILib.Core; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("CityMonitor")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("A little panel with the most important metrics of your city without having to browse around")] [assembly: AssemblyFileVersion("0.3.0.0")] [assembly: AssemblyInformationalVersion("0.3.0+4ff59b1edff402446d171bb9b6ff1ced204af784")] [assembly: AssemblyProduct("CityMonitor")] [assembly: AssemblyTitle("CityMonitor")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CityMonitor { [BepInPlugin("CityMonitor", "CityMonitor", "0.3.0")] public class Plugin : BaseUnityPlugin { private void Awake() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin CityMonitor is loaded!"); Harmony val = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "CityMonitor_Cities2Harmony"); MethodBase[] array = val.GetPatchedMethods().ToArray(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin CityMonitor made patches! Patched methods: " + array.Length)); MethodBase[] array2 = array; foreach (MethodBase methodBase in array2) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched method: " + methodBase.Module.Name + ":" + methodBase.Name)); } } } public class CityMonitorUI : UIExtension { public readonly string extensionID = "example.city_monitor"; public readonly string extensionContent; public readonly ExtensionType extensionType = (ExtensionType)0; public CityMonitorUI() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) extensionContent = ((UIExtension)this).LoadEmbeddedResource("CityMonitor.dist.bundle.js"); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "CityMonitor"; public const string PLUGIN_NAME = "CityMonitor"; public const string PLUGIN_VERSION = "0.3.0"; } } namespace CityMonitor.Systems { public record MeterSetting : IJsonWritable { public string label; public string eventName; public int index; public string gradientName; public bool isEnabled; public void Write(IJsonWriter writer) { writer.TypeBegin(GetType().FullName); writer.PropertyName("label"); writer.Write(label); writer.PropertyName("eventName"); writer.Write(eventName); writer.PropertyName("index"); writer.Write(index); writer.PropertyName("gradientName"); writer.Write(gradientName); writer.PropertyName("isEnabled"); writer.Write(isEnabled); writer.TypeEnd(); } } internal class CityMonitorUISystem : UISystemBase { private ImmutableDictionary<string, MeterSetting> meters; private string kGroup = "city_monitor"; protected override void OnCreate() { ((UISystemBase)this).OnCreate(); ImmutableDictionary<string, MeterSetting>.Builder builder = ImmutableDictionary.CreateBuilder<string, MeterSetting>(); AddMeter(builder, 0, "electricity", "Electricity Availability", "electricityInfo.electricityAvailability", "maxGood"); AddMeter(builder, 1, "water", "Water Availability", "waterInfo.waterAvailability", "maxGood"); AddMeter(builder, 2, "sewage", "Sewage", "waterInfo.sewageAvailability", "maxGood"); AddMeter(builder, 3, "landfill", "Landfill Usage", "garbageInfo.landfillAvailability", "maxGood"); AddMeter(builder, 4, "healthcare", "Healthcare Availability", "healthcareInfo.healthcareAvailability", "maxGood"); AddMeter(builder, 5, "health", "Average Health", "healthcareInfo.averageHealth", "maxGood"); AddMeter(builder, 6, "cemetery", "Cemetery Availability", "healthcareInfo.cemeteryAvailability", "maxGood"); AddMeter(builder, 7, "fire_hazard", "Fire Hazard", "fireAndRescueInfo.averageFireHazard", "minGood"); AddMeter(builder, 8, "crime", "Crime Rate", "policeInfo.averageCrimeProbability", "minGood"); AddMeter(builder, 9, "jail", "Jail Availability", "policeInfo.jailAvailability", "maxGood"); AddMeter(builder, 10, "elementary", "Elementary School Availability", "educationInfo.elementaryAvailability", "maxGood"); AddMeter(builder, 11, "highschool", "High School Availability", "educationInfo.highSchoolAvailability", "maxGood"); AddMeter(builder, 12, "collage", "College Availability", "educationInfo.collegeAvailability", "maxGood"); AddMeter(builder, 13, "university", "University Availability", "educationInfo.universityAvailability", "maxGood"); meters = builder.ToImmutableDictionary(); ((UISystemBase)this).AddUpdateBinding((IUpdateBinding)(object)new GetterValueBinding<ImmutableDictionary<string, MeterSetting>>(kGroup, "meters", (Func<ImmutableDictionary<string, MeterSetting>>)(() => meters), (IWriter<ImmutableDictionary<string, MeterSetting>>)(object)new MyDictionaryWriter<string, MeterSetting>(), (EqualityComparer<ImmutableDictionary<string, MeterSetting>>)null)); ((UISystemBase)this).AddBinding((IBinding)(object)new TriggerBinding<string, bool>(kGroup, "toggle_visibility", (Action<string, bool>)ToggleVisibility, (IReader<string>)null, (IReader<bool>)null)); } private void AddMeter(ImmutableDictionary<string, MeterSetting>.Builder builder, int index, string key, string label, string eventName, string gradient) { builder.Add(key, new MeterSetting { label = label, eventName = eventName, index = index, gradientName = gradient, isEnabled = true }); } private void ToggleVisibility(string key, bool newValue) { MeterSetting meterSetting = meters[key]; meterSetting.isEnabled = newValue; ImmutableDictionary<string, MeterSetting> immutableDictionary = meters.Remove(key).Add(key, meterSetting); meters = immutableDictionary; } } public class MyDictionaryWriter<K, V> : IWriter<IDictionary<K, V>> { [NotNull] private readonly IWriter<K> m_KeyWriter; [NotNull] private readonly IWriter<V> m_ValueWriter; public MyDictionaryWriter(IWriter<K> keyWriter = null, IWriter<V> valueWriter = null) { m_KeyWriter = keyWriter ?? ValueWriters.Create<K>(); m_ValueWriter = valueWriter ?? ValueWriters.Create<V>(); } public void Write(IJsonWriter writer, IDictionary<K, V> value) { if (value != null) { JsonWriterExtensions.MapBegin(writer, value.Count); foreach (KeyValuePair<K, V> item in value) { m_KeyWriter.Write(writer, item.Key); if ((object)item.Value is IDictionary<K, V> value2) { Write(writer, value2); } else { ((IWriter<?>)(object)m_ValueWriter).Write(writer, item.Value); } } writer.MapEnd(); return; } writer.WriteNull(); throw new ArgumentNullException("value", "Null passed to non-nullable dictionary writer"); } } } namespace CityMonitor.Patches { [HarmonyPatch(typeof(SystemOrder))] public static class SystemOrderPatch { [HarmonyPatch("Initialize")] [HarmonyPostfix] public static void Postfix(UpdateSystem updateSystem) { updateSystem.UpdateAt<CityMonitorUISystem>((SystemUpdatePhase)22); } } }