Extract Unity version range management from UnityHeader to UnityVersionRange
This commit is contained in:
@@ -20,34 +20,18 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
public double MetadataVersion { get; }
|
public double MetadataVersion { get; }
|
||||||
|
|
||||||
// Minimum and maximum Unity version numbers corresponding to this header. Both endpoints are inclusive
|
// Minimum and maximum Unity version numbers corresponding to this header. Both endpoints are inclusive
|
||||||
public UnityVersion MinVersion { get; }
|
public UnityVersionRange Version { get; }
|
||||||
public UnityVersion MaxVersion { get; }
|
|
||||||
|
|
||||||
// Filename for the embedded .h resource file containing the header
|
// Filename for the embedded .h resource file containing the header
|
||||||
public string HeaderFilename { get; }
|
public string HeaderFilename { get; }
|
||||||
|
|
||||||
private UnityHeader(string headerFilename) {
|
private UnityHeader(string headerFilename) {
|
||||||
HeaderFilename = headerFilename;
|
HeaderFilename = headerFilename;
|
||||||
var bits = headerFilename.Replace(".h", "").Split("-");
|
Version = UnityVersionRange.FromFilename(HeaderFilename);
|
||||||
MetadataVersion = double.Parse(bits[0], NumberFormatInfo.InvariantInfo);
|
MetadataVersion = double.Parse(headerFilename.Split("-")[0], NumberFormatInfo.InvariantInfo);
|
||||||
MinVersion = new UnityVersion(bits[1]);
|
|
||||||
if (bits.Length == 2)
|
|
||||||
MaxVersion = MinVersion;
|
|
||||||
else if (bits[2] != "")
|
|
||||||
MaxVersion = new UnityVersion(bits[2]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() => Version.ToString();
|
||||||
var res = $"{MinVersion}";
|
|
||||||
if (MaxVersion == null)
|
|
||||||
res += "+";
|
|
||||||
else if (MaxVersion != MinVersion)
|
|
||||||
res += $" - {MaxVersion}";
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if this header supports the given version of Unity
|
|
||||||
public bool Contains(UnityVersion version) => version.CompareTo(MinVersion) >= 0 && (MaxVersion == null || version.CompareTo(MaxVersion) <= 0);
|
|
||||||
|
|
||||||
// Return the contents of this header file as a string
|
// Return the contents of this header file as a string
|
||||||
public string GetHeaderText() {
|
public string GetHeaderText() {
|
||||||
@@ -62,7 +46,7 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all header files embedded into this build of Il2Cpp
|
// List all header files embedded into this build of Il2CppInspector
|
||||||
public static IEnumerable<UnityHeader> GetAllHeaders() {
|
public static IEnumerable<UnityHeader> GetAllHeaders() {
|
||||||
string prefix = typeof(UnityHeader).Namespace + ".";
|
string prefix = typeof(UnityHeader).Namespace + ".";
|
||||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||||
@@ -71,26 +55,58 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
.Select(s => new UnityHeader(s.Substring(prefix.Length)));
|
.Select(s => new UnityHeader(s.Substring(prefix.Length)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List all API header files and versions embedded into this build of Il2CppInspector
|
||||||
|
public static IEnumerable<(string resourceName, UnityVersion minVersion, UnityVersion maxVersion)> GetAPIList() {
|
||||||
|
string prefix = "Il2CppInspector.Cpp.Il2CppAPIHeaders.";
|
||||||
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||||
|
var versions = new List<(string resourceName, UnityVersion minVersion, UnityVersion maxVersion)>();
|
||||||
|
|
||||||
|
foreach (var headerFilename in assembly.GetManifestResourceNames().Where(s => s.StartsWith(prefix) && s.EndsWith(".h"))) {
|
||||||
|
var bits = headerFilename.Substring(prefix.Length).Replace(".h", "").Split("-");
|
||||||
|
var min = new UnityVersion(bits[0]);
|
||||||
|
UnityVersion max = min;
|
||||||
|
if (bits.Length == 2 && bits[1] != "")
|
||||||
|
max = new UnityVersion(bits[1]);
|
||||||
|
versions.Add((headerFilename, min, max));
|
||||||
|
}
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the header file which supports the given version of Unity
|
// Get the header file which supports the given version of Unity
|
||||||
public static UnityHeader GetHeaderForVersion(string version) => GetHeaderForVersion(new UnityVersion(version));
|
public static UnityHeader GetHeaderForVersion(string version) => GetHeaderForVersion(new UnityVersion(version));
|
||||||
public static UnityHeader GetHeaderForVersion(UnityVersion version) => GetAllHeaders().Where(v => v.Contains(version)).First();
|
public static UnityHeader GetHeaderForVersion(UnityVersion version) => GetAllHeaders().First(h => h.Version.Contains(version));
|
||||||
|
|
||||||
|
public static string GetAPIResourceNameForVersion(UnityVersion version) =>
|
||||||
|
GetAPIList().First(v => version.CompareTo(v.minVersion) >= 0 && (v.maxVersion == null || version.CompareTo(v.maxVersion) <= 0)).resourceName;
|
||||||
|
|
||||||
|
public static string GetAPITextForVersion(UnityVersion version) {
|
||||||
|
var apiResource = GetAPIResourceNameForVersion(version);
|
||||||
|
Assembly assembly = Assembly.GetCallingAssembly();
|
||||||
|
using Stream stream = assembly.GetManifestResourceStream(apiResource);
|
||||||
|
if (stream == null) {
|
||||||
|
throw new FileNotFoundException(apiResource);
|
||||||
|
}
|
||||||
|
using StreamReader reader = new StreamReader(stream);
|
||||||
|
string result = reader.ReadToEnd();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Guess which header file(s) correspond to the given metadata+binary.
|
// Guess which header file(s) correspond to the given metadata+binary.
|
||||||
// Note that this may match multiple headers due to structural changes between versions
|
// Note that this may match multiple headers due to structural changes between versions
|
||||||
// that are not reflected in the metadata version.
|
// that are not reflected in the metadata version.
|
||||||
public static List<UnityHeader> GuessHeadersForModel(Reflection.TypeModel model) {
|
public static List<UnityHeader> GuessHeadersForModel(Reflection.TypeModel model) {
|
||||||
List<UnityHeader> result = new List<UnityHeader>();
|
List<UnityHeader> result = new List<UnityHeader>();
|
||||||
foreach (var v in GetAllHeaders()) {
|
foreach (var h in GetAllHeaders()) {
|
||||||
if (v.MetadataVersion != model.Package.BinaryImage.Version)
|
if (h.MetadataVersion != model.Package.BinaryImage.Version)
|
||||||
continue;
|
continue;
|
||||||
if (v.MetadataVersion == 21) {
|
if (h.MetadataVersion == 21) {
|
||||||
/* Special version logic for metadata version 21 based on the Il2CppMetadataRegistration.fieldOffsets field */
|
/* Special version logic for metadata version 21 based on the Il2CppMetadataRegistration.fieldOffsets field */
|
||||||
var headerFieldOffsetsArePointers = v.MinVersion.CompareTo("5.3.7") >= 0 && v.MinVersion.CompareTo("5.4.0") != 0;
|
var headerFieldOffsetsArePointers = h.Version.Min.CompareTo("5.3.7") >= 0 && h.Version.Min.CompareTo("5.4.0") != 0;
|
||||||
var binaryFieldOffsetsArePointers = model.Package.Binary.FieldOffsets == null;
|
var binaryFieldOffsetsArePointers = model.Package.Binary.FieldOffsets == null;
|
||||||
if (headerFieldOffsetsArePointers != binaryFieldOffsetsArePointers)
|
if (headerFieldOffsetsArePointers != binaryFieldOffsetsArePointers)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
result.Add(v);
|
result.Add(h);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace Il2CppInspector.Cpp.UnityHeaders
|
namespace Il2CppInspector.Cpp.UnityHeaders
|
||||||
@@ -110,4 +112,58 @@ namespace Il2CppInspector.Cpp.UnityHeaders
|
|||||||
return HashCode.Combine(Major, Minor, Update, BuildType, BuildNumber);
|
return HashCode.Combine(Major, Minor, Update, BuildType, BuildNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A range of Unity versions
|
||||||
|
public class UnityVersionRange
|
||||||
|
{
|
||||||
|
// Minimum and maximum Unity version numbers for this range. Both endpoints are inclusive
|
||||||
|
public UnityVersion Min { get; }
|
||||||
|
public UnityVersion Max { get; }
|
||||||
|
|
||||||
|
// Determine if this range contains the specified version
|
||||||
|
public bool Contains(UnityVersion version) => version.CompareTo(Min) >= 0 && (Max == null || version.CompareTo(Max) <= 0);
|
||||||
|
|
||||||
|
public UnityVersionRange(UnityVersion min, UnityVersion max) {
|
||||||
|
Min = min;
|
||||||
|
Max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a version range from a string, in the format "[Il2CppInspector.Cpp.<namespace-leaf>.][metadataVersion-]<min>-[max].h"
|
||||||
|
public static UnityVersionRange FromFilename(string headerFilename) {
|
||||||
|
var baseNamespace = "Il2CppInspector.Cpp.";
|
||||||
|
headerFilename = headerFilename.Replace(".h", "");
|
||||||
|
|
||||||
|
if (headerFilename.StartsWith(baseNamespace)) {
|
||||||
|
headerFilename = headerFilename.Substring(baseNamespace.Length);
|
||||||
|
headerFilename = headerFilename.Substring(headerFilename.IndexOf(".") + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var bits = headerFilename.Split("-");
|
||||||
|
|
||||||
|
// Metadata version supplied
|
||||||
|
// Note: This relies on the metadata version being either 2 or 4 characters,
|
||||||
|
// and that the smallest Unity version must be 5 characters or more
|
||||||
|
if (headerFilename[2] == '-' || headerFilename[4] == '-')
|
||||||
|
bits = bits.Skip(1).ToArray();
|
||||||
|
|
||||||
|
var Min = new UnityVersion(bits[0]);
|
||||||
|
UnityVersion Max = null;
|
||||||
|
|
||||||
|
if (bits.Length == 1)
|
||||||
|
Max = Min;
|
||||||
|
if (bits.Length == 2 && bits[1] != "")
|
||||||
|
Max = new UnityVersion(bits[1]);
|
||||||
|
|
||||||
|
return new UnityVersionRange(Min, Max);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
var res = $"{Min}";
|
||||||
|
if (Max == null)
|
||||||
|
res += "+";
|
||||||
|
else if (Max != Min)
|
||||||
|
res += $" - {Max}";
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ namespace Il2CppInspector.Model
|
|||||||
|
|
||||||
// Determine Unity version and get headers
|
// Determine Unity version and get headers
|
||||||
UnityHeader = unityVersion != null ? UnityHeader.GetHeaderForVersion(unityVersion) : UnityHeader.GuessHeadersForModel(ILModel)[0];
|
UnityHeader = unityVersion != null ? UnityHeader.GetHeaderForVersion(unityVersion) : UnityHeader.GuessHeadersForModel(ILModel)[0];
|
||||||
UnityVersion = unityVersion ?? UnityHeader.MinVersion;
|
UnityVersion = unityVersion ?? UnityHeader.Version.Min;
|
||||||
|
|
||||||
// Check for matching metadata and binary versions
|
// Check for matching metadata and binary versions
|
||||||
if (UnityHeader.MetadataVersion != ILModel.Package.BinaryImage.Version) {
|
if (UnityHeader.MetadataVersion != ILModel.Package.BinaryImage.Version) {
|
||||||
|
|||||||
@@ -406,7 +406,7 @@ namespace Il2CppInspectorGUI
|
|||||||
var outFile = scriptSaveFileDialog.FileName;
|
var outFile = scriptSaveFileDialog.FileName;
|
||||||
|
|
||||||
areaBusyIndicator.Visibility = Visibility.Visible;
|
areaBusyIndicator.Visibility = Visibility.Visible;
|
||||||
var selectedVersion = ((UnityHeader)cboUnityVersion.SelectedItem)?.MinVersion;
|
var selectedVersion = ((UnityHeader) cboUnityVersion.SelectedItem)?.Version.Min;
|
||||||
await Task.Run(() => {
|
await Task.Run(() => {
|
||||||
OnStatusUpdate(this, "Building C++ application model");
|
OnStatusUpdate(this, "Building C++ application model");
|
||||||
model.Build(selectedVersion, CppCompilerType.GCC);
|
model.Build(selectedVersion, CppCompilerType.GCC);
|
||||||
@@ -430,7 +430,7 @@ namespace Il2CppInspectorGUI
|
|||||||
var cppOutPath = cppSaveFolderDialog.SelectedPath;
|
var cppOutPath = cppSaveFolderDialog.SelectedPath;
|
||||||
|
|
||||||
areaBusyIndicator.Visibility = Visibility.Visible;
|
areaBusyIndicator.Visibility = Visibility.Visible;
|
||||||
var selectedCppUnityVersion = ((UnityHeader)cboCppUnityVersion.SelectedItem)?.MinVersion;
|
var selectedCppUnityVersion = ((UnityHeader) cboCppUnityVersion.SelectedItem)?.Version.Min;
|
||||||
var cppCompiler = (CppCompilerType) Enum.Parse(typeof(CppCompilerType), cboCppCompiler.SelectionBoxItem.ToString());
|
var cppCompiler = (CppCompilerType) Enum.Parse(typeof(CppCompilerType), cboCppCompiler.SelectionBoxItem.ToString());
|
||||||
await Task.Run(() => {
|
await Task.Run(() => {
|
||||||
OnStatusUpdate(this, "Building C++ application model");
|
OnStatusUpdate(this, "Building C++ application model");
|
||||||
|
|||||||
Reference in New Issue
Block a user