Added 1.2 and 1.5 support, mod icon, DefaultValue/Key for FishSet/Table

This commit is contained in:
bbradson
2024-04-14 20:06:00 +02:00
parent c584f58dfd
commit 64152cef07
60 changed files with 643 additions and 251 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3
View File
@@ -3,10 +3,13 @@
<name>Fishery - Modding Library</name> <name>Fishery - Modding Library</name>
<packageId>bs.fishery</packageId> <packageId>bs.fishery</packageId>
<supportedVersions> <supportedVersions>
<li>1.2</li>
<li>1.3</li> <li>1.3</li>
<li>1.4</li> <li>1.4</li>
<li>1.5</li>
</supportedVersions> </supportedVersions>
<author>bradson</author> <author>bradson</author>
<modIconPath IgnoreIfNoMatchingField="True">FisheryLib/ModIcon</modIconPath>
<url>https://github.com/bbradson/fishery</url> <url>https://github.com/bbradson/fishery</url>
<loadBefore> <loadBefore>
<li>Ludeon.RimWorld</li> <li>Ludeon.RimWorld</li>
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+1 -1
View File
@@ -68,7 +68,7 @@ dotnet_naming_rule.public_or_internal_field_should_be_camel_case.style = camel_c
# Symbol specifications # Symbol specifications
dotnet_naming_symbols.constant.applicable_kinds = field, local dotnet_naming_symbols.constant.applicable_kinds = field, local
dotnet_naming_symbols.constant.applicable_accessibilities = * dotnet_naming_symbols.constant.applicable_accessibilities = private, local
dotnet_naming_symbols.constant.required_modifiers = const dotnet_naming_symbols.constant.required_modifiers = const
dotnet_naming_symbols.private_or_protected_field.applicable_kinds = field dotnet_naming_symbols.private_or_protected_field.applicable_kinds = field
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutDir>..\..\1.2\Assemblies\</OutDir>
<Copyright>Copyright (c) 2024 Bradson</Copyright>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DefineConstants>DEBUG;V1_2</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DefineConstants>V1_2</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.2.*" />
<PackageReference Include="Lib.Harmony" Version="2.2.*" ExcludeAssets="runtime" />
<PackageReference Include="JetBrains.Annotations" Version="2023.*" Aliases="nuget" ExcludeAssets="runtime" />
</ItemGroup>
</Project>
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutDir>..\..\1.3\Assemblies\</OutDir>
<Copyright>Copyright (c) 2022 Bradson</Copyright>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DefineConstants>DEBUG;V1_3</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DefineConstants>V1_3</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.3.*" />
<PackageReference Include="Lib.Harmony" Version="2.2.*" ExcludeAssets="runtime" />
</ItemGroup>
</Project>
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutDir>..\..\1.4\Assemblies\</OutDir>
<Copyright>Copyright (c) 2022 Bradson</Copyright>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DefineConstants>DEBUG;V1_4</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DefineConstants>V1_4</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.4.*" />
<PackageReference Include="Lib.Harmony" Version="2.2.*" ExcludeAssets="runtime" />
</ItemGroup>
</Project>
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutDir>..\..\1.5\Assemblies\</OutDir>
<Copyright>Copyright (c) 2024 Bradson</Copyright>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DefineConstants>DEBUG;V1_5</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DefineConstants>V1_5</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.5.*" />
<PackageReference Include="Lib.Harmony" Version="2.3.*" ExcludeAssets="runtime" />
</ItemGroup>
</Project>
-1
View File
@@ -5,7 +5,6 @@
global using static FisheryLib.Aliases; global using static FisheryLib.Aliases;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
-1
View File
@@ -5,7 +5,6 @@
// https://github.com/CommunityToolkit/dotnet/blob/main/CommunityToolkit.HighPerformance/Extensions/BoolExtensions.cs // https://github.com/CommunityToolkit/dotnet/blob/main/CommunityToolkit.HighPerformance/Extensions/BoolExtensions.cs
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
@@ -4,7 +4,6 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/. // file, You can obtain one at https://mozilla.org/MPL/2.0/.
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using Mono.Cecil; using Mono.Cecil;
using Mono.Collections.Generic; using Mono.Collections.Generic;
+11 -11
View File
@@ -9,7 +9,6 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using FisheryLib.Collections; using FisheryLib.Collections;
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
@@ -77,8 +76,8 @@ public static class CollectionExtensions
return array; return array;
} }
public static Telement[] ToArray<Tenumerable, Telement>(this Tenumerable enumerable, Telement[] destination) public static TElement[] ToArray<TEnumerable, TElement>(this TEnumerable enumerable, TElement[] destination)
where Tenumerable : IList<Telement> where TEnumerable : IList<TElement>
{ {
Guard.IsNotNull(destination); Guard.IsNotNull(destination);
@@ -112,9 +111,9 @@ public static class CollectionExtensions
} }
} }
public static void Fill<Telement, Tcollection>(this Telement[] array, Tcollection collection, int startIndex = 0, public static void Fill<TElement, TCollection>(this TElement[] array, TCollection collection, int startIndex = 0,
int count = -1) int count = -1)
where Tcollection : IList<Telement> where TCollection : IList<TElement>
{ {
Guard.IsNotNull(collection); Guard.IsNotNull(collection);
@@ -442,7 +441,7 @@ public static class CollectionExtensions
continue; continue;
// predicate might modify collection, turning a ref invalid // predicate might modify collection, turning a ref invalid
var keyValuePair = new KeyValuePair<TKey,TValue>(entry.key, entry.value); var keyValuePair = new KeyValuePair<TKey, TValue>(entry.key, entry.value);
if (!predicate(keyValuePair)) if (!predicate(keyValuePair))
continue; continue;
@@ -544,10 +543,11 @@ public static class CollectionExtensions
list._version++; list._version++;
} }
public static void ReplaceContentsWith<T, V>(this List<T> list, [AllowNull] V collection) where V : ICollection<T> public static void ReplaceContentsWith<TThis, TOther>(this List<TThis> list, [AllowNull] TOther collection)
where TOther : ICollection<TThis>
{ {
if (typeof(V) == typeof(List<T>)) if (typeof(TOther) == typeof(List<TThis>))
list.ReplaceContentsWith(Unsafe.As<List<T>>(collection)); list.ReplaceContentsWith(Unsafe.As<List<TThis>>(collection));
if (ReferenceEquals(list, collection)) if (ReferenceEquals(list, collection))
return; return;
@@ -568,7 +568,7 @@ public static class CollectionExtensions
} }
else else
{ {
list._items = new T[collectionCount]; list._items = new TThis[collectionCount];
collection.CopyTo(list._items, 0); collection.CopyTo(list._items, 0);
list._size = collectionCount; list._size = collectionCount;
} }
@@ -723,7 +723,7 @@ public static class CollectionExtensions
public static void InsertFastUnordered<T>(this List<T> list, int index, T item) public static void InsertFastUnordered<T>(this List<T> list, int index, T item)
{ {
if ((uint) index > (uint) list._size) if ((uint)index > (uint)list._size)
ThrowHelper.ThrowArgumentOutOfRangeException(); ThrowHelper.ThrowArgumentOutOfRangeException();
if (list._size == list._items.Length) if (list._size == list._items.Length)
+45 -4
View File
@@ -7,6 +7,9 @@
// which itself is based on // which itself is based on
// https://probablydance.com/2018/05/28/a-new-fast-hash-table-in-response-to-googles-new-fast-hash-table/ // https://probablydance.com/2018/05/28/a-new-fast-hash-table-in-response-to-googles-new-fast-hash-table/
#if V1_2
extern alias nuget;
#endif
using System.Collections; using System.Collections;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@@ -14,7 +17,10 @@ using System.Runtime.InteropServices;
using FisheryLib.FunctionPointers; using FisheryLib.FunctionPointers;
using FisheryLib.Pools; using FisheryLib.Pools;
using FisheryLib.Utility; using FisheryLib.Utility;
using JetBrains.Annotations; #if V1_2
using CollectionAccessType = nuget::JetBrains.Annotations.CollectionAccessType;
using CollectionAccessAttribute = nuget::JetBrains.Annotations.CollectionAccessAttribute;
#endif
namespace FisheryLib.Collections; namespace FisheryLib.Collections;
@@ -42,6 +48,8 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
private float _maxLoadFactor = 0.5f; private float _maxLoadFactor = 0.5f;
private T _defaultValue = Internal.KeyUtility<T>.Default;
public int Version public int Version
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -65,6 +73,22 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
public bool IsReadOnly => false; public bool IsReadOnly => false;
/// <summary>
/// Empty FishSets have their entries set to a default value, causing fishSet.Contains(DefaultValue) to return
/// true. This property can be used for a check against this default, similar to a null. Unless set to a different
/// default through the FishSet constructor, for most reference types, the returned value is a static invalid
/// reference. Reference types implementing IEquatable or overriding Equals have null as default instead. Primitives
/// have all their bytes set to sbyte.MaxValue. Structs have their contents set according to previous rules.
/// </summary>
public T DefaultValue => _defaultValue;
public unsafe uint SizeEstimate
=> GetType().ComputeManagedObjectSizeEstimate()
+ ((uint)sizeof(T) * (uint)_buckets.Length)
+ ((_tails.Length + 1u) >> 1);
public uint CollisionCount => (uint)GetTailingEntriesCount();
public event Action<T>? public event Action<T>?
EntryAdded, EntryAdded,
EntryRemoved; EntryRemoved;
@@ -112,6 +136,19 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
public FishSet(int minimumCapacity) => Initialize(minimumCapacity); public FishSet(int minimumCapacity) => Initialize(minimumCapacity);
/// <summary>
/// Initialize a new FishSet
/// </summary>
/// <param name="minimumCapacity">The minimum capacity of the backing array</param>
/// <param name="defaultValue">
/// The default value for empty entries. Contains() returns true for this value when empty
/// </param>
public FishSet(int minimumCapacity, T defaultValue)
{
_defaultValue = defaultValue;
Initialize(minimumCapacity);
}
[MemberNotNull(nameof(_buckets))] [MemberNotNull(nameof(_buckets))]
[MemberNotNull(nameof(_tails))] [MemberNotNull(nameof(_tails))]
private void Initialize(int minimumCapacity = 0) private void Initialize(int minimumCapacity = 0)
@@ -120,6 +157,7 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
// Mathf.NextPowerOfTwo(minimumCapacity); // Mathf.NextPowerOfTwo(minimumCapacity);
_buckets = new T?[minimumCapacity]; _buckets = new T?[minimumCapacity];
Array.Fill(_buckets, _defaultValue);
_tails = new((uint)minimumCapacity); _tails = new((uint)minimumCapacity);
_bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length); _bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length);
_wrapAroundMask = _buckets.Length - 1; _wrapAroundMask = _buckets.Length - 1;
@@ -167,7 +205,7 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
private void SetBucketEmpty(int index) private void SetBucketEmpty(int index)
{ {
_buckets[index] = default; _buckets[index] = _defaultValue;
_tails.SetEmpty(index); _tails.SetEmpty(index);
} }
@@ -356,7 +394,7 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
{ {
ref var tailingBucket = ref _buckets[tailIndex]; ref var tailingBucket = ref _buckets[tailIndex];
tailingEntriesList.Add(tailingBucket!); tailingEntriesList.Add(tailingBucket!);
tailingBucket = default; tailingBucket = _defaultValue;
if (HasTail(tailIndex)) if (HasTail(tailIndex))
{ {
@@ -409,6 +447,7 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
_tails = new((uint)_buckets.Length << 1); _tails = new((uint)_buckets.Length << 1);
_buckets = new T?[_buckets.Length << 1]; _buckets = new T?[_buckets.Length << 1];
Array.Fill(_buckets, _defaultValue);
_bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length); _bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length);
_wrapAroundMask = _buckets.Length - 1; _wrapAroundMask = _buckets.Length - 1;
@@ -579,7 +618,7 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
if (_buckets is null) if (_buckets is null)
Initialize(); Initialize();
Array.Clear(_buckets, 0, _buckets.Length); Array.Fill(_buckets, Internal.KeyUtility<T>.Default);
_tails.Reset(); _tails.Reset();
_count = 0; _count = 0;
@@ -660,6 +699,8 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
private NibbleArray _values = new(length); private NibbleArray _values = new(length);
public uint Length => _values.Length;
public uint this[uint index] public uint this[uint index]
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
+85 -10
View File
@@ -7,15 +7,22 @@
// which itself is based on // which itself is based on
// https://probablydance.com/2018/05/28/a-new-fast-hash-table-in-response-to-googles-new-fast-hash-table/ // https://probablydance.com/2018/05/28/a-new-fast-hash-table-in-response-to-googles-new-fast-hash-table/
#if V1_2
extern alias nuget;
#endif
using System.Collections; using System.Collections;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security; using System.Security;
using FisheryLib.Collections.Internal;
using FisheryLib.FunctionPointers; using FisheryLib.FunctionPointers;
using FisheryLib.Pools; using FisheryLib.Pools;
using FisheryLib.Utility; using FisheryLib.Utility;
using JetBrains.Annotations; #if V1_2
using CollectionAccessType = nuget::JetBrains.Annotations.CollectionAccessType;
using CollectionAccessAttribute = nuget::JetBrains.Annotations.CollectionAccessAttribute;
#endif
namespace FisheryLib.Collections; namespace FisheryLib.Collections;
@@ -46,6 +53,8 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
private float _maxLoadFactor = 0.5f; private float _maxLoadFactor = 0.5f;
private Entry _defaultEntry = Entry.Default;
public KeyCollection Keys => new(this); public KeyCollection Keys => new(this);
public ValueCollection Values => new(this); public ValueCollection Values => new(this);
@@ -65,6 +74,15 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
public bool IsReadOnly => false; public bool IsReadOnly => false;
/// <summary>
/// Empty FishTables have their entries set to a default value, causing fishTable.ContainsKey(DefaultKey) to return
/// true. This property can be used for a check against this default, similar to a null. Unless set to a different
/// default through the FishTable constructor, for most reference types, the returned value is a static invalid
/// reference. Reference types implementing IEquatable or overriding Equals have null as default instead. Primitives
/// have all their bytes set to sbyte.MaxValue. Structs have their contents set according to previous rules.
/// </summary>
public TKey DefaultKey => _defaultEntry.Key;
public unsafe uint SizeEstimate public unsafe uint SizeEstimate
=> GetType().ComputeManagedObjectSizeEstimate() => GetType().ComputeManagedObjectSizeEstimate()
+ ((uint)sizeof(Entry) * (uint)_buckets.Length) + ((uint)sizeof(Entry) * (uint)_buckets.Length)
@@ -227,6 +245,19 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
public FishTable(int minimumCapacity) => Initialize(minimumCapacity); public FishTable(int minimumCapacity) => Initialize(minimumCapacity);
/// <summary>
/// Initialize a new FishTable
/// </summary>
/// <param name="minimumCapacity">The minimum capacity of the backing array</param>
/// <param name="defaultKey">
/// The default key for empty entries. ContainsKey() returns true for this when empty
/// </param>
public FishTable(int minimumCapacity, TKey defaultKey)
{
_defaultEntry.Key = defaultKey;
Initialize(minimumCapacity);
}
[MemberNotNull(nameof(_buckets))] [MemberNotNull(nameof(_buckets))]
[MemberNotNull(nameof(_tails))] [MemberNotNull(nameof(_tails))]
private void Initialize(int minimumCapacity = 0) private void Initialize(int minimumCapacity = 0)
@@ -235,6 +266,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
// Mathf.NextPowerOfTwo(minimumCapacity); // Mathf.NextPowerOfTwo(minimumCapacity);
_buckets = new Entry[minimumCapacity]; _buckets = new Entry[minimumCapacity];
Array.Fill(_buckets, _defaultEntry);
_tails = new((uint)minimumCapacity); _tails = new((uint)minimumCapacity);
_bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length); _bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length);
_wrapAroundMask = _buckets.Length - 1; _wrapAroundMask = _buckets.Length - 1;
@@ -280,7 +312,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
private void SetBucketEmpty(int index) private void SetBucketEmpty(int index)
{ {
_buckets[index] = default; _buckets[index] = _defaultEntry;
_tails.SetEmpty(index); _tails.SetEmpty(index);
} }
@@ -400,8 +432,11 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
{ {
ref var bucket = ref buckets[bucketIndex]; ref var bucket = ref buckets[bucketIndex];
if (!_keyEqualityComparer(bucket.Key, default)) if (!CompareBytes(bucket.Key, _defaultEntry.Key)
&& !_keyEqualityComparer(bucket.Key, _defaultEntry.Key))
{
ThrowHelper.ThrowEmptyBucketKeyInvalidOperationException(bucketIndex, bucket); ThrowHelper.ThrowEmptyBucketKeyInvalidOperationException(bucketIndex, bucket);
}
if (bucket.Value.Equals<TValue>(default)) if (bucket.Value.Equals<TValue>(default))
return true; return true;
@@ -412,6 +447,43 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
return false; // no good workaround without performance hit return false; // no good workaround without performance hit
} }
private static unsafe bool CompareBytes(TKey a, TKey b)
{
var size = sizeof(TKey);
var iOffset = 0;
var i = 0;
do
{
var currentA = *((nint*)&a + iOffset);
var currentB = *((nint*)&b + iOffset);
if (size - i >= sizeof(nint))
{
if (currentA != currentB)
return false;
iOffset++;
i += sizeof(nint);
}
else
{
var remainingSize = size & sizeof(nint);
i = 0;
do
{
if ((byte)(currentA >> i) != (byte)(currentB >> i))
return false;
}
while (++i < remainingSize);
break;
}
}
while (i < size);
return size != 0;
}
private bool TryFindTailIndexAndReplace(in Entry entry, ref int bucketIndex, ReplaceBehaviour replaceBehaviour) private bool TryFindTailIndexAndReplace(in Entry entry, ref int bucketIndex, ReplaceBehaviour replaceBehaviour)
{ {
while (true) while (true)
@@ -498,7 +570,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
{ {
ref var tailingBucket = ref _buckets[tailIndex]; ref var tailingBucket = ref _buckets[tailIndex];
tailingEntriesList.Add(tailingBucket); tailingEntriesList.Add(tailingBucket);
tailingBucket = default; tailingBucket = _defaultEntry;
if (HasTail(tailIndex)) if (HasTail(tailIndex))
{ {
@@ -585,6 +657,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
_tails = new((uint)newSize); _tails = new((uint)newSize);
_buckets = new Entry[newSize]; _buckets = new Entry[newSize];
Array.Fill(_buckets, _defaultEntry);
_bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)newSize); _bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)newSize);
_wrapAroundMask = _buckets.Length - 1; _wrapAroundMask = _buckets.Length - 1;
@@ -1046,7 +1119,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
private void EmplaceWithTailsBackward(int entryIndex) private void EmplaceWithTailsBackward(int entryIndex)
{ {
if (IsBucketEmpty(entryIndex)) if (IsBucketEmpty(entryIndex))
Utility.Diagnostics.ThrowHelper.ThrowInvalidOperationException("Tried to emplace entry bucket"); Utility.Diagnostics.ThrowHelper.ThrowInvalidOperationException("Tried to emplace empty bucket");
while (true) while (true)
{ {
@@ -1225,7 +1298,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
if (_buckets is null) if (_buckets is null)
Initialize(); Initialize();
Array.Clear(_buckets, 0, _buckets.Length); Array.Fill(_buckets, _defaultEntry);
_tails.Reset(); _tails.Reset();
_count = 0; _count = 0;
@@ -1360,6 +1433,8 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
.Append<TValue>(Value) .Append<TValue>(Value)
.Append(" }").ToString(); .Append(" }").ToString();
} }
public static readonly Entry Default = new(KeyUtility<TKey>.Default, default);
} }
internal struct Tails(uint length) internal struct Tails(uint length)
@@ -1688,11 +1763,11 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
internal static void ThrowKeyNotFoundException<T>(T key) internal static void ThrowKeyNotFoundException<T>(T key)
{ {
Guard.IsNotNull(key); Guard.IsNotNull(key);
ThrowKeyNotFoundException((object)key); ThrowKeyNotFoundException((object?)key);
} }
[DoesNotReturn] [DoesNotReturn]
private static void ThrowKeyNotFoundException(object key) private static void ThrowKeyNotFoundException(object? key)
=> throw new KeyNotFoundException($"The given key '{key}' was not present in the dictionary."); => throw new KeyNotFoundException($"The given key '{key}' was not present in the dictionary.");
[DoesNotReturn] [DoesNotReturn]
@@ -1715,7 +1790,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
internal static bool ThrowAddingDuplicateWithKeyArgumentException<T>(T key) internal static bool ThrowAddingDuplicateWithKeyArgumentException<T>(T key)
{ {
Guard.IsNotNull(key); Guard.IsNotNull(key);
ThrowAddingDuplicateWithKeyArgumentException((object)key); ThrowAddingDuplicateWithKeyArgumentException((object?)key);
return true; return true;
} }
@@ -1782,7 +1857,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
} }
[DoesNotReturn] [DoesNotReturn]
private static void ThrowAddingDuplicateWithKeyArgumentException(object key) private static void ThrowAddingDuplicateWithKeyArgumentException(object? key)
=> throw new ArgumentException($"An item with the same key has already been added. Key: {key}"); => throw new ArgumentException($"An item with the same key has already been added. Key: {key}");
} }
} }
@@ -6,7 +6,6 @@
using System.Collections; using System.Collections;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib.Collections; namespace FisheryLib.Collections;
@@ -5,7 +5,6 @@
using System.Collections; using System.Collections;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
namespace FisheryLib.Collections; namespace FisheryLib.Collections;
@@ -0,0 +1,165 @@
// Copyright (c) 2022 bradson
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v.2.0.If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
namespace FisheryLib.Collections.Internal;
public static class KeyUtility<T>
{
public static readonly T Default = GetDefaultValue();
private static T GetDefaultValue()
{
var type = typeof(T);
var invalidKey = KeyUtility.GetDefaultValue(type);
if (!type.IsValueType)
return Unsafe.As<object?, T>(ref invalidKey);
return (T)invalidKey!;
}
}
public static class KeyUtility
{
public static readonly object InvalidObject = new();
public const ulong InvalidValue = 0x7F7F_7F7F_7F7F_7F7FUL;
public static readonly string InvalidString
= new(['\u7F7F', '\u7F7F', '\u7F7F', '\u7F7F', '\u7F7F', '\u7F7F', '\u7F7F', '\u7F7F']);
private static readonly ConcurrentDictionary<FieldInfo, Action<object>> _fieldSetters = [];
private static readonly ConcurrentDictionary<Type, object> _defaultValues = [];
private static readonly MethodInfo _genericMaxValueMethodDefinition
= methodof(GetMaxValue<ulong>).GetGenericMethodDefinition();
private static readonly FieldInfo _invalidFieldInfo = typeof(KeyUtility).GetField(nameof(InvalidObject));
public static object? GetDefaultValue(Type type)
{
if (type == typeof(string))
return InvalidString;
if (_defaultValues.TryGetValue(type, out var result))
return result;
if (!type.IsValueType)
{
return !type.IsAssignableTo(typeof(IEquatable<>), type)
&& type.GetMethod(nameof(object.Equals),
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, [typeof(object)],
Array.Empty<ParameterModifier>())?.DeclaringType
== typeof(object)
? InvalidObject
: null;
}
result = FormatterServices.GetUninitializedObject(type);
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
for (var i = 0; i < fields.Length; i++)
{
var field = fields[i];
var fieldType = field.FieldType;
if (fieldType.IsValueType)
{
if (AccessTools.IsValue(fieldType))
field.SetValue(result, GetMaxValue(fieldType));
else
GetFieldInvalidator(field)(result);
}
else
{
if (fieldType != typeof(string))
{
if (!fieldType.IsAssignableTo(typeof(IEquatable<>), fieldType))
GetFieldInvalidator(field)(result);
else
field.SetValue(result, null);
}
else
{
field.SetValue(result, InvalidString);
}
}
if (Unsafe.As<object, ulong>(ref result) > 0xFFFF_FFFF_FFFF)
Log.Error($"Detected invalid pointer with a value > 48 bit\n{new StackTrace(true)}");
}
_defaultValues.TryAdd(type, result);
return result;
}
private static object GetMaxValue(Type type)
{
if (!AccessTools.IsValue(type))
{
return ThrowHelper.ThrowArgumentException<object>($"Invalid type passed to KeyUtility.GetMaxValue: '{
type.FullDescription()}'. Only primitive structs are supported.");
}
var result = _genericMaxValueMethodDefinition.MakeGenericMethod(type).Invoke(null, null);
_defaultValues.TryAdd(type, result);
return result;
}
private static object GetMaxValue<T>() where T : struct
{
var maxValue = InvalidValue;
return Unsafe.As<ulong, T>(ref maxValue)!;
}
private static Action<object> GetFieldInvalidator(FieldInfo fieldInfo)
{
if (_fieldSetters.TryGetValue(fieldInfo, out var result))
return result;
var method = new DynamicMethod($"FisheryLib><::>UnsafeSetter<::><{fieldInfo.FullDescription()}", typeof(void),
[typeof(object)], typeof(KeyUtility), true);
var ilGenerator = method.GetILGenerator();
var fieldType = fieldInfo.FieldType;
var declaringType = fieldInfo.DeclaringType;
ilGenerator.Emit(FishTranspiler.Argument(0));
if (declaringType?.IsValueType ?? false)
ilGenerator.Emit(FishTranspiler.UnboxAddress(declaringType));
if (!fieldType.IsValueType)
{
ilGenerator.Emit(FishTranspiler.Field(_invalidFieldInfo));
ilGenerator.Emit(FishTranspiler.Call(methodof(Unsafe.As<object>).GetGenericMethodDefinition()
.MakeGenericMethod(fieldType)));
}
else
{
ilGenerator.Emit(FishTranspiler.Token(fieldType));
ilGenerator.Emit(FishTranspiler.Call(Type.GetTypeFromHandle));
ilGenerator.Emit(FishTranspiler.Call(AccessTools.IsValue(fieldType)
// ReSharper disable once RedundantCast
? (Func<Type, object?>)GetMaxValue
: GetDefaultValue));
ilGenerator.Emit(FishTranspiler.UnboxValue(fieldType));
}
ilGenerator.Emit(FishTranspiler.StoreField(fieldInfo));
ilGenerator.Emit(FishTranspiler.Return);
result = (Action<object>)method.CreateDelegate(typeof(Action<object>));
_fieldSetters.TryAdd(fieldInfo, result);
return result;
}
}
@@ -4,7 +4,6 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/. // file, You can obtain one at https://mozilla.org/MPL/2.0/.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib.Collections; namespace FisheryLib.Collections;
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
#pragma warning disable CS8777 #pragma warning disable CS8777
+2 -1
View File
@@ -4,8 +4,9 @@
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
#if V1_2
using JetBrains.Annotations; using JetBrains.Annotations;
using NotNullAttribute = System.Diagnostics.CodeAnalysis.NotNullAttribute; #endif
namespace FisheryLib.Utility.Diagnostics; namespace FisheryLib.Utility.Diagnostics;
+1 -1
View File
@@ -7,7 +7,7 @@ using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using JetBrains.Annotations;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace FisheryLib.Utility.Diagnostics; namespace FisheryLib.Utility.Diagnostics;
+93
View File
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<RootNamespace>FisheryLib</RootNamespace>
<AssemblyName>1Fishery</AssemblyName>
<Authors>bradson</Authors>
<TargetFramework>net48</TargetFramework>
<LangVersion>preview</LangVersion>
<PlatformTarget>AnyCPU</PlatformTarget>
<Optimize>true</Optimize>
<DebugSymbols>true</DebugSymbols>
<Nullable>enable</Nullable>
<EnableNETAnalyzers>True</EnableNETAnalyzers>
<AnalysisLevel>preview-recommended</AnalysisLevel>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>5</WarningLevel>
<DebugType>portable</DebugType>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<NoWarn>CA1000;CA1051;CA1305;CA1310;CA1707;CA1708;CA1710;CA1711;CA1716;CA1725;CA1852;CA2201;CS8500</NoWarn>
<BaseIntermediateOutputPath>obj\$(MSBuildProjectName)\$(Configuration)\</BaseIntermediateOutputPath>
<MSBuildProjectExtensionsPath>obj\$(MSBuildProjectName)\$(Configuration)\</MSBuildProjectExtensionsPath>
<DefaultItemExcludes>$(DefaultItemExcludes);obj/**/*.*</DefaultItemExcludes>
<PublicizerClearCacheOnClean>true</PublicizerClearCacheOnClean>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Zetrith.Prepatcher" Version="1.*" />
<PackageReference Include="PolySharp" Version="1.*" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.*" />
<PackageReference Include="Krafs.Publicizer" Version="2.*" />
<Publicize Include="Assembly-CSharp;0Harmony" IncludeVirtualMembers="false" />
<!-- DoNotPublicize Include="0Harmony:Mono.Collections.Generic.Collection`1" / -->
<DoNotPublicize Include="0Harmony:System.Memory`1" />
<DoNotPublicize Include="0Harmony:System.ReadOnlyMemory`1" />
<DoNotPublicize Include="0Harmony:System.Span`1" />
<DoNotPublicize Include="0Harmony:System.ReadOnlySpan`1" />
<DoNotPublicize Include="0Harmony:System.ThrowHelper" />
<DoNotPublicize Include="0Harmony:System.HashCode" />
<DoNotPublicize Include="0Harmony:System.StringExtensions" />
<DoNotPublicize Include="0Harmony:System.MemoryExtensions" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.CallerArgumentExpressionAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.DefaultInterpolatedStringHandler" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.IsByRefLikeAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.IsExternalInit" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.IsReadOnlyAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.NativeIntegerAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.NullableAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.NullableContextAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.NullablePublicOnlyAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.RefSafetyRulesAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.ModuleInitializerAttribute" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.ITuple" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.Unsafe" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.AllowNullAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.DisallowNullAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.ExtraDynamicallyAccessedMemberTypes" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.MaybeNullAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.MemberNotNullAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.NotNullAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute" />
<DoNotPublicize Include="0Harmony:System.Diagnostics.CodeAnalysis.UnscopedRefAttribute" />
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2.buckets" />
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2.entries" />
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2.version" />
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2+Entry" />
<Publicize Include="mscorlib:System.Collections.Generic.List`1._items" />
<Publicize Include="mscorlib:System.Collections.Generic.List`1._version" />
<Publicize Include="mscorlib:System.Collections.Generic.List`1._size" />
<Publicize Include="mscorlib:System.Collections.Generic.List`1.EnsureCapacity" />
<Publicize Include="System.Core:System.Collections.Generic.HashSet`1._version" />
<Publicize Include="mscorlib:System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast" />
<Publicize Include="mscorlib:System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCastLong" />
<Publicize Include="mscorlib:System.Runtime.CompilerServices.JitHelpers.UnsafeCast" />
<Publicize Include="mscorlib:System.Reflection.Emit.Label.label" />
<Publicize Include="mscorlib:System.String.m_firstChar" />
<None Include="..\..\LICENSE">
<Pack>True</Pack>
<PackagePath />
</None>
</ItemGroup>
</Project>
+96 -73
View File
@@ -9,8 +9,8 @@ using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Security; using System.Security;
using JetBrains.Annotations;
using Verse; using Verse;
// ReSharper disable PossibleMultipleEnumeration // ReSharper disable PossibleMultipleEnumeration
namespace FisheryLib; namespace FisheryLib;
@@ -163,13 +163,19 @@ public static class FishTranspiler
: null; : null;
public Type? GetTypeIn(MethodBase method) public Type? GetTypeIn(MethodBase method)
=> OpCode.LoadsArgument() ? method.GetParameters()[GetIndex()].ParameterType => OpCode.LoadsArgument()
? method.GetParameters()[GetIndex()].ParameterType
: OpCode.LoadsLocalVariable() || OpCode.StoresLocalVariable() : OpCode.LoadsLocalVariable() || OpCode.StoresLocalVariable()
? method.GetLocalVariables()[GetIndex()].LocalType ? method.GetLocalVariables()[GetIndex()].LocalType
: OpCode.LoadsField() || OpCode.StoresField() ? (Operand as FieldInfo)?.FieldType : OpCode.LoadsField() || OpCode.StoresField()
: OpCode == OpCodes.Call || OpCode == OpCodes.Callvirt ? (Operand as MethodInfo)?.ReturnType ? (Operand as FieldInfo)?.FieldType
: OpCode.LoadsConstant() ? Operand?.GetType() : OpCode == OpCodes.Call || OpCode == OpCodes.Callvirt
: null; ? (Operand as MethodInfo)?.ReturnType
: OpCode.LoadsConstant()
? Operand?.GetType()
: null;
private bool Calls() => (OpCode == OpCodes.Call) | (OpCode == OpCodes.Callvirt);
public override bool Equals(object? obj) public override bool Equals(object? obj)
=> obj is CodeInstruction code => obj is CodeInstruction code
@@ -186,13 +192,13 @@ public static class FishTranspiler
: unchecked((((1009 * 9176) + OpCode.GetHashCode()) * 9176) + Operand.GetHashCode()); : unchecked((((1009 * 9176) + OpCode.GetHashCode()) * 9176) + Operand.GetHashCode());
public static bool operator ==(Container lhs, Container rhs) public static bool operator ==(Container lhs, Container rhs)
=> lhs.OpCode == rhs.OpCode => OpCodeEquals(lhs.OpCode, rhs.OpCode) && CompareOperands(lhs.Operand, rhs.Operand);
&& CompareOperands(lhs.Operand, rhs.Operand);
public static bool operator !=(Container lhs, Container rhs) => !(lhs == rhs); public static bool operator !=(Container lhs, Container rhs) => !(lhs == rhs);
public static bool operator ==(Container helper, CodeInstruction code) public static bool operator ==(Container helper, CodeInstruction? code)
=> helper.OpCode == code.opcode => code != null
&& OpCodeEquals(helper.OpCode, code.opcode)
&& CompareOperands(helper.Operand, code.operand); && CompareOperands(helper.Operand, code.operand);
public static bool operator !=(Container helper, CodeInstruction code) => !(helper == code); public static bool operator !=(Container helper, CodeInstruction code) => !(helper == code);
@@ -201,6 +207,11 @@ public static class FishTranspiler
public static bool operator !=(CodeInstruction code, Container helper) => !(helper == code); public static bool operator !=(CodeInstruction code, Container helper) => !(helper == code);
private static bool OpCodeEquals(in OpCode lhs, in OpCode rhs)
=> lhs == rhs || (IsCallOpcode(lhs) && IsCallOpcode(rhs));
private static bool IsCallOpcode(in OpCode opCode) => opCode == OpCodes.Call || opCode == OpCodes.Callvirt;
[SuppressMessage("Usage", "CA2225")] [SuppressMessage("Usage", "CA2225")]
public static implicit operator CodeInstruction(Container helper) => helper.ToInstruction(); public static implicit operator CodeInstruction(Container helper) => helper.ToInstruction();
@@ -506,7 +517,7 @@ public static class FishTranspiler
? locals.First() ? locals.First()
: ThrowHelper.ThrowInvalidOperationException<Container>( : ThrowHelper.ThrowInvalidOperationException<Container>(
$"No local variable found for predicate {predicate.Method.FullDescription()} and method { $"No local variable found for predicate {predicate.Method.FullDescription()} and method {
method.FullDescription()}"); method.FullDescription()}");
} }
/// <summary> /// <summary>
@@ -782,7 +793,7 @@ public static class FishTranspiler
=> ThrowHelper.ThrowArgumentException<Container>( => ThrowHelper.ThrowArgumentException<Container>(
$"Tried using Enum {e.GetType().FullDescription()} with underlying Type { $"Tried using Enum {e.GetType().FullDescription()} with underlying Type {
Enum.GetUnderlyingType(e.GetType()).FullDescription()} (TypeCode: { Enum.GetUnderlyingType(e.GetType()).FullDescription()} (TypeCode: {
typeCode}) for FishTranspiler.Constant."); typeCode}) for FishTranspiler.Constant.");
/// <summary> /// <summary>
/// Calls the method indicated by the passed method group. /// Calls the method indicated by the passed method group.
@@ -828,8 +839,7 @@ public static class FishTranspiler
Guard.IsNotNullOrEmpty(type); Guard.IsNotNullOrEmpty(type);
Guard.IsNotNullOrEmpty(name); Guard.IsNotNullOrEmpty(name);
return Call( return Call(Type.GetType($"{type}, {assembly}")
Type.GetType($"{type}, {assembly}")
?? ThrowHelper.ThrowArgumentException<Type>($"No type named {type} found in assembly {assembly}"), name, ?? ThrowHelper.ThrowArgumentException<Type>($"No type named {type} found in assembly {assembly}"), name,
parameters, generics, forceNoCallvirt); parameters, generics, forceNoCallvirt);
} }
@@ -851,11 +861,10 @@ public static class FishTranspiler
Guard.IsNotNull(type); Guard.IsNotNull(type);
Guard.IsNotNullOrEmpty(name); Guard.IsNotNullOrEmpty(name);
return Call( return Call(AccessTools.Method(type, name, parameters, generics)
AccessTools.Method(type, name, parameters, generics)
?? ThrowHelper.ThrowArgumentException<MethodInfo>($"No method found with type {type}, name { ?? ThrowHelper.ThrowArgumentException<MethodInfo>($"No method found with type {type}, name {
name}{(parameters != null ? $", parameters: {parameters.ToStringSafeEnumerable()}" : "")}{ name}{(parameters != null ? $", parameters: {parameters.ToStringSafeEnumerable()}" : "")}{
(generics != null ? $", generics: {generics.ToStringSafeEnumerable()}" : "")}"), (generics != null ? $", generics: {generics.ToStringSafeEnumerable()}" : "")}"),
forceNoCallvirt); forceNoCallvirt);
} }
@@ -869,10 +878,9 @@ public static class FishTranspiler
{ {
Guard.IsNotNull(method); Guard.IsNotNull(method);
return new( return new(method.IsStatic || (method.DeclaringType?.IsValueType ?? false) || forceNoCallvirt
method.IsStatic || (method.DeclaringType?.IsValueType ?? false) || forceNoCallvirt ? OpCodes.Call
? OpCodes.Call : OpCodes.Callvirt, method);
: OpCodes.Callvirt, method);
} }
/// <summary> /// <summary>
@@ -1489,7 +1497,6 @@ public static class FishTranspiler
$"Type ({type}) for FishTranspiler.Box must be a ValueType.", nameof(type)); $"Type ({type}) for FishTranspiler.Box must be a ValueType.", nameof(type));
} }
/// <summary> /// <summary>
/// Converts the boxed representation of a value type to its unboxed form, pushing an address to the box object's /// Converts the boxed representation of a value type to its unboxed form, pushing an address to the box object's
/// held value to the stack. Implemented using the Unbox instruction. /// held value to the stack. Implemented using the Unbox instruction.
@@ -1983,9 +1990,9 @@ public static class FishTranspiler
return new(!type.IsPrimitive || type == typeof(char) return new(!type.IsPrimitive || type == typeof(char)
? ThrowHelper.ThrowArgumentException<OpCode>("Convert expects a non-character primitive type", nameof(type)) ? ThrowHelper.ThrowArgumentException<OpCode>("Convert expects a non-character primitive type", nameof(type))
: ConvertOpCodesByType.TryGetValue(type, out var value) ? value : ConvertOpCodesByType.TryGetValue(type, out var value)
: ThrowHelper.ThrowArgumentException<OpCode>( ? value
$"Type {type.FullDescription()} cannot be converted to")); : ThrowHelper.ThrowArgumentException<OpCode>($"Type {type.FullDescription()} cannot be converted to"));
} }
public static readonly Dictionary<Type, OpCode> ConvertOpCodesByType = new() public static readonly Dictionary<Type, OpCode> ConvertOpCodesByType = new()
@@ -2034,12 +2041,13 @@ public static class FishTranspiler
: type == typeof(float) : type == typeof(float)
? ThrowHelper.ThrowInvalidOperationException<OpCode>( ? ThrowHelper.ThrowInvalidOperationException<OpCode>(
"There is no operation for converting to a float with overflow checking") "There is no operation for converting to a float with overflow checking")
: type == typeof(double) : type == typeof(double)
? ThrowHelper.ThrowInvalidOperationException<OpCode>( ? ThrowHelper.ThrowInvalidOperationException<OpCode>(
"There is no operation for converting to a double with overflow checking") "There is no operation for converting to a double with overflow checking")
: ConvertWithOverflowCheckOpCodesByType.TryGetValue(type, out var value) ? value : ConvertWithOverflowCheckOpCodesByType.TryGetValue(type, out var value)
: ThrowHelper.ThrowArgumentException<OpCode>( ? value
$"Type {type.FullDescription()} cannot be converted to")); : ThrowHelper.ThrowArgumentException<OpCode>(
$"Type {type.FullDescription()} cannot be converted to"));
} }
public static readonly Dictionary<Type, OpCode> ConvertWithOverflowCheckOpCodesByType = new() public static readonly Dictionary<Type, OpCode> ConvertWithOverflowCheckOpCodesByType = new()
@@ -2081,12 +2089,13 @@ public static class FishTranspiler
: type == typeof(float) : type == typeof(float)
? ThrowHelper.ThrowInvalidOperationException<OpCode>( ? ThrowHelper.ThrowInvalidOperationException<OpCode>(
"There is no operation for converting to a float with overflow checking") "There is no operation for converting to a float with overflow checking")
: type == typeof(double) : type == typeof(double)
? ThrowHelper.ThrowInvalidOperationException<OpCode>( ? ThrowHelper.ThrowInvalidOperationException<OpCode>(
"There is no operation for converting to a double with overflow checking") "There is no operation for converting to a double with overflow checking")
: ConvertUnsignedWithOverflowCheckOpCodesByType.TryGetValue(type, out var value) ? value : ConvertUnsignedWithOverflowCheckOpCodesByType.TryGetValue(type, out var value)
: ThrowHelper.ThrowArgumentException<OpCode>( ? value
$"Type {type.FullDescription()} cannot be converted to")); : ThrowHelper.ThrowArgumentException<OpCode>(
$"Type {type.FullDescription()} cannot be converted to"));
} }
public static readonly Dictionary<Type, OpCode> ConvertUnsignedWithOverflowCheckOpCodesByType = new() public static readonly Dictionary<Type, OpCode> ConvertUnsignedWithOverflowCheckOpCodesByType = new()
@@ -2191,8 +2200,8 @@ public static class FishTranspiler
} }
} }
public static CodeInstructions MethodReplacer<T, V>(this CodeInstructions instructions, T from, V to, public static CodeInstructions MethodReplacer<TFrom, TTo>(this CodeInstructions instructions, TFrom from, TTo to,
bool throwOnFailure = true) where T : Delegate where V : Delegate bool throwOnFailure = true) where TFrom : Delegate where TTo : Delegate
{ {
Guard.IsNotNull(instructions); Guard.IsNotNull(instructions);
Guard.IsNotNull(from); Guard.IsNotNull(from);
@@ -2333,10 +2342,9 @@ public static class FishTranspiler
if (throwOnFailure && !success) if (throwOnFailure && !success)
{ {
ThrowHelper.ThrowInvalidOperationException( ThrowHelper.ThrowInvalidOperationException($"FishTranspiler.Replace couldn't find target instruction for {
$"FishTranspiler.Replace couldn't find target instruction for { predicate.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version {
predicate.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version { UtilityF.GetCallingAssembly().GetName().Version}");
UtilityF.GetCallingAssembly().GetName().Version}");
} }
} }
@@ -2377,9 +2385,8 @@ public static class FishTranspiler
if (throwOnFailure && !success) if (throwOnFailure && !success)
{ {
ThrowHelper.ThrowInvalidOperationException( ThrowHelper.ThrowInvalidOperationException($"FishTranspiler.ReplaceAt couldn't find target instruction for {
$"FishTranspiler.ReplaceAt couldn't find target instruction for { position.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version {
position.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version {
UtilityF.GetCallingAssembly().GetName().Version}"); UtilityF.GetCallingAssembly().GetName().Version}");
} }
@@ -2406,8 +2413,13 @@ public static class FishTranspiler
return instruction; return instruction;
} }
public static bool LoadsLocalVariable(this OpCode opcode) public static bool LoadsLocalVariable(this OpCode opcode) => LoadLocalVariableOpCodes.Contains(opcode);
=> CodeInstructionExtensions.loadVarCodes.Contains(opcode);
public static readonly HashSet<OpCode> LoadLocalVariableOpCodes =
[
OpCodes.Ldloca_S, OpCodes.Ldloca, OpCodes.Ldloc_0, OpCodes.Ldloc_1, OpCodes.Ldloc_2, OpCodes.Ldloc_3,
OpCodes.Ldloc_S, OpCodes.Ldloc
];
public static OpCode ToLoadLocalVariable(this OpCode opcode) public static OpCode ToLoadLocalVariable(this OpCode opcode)
=> opcode.LoadsLocalVariable() && opcode != OpCodes.Ldarga && opcode != OpCodes.Ldarga_S ? opcode => opcode.LoadsLocalVariable() && opcode != OpCodes.Ldarga && opcode != OpCodes.Ldarga_S ? opcode
@@ -2416,8 +2428,12 @@ public static class FishTranspiler
: opcode == OpCodes.Stloc ? OpCodes.Ldloc : opcode == OpCodes.Stloc ? OpCodes.Ldloc
: ThrowHelper.ThrowInvalidOperationException<OpCode>($"{opcode} cannot be cast to Ldloc."); : ThrowHelper.ThrowInvalidOperationException<OpCode>($"{opcode} cannot be cast to Ldloc.");
public static bool StoresLocalVariable(this OpCode opcode) public static bool StoresLocalVariable(this OpCode opcode) => StoreLocalVariableOpCodes.Contains(opcode);
=> CodeInstructionExtensions.storeVarCodes.Contains(opcode);
public static readonly HashSet<OpCode> StoreLocalVariableOpCodes =
[
OpCodes.Stloc_0, OpCodes.Stloc_1, OpCodes.Stloc_2, OpCodes.Stloc_3, OpCodes.Stloc_S, OpCodes.Stloc
];
public static OpCode ToStoreLocalVariable(this OpCode opcode) public static OpCode ToStoreLocalVariable(this OpCode opcode)
=> opcode.StoresLocalVariable() ? opcode => opcode.StoresLocalVariable() ? opcode
@@ -2498,9 +2514,16 @@ public static class FishTranspiler
public static bool LoadsString(this OpCode opcode) => opcode == OpCodes.Ldstr; public static bool LoadsString(this OpCode opcode) => opcode == OpCodes.Ldstr;
public static bool Branches(this OpCode opcode) public static bool Branches(this OpCode opcode) => BranchingOpCodes.Contains(opcode);
=> CodeInstructionExtensions.branchCodes.Contains(opcode)
|| opcode == OpCodes.Switch; public static readonly HashSet<OpCode> BranchingOpCodes =
[
OpCodes.Br_S, OpCodes.Brfalse_S, OpCodes.Brtrue_S, OpCodes.Beq_S, OpCodes.Bge_S, OpCodes.Bgt_S,
OpCodes.Ble_S, OpCodes.Blt_S, OpCodes.Bne_Un_S, OpCodes.Bge_Un_S, OpCodes.Bgt_Un_S, OpCodes.Ble_Un_S,
OpCodes.Blt_Un_S, OpCodes.Br, OpCodes.Brfalse, OpCodes.Brtrue, OpCodes.Beq, OpCodes.Bge, OpCodes.Bgt,
OpCodes.Ble, OpCodes.Blt, OpCodes.Bne_Un, OpCodes.Bge_Un, OpCodes.Bgt_Un, OpCodes.Ble_Un, OpCodes.Blt_Un,
OpCodes.Switch
];
public static bool Compares(this OpCode opcode) => CompareOpCodes.Contains(opcode); public static bool Compares(this OpCode opcode) => CompareOpCodes.Contains(opcode);
@@ -2647,26 +2670,26 @@ public static class FishTranspiler
{ {
{ OpCodes.Ldarg_0, 0 }, { OpCodes.Ldarg_0, 0 },
{ OpCodes.Ldarg_1, 1 }, { OpCodes.Ldarg_1, 1 },
{ OpCodes.Ldarg_2, 2 }, { OpCodes.Ldarg_2, 2 },
{ OpCodes.Ldarg_3, 3 }, { OpCodes.Ldarg_3, 3 },
{ OpCodes.Ldloc_0, 0 }, { OpCodes.Ldloc_0, 0 },
{ OpCodes.Ldloc_1, 1 }, { OpCodes.Ldloc_1, 1 },
{ OpCodes.Ldloc_2, 2 }, { OpCodes.Ldloc_2, 2 },
{ OpCodes.Ldloc_3, 3 }, { OpCodes.Ldloc_3, 3 },
{ OpCodes.Stloc_0, 0 }, { OpCodes.Stloc_0, 0 },
{ OpCodes.Stloc_1, 1 }, { OpCodes.Stloc_1, 1 },
{ OpCodes.Stloc_2, 2 }, { OpCodes.Stloc_2, 2 },
{ OpCodes.Stloc_3, 3 }, { OpCodes.Stloc_3, 3 },
{ OpCodes.Ldc_I4_0, 0 }, { OpCodes.Ldc_I4_0, 0 },
{ OpCodes.Ldc_I4_1, 1 }, { OpCodes.Ldc_I4_1, 1 },
{ OpCodes.Ldc_I4_2, 2 }, { OpCodes.Ldc_I4_2, 2 },
{ OpCodes.Ldc_I4_3, 3 }, { OpCodes.Ldc_I4_3, 3 },
{ OpCodes.Ldc_I4_4, 4 }, { OpCodes.Ldc_I4_4, 4 },
{ OpCodes.Ldc_I4_5, 5 }, { OpCodes.Ldc_I4_5, 5 },
{ OpCodes.Ldc_I4_6, 6 }, { OpCodes.Ldc_I4_6, 6 },
{ OpCodes.Ldc_I4_7, 7 }, { OpCodes.Ldc_I4_7, 7 },
{ OpCodes.Ldc_I4_8, 8 }, { OpCodes.Ldc_I4_8, 8 },
{ OpCodes.Ldc_I4_M1, -1 } { OpCodes.Ldc_I4_M1, -1 }
}; };
public static object? GetOperandFromIndex(int index) => index > 3 ? index : null; public static object? GetOperandFromIndex(int index) => index > 3 ? index : null;
+4 -3
View File
@@ -10,11 +10,12 @@ global using System.Collections.Generic;
global using System.Reflection; global using System.Reflection;
global using HarmonyLib; global using HarmonyLib;
global using FisheryLib.Utility.Diagnostics; global using FisheryLib.Utility.Diagnostics;
global using JetBrains.Annotations;
global using CodeInstructions = System.Collections.Generic.IEnumerable<HarmonyLib.CodeInstruction>; global using CodeInstructions = System.Collections.Generic.IEnumerable<HarmonyLib.CodeInstruction>;
global using NotNullAttribute = System.Diagnostics.CodeAnalysis.NotNullAttribute;
using System.Security; using System.Security;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
[assembly: AllowPartiallyTrustedCallers] [assembly: AllowPartiallyTrustedCallers]
[assembly: SecurityRules(SecurityRuleSet.Level2, SkipVerificationInFullTrust = true)] [assembly: SecurityRules(SecurityRuleSet.Level2, SkipVerificationInFullTrust = true)]
@@ -28,11 +29,11 @@ namespace FisheryLib;
[PublicAPI] [PublicAPI]
public static class FisheryLib public static class FisheryLib
{ {
public const decimal VERSION = 0.5M; public const decimal VERSION = 0.51M;
public static decimal CurrentlyLoadedVersion { get; } = VERSION; public static decimal CurrentlyLoadedVersion { get; } = VERSION;
public const string VERSION_STRING = "0.5.0.0"; public const string VERSION_STRING = "0.5.1.0";
// public static string GetVersion() // public static string GetVersion()
// { // {
-81
View File
@@ -1,81 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>FisheryLib</RootNamespace>
<AssemblyName>1Fishery</AssemblyName>
<TargetFramework>net48</TargetFramework>
<LangVersion>preview</LangVersion>
<PlatformTarget>AnyCPU</PlatformTarget>
<Optimize>true</Optimize>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<Authors>bradson</Authors>
<Copyright>Copyright (c) 2022 bradson</Copyright>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<EnableNETAnalyzers>True</EnableNETAnalyzers>
<AnalysisLevel>preview-all</AnalysisLevel>
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>5</WarningLevel>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<Configurations>v1.4;v1.3</Configurations>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<!-- Version>0.3.800.85</Version -->
<!-- Deterministic>False</Deterministic -->
<NoWarn>
1701;1702;IL2121;CS8500;CS9082;CA1000;CA1002;CA1003;CA1707;CA1010;CA1715;CA1716;CA1724;CA1031;CA1033;
CA1034;CA1043;CA1051;CA1305;CA1310;CA1710;CA1711;CA1810;CA1812;CA1819;CA1851;CA2002;CA5394;CA1725;CA1062
</NoWarn>
</PropertyGroup>
<Choose>
<When Condition="'$(Configuration)' == 'v1.4'">
<PropertyGroup>
<OutputPath>..\..\1.4\Assemblies\</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.4.*" />
</ItemGroup>
</When>
<When Condition="'$(Configuration)' == 'v1.3'">
<PropertyGroup>
<OutputPath>..\..\1.3\Assemblies\</OutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.3.*" />
</ItemGroup>
</When>
</Choose>
<ItemGroup>
<PackageReference Include="Lib.Harmony" Version="2.2.*" ExcludeAssets="runtime" />
<PackageReference Include="PolySharp" Version="1.*" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.*" />
<PackageReference Include="Krafs.Publicizer" Version="2.*" />
<Publicize Include="Assembly-CSharp;0Harmony" IncludeVirtualMembers="false" />
<DoNotPublicize Include="0Harmony:System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute" />
<DoNotPublicize Include="0Harmony:Mono.Collections.Generic.Collection`1" />
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2.buckets" />
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2.entries" />
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2.version" />
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2+Entry" />
<Publicize Include="mscorlib:System.Collections.Generic.List`1._items" />
<Publicize Include="mscorlib:System.Collections.Generic.List`1._version" />
<Publicize Include="mscorlib:System.Collections.Generic.List`1._size" />
<Publicize Include="mscorlib:System.Collections.Generic.List`1.EnsureCapacity" />
<Publicize Include="System.Core:System.Collections.Generic.HashSet`1._version" />
<Publicize Include="mscorlib:System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast" />
<Publicize Include="mscorlib:System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCastLong" />
<Publicize Include="mscorlib:System.Runtime.CompilerServices.JitHelpers.UnsafeCast" />
<Publicize Include="mscorlib:System.Reflection.Emit.Label.label" />
<Publicize Include="mscorlib:System.String.m_firstChar" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\LICENSE">
<Pack>True</Pack>
<PackagePath />
</None>
</ItemGroup>
</Project>
+25 -7
View File
@@ -3,18 +3,36 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.1.32120.378 VisualStudioVersion = 17.1.32120.378
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fishery", "Fishery.csproj", "{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.5", "1.5.csproj", "{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.4", "1.4.csproj", "{BE85EB31-71CD-443C-8C93-20E2B7F3F549}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.3", "1.3.csproj", "{FC5FB1F4-626D-4895-AE5E-922DFE1AE120}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "1.2", "1.2.csproj", "{E4269847-7C6E-404E-93C0-E47CF7459E81}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
v1.3|Any CPU = v1.3|Any CPU Debug|Any CPU = Debug|Any CPU
v1.4|Any CPU = v1.4|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.3|Any CPU.ActiveCfg = v1.3|Any CPU {B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.3|Any CPU.Build.0 = v1.3|Any CPU {B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.4|Any CPU.ActiveCfg = v1.4|Any CPU {B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.4|Any CPU.Build.0 = v1.4|Any CPU {B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.Release|Any CPU.Build.0 = Release|Any CPU
{BE85EB31-71CD-443C-8C93-20E2B7F3F549}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BE85EB31-71CD-443C-8C93-20E2B7F3F549}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BE85EB31-71CD-443C-8C93-20E2B7F3F549}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BE85EB31-71CD-443C-8C93-20E2B7F3F549}.Release|Any CPU.Build.0 = Release|Any CPU
{FC5FB1F4-626D-4895-AE5E-922DFE1AE120}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC5FB1F4-626D-4895-AE5E-922DFE1AE120}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC5FB1F4-626D-4895-AE5E-922DFE1AE120}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC5FB1F4-626D-4895-AE5E-922DFE1AE120}.Release|Any CPU.Build.0 = Release|Any CPU
{E4269847-7C6E-404E-93C0-E47CF7459E81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E4269847-7C6E-404E-93C0-E47CF7459E81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4269847-7C6E-404E-93C0-E47CF7459E81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E4269847-7C6E-404E-93C0-E47CF7459E81}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -7,7 +7,6 @@ using System.Diagnostics.CodeAnalysis;
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Security; using System.Security;
using JetBrains.Annotations;
namespace FisheryLib.FunctionPointers; namespace FisheryLib.FunctionPointers;
@@ -7,7 +7,6 @@ using System.Diagnostics.CodeAnalysis;
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Security; using System.Security;
using JetBrains.Annotations;
namespace FisheryLib.FunctionPointers; namespace FisheryLib.FunctionPointers;
@@ -5,7 +5,6 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib.FunctionPointers; namespace FisheryLib.FunctionPointers;
@@ -5,7 +5,6 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib.FunctionPointers; namespace FisheryLib.FunctionPointers;
+12 -3
View File
@@ -4,7 +4,6 @@
// You can obtain one at https://opensource.org/licenses/MIT/. // You can obtain one at https://opensource.org/licenses/MIT/.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
using UnityEngine; using UnityEngine;
using Verse; using Verse;
@@ -15,9 +14,19 @@ public static class GUIScope
{ {
public readonly record struct WidgetGroup : IDisposable public readonly record struct WidgetGroup : IDisposable
{ {
public WidgetGroup(in Rect rect) => Widgets.BeginGroup(rect); public WidgetGroup(in Rect rect)
#if !V1_2
=> Widgets.BeginGroup(rect);
#else
=> GUI.BeginGroup(rect);
#endif
public void Dispose() => Widgets.EndGroup(); public void Dispose()
#if !V1_2
=> Widgets.EndGroup();
#else
=> GUI.EndGroup();
#endif
} }
public readonly record struct ScrollView : IDisposable public readonly record struct ScrollView : IDisposable
-2
View File
@@ -3,8 +3,6 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this // License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/. // file, You can obtain one at https://mozilla.org/MPL/2.0/.
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
[PublicAPI] [PublicAPI]
@@ -5,7 +5,6 @@
using System.Security; using System.Security;
using System.Text; using System.Text;
using JetBrains.Annotations;
namespace FisheryLib.Pools; namespace FisheryLib.Pools;
@@ -5,7 +5,6 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using JetBrains.Annotations;
namespace FisheryLib.Pools; namespace FisheryLib.Pools;
@@ -4,7 +4,6 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/. // file, You can obtain one at https://mozilla.org/MPL/2.0/.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib.Pools; namespace FisheryLib.Pools;
@@ -6,7 +6,6 @@
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
@@ -8,7 +8,6 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
-1
View File
@@ -13,7 +13,6 @@ using System.Security;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using FisheryLib.Pools; using FisheryLib.Pools;
using JetBrains.Annotations;
using Verse; using Verse;
namespace FisheryLib; namespace FisheryLib;
-1
View File
@@ -4,7 +4,6 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/. // file, You can obtain one at https://mozilla.org/MPL/2.0/.
using System.Collections.Concurrent; using System.Collections.Concurrent;
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
-1
View File
@@ -6,7 +6,6 @@
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
-1
View File
@@ -8,7 +8,6 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
-1
View File
@@ -4,7 +4,6 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/. // file, You can obtain one at https://mozilla.org/MPL/2.0/.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
-1
View File
@@ -4,7 +4,6 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/. // file, You can obtain one at https://mozilla.org/MPL/2.0/.
using System.Diagnostics; using System.Diagnostics;
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
-1
View File
@@ -7,7 +7,6 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using JetBrains.Annotations;
namespace FisheryLib; namespace FisheryLib;
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB