mirror of
https://github.com/AssetRipper/AssetRipper.Primitives.git
synced 2026-11-13 04:26:30 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c4a7d8127 | ||
|
|
fd3590ad52 | ||
|
|
3ef5dae9d4 | ||
|
|
78ecfb7de4 | ||
|
|
5080b7eb29 | ||
|
|
2e8940973f | ||
|
|
64f50b46fb | ||
|
|
fbdda777ac | ||
|
|
2de06bfaf4 | ||
|
|
c7a8932863 | ||
|
|
4bcc823371 | ||
|
|
7630da6da0 | ||
|
|
e5802e39ee | ||
|
|
c663c68124 | ||
|
|
fa2458cfae | ||
|
|
ee923d8e9b | ||
|
|
8b23a0c671 | ||
|
|
f56feaf217 | ||
|
|
bd575f0063 | ||
|
|
0a6b003bf2 | ||
|
|
f4026adfd0 |
No files matched your search
@@ -7,6 +7,23 @@ on:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
net8:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup .NET
|
||||
uses: actions/[email protected]
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
run: dotnet build --framework net8.0 --no-restore
|
||||
- name: Test
|
||||
run: dotnet test --framework net8.0 --no-build --verbosity normal
|
||||
|
||||
net7:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
@@ -50,9 +67,7 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/[email protected]
|
||||
with:
|
||||
dotnet-version: |
|
||||
5.0.x
|
||||
6.0.x
|
||||
dotnet-version: 5.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<LangVersion>Latest</LangVersion>
|
||||
<TargetFrameworks>net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.11" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,11 +0,0 @@
|
||||
using BenchmarkDotNet.Running;
|
||||
|
||||
namespace AssetRipper.Primitives.Benckmarks;
|
||||
|
||||
internal static class Program
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
BenchmarkRunner.Run(typeof(Program).Assembly);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace AssetRipper.Primitives.Benckmarks;
|
||||
|
||||
[SimpleJob(RuntimeMoniker.Net80)]
|
||||
[RPlotExporter]
|
||||
public class YearVersionCheck
|
||||
{
|
||||
[Params(4, 5, 6, 7, 2016, 2017, 2018, 2022, 2023, 2024)]
|
||||
public ushort Major;
|
||||
|
||||
[Benchmark]
|
||||
public bool Simple() => Major is >= 2017 and <= 2023;
|
||||
|
||||
[Benchmark]
|
||||
public bool BitsWith2016() => BitComparison(Major);
|
||||
|
||||
[Benchmark]
|
||||
public bool BitsWithout2016() => BitComparison(Major) && Major is not 2016;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static bool BitComparison(uint value)
|
||||
{
|
||||
//This function determines if an unsigned integer
|
||||
//is between 2016 and 2023, inclusive. It does this
|
||||
//by comparing bits of the value with know constants.
|
||||
|
||||
const uint VariableBitMask = 0x7;
|
||||
const uint FixedBitMask = ~VariableBitMask;
|
||||
const uint ExpectedFixedBits = 0x7E0;//2016
|
||||
return (value & FixedBitMask) == ExpectedFixedBits;
|
||||
}
|
||||
|
||||
/* Results:
|
||||
* Due to the simplicity of the methods being profiled,
|
||||
* benchmarking was inconclusive. The costs of calling
|
||||
* these methods are almost neglible.
|
||||
*
|
||||
* Decision:
|
||||
* For the time being, the library will continue to use
|
||||
* the simple bounds check. If another option is shown
|
||||
* to be significantly better, I am open to switching.
|
||||
*/
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netframework3.5;netframework4.0;netframework4.8;net5.0;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net35;net40;net48;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<LangVersion>Latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.14.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.10.0">
|
||||
<PackageReference Include="NUnit.Analyzers" Version="4.1.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -72,20 +72,4 @@ public class ComparisonTests
|
||||
Assert.That(new UnityVersion(2019, 1, 0, UnityVersionType.Final, 1).LessThanOrEquals(2019, 1, 0));
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(2017)]
|
||||
[TestCase(2018)]
|
||||
[TestCase(2019)]
|
||||
[TestCase(2020)]
|
||||
[TestCase(2021)]
|
||||
[TestCase(2022)]
|
||||
[TestCase(2023)]
|
||||
public void YearVersioningIsBetweenFiveAndSix(int year)
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(new UnityVersion((ushort)year).GreaterThan(5));
|
||||
Assert.That(new UnityVersion((ushort)year).LessThan(6));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,13 @@ public class ParsingTests
|
||||
[TestCase("4.2.2f1\n1", 4, 2, 2, UnityVersionType.Final, 1, "\n1", "Custom Unity 4 Version")]
|
||||
[TestCase("2343.4.5f7", 2343, 4, 5, UnityVersionType.Final, 7, null, "Fictitious Future Version")]
|
||||
[TestCase("2019.2.2f1c2\n2", 2019, 2, 2, UnityVersionType.China, 2, "\n2", "Fake Custom Chinese Version")]
|
||||
[TestCase("2019", 2019, 0, 0, UnityVersionType.Final, 1, null, "Major Only")]
|
||||
[TestCase("2019.4", 2019, 4, 0, UnityVersionType.Final, 1, null, "Major Minor Only")]
|
||||
[TestCase("2019.4.3", 2019, 4, 3, UnityVersionType.Final, 1, null, "Major Minor Build Only")]
|
||||
[TestCase("0", 0, 0, 0, UnityVersionType.Alpha, 0, null, "Zero, Major Only")]
|
||||
[TestCase("0.0", 0, 0, 0, UnityVersionType.Alpha, 0, null, "Zero, Major Minor Only")]
|
||||
[TestCase("0.0.0", 0, 0, 0, UnityVersionType.Alpha, 0, null, "Zero, Major Minor Build Only")]
|
||||
[TestCase("0.0.0b2", 0, 0, 0, UnityVersionType.Beta, 2, null, "Zero, Full")]
|
||||
[TestCase("2019.2.2f1-letters", 2019, 2, 2, UnityVersionType.Final, 1, "-letters", "Issue #40 - Appended Custom Characters")]
|
||||
public void UnityVersionParsesCorrectly(string versionString, int major, int minor, int build, UnityVersionType type, int typeNumber, string? customEngine, string name)
|
||||
{
|
||||
@@ -20,7 +25,7 @@ public class ParsingTests
|
||||
{
|
||||
Assert.That(parsedCustomEngine, Is.EqualTo(customEngine), $"The custom engine boolean is incorrect for '{name}'");
|
||||
Assert.That(parsedVersion, Is.EqualTo(expected), $"The parsed version is incorrect for '{name}'");
|
||||
if (customEngine is not null || typeNumber is not 1)
|
||||
if (customEngine is not null || typeNumber is not 0 and not 1)
|
||||
{
|
||||
Assert.That(parsedVersion.ToString(UnityVersionFormatFlags.Default, parsedCustomEngine ?? ""), Is.EqualTo(versionString));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if NET7_0_OR_GREATER
|
||||
#if NET5_0_OR_GREATER
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -83,7 +83,7 @@ public class UnityGuidTests
|
||||
{
|
||||
Guid originalGuid = Guid.NewGuid();
|
||||
UnityGuid tobyteArrayGuid = new UnityGuid(originalGuid.ToByteArray());
|
||||
UnityGuid memoryMarshallGuid = new UnityGuid(MemoryMarshal.Cast<Guid, byte>(new ReadOnlySpan<Guid>(in originalGuid)));
|
||||
UnityGuid memoryMarshallGuid = Unsafe.As<Guid, UnityGuid>(ref originalGuid);
|
||||
Assert.That(memoryMarshallGuid, Is.EqualTo(tobyteArrayGuid));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if NET7_0_OR_GREATER
|
||||
#if NET5_0_OR_GREATER
|
||||
namespace AssetRipper.Primitives.Tests;
|
||||
|
||||
public class Utf8StringTests
|
||||
|
||||
@@ -24,8 +24,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetRipper.Primitives", "A
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetRipper.Primitives.Tests", "AssetRipper.Primitives.Tests\AssetRipper.Primitives.Tests.csproj", "{545E670D-141B-4F05-9AFD-2F184A59EADC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssetRipper.Primitives.Benckmarks", "AssetRipper.Primitives.Benckmarks\AssetRipper.Primitives.Benckmarks.csproj", "{E3DEB571-4EE4-4C89-9005-DB10D9FB561B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -40,10 +38,6 @@ Global
|
||||
{545E670D-141B-4F05-9AFD-2F184A59EADC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{545E670D-141B-4F05-9AFD-2F184A59EADC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{545E670D-141B-4F05-9AFD-2F184A59EADC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E3DEB571-4EE4-4C89-9005-DB10D9FB561B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E3DEB571-4EE4-4C89-9005-DB10D9FB561B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E3DEB571-4EE4-4C89-9005-DB10D9FB561B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E3DEB571-4EE4-4C89-9005-DB10D9FB561B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netframework3.5;netframework4.0;netstandard2.0;net5.0;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net35;net40;net461;netstandard2.0;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<LangVersion>Latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<Authors>ds5678</Authors>
|
||||
<Company>AssetRipper</Company>
|
||||
<Version>2.1.0</Version>
|
||||
<Version>3.1.3</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<PackageId>AssetRipper.Primitives</PackageId>
|
||||
<PackageTags>C# assetripper unity unity3d</PackageTags>
|
||||
@@ -14,26 +14,45 @@
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageProjectUrl>https://github.com/AssetRipper/AssetRipper.Primitives</PackageProjectUrl>
|
||||
<Copyright>Copyright (c) 2022-2023 ds5678</Copyright>
|
||||
<Copyright>Copyright (c) 2022-2024 ds5678</Copyright>
|
||||
<Description>Managed library for primitive types used in AssetRipper.</Description>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<NoWarn>1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' != 'netframework3.5' and '$(TargetFramework)' != 'netframework4.0' ">
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' != 'net35' and '$(TargetFramework)' != 'net40' ">
|
||||
<IsTrimmable>true</IsTrimmable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
||||
<IsAotCompatible>true</IsAotCompatible>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="PolySharp" Version="1.14.0">
|
||||
<PackageReference Include="PolySharp" Version="1.14.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'net461'">
|
||||
<PackageReference Include="Microsoft.Bcl.HashCode">
|
||||
<Version>1.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Memory">
|
||||
<Version>4.5.5</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net461'">
|
||||
<PackageReference Include="System.ValueTuple">
|
||||
<Version>4.5.0</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,21 +1,31 @@
|
||||
#if NET7_0_OR_GREATER
|
||||
#if NET5_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER || NET461_OR_GREATER
|
||||
using System.Buffers.Binary;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AssetRipper.Primitives;
|
||||
|
||||
[JsonConverter(typeof(UnityGuidJsonConverter))]
|
||||
#if NET5_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonConverter(typeof(UnityGuidJsonConverter))]
|
||||
#endif
|
||||
public readonly record struct UnityGuid
|
||||
#if NET7_0_OR_GREATER
|
||||
: System.Numerics.IEqualityOperators<UnityGuid, UnityGuid, bool>
|
||||
#endif
|
||||
{
|
||||
public UnityGuid(Guid guid)
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
Span<byte> guidData = stackalloc byte[16];
|
||||
bool success = guid.TryWriteBytes(guidData);
|
||||
Debug.Assert(success);
|
||||
#else
|
||||
Span<byte> guidData = guid.ToByteArray();
|
||||
#endif
|
||||
ConvertSystemOrUnityBytes(guidData, guidData);
|
||||
Data0 = ReadUInt32LittleEndian(guidData, 0);
|
||||
Data1 = ReadUInt32LittleEndian(guidData, 1);
|
||||
@@ -44,10 +54,24 @@ public readonly record struct UnityGuid
|
||||
//This is not an acceptable way to convert between Unity and System Guids.
|
||||
//We only do it this way to efficiently get 16 random bytes.
|
||||
//We don't care about official Guid validity because Unity does not care either.
|
||||
Guid guid = Guid.NewGuid();
|
||||
ReadOnlySpan<Guid> guidSpan = new ReadOnlySpan<Guid>(in guid);
|
||||
ReadOnlySpan<byte> byteSpan = MemoryMarshal.AsBytes(guidSpan);
|
||||
return new UnityGuid(byteSpan);
|
||||
if (Unsafe.SizeOf<Guid>() == Unsafe.SizeOf<UnityGuid>())
|
||||
{
|
||||
Guid guid = Guid.NewGuid();
|
||||
return Unsafe.As<Guid, UnityGuid>(ref guid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ThrowOrReturnDefault();
|
||||
}
|
||||
|
||||
static UnityGuid ThrowOrReturnDefault()
|
||||
{
|
||||
#if DEBUG
|
||||
throw new InvalidCastException($"{nameof(UnityGuid)} struct size does not match {nameof(Guid)}.");
|
||||
#else
|
||||
return default;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public static explicit operator UnityGuid(Guid systemGuid) => new UnityGuid(systemGuid);
|
||||
@@ -57,7 +81,11 @@ public readonly record struct UnityGuid
|
||||
Span<byte> span = stackalloc byte[16];
|
||||
unityGuid.Write(span);
|
||||
ConvertSystemOrUnityBytes(span, span);
|
||||
#if NET5_0_OR_GREATER
|
||||
return new Guid(span);
|
||||
#else
|
||||
return new Guid(span.ToArray());
|
||||
#endif
|
||||
}
|
||||
|
||||
private void Write(Span<byte> span)
|
||||
@@ -79,7 +107,16 @@ public readonly record struct UnityGuid
|
||||
{
|
||||
Span<char> span = stackalloc char[32];
|
||||
ToString(span);
|
||||
return new string(span);
|
||||
return CreateString(span);
|
||||
|
||||
static string CreateString(Span<char> span)
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
return new string(span);
|
||||
#else
|
||||
return new string(span.ToArray());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public void ToString(Span<char> buffer)
|
||||
@@ -193,15 +230,31 @@ public readonly record struct UnityGuid
|
||||
/// <returns>A stable guid corresponding to the <paramref name="input"/>.</returns>
|
||||
public static UnityGuid Md5Hash(scoped ReadOnlySpan<byte> input)
|
||||
{
|
||||
byte[] hashBytes = MD5.HashData(input);
|
||||
ConvertSystemOrUnityBytes(hashBytes, hashBytes);
|
||||
return new UnityGuid(hashBytes);
|
||||
Span<byte> buffer = stackalloc byte[16];
|
||||
HashData(input, buffer);
|
||||
ConvertSystemOrUnityBytes(buffer, buffer);
|
||||
return new UnityGuid(buffer);
|
||||
}
|
||||
|
||||
private static void HashData(ReadOnlySpan<byte> data, Span<byte> buffer)
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
MD5.HashData(data, buffer);
|
||||
#else
|
||||
MD5.Create().ComputeHash(data.ToArray()).AsSpan().CopyTo(buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static UnityGuid Md5Hash(scoped ReadOnlySpan<byte> assemblyName, scoped ReadOnlySpan<byte> @namespace, scoped ReadOnlySpan<byte> className)
|
||||
{
|
||||
int length = assemblyName.Length + @namespace.Length + className.Length;
|
||||
Span<byte> input = length < 1024 ? stackalloc byte[length] : GC.AllocateUninitializedArray<byte>(length);
|
||||
Span<byte> input = length < 1024
|
||||
? stackalloc byte[length]
|
||||
#if NET5_0_OR_GREATER
|
||||
: GC.AllocateUninitializedArray<byte>(length);
|
||||
#else
|
||||
: new byte[length];
|
||||
#endif
|
||||
assemblyName.CopyTo(input);
|
||||
@namespace.CopyTo(input.Slice(assemblyName.Length));
|
||||
className.CopyTo(input.Slice(assemblyName.Length + @namespace.Length));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if NET7_0_OR_GREATER
|
||||
#if NET5_0_OR_GREATER
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
|
||||
@@ -27,47 +27,7 @@ public readonly partial struct UnityVersion : IEquatable<UnityVersion>, ICompara
|
||||
/// </returns>
|
||||
public int CompareTo(UnityVersion other)
|
||||
{
|
||||
//Unity 6 is sequentially equivalent to Unity 2024 because
|
||||
//they switched to back to the old versioning scheme.
|
||||
const ushort FirstNewVersion = 6;
|
||||
|
||||
if (this == other)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (UsesYearNumbering(this))
|
||||
{
|
||||
if (UsesYearNumbering(other))
|
||||
{
|
||||
return CompareByData(this, other);
|
||||
}
|
||||
else
|
||||
{
|
||||
return other.Major < FirstNewVersion ? 1 : -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UsesYearNumbering(other))
|
||||
{
|
||||
return Major < FirstNewVersion ? -1 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CompareByData(this, other);
|
||||
}
|
||||
}
|
||||
|
||||
static int CompareByData(UnityVersion x, UnityVersion y)
|
||||
{
|
||||
return x.m_data < y.m_data ? -1 : 1;
|
||||
}
|
||||
|
||||
static bool UsesYearNumbering(UnityVersion version)
|
||||
{
|
||||
return version.Major is >= 2017 and <= 2023;
|
||||
}
|
||||
return m_data.CompareTo(other.m_data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -90,6 +50,6 @@ public readonly partial struct UnityVersion : IEquatable<UnityVersion>, ICompara
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return unchecked(827 + 911 * m_data.GetHashCode());
|
||||
return m_data.GetHashCode();
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ public readonly partial struct UnityVersion
|
||||
/// <returns></returns>
|
||||
public static bool operator >(UnityVersion left, UnityVersion right)
|
||||
{
|
||||
return left.CompareTo(right) > 0;
|
||||
return left.m_data > right.m_data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -43,7 +43,7 @@ public readonly partial struct UnityVersion
|
||||
/// <returns></returns>
|
||||
public static bool operator >=(UnityVersion left, UnityVersion right)
|
||||
{
|
||||
return left.CompareTo(right) >= 0;
|
||||
return left.m_data >= right.m_data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -54,7 +54,7 @@ public readonly partial struct UnityVersion
|
||||
/// <returns></returns>
|
||||
public static bool operator <(UnityVersion left, UnityVersion right)
|
||||
{
|
||||
return left.CompareTo(right) < 0;
|
||||
return left.m_data < right.m_data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -65,6 +65,6 @@ public readonly partial struct UnityVersion
|
||||
/// <returns></returns>
|
||||
public static bool operator <=(UnityVersion left, UnityVersion right)
|
||||
{
|
||||
return left.CompareTo(right) <= 0;
|
||||
return left.m_data <= right.m_data;
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,8 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AssetRipper.Primitives;
|
||||
|
||||
public readonly partial struct UnityVersion
|
||||
{
|
||||
private static readonly Regex majorMinorRegex = new Regex(@"^([0-9]+)\.([0-9]+)$", RegexOptions.Compiled);
|
||||
private static readonly Regex majorMinorBuildRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)$", RegexOptions.Compiled);
|
||||
private static readonly Regex normalRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)\.?([abcfpx])([0-9]+)((?:.|[\r\n])+)?$", RegexOptions.Compiled);
|
||||
private static readonly Regex chinaRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)\.?f1c([0-9]+)((?:.|[\r\n])+)?$", RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Serialize the version as a string using <see cref="UnityVersionFormatFlags.Default"/>.
|
||||
/// </summary>
|
||||
@@ -98,7 +92,7 @@ public readonly partial struct UnityVersion
|
||||
version = default;
|
||||
return false;
|
||||
}
|
||||
else if (chinaRegex.TryMatch(s, out Match? match))
|
||||
else if (UnityVersionRegexes.GetChinaRegex().TryMatch(s, out Match? match))
|
||||
{
|
||||
int major = int.Parse(match.Groups[1].Value);
|
||||
int minor = int.Parse(match.Groups[2].Value);
|
||||
@@ -108,7 +102,7 @@ public readonly partial struct UnityVersion
|
||||
version = new UnityVersion((ushort)major, (ushort)minor, (ushort)build, UnityVersionType.China, (byte)typeNumber);
|
||||
return true;
|
||||
}
|
||||
else if(normalRegex.TryMatch(s, out match))
|
||||
else if(UnityVersionRegexes.GetNormalRegex().TryMatch(s, out match))
|
||||
{
|
||||
int major = int.Parse(match.Groups[1].Value);
|
||||
int minor = int.Parse(match.Groups[2].Value);
|
||||
@@ -119,21 +113,34 @@ public readonly partial struct UnityVersion
|
||||
version = new UnityVersion((ushort)major, (ushort)minor, (ushort)build, type.ToUnityVersionType(), (byte)typeNumber);
|
||||
return true;
|
||||
}
|
||||
else if (majorMinorBuildRegex.TryMatch(s, out match))
|
||||
else if (UnityVersionRegexes.GetMajorMinorBuildRegex().TryMatch(s, out match))
|
||||
{
|
||||
int major = int.Parse(match.Groups[1].Value);
|
||||
int minor = int.Parse(match.Groups[2].Value);
|
||||
int build = int.Parse(match.Groups[3].Value);
|
||||
customEngine = null;
|
||||
version = new UnityVersion((ushort)major, (ushort)minor, (ushort)build, UnityVersionType.Final, 1);
|
||||
version = major is not 0 || minor is not 0 || build is not 0
|
||||
? new UnityVersion((ushort)major, (ushort)minor, (ushort)build, UnityVersionType.Final, 1)
|
||||
: default;
|
||||
return true;
|
||||
}
|
||||
else if (majorMinorRegex.TryMatch(s, out match))
|
||||
else if (UnityVersionRegexes.GetMajorMinorRegex().TryMatch(s, out match))
|
||||
{
|
||||
int major = int.Parse(match.Groups[1].Value);
|
||||
int minor = int.Parse(match.Groups[2].Value);
|
||||
customEngine = null;
|
||||
version = new UnityVersion((ushort)major, (ushort)minor, 0, UnityVersionType.Final, 1);
|
||||
version = major is not 0 || minor is not 0
|
||||
? new UnityVersion((ushort)major, (ushort)minor, 0, UnityVersionType.Final, 1)
|
||||
: default;
|
||||
return true;
|
||||
}
|
||||
else if (UnityVersionRegexes.GetMajorRegex().TryMatch(s, out match))
|
||||
{
|
||||
int major = int.Parse(match.Groups[1].Value);
|
||||
customEngine = null;
|
||||
version = major is not 0
|
||||
? new UnityVersion((ushort)major, 0, 0, UnityVersionType.Final, 1)
|
||||
: default;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AssetRipper.Primitives;
|
||||
|
||||
internal static partial class UnityVersionRegexes
|
||||
{
|
||||
#if NET35
|
||||
private const RegexOptions Options = RegexOptions.None;
|
||||
#else
|
||||
private const RegexOptions Options = RegexOptions.Compiled;
|
||||
#endif
|
||||
|
||||
[StringSyntax("regex")]
|
||||
private const string Major = @"([0-9]+)";
|
||||
|
||||
[StringSyntax("regex")]
|
||||
private const string MajorMinor = @"([0-9]+)\.([0-9]+)";
|
||||
|
||||
[StringSyntax("regex")]
|
||||
private const string MajorMinorBuild = @"([0-9]+)\.([0-9]+)\.([0-9]+)";
|
||||
|
||||
[StringSyntax("regex")]
|
||||
private const string Normal = @"([0-9]+)\.([0-9]+)\.([0-9]+)\.?([abcfpx])([0-9]+)((?:.|[\r\n])+)?";
|
||||
|
||||
[StringSyntax("regex")]
|
||||
private const string China = @"([0-9]+)\.([0-9]+)\.([0-9]+)\.?f1c([0-9]+)((?:.|[\r\n])+)?";
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[GeneratedRegex(Major, Options)]
|
||||
public static partial Regex GetMajorRegex();
|
||||
#else
|
||||
private static readonly Regex majorRegex = new Regex(Major, Options);
|
||||
public static Regex GetMajorRegex() => majorRegex;
|
||||
#endif
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[GeneratedRegex(MajorMinor, Options)]
|
||||
public static partial Regex GetMajorMinorRegex();
|
||||
#else
|
||||
private static readonly Regex majorMinorRegex = new Regex(MajorMinor, Options);
|
||||
public static Regex GetMajorMinorRegex() => majorMinorRegex;
|
||||
#endif
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[GeneratedRegex(MajorMinorBuild, Options)]
|
||||
public static partial Regex GetMajorMinorBuildRegex();
|
||||
#else
|
||||
private static readonly Regex majorMinorBuildRegex = new Regex(MajorMinorBuild, Options);
|
||||
public static Regex GetMajorMinorBuildRegex() => majorMinorBuildRegex;
|
||||
#endif
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[GeneratedRegex(Normal, Options)]
|
||||
public static partial Regex GetNormalRegex();
|
||||
#else
|
||||
private static readonly Regex normalRegex = new Regex(Normal, Options);
|
||||
public static Regex GetNormalRegex() => normalRegex;
|
||||
#endif
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[GeneratedRegex(China, Options)]
|
||||
public static partial Regex GetChinaRegex();
|
||||
#else
|
||||
private static readonly Regex chinaRegex = new Regex(China, Options);
|
||||
public static Regex GetChinaRegex() => chinaRegex;
|
||||
#endif
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#if NET7_0_OR_GREATER
|
||||
#if NET5_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER || NET461_OR_GREATER
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
@@ -11,7 +11,12 @@ namespace AssetRipper.Primitives;
|
||||
/// <remarks>
|
||||
/// Conversions to and from <see cref="string"/> are handled by <see cref="Encoding.UTF8"/>.
|
||||
/// </remarks>
|
||||
public sealed class Utf8String : IEquatable<Utf8String>
|
||||
public sealed class Utf8String :
|
||||
#if NET7_0_OR_GREATER
|
||||
System.Numerics.IEqualityOperators<Utf8String?, Utf8String?, bool>,
|
||||
System.Numerics.IEqualityOperators<Utf8String?, string?, bool>,
|
||||
#endif
|
||||
IEquatable<Utf8String>
|
||||
{
|
||||
private readonly byte[] data;
|
||||
private string? cachedString;
|
||||
@@ -60,7 +65,14 @@ public sealed class Utf8String : IEquatable<Utf8String>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
HashCode hash = new();
|
||||
#if NET6_0_OR_GREATER
|
||||
hash.AddBytes(data);
|
||||
#else
|
||||
foreach (byte b in data)
|
||||
{
|
||||
hash.Add(b);
|
||||
}
|
||||
#endif
|
||||
return hash.ToHashCode();
|
||||
}
|
||||
|
||||
@@ -198,7 +210,10 @@ public sealed class Utf8String : IEquatable<Utf8String>
|
||||
|
||||
public static Utf8String Concat(params Utf8String?[] values)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(values);
|
||||
if (values is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(values));
|
||||
}
|
||||
|
||||
int totalLength = 0;
|
||||
foreach (Utf8String? value in values)
|
||||
|
||||
Reference in new issue
Block a user