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;
}
}