From 841e76d2d7fedffd89ce11fcb1d924a3eaeac4ca Mon Sep 17 00:00:00 2001 From: iAmAsval Date: Mon, 4 Jan 2021 14:12:08 +0100 Subject: [PATCH] implemented usmap --- FModel.sln | 8 +- FModel/FModel.csproj | 1 + FModel/Globals.cs | 5 +- FModel/Grabber/Mappings/MappingsData.cs | 50 +++++++++++ FModel/Grabber/Mappings/MappingsGrabber.cs | 45 ++++++++++ FModel/MainWindow.xaml.cs | 51 ++--------- .../PakReader/IO/FIoDirectoryIndexHandle.cs | 6 +- FModel/PakReader/IO/FIterator.cs | 3 +- FModel/PakReader/IO/FUnversionedProperty.cs | 29 +++++++ FModel/PakReader/IO/PropertyInfo.cs | 34 -------- FModel/PakReader/Parsers/Class/UCurveTable.cs | 12 +-- FModel/PakReader/Parsers/Class/UDataTable.cs | 23 +++-- FModel/PakReader/Parsers/Class/UObject.cs | 86 ++++++++----------- FModel/PakReader/Parsers/Class/USoundWave.cs | 5 +- FModel/PakReader/Parsers/Class/UTexture2D.cs | 4 +- FModel/PakReader/Parsers/IoPackageReader.cs | 78 ++++++++++------- FModel/PakReader/Parsers/Objects/FName.cs | 8 ++ .../PakReader/Parsers/Objects/FPropertyTag.cs | 27 ++++-- .../Parsers/Objects/UScriptStruct.cs | 7 +- .../Parsers/PropertyTagData/EnumProperty.cs | 21 ++--- .../Parsers/PropertyTagData/MapProperty.cs | 1 - .../PropertyTagData/SoftObjectProperty.cs | 2 +- FModel/Utils/Endpoints.cs | 21 ++--- 23 files changed, 298 insertions(+), 229 deletions(-) create mode 100644 FModel/Grabber/Mappings/MappingsData.cs create mode 100644 FModel/Grabber/Mappings/MappingsGrabber.cs create mode 100644 FModel/PakReader/IO/FUnversionedProperty.cs delete mode 100644 FModel/PakReader/IO/PropertyInfo.cs diff --git a/FModel.sln b/FModel.sln index 6aaf2847..2a36b4f9 100644 --- a/FModel.sln +++ b/FModel.sln @@ -1,18 +1,22 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 -VisualStudioVersion = 16.0.29806.167 +VisualStudioVersion = 16.0.30804.86 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FModel", "FModel\FModel.csproj", "{A42F8737-D056-4FA5-BEB5-AA96E1639F8A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Debug|Any CPU.ActiveCfg = Debug|x64 {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Debug|x64.ActiveCfg = Debug|x64 {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Debug|x64.Build.0 = Debug|x64 + {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Release|Any CPU.ActiveCfg = Release|x64 {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Release|x64.ActiveCfg = Release|x64 {A42F8737-D056-4FA5-BEB5-AA96E1639F8A}.Release|x64.Build.0 = Release|x64 EndGlobalSection @@ -20,6 +24,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {FE6EA91D-BBB8-4FBC-875C-25AD92EDB519} + SolutionGuid = {688BAB53-42F7-45F2-AFDF-79A07771213F} EndGlobalSection EndGlobal diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index 59ff7c7f..a07f45f0 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -131,6 +131,7 @@ + diff --git a/FModel/Globals.cs b/FModel/Globals.cs index 6cc6cf5e..bae21c68 100644 --- a/FModel/Globals.cs +++ b/FModel/Globals.cs @@ -8,6 +8,7 @@ using FModel.Properties; using ToastNotifications; using ToastNotifications.Lifetime; using ToastNotifications.Position; +using UsmapNET.Classes; namespace FModel { @@ -19,9 +20,9 @@ namespace FModel /// public static readonly Dictionary CachedPakFiles = new Dictionary(); public static readonly Dictionary CachedIoStores = new Dictionary(); + public static readonly Dictionary CachedSchemas = new Dictionary(); + public static Usmap Usmap = null; public static FIoGlobalData GlobalData = null; - public static Dictionary> TypeMappings; - public static Dictionary> EnumMappings; public static readonly Notifier gNotifier = new Notifier(cfg => { cfg.LifetimeSupervisor = new TimeAndCountBasedLifetimeSupervisor(TimeSpan.FromSeconds(7), MaximumNotificationCount.FromCount(15)); diff --git a/FModel/Grabber/Mappings/MappingsData.cs b/FModel/Grabber/Mappings/MappingsData.cs new file mode 100644 index 00000000..d301fbd9 --- /dev/null +++ b/FModel/Grabber/Mappings/MappingsData.cs @@ -0,0 +1,50 @@ +using FModel.Logger; +using FModel.Utils; +using FModel.Windows.CustomNotifier; +using Newtonsoft.Json; +using System.Net.NetworkInformation; +using System.Threading.Tasks; + +namespace FModel.Grabber.Mappings +{ + static class MappingsData + { + public static async Task GetData() + { + if (NetworkInterface.GetIsNetworkAvailable()) + { + Mapping[] data = await Endpoints.GetJsonEndpoint(Endpoints.BENBOT_MAPPINGS, string.Empty).ConfigureAwait(false); + return data; + } + else + { + Globals.gNotifier.ShowCustomMessage("Mappings", Properties.Resources.NoInternet, "/FModel;component/Resources/wifi-strength-off.ico"); + DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Mappings]", "No internet"); + return null; + } + } + } + + public class Mapping + { + [JsonProperty("url")] + public string Url { get; set; } + [JsonProperty("fileName")] + public string FileName { get; set; } + [JsonProperty("hash")] + public string Hash { get; set; } + [JsonProperty("length")] + public string Length { get; set; } + [JsonProperty("uploaded")] + public string Uploaded { get; set; } + [JsonProperty("meta")] + public Metadata Meta { get; set; } + } + public class Metadata + { + [JsonProperty("version")] + public string Version { get; set; } + [JsonProperty("compressionMethod")] + public string CompressionMethod { get; set; } + } +} diff --git a/FModel/Grabber/Mappings/MappingsGrabber.cs b/FModel/Grabber/Mappings/MappingsGrabber.cs new file mode 100644 index 00000000..103f3540 --- /dev/null +++ b/FModel/Grabber/Mappings/MappingsGrabber.cs @@ -0,0 +1,45 @@ +using FModel.Utils; +using System; +using System.IO; +using System.Threading.Tasks; +using UsmapNET.Classes; + +namespace FModel.Grabber.Mappings +{ + static class MappingsGrabber + { + public static async Task Load(bool forceReload = false) + { + if (Globals.Game.ActualGame == EGame.Fortnite) + { + Mapping[] benMappings = await MappingsData.GetData().ConfigureAwait(false); + if (benMappings != null) + { + foreach (Mapping mapping in benMappings) + { + if (mapping.Meta.CompressionMethod == "Brotli") + { + DirectoryInfo chunksDir = Directory.CreateDirectory(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks")); + string mappingPath = Path.Combine(chunksDir.FullName, mapping.FileName); + + byte[] mappingsData; + if (!forceReload && File.Exists(mappingPath)) + { + mappingsData = await File.ReadAllBytesAsync(mappingPath); + } + else + { + mappingsData = await Endpoints.GetRawDataAsync(new Uri(mapping.Url)).ConfigureAwait(false); + await File.WriteAllBytesAsync(mappingPath, mappingsData).ConfigureAwait(false); + } + + Globals.Usmap = new Usmap(mappingsData); + return true; + } + } + } + } + return false; + } + } +} diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs index d6247863..9023dc46 100644 --- a/FModel/MainWindow.xaml.cs +++ b/FModel/MainWindow.xaml.cs @@ -23,19 +23,15 @@ using FModel.Windows.Search; using FModel.Windows.Settings; using FModel.Windows.SoundPlayer; using System; -using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; -using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using System.Net.NetworkInformation; +using FModel.Grabber.Mappings; namespace FModel { @@ -83,7 +79,6 @@ namespace FModel Keys.NoKeyGoodBye(); MenuItems.FeedCustomGoTos(); AeConfiguration(); - LoadMappings(); if (t.Exception != null) Tasks.TaskCompleted(t.Exception); else StatusBarVm.statusBarViewModel.Set($"{Properties.Resources.Hello} {Environment.UserName}!", Properties.Resources.State); @@ -98,54 +93,22 @@ namespace FModel { await PaksGrabber.PopulateMenu().ConfigureAwait(false); await AesGrabber.Load(Properties.Settings.Default.ReloadAesKeys).ConfigureAwait(false); + await MappingsGrabber.Load().ConfigureAwait(false); await CdnDataGrabber.DoCDNStuff().ConfigureAwait(false); await Folders.DownloadAndExtractVgm().ConfigureAwait(false); if (Properties.Settings.Default.UseDiscordRpc) DiscordIntegration.StartClient(); } - private async void LoadMappings() + public async void ReloadMappings(object sender, RoutedEventArgs e) { - string rawMappings = "{}"; - string rawEnumMappings = "{}"; - -#if DEBUG - if (File.Exists("TypeMappings.json")) + if (await MappingsGrabber.Load(true).ConfigureAwait(false)) { - rawMappings = await File.ReadAllTextAsync("TypeMappings.json"); + Globals.gNotifier.ShowCustomMessage("Mappings", "Reloaded successfully"); } - else if (NetworkInterface.GetIsNetworkAvailable()) + else { - rawMappings = await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_TYPE_MAPPINGS); + Globals.gNotifier.ShowCustomMessage("Mappings", "Fail to reload"); } - - if (File.Exists("EnumMappings.json")) - { - rawEnumMappings = await File.ReadAllTextAsync("EnumMappings.json"); - } - else if (NetworkInterface.GetIsNetworkAvailable()) - { - rawEnumMappings = await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_ENUM_MAPPINGS); - } -#else - rawMappings = await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_TYPE_MAPPINGS); - rawEnumMappings = await Endpoints.GetStringEndpoint(Endpoints.FORTNITE_ENUM_MAPPINGS); -#endif - - var serializerSettings = new JsonSerializerSettings - { - ContractResolver = new DefaultContractResolver - { - NamingStrategy = new CamelCaseNamingStrategy(false, false) - } - }; - Globals.TypeMappings = JsonConvert.DeserializeObject>>(rawMappings, serializerSettings); - Globals.EnumMappings = JsonConvert.DeserializeObject>>(rawEnumMappings, serializerSettings); - } - - public void ReloadMappings(object sender, RoutedEventArgs e) - { - LoadMappings(); - Globals.gNotifier.ShowCustomMessage("Mappings", "Reloaded successfully"); } private void AeConfiguration() diff --git a/FModel/PakReader/IO/FIoDirectoryIndexHandle.cs b/FModel/PakReader/IO/FIoDirectoryIndexHandle.cs index 1708b24f..6e4a7cad 100644 --- a/FModel/PakReader/IO/FIoDirectoryIndexHandle.cs +++ b/FModel/PakReader/IO/FIoDirectoryIndexHandle.cs @@ -27,7 +27,11 @@ namespace FModel.PakReader.IO public static bool operator ==(FIoDirectoryIndexHandle a, FIoDirectoryIndexHandle b) => a._handle == b._handle; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(FIoDirectoryIndexHandle a, FIoDirectoryIndexHandle b) => a._handle != b._handle; - + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(FIoDirectoryIndexHandle b) => _handle == b._handle; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object obj) => obj is FIoDirectoryIndexHandle handle && Equals(handle); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static FIoDirectoryIndexHandle FromIndex(uint index) => new FIoDirectoryIndexHandle(index); } diff --git a/FModel/PakReader/IO/FIterator.cs b/FModel/PakReader/IO/FIterator.cs index eb9bf0cb..632eac7f 100644 --- a/FModel/PakReader/IO/FIterator.cs +++ b/FModel/PakReader/IO/FIterator.cs @@ -17,8 +17,7 @@ namespace FModel.PakReader.IO { _zeroMask = header.ZeroMask; _fragmentIt = header.Fragments.GetEnumerator(); - if (header.HasValues) - Skip(); + Skip(); } public bool MoveNext() diff --git a/FModel/PakReader/IO/FUnversionedProperty.cs b/FModel/PakReader/IO/FUnversionedProperty.cs new file mode 100644 index 00000000..3fa5cb31 --- /dev/null +++ b/FModel/PakReader/IO/FUnversionedProperty.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using UsmapNET.Classes; + +namespace FModel.PakReader.IO +{ + public class FUnversionedType + { + public string Name { get; } + public Dictionary Properties { get; set; } + + public FUnversionedType(string name) + { + Name = name; + Properties = new Dictionary(); + } + } + + public class FUnversionedProperty + { + public string Name { get; set; } + public UsmapPropertyData Data { get; set; } + + public FUnversionedProperty(UsmapProperty prop) + { + Name = prop.Name; + Data = prop.Data; + } + } +} diff --git a/FModel/PakReader/IO/PropertyInfo.cs b/FModel/PakReader/IO/PropertyInfo.cs deleted file mode 100644 index 416093b0..00000000 --- a/FModel/PakReader/IO/PropertyInfo.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Newtonsoft.Json; - -namespace FModel.PakReader.IO -{ - public class PropertyInfo - { - public string Name; - public string Type; - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string StructType; - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public bool? Bool; - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string EnumName; - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string EnumType; - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string InnerType; - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string ValueType; - - public PropertyInfo(string name, string type, string structType = null, bool? b = null, string enumName = null, string enumType = null, string innerType = null, string valueType = null) - { - Name = name; - Type = type; - StructType = structType; - Bool = b; - EnumName = enumName; - EnumType = enumType; - InnerType = innerType; - ValueType = valueType; - } - } -} \ No newline at end of file diff --git a/FModel/PakReader/Parsers/Class/UCurveTable.cs b/FModel/PakReader/Parsers/Class/UCurveTable.cs index 0674effb..335177d2 100644 --- a/FModel/PakReader/Parsers/Class/UCurveTable.cs +++ b/FModel/PakReader/Parsers/Class/UCurveTable.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; -using FModel.PakReader.IO; using FModel.PakReader.Parsers.Objects; namespace FModel.PakReader.Parsers.Class @@ -34,17 +33,18 @@ namespace FModel.PakReader.Parsers.Class } } - internal UCurveTable(IoPackageReader reader) + internal UCurveTable(IoPackageReader reader, string _) { reader.ReadUInt16(); // don't ask me reader.ReadUInt32(); // what this is int NumRows = reader.ReadInt32(); CurveTableMode = (ECurveTableMode)reader.ReadByte(); - Dictionary properties = CurveTableMode switch + + string export = CurveTableMode switch { - ECurveTableMode.RichCurves => Globals.TypeMappings["RichCurve"], - ECurveTableMode.SimpleCurves => Globals.TypeMappings["SimpleCurve"], + ECurveTableMode.RichCurves => "RichCurve", + ECurveTableMode.SimpleCurves => "SimpleCurve", _ => throw new FileLoadException($"This table has an unknown mode ({CurveTableMode})") }; @@ -59,7 +59,7 @@ namespace FModel.PakReader.Parsers.Class RowName = $"{baseName}_NK{num++:00}"; } - RowMap[RowName] = new UObject(reader, properties, true); + RowMap[RowName] = new UObject(reader, export, true); } } diff --git a/FModel/PakReader/Parsers/Class/UDataTable.cs b/FModel/PakReader/Parsers/Class/UDataTable.cs index 83f6abef..3aa9c3a7 100644 --- a/FModel/PakReader/Parsers/Class/UDataTable.cs +++ b/FModel/PakReader/Parsers/Class/UDataTable.cs @@ -1,8 +1,8 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Runtime.CompilerServices; - using FModel.PakReader.IO; using FModel.PakReader.Parsers.PropertyTagData; using FModel.Utils; @@ -34,24 +34,21 @@ namespace FModel.PakReader.Parsers.Class } } - internal UDataTable(IoPackageReader reader, IReadOnlyDictionary properties, string type) + internal UDataTable(IoPackageReader reader, string type) { - var baseObj = new UObject(reader, properties, type: type); - + var baseObj = new UObject(reader, type); if (!baseObj.TryGetValue("RowStruct", out var rowStructProp) || !(rowStructProp is ObjectProperty rowStruct) || !rowStruct.Value.IsImport) { return; } var rowStructimportIndex = rowStruct.Value.AsImport; - if (rowStructimportIndex >= reader.ImportMap.Length) { return; } var rowStructimport = reader.ImportMap[rowStructimportIndex]; - if (rowStructimport.Type != EType.ScriptImport || !Globals.GlobalData.ScriptObjectByGlobalId.TryGetValue(rowStructimport, out var rowStrucDesc) || rowStrucDesc.Name.IsNone) @@ -59,11 +56,13 @@ namespace FModel.PakReader.Parsers.Class return; } - if (!Globals.TypeMappings.TryGetValue(rowStrucDesc.Name.String, out var rowProperties)) - { - FConsole.AppendText($"{reader.Summary.Name.String} can't be parsed yet (RowType: {rowStrucDesc.Name.String})", FColors.Red, true); - return; - } + // this slows down icon generation + //bool hasStruct = Globals.Usmap.Schemas.Any(x => x.Name == rowStrucDesc.Name.String); + //if (!hasStruct) + //{ + // FConsole.AppendText($"{reader.Summary.Name.String} can't be parsed yet (RowType: {rowStrucDesc.Name.String})", FColors.Red, true); + // return; + //} var NumRows = reader.ReadInt32(); RowMap = new Dictionary(); @@ -79,7 +78,7 @@ namespace FModel.PakReader.Parsers.Class RowName = $"{baseName}_NK{num++:00}"; } - RowMap[RowName] = new UObject(reader, rowProperties, true, rowStrucDesc.Name.String); + RowMap[RowName] = new UObject(reader, rowStrucDesc.Name.String, true); } } diff --git a/FModel/PakReader/Parsers/Class/UObject.cs b/FModel/PakReader/Parsers/Class/UObject.cs index 77d13691..a83efe79 100644 --- a/FModel/PakReader/Parsers/Class/UObject.cs +++ b/FModel/PakReader/Parsers/Class/UObject.cs @@ -12,63 +12,51 @@ namespace FModel.PakReader.Parsers.Class { private readonly Dictionary Dict; - public UObject(IoPackageReader reader, IReadOnlyDictionary properties, bool structFallback = false, string type = null) + public UObject(IoPackageReader reader, string type, bool structFallback = false) { Dict = new Dictionary(); var header = new FUnversionedHeader(reader); - - if (!header.HasValues) + if (header.HasValues) { - if (!structFallback && reader.ReadInt32() != 0 /* && reader.Position + 16 <= maxSize*/) - reader.Position += FGuid.SIZE; - - return; - } - - using var it = new FIterator(header); - + FUnversionedType unversionedType = reader.GetOrCreateSchema(type); + using var it = new FIterator(header); + if (header.HasNonZeroValues) + { + var num = 1; + do + { + var (val, isNonZero) = it.Current; + if (unversionedType.Properties.TryGetValue(val, out var props)) + { + var propertyTag = new FPropertyTag(props); + if (isNonZero) + { + var key = Dict.ContainsKey(props.Name) ? $"{props.Name}_NK{num++:00}" : props.Name; + var obj = BaseProperty.ReadAsObject(reader, propertyTag, propertyTag.Type, ReadType.NORMAL); + Dict[key] = obj; + } + else + { + var key = Dict.ContainsKey(props.Name) ? $"{props.Name}_NK{num++:00}" : props.Name; + var obj = BaseProperty.ReadAsZeroObject(reader, propertyTag, propertyTag.Type); + Dict[key] = obj; + } + } + else Dict[val.ToString()] = null; + } while (it.MoveNext()); + } + else + { #if DEBUG - - var headerWritten = false; - - do - { - if (properties.ContainsKey(it.Current.Val)) - continue; - - if (!headerWritten) - { - headerWritten = true; FConsole.AppendText(string.Concat("\n", type ?? "Unknown", ": ", reader.Summary.Name.String), "#CA6C6C", true); - } - - FConsole.AppendText($"Val: {it.Current.Val} (IsNonZero: {it.Current.IsNonZero})", FColors.Yellow, true); - } - while (it.MoveNext()); - it.Reset(); + do + { + FConsole.AppendText($"Val: {it.Current.Val} (IsNonZero: {it.Current.IsNonZero})", FColors.Yellow, true); + } + while (it.MoveNext()); #endif - - var num = 1; - do - { - var (val, isNonZero) = it.Current; - if (properties.TryGetValue(val, out var propertyInfo)) - { - if (isNonZero) - { - var key = Dict.ContainsKey(propertyInfo.Name) ? $"{propertyInfo.Name}_NK{num++:00}" : propertyInfo.Name; - var obj = BaseProperty.ReadAsObject(reader, new FPropertyTag(propertyInfo), new FName(propertyInfo.Type), ReadType.NORMAL); - Dict[key] = obj; - } - else - { - var obj = BaseProperty.ReadAsZeroObject(reader, new FPropertyTag(propertyInfo), new FName(propertyInfo.Type)); - var key = Dict.ContainsKey(propertyInfo.Name) ? $"{propertyInfo.Name}_NK{num++:00}" : propertyInfo.Name; - Dict[key] = obj; - } } - else Dict[val.ToString()] = null; - } while (it.MoveNext()); + } if (!structFallback && reader.ReadInt32() != 0 /* && reader.Position + 16 <= maxSize*/) reader.Position += FGuid.SIZE; diff --git a/FModel/PakReader/Parsers/Class/USoundWave.cs b/FModel/PakReader/Parsers/Class/USoundWave.cs index 21c1dd9f..ae9ee53c 100644 --- a/FModel/PakReader/Parsers/Class/USoundWave.cs +++ b/FModel/PakReader/Parsers/Class/USoundWave.cs @@ -1,8 +1,6 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using FModel.PakReader.IO; using FModel.PakReader.Parsers.Objects; using FModel.PakReader.Parsers.PropertyTagData; @@ -53,8 +51,7 @@ namespace FModel.PakReader.Parsers.Class } } - internal USoundWave(IoPackageReader reader, Dictionary properties, Stream ubulk, - long ubulkOffset) : base(reader, properties) + internal USoundWave(IoPackageReader reader, string type, Stream ubulk, long ubulkOffset) : base(reader, type) { Serialize(reader, ubulk, ubulkOffset); } diff --git a/FModel/PakReader/Parsers/Class/UTexture2D.cs b/FModel/PakReader/Parsers/Class/UTexture2D.cs index fdcb46d9..12cd1a2f 100644 --- a/FModel/PakReader/Parsers/Class/UTexture2D.cs +++ b/FModel/PakReader/Parsers/Class/UTexture2D.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.IO; -using FModel.PakReader.IO; using FModel.PakReader.Parsers.Objects; using FModel.PakReader.Textures; using SkiaSharp; @@ -50,8 +49,7 @@ namespace FModel.PakReader.Parsers.Class } } - internal UTexture2D(IoPackageReader reader, Dictionary properties, Stream ubulk, - long bulkOffset) : base(reader, properties) + internal UTexture2D(IoPackageReader reader, string type, Stream ubulk, long bulkOffset) : base(reader, type) { Serialize(reader, ubulk, bulkOffset); } diff --git a/FModel/PakReader/Parsers/IoPackageReader.cs b/FModel/PakReader/Parsers/IoPackageReader.cs index d88ed5b2..ca63c3ca 100644 --- a/FModel/PakReader/Parsers/IoPackageReader.cs +++ b/FModel/PakReader/Parsers/IoPackageReader.cs @@ -8,6 +8,7 @@ using FModel.PakReader.IO; using FModel.PakReader.Parsers.Class; using FModel.PakReader.Parsers.Objects; using FModel.Utils; +using UsmapNET.Classes; namespace FModel.PakReader.Parsers { @@ -159,36 +160,16 @@ namespace FModel.PakReader.Parsers _dataExportTypes[i] = exportType; try { - if (Globals.TypeMappings.TryGetValue(exportType.String, out var properties)) + _dataExports[i] = exportType.String switch { - _dataExports[i] = exportType.String switch - { - "Texture2D" => new UTexture2D(this, properties, _ubulk, ExportMap.Sum(e => (long)e.CookedSerialSize) + beginExportOffset), - "TextureCube" => new UTexture2D(this, properties, _ubulk, ExportMap.Sum(e => (long)e.CookedSerialSize) + beginExportOffset), - "VirtualTexture2D" => new UTexture2D(this, properties, _ubulk, ExportMap.Sum(e => (long)e.CookedSerialSize) + beginExportOffset), - "CurveTable" => new UCurveTable(this), - "DataTable" => new UDataTable(this, properties, exportType.String), - "SoundWave" => new USoundWave(this, properties, _ubulk, ExportMap.Sum(e => (long)e.CookedSerialSize) + beginExportOffset), - _ => new UObject(this, properties, structFallback, exportType.String), - }; - } - else - { - _dataExports[i] = new UObject(); -#if DEBUG - var header = new FUnversionedHeader(this); - if (!header.HasValues) - continue; - using var it = new FIterator(header); - FConsole.AppendText(string.Concat("\n", exportType.String, ": ", Summary.Name.String), "#CA6C6C", true); - - do - { - FConsole.AppendText($"Val: {it.Current.Val} (IsNonZero: {it.Current.IsNonZero})", FColors.Yellow, true); - } - while (it.MoveNext()); -#endif - } + "Texture2D" => new UTexture2D(this, exportType.String, _ubulk, ExportMap.Sum(e => (long)e.CookedSerialSize) + beginExportOffset), + "TextureCube" => new UTexture2D(this, exportType.String, _ubulk, ExportMap.Sum(e => (long)e.CookedSerialSize) + beginExportOffset), + "VirtualTexture2D" => new UTexture2D(this, exportType.String, _ubulk, ExportMap.Sum(e => (long)e.CookedSerialSize) + beginExportOffset), + "CurveTable" => new UCurveTable(this, exportType.String), + "DataTable" => new UDataTable(this, exportType.String), + "SoundWave" => new USoundWave(this, exportType.String, _ubulk, ExportMap.Sum(e => (long)e.CookedSerialSize) + beginExportOffset), + _ => new UObject(this, exportType.String, structFallback), + }; } catch (Exception e) { @@ -203,6 +184,45 @@ namespace FModel.PakReader.Parsers public override string ToString() => Summary.Name.String; + public FUnversionedType GetOrCreateSchema(string export) + { + if (Globals.CachedSchemas.TryGetValue(export, out var v)) + { + return v; + } + else + { + var type = export; + var bNested = false; + var bNop = false; + var ret = new FUnversionedType(type); + while (type != null) + { + var schema = Globals.Usmap.Schemas.FirstOrDefault(x => x.Name == type); + if (schema.Name != null) + { + var lastIndex = ret.Properties.LastOrDefault().Key; + if (!bNop && (bNested && schema.PropCount > 0)) lastIndex++; + + foreach (var prop in schema.Properties) + { + for (int i = 0; i < prop.ArraySize; i++) + { + ret.Properties[lastIndex + i + prop.SchemaIdx] = new FUnversionedProperty(prop); + } + } + + bNop = !bNested && schema.PropCount == 0; + bNested = true; + type = schema.SuperType; + } + } + + Globals.CachedSchemas[export] = ret; + return ret; + } + } + private string Transform(string path) { string gname = Folders.GetGameName(); diff --git a/FModel/PakReader/Parsers/Objects/FName.cs b/FModel/PakReader/Parsers/Objects/FName.cs index f962ea3b..6e4b51e7 100644 --- a/FModel/PakReader/Parsers/Objects/FName.cs +++ b/FModel/PakReader/Parsers/Objects/FName.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using UsmapNET.Classes; namespace FModel.PakReader.Parsers.Objects { @@ -23,6 +24,13 @@ namespace FModel.PakReader.Parsers.Objects Number = number; } + public FName(UsmapPropertyData name, int index = 0, int number = 0) + { + String = name != null ? name.Type.ToString() : "None"; + Index = index; + Number = number; + } + public FName(string name, int index = 0, int number = 0) { String = name; diff --git a/FModel/PakReader/Parsers/Objects/FPropertyTag.cs b/FModel/PakReader/Parsers/Objects/FPropertyTag.cs index 0904b980..983cf6b3 100644 --- a/FModel/PakReader/Parsers/Objects/FPropertyTag.cs +++ b/FModel/PakReader/Parsers/Objects/FPropertyTag.cs @@ -21,16 +21,27 @@ namespace FModel.PakReader.Parsers.Objects public readonly FName Type; // Variables public readonly FName ValueType; - public FPropertyTag(PropertyInfo info) + public FPropertyTag(FUnversionedProperty info) { + BoolVal = 0; + Name = new FName(info.Name); - Type = new FName(info.Type); - StructName = new FName(info.StructType); - BoolVal = (byte) ((info.Bool ?? false) ? 1 : 0); - EnumName = new FName(info.EnumName); - EnumType = new FName(info.EnumType); - InnerType = new FName(info.InnerType); - ValueType = new FName(info.ValueType); + Type = new FName(info.Data); + StructName = new FName(info.Data.StructType); + EnumName = new FName(info.Data.EnumName); + EnumType = new FName(info.Data.InnerType); + InnerType = new FName(info.Data.InnerType); + ValueType = new FName(info.Data.ValueType); + + if (InnerType.String == "StructProperty") + { + StructName = new FName(info.Data.InnerType.StructType); + } + else if (ValueType.String == "StructProperty") + { + StructName = new FName(info.Data.ValueType.StructType); + } + ArrayIndex = 0; Position = 0; HasPropertyGuid = 0; diff --git a/FModel/PakReader/Parsers/Objects/UScriptStruct.cs b/FModel/PakReader/Parsers/Objects/UScriptStruct.cs index c97619b0..7a33c4b8 100644 --- a/FModel/PakReader/Parsers/Objects/UScriptStruct.cs +++ b/FModel/PakReader/Parsers/Objects/UScriptStruct.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -using FModel.PakReader.IO; +using System.Runtime.CompilerServices; using FModel.PakReader.Parsers.Class; namespace FModel.PakReader.Parsers.Objects @@ -121,7 +118,7 @@ namespace FModel.PakReader.Parsers.Objects { if (reader is IoPackageReader ioReader) { - return Globals.TypeMappings.TryGetValue(structName, out var structProperties) ? new UObject(ioReader, structProperties, true, structName) : new UObject(ioReader, new Dictionary(), true, structName); + return new UObject(ioReader, structName, true); } return new UObject(reader, true); diff --git a/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs index c3975d46..dcbf87ad 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/EnumProperty.cs @@ -1,4 +1,5 @@ using FModel.PakReader.Parsers.Objects; +using System.Linq; namespace FModel.PakReader.Parsers.PropertyTagData { @@ -11,7 +12,6 @@ namespace FModel.PakReader.Parsers.PropertyTagData internal EnumProperty(PackageReader reader, FPropertyTag tag, ReadType readType) { Position = reader.Position; - if (!(reader is IoPackageReader) || readType != ReadType.NORMAL) { Value = reader.ReadFName(); @@ -23,23 +23,16 @@ namespace FModel.PakReader.Parsers.PropertyTagData } } - private static string ByteToEnum(string enumName, int value) + private static string ByteToEnum(string enumName, int index) { if (enumName == null) - return value.ToString(); + return index.ToString(); - string result; - - if (Globals.EnumMappings.TryGetValue(enumName, out var values)) - { - result = values.TryGetValue(value, out var member) ? string.Concat(enumName, "::", member) : string.Concat(enumName, "::", value); - } + var enumProp = Globals.Usmap.Enums.FirstOrDefault(x => x.Name == enumName); + if (!enumProp.Equals(default)) + return index >= enumProp.Names.Length ? string.Concat(enumName, "::", index) : string.Concat(enumName, "::", enumProp.Names[index]); else - { - result = string.Concat(enumName, "::", value); - } - - return result; + return string.Concat(enumName, "::", index); } public string GetValue() => Value.String; diff --git a/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs index 9f818f0a..a7656fa1 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/MapProperty.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using FModel.PakReader.Parsers.Objects; diff --git a/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs b/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs index ca4900a9..73236723 100644 --- a/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs +++ b/FModel/PakReader/Parsers/PropertyTagData/SoftObjectProperty.cs @@ -13,7 +13,7 @@ namespace FModel.PakReader.Parsers.PropertyTagData { Position = reader.Position; Value = new FSoftObjectPath(reader); - if (readType == ReadType.MAP) + if (!(reader is IoPackageReader) && readType == ReadType.MAP) reader.Position += 16 - (reader.Position - Position); // skip ahead, putting the total bytes read to 16 } diff --git a/FModel/Utils/Endpoints.cs b/FModel/Utils/Endpoints.cs index 3dd68877..245d97c5 100644 --- a/FModel/Utils/Endpoints.cs +++ b/FModel/Utils/Endpoints.cs @@ -14,9 +14,8 @@ namespace FModel.Utils static class Endpoints { public static readonly FortniteApi FortniteAPI = new FortniteApi($"FModel/{Assembly.GetExecutingAssembly().GetName().Version}"); - public const string FORTNITE_TYPE_MAPPINGS = "https://raw.githubusercontent.com/FabianFG/FortniteTypeMappings/master/TypeMappings.json"; - public const string FORTNITE_ENUM_MAPPINGS = "https://raw.githubusercontent.com/FabianFG/FortniteTypeMappings/master/EnumMappings.json"; public const string BENBOT_AES = "https://benbotfn.tk/api/v1/aes"; + public const string BENBOT_MAPPINGS = "https://benbotfn.tk/api/v1/mappings"; public const string BENBOT_HOTFIXES = "https://benbotfn.tk/api/v1/hotfixes"; public const string FMODEL_JSON = "https://dl.dropbox.com/s/sxyaqo6zu1drlea/FModel.json?dl=0"; public const string OAUTH_URL = "https://account-public-service-prod03.ol.epicgames.com/account/api/oauth/token"; @@ -25,17 +24,15 @@ namespace FModel.Utils public static byte[] GetRawData(Uri uri) => GetRawDataAsync(uri).GetAwaiter().GetResult(); public static async Task GetRawDataAsync(Uri uri) { - using (HttpClient client = new HttpClient { Timeout = TimeSpan.FromSeconds(2) }) + using HttpClient client = new HttpClient { Timeout = TimeSpan.FromSeconds(2) }; + try { - try - { - var data = await client.GetByteArrayAsync(uri).ConfigureAwait(false); - return data; - } - catch - { - return null; - } + var data = await client.GetByteArrayAsync(uri).ConfigureAwait(false); + return data; + } + catch + { + return null; } }