using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using AssetRipper.VersionUtilities.Extensions; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("VersionUtilities.Tests")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyMetadata("IsTrimmable", "True")] [assembly: AssemblyCompany("AssetRipper")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2022-2023 ds5678")] [assembly: AssemblyDescription("Managed library for handling Unity versions")] [assembly: AssemblyFileVersion("1.3.1.0")] [assembly: AssemblyInformationalVersion("1.3.1.0+3e5ee806808370156f641019e278b30a80ab5062")] [assembly: AssemblyProduct("AssetRipper.VersionUtilities")] [assembly: AssemblyTitle("AssetRipper.VersionUtilities")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/AssetRipper/VersionUtilities")] [assembly: AssemblyVersion("1.3.1.0")] [assembly: TypeForwardedTo(typeof(IsExternalInit))] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] internal sealed class RequiredMemberAttribute : Attribute { } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] internal sealed class UnscopedRefAttribute : Attribute { } } namespace AssetRipper.VersionUtilities { public struct CompactUnityVersion24 : IEquatable, IComparable, IComparable { private const int majorOffset = 3; private const int buildOffset = 9; private const int typeOffset = 6; private const uint bitMask3 = 7u; private const uint bitMask5 = 31u; private const uint bitMask6 = 63u; private const uint bitMask7 = 127u; private readonly byte m_MajorMinorByte; private readonly ushort m_BuildTypeShort; public const ushort MajorMaxValue = 2042; private byte MajorRaw => (byte)((ulong)(m_MajorMinorByte >> 3) & 0x1FuL); public ushort Major => ConvertMajorRawToNormal(MajorRaw); public byte Minor => (byte)(m_MajorMinorByte & 7u); public byte Build => (byte)((ulong)(m_BuildTypeShort >> 9) & 0x7FuL); public UnityVersionType Type => (UnityVersionType)((ulong)(m_BuildTypeShort >> 6) & 7uL); public byte TypeNumber => (byte)(m_BuildTypeShort & 0x3Fu); public static CompactUnityVersion24 MinVersion { get; } = new CompactUnityVersion24((byte)0, (ushort)0); public static CompactUnityVersion24 MaxVersion { get; } = new CompactUnityVersion24(byte.MaxValue, ushort.MaxValue); public CompactUnityVersion24(ushort major) { m_MajorMinorByte = (byte)(ConvertMajorRawToNormal(major) << 3); m_BuildTypeShort = 0; } public CompactUnityVersion24(ushort major, byte minor) { m_MajorMinorByte = (byte)((ConvertMajorRawToNormal(major) << 3) | CastToThreeBits(minor)); m_BuildTypeShort = 0; } public CompactUnityVersion24(ushort major, byte minor, byte build) { m_MajorMinorByte = (byte)((ConvertMajorRawToNormal(major) << 3) | CastToThreeBits(minor)); m_BuildTypeShort = (ushort)(CastToSevenBits(build) << 9); } public CompactUnityVersion24(ushort major, byte minor, byte build, UnityVersionType type) { m_MajorMinorByte = (byte)((ConvertMajorRawToNormal(major) << 3) | CastToThreeBits(minor)); m_BuildTypeShort = (ushort)((CastToSevenBits(build) << 9) | (CastToThreeBits((byte)type) << 6)); } public CompactUnityVersion24(ushort major, byte minor, byte build, UnityVersionType type, byte typeNumber) { m_MajorMinorByte = (byte)((ConvertMajorRawToNormal(major) << 3) | CastToThreeBits(minor)); m_BuildTypeShort = (ushort)((CastToSevenBits(build) << 9) | (CastToThreeBits((byte)type) << 6) | CastToSixBits(typeNumber)); } private CompactUnityVersion24(byte majorMinorByte, ushort buildTypeShort) { m_MajorMinorByte = majorMinorByte; m_BuildTypeShort = buildTypeShort; } public void GetBits(out byte majorMinorByte, out ushort buildTypeShort) { majorMinorByte = m_MajorMinorByte; buildTypeShort = m_BuildTypeShort; } public static CompactUnityVersion24 FromBits(byte majorMinorByte, ushort buildTypeShort) { return new CompactUnityVersion24(majorMinorByte, buildTypeShort); } private static ushort ConvertMajorRawToNormal(byte raw) { if (raw >= 6) { return (ushort)(raw + 2011); } return raw; } private static byte ConvertMajorRawToNormal(ushort major) { if (major < 6) { return (byte)major; } if (major >= 2017 && major <= 2042) { return (byte)(major - 2011); } throw new ArgumentOutOfRangeException("major"); } private static byte CastToThreeBits(byte b) { if ((uint)b > 7u) { throw new ArgumentOutOfRangeException("b"); } return b; } private static byte CastToSixBits(byte b) { if ((uint)b > 63u) { throw new ArgumentOutOfRangeException("b"); } return b; } private static byte CastToSevenBits(byte b) { if ((uint)b > 127u) { throw new ArgumentOutOfRangeException("b"); } return b; } public override string ToString() { return ((UnityVersion)this).ToString(); } public int CompareTo(object? obj) { if (!(obj is CompactUnityVersion24 other)) { return 1; } return CompareTo(other); } public int CompareTo(CompactUnityVersion24 other) { if (this > other) { return 1; } if (this < other) { return -1; } return 0; } public override bool Equals(object? obj) { if (obj is CompactUnityVersion24 compactUnityVersion) { return this == compactUnityVersion; } return false; } public bool Equals(CompactUnityVersion24 other) { return this == other; } public override int GetHashCode() { return (m_MajorMinorByte << 16) | m_BuildTypeShort; } public static implicit operator UnityVersion(CompactUnityVersion24 version) { return new UnityVersion(version.Major, version.Minor, version.Build, version.Type, version.TypeNumber); } public static implicit operator CompactUnityVersion32(CompactUnityVersion24 version) { return new CompactUnityVersion32(version.Major, version.Minor, version.Build, version.Type, version.TypeNumber); } public static explicit operator CompactUnityVersion24(UnityVersion version) { return new CompactUnityVersion24(version.Major, (byte)version.Minor, (byte)version.Build, version.Type, version.TypeNumber); } public static explicit operator CompactUnityVersion24(CompactUnityVersion32 version) { return new CompactUnityVersion24(version.Major, version.Minor, version.Build, version.Type, version.TypeNumber); } public static bool operator ==(CompactUnityVersion24 left, CompactUnityVersion24 right) { if (left.m_MajorMinorByte == right.m_MajorMinorByte) { return left.m_BuildTypeShort == right.m_BuildTypeShort; } return false; } public static bool operator !=(CompactUnityVersion24 left, CompactUnityVersion24 right) { if (left.m_MajorMinorByte == right.m_MajorMinorByte) { return left.m_BuildTypeShort != right.m_BuildTypeShort; } return true; } public static bool operator >(CompactUnityVersion24 left, CompactUnityVersion24 right) { if (left.m_MajorMinorByte <= right.m_MajorMinorByte) { if (left.m_MajorMinorByte == right.m_MajorMinorByte) { return left.m_BuildTypeShort > right.m_BuildTypeShort; } return false; } return true; } public static bool operator >=(CompactUnityVersion24 left, CompactUnityVersion24 right) { if (left.m_MajorMinorByte <= right.m_MajorMinorByte) { if (left.m_MajorMinorByte == right.m_MajorMinorByte) { return left.m_BuildTypeShort >= right.m_BuildTypeShort; } return false; } return true; } public static bool operator <(CompactUnityVersion24 left, CompactUnityVersion24 right) { if (left.m_MajorMinorByte >= right.m_MajorMinorByte) { if (left.m_MajorMinorByte == right.m_MajorMinorByte) { return left.m_BuildTypeShort < right.m_BuildTypeShort; } return false; } return true; } public static bool operator <=(CompactUnityVersion24 left, CompactUnityVersion24 right) { if (left.m_MajorMinorByte >= right.m_MajorMinorByte) { if (left.m_MajorMinorByte == right.m_MajorMinorByte) { return left.m_BuildTypeShort <= right.m_BuildTypeShort; } return false; } return true; } } public struct CompactUnityVersion32 : IEquatable, IComparable, IComparable { private const int majorOffset = 24; private const int minorOffset = 20; private const int buildOffset = 12; private const int typeOffset = 8; private const uint byteMask = 255u; private const uint bitMask4 = 15u; private readonly uint m_data; public const ushort MajorMaxValue = 2266; private byte MajorRaw => (byte)((m_data >> 24) & 0xFFu); public ushort Major => ConvertMajorRawToNormal(MajorRaw); public byte Minor => (byte)((m_data >> 20) & 0xFu); public byte Build => (byte)((m_data >> 12) & 0xFFu); public UnityVersionType Type => (UnityVersionType)((m_data >> 8) & 0xFu); public byte TypeNumber => (byte)(m_data & 0xFFu); public static CompactUnityVersion32 MinVersion { get; } = new CompactUnityVersion32(0u); public static CompactUnityVersion32 MaxVersion { get; } = new CompactUnityVersion32(uint.MaxValue); public CompactUnityVersion32(ushort major) { m_data = (uint)(ConvertMajorRawToNormal(major) << 24); } public CompactUnityVersion32(ushort major, byte minor) { m_data = (uint)((ConvertMajorRawToNormal(major) << 24) | (CastToFourBits(minor) << 20)); } public CompactUnityVersion32(ushort major, byte minor, byte build) { m_data = (uint)((ConvertMajorRawToNormal(major) << 24) | (CastToFourBits(minor) << 20) | (build << 12)); } public CompactUnityVersion32(ushort major, byte minor, byte build, UnityVersionType type) { m_data = (uint)((ConvertMajorRawToNormal(major) << 24) | (CastToFourBits(minor) << 20) | (build << 12)) | ((uint)CastToFourBits(type) << 8); } public CompactUnityVersion32(ushort major, byte minor, byte build, UnityVersionType type, byte typeNumber) { m_data = (uint)((ConvertMajorRawToNormal(major) << 24) | (CastToFourBits(minor) << 20) | (build << 12)) | ((uint)CastToFourBits(type) << 8) | typeNumber; } private CompactUnityVersion32(uint data) { m_data = data; } public uint GetBits() { return m_data; } public static CompactUnityVersion32 FromBits(uint bits) { return new CompactUnityVersion32(bits); } private static ushort ConvertMajorRawToNormal(byte raw) { if (raw >= 6) { return (ushort)(raw + 2011); } return raw; } private static byte ConvertMajorRawToNormal(ushort major) { if (major < 6) { return (byte)major; } if (major >= 2017 && major <= 2266) { return (byte)(major - 2011); } throw new ArgumentOutOfRangeException("major"); } private static byte CastToFourBits(byte b) { if ((uint)b > 15u) { throw new ArgumentOutOfRangeException("b"); } return b; } private static UnityVersionType CastToFourBits(UnityVersionType type) { if (type > (UnityVersionType)15) { throw new ArgumentOutOfRangeException("type"); } return type; } public override string ToString() { return ((UnityVersion)this).ToString(); } public int CompareTo(object? obj) { if (!(obj is CompactUnityVersion32 other)) { return 1; } return CompareTo(other); } public int CompareTo(CompactUnityVersion32 other) { if (this > other) { return 1; } if (this < other) { return -1; } return 0; } public override bool Equals(object? obj) { if (obj is CompactUnityVersion32 compactUnityVersion) { return this == compactUnityVersion; } return false; } public bool Equals(CompactUnityVersion32 other) { return this == other; } public override int GetHashCode() { return m_data.GetHashCode(); } public static implicit operator UnityVersion(CompactUnityVersion32 version) { return new UnityVersion(version.Major, version.Minor, version.Build, version.Type, version.TypeNumber); } public static explicit operator CompactUnityVersion32(UnityVersion version) { return new CompactUnityVersion32(version.Major, (byte)version.Minor, (byte)version.Build, version.Type, version.TypeNumber); } public static bool operator ==(CompactUnityVersion32 left, CompactUnityVersion32 right) { return left.m_data == right.m_data; } public static bool operator !=(CompactUnityVersion32 left, CompactUnityVersion32 right) { return left.m_data != right.m_data; } public static bool operator >(CompactUnityVersion32 left, CompactUnityVersion32 right) { return left.m_data > right.m_data; } public static bool operator >=(CompactUnityVersion32 left, CompactUnityVersion32 right) { return left.m_data >= right.m_data; } public static bool operator <(CompactUnityVersion32 left, CompactUnityVersion32 right) { return left.m_data < right.m_data; } public static bool operator <=(CompactUnityVersion32 left, CompactUnityVersion32 right) { return left.m_data <= right.m_data; } } public readonly struct UnityVersion : IEquatable, IComparable, IComparable { private const ulong subMajorMask = 281474976710655uL; private const ulong subMinorMask = 4294967295uL; private const ulong subBuildMask = 65535uL; private const ulong subTypeMask = 255uL; private const int majorOffset = 48; private const int minorOffset = 32; private const int buildOffset = 16; private const int typeOffset = 8; private const ulong byteMask = 255uL; private const ulong ushortMask = 65535uL; private readonly ulong m_data; 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]+)\\.?([abfpx])([0-9]+)$", RegexOptions.Compiled); private static readonly Regex chinaRegex = new Regex("^([0-9]+)\\.([0-9]+)\\.([0-9]+)\\.?f1c([0-9]+)$", RegexOptions.Compiled); public ushort Major => (ushort)((m_data >> 48) & 0xFFFF); public ushort Minor => (ushort)((m_data >> 32) & 0xFFFF); public ushort Build => (ushort)((m_data >> 16) & 0xFFFF); public UnityVersionType Type => (UnityVersionType)((m_data >> 8) & 0xFF); public byte TypeNumber => (byte)(m_data & 0xFF); public static UnityVersion MinVersion { get; } = new UnityVersion(0uL); public static UnityVersion MaxVersion { get; } = new UnityVersion(ulong.MaxValue); public bool IsEqual(ushort major) { return this == From(major); } public bool IsEqual(ushort major, ushort minor) { return this == From(major, minor); } public bool IsEqual(ushort major, ushort minor, ushort build) { return this == From(major, minor, build); } public bool IsEqual(ushort major, ushort minor, ushort build, UnityVersionType type) { return this == From(major, minor, build, type); } public bool IsEqual(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) { return this == new UnityVersion(major, minor, build, type, typeNumber); } public bool IsEqual(string version) { return this == Parse(version); } public bool IsLess(ushort major) { return this < From(major); } public bool IsLess(ushort major, ushort minor) { return this < From(major, minor); } public bool IsLess(ushort major, ushort minor, ushort build) { return this < From(major, minor, build); } public bool IsLess(ushort major, ushort minor, ushort build, UnityVersionType type) { return this < From(major, minor, build, type); } public bool IsLess(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) { return this < new UnityVersion(major, minor, build, type, typeNumber); } public bool IsLess(string version) { return this < Parse(version); } public bool IsLessEqual(ushort major) { return this <= From(major); } public bool IsLessEqual(ushort major, ushort minor) { return this <= From(major, minor); } public bool IsLessEqual(ushort major, ushort minor, ushort build) { return this <= From(major, minor, build); } public bool IsLessEqual(ushort major, ushort minor, ushort build, UnityVersionType type) { return this <= From(major, minor, build, type); } public bool IsLessEqual(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) { return this <= new UnityVersion(major, minor, build, type, typeNumber); } public bool IsLessEqual(string version) { return this <= Parse(version); } public bool IsGreater(ushort major) { return this > From(major); } public bool IsGreater(ushort major, ushort minor) { return this > From(major, minor); } public bool IsGreater(ushort major, ushort minor, ushort build) { return this > From(major, minor, build); } public bool IsGreater(ushort major, ushort minor, ushort build, UnityVersionType type) { return this > From(major, minor, build, type); } public bool IsGreater(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) { return this > new UnityVersion(major, minor, build, type, typeNumber); } public bool IsGreater(string version) { return this > Parse(version); } public bool IsGreaterEqual(ushort major) { return this >= From(major); } public bool IsGreaterEqual(ushort major, ushort minor) { return this >= From(major, minor); } public bool IsGreaterEqual(ushort major, ushort minor, ushort build) { return this >= From(major, minor, build); } public bool IsGreaterEqual(ushort major, ushort minor, ushort build, UnityVersionType type) { return this >= From(major, minor, build, type); } public bool IsGreaterEqual(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) { return this >= new UnityVersion(major, minor, build, type, typeNumber); } public bool IsGreaterEqual(string version) { return this >= Parse(version); } private UnityVersion From(ushort major) { return new UnityVersion(((ulong)major << 48) | (0xFFFFFFFFFFFFuL & m_data)); } private UnityVersion From(ushort major, ushort minor) { return new UnityVersion(((ulong)major << 48) | ((ulong)minor << 32) | (0xFFFFFFFFu & m_data)); } private UnityVersion From(ushort major, ushort minor, ushort build) { return new UnityVersion(((ulong)major << 48) | ((ulong)minor << 32) | ((ulong)build << 16) | (0xFFFF & m_data)); } private UnityVersion From(ushort major, ushort minor, ushort build, UnityVersionType type) { return new UnityVersion(((ulong)major << 48) | ((ulong)minor << 32) | ((ulong)build << 16) | ((ulong)type << 8) | (0xFF & m_data)); } public UnityVersion(ushort major) { m_data = (ulong)major << 48; } public UnityVersion(ushort major, ushort minor) { m_data = ((ulong)major << 48) | ((ulong)minor << 32); } public UnityVersion(ushort major, ushort minor, ushort build) { m_data = ((ulong)major << 48) | ((ulong)minor << 32) | ((ulong)build << 16); } public UnityVersion(ushort major, ushort minor, ushort build, UnityVersionType type) { m_data = ((ulong)major << 48) | ((ulong)minor << 32) | ((ulong)build << 16) | ((ulong)type << 8); } public UnityVersion(ushort major, ushort minor, ushort build, UnityVersionType type, byte typeNumber) { m_data = ((ulong)major << 48) | ((ulong)minor << 32) | ((ulong)build << 16) | ((ulong)type << 8) | typeNumber; } private UnityVersion(ulong data) { m_data = data; } public ulong GetBits() { return m_data; } public static UnityVersion FromBits(ulong bits) { return new UnityVersion(bits); } public int CompareTo(object? obj) { if (!(obj is UnityVersion other)) { return 1; } return CompareTo(other); } public int CompareTo(UnityVersion other) { if (this > other) { return 1; } if (this < other) { return -1; } return 0; } public override bool Equals(object? obj) { if (obj is UnityVersion unityVersion) { return this == unityVersion; } return false; } public bool Equals(UnityVersion other) { return this == other; } public override int GetHashCode() { return 827 + 911 * m_data.GetHashCode(); } public static UnityVersion Max(UnityVersion left, UnityVersion right) { if (!(left > right)) { return right; } return left; } public static UnityVersion Min(UnityVersion left, UnityVersion right) { if (!(left < right)) { return right; } return left; } public static ulong Distance(UnityVersion left, UnityVersion right) { if (left.m_data >= right.m_data) { return left.m_data - right.m_data; } return right.m_data - left.m_data; } public UnityVersion GetClosestVersion(UnityVersion[] versions) { if (versions == null) { throw new ArgumentNullException("versions"); } if (versions.Length == 0) { throw new ArgumentException("Length cannot be zero", "versions"); } UnityVersion unityVersion = versions[0]; ulong num = Distance(this, unityVersion); for (int i = 1; i < versions.Length; i++) { ulong num2 = Distance(this, versions[i]); if (num2 < num) { num = num2; unityVersion = versions[i]; } } return unityVersion; } public UnityVersion ChangeMajor(ushort value) { return new UnityVersion(value, Minor, Build, Type, TypeNumber); } public UnityVersion ChangeMinor(ushort value) { return new UnityVersion(Major, value, Build, Type, TypeNumber); } public UnityVersion ChangeBuild(ushort value) { return new UnityVersion(Major, Minor, value, Type, TypeNumber); } public UnityVersion ChangeType(UnityVersionType value) { return new UnityVersion(Major, Minor, Build, value, TypeNumber); } public UnityVersion ChangeTypeNumber(byte value) { return new UnityVersion(Major, Minor, Build, Type, value); } public static bool operator ==(UnityVersion left, UnityVersion right) { return left.m_data == right.m_data; } public static bool operator !=(UnityVersion left, UnityVersion right) { return left.m_data != right.m_data; } public static bool operator >(UnityVersion left, UnityVersion right) { return left.m_data > right.m_data; } public static bool operator >=(UnityVersion left, UnityVersion right) { return left.m_data >= right.m_data; } public static bool operator <(UnityVersion left, UnityVersion right) { return left.m_data < right.m_data; } public static bool operator <=(UnityVersion left, UnityVersion right) { return left.m_data <= right.m_data; } public override string ToString() { return ToString(hasUnderscorePrefix: false, useUnderscoresAsSeparators: false, hasDllExtension: false, hasSeparatorAfterBuild: false); } public string ToString(bool hasUnderscorePrefix, bool useUnderscoresAsSeparators, bool hasDllExtension, bool hasSeparatorAfterBuild) { StringBuilder stringBuilder = new StringBuilder(); char value = (useUnderscoresAsSeparators ? '_' : '.'); if (hasUnderscorePrefix) { stringBuilder.Append('_'); } stringBuilder.Append(Major); stringBuilder.Append(value); stringBuilder.Append(Minor); stringBuilder.Append(value); stringBuilder.Append(Build); if (hasSeparatorAfterBuild) { stringBuilder.Append(value); } if (Type == UnityVersionType.China) { stringBuilder.Append("f1"); stringBuilder.Append('c'); stringBuilder.Append(TypeNumber); } else { stringBuilder.Append(Type.ToCharacter()); stringBuilder.Append(TypeNumber); } if (hasDllExtension) { stringBuilder.Append(".dll"); } return stringBuilder.ToString(); } public string ToStringWithoutType() { return $"{Major}.{Minor}.{Build}"; } public static UnityVersion ParseFromDllName(string dllName) { if (string.IsNullOrEmpty(dllName)) { throw new ArgumentNullException("dllName"); } if (dllName[0] == '_') { dllName = dllName.Substring(1); } return Parse(dllName.Replace('_', '.').Replace(".dll", "")); } public static UnityVersion Parse(string version) { if (string.IsNullOrEmpty(version)) { throw new ArgumentNullException("version"); } if (normalRegex.TryMatch(version, out Match match)) { int num = int.Parse(match.Groups[1].Value); int num2 = int.Parse(match.Groups[2].Value); int num3 = int.Parse(match.Groups[3].Value); char c = match.Groups[4].Value[0]; return new UnityVersion(typeNumber: (byte)int.Parse(match.Groups[5].Value), major: (ushort)num, minor: (ushort)num2, build: (ushort)num3, type: c.ToUnityVersionType()); } if (majorMinorBuildRegex.TryMatch(version, out match)) { int num4 = int.Parse(match.Groups[1].Value); int num5 = int.Parse(match.Groups[2].Value); int num6 = int.Parse(match.Groups[3].Value); return new UnityVersion((ushort)num4, (ushort)num5, (ushort)num6, UnityVersionType.Final, 1); } if (majorMinorRegex.TryMatch(version, out match)) { int num7 = int.Parse(match.Groups[1].Value); int num8 = int.Parse(match.Groups[2].Value); return new UnityVersion((ushort)num7, (ushort)num8, 0, UnityVersionType.Final, 1); } if (chinaRegex.TryMatch(version, out match)) { int num9 = int.Parse(match.Groups[1].Value); int num10 = int.Parse(match.Groups[2].Value); int num11 = int.Parse(match.Groups[3].Value); int num12 = int.Parse(match.Groups[4].Value); return new UnityVersion((ushort)num9, (ushort)num10, (ushort)num11, UnityVersionType.China, (byte)num12); } throw new ArgumentException("Invalid version format: " + version, "version"); } } public enum UnityVersionType : byte { Alpha = 0, Beta = 1, China = 2, Final = 3, Patch = 4, Experimental = 5, MinValue = 0, MaxValue = 5 } public static class UnityVersionTypeExtentions { public static char ToCharacter(this UnityVersionType type) { return type switch { UnityVersionType.Alpha => 'a', UnityVersionType.Beta => 'b', UnityVersionType.China => 'c', UnityVersionType.Final => 'f', UnityVersionType.Patch => 'p', UnityVersionType.Experimental => 'x', _ => 'u', }; } } } namespace AssetRipper.VersionUtilities.Extensions { public static class BinaryReaderExtensions { public static UnityVersion ReadUnityVersion(this BinaryReader reader) { return UnityVersion.FromBits(reader.ReadUInt64()); } public static CompactUnityVersion32 ReadCompactUnityVersion32(this BinaryReader reader) { return CompactUnityVersion32.FromBits(reader.ReadUInt32()); } public static CompactUnityVersion24 ReadCompactUnityVersion24(this BinaryReader reader) { byte majorMinorByte = reader.ReadByte(); ushort buildTypeShort = reader.ReadUInt16(); return CompactUnityVersion24.FromBits(majorMinorByte, buildTypeShort); } } public static class BinaryWriterExtensions { public static void Write(this BinaryWriter writer, UnityVersion version) { writer.Write(version.GetBits()); } public static void Write(this BinaryWriter writer, CompactUnityVersion32 version) { writer.Write(version.GetBits()); } public static void Write(this BinaryWriter writer, CompactUnityVersion24 version) { version.GetBits(out var majorMinorByte, out var buildTypeShort); writer.Write(majorMinorByte); writer.Write(buildTypeShort); } } public static class CharacterExtensions { public static UnityVersionType ToUnityVersionType(this char c) { return c switch { 'a' => UnityVersionType.Alpha, 'b' => UnityVersionType.Beta, 'c' => UnityVersionType.China, 'f' => UnityVersionType.Final, 'p' => UnityVersionType.Patch, 'x' => UnityVersionType.Experimental, _ => throw new ArgumentException($"There is no version type {c}", "c"), }; } } internal static class RegexExtensions { public static bool TryMatch(this Regex regex, string input, [NotNullWhen(true)] out Match? match) { match = regex.Match(input); if (match.Success) { return true; } match = null; return false; } } }