Added 1.2 and 1.5 support, mod icon, DefaultValue/Key for FishSet/Table
This commit is contained in:
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.
Binary file not shown.
Binary file not shown.
@@ -3,10 +3,13 @@
|
||||
<name>Fishery - Modding Library</name>
|
||||
<packageId>bs.fishery</packageId>
|
||||
<supportedVersions>
|
||||
<li>1.2</li>
|
||||
<li>1.3</li>
|
||||
<li>1.4</li>
|
||||
<li>1.5</li>
|
||||
</supportedVersions>
|
||||
<author>bradson</author>
|
||||
<modIconPath IgnoreIfNoMatchingField="True">FisheryLib/ModIcon</modIconPath>
|
||||
<url>https://github.com/bbradson/fishery</url>
|
||||
<loadBefore>
|
||||
<li>Ludeon.RimWorld</li>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -68,7 +68,7 @@ dotnet_naming_rule.public_or_internal_field_should_be_camel_case.style = camel_c
|
||||
# Symbol specifications
|
||||
|
||||
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.private_or_protected_field.applicable_kinds = field
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
global using static FisheryLib.Aliases;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
// https://github.com/CommunityToolkit/dotnet/blob/main/CommunityToolkit.HighPerformance/Extensions/BoolExtensions.cs
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using JetBrains.Annotations;
|
||||
using Mono.Cecil;
|
||||
using Mono.Collections.Generic;
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using FisheryLib.Collections;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
@@ -77,8 +76,8 @@ public static class CollectionExtensions
|
||||
return array;
|
||||
}
|
||||
|
||||
public static Telement[] ToArray<Tenumerable, Telement>(this Tenumerable enumerable, Telement[] destination)
|
||||
where Tenumerable : IList<Telement>
|
||||
public static TElement[] ToArray<TEnumerable, TElement>(this TEnumerable enumerable, TElement[] destination)
|
||||
where TEnumerable : IList<TElement>
|
||||
{
|
||||
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)
|
||||
where Tcollection : IList<Telement>
|
||||
where TCollection : IList<TElement>
|
||||
{
|
||||
Guard.IsNotNull(collection);
|
||||
|
||||
@@ -442,7 +441,7 @@ public static class CollectionExtensions
|
||||
continue;
|
||||
|
||||
// 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))
|
||||
continue;
|
||||
@@ -544,10 +543,11 @@ public static class CollectionExtensions
|
||||
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>))
|
||||
list.ReplaceContentsWith(Unsafe.As<List<T>>(collection));
|
||||
if (typeof(TOther) == typeof(List<TThis>))
|
||||
list.ReplaceContentsWith(Unsafe.As<List<TThis>>(collection));
|
||||
|
||||
if (ReferenceEquals(list, collection))
|
||||
return;
|
||||
@@ -568,7 +568,7 @@ public static class CollectionExtensions
|
||||
}
|
||||
else
|
||||
{
|
||||
list._items = new T[collectionCount];
|
||||
list._items = new TThis[collectionCount];
|
||||
collection.CopyTo(list._items, 0);
|
||||
list._size = collectionCount;
|
||||
}
|
||||
@@ -723,7 +723,7 @@ public static class CollectionExtensions
|
||||
|
||||
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();
|
||||
|
||||
if (list._size == list._items.Length)
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
// which itself is based on
|
||||
// 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.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -14,7 +17,10 @@ using System.Runtime.InteropServices;
|
||||
using FisheryLib.FunctionPointers;
|
||||
using FisheryLib.Pools;
|
||||
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;
|
||||
|
||||
@@ -42,6 +48,8 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
|
||||
|
||||
private float _maxLoadFactor = 0.5f;
|
||||
|
||||
private T _defaultValue = Internal.KeyUtility<T>.Default;
|
||||
|
||||
public int Version
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -65,6 +73,22 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
|
||||
|
||||
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>?
|
||||
EntryAdded,
|
||||
EntryRemoved;
|
||||
@@ -112,6 +136,19 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
|
||||
|
||||
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(_tails))]
|
||||
private void Initialize(int minimumCapacity = 0)
|
||||
@@ -120,6 +157,7 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
|
||||
// Mathf.NextPowerOfTwo(minimumCapacity);
|
||||
|
||||
_buckets = new T?[minimumCapacity];
|
||||
Array.Fill(_buckets, _defaultValue);
|
||||
_tails = new((uint)minimumCapacity);
|
||||
_bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length);
|
||||
_wrapAroundMask = _buckets.Length - 1;
|
||||
@@ -167,7 +205,7 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
|
||||
|
||||
private void SetBucketEmpty(int index)
|
||||
{
|
||||
_buckets[index] = default;
|
||||
_buckets[index] = _defaultValue;
|
||||
_tails.SetEmpty(index);
|
||||
}
|
||||
|
||||
@@ -356,7 +394,7 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
|
||||
{
|
||||
ref var tailingBucket = ref _buckets[tailIndex];
|
||||
tailingEntriesList.Add(tailingBucket!);
|
||||
tailingBucket = default;
|
||||
tailingBucket = _defaultValue;
|
||||
|
||||
if (HasTail(tailIndex))
|
||||
{
|
||||
@@ -409,6 +447,7 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
|
||||
|
||||
_tails = new((uint)_buckets.Length << 1);
|
||||
_buckets = new T?[_buckets.Length << 1];
|
||||
Array.Fill(_buckets, _defaultValue);
|
||||
|
||||
_bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length);
|
||||
_wrapAroundMask = _buckets.Length - 1;
|
||||
@@ -579,7 +618,7 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
|
||||
if (_buckets is null)
|
||||
Initialize();
|
||||
|
||||
Array.Clear(_buckets, 0, _buckets.Length);
|
||||
Array.Fill(_buckets, Internal.KeyUtility<T>.Default);
|
||||
_tails.Reset();
|
||||
|
||||
_count = 0;
|
||||
@@ -660,6 +699,8 @@ public class FishSet<T> : ISet<T>, IReadOnlyCollection<T>, ICollection
|
||||
|
||||
private NibbleArray _values = new(length);
|
||||
|
||||
public uint Length => _values.Length;
|
||||
|
||||
public uint this[uint index]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
||||
@@ -7,15 +7,22 @@
|
||||
// which itself is based on
|
||||
// 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.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using FisheryLib.Collections.Internal;
|
||||
using FisheryLib.FunctionPointers;
|
||||
using FisheryLib.Pools;
|
||||
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;
|
||||
|
||||
@@ -46,6 +53,8 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
|
||||
private float _maxLoadFactor = 0.5f;
|
||||
|
||||
private Entry _defaultEntry = Entry.Default;
|
||||
|
||||
public KeyCollection Keys => 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;
|
||||
|
||||
/// <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
|
||||
=> GetType().ComputeManagedObjectSizeEstimate()
|
||||
+ ((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);
|
||||
|
||||
/// <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(_tails))]
|
||||
private void Initialize(int minimumCapacity = 0)
|
||||
@@ -235,6 +266,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
// Mathf.NextPowerOfTwo(minimumCapacity);
|
||||
|
||||
_buckets = new Entry[minimumCapacity];
|
||||
Array.Fill(_buckets, _defaultEntry);
|
||||
_tails = new((uint)minimumCapacity);
|
||||
_bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)_buckets.Length);
|
||||
_wrapAroundMask = _buckets.Length - 1;
|
||||
@@ -280,7 +312,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
|
||||
private void SetBucketEmpty(int index)
|
||||
{
|
||||
_buckets[index] = default;
|
||||
_buckets[index] = _defaultEntry;
|
||||
_tails.SetEmpty(index);
|
||||
}
|
||||
|
||||
@@ -400,8 +432,11 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (bucket.Value.Equals<TValue>(default))
|
||||
return true;
|
||||
@@ -412,6 +447,43 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
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)
|
||||
{
|
||||
while (true)
|
||||
@@ -498,7 +570,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
{
|
||||
ref var tailingBucket = ref _buckets[tailIndex];
|
||||
tailingEntriesList.Add(tailingBucket);
|
||||
tailingBucket = default;
|
||||
tailingBucket = _defaultEntry;
|
||||
|
||||
if (HasTail(tailIndex))
|
||||
{
|
||||
@@ -585,6 +657,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
|
||||
_tails = new((uint)newSize);
|
||||
_buckets = new Entry[newSize];
|
||||
Array.Fill(_buckets, _defaultEntry);
|
||||
|
||||
_bucketBitShift = 32 - FishMath.TrailingZeroCount((uint)newSize);
|
||||
_wrapAroundMask = _buckets.Length - 1;
|
||||
@@ -1046,7 +1119,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
private void EmplaceWithTailsBackward(int entryIndex)
|
||||
{
|
||||
if (IsBucketEmpty(entryIndex))
|
||||
Utility.Diagnostics.ThrowHelper.ThrowInvalidOperationException("Tried to emplace entry bucket");
|
||||
Utility.Diagnostics.ThrowHelper.ThrowInvalidOperationException("Tried to emplace empty bucket");
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -1225,7 +1298,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
if (_buckets is null)
|
||||
Initialize();
|
||||
|
||||
Array.Clear(_buckets, 0, _buckets.Length);
|
||||
Array.Fill(_buckets, _defaultEntry);
|
||||
_tails.Reset();
|
||||
|
||||
_count = 0;
|
||||
@@ -1360,6 +1433,8 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
.Append<TValue>(Value)
|
||||
.Append(" }").ToString();
|
||||
}
|
||||
|
||||
public static readonly Entry Default = new(KeyUtility<TKey>.Default, default);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Guard.IsNotNull(key);
|
||||
ThrowKeyNotFoundException((object)key);
|
||||
ThrowKeyNotFoundException((object?)key);
|
||||
}
|
||||
|
||||
[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.");
|
||||
|
||||
[DoesNotReturn]
|
||||
@@ -1715,7 +1790,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
internal static bool ThrowAddingDuplicateWithKeyArgumentException<T>(T key)
|
||||
{
|
||||
Guard.IsNotNull(key);
|
||||
ThrowAddingDuplicateWithKeyArgumentException((object)key);
|
||||
ThrowAddingDuplicateWithKeyArgumentException((object?)key);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1782,7 +1857,7 @@ public class FishTable<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, I
|
||||
}
|
||||
|
||||
[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}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib.Collections;
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
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/.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib.Collections;
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#pragma warning disable CS8777
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
#if V1_2
|
||||
using JetBrains.Annotations;
|
||||
using NotNullAttribute = System.Diagnostics.CodeAnalysis.NotNullAttribute;
|
||||
#endif
|
||||
|
||||
namespace FisheryLib.Utility.Diagnostics;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace FisheryLib.Utility.Diagnostics;
|
||||
|
||||
@@ -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>
|
||||
@@ -9,8 +9,8 @@ using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection.Emit;
|
||||
using System.Security;
|
||||
using JetBrains.Annotations;
|
||||
using Verse;
|
||||
|
||||
// ReSharper disable PossibleMultipleEnumeration
|
||||
|
||||
namespace FisheryLib;
|
||||
@@ -163,13 +163,19 @@ public static class FishTranspiler
|
||||
: null;
|
||||
|
||||
public Type? GetTypeIn(MethodBase method)
|
||||
=> OpCode.LoadsArgument() ? method.GetParameters()[GetIndex()].ParameterType
|
||||
=> OpCode.LoadsArgument()
|
||||
? method.GetParameters()[GetIndex()].ParameterType
|
||||
: OpCode.LoadsLocalVariable() || OpCode.StoresLocalVariable()
|
||||
? method.GetLocalVariables()[GetIndex()].LocalType
|
||||
: OpCode.LoadsField() || OpCode.StoresField() ? (Operand as FieldInfo)?.FieldType
|
||||
: OpCode == OpCodes.Call || OpCode == OpCodes.Callvirt ? (Operand as MethodInfo)?.ReturnType
|
||||
: OpCode.LoadsConstant() ? Operand?.GetType()
|
||||
: null;
|
||||
: OpCode.LoadsField() || OpCode.StoresField()
|
||||
? (Operand as FieldInfo)?.FieldType
|
||||
: OpCode == OpCodes.Call || OpCode == OpCodes.Callvirt
|
||||
? (Operand as MethodInfo)?.ReturnType
|
||||
: OpCode.LoadsConstant()
|
||||
? Operand?.GetType()
|
||||
: null;
|
||||
|
||||
private bool Calls() => (OpCode == OpCodes.Call) | (OpCode == OpCodes.Callvirt);
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
=> obj is CodeInstruction code
|
||||
@@ -186,13 +192,13 @@ public static class FishTranspiler
|
||||
: unchecked((((1009 * 9176) + OpCode.GetHashCode()) * 9176) + Operand.GetHashCode());
|
||||
|
||||
public static bool operator ==(Container lhs, Container rhs)
|
||||
=> lhs.OpCode == rhs.OpCode
|
||||
&& CompareOperands(lhs.Operand, rhs.Operand);
|
||||
=> OpCodeEquals(lhs.OpCode, rhs.OpCode) && CompareOperands(lhs.Operand, rhs.Operand);
|
||||
|
||||
public static bool operator !=(Container lhs, Container rhs) => !(lhs == rhs);
|
||||
|
||||
public static bool operator ==(Container helper, CodeInstruction code)
|
||||
=> helper.OpCode == code.opcode
|
||||
public static bool operator ==(Container helper, CodeInstruction? code)
|
||||
=> code != null
|
||||
&& OpCodeEquals(helper.OpCode, code.opcode)
|
||||
&& CompareOperands(helper.Operand, code.operand);
|
||||
|
||||
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);
|
||||
|
||||
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")]
|
||||
public static implicit operator CodeInstruction(Container helper) => helper.ToInstruction();
|
||||
|
||||
@@ -506,7 +517,7 @@ public static class FishTranspiler
|
||||
? locals.First()
|
||||
: ThrowHelper.ThrowInvalidOperationException<Container>(
|
||||
$"No local variable found for predicate {predicate.Method.FullDescription()} and method {
|
||||
method.FullDescription()}");
|
||||
method.FullDescription()}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -782,7 +793,7 @@ public static class FishTranspiler
|
||||
=> ThrowHelper.ThrowArgumentException<Container>(
|
||||
$"Tried using Enum {e.GetType().FullDescription()} with underlying Type {
|
||||
Enum.GetUnderlyingType(e.GetType()).FullDescription()} (TypeCode: {
|
||||
typeCode}) for FishTranspiler.Constant.");
|
||||
typeCode}) for FishTranspiler.Constant.");
|
||||
|
||||
/// <summary>
|
||||
/// Calls the method indicated by the passed method group.
|
||||
@@ -828,8 +839,7 @@ public static class FishTranspiler
|
||||
Guard.IsNotNullOrEmpty(type);
|
||||
Guard.IsNotNullOrEmpty(name);
|
||||
|
||||
return Call(
|
||||
Type.GetType($"{type}, {assembly}")
|
||||
return Call(Type.GetType($"{type}, {assembly}")
|
||||
?? ThrowHelper.ThrowArgumentException<Type>($"No type named {type} found in assembly {assembly}"), name,
|
||||
parameters, generics, forceNoCallvirt);
|
||||
}
|
||||
@@ -851,11 +861,10 @@ public static class FishTranspiler
|
||||
Guard.IsNotNull(type);
|
||||
Guard.IsNotNullOrEmpty(name);
|
||||
|
||||
return Call(
|
||||
AccessTools.Method(type, name, parameters, generics)
|
||||
return Call(AccessTools.Method(type, name, parameters, generics)
|
||||
?? ThrowHelper.ThrowArgumentException<MethodInfo>($"No method found with type {type}, name {
|
||||
name}{(parameters != null ? $", parameters: {parameters.ToStringSafeEnumerable()}" : "")}{
|
||||
(generics != null ? $", generics: {generics.ToStringSafeEnumerable()}" : "")}"),
|
||||
(generics != null ? $", generics: {generics.ToStringSafeEnumerable()}" : "")}"),
|
||||
forceNoCallvirt);
|
||||
}
|
||||
|
||||
@@ -869,10 +878,9 @@ public static class FishTranspiler
|
||||
{
|
||||
Guard.IsNotNull(method);
|
||||
|
||||
return new(
|
||||
method.IsStatic || (method.DeclaringType?.IsValueType ?? false) || forceNoCallvirt
|
||||
? OpCodes.Call
|
||||
: OpCodes.Callvirt, method);
|
||||
return new(method.IsStatic || (method.DeclaringType?.IsValueType ?? false) || forceNoCallvirt
|
||||
? OpCodes.Call
|
||||
: OpCodes.Callvirt, method);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1489,7 +1497,6 @@ public static class FishTranspiler
|
||||
$"Type ({type}) for FishTranspiler.Box must be a ValueType.", nameof(type));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
@@ -1983,9 +1990,9 @@ public static class FishTranspiler
|
||||
|
||||
return new(!type.IsPrimitive || type == typeof(char)
|
||||
? ThrowHelper.ThrowArgumentException<OpCode>("Convert expects a non-character primitive type", nameof(type))
|
||||
: ConvertOpCodesByType.TryGetValue(type, out var value) ? value
|
||||
: ThrowHelper.ThrowArgumentException<OpCode>(
|
||||
$"Type {type.FullDescription()} cannot be converted to"));
|
||||
: ConvertOpCodesByType.TryGetValue(type, out var value)
|
||||
? value
|
||||
: ThrowHelper.ThrowArgumentException<OpCode>($"Type {type.FullDescription()} cannot be converted to"));
|
||||
}
|
||||
|
||||
public static readonly Dictionary<Type, OpCode> ConvertOpCodesByType = new()
|
||||
@@ -2034,12 +2041,13 @@ public static class FishTranspiler
|
||||
: type == typeof(float)
|
||||
? ThrowHelper.ThrowInvalidOperationException<OpCode>(
|
||||
"There is no operation for converting to a float with overflow checking")
|
||||
: type == typeof(double)
|
||||
? ThrowHelper.ThrowInvalidOperationException<OpCode>(
|
||||
"There is no operation for converting to a double with overflow checking")
|
||||
: ConvertWithOverflowCheckOpCodesByType.TryGetValue(type, out var value) ? value
|
||||
: ThrowHelper.ThrowArgumentException<OpCode>(
|
||||
$"Type {type.FullDescription()} cannot be converted to"));
|
||||
: type == typeof(double)
|
||||
? ThrowHelper.ThrowInvalidOperationException<OpCode>(
|
||||
"There is no operation for converting to a double with overflow checking")
|
||||
: ConvertWithOverflowCheckOpCodesByType.TryGetValue(type, out var value)
|
||||
? value
|
||||
: ThrowHelper.ThrowArgumentException<OpCode>(
|
||||
$"Type {type.FullDescription()} cannot be converted to"));
|
||||
}
|
||||
|
||||
public static readonly Dictionary<Type, OpCode> ConvertWithOverflowCheckOpCodesByType = new()
|
||||
@@ -2081,12 +2089,13 @@ public static class FishTranspiler
|
||||
: type == typeof(float)
|
||||
? ThrowHelper.ThrowInvalidOperationException<OpCode>(
|
||||
"There is no operation for converting to a float with overflow checking")
|
||||
: type == typeof(double)
|
||||
? ThrowHelper.ThrowInvalidOperationException<OpCode>(
|
||||
"There is no operation for converting to a double with overflow checking")
|
||||
: ConvertUnsignedWithOverflowCheckOpCodesByType.TryGetValue(type, out var value) ? value
|
||||
: ThrowHelper.ThrowArgumentException<OpCode>(
|
||||
$"Type {type.FullDescription()} cannot be converted to"));
|
||||
: type == typeof(double)
|
||||
? ThrowHelper.ThrowInvalidOperationException<OpCode>(
|
||||
"There is no operation for converting to a double with overflow checking")
|
||||
: ConvertUnsignedWithOverflowCheckOpCodesByType.TryGetValue(type, out var value)
|
||||
? value
|
||||
: ThrowHelper.ThrowArgumentException<OpCode>(
|
||||
$"Type {type.FullDescription()} cannot be converted to"));
|
||||
}
|
||||
|
||||
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,
|
||||
bool throwOnFailure = true) where T : Delegate where V : Delegate
|
||||
public static CodeInstructions MethodReplacer<TFrom, TTo>(this CodeInstructions instructions, TFrom from, TTo to,
|
||||
bool throwOnFailure = true) where TFrom : Delegate where TTo : Delegate
|
||||
{
|
||||
Guard.IsNotNull(instructions);
|
||||
Guard.IsNotNull(from);
|
||||
@@ -2333,10 +2342,9 @@ public static class FishTranspiler
|
||||
|
||||
if (throwOnFailure && !success)
|
||||
{
|
||||
ThrowHelper.ThrowInvalidOperationException(
|
||||
$"FishTranspiler.Replace couldn't find target instruction for {
|
||||
predicate.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version {
|
||||
UtilityF.GetCallingAssembly().GetName().Version}");
|
||||
ThrowHelper.ThrowInvalidOperationException($"FishTranspiler.Replace couldn't find target instruction for {
|
||||
predicate.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version {
|
||||
UtilityF.GetCallingAssembly().GetName().Version}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2377,9 +2385,8 @@ public static class FishTranspiler
|
||||
|
||||
if (throwOnFailure && !success)
|
||||
{
|
||||
ThrowHelper.ThrowInvalidOperationException(
|
||||
$"FishTranspiler.ReplaceAt couldn't find target instruction for {
|
||||
position.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version {
|
||||
ThrowHelper.ThrowInvalidOperationException($"FishTranspiler.ReplaceAt couldn't find target instruction for {
|
||||
position.Method.FullDescription()} of {UtilityF.GetCallingAssembly().GetName().Name}, Version {
|
||||
UtilityF.GetCallingAssembly().GetName().Version}");
|
||||
}
|
||||
|
||||
@@ -2406,8 +2413,13 @@ public static class FishTranspiler
|
||||
return instruction;
|
||||
}
|
||||
|
||||
public static bool LoadsLocalVariable(this OpCode opcode)
|
||||
=> CodeInstructionExtensions.loadVarCodes.Contains(opcode);
|
||||
public static bool LoadsLocalVariable(this OpCode opcode) => LoadLocalVariableOpCodes.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)
|
||||
=> opcode.LoadsLocalVariable() && opcode != OpCodes.Ldarga && opcode != OpCodes.Ldarga_S ? opcode
|
||||
@@ -2416,8 +2428,12 @@ public static class FishTranspiler
|
||||
: opcode == OpCodes.Stloc ? OpCodes.Ldloc
|
||||
: ThrowHelper.ThrowInvalidOperationException<OpCode>($"{opcode} cannot be cast to Ldloc.");
|
||||
|
||||
public static bool StoresLocalVariable(this OpCode opcode)
|
||||
=> CodeInstructionExtensions.storeVarCodes.Contains(opcode);
|
||||
public static bool StoresLocalVariable(this OpCode opcode) => StoreLocalVariableOpCodes.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)
|
||||
=> opcode.StoresLocalVariable() ? opcode
|
||||
@@ -2498,9 +2514,16 @@ public static class FishTranspiler
|
||||
|
||||
public static bool LoadsString(this OpCode opcode) => opcode == OpCodes.Ldstr;
|
||||
|
||||
public static bool Branches(this OpCode opcode)
|
||||
=> CodeInstructionExtensions.branchCodes.Contains(opcode)
|
||||
|| opcode == OpCodes.Switch;
|
||||
public static bool Branches(this OpCode opcode) => BranchingOpCodes.Contains(opcode);
|
||||
|
||||
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);
|
||||
|
||||
@@ -2647,26 +2670,26 @@ public static class FishTranspiler
|
||||
{
|
||||
{ OpCodes.Ldarg_0, 0 },
|
||||
{ OpCodes.Ldarg_1, 1 },
|
||||
{ OpCodes.Ldarg_2, 2 },
|
||||
{ OpCodes.Ldarg_3, 3 },
|
||||
{ OpCodes.Ldloc_0, 0 },
|
||||
{ OpCodes.Ldloc_1, 1 },
|
||||
{ OpCodes.Ldloc_2, 2 },
|
||||
{ OpCodes.Ldloc_3, 3 },
|
||||
{ OpCodes.Stloc_0, 0 },
|
||||
{ OpCodes.Stloc_1, 1 },
|
||||
{ OpCodes.Stloc_2, 2 },
|
||||
{ OpCodes.Stloc_3, 3 },
|
||||
{ OpCodes.Ldc_I4_0, 0 },
|
||||
{ OpCodes.Ldc_I4_1, 1 },
|
||||
{ OpCodes.Ldc_I4_2, 2 },
|
||||
{ OpCodes.Ldc_I4_3, 3 },
|
||||
{ OpCodes.Ldc_I4_4, 4 },
|
||||
{ OpCodes.Ldc_I4_5, 5 },
|
||||
{ OpCodes.Ldc_I4_6, 6 },
|
||||
{ OpCodes.Ldc_I4_7, 7 },
|
||||
{ OpCodes.Ldc_I4_8, 8 },
|
||||
{ OpCodes.Ldc_I4_M1, -1 }
|
||||
{ OpCodes.Ldarg_2, 2 },
|
||||
{ OpCodes.Ldarg_3, 3 },
|
||||
{ OpCodes.Ldloc_0, 0 },
|
||||
{ OpCodes.Ldloc_1, 1 },
|
||||
{ OpCodes.Ldloc_2, 2 },
|
||||
{ OpCodes.Ldloc_3, 3 },
|
||||
{ OpCodes.Stloc_0, 0 },
|
||||
{ OpCodes.Stloc_1, 1 },
|
||||
{ OpCodes.Stloc_2, 2 },
|
||||
{ OpCodes.Stloc_3, 3 },
|
||||
{ OpCodes.Ldc_I4_0, 0 },
|
||||
{ OpCodes.Ldc_I4_1, 1 },
|
||||
{ OpCodes.Ldc_I4_2, 2 },
|
||||
{ OpCodes.Ldc_I4_3, 3 },
|
||||
{ OpCodes.Ldc_I4_4, 4 },
|
||||
{ OpCodes.Ldc_I4_5, 5 },
|
||||
{ OpCodes.Ldc_I4_6, 6 },
|
||||
{ OpCodes.Ldc_I4_7, 7 },
|
||||
{ OpCodes.Ldc_I4_8, 8 },
|
||||
{ OpCodes.Ldc_I4_M1, -1 }
|
||||
};
|
||||
|
||||
public static object? GetOperandFromIndex(int index) => index > 3 ? index : null;
|
||||
|
||||
@@ -10,11 +10,12 @@ global using System.Collections.Generic;
|
||||
global using System.Reflection;
|
||||
global using HarmonyLib;
|
||||
global using FisheryLib.Utility.Diagnostics;
|
||||
global using JetBrains.Annotations;
|
||||
global using CodeInstructions = System.Collections.Generic.IEnumerable<HarmonyLib.CodeInstruction>;
|
||||
global using NotNullAttribute = System.Diagnostics.CodeAnalysis.NotNullAttribute;
|
||||
using System.Security;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
[assembly: AllowPartiallyTrustedCallers]
|
||||
[assembly: SecurityRules(SecurityRuleSet.Level2, SkipVerificationInFullTrust = true)]
|
||||
@@ -28,11 +29,11 @@ namespace FisheryLib;
|
||||
[PublicAPI]
|
||||
public static class FisheryLib
|
||||
{
|
||||
public const decimal VERSION = 0.5M;
|
||||
public const decimal VERSION = 0.51M;
|
||||
|
||||
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()
|
||||
// {
|
||||
|
||||
@@ -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>
|
||||
@@ -3,18 +3,36 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.1.32120.378
|
||||
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
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
v1.3|Any CPU = v1.3|Any CPU
|
||||
v1.4|Any CPU = v1.4|Any CPU
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.3|Any CPU.ActiveCfg = v1.3|Any CPU
|
||||
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.3|Any CPU.Build.0 = v1.3|Any CPU
|
||||
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.4|Any CPU.ActiveCfg = v1.4|Any CPU
|
||||
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.4|Any CPU.Build.0 = v1.4|Any CPU
|
||||
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.Release|Any CPU.ActiveCfg = Release|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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib.FunctionPointers;
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib.FunctionPointers;
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib.FunctionPointers;
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib.FunctionPointers;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
// You can obtain one at https://opensource.org/licenses/MIT/.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
@@ -15,9 +14,19 @@ public static class GUIScope
|
||||
{
|
||||
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
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
// 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 JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
[PublicAPI]
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib.Pools;
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib.Pools;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib.Pools;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FisheryLib.Pools;
|
||||
using JetBrains.Annotations;
|
||||
using Verse;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
using System.Diagnostics;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace FisheryLib;
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Reference in New Issue
Block a user