namespace AssetRipper.VersionUtilities; /// /// A compact value type for efficiently storing Unity versions inside 32 bits /// public partial struct CompactUnityVersion32 { private const int majorOffset = 24; private const int minorOffset = 20; private const int buildOffset = 12; private const int typeOffset = 8; private const uint byteMask = 0x00FFU; private const uint bitMask4 = 0x000FU; private readonly uint m_data; /// /// 2266 /// public const ushort MajorMaxValue = (ushort)(byte.MaxValue + 2011U); /// /// 8 bits /// private byte MajorRaw => unchecked((byte)((m_data >> majorOffset) & byteMask)); /// /// The first number in a Unity version string. 8 bits. /// Valid values inclusive: 0 - 5, 2017 - 2266 /// public ushort Major => ConvertMajorRawToNormal(MajorRaw); /// /// The second number in a Unity version string. 4 bits /// public byte Minor => unchecked((byte)((m_data >> minorOffset) & bitMask4)); /// /// The third number in a Unity version string. 8 bits /// public byte Build => unchecked((byte)((m_data >> buildOffset) & byteMask)); /// /// The letter in a Unity version string. 4 bits /// public UnityVersionType Type => (UnityVersionType)unchecked((byte)((m_data >> typeOffset) & bitMask4)); /// /// The last number in a Unity version string. 8 bits /// public byte TypeNumber => unchecked((byte)(m_data & byteMask)); /// /// The minimum value this type can have /// public static CompactUnityVersion32 MinVersion { get; } = new CompactUnityVersion32(0U); /// /// The maximum value this type can have /// public static CompactUnityVersion32 MaxVersion { get; } = new CompactUnityVersion32(uint.MaxValue); /// /// Construct a new Unity version /// public CompactUnityVersion32(ushort major) { m_data = (uint)ConvertMajorRawToNormal(major) << majorOffset; } /// /// Construct a new Unity version /// public CompactUnityVersion32(ushort major, byte minor) { m_data = ((uint)ConvertMajorRawToNormal(major) << majorOffset) | ((uint)CastToFourBits(minor) << minorOffset); } /// /// Construct a new Unity version /// public CompactUnityVersion32(ushort major, byte minor, byte build) { m_data = ((uint)ConvertMajorRawToNormal(major) << majorOffset) | ((uint)CastToFourBits(minor) << minorOffset) | ((uint)build << buildOffset); } /// /// Construct a new Unity version /// public CompactUnityVersion32(ushort major, byte minor, byte build, UnityVersionType type) { m_data = ((uint)ConvertMajorRawToNormal(major) << majorOffset) | ((uint)CastToFourBits(minor) << minorOffset) | ((uint)build << buildOffset) | ((uint)CastToFourBits(type) << typeOffset); } /// /// Construct a new Unity version /// public CompactUnityVersion32(ushort major, byte minor, byte build, UnityVersionType type, byte typeNumber) { m_data = ((uint)ConvertMajorRawToNormal(major) << majorOffset) | ((uint)CastToFourBits(minor) << minorOffset) | ((uint)build << buildOffset) | ((uint)CastToFourBits(type) << typeOffset) | typeNumber; } private CompactUnityVersion32(uint data) { m_data = data; } /// /// Converts this to its binary representation /// /// An unsigned integer having the same bits as this public uint GetBits() => m_data; /// /// Converts a binary representation into its respective version /// /// An unsigned integer having the relevant bits /// A new Unity version with the cooresponding bits public static CompactUnityVersion32 FromBits(uint bits) => new CompactUnityVersion32(bits); private static ushort ConvertMajorRawToNormal(byte raw) { return raw < 6 ? raw : unchecked((ushort)(raw + 2011U)); } private static byte ConvertMajorRawToNormal(ushort major) { if (major < 6) { return unchecked((byte)major); } else if (major >= 2017 && major <= MajorMaxValue) { return unchecked((byte)(major - 2011U)); } else { throw new ArgumentOutOfRangeException(nameof(major)); } } private static byte CastToFourBits(byte b) { return b <= bitMask4 ? b : throw new ArgumentOutOfRangeException(nameof(b)); } private static UnityVersionType CastToFourBits(UnityVersionType type) { return (byte)type <= bitMask4 ? type : throw new ArgumentOutOfRangeException(nameof(type)); } /// /// Serialize the version as a string /// /// A new string like 2019.4.3f1 public override string ToString() { return ((UnityVersion)this).ToString(); } }